37template <
class InputType>
40 setContainer(clustersContainer, inputsContainer, cellsIndices);
43template <
class InputType>
46 mClustersContainer = std::span<const o2::emcal::Cluster>();
47 mInputsContainer = std::span<const InputType>();
48 mCellsIndices = std::span<int>();
50 mCellLabelContainer = std::span<const o2::emcal::CellLabel>();
56template <
class InputType>
59 if (clusterIndex >= mClustersContainer.size()) {
67 clusterAnalysis.
setID(clusterIndex);
69 int firstCellIndex = mClustersContainer[clusterIndex].getCellIndexFirst();
70 int nCells = mClustersContainer[clusterIndex].getNCells();
72 std::span<const int> inputsIndices = std::span<const int>(&mCellsIndices[firstCellIndex], nCells);
77 auto [inputIndMax, inputEnergyMax, cellAmp, shared] = getMaximalEnergyIndex(inputsIndices);
81 mSharedCluster = shared;
85 mCellGeomBuffer.clear();
86 mCellGeomBuffer.reserve(inputsIndices.size());
87 for (
auto iInput : inputsIndices) {
88 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
89 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
90 auto [
row,
col] = mGeomPtr->GetTopologicalRowColumn(nSupMod, nModule, nIphi, nIeta);
94 int ietaShared = ieta + ((mSharedCluster && nSupMod % 2) ?
EMCAL_COLS : 0);
96 mCellGeomBuffer.push_back({
static_cast<int8_t
>(nSupMod),
static_cast<int8_t
>(iphi),
static_cast<int8_t
>(ieta),
97 static_cast<int8_t
>(ietaShared),
static_cast<int16_t
>(
row),
static_cast<int16_t
>(
col)});
100 int16_t towerId = mInputsContainer[inputIndMax].getTower();
102 float exoticTime = mInputsContainer[inputIndMax].getTimeStamp();
107 clusterAnalysis.
setIsExotic(isExoticCell(towerId, inputEnergyMax, exoticTime, fCross));
115 clusterAnalysis.
setE(cellAmp);
117 mSuperModuleNumber = mGeomPtr->GetSuperModuleNumber(towerId);
119 clusterAnalysis.
setNCells(inputsIndices.size());
121 std::vector<uint16_t> cellsIdices;
123 bool addClusterLabels = ((clusterLabel !=
nullptr) && (mCellLabelContainer.size() > 0));
124 for (
auto cellIndex : inputsIndices) {
125 cellsIdices.push_back(cellIndex);
126 if (addClusterLabels) {
127 for (
size_t iLabel = 0; iLabel < mCellLabelContainer[cellIndex].GetLabelSize(); iLabel++) {
128 if (mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) <= 0.f) {
131 clusterLabel->
addValue(mCellLabelContainer[cellIndex].GetLabel(iLabel),
132 mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) * mInputsContainer[cellIndex].getEnergy());
136 if (addClusterLabels) {
144 evalGlobalPosition(inputsIndices, clusterAnalysis);
145 evalLocalPosition(inputsIndices, clusterAnalysis);
148 evalElipsAxis(inputsIndices, clusterAnalysis);
149 evalDispersion(inputsIndices, clusterAnalysis);
152 evalNExMax(inputsIndices, clusterAnalysis);
154 evalCoreEnergy(inputsIndices, clusterAnalysis);
155 evalTime(inputsIndices, clusterAnalysis);
167 return clusterAnalysis;
175template <
class InputType>
178 double d = 0., wtot = 0.;
180 if (clusterAnalysis.
E() <= 0) {
188 std::vector<CellWeight> cellData;
189 cellData.reserve(inputsIndices.size());
191 double etaMean = 0.0, phiMean = 0.0;
193 for (
size_t i = 0;
i < inputsIndices.size(); ++
i) {
194 auto iInput = inputsIndices[
i];
195 if (mInputsContainer[iInput].getEnergy() <= 0) {
199 const auto& geom = mCellGeomBuffer[
i];
200 auto etai =
static_cast<double>(geom.ietaShared);
201 auto phii =
static_cast<double>(geom.iphi);
202 double w = std::max(0.,
static_cast<double>(mLogWeight + std::log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.
E())));
205 cellData.push_back({etai, phii,
w});
216 LOG(error) <<
"Wrong weight " << wtot;
219 for (
const auto&
c : cellData) {
220 d +=
c.w * ((
c.eta - etaMean) * (
c.eta - etaMean) + (
c.phi - phiMean) * (
c.phi - phiMean));
223 if (wtot > 0 && cellData.size() > 1) {
235template <
class InputType>
241 double dist = tMaxInCm(
static_cast<double>(clusterAnalysis.
E()));
243 std::array<double, 3> clXYZ = {0., 0., 0.}, clRmsXYZ = {0., 0., 0.}, xyzi{};
244 double wtot = 0.,
w = 0.;
246 for (
auto iInput : inputsIndices) {
249 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
256 if (mSharedCluster && mSuperModuleNumber != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
260 if (mLogWeight > 0.0) {
261 w = std::max(0.,
static_cast<double>(mLogWeight + std::log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.
E())));
263 w = mInputsContainer[iInput].getEnergy();
270 for (
int i = 0;
i < 3;
i++) {
271 clXYZ[
i] += (
w * xyzi[
i]);
272 clRmsXYZ[
i] += (
w * xyzi[
i] * xyzi[
i]);
281 for (
int i = 0;
i < 3;
i++) {
285 clRmsXYZ[
i] /= (wtot * wtot);
286 clRmsXYZ[
i] = clRmsXYZ[
i] - clXYZ[
i] * clXYZ[
i];
288 if (clRmsXYZ[
i] > 0.0) {
289 clRmsXYZ[
i] = std::sqrt(clRmsXYZ[
i]);
298 for (
int i = 0;
i < 3;
i++) {
299 clXYZ[
i] = clRmsXYZ[
i] = -1.;
303 clusterAnalysis.
setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
309template <
class InputType>
313 int i = 0, nstat = 0;
315 double dist = tMaxInCm(
static_cast<double>(clusterAnalysis.
E()));
317 std::array<double, 3> clXYZ = {0., 0., 0.}, clRmsXYZ = {0., 0., 0.}, lxyzi{}, xyzi{};
318 double wtot = 0.,
w = 0.;
320 for (
auto iInput : inputsIndices) {
324 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(lxyzi[0], lxyzi[1], lxyzi[2]);
331 mGeomPtr->GetGlobal(lxyzi, xyzi, mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower()));
333 if (mLogWeight > 0.0) {
334 w = std::max(0.,
static_cast<double>(mLogWeight + std::log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.
E())));
336 w = mInputsContainer[iInput].getEnergy();
343 for (
i = 0;
i < 3;
i++) {
344 clXYZ[
i] += (
w * xyzi[
i]);
345 clRmsXYZ[
i] += (
w * xyzi[
i] * xyzi[
i]);
354 for (
i = 0;
i < 3;
i++) {
358 clRmsXYZ[
i] /= (wtot * wtot);
359 clRmsXYZ[
i] = clRmsXYZ[
i] - clXYZ[
i] * clXYZ[
i];
361 if (clRmsXYZ[
i] > 0.0) {
362 clRmsXYZ[
i] = std::sqrt(clRmsXYZ[
i]);
371 for (
i = 0;
i < 3;
i++) {
372 clXYZ[
i] = clRmsXYZ[
i] = -1.;
376 clusterAnalysis.
setGlobalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
382template <
class InputType>
384 double phiSlope, std::span<const int> inputsIndices,
AnalysisCluster& clusterAnalysis)
const
386 int i = 0, nstat = 0;
387 std::array<double, 3> clXYZ = {0., 0., 0.}, clRmsXYZ = {0., 0., 0.}, xyzi{};
388 double wtot = 0.,
w = 0.;
390 for (
auto iInput : inputsIndices) {
393 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), deff).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
399 if (mLogWeight > 0.0) {
400 w = std::max(0.,
static_cast<double>(mLogWeight + std::log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.
E())));
402 w = mInputsContainer[iInput].getEnergy();
409 for (
i = 0;
i < 3;
i++) {
410 clXYZ[
i] += (
w * xyzi[
i]);
411 clRmsXYZ[
i] += (
w * xyzi[
i] * xyzi[
i]);
420 for (
i = 0;
i < 3;
i++) {
424 clRmsXYZ[
i] /= (wtot * wtot);
425 clRmsXYZ[
i] = clRmsXYZ[
i] - clXYZ[
i] * clXYZ[
i];
427 if (clRmsXYZ[
i] > 0.0) {
428 clRmsXYZ[
i] = std::sqrt(clRmsXYZ[
i]);
437 for (
i = 0;
i < 3;
i++) {
438 clXYZ[
i] = clRmsXYZ[
i] = -1.;
444 if (phiSlope != 0.0 && mLogWeight > 0.0 && wtot != 0.0) {
447 double ycorr = clXYZ[1] * (1. + phiSlope);
453 clusterAnalysis.
setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
461template <
class InputType>
465 const double kdp0 = 9.25147, kdp1 = 1.16700;
466 const double kwp0 = 4.83713, kwp1 = -2.77970e-01, kwp2 = 4.41116;
469 e = esum < 0.5 ? 0.5 : esum;
470 e = e > 100. ? 100. : e;
472 deff = kdp0 + kdp1 * std::log(e);
473 w0 = kwp0 / (1. + std::exp(kwp1 * (e + kwp2)));
484template <
class InputType>
488 float coreEnergy = 0.;
491 evalLocalPosition(inputsIndices, clusterAnalysis);
496 for (
auto iInput : inputsIndices) {
498 auto [eta, phi] = mGeomPtr->EtaPhiFromIndex(mInputsContainer[iInput].getTower());
499 phi = phi * o2::constants::math::Deg2Rad;
501 double distance = std::sqrt((eta - etaPoint) * (eta - etaPoint) + (phi - phiPoint) * (phi - phiPoint));
504 coreEnergy += mInputsContainer[iInput].getEnergy();
513template <
class InputType>
516 const size_t n = inputsIndices.size();
517 std::vector<double> energies;
519 for (
auto iInput : inputsIndices) {
520 energies.push_back(mInputsContainer[iInput].getEnergy());
524 for (
size_t i = 0;
i <
n;
i++) {
526 const auto& gi = mCellGeomBuffer[
i];
528 for (
size_t j = 0;
j <
n;
j++) {
532 const auto& gj = mCellGeomBuffer[
j];
534 if (std::abs(gi.row - gj.row) <= 1 && std::abs(gi.col - gj.col) <= 1) {
535 if (energies[
j] > energies[
i]) {
553template <
class InputType>
563 std::array<float, 2> lambda{};
565 for (
size_t i = 0;
i < inputsIndices.size(); ++
i) {
566 auto iInput = inputsIndices[
i];
567 const auto& geom = mCellGeomBuffer[
i];
569 auto etai =
static_cast<double>(geom.ietaShared);
570 auto phii =
static_cast<double>(geom.iphi);
572 double w = std::max(0.,
static_cast<double>(mLogWeight + std::log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.
E())));
574 dxx +=
w * etai * etai;
576 dzz +=
w * phii * phii;
578 dxz +=
w * etai * phii;
593 lambda[0] = 0.5 * (dxx + dzz) + std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
596 lambda[0] = std::sqrt(lambda[0]);
601 lambda[1] = 0.5 * (dxx + dzz) - std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
604 lambda[1] = std::sqrt(lambda[1]);
613 clusterAnalysis.
setM02(lambda[0] * lambda[0]);
614 clusterAnalysis.
setM20(lambda[1] * lambda[1]);
620template <
class InputType>
629 for (
auto iInput : inputsIndices) {
630 if (iInput >= mInputsContainer.size()) {
633 cellAmp += mInputsContainer[iInput].getEnergy();
634 if (iSupMod0 == -1) {
635 iSupMod0 = mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower());
636 }
else if (iSupMod0 != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
639 if (mInputsContainer[iInput].getEnergy() > energy) {
640 energy = mInputsContainer[iInput].getEnergy();
645 return std::make_tuple(mid, energy, cellAmp, shared);
651template <
class InputType>
654 if (ecell < mExoticCellMinAmplitude) {
659 if (!getLookUpInit()) {
663 float eCross = getECross(towerId, ecell, exoticTime);
664 fCross = 1.f - eCross / ecell;
666 if (fCross > mExoticCellFraction) {
667 LOG(
debug) <<
"EXOTIC CELL id " << towerId <<
", eCell " << ecell <<
", eCross " << eCross <<
", 1-eCross/eCell " << 1 - eCross / ecell;
677template <
class InputType>
680 auto [iSM, iMod, iIphi, iIeta] = mGeomPtr->GetCellIndex(absID);
681 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta);
685 int16_t towerId1 = -1;
686 int16_t towerId2 = -1;
690 towerId1 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi + 1, ieta);
697 towerId2 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi - 1, ieta);
705 int16_t towerId3 = -1;
706 int16_t towerId4 = -1;
710 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM + 1, iphi, 0);
715 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
719 }
else if (ieta == 0 && (iSM % 2) != 0) {
721 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
733 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
740 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
747 LOG(
debug) <<
"iSM " << iSM <<
", absID " << absID <<
", a " << towerId1 <<
", b " << towerId2 <<
", c " << towerId3 <<
", e " << towerId3;
749 int16_t index1 = (towerId1 > -1) ? mLoolUpTowerToIndex.at(towerId1) : -1;
750 int16_t index2 = (towerId2 > -1) ? mLoolUpTowerToIndex.at(towerId2) : -1;
751 int16_t index3 = (towerId3 > -1) ? mLoolUpTowerToIndex.at(towerId3) : -1;
752 int16_t index4 = (towerId4 > -1) ? mLoolUpTowerToIndex.at(towerId4) : -1;
754 std::array<std::pair<float, float>, 4> cellData = {
755 {{(index1 > -1) ? mInputsContainer[index1].getEnergy() : 0., (index1 > -1) ? mInputsContainer[index1].getTimeStamp() : 0.},
756 {(index2 > -1) ? mInputsContainer[index2].getEnergy() : 0., (index2 > -1) ? mInputsContainer[index2].getTimeStamp() : 0.},
757 {(index3 > -1) ? mInputsContainer[index3].getEnergy() : 0., (index3 > -1) ? mInputsContainer[index3].getTimeStamp() : 0.},
758 {(index4 > -1) ? mInputsContainer[index4].getEnergy() : 0., (index4 > -1) ? mInputsContainer[index4].getTimeStamp() : 0.}}};
760 for (
auto& cell : cellData) {
761 if (std::abs(exoticTime - cell.second) > mExoticCellDiffTime) {
766 float w1 = 1, w2 = 1, w3 = 1, w4 = 1;
767 if (mUseWeightExotic) {
768 w1 = GetCellWeight(cellData[0].
first, energy);
769 w2 = GetCellWeight(cellData[1].
first, energy);
770 w3 = GetCellWeight(cellData[2].
first, energy);
771 w4 = GetCellWeight(cellData[3].
first, energy);
774 if (cellData[0].
first < mExoticCellInCrossMinAmplitude || w1 <= 0) {
775 cellData[0].first = 0;
777 if (cellData[1].
first < mExoticCellInCrossMinAmplitude || w2 <= 0) {
778 cellData[1].first = 0;
780 if (cellData[2].
first < mExoticCellInCrossMinAmplitude || w3 <= 0) {
781 cellData[2].first = 0;
783 if (cellData[3].
first < mExoticCellInCrossMinAmplitude || w4 <= 0) {
784 cellData[3].first = 0;
787 return cellData[0].first + cellData[1].first + cellData[2].first + cellData[3].first;
793template <
class InputType>
796 if (eCell > 0 && eCluster > 0) {
797 if (mLogWeight > 0) {
798 return std::max(0.f, mLogWeight + std::log(eCell / eCluster));
800 return std::log(eCluster / eCell);
808template <
class InputType>
812 for (
auto iInput : inputsIndices) {
813 if (mInputsContainer[iInput].getEnergy() >
level * clusterAnalysis.
E()) {
824template <
class InputType>
829 for (
auto iInput : inputsIndices) {
830 if (mInputsContainer[iInput].getEnergy() > maxE) {
831 maxE = mInputsContainer[iInput].getEnergy();
836 clusterAnalysis.
setClusterTime(mInputsContainer[maxAt].getTimeStamp());
843template <
class InputType>
846 const double ca = 4.82;
849 const double x0 = 1.31;
852 tmax = std::log(e) + ca;
868template <
class InputType>
871 return (2.f * std::atan(std::exp(-eta)));
878template <
class InputType>
881 return (-1.f * std::log(std::tan(0.5f * theta)));
884template <
class InputType>
886 mCurrentCluster(mClusterFactory->buildCluster(clusterIndex)),
887 mClusterID(clusterIndex),
892template <
class InputType>
895 return mClusterFactory == rhs.mClusterFactory && mClusterID == rhs.mClusterID && mForward == rhs.mForward;
898template <
class InputType>
906 mCurrentCluster = mClusterFactory->buildCluster(mClusterID);
910template <
class InputType>
918template <
class InputType>
926 mCurrentCluster = mClusterFactory->buildCluster(mClusterID);
930template <
class InputType>
Cluster class for kinematic cluster parametersported from AliVCluster in AliRoot.
void setNExMax(unsigned char nExMax)
void setFCross(float fCross)
void setCoreEnergy(float energy)
math_utils::Point3D< float > getLocalPosition() const
void setGlobalPosition(const math_utils::Point3D< float > &x)
Set the cluster global position.
void setCellsIndices(const std::vector< unsigned short > &array)
Set the array of cell indices.
void setLocalPosition(const math_utils::Point3D< float > &x)
void setDispersion(float disp)
void setIndMaxInput(const int ind)
void setClusterTime(float time)
ClusterIterator & operator--()
Prefix decrementation operator.
ClusterIterator(const ClusterFactory &factory, int clusterIndex, bool forward)
Constructor, initializing the iterator.
bool operator==(const ClusterIterator &rhs) const
Check for equalness.
ClusterIterator & operator++()
Prefix incrementation operator.
Exception handling uninitialized look up table.
const char * what() const noexcept final
Access to error message of the exception.
EMCal clusters factory Ported from class AliEMCALcluster.
void reset()
Reset containers.
float GetCellWeight(float eCell, float eCluster) const
return weight of cell for shower shape calculation
float etaToTheta(float eta) const
Converts Eta (Radians) to Theta (Radians)
void evalGlobalPosition(std::span< const int > inputsIndices, AnalysisCluster &cluster) const
Calculates the center of gravity in the global ALICE coordinates.
bool isExoticCell(int16_t towerId, float ecell, float const exoticTime, float &fCross) const
Look to cell neighbourhood and reject if it seems exotic.
std::tuple< int, float, float, bool > getMaximalEnergyIndex(std::span< const int > inputsIndices) const
Finds the maximum energy in the cluster and computes the Summed amplitude of digits/cells.
float getECross(int16_t absID, float energy, float const exoticTime) const
Calculate the energy in the cross around the energy of a given cell.
int getMultiplicityAtLevel(float level, std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculates the multiplicity of digits/cells with energy larger than level*energy.
Double_t tMaxInCm(const Double_t e=0.0, const int key=0) const
void evalTime(std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Time is set to the time of the digit with the maximum energy.
void evalLocalPosition(std::span< const int > inputsIndices, AnalysisCluster &cluster) const
Calculates the center of gravity in the local EMCAL-module coordinates.
static void getDeffW0(const Double_t esum, Double_t &deff, Double_t &w0)
ClusterFactory()=default
Dummy constructor.
void evalLocalPositionFit(double deff, double mLogWeight, double phiSlope, std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
evaluates local position of clusters in SM
void evalCoreEnergy(std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
void evalDispersion(std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculates the dispersion of the shower at the origin of the cluster in cell units.
void evalElipsAxis(std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculates the axis of the shower ellipsoid in eta and phi in cell units.
float thetaToEta(float theta) const
Converts Theta (Radians) to Eta (Radians)
AnalysisCluster buildCluster(int index, o2::emcal::ClusterLabel *clusterLabel=nullptr) const
evaluates cluster parameters: position, shower shape, primaries ...
void evalNExMax(std::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculate the number of local maxima in the cluster.
cluster class for MC particle IDs and their respective energy fraction
void orderLabels()
Sort the labels and energy fraction in descending order (largest energy fraction to smallest)
void normalize(float factor)
Normalize the energy fraction.
void addValue(int label, float energyFraction)
Add label and energy fraction to the.
Exception handling non-existing cell IDs.
int getCellID() const noexcept
Access to cell ID raising the exception.
const char * what() const noexcept final
Access to error message of the exception.
GLsizei GLsizei GLfloat distance
GLubyte GLubyte GLubyte GLubyte w
GLdouble GLdouble GLdouble z
@ EMCAL_ROWS
Number of rows per module for EMCAL.
@ EMCAL_COLS
Number of columns per module for EMCAL.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"