10#include <ecl/modules/eclSplitterN1/ECLSplitterN1Module.h>
13#include <ecl/dataobjects/ECLCalDigit.h>
14#include <ecl/dataobjects/ECLConnectedRegion.h>
15#include <ecl/dataobjects/ECLElementNumbers.h>
16#include <ecl/dataobjects/ECLLocalMaximum.h>
17#include <ecl/dataobjects/ECLShower.h>
18#include <ecl/dbobjects/ECLnOptimal.h>
19#include <ecl/geometry/ECLGeometryPar.h>
20#include <ecl/geometry/ECLNeighbours.h>
21#include <ecl/utility/Position.h>
24#include <framework/geometry/B2Vector3.h>
25#include <framework/logging/Logger.h>
26#include <mdst/dataobjects/EventLevelClusteringInfo.h>
48 m_eclCalDigits(eclCalDigitArrayName()),
49 m_eclConnectedRegions(eclConnectedRegionArrayName()),
50 m_eclShowers(eclShowerArrayName()),
51 m_eclLocalMaximums(eclLocalMaximumArrayName()),
52 m_eventLevelClusteringInfo(eventLevelClusteringInfoName())
55 setDescription(
"ECLSplitterN1Module: Baseline reconstruction splitter code for the n photon hypothesis.");
57 "Number of background digits at full background (as provided by EventLevelClusteringInfo).",
68 addParam(
"maxSplits",
m_maxSplits,
"Maximum number of splits within one connected region.", 10);
70 "Minimum digit energy to be included in the shower energy calculation. (NOT USED)", 0.5 *
Belle2::Unit::MeV);
72 "Maximum time residual to be included in the shower energy calculation. (NOT USED)", 5.0);
76 "Optimize the number of digits for energy calculations.", 1);
138 std::vector<float> eBoundariesFwd =
m_eclNOptimal->getUpperBoundariesFwd();
139 std::vector<float> eBoundariesBrl =
m_eclNOptimal->getUpperBoundariesBrl();
140 std::vector<float> eBoundariesBwd =
m_eclNOptimal->getUpperBoundariesBwd();
144 B2INFO(
"ECLSplitterN1 beginRun: number of nOptimal payload energies = " <<
m_nEnergyBins);
166 B2DEBUG(175,
"ECLCRSplitterModule::event()");
221 double backgroundLevel = 0.0;
223 backgroundLevel =
static_cast<double>(bkgdcount) /
static_cast<double>(
m_fullBkgdCount);
229 B2DEBUG(170,
"ECLCRSplitterModule::splitConnectedRegion: nLocalMaximums = " << nLocalMaximums);
238 if (nLocalMaximums == 1) {
244 aECLShower->addRelationTo(&aCR);
247 double weightSum = 0.0;
253 const int locmaxcellid = locmaxvector[0]->getCellId();
258 double highestEnergyTimeResolution = (
m_eclCalDigits[pos])->getTimeResolution();
270 std::vector<ECLCalDigit> digits;
271 std::vector<double> weights;
272 for (
auto& neighbourId : neighbourMap->
getNeighbours(highestEnergyID)) {
279 weights.push_back(1.0);
287 aECLShower->setTheta(showerposition.
Theta());
288 aECLShower->setPhi(showerposition.
Phi());
289 aECLShower->setR(showerposition.
Mag());
292 double showerEnergy = 0.0;
297 const unsigned int nOptimal =
static_cast<unsigned int>(nOptimalVec[0]);
298 aECLShower->setNominalNumberOfCrystalsForEnergy(
static_cast<double>(nOptimal));
302 aECLShower->setNOptimalGroupIndex(nOptimalVec[1]);
303 aECLShower->setNOptimalEnergyBin(nOptimalVec[2]);
304 aECLShower->setNOptimalEnergy(energyEstimation);
307 std::vector< std::pair<unsigned int, double>> listCrystalPairs;
308 listCrystalPairs.resize(digits.size());
310 std::vector < std::pair<double, double> > weighteddigits;
311 weighteddigits.resize(digits.size());
312 for (
unsigned int i = 0; i < digits.size(); ++i) {
313 weighteddigits.at(i) = std::make_pair((digits.at(i)).getEnergy(), weights.at(i));
314 listCrystalPairs.at(i) = std::make_pair((digits.at(i)).getCellId(), weights.at(i) * (digits.at(i)).getEnergy());
318 std::sort(listCrystalPairs.begin(), listCrystalPairs.end(), [](
const auto & left,
const auto & right) {
319 return left.second > right.second;
321 std::vector< unsigned int> listCrystals;
323 for (
unsigned int i = 0; i < digits.size(); ++i) {
325 listCrystals.push_back(listCrystalPairs[i].first);
329 aECLShower->setNumberOfCrystalsForEnergy(
static_cast<double>(listCrystals.size()));
330 aECLShower->setListOfCrystalsForEnergy(listCrystals);
333 B2DEBUG(175,
"Shower Energy (1): " << showerEnergy);
336 showerEnergy = Belle2::ECL::computeEnergySum(digits, weights);
339 aECLShower->setEnergy(showerEnergy);
340 aECLShower->setEnergyRaw(showerEnergy);
341 aECLShower->setEnergyHighestCrystal(highestEnergy);
342 aECLShower->setTime(highestEnergyTime);
343 aECLShower->setDeltaTime99(highestEnergyTimeResolution);
344 aECLShower->setNumberOfCrystals(weightSum);
345 aECLShower->setCentralCellId(highestEnergyID);
347 B2DEBUG(175,
"theta = " << showerposition.
Theta());
348 B2DEBUG(175,
"phi = " << showerposition.
Phi());
349 B2DEBUG(175,
"R = " << showerposition.
Mag());
350 B2DEBUG(175,
"energy = " << showerEnergy);
351 B2DEBUG(175,
"time = " << highestEnergyTime);
352 B2DEBUG(175,
"time resolution = " << highestEnergyTimeResolution);
353 B2DEBUG(175,
"neighbours = " << nNeighbours);
354 B2DEBUG(175,
"backgroundLevel = " << backgroundLevel);
357 aECLShower->setShowerId(1);
359 aECLShower->setConnectedRegionId(aCR.
getCRId());
373 std::vector<std::pair<ECLLocalMaximum, double>> lm_energy_vector;
375 const int cellid = aLocalMaximum.getCellId();
378 lm_energy_vector.push_back(std::pair<ECLLocalMaximum, double>(aLocalMaximum, digitenergy));
382 if (lm_energy_vector.size() >=
static_cast<size_t>(
m_maxSplits)) {
383 std::sort(lm_energy_vector.begin(), lm_energy_vector.end(), [](
const std::pair<ECLLocalMaximum, double>& x,
384 const std::pair<ECLLocalMaximum, double>& y) {
385 return x.second > y.second;
391 std::vector<ECLCalDigit> digits;
392 std::vector<double> weights;
393 std::map<int, B2Vector3D> centroidList;
394 std::map<int, double> centroidEnergyList;
395 std::map<int, B2Vector3D> allPoints;
396 std::map<int, std::vector < double > > weightMap;
397 std::vector < ECLCalDigit > digitVector;
400 std::map<int, B2Vector3D> localMaximumsPoints;
401 std::map<int, B2Vector3D> centroidPoints;
403 for (
auto& aLocalMaximum : lm_energy_vector) {
405 int cellid = aLocalMaximum.first.getCellId();
409 localMaximumsPoints.insert(std::map<int, B2Vector3D>::value_type(cellid, vectorPosition));
410 centroidPoints.insert(std::map<int, B2Vector3D>::value_type(cellid, vectorPosition));
414 bool iterateclusters =
true;
418 centroidList.clear();
419 centroidEnergyList.clear();
426 const int cellid = aCalDigit.getCellId();
429 allPoints.insert(std::map<int, B2Vector3D>::value_type(cellid, vectorPosition));
430 digits.push_back(aCalDigit);
433 for (
const auto& digitpoint : allPoints) {
434 const int cellid = digitpoint.first;
445 double centroidShiftAverage = 0.0;
449 B2DEBUG(175,
"Iteration: #" << nIterations <<
" (of max. " <<
m_maxIterations <<
")");
451 centroidShiftAverage = 0.0;
452 if (nIterations == 0) {
453 centroidList.clear();
454 centroidEnergyList.clear();
459 for (
const auto& locmaxpoint : localMaximumsPoints) {
462 const int locmaxcellid = locmaxpoint.first;
468 if (nIterations == 0) {
471 centroidEnergyList[locmaxcellid] = 1.5 * locmaxenergy;
474 B2DEBUG(175,
"local maximum cellid: " << locmaxcellid);
478 for (
const auto& digitpoint : allPoints) {
481 const int digitcellid = digitpoint.first;
489 double distance = 0.0;
490 double distanceEnergySum = 0.0;
493 for (
const auto& centroidpoint : centroidPoints) {
496 const int centroidcellid = centroidpoint.first;
497 B2Vector3D centroidpos = centroidpoint.second;
499 double thisdistance = 0.;
502 if (nIterations == 0 and digitcellid == centroidcellid) {
505 B2Vector3D vectorDistance = ((centroidpos) - (digitpos));
506 thisdistance = vectorDistance.
Mag();
514 if (locmaxcellid == centroidcellid) {
515 distance = thisdistance;
521 distanceEnergySum += (thisenergy * expfactor);
526 if (distanceEnergySum > 0.0) {
528 weight = energy * expfactor / distanceEnergySum;
540 B2WARNING(
"ECLCRSplitterModule::splitConnectedRegion: Floating point glitch, weight for this digit " << weight <<
541 ", resetting it to 1.0.");
546 B2DEBUG(175,
" cellid: " << digitcellid <<
", energy: " << digitenergy <<
", weight: " << weight <<
", distance: " << distance);
547 weights.push_back(weight);
552 B2Vector3D oldCentroidPos = (centroidPoints.find(locmaxcellid))->second;
558 const double newEnergy = Belle2::ECL::computeEnergySum(digits, weights);
561 const B2Vector3D centroidShift = (oldCentroidPos - newCentroidPos);
564 centroidList[locmaxcellid] = newCentroidPos;
565 weightMap[locmaxcellid] = weights;
567 B2DEBUG(175,
"--> inserting new energy: " << newEnergy <<
" for local maximum " << locmaxcellid);
568 centroidEnergyList[locmaxcellid] = newEnergy;
569 double showerenergy = (*centroidEnergyList.find(locmaxcellid)).second /
Belle2::Unit::MeV;
570 B2DEBUG(175,
"--> new energy = " << showerenergy <<
" MeV");
573 centroidShiftAverage += centroidShift.
Mag();
576 B2DEBUG(175,
" old centroid: " << oldCentroidPos.
X() <<
" cm, " << oldCentroidPos.
Y() <<
" cm, " << oldCentroidPos.
Z() <<
578 B2DEBUG(175,
" new centroid: " << newCentroidPos.
X() <<
" cm, " << newCentroidPos.
Y() <<
" cm, " << newCentroidPos.
Z() <<
580 B2DEBUG(175,
" centroid shift: " << centroidShift.
Mag() <<
" cm");
585 centroidShiftAverage /=
static_cast<double>(nLocalMaximums);
587 B2DEBUG(175,
"--> average centroid shift: " << centroidShiftAverage <<
" cm (tolerance is " <<
m_shiftTolerance <<
" cm)");
590 for (
const auto& locmaxpoint : localMaximumsPoints) {
591 centroidPoints[locmaxpoint.first] = (centroidList.find(locmaxpoint.first))->second;
596 }
while (nIterations < m_maxIterations and centroidShiftAverage >
m_shiftTolerance);
600 std::vector<int> markfordeletion;
601 iterateclusters =
false;
602 for (
const auto& locmaxpoint : localMaximumsPoints) {
605 const int locmaxcellid = locmaxpoint.first;
608 B2DEBUG(175,
"locmaxcellid: " << locmaxcellid);
610 B2DEBUG(175,
"ok: ");
613 std::vector < double > myWeights = (*weightMap.find(locmaxcellid)).second;
615 for (
unsigned int i = 0; i < digitVector.size(); ++i) {
618 const double weight = myWeights[i];
625 if ((energy * weight > lmenergy and cellid != locmaxcellid) or (energy * weight <
m_threshold and cellid == locmaxcellid)) {
626 markfordeletion.push_back(locmaxcellid);
627 iterateclusters =
true;
634 for (
const auto lmid : markfordeletion) {
635 localMaximumsPoints.erase(lmid);
636 centroidPoints.erase(lmid);
639 }
while (iterateclusters);
642 unsigned int iShower = 1;
643 for (
const auto& locmaxpoint : localMaximumsPoints) {
645 const int locmaxcellid = locmaxpoint.first;
661 std::vector<short int> neighbourlist = neighbourMap->
getNeighbours(locmaxcellid);
664 std::vector < double > myWeights = (*weightMap.find(locmaxcellid)).second;
667 std::vector<ECLCalDigit> newdigits;
668 std::vector<double> newweights;
669 double highestEnergy = 0.;
670 double highestEnergyTime = 0.;
671 double highestEnergyTimeResolution = 0.;
672 double weightSum = 0.0;
674 for (
unsigned int i = 0; i < digitVector.size(); ++i) {
677 const double weight = myWeights[i];
687 if (std::find(neighbourlist.begin(), neighbourlist.end(), cellid) != neighbourlist.end()) {
691 newdigits.push_back(dig);
692 newweights.push_back(weight);
698 if (energy * weight > highestEnergy) {
699 highestEnergy = energy * weight;
700 highestEnergyTime = dig.
getTime();
710 B2DEBUG(175,
"old theta: " << oldshowerposition->
Theta());
711 B2DEBUG(175,
"old phi: " << oldshowerposition->
Phi());
712 B2DEBUG(175,
"old R: " << oldshowerposition->
Mag());
713 B2DEBUG(175,
"old energy: " << energyEstimation);
714 delete oldshowerposition;
720 aECLShower->setTheta(showerposition->
Theta());
721 aECLShower->setPhi(showerposition->
Phi());
722 aECLShower->setR(showerposition->
Mag());
724 B2DEBUG(175,
"new theta: " << showerposition->
Theta());
725 B2DEBUG(175,
"new phi: " << showerposition->
Phi());
726 B2DEBUG(175,
"new R: " << showerposition->
Mag());
727 delete showerposition;
730 double showerEnergy = 0.0;
736 const unsigned int nOptimal =
static_cast<unsigned int>(nOptimalVec[0]);
737 aECLShower->setNominalNumberOfCrystalsForEnergy(
static_cast<double>(nOptimal));
741 aECLShower->setNOptimalGroupIndex(nOptimalVec[1]);
742 aECLShower->setNOptimalEnergyBin(nOptimalVec[2]);
743 aECLShower->setNOptimalEnergy(energyEstimation);
746 std::vector< std::pair<unsigned int, double>> listCrystalPairs;
747 listCrystalPairs.resize(newdigits.size());
749 std::vector < std::pair<double, double> > weighteddigits;
750 weighteddigits.resize(newdigits.size());
751 for (
unsigned int i = 0; i < newdigits.size(); ++i) {
752 weighteddigits.at(i) = std::make_pair((newdigits.at(i)).getEnergy(), newweights.at(i));
753 listCrystalPairs.at(i) = std::make_pair((newdigits.at(i)).getCellId(), newweights.at(i) * (newdigits.at(i)).getEnergy());
757 std::sort(listCrystalPairs.begin(), listCrystalPairs.end(), [](
const auto & left,
const auto & right) {
758 return left.second > right.second;
761 std::vector< unsigned int> listCrystals;
763 for (
unsigned int i = 0; i < newdigits.size(); ++i) {
765 listCrystals.push_back(listCrystalPairs[i].first);
769 aECLShower->setNumberOfCrystalsForEnergy(
static_cast<double>(listCrystals.size()));
770 aECLShower->setListOfCrystalsForEnergy(listCrystals);
773 B2DEBUG(175,
"Shower Energy (2): " << showerEnergy);
776 showerEnergy = Belle2::ECL::computeEnergySum(newdigits, newweights);
779 aECLShower->setEnergy(showerEnergy);
780 aECLShower->setEnergyRaw(showerEnergy);
781 aECLShower->setEnergyHighestCrystal(highestEnergy);
782 aECLShower->setTime(highestEnergyTime);
783 aECLShower->setDeltaTime99(highestEnergyTimeResolution);
784 aECLShower->setNumberOfCrystals(weightSum);
785 aECLShower->setCentralCellId(locmaxcellid);
787 B2DEBUG(175,
"new energy: " << showerEnergy);
790 aECLShower->setShowerId(iShower);
793 aECLShower->setConnectedRegionId(aCR.
getCRId());
796 aECLShower->addRelationTo(&aCR);
806 if (background <= 0.1)
return 21;
808 if (energy > 0.06 + 0.4 * background)
return 21;
829 int nOptimalNeighbours = (int)(0.5 +
m_nOptimal2D.GetBinContent(iGroup + 1, iEnergy + 1));
832 std::vector<int> nOptimalVector;
833 nOptimalVector.push_back(nOptimalNeighbours);
834 nOptimalVector.push_back(iGroup);
835 nOptimalVector.push_back(iEnergy);
837 B2DEBUG(175,
"ECLSplitterN1Module::getOptimalNumberOfDigits: cellID: " << cellid <<
" energy: " << energy <<
" iG: " << iGroup <<
838 " iE: " << iEnergy <<
" nOpt: " << nOptimalNeighbours);
840 return nOptimalVector;
847 double energysum = 0.;
849 std::sort(weighteddigits.begin(), weighteddigits.end(), [](
const auto & left,
const auto & right) {
850 return left.first * left.second > right.first * right.second;
854 unsigned int min = n;
855 if (weighteddigits.size() < n) min = weighteddigits.size();
857 for (
unsigned int i = 0; i < min; ++i) {
858 B2DEBUG(175,
"getEnergySum: " << weighteddigits.at(i).first <<
" " << weighteddigits.at(i).second);
859 energysum += (weighteddigits.at(i).first * weighteddigits.at(i).second);
861 B2DEBUG(175,
"getEnergySum: energysum=" << energysum);
870 double energyEstimation = 0.0;
882 energyEstimation += energyNeighbour;
885 return energyEstimation;
DataType Phi() const
The azimuth angle.
DataType Z() const
access variable Z (= .at(2) without boundary check)
DataType Theta() const
The polar angle.
DataType X() const
access variable X (= .at(0) without boundary check)
DataType Y() const
access variable Y (= .at(1) without boundary check)
DataType Mag() const
The magnitude (rho in spherical coordinate system).
Class to store calibrated ECLDigits: ECLCalDigits.
int getCellId() const
Get Cell ID.
double getEnergy() const
Get Calibrated Energy.
double getTimeResolution() const
Get Calibrated Time Resolution.
double getTime() const
Get Calibrated Time.
Class to store connected regions (CRs)
int getCRId() const
Get CR identifier.
Class to store local maxima (LM)
@ c_nPhotons
CR is split into n photons (N1)
ECLSplitterN1Module()
Constructor.
virtual const char * eclShowerArrayName() const
Default name ECLShowers.
ECL::ECLNeighbours * m_NeighbourMap9
Neighbour maps.
virtual const char * eventLevelClusteringInfoName() const
Name to be used for default option: EventLevelClusteringInfo.
double m_liloParameterB
lin-log parameter B
int m_maxIterations
Maximum number of iterations.
~ECLSplitterN1Module()
Destructor.
StoreArray< ECLShower > m_eclShowers
Store array: ECLShower.
ECL::ECLNeighbours * m_NeighbourMap21
5x5 neighbours excluding corners = 21
StoreArray< ECLConnectedRegion > m_eclConnectedRegions
Store array: ECLConnectedRegion.
double m_minimumSharedEnergy
Minimum shared energy.
const int m_nLeakReg
3 ECL regions: 0 = forward, 1 = barrel, 2 = backward
std::string m_positionMethod
Position calculation: lilo or linear.
void splitConnectedRegion(ECLConnectedRegion &aCR)
Split connected region into showers.
virtual void initialize() override
Initialize.
double m_cutDigitTimeResidualForEnergy
Maximum time residual to be included in the shower energy calculation.
StoreArray< ECLLocalMaximum > m_eclLocalMaximums
Store array: ECLLocalMaximum.
virtual void event() override
Event.
virtual const char * eclLocalMaximumArrayName() const
Default name ECLLocalMaximums.
double m_threshold
Local maximum threshold after splitting.
double estimateEnergy(const int centerid)
Estimate energy using 3x3 around central crystal.
virtual void endRun() override
End run.
virtual void terminate() override
Terminate.
std::vector< int > getOptimalNumberOfDigits(const int cellid, const double energy)
Get optimal number of digits (out of 21) based on first energy estimation and background level per ev...
ECL::ECLGeometryPar * m_geom
Geometry.
std::vector< int > m_cellIdInCR
list with all cellid of this connected region
double m_shiftTolerance
Tolerance level for centroid shifts.
DBObjPtr< ECLnOptimal > m_eclNOptimal
nOptimal payload
virtual void beginRun() override
Begin run.
int m_fullBkgdCount
Number of expected background digits at full background, FIXME: move to database.
int m_nEnergyBins
number of energies bins in nOptimal payload
const double c_molierRadius
Constant RM (Molier Radius) from exp(-a*dist/RM), http://pdg.lbl.gov/2009/AtomicNuclearProperties/HTM...
virtual const char * eclConnectedRegionArrayName() const
Default name ECLConnectedRegions.
int m_maxSplits
Maximum number of splits.
int m_useOptimalNumberOfDigitsForEnergy
Optimize the number of neighbours for energy calculations.
int getNeighbourMap(const double energy, const double background)
Get number of neighbours based on first energy estimation and background level per event.
double m_cutDigitEnergyForEnergy
Minimum digit energy to be included in the shower energy calculation.
virtual const char * eclCalDigitArrayName() const
Default name ECLCalDigits.
std::vector< double > m_liloParameters
lin-log parameters A, B, and C
std::vector< int > m_StoreArrPosition
vector (ECLElementNumbers::c_NCrystals + 1 entries) with cell id to store array positions
std::vector< int > m_StoreArrPositionLM
vector (ECLElementNumbers::c_NCrystals + 1 entries) with cell id to store array positions for LM
double m_liloParameterA
lin-log parameter A
StoreObjPtr< EventLevelClusteringInfo > m_eventLevelClusteringInfo
Store object pointer: EventLevelClusteringInfo.
std::vector< std::vector< float > > m_eBoundaries
energy boundaries each region
TH2F m_nOptimal2D
2D hist of nOptimal for Ebin vs groupID
std::vector< int > m_groupNumber
group number for each crystal
double getEnergySum(std::vector< std::pair< double, double > > &weighteddigits, const unsigned int n)
Get energy sum for weighted entries.
StoreArray< ECLCalDigit > m_eclCalDigits
Store array: ECLCalDigit.
double m_expConstant
Constant a from exp(-a*dist/RM), 1.5 to 2.5.
double m_liloParameterC
lin-log parameter C
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
ROOT::Math::XYZVector GetCrystalPos(int cid)
The Position of crystal.
Class to get the neighbours for a given cell id.
const std::vector< short int > & getNeighbours(short int cid) const
Return the neighbours for a given cell ID.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Class for type safe access to objects that are referred to in relations.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
RelationVector< T > getRelationsWith(const std::string &name="", const std::string &namedRelation="") const
Get the relations between this object and another store array.
static const double mm
[millimeters]
static const double keV
[kiloelectronvolt]
static const double MeV
[megaelectronvolt]
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
B2Vector3< double > B2Vector3D
typedef for common usage with double
bool isForward(int cellId)
Check whether the crystal is in forward ECL.
const int c_NCrystals
Number of crystals.
bool isBackward(int cellId)
Check whether the crystal is in backward ECL.
Abstract base class for different kinds of events.