Skip to content
Open
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
7 changes: 7 additions & 0 deletions Detectors/Base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ o2_add_test(
PUBLIC_LINK_LIBRARIES O2::DetectorsBase
LABELS detectorsbase)

o2_add_test(
GetOrMakeBranch
SOURCES test/testGetOrMakeBranch.cxx
COMPONENT_NAME DetectorsBase
PUBLIC_LINK_LIBRARIES O2::DetectorsBase
LABELS detectorsbase)

o2_add_test(
O2Tessellated
SOURCES test/testO2Tessellated.cxx
Expand Down
8 changes: 7 additions & 1 deletion Detectors/Base/include/DetectorsBase/Detector.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,13 @@ template <typename T>
TBranch* getOrMakeBranch(TTree& tree, const char* brname, T* ptr)
{
if (auto br = tree.GetBranch(brname)) {
br->SetAddress(static_cast<void*>(&ptr));
if constexpr (std::is_pointer_v<T>) {
// ptr is the address of the caller's pointer to the object
br->SetAddress(ptr);
} else {
// the branch keeps the object address itself, as for a branch made with Branch() below
br->SetObject(ptr);
}
return br;
}
// otherwise make it
Expand Down
73 changes: 73 additions & 0 deletions Detectors/Base/test/testGetOrMakeBranch.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2019-2026 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.

/// \file testGetOrMakeBranch.cxx
/// \brief Checks that getOrMakeBranch leaves a valid address on an existing branch

#define BOOST_TEST_MODULE Test GetOrMakeBranch
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include "DetectorsBase/Detector.h"
#include <TTree.h>
#include <cstring>
#include <vector>

namespace
{
// attach the data in their own stack frame, which is gone when the branch is filled
__attribute__((noinline)) TBranch* attach(TTree& tree, std::vector<int>* data)
{
return o2::base::getOrMakeBranch(tree, "data", data);
}

__attribute__((noinline)) TBranch* attachPointer(TTree& tree, std::vector<int>** data)
{
return o2::base::getOrMakeBranch(tree, "pointer", data);
}

// overwrites the stack below the caller
__attribute__((noinline)) void clobberStack()
{
volatile char buffer[4096];
std::memset(const_cast<char*>(buffer), 0xab, sizeof(buffer));
}
} // namespace

BOOST_AUTO_TEST_CASE(FillExistingBranch)
{
TTree tree("t", "t");
tree.SetDirectory(nullptr);
std::vector<std::vector<int>> entries{{1, 2, 3}, {4, 5}, {6}};
for (auto& entry : entries) {
auto pointer = &entry;
auto br = attach(tree, &entry);
auto brPointer = attachPointer(tree, &pointer);
clobberStack();
br->Fill();
brPointer->Fill();
br->ResetAddress();
brPointer->ResetAddress();
}
tree.SetEntries(entries.size());

std::vector<int>* read = nullptr;
std::vector<int>* readPointer = nullptr;
tree.SetBranchAddress("data", &read);
tree.SetBranchAddress("pointer", &readPointer);
BOOST_REQUIRE_EQUAL(tree.GetEntries(), entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
tree.GetEntry(i);
BOOST_CHECK(*read == entries[i]);
BOOST_CHECK(*readPointer == entries[i]);
}
}
1 change: 1 addition & 0 deletions Detectors/TPC/simulation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ o2_add_library(TPCSimulation
src/DigitContainer.cxx
src/DigitGlobalPad.cxx
src/Digitizer.cxx
src/DigitizerCalibrations.cxx
src/DigitTime.cxx
src/ElectronTransport.cxx
src/GEMAmplification.cxx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "DataFormatsTPC/Defs.h"
#include "TPCSimulation/DigitTime.h"
#include "TPCSimulation/SAMPAProcessing.h"
#include "TPCSimulation/DigitizerCalibrations.h"
#include "TPCBase/CalDet.h"
#include "CommonUtils/DebugStreamer.h"
#include "TPCBase/ParameterDetector.h"
Expand Down Expand Up @@ -95,6 +96,9 @@ class DigitContainer
/// Must be called after the CDBInterface is configured; fillOutputContainer calls it lazily otherwise
void updateCalibrations();

/// Use the calibration objects of a snapshot, which the container keeps alive
void updateCalibrations(std::shared_ptr<const DigitizerCalibrations> calib);

private:
TimeBin mFirstTimeBin = 0; ///< First time bin to consider
TimeBin mEffectiveTimeBin = 0; ///< Effective time bin of that digit
Expand All @@ -104,14 +108,12 @@ class DigitContainer
std::unique_ptr<DigitTime::PrevDigitInfoArray> mPrevDigArr; ///< Keep track of ToT and ion tail cumul from last time bin
o2::utils::DebugStreamer mStreamer; ///< Debug streamer
const CalPad* mPadParams[3] = {nullptr, nullptr, nullptr}; //!< Ion tail fraction, ion tail slope and common mode k-values per pad
const CalDet<bool>* mDeadMap = nullptr; //!< Dead channel map, points to mDeadMapCopy if set
std::unique_ptr<CalDet<bool>> mDeadMapCopy; //!< Own copy of the dead channel map, which the CDBInterface rebuilds on each access
const CalDet<bool>* mDeadMap = nullptr; //!< Dead channel map of the calibration snapshot, if used
std::shared_ptr<const DigitizerCalibrations> mCalibrations; //!< Calibration snapshot in use
bool mCMCEnabled = false; //!< Common mode correction enabled in the FEE config (DigiMode Auto)
bool mCalibrationsUpdated = false; //!< Whether updateCalibrations was called
SAMPAProcessing* mSAMPAProcessing = nullptr; //!< SAMPAProcessing used for the output, the singleton if not set
std::vector<std::pair<MCCompLabel, int>> mLabelCollector; //!< Workspace to sort the MC labels of a digit

void reportSettings();
};

inline DigitContainer::DigitContainer()
Expand Down
10 changes: 9 additions & 1 deletion Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define ALICEO2_TPC_Digitizer_H_

#include "TPCSimulation/DigitContainer.h"
#include "TPCSimulation/DigitizerCalibrations.h"
#include "TPCSimulation/Point.h"
#include "TPCBase/Mapper.h"

Expand Down Expand Up @@ -66,9 +67,12 @@ class Digitizer
Digitizer(const Digitizer&) = delete;
Digitizer& operator=(const Digitizer&) = delete;

/// Initializer
/// Initializer, with the calibrations set by setCalibrations or else read from the CDBInterface
void init();

/// Use this calibration snapshot from the next init() on; digitizers in several threads share one snapshot
void setCalibrations(std::shared_ptr<const DigitizerCalibrations> calib) { mCalibrations = std::move(calib); }

/// Process a single hit group
/// \param hits Container with TPC hit groups
/// \param eventID ID of the event to be processed
Expand Down Expand Up @@ -164,6 +168,8 @@ class Digitizer
private:
/// Fill the random rings of the sector seeding, if not done yet
void initSectorSeeding();
/// the calibration snapshot, read from the CDBInterface if none was set
const DigitizerCalibrations& calibrations();

ElectronTransport& electronTransport();
GEMAmplification& gemAmplification();
Expand All @@ -177,6 +183,8 @@ class Digitizer
bool mUseSectorSeeding = false; //!< Whether sector seeding is used
bool mFlushDebugStreamer = true; //!< Whether flush() flushes the debug streamer

std::shared_ptr<const DigitizerCalibrations> mCalibrations; //!< Calibration snapshot used by init()

DigitContainer mDigitContainer; ///< Container for the Digits
std::vector<float> mSignalArray; //!< Workspace for the shaped signal of one electron
std::unique_ptr<SC> mSpaceChargeOwned; //!< Distortions created by the digitizer itself
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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.

/// \file DigitizerCalibrations.h
/// \brief Calibration objects of the TPC digitizer, shared read-only between digitizers

#ifndef ALICEO2_TPC_DIGITIZERCALIBRATIONS_H_
#define ALICEO2_TPC_DIGITIZERCALIBRATIONS_H_

#include "TPCBase/CalDet.h"
#include <memory>

namespace o2::tpc
{

/// Calibration objects of the TPC digitizer, read from the CDBInterface by one thread and then only read
struct DigitizerCalibrations {
const CalPad* gainMap = nullptr;
const CalPad* pedestals = nullptr;
const CalPad* pedestalsCRU = nullptr;
const CalPad* noise = nullptr;
const CalPad* zeroSuppression = nullptr;
const CalPad* padParams[3] = {nullptr, nullptr, nullptr}; ///< ion tail fraction, ion tail slope and common mode k-values per pad, if used
std::unique_ptr<const CalDet<bool>> deadMap; ///< own copy of the dead channel map, if used, since the CDBInterface rebuilds it on each access
bool cmcEnabled = false; ///< common mode correction enabled in the FEE config (DigiMode Auto)

/// Read the calibration objects from the CDBInterface, which is not thread safe
static std::shared_ptr<const DigitizerCalibrations> fetch();
};

} // namespace o2::tpc

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "TPCBase/CRU.h"
#include "TPCBase/PadPos.h"
#include "TPCBase/CalDet.h"
#include "TPCSimulation/DigitizerCalibrations.h"

namespace o2
{
Expand Down Expand Up @@ -56,6 +57,9 @@ class GEMAmplification
/// Update the OCDB parameters cached in the class. To be called once per event
void updateParameters();

/// Update the parameters cached in the class, with the gain map from the calibration snapshot
void updateParameters(const DigitizerCalibrations& calib);

/// Compute the number of electrons after amplification in a full stack of four GEM foils
/// \param nElectrons Number of electrons arriving at the first amplification stage (GEM1)
/// \return Number of electrons after amplification in a full stack of four GEM foils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "TPCBase/PadPos.h"
#include "TPCBase/CalDet.h"
#include "TPCSimulation/DigitizerCalibrations.h"
#include "TPCBase/CRU.h"
#include "MathUtils/RandomRing.h"
#include "TPCBase/ParameterDetector.h"
Expand Down Expand Up @@ -58,6 +59,9 @@ class SAMPAProcessing
/// Update the OCDB parameters cached in the class. To be called once per event
void updateParameters(float vdrift = 0);

/// Update the parameters cached in the class, with the maps from the calibration snapshot
void updateParameters(float vdrift, const DigitizerCalibrations& calib);

/// Conversion from a given number of electrons into ADC value without taking into account saturation (vectorized)
/// \param nElectrons Number of electrons in time bin
/// \return ADC value
Expand Down
54 changes: 8 additions & 46 deletions Detectors/TPC/simulation/src/DigitContainer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@
/// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de

#include "TPCSimulation/DigitContainer.h"
#include <atomic>
#include <memory>
#include <type_traits>
#include <fairlogger/Logger.h>
#include "TPCBase/Mapper.h"
#include "TPCBaseRecSim/CDBInterface.h"
#include "TPCBase/ParameterElectronics.h"
#include "TPCBase/IonTailSettings.h"
#include "SimConfig/DigiParams.h"

using namespace o2::tpc;
Expand Down Expand Up @@ -135,51 +132,16 @@ void DigitContainer::fillOutputContainer(std::vector<Digit>& output,

void DigitContainer::updateCalibrations()
{
const auto& eleParam = ParameterElectronics::Instance();
auto& cdb = CDBInterface::instance();

// ion tail per pad parameters
mPadParams[0] = mPadParams[1] = mPadParams[2] = nullptr;
if (eleParam.doIonTailPerPad) {
const auto& itSettings = IonTailSettings::Instance();
if (itSettings.padITCorrFile.size()) {
cdb.setFEEParamsFromFile(itSettings.padITCorrFile);
}
mPadParams[0] = &cdb.getITFraction();
mPadParams[1] = &cdb.getITExpLambda();
}
if (eleParam.doCommonModePerPad) {
mPadParams[2] = &cdb.getCMkValues();
}

// dead channel map
mDeadMap = nullptr;
mDeadMapCopy.reset();
if (eleParam.applyDeadMap) {
mDeadMapCopy = std::make_unique<CalDet<bool>>(cdb.getDeadChannelMap());
mDeadMap = mDeadMapCopy.get();
}
updateCalibrations(DigitizerCalibrations::fetch());
}

void DigitContainer::updateCalibrations(std::shared_ptr<const DigitizerCalibrations> calib)
{
mCalibrations = std::move(calib);
std::copy(std::begin(mCalibrations->padParams), std::end(mCalibrations->padParams), std::begin(mPadParams));
mDeadMap = mCalibrations->deadMap.get();
// common mode correction in the FEE, needed to resolve DigiMode Auto
mCMCEnabled = (eleParam.DigiMode == DigitzationMode::Auto) && cdb.getFEEConfig().isCMCEnabled();
mCMCEnabled = mCalibrations->cmcEnabled;

mCalibrationsUpdated = true;

static std::atomic<bool> reportedSettings{false};
if (!reportedSettings.exchange(true)) {
reportSettings();
if (mDeadMap) {
LOGP(info, "Using dead map with {} masked pads", mDeadMap->getSum<int>());
}
}
}

void DigitContainer::reportSettings()
{
auto& cdb = CDBInterface::instance();
const auto& eleParam = ParameterElectronics::Instance();
const auto& feeConfig = cdb.getFEEConfig();
LOGP(info, "ParameterElectronics: doIonTail={}, doIonTailPerPad={}, doCommonModePerPad={}, doSaturationTail={}, doNoiseEmptyPads={}, applyDeadMap={}, commonModeCoupling={}, DigiMode={}",
eleParam.doIonTail, eleParam.doIonTailPerPad, eleParam.doCommonModePerPad, eleParam.doSaturationTail, eleParam.doNoiseEmptyPads, eleParam.applyDeadMap, eleParam.commonModeCoupling, (int)eleParam.DigiMode);
feeConfig.printShort();
}
Loading
Loading