16 #include <ecl/modules/eclClusterPSD/ECLClusterPSD.h>
19 #include <boost/algorithm/string/predicate.hpp>
22 #include <ecl/dataobjects/ECLShower.h>
23 #include <ecl/dataobjects/ECLCalDigit.h>
24 #include <ecl/geometry/ECLGeometryPar.h>
27 #include <mva/interface/Expert.h>
28 #include <mva/interface/Weightfile.h>
29 #include <mva/interface/Interface.h>
30 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
35 #include <framework/logging/Logger.h>
36 #include <framework/geometry/B2Vector3.h>
52 setDescription(
"Module uses offline two component fit results to compute pulse shape discrimation variables for particle identification.");
53 setPropertyFlags(c_ParallelProcessingCertified);
54 addParam(
"CrystalHadronEnergyThreshold", m_CrystalHadronEnergyThreshold,
55 "Hadron component energy threshold to identify as hadron digit.(GeV)", 0.003);
56 addParam(
"CrystalHadronIntensityThreshold", m_CrystalHadronIntensityThreshold,
57 "Hadron component intensity threshold to identify as hadron digit.", 0.005);
58 addParam(
"MVAidentifier", m_MVAidentifier,
"MVA database identifier.", std::string{
"eclClusterPSD_MVA"});
70 if (not(boost::ends_with(identifier,
".root") or boost::ends_with(identifier,
".xml"))) {
71 weightFileRepresentation = std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>(
new
92 if (weightFileRepresentation) {
94 if (weightFileRepresentation->hasChanged()) {
95 std::stringstream ss((*weightFileRepresentation)->m_data);
110 B2FATAL(
"Expecting " <<
m_numMVAvariables <<
" variables, found " << general_options.m_variables.size());
112 expert = supported_interfaces[general_options.m_method]->getExpert();
113 expert->load(weightfile);
117 std::vector<float> dummy(general_options.m_variables.size(), 0);
135 auto relatedDigits = cluster->getRelationsTo<
ECLCalDigit>();
138 std::vector<std::tuple<double, unsigned int>> EnergyToSort;
140 for (
unsigned int iRel = 0; iRel < relatedDigits.size(); iRel++) {
142 const auto caldigit = relatedDigits.object(iRel);
146 if (digitChi2 < 0)
continue;
156 EnergyToSort.emplace_back(caldigit->getTwoComponentTotalEnergy(), iRel);
161 std::sort(EnergyToSort.begin(), EnergyToSort.end(), std::greater<>());
164 const double showerR = cluster->getR();
165 const double showerTheta = cluster->getTheta();
166 const double showerPhi = cluster->getPhi();
171 size_t input_index{0};
174 for (
unsigned int digit = 0; digit <
maxdigits; ++digit) {
176 if (digit >= EnergyToSort.size())
break;
178 const auto [digitEnergy, next] = EnergyToSort[digit];
180 const auto caldigit = relatedDigits.object(next);
181 const double digitHadronEnergy = caldigit->getTwoComponentHadronEnergy();
182 const double digitOnlineEnergy = caldigit->getEnergy();
183 const double digitWeight = relatedDigits.weight(next);
185 const int digitFitType = digitFitType1;
186 const int cellId = caldigit->getCellId();
187 B2Vector3D calDigitPosition = geometry->GetCrystalPos(cellId - 1);
188 TVector3 tempP = showerPosition - calDigitPosition;
189 const double Rval = tempP.
Mag();
190 const double theVal = tempP.CosTheta();
191 const double phiVal = cos(tempP.Phi());
193 input[input_index++] = theVal;
194 input[input_index++] = phiVal;
195 input[input_index++] = Rval;
196 input[input_index++] = digitOnlineEnergy;
197 input[input_index++] = digitEnergy;
198 input[input_index++] = (digitHadronEnergy / digitEnergy);
199 input[input_index++] = digitFitType;
200 input[input_index++] = digitWeight;
205 while (input_index < input.size()) {
206 if (((input_index - 6) % 8) != 0) {
207 input[input_index++] = 0.0;
209 input[input_index++] = -1.0;
226 auto relatedDigits = shower.getRelationsTo<
ECLCalDigit>();
228 double cluster2CTotalEnergy = 0;
229 double cluster2CHadronEnergy = 0;
230 double numberofHadronDigits = 0;
231 double nWaveforminCluster = 0;
233 for (
unsigned int iRel = 0; iRel < relatedDigits.size(); iRel++) {
235 const auto weight = relatedDigits.weight(iRel);
237 const auto caldigit = relatedDigits.object(iRel);
238 const double digit2CChi2 = caldigit->getTwoComponentChi2();
240 if (digit2CChi2 < 0)
continue;
250 const double digit2CTotalEnergy = caldigit->getTwoComponentTotalEnergy();
251 const double digit2CHadronComponentEnergy = caldigit->getTwoComponentHadronEnergy();
253 cluster2CTotalEnergy += digit2CTotalEnergy;
254 cluster2CHadronEnergy += digit2CHadronComponentEnergy;
256 if (digit2CTotalEnergy < 0.6) {
259 const double digitHadronComponentIntensity = digit2CHadronComponentEnergy / digit2CTotalEnergy;
263 nWaveforminCluster += weight;
267 if (nWaveforminCluster > 0) {
268 if (cluster2CTotalEnergy != 0) shower.setShowerHadronIntensity(cluster2CHadronEnergy / cluster2CTotalEnergy);
271 shower.setPulseShapeDiscriminationMVA(mvaout);
273 shower.setNumberOfHadronDigits(numberofHadronDigits);
277 shower.setShowerHadronIntensity(0);
278 shower.setPulseShapeDiscriminationMVA(0.5);
279 shower.setNumberOfHadronDigits(0);