10#include <analysis/variables/MetaVariables.h>
11#include <analysis/variables/MCTruthVariables.h>
13#include <analysis/VariableManager/Utility.h>
14#include <analysis/dataobjects/Particle.h>
15#include <analysis/dataobjects/ParticleList.h>
16#include <analysis/dataobjects/EventKinematics.h>
17#include <analysis/utility/PCmsLabTransform.h>
18#include <analysis/utility/ReferenceFrame.h>
19#include <analysis/utility/EvtPDLUtil.h>
20#include <analysis/utility/ParticleCopy.h>
21#include <analysis/utility/ValueIndexPairSorting.h>
22#include <analysis/ClusterUtility/ClusterUtils.h>
23#include <analysis/variables/VariableFormulaConstructor.h>
25#include <framework/logging/Logger.h>
26#include <framework/datastore/StoreArray.h>
27#include <framework/datastore/StoreObjPtr.h>
28#include <framework/dataobjects/EventExtraInfo.h>
29#include <framework/utilities/Conversion.h>
30#include <framework/utilities/MakeROOTCompatible.h>
31#include <framework/gearbox/Const.h>
33#include <mdst/dataobjects/Track.h>
34#include <mdst/dataobjects/MCParticle.h>
35#include <mdst/dataobjects/ECLCluster.h>
36#include <mdst/dataobjects/TrackFitResult.h>
38#include <boost/algorithm/string.hpp>
44#include <unordered_set>
46#include <TDatabasePDG.h>
47#include <Math/Vector4D.h>
48#include <Math/VectorUtil.h>
56 double requireDoubleForFrameVariable(
const Variable::Manager::Var* var,
58 const std::string& frameFunction)
60 if (std::holds_alternative<double>(value)) {
61 return std::get<double>(value);
64 const char* returnedType = std::holds_alternative<int>(value) ?
"int" :
"bool";
65 B2ERROR(
"Meta function " << frameFunction <<
" expects a double variable, but '" << var->name
66 <<
"' returned " << returnedType <<
". Returning NaN.");
70 static int getDaughterIndex(
const std::string& daughterString,
const Particle* particle)
72 if (particle ==
nullptr)
return -1;
73 int daughterNumber = 0;
76 }
catch (std::invalid_argument&) {
77 auto daughterFunction = convertToInt({daughterString,
"-1"});
78 auto daughterVarResult = daughterFunction(particle);
79 daughterNumber = std::get<int>(daughterVarResult);
81 return daughterNumber;
86 if (arguments.size() == 1) {
88 auto func = [var](
const Particle * particle) ->
double {
89 UseReferenceFrame<RestFrame> frame(particle);
90 return requireDoubleForFrameVariable(var, var->function(particle),
"useRestFrame");
94 B2FATAL(
"Wrong number of arguments for meta function useRestFrame");
100 if (arguments.size() == 1) {
102 auto func = [var](
const Particle * particle) ->
double {
103 UseReferenceFrame<CMSFrame> frame;
104 return requireDoubleForFrameVariable(var, var->function(particle),
"useCMSFrame");
108 B2FATAL(
"Wrong number of arguments for meta function useCMSFrame");
114 if (arguments.size() == 1) {
116 auto func = [var](
const Particle * particle) ->
double {
117 UseReferenceFrame<LabFrame> frame;
118 return requireDoubleForFrameVariable(var, var->function(particle),
"useLabFrame");
122 B2FATAL(
"Wrong number of arguments for meta function useLabFrame");
128 if (arguments.size() == 2) {
130 const std::string daughterString = arguments[1];
131 auto func = [var, daughterString](
const Particle * particle) ->
double {
132 int daughterIndexTagB = getDaughterIndex(daughterString, particle);
133 if (daughterIndexTagB < 0)
136 if (particle->getPDGCode() != 300553)
138 B2ERROR(
"Variable should only be used on a Upsilon(4S) Particle List!");
143 ROOT::Math::PxPyPzEVector pSigB = T.getBeamFourMomentum() - particle->getDaughter(daughterIndexTagB)->get4Vector();
144 Particle tmp(pSigB, -particle->getDaughter(daughterIndexTagB)->getPDGCode());
146 UseReferenceFrame<RestFrame> frame(&tmp);
147 return requireDoubleForFrameVariable(var, var->function(particle),
"useTagSideRecoilRestFrame");
152 B2FATAL(
"Wrong number of arguments for meta function useTagSideRecoilRestFrame");
158 if (arguments.size() == 2) {
160 std::string listName = arguments[1];
161 auto func = [var, listName](
const Particle * particle) ->
double {
162 StoreObjPtr<ParticleList> list(listName);
163 unsigned listSize = list->getListSize();
167 B2WARNING(
"The selected ParticleList contains more than 1 Particles in this event. The variable useParticleRestFrame will use only the first candidate, and the result may not be the expected one."
168 << LogVar(
"ParticleList", listName)
169 << LogVar(
"Number of candidates in the list", listSize));
170 const Particle* p = list->getParticle(0);
171 UseReferenceFrame<RestFrame> frame(p);
172 return requireDoubleForFrameVariable(var, var->function(particle),
"useParticleRestFrame");
176 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
182 if (arguments.size() == 2) {
184 std::string listName = arguments[1];
185 auto func = [var, listName](
const Particle * particle) ->
double {
186 StoreObjPtr<ParticleList> list(listName);
187 unsigned listSize = list->getListSize();
191 B2WARNING(
"The selected ParticleList contains more than 1 Particles in this event. The variable useParticleRestFrame will use only the first candidate, and the result may not be the expected one."
192 << LogVar(
"ParticleList", listName)
193 << LogVar(
"Number of candidates in the list", listSize));
194 const Particle* p = list->getParticle(0);
196 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - p->get4Vector();
198 Particle pRecoil(recoil, 0);
199 pRecoil.setVertex(particle->getVertex());
200 UseReferenceFrame<RestFrame> frame(&pRecoil);
201 return requireDoubleForFrameVariable(var, var->function(particle),
"useRecoilParticleRestFrame");
205 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
211 if (arguments.size() >= 2) {
213 auto func = [var, arguments](
const Particle * particle) ->
double {
216 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
218 for (
unsigned int i = 1; i < arguments.size(); i++)
220 auto generalizedIndex = arguments[i];
221 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
223 pSum += dauPart->get4Vector();
227 Particle tmp(pSum, 0);
228 UseReferenceFrame<RestFrame> frame(&tmp);
229 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRestFrame");
233 B2FATAL(
"Wrong number of arguments for meta function useDaughterRestFrame.");
239 if (arguments.size() >= 2) {
241 auto func = [var, arguments](
const Particle * particle) ->
double {
244 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
246 for (
unsigned int i = 1; i < arguments.size(); i++)
248 auto generalizedIndex = arguments[i];
249 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
251 pSum += dauPart->get4Vector();
256 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - pSum;
258 Particle pRecoil(recoil, 0);
259 UseReferenceFrame<RestFrame> frame(&pRecoil);
260 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRecoilRestFrame");
264 B2FATAL(
"Wrong number of arguments for meta function useDaughterRecoilRestFrame.");
270 if (arguments.size() == 1) {
272 auto func = [var](
const Particle * particle) ->
double {
273 int index = ancestorBIndex(particle);
275 StoreArray<MCParticle> mcparticles;
276 Particle temp(mcparticles[index]);
277 UseReferenceFrame<RestFrame> frame(&temp);
278 return requireDoubleForFrameVariable(var, var->function(particle),
"useMCancestorBRestFrame");
282 B2FATAL(
"Wrong number of arguments for meta function useMCancestorBRestFrame.");
288 if (arguments.size() == 1) {
289 auto extraInfoName = arguments[0];
290 auto func = [extraInfoName](
const Particle * particle) ->
double {
291 if (particle ==
nullptr)
293 B2WARNING(
"Returns NaN because the particle is nullptr! If you want EventExtraInfo variables, please use eventExtraInfo() instead");
296 if (particle->hasExtraInfo(extraInfoName))
298 return particle->getExtraInfo(extraInfoName);
306 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
312 if (arguments.size() == 1) {
313 auto extraInfoName = arguments[0];
314 auto func = [extraInfoName](
const Particle*) ->
double {
315 StoreObjPtr<EventExtraInfo> eventExtraInfo;
316 if (not eventExtraInfo.isValid())
318 if (eventExtraInfo->hasExtraInfo(extraInfoName))
320 return eventExtraInfo->getExtraInfo(extraInfoName);
328 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
334 if (arguments.size() == 1) {
337 auto func = [var, key](
const Particle*) ->
double {
339 StoreObjPtr<EventExtraInfo> eventExtraInfo;
340 if (not eventExtraInfo.isValid())
341 eventExtraInfo.create();
342 if (eventExtraInfo->hasExtraInfo(key))
344 return eventExtraInfo->getExtraInfo(key);
348 auto var_result = var->function(
nullptr);
349 if (std::holds_alternative<double>(var_result)) {
350 value = std::get<double>(var_result);
351 }
else if (std::holds_alternative<int>(var_result)) {
352 return std::get<int>(var_result);
353 }
else if (std::holds_alternative<bool>(var_result)) {
354 return std::get<bool>(var_result);
356 eventExtraInfo->addExtraInfo(key, value);
362 B2FATAL(
"Wrong number of arguments for meta function eventCached");
368 if (arguments.size() == 1) {
371 auto func = [var, key](
const Particle * particle) ->
double {
373 if (particle->hasExtraInfo(key))
375 return particle->getExtraInfo(key);
378 double value = std::get<double>(var->function(particle));
386 const_cast<Particle*
>(particle)->addExtraInfo(key, value);
392 B2FATAL(
"Wrong number of arguments for meta function particleCached");
401 if (arguments.size() != 1) B2FATAL(
"Wrong number of arguments for meta function formula");
402 FormulaParser<VariableFormulaConstructor> parser;
404 return parser.parse(arguments[0]);
405 }
catch (std::runtime_error& e) {
412 if (arguments.size() <= 1) {
414 std::string cutString;
415 if (arguments.size() == 1)
416 cutString = arguments[0];
418 auto func = [cut](
const Particle*) ->
int {
420 int number_of_tracks = 0;
421 StoreArray<Track> tracks;
422 for (
const auto& track : tracks)
424 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(
Const::pion);
425 if (!trackFit)
continue;
426 if (trackFit->getChargeSign() == 0) {
430 if (cut->check(&particle))
435 return number_of_tracks;
440 B2FATAL(
"Wrong number of arguments for meta function nCleanedTracks");
446 if (arguments.size() <= 1) {
448 std::string cutString;
449 if (arguments.size() == 1)
450 cutString = arguments[0];
452 auto func = [cut](
const Particle*) ->
int {
454 int number_of_clusters = 0;
455 StoreArray<ECLCluster> clusters;
456 for (
const auto& cluster : clusters)
462 Particle particle(&cluster);
463 if (cut->check(&particle))
464 number_of_clusters++;
467 return number_of_clusters;
472 B2FATAL(
"Wrong number of arguments for meta function nCleanedECLClusters");
478 if (arguments.size() == 1) {
479 std::string cutString = arguments[0];
481 auto func = [cut](
const Particle * particle) ->
bool {
482 if (cut->check(particle))
489 B2FATAL(
"Wrong number of arguments for meta function passesCut");
495 if (arguments.size() == 1) {
496 std::string cutString = arguments[0];
498 auto func = [cut](
const Particle*) ->
bool {
499 if (cut->check(
nullptr))
506 B2FATAL(
"Wrong number of arguments for meta function passesEventCut");
512 if (arguments.size() == 2) {
516 }
catch (std::invalid_argument&) {
517 B2FATAL(
"The first argument of varFor meta function must be a positive integer!");
520 auto func = [pdgCode, var](
const Particle * particle) ->
double {
521 if (std::abs(particle->getPDGCode()) == std::abs(pdgCode))
523 auto var_result = var->function(particle);
524 if (std::holds_alternative<double>(var_result)) {
525 return std::get<double>(var_result);
526 }
else if (std::holds_alternative<int>(var_result)) {
527 return std::get<int>(var_result);
528 }
else if (std::holds_alternative<bool>(var_result)) {
529 return std::get<bool>(var_result);
535 B2FATAL(
"Wrong number of arguments for meta function varFor");
541 if (arguments.size() == 1) {
543 auto func = [var](
const Particle * particle) ->
double {
544 if (particle->getMCParticle())
549 auto var_result = var->function(particle);
550 if (std::holds_alternative<double>(var_result)) {
551 return std::get<double>(var_result);
552 }
else if (std::holds_alternative<int>(var_result)) {
553 return std::get<int>(var_result);
554 }
else if (std::holds_alternative<bool>(var_result)) {
555 return std::get<bool>(var_result);
562 B2FATAL(
"Wrong number of arguments for meta function varForMCGen");
568 if (arguments.size() == 1) {
569 std::string listName = arguments[0];
570 auto func = [listName](
const Particle * particle) ->
int {
573 StoreObjPtr<ParticleList> listOfParticles(listName);
575 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to nParticlesInList");
577 return listOfParticles->getListSize();
582 B2FATAL(
"Wrong number of arguments for meta function nParticlesInList");
588 if (arguments.size() != 2 && arguments.size() != 3) {
589 B2FATAL(
"nParticlesInCone requires a particle list, a cone half-angle in degrees, "
590 "and optionally a particle cut");
593 const std::string listName = arguments[0];
595 double angleDegrees = 0.;
598 }
catch (
const std::exception&) {
599 B2FATAL(
"Invalid cone half-angle: " << arguments[1]);
601 if (!std::isfinite(angleDegrees) || angleDegrees < 0. || angleDegrees > 180.) {
602 B2FATAL(
"The cone half-angle must be between 0 and 180 degrees");
604 const double cosineThreshold = std::cos(angleDegrees * std::acos(-1.) / 180.);
606 std::shared_ptr<Variable::Cut> cut;
607 if (arguments.size() == 3 && !arguments[2].empty()) {
611 return [listName, cosineThreshold, cut](
const Particle * particle) ->
double {
612 StoreObjPtr<ParticleList> particles(listName);
613 if (!particles.isValid())
615 B2FATAL(
"Invalid particle list in nParticlesInCone: " << listName);
618 const auto isSupported = [](
const Particle * candidate)
620 if (!candidate)
return false;
621 const auto source = candidate->getParticleSource();
622 return source == Particle::c_Track ||
623 source == Particle::c_ECLCluster ||
624 source == Particle::c_KLMCluster;
629 const auto labToCms = PCmsLabTransform().rotateLabToCms();
630 const auto central = labToCms * particle->get4Vector();
631 const double cx = central.Px();
632 const double cy = central.Py();
633 const double cz = central.Pz();
634 const double c2 = cx * cx + cy * cy + cz * cz;
637 const int ownSource = particle->getMdstSource();
638 std::unordered_set<int> countedSources;
641 for (
unsigned i = 0; i < particles->getListSize(); ++i)
643 const Particle* other = particles->getParticle(i);
644 if (!isSupported(other))
continue;
646 const int source = other->getMdstSource();
647 if (source == ownSource || countedSources.count(source))
continue;
648 if (cut && !cut->check(other))
continue;
650 const auto momentum = labToCms * other->get4Vector();
651 const double px = momentum.Px();
652 const double py = momentum.Py();
653 const double pz = momentum.Pz();
654 const double p2 = px * px + py * py + pz * pz;
655 if (!std::isfinite(p2) || p2 <= 0.)
continue;
657 double cosine = (cx * px + cy * py + cz * pz) / std::sqrt(c2 * p2);
658 if (cosine > 1.) cosine = 1.;
659 if (cosine < -1.) cosine = -1.;
661 if (cosine >= cosineThreshold && countedSources.insert(source).second) {
672 if (arguments.size() != 1) {
673 B2FATAL(
"Wrong number of arguments for isInList");
675 auto listName = arguments[0];
677 auto func = [listName](
const Particle * particle) ->
bool {
680 StoreObjPtr<ParticleList> list(listName);
681 if (!(list.isValid()))
683 B2FATAL(
"Invalid Listname " << listName <<
" given to isInList");
687 return list->contains(particle);
696 if (arguments.size() != 1) {
697 B2FATAL(
"Wrong number of arguments for sourceObjectIsInList");
699 auto listName = arguments[0];
701 auto func = [listName](
const Particle * particle) ->
int {
704 StoreObjPtr<ParticleList> list(listName);
705 if (!(list.isValid()))
707 B2FATAL(
"Invalid Listname " << listName <<
" given to sourceObjectIsInList");
713 if (particlesource == Particle::EParticleSourceObject::c_Composite
714 or particlesource == Particle::EParticleSourceObject::c_Undefined)
720 for (
unsigned i = 0; i < list->getListSize(); ++i)
722 const Particle* iparticle = list->getParticle(i);
723 if (particle->getMdstSource() == iparticle->getMdstSource())
735 if (arguments.size() != 1) {
736 B2FATAL(
"Wrong number of arguments for mcParticleIsInMCList");
738 auto listName = arguments[0];
740 auto func = [listName](
const Particle * particle) ->
bool {
743 StoreObjPtr<ParticleList> list(listName);
744 if (!(list.isValid()))
745 B2FATAL(
"Invalid Listname " << listName <<
" given to mcParticleIsInMCList");
748 const MCParticle* mcp = particle->getMCParticle();
749 if (mcp ==
nullptr)
return false;
752 for (
unsigned i = 0; i < list->getListSize(); ++i)
754 const MCParticle* imcp = list->getParticle(i)->getMCParticle();
755 if ((imcp !=
nullptr) and (mcp->getArrayIndex() == imcp->getArrayIndex()))
765 B2WARNING(
"isDaughterOfList is outdated and replaced by isDescendantOfList.");
766 std::vector<std::string> new_arguments = arguments;
767 new_arguments.push_back(std::string(
"1"));
768 return isDescendantOfList(new_arguments);
773 B2WARNING(
"isGrandDaughterOfList is outdated and replaced by isDescendantOfList.");
774 std::vector<std::string> new_arguments = arguments;
775 new_arguments.push_back(std::string(
"2"));
776 return isDescendantOfList(new_arguments);
781 if (arguments.size() > 0) {
782 auto listNames = arguments;
783 auto func = [listNames](
const Particle * particle) ->
bool {
785 int generation_flag = -1;
789 }
catch (
const std::exception& e) {}
791 for (
const auto& iListName : listNames)
796 }
catch (
const std::exception& e) {}
799 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
801 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
803 const Particle* daughter = m->getDaughter(i);
804 if ((flag == 1.) or (flag < 0)) {
805 if (p->isCopyOf(daughter)) {
811 if (daughter->getNDaughters() > 0) {
812 result = self(self, daughter, p, flag - 1);
822 StoreObjPtr<ParticleList> listOfParticles(iListName);
824 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isDescendantOfList");
826 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
827 Particle* iParticle = listOfParticles->getParticle(i);
828 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
838 B2FATAL(
"Wrong number of arguments for meta function isDescendantOfList");
844 if (arguments.size() > 0) {
845 auto listNames = arguments;
846 auto func = [listNames](
const Particle * particle) ->
bool {
848 int generation_flag = -1;
852 }
catch (
const std::exception& e) {}
854 if (particle->getMCParticle() ==
nullptr)
859 for (
const auto& iListName : listNames)
864 std::stod(iListName);
866 }
catch (
const std::exception& e) {}
868 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
870 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
872 const Particle* daughter = m->getDaughter(i);
873 if ((flag == 1.) or (flag < 0)) {
874 if (daughter->getMCParticle() !=
nullptr) {
875 if (p->getMCParticle()->getArrayIndex() == daughter->getMCParticle()->getArrayIndex()) {
881 if (daughter->getNDaughters() > 0) {
882 result = self(self, daughter, p, flag - 1);
892 StoreObjPtr<ParticleList> listOfParticles(iListName);
894 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isMCDescendantOfList");
896 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
897 Particle* iParticle = listOfParticles->getParticle(i);
898 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
908 B2FATAL(
"Wrong number of arguments for meta function isMCDescendantOfList");
914 if (arguments.size() == 1) {
916 auto func = [var](
const Particle * particle) ->
double {
917 double product = 1.0;
918 if (particle->getNDaughters() == 0)
922 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
924 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
925 product *= std::get<double>(var->function(particle->getDaughter(j)));
927 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
929 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
930 product *= std::get<int>(var->function(particle->getDaughter(j)));
937 B2FATAL(
"Wrong number of arguments for meta function daughterProductOf");
943 if (arguments.size() == 1) {
945 auto func = [var](
const Particle * particle) ->
double {
947 if (particle->getNDaughters() == 0)
951 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
953 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
954 sum += std::get<double>(var->function(particle->getDaughter(j)));
956 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
958 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
959 sum += std::get<int>(var->function(particle->getDaughter(j)));
966 B2FATAL(
"Wrong number of arguments for meta function daughterSumOf");
972 if (arguments.size() == 1) {
974 auto func = [var](
const Particle * particle) ->
double {
976 if (particle->getNDaughters() == 0)
980 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
982 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
983 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
984 if (std::isnan(iValue))
continue;
985 if (std::isnan(min)) min = iValue;
986 if (iValue < min) min = iValue;
988 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
990 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
991 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
992 if (std::isnan(min)) min = iValue;
993 if (iValue < min) min = iValue;
1000 B2FATAL(
"Wrong number of arguments for meta function daughterLowest");
1006 if (arguments.size() == 1) {
1008 auto func = [var](
const Particle * particle) ->
double {
1010 if (particle->getNDaughters() == 0)
1014 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
1016 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
1017 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
1018 if (std::isnan(iValue))
continue;
1019 if (std::isnan(max)) max = iValue;
1020 if (iValue > max) max = iValue;
1022 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
1024 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
1025 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
1026 if (std::isnan(max)) max = iValue;
1027 if (iValue > max) max = iValue;
1034 B2FATAL(
"Wrong number of arguments for meta function daughterHighest");
1040 if (arguments.size() == 3) {
1041 auto func = [arguments](
const Particle * particle) ->
double {
1042 if (particle ==
nullptr)
1044 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1045 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1046 auto variablename = arguments[2];
1047 if (dau_i ==
nullptr || dau_j ==
nullptr)
1049 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1053 auto result_j = var->function(dau_j);
1054 auto result_i = var->function(dau_i);
1056 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1058 diff = std::get<double>(result_j) - std::get<double>(result_i);
1059 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1061 diff = std::get<int>(result_j) - std::get<int>(result_i);
1064 throw std::runtime_error(
"Bad variant access");
1066 if (variablename ==
"phi" or variablename ==
"clusterPhi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)"))
1067 or std::regex_match(variablename, std::regex(
"use.*Frame\\(clusterPhi\\)")))
1069 if (fabs(diff) > M_PI) {
1071 diff = diff - 2 * M_PI;
1073 diff = 2 * M_PI + diff;
1081 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOf");
1087 if (arguments.size() == 3) {
1088 auto func = [arguments](
const Particle * particle) ->
double {
1089 if (particle ==
nullptr)
1091 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1092 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1093 auto variablename = arguments[2];
1094 if (dau_i ==
nullptr || dau_j ==
nullptr)
1096 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1099 const MCParticle* iMcDaughter = dau_i->getMCParticle();
1100 const MCParticle* jMcDaughter = dau_j->getMCParticle();
1101 if (iMcDaughter ==
nullptr || jMcDaughter ==
nullptr)
1103 Particle iTmpPart(iMcDaughter);
1104 Particle jTmpPart(jMcDaughter);
1106 auto result_j = var->function(&jTmpPart);
1107 auto result_i = var->function(&iTmpPart);
1109 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1111 diff = std::get<double>(result_j) - std::get<double>(result_i);
1112 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1114 diff = std::get<int>(result_j) - std::get<int>(result_i);
1117 throw std::runtime_error(
"Bad variant access");
1119 if (variablename ==
"phi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)")))
1121 if (fabs(diff) > M_PI) {
1123 diff = diff - 2 * M_PI;
1125 diff = 2 * M_PI + diff;
1133 B2FATAL(
"Wrong number of arguments for meta function mcDaughterDiffOf");
1139 if (arguments.size() == 5) {
1145 }
catch (std::invalid_argument&) {
1146 B2FATAL(
"First four arguments of grandDaughterDiffOf meta function must be integers!");
1148 std::vector<std::string> new_arguments;
1149 new_arguments.push_back(std::string(arguments[0] +
":" + arguments[2]));
1150 new_arguments.push_back(std::string(arguments[1] +
":" + arguments[3]));
1151 new_arguments.push_back(arguments[4]);
1152 return daughterDiffOf(new_arguments);
1154 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOf");
1160 if (arguments.size() == 3) {
1161 auto func = [arguments](
const Particle * particle) ->
double {
1162 if (particle ==
nullptr)
1164 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1165 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1166 if (!(dau_i && dau_j))
1168 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1172 double iValue, jValue;
1173 if (std::holds_alternative<double>(var->function(dau_j)))
1175 iValue = std::get<double>(var->function(dau_i));
1176 jValue = std::get<double>(var->function(dau_j));
1177 }
else if (std::holds_alternative<int>(var->function(dau_j)))
1179 iValue = std::get<int>(var->function(dau_i));
1180 jValue = std::get<int>(var->function(dau_j));
1182 return (jValue - iValue) / (jValue + iValue);
1186 B2FATAL(
"Wrong number of arguments for meta function daughterNormDiffOf");
1192 if (arguments.size() == 2) {
1193 const std::string daughterString = arguments[0];
1194 std::string variableName = arguments[1];
1195 auto func = [daughterString, variableName](
const Particle * particle) ->
double {
1196 if (particle ==
nullptr)
1198 int daughterNumber = getDaughterIndex(daughterString, particle);
1199 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1202 auto result_mother = var->function(particle);
1203 auto result_daughter = var->function(particle->getDaughter(daughterNumber));
1205 if (std::holds_alternative<double>(result_mother) && std::holds_alternative<double>(result_daughter))
1207 diff = std::get<double>(result_mother) - std::get<double>(result_daughter);
1208 }
else if (std::holds_alternative<int>(result_mother) && std::holds_alternative<int>(result_daughter))
1210 diff = std::get<int>(result_mother) - std::get<int>(result_daughter);
1213 throw std::runtime_error(
"Bad variant access");
1216 if (variableName ==
"phi" or variableName ==
"useCMSFrame(phi)")
1218 if (fabs(diff) > M_PI) {
1220 diff = diff - 2 * M_PI;
1222 diff = 2 * M_PI + diff;
1230 B2FATAL(
"Wrong number of arguments for meta function daughterMotherDiffOf");
1236 if (arguments.size() == 2) {
1237 const std::string daughterString = arguments[0];
1239 auto func = [var, daughterString](
const Particle * particle) ->
double {
1240 if (particle ==
nullptr)
1242 int daughterNumber = getDaughterIndex(daughterString, particle);
1243 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1245 double daughterValue = 0.0, motherValue = 0.0;
1246 if (std::holds_alternative<double>(var->function(particle)))
1248 daughterValue = std::get<double>(var->function(particle->getDaughter(daughterNumber)));
1249 motherValue = std::get<double>(var->function(particle));
1250 }
else if (std::holds_alternative<int>(var->function(particle)))
1252 daughterValue = std::get<int>(var->function(particle->getDaughter(daughterNumber)));
1253 motherValue = std::get<int>(var->function(particle));
1255 return (motherValue - daughterValue) / (motherValue + daughterValue);
1259 B2FATAL(
"Wrong number of arguments for meta function daughterMotherNormDiffOf");
1265 if (arguments.size() >= 1) {
1267 auto func = [arguments](
const Particle * particle) ->
double {
1268 if (particle ==
nullptr)
1273 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1274 for (
const auto& generalizedIndex : arguments)
1276 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1277 if (dauPart) pSum += frame.getMomentum(dauPart);
1279 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1285 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
1286 ROOT::Math::PxPyPzEVector pRecoil = frame.getMomentum(pIN - particle->get4Vector());
1288 return ROOT::Math::VectorUtil::Angle(pRecoil, pSum);
1292 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndRecoil");
1296 Manager::FunctionPtr angleBetweenDaughterAndMissingMomentum(
const std::vector<std::string>& arguments)
1298 if (arguments.size() >= 1) {
1299 auto func = [arguments](
const Particle * particle) ->
double {
1300 if (particle ==
nullptr)
1303 StoreObjPtr<EventKinematics> evtShape;
1306 B2WARNING(
"Cannot find missing momentum information, did you forget to run EventKinematicsModule?");
1309 ROOT::Math::XYZVector missingMomentumCMS = evtShape->getMissingMomentumCMS();
1310 ROOT::Math::PxPyPzEVector missingTotalMomentumCMS(missingMomentumCMS.X(),
1311 missingMomentumCMS.Y(),
1312 missingMomentumCMS.Z(),
1313 evtShape->getMissingEnergyCMS());
1315 ROOT::Math::PxPyPzEVector missingTotalMomentumLab = T.rotateCmsToLab() * missingTotalMomentumCMS;
1318 ROOT::Math::PxPyPzEVector pMiss = frame.getMomentum(missingTotalMomentumLab);
1320 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1321 for (
const auto& generalizedIndex : arguments)
1323 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1324 if (dauPart) pSum += frame.getMomentum(dauPart);
1326 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1331 return ROOT::Math::VectorUtil::Angle(pMiss, pSum);
1335 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndMissingMomentum");
1341 if (arguments.size() == 2 || arguments.size() == 3) {
1343 auto func = [arguments](
const Particle * particle) ->
double {
1344 if (particle ==
nullptr)
1347 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1351 for (
const auto& generalizedIndex : arguments)
1353 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1355 pDaus.push_back(frame.getMomentum(dauPart));
1357 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1363 if (pDaus.size() == 2)
1364 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1366 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1370 B2FATAL(
"Wrong number of arguments for meta function daughterAngle");
1374 double grandDaughterDecayAngle(
const Particle* particle,
const std::vector<double>& arguments)
1376 if (arguments.size() == 2) {
1381 int daughterIndex = std::lround(arguments[0]);
1382 if (daughterIndex >=
int(particle->getNDaughters()))
1384 const Particle* dau = particle->getDaughter(daughterIndex);
1386 int grandDaughterIndex = std::lround(arguments[1]);
1387 if (grandDaughterIndex >=
int(dau->getNDaughters()))
1390 ROOT::Math::XYZVector boost = dau->get4Vector().BoostToCM();
1392 ROOT::Math::PxPyPzEVector motherMomentum = - particle->get4Vector();
1393 motherMomentum = ROOT::Math::Boost(boost) * motherMomentum;
1395 ROOT::Math::PxPyPzEVector grandDaughterMomentum = dau->getDaughter(grandDaughterIndex)->get4Vector();
1396 grandDaughterMomentum = ROOT::Math::Boost(boost) * grandDaughterMomentum;
1398 return ROOT::Math::VectorUtil::Angle(motherMomentum, grandDaughterMomentum);
1401 B2FATAL(
"The variable grandDaughterDecayAngle needs exactly two integers as arguments!");
1407 if (arguments.size() == 2 || arguments.size() == 3) {
1409 auto func = [arguments](
const Particle * particle) ->
double {
1410 if (particle ==
nullptr)
1413 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1417 if (particle->getParticleSource() == Particle::EParticleSourceObject::c_MCParticle)
1419 for (
const auto& generalizedIndex : arguments) {
1420 const MCParticle* mcPart = particle->getMCParticle();
1421 if (mcPart ==
nullptr)
1423 const MCParticle* dauMcPart = mcPart->getParticleFromGeneralizedIndexString(generalizedIndex);
1424 if (dauMcPart ==
nullptr)
1427 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1431 for (
const auto& generalizedIndex : arguments) {
1432 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1433 if (dauPart ==
nullptr)
1436 const MCParticle* dauMcPart = dauPart->getMCParticle();
1437 if (dauMcPart ==
nullptr)
1440 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1445 if (pDaus.size() == 2)
1446 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1448 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1452 B2FATAL(
"Wrong number of arguments for meta function mcDaughterAngle");
1456 double daughterClusterAngleInBetween(
const Particle* particle,
const std::vector<double>& daughterIndices)
1458 if (daughterIndices.size() == 2) {
1459 int daughterIndexi = std::lround(daughterIndices[0]);
1460 int daughterIndexj = std::lround(daughterIndices[1]);
1461 if (std::max(daughterIndexi, daughterIndexj) >=
int(particle->getNDaughters())) {
1464 const ECLCluster* clusteri = particle->getDaughter(daughterIndexi)->getECLCluster();
1465 const ECLCluster* clusterj = particle->getDaughter(daughterIndexj)->getECLCluster();
1466 if (clusteri and clusterj) {
1470 ClusterUtils clusutils;
1471 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1472 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1473 return ROOT::Math::VectorUtil::Angle(pi, pj);
1477 }
else if (daughterIndices.size() == 3) {
1478 int daughterIndexi = std::lround(daughterIndices[0]);
1479 int daughterIndexj = std::lround(daughterIndices[1]);
1480 int daughterIndexk = std::lround(daughterIndices[2]);
1481 if (std::max(std::max(daughterIndexi, daughterIndexj), daughterIndexk) >=
int(particle->getNDaughters())) {
1484 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1485 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1486 const ECLCluster* clusterk = (particle->getDaughter(daughterIndices[2]))->getECLCluster();
1487 if (clusteri and clusterj and clusterk) {
1492 ClusterUtils clusutils;
1493 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1494 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1495 ROOT::Math::PxPyPzEVector pk = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterk, clusterkBit));
1496 return ROOT::Math::VectorUtil::Angle(pk, pi + pj);
1501 B2FATAL(
"Wrong number of arguments for daughterClusterAngleInBetween!");
1507 if (arguments.size() > 1) {
1508 auto func = [arguments](
const Particle * particle) ->
double {
1510 ROOT::Math::PxPyPzEVector pSum;
1512 for (
const auto& generalizedIndex : arguments)
1514 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1516 pSum += frame.getMomentum(dauPart);
1525 B2FATAL(
"Wrong number of arguments for meta function daughterInvM. At least two integers are needed.");
1531 if (arguments.size() == 2) {
1536 }
catch (std::invalid_argument&) {
1537 B2FATAL(
"Second argument of modulo meta function must be integer!");
1539 auto func = [var, divideBy](
const Particle * particle) ->
int {
1540 auto var_result = var->function(particle);
1541 if (std::holds_alternative<double>(var_result))
1543 return int(std::get<double>(var_result)) % divideBy;
1544 }
else if (std::holds_alternative<int>(var_result))
1546 return std::get<int>(var_result) % divideBy;
1547 }
else if (std::holds_alternative<bool>(var_result))
1549 return int(std::get<bool>(var_result)) % divideBy;
1554 B2FATAL(
"Wrong number of arguments for meta function modulo");
1560 if (arguments.size() == 1) {
1563 auto func = [var](
const Particle * particle) ->
bool {
return std::isnan(std::get<double>(var->function(particle))); };
1566 B2FATAL(
"Wrong number of arguments for meta function isNAN");
1572 if (arguments.size() == 2) {
1574 double defaultOutput;
1577 }
catch (std::invalid_argument&) {
1578 B2FATAL(
"The second argument of ifNANgiveX meta function must be a number!");
1580 auto func = [var, defaultOutput](
const Particle * particle) ->
double {
1581 double output = std::get<double>(var->function(particle));
1582 if (std::isnan(output))
return defaultOutput;
1587 B2FATAL(
"Wrong number of arguments for meta function ifNANgiveX");
1593 if (arguments.size() == 1) {
1596 auto func = [var](
const Particle * particle) ->
bool {
return std::isinf(std::get<double>(var->function(particle))); };
1599 B2FATAL(
"Wrong number of arguments for meta function isInfinity");
1605 if (arguments.size() >= 2) {
1611 for (
size_t i = 1; i < arguments.size(); ++i) {
1614 }
catch (std::invalid_argument&) {
1615 B2FATAL(
"The input flags to meta function unmask() should be integer!");
1621 auto func = [var, finalMask](
const Particle * particle) ->
double {
1623 auto var_result = var->function(particle);
1624 if (std::holds_alternative<double>(var_result))
1627 if (std::isnan(std::get<double>(var_result))) {
1630 value = int(std::get<double>(var_result));
1631 }
else if (std::holds_alternative<int>(var_result))
1633 value = std::get<int>(var_result);
1637 value &= (~finalMask);
1644 B2FATAL(
"Meta function unmask needs at least two arguments!");
1650 if (arguments.size() == 3) {
1652 std::string cutString = arguments[0];
1658 auto func = [cut, variableIfTrue, variableIfFalse](
const Particle * particle) ->
double {
1659 if (particle ==
nullptr)
1661 if (cut->check(particle))
1663 auto var_result = variableIfTrue->function(particle);
1664 if (std::holds_alternative<double>(var_result)) {
1665 return std::get<double>(var_result);
1666 }
else if (std::holds_alternative<int>(var_result)) {
1667 return std::get<int>(var_result);
1668 }
else if (std::holds_alternative<bool>(var_result)) {
1669 return std::get<bool>(var_result);
1673 auto var_result = variableIfFalse->function(particle);
1674 if (std::holds_alternative<double>(var_result)) {
1675 return std::get<double>(var_result);
1676 }
else if (std::holds_alternative<int>(var_result)) {
1677 return std::get<int>(var_result);
1678 }
else if (std::holds_alternative<bool>(var_result)) {
1679 return std::get<bool>(var_result);
1686 B2FATAL(
"Wrong number of arguments for meta function conditionalVariableSelector");
1692 if (arguments.size() > 0) {
1693 std::vector<const Variable::Manager::Var*> variables;
1694 for (
const auto& argument : arguments)
1697 auto func = [variables, arguments](
const Particle * particle) ->
double {
1698 double pValueProduct = 1.;
1699 for (
auto variable : variables)
1701 double pValue = std::get<double>(variable->function(particle));
1705 pValueProduct *= pValue;
1707 double pValueSum = 1.;
1708 double factorial = 1.;
1709 for (
unsigned int i = 1; i < arguments.size(); ++i)
1712 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1714 return pValueProduct * pValueSum;
1718 B2FATAL(
"Wrong number of arguments for meta function pValueCombination");
1724 if (arguments.size() == 1) {
1726 auto func = [var](
const Particle * particle) ->
double {
1727 double pValueProduct = 1.;
1728 if (particle->getNDaughters() == 0)
1733 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
1735 double pValue = std::get<double>(var->function(particle->getDaughter(j)));
1736 if (pValue < 0)
return -1;
1737 else pValueProduct *= pValue;
1740 double pValueSum = 1.;
1741 double factorial = 1.;
1742 for (
unsigned int i = 1; i < particle->getNDaughters(); ++i)
1745 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1747 return pValueProduct * pValueSum;
1751 B2FATAL(
"Wrong number of arguments for meta function pValueCombinationOfDaughters");
1757 if (arguments.size() == 1) {
1759 auto func = [var](
const Particle * particle) ->
double {
1760 auto var_result = var->function(particle);
1761 if (std::holds_alternative<double>(var_result))
1763 return std::abs(std::get<double>(var_result));
1764 }
else if (std::holds_alternative<int>(var_result))
1766 return std::abs(std::get<int>(var_result));
1771 B2FATAL(
"Wrong number of arguments for meta function abs");
1777 if (arguments.size() == 2) {
1782 B2FATAL(
"One or both of the used variables doesn't exist!");
1784 auto func = [var1, var2](
const Particle * particle) ->
double {
1785 double val1 = 0.0, val2 = 0.0;
1786 auto var_result1 = var1->function(particle);
1787 auto var_result2 = var2->function(particle);
1788 if (std::holds_alternative<double>(var_result1))
1790 val1 = std::get<double>(var_result1);
1791 }
else if (std::holds_alternative<int>(var_result1))
1793 val1 = std::get<int>(var_result1);
1794 }
else if (std::holds_alternative<bool>(var_result1))
1796 val1 = std::get<bool>(var_result1);
1799 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1801 if (std::holds_alternative<double>(var_result2))
1803 val2 = std::get<double>(var_result2);
1804 }
else if (std::holds_alternative<int>(var_result2))
1806 val2 = std::get<int>(var_result2);
1807 }
else if (std::holds_alternative<bool>(var_result2))
1809 val2 = std::get<bool>(var_result2);
1812 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1814 return std::max(val1, val2);
1818 B2FATAL(
"Wrong number of arguments for meta function max");
1824 if (arguments.size() == 2) {
1829 B2FATAL(
"One or both of the used variables doesn't exist!");
1831 auto func = [var1, var2](
const Particle * particle) ->
double {
1832 double val1 = 0.0, val2 = 0.0;
1833 auto var_result1 = var1->function(particle);
1834 auto var_result2 = var2->function(particle);
1835 if (std::holds_alternative<double>(var_result1))
1837 val1 = std::get<double>(var_result1);
1838 }
else if (std::holds_alternative<int>(var_result1))
1840 val1 = std::get<int>(var_result1);
1841 }
else if (std::holds_alternative<bool>(var_result1))
1843 val1 = std::get<bool>(var_result1);
1846 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1848 if (std::holds_alternative<double>(var_result2))
1850 val2 = std::get<double>(var_result2);
1851 }
else if (std::holds_alternative<int>(var_result2))
1853 val2 = std::get<int>(var_result2);
1854 }
else if (std::holds_alternative<bool>(var_result2))
1856 val2 = std::get<bool>(var_result2);
1859 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1861 return std::min(val1, val2);
1865 B2FATAL(
"Wrong number of arguments for meta function min");
1871 if (arguments.size() == 1) {
1873 auto func = [var](
const Particle * particle) ->
double {
1874 auto var_result = var->function(particle);
1875 if (std::holds_alternative<double>(var_result))
1876 return std::sin(std::get<double>(var_result));
1877 else if (std::holds_alternative<int>(var_result))
1878 return std::sin(std::get<int>(var_result));
1883 B2FATAL(
"Wrong number of arguments for meta function sin");
1889 if (arguments.size() == 1) {
1891 auto func = [var](
const Particle * particle) ->
double {
1892 auto var_result = var->function(particle);
1893 if (std::holds_alternative<double>(var_result))
1894 return std::asin(std::get<double>(var_result));
1895 else if (std::holds_alternative<int>(var_result))
1896 return std::asin(std::get<int>(var_result));
1901 B2FATAL(
"Wrong number of arguments for meta function asin");
1907 if (arguments.size() == 1) {
1909 auto func = [var](
const Particle * particle) ->
double {
1910 auto var_result = var->function(particle);
1911 if (std::holds_alternative<double>(var_result))
1912 return std::cos(std::get<double>(var_result));
1913 else if (std::holds_alternative<int>(var_result))
1914 return std::cos(std::get<int>(var_result));
1919 B2FATAL(
"Wrong number of arguments for meta function cos");
1925 if (arguments.size() == 1) {
1927 auto func = [var](
const Particle * particle) ->
double {
1928 auto var_result = var->function(particle);
1929 if (std::holds_alternative<double>(var_result))
1930 return std::acos(std::get<double>(var_result));
1931 else if (std::holds_alternative<int>(var_result))
1932 return std::acos(std::get<int>(var_result));
1937 B2FATAL(
"Wrong number of arguments for meta function acos");
1943 if (arguments.size() == 1) {
1945 auto func = [var](
const Particle * particle) ->
double {
return std::tan(std::get<double>(var->function(particle))); };
1948 B2FATAL(
"Wrong number of arguments for meta function tan");
1954 if (arguments.size() == 1) {
1956 auto func = [var](
const Particle * particle) ->
double {
return std::atan(std::get<double>(var->function(particle))); };
1959 B2FATAL(
"Wrong number of arguments for meta function atan");
1965 if (arguments.size() == 2) {
1968 auto func = [varY, varX](
const Particle * particle) ->
double {
1969 double y = std::get<double>(varY->function(particle));
1970 double x = std::get<double>(varX->function(particle));
1971 return std::atan2(y, x);
1975 B2FATAL(
"Wrong number of arguments for meta function atan2");
1981 if (arguments.size() == 1) {
1983 auto func = [var](
const Particle * particle) ->
double {
1984 auto var_result = var->function(particle);
1985 if (std::holds_alternative<double>(var_result))
1986 return std::exp(std::get<double>(var_result));
1987 else if (std::holds_alternative<int>(var_result))
1988 return std::exp(std::get<int>(var_result));
1993 B2FATAL(
"Wrong number of arguments for meta function exp");
1999 if (arguments.size() == 1) {
2001 auto func = [var](
const Particle * particle) ->
double {
2002 auto var_result = var->function(particle);
2003 if (std::holds_alternative<double>(var_result))
2004 return std::log(std::get<double>(var_result));
2005 else if (std::holds_alternative<int>(var_result))
2006 return std::log(std::get<int>(var_result));
2011 B2FATAL(
"Wrong number of arguments for meta function log");
2017 if (arguments.size() == 1) {
2019 auto func = [var](
const Particle * particle) ->
double {
2020 auto var_result = var->function(particle);
2021 if (std::holds_alternative<double>(var_result))
2022 return std::log10(std::get<double>(var_result));
2023 else if (std::holds_alternative<int>(var_result))
2024 return std::log10(std::get<int>(var_result));
2029 B2FATAL(
"Wrong number of arguments for meta function log10");
2035 if (arguments.size() == 1) {
2037 auto func = [var](
const Particle * particle) ->
double {
2038 if (particle ==
nullptr)
2041 StoreArray<Particle> particles;
2042 if (!particle->hasExtraInfo(
"original_index"))
2045 auto originalParticle = particles[particle->getExtraInfo(
"original_index")];
2046 if (!originalParticle)
2048 auto var_result = var->function(originalParticle);
2049 if (std::holds_alternative<double>(var_result))
2051 return std::get<double>(var_result);
2052 }
else if (std::holds_alternative<int>(var_result))
2054 return std::get<int>(var_result);
2055 }
else if (std::holds_alternative<bool>(var_result))
2057 return std::get<bool>(var_result);
2062 B2FATAL(
"Wrong number of arguments for meta function originalParticle");
2068 if (arguments.size() == 2) {
2069 const std::string daughterString = arguments[0];
2071 auto func = [var, daughterString](
const Particle * particle) ->
double {
2072 if (particle ==
nullptr)
2074 int daughterNumber = getDaughterIndex(daughterString, particle);
2075 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2077 auto var_result = var->function(particle->getDaughter(daughterNumber));
2078 if (std::holds_alternative<double>(var_result))
2080 return std::get<double>(var_result);
2081 }
else if (std::holds_alternative<int>(var_result))
2083 return std::get<int>(var_result);
2084 }
else if (std::holds_alternative<bool>(var_result))
2086 return std::get<bool>(var_result);
2091 B2FATAL(
"Wrong number of arguments for meta function daughter");
2097 if (arguments.size() == 2) {
2098 const std::string daughterString = arguments[0];
2100 auto func = [var, daughterString](
const Particle * particle) ->
double {
2101 if (particle ==
nullptr)
2103 int daughterNumber = getDaughterIndex(daughterString, particle);
2104 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2108 StoreArray<Particle> particles;
2109 if (!particle->getDaughter(daughterNumber)->hasExtraInfo(
"original_index"))
2111 auto originalDaughter = particles[particle->getDaughter(daughterNumber)->getExtraInfo(
"original_index")];
2112 if (!originalDaughter)
2115 auto var_result = var->function(originalDaughter);
2116 if (std::holds_alternative<double>(var_result)) {
2117 return std::get<double>(var_result);
2118 }
else if (std::holds_alternative<int>(var_result)) {
2119 return std::get<int>(var_result);
2120 }
else if (std::holds_alternative<bool>(var_result)) {
2121 return std::get<bool>(var_result);
2127 B2FATAL(
"Wrong number of arguments for meta function daughter");
2133 if (arguments.size() == 1) {
2134 std::string daughterString = arguments[0];
2135 auto func = [daughterString](
const Particle * particle) ->
int {
2136 return getDaughterIndex(daughterString, particle);
2140 B2FATAL(
"Wrong number of arguments for meta function convertToDaughterIndex");
2146 if (arguments.size() == 2) {
2147 const std::string daughterString = arguments[0];
2149 auto func = [var, daughterString](
const Particle * particle) ->
double {
2150 if (particle ==
nullptr)
2152 if (particle->getMCParticle())
2154 int daughterNumber = getDaughterIndex(daughterString, particle);
2155 if (daughterNumber >=
int(particle->getMCParticle()->getNDaughters()) or daughterNumber < 0)
2157 Particle tempParticle = Particle(particle->getMCParticle()->getDaughters().at(daughterNumber));
2158 auto var_result = var->function(&tempParticle);
2159 if (std::holds_alternative<double>(var_result)) {
2160 return std::get<double>(var_result);
2161 }
else if (std::holds_alternative<int>(var_result)) {
2162 return std::get<int>(var_result);
2163 }
else if (std::holds_alternative<bool>(var_result)) {
2164 return std::get<bool>(var_result);
2175 B2FATAL(
"Wrong number of arguments for meta function mcDaughter");
2181 if (arguments.size() == 1) {
2183 auto func = [var](
const Particle * particle) ->
double {
2184 if (particle ==
nullptr)
2186 if (particle->getMCParticle())
2188 if (particle->getMCParticle()->getMother() ==
nullptr) {
2191 Particle tempParticle = Particle(particle->getMCParticle()->getMother());
2192 auto var_result = var->function(&tempParticle);
2193 if (std::holds_alternative<double>(var_result)) {
2194 return std::get<double>(var_result);
2195 }
else if (std::holds_alternative<int>(var_result)) {
2196 return std::get<int>(var_result);
2197 }
else if (std::holds_alternative<bool>(var_result)) {
2198 return std::get<bool>(var_result);
2207 B2FATAL(
"Wrong number of arguments for meta function mcMother");
2213 if (arguments.size() == 2) {
2214 std::string indexString = arguments[0];
2217 auto func = [var, indexString](
const Particle * particle) ->
double {
2219 int particleNumber = 0;
2223 }
catch (std::invalid_argument&)
2225 auto indexFunction = convertToInt({indexString,
"-1"});
2226 auto indexVarResult = indexFunction(particle);
2227 particleNumber = std::get<int>(indexVarResult);
2230 StoreArray<MCParticle> mcParticles(
"MCParticles");
2231 if (particleNumber < 0 or particleNumber >= mcParticles.getEntries())
2236 const MCParticle* mcParticle = mcParticles[particleNumber];
2237 Particle part = Particle(mcParticle);
2238 auto var_result = var->function(&part);
2239 if (std::holds_alternative<double>(var_result))
2241 return std::get<double>(var_result);
2242 }
else if (std::holds_alternative<int>(var_result))
2244 return std::get<int>(var_result);
2245 }
else if (std::holds_alternative<bool>(var_result))
2247 return std::get<bool>(var_result);
2252 B2FATAL(
"Wrong number of arguments for meta function genParticle");
2258 if (arguments.size() == 1) {
2261 auto func = [var](
const Particle*) ->
double {
2262 StoreArray<MCParticle> mcParticles(
"MCParticles");
2263 if (mcParticles.getEntries() == 0)
2268 const MCParticle* mcUpsilon4S = mcParticles[0];
2269 if (mcUpsilon4S->isInitial()) mcUpsilon4S = mcParticles[2];
2270 if (mcUpsilon4S->getPDG() != 300553)
2275 Particle upsilon4S = Particle(mcUpsilon4S);
2276 auto var_result = var->function(&upsilon4S);
2277 if (std::holds_alternative<double>(var_result))
2279 return std::get<double>(var_result);
2280 }
else if (std::holds_alternative<int>(var_result))
2282 return std::get<int>(var_result);
2283 }
else if (std::holds_alternative<bool>(var_result))
2285 return std::get<bool>(var_result);
2290 B2FATAL(
"Wrong number of arguments for meta function genUpsilon4S");
2296 if (arguments.size() == 4) {
2297 std::string listName = arguments[0];
2298 std::string rankedVariableName = arguments[1];
2299 std::string returnVariableName = arguments[2];
2300 std::string extraInfoName = rankedVariableName +
"_rank";
2304 }
catch (std::invalid_argument&) {
2305 B2ERROR(
"3rd argument of getVariableByRank meta function (Rank) must be an integer!");
2310 auto func = [var, rank, extraInfoName, listName](
const Particle*)->
double {
2311 StoreObjPtr<ParticleList> list(listName);
2313 const unsigned int numParticles = list->getListSize();
2314 for (
unsigned int i = 0; i < numParticles; i++)
2316 const Particle* p = list->getParticle(i);
2317 if (p->getExtraInfo(extraInfoName) == rank) {
2318 auto var_result = var->function(p);
2319 if (std::holds_alternative<double>(var_result)) {
2320 return std::get<double>(var_result);
2321 }
else if (std::holds_alternative<int>(var_result)) {
2322 return std::get<int>(var_result);
2323 }
else if (std::holds_alternative<bool>(var_result)) {
2324 return std::get<bool>(var_result);
2329 return std::numeric_limits<double>::signaling_NaN();
2333 B2FATAL(
"Wrong number of arguments for meta function getVariableByRank");
2339 if (arguments.size() == 1 or arguments.size() == 2) {
2341 std::string listName = arguments[0];
2342 std::string cutString =
"";
2344 if (arguments.size() == 2) {
2345 cutString = arguments[1];
2350 auto func = [listName, cut](
const Particle*) ->
int {
2352 StoreObjPtr<ParticleList> list(listName);
2354 for (
unsigned int i = 0; i < list->getListSize(); i++)
2356 const Particle* particle = list->getParticle(i);
2357 if (cut->check(particle)) {
2365 B2FATAL(
"Wrong number of arguments for meta function countInList");
2371 if (arguments.size() == 2 or arguments.size() == 3) {
2373 std::string roeListName = arguments[0];
2374 std::string cutString = arguments[1];
2376 if (arguments.size() == 2) {
2377 B2INFO(
"Use pdgCode of electron as default in meta variable veto, other arguments: " << roeListName <<
", " << cutString);
2381 }
catch (std::invalid_argument&) {
2382 B2FATAL(
"Third argument of veto meta function must be integer!");
2389 auto func = [roeListName, cut, pdgCode, flavourType](
const Particle * particle) ->
bool {
2390 StoreObjPtr<ParticleList> roeList(roeListName);
2391 ROOT::Math::PxPyPzEVector vec = particle->get4Vector();
2392 for (
unsigned int i = 0; i < roeList->getListSize(); i++)
2394 const Particle* roeParticle = roeList->getParticle(i);
2395 if (not particle->overlapsWith(roeParticle)) {
2396 ROOT::Math::PxPyPzEVector tempCombination = roeParticle->get4Vector() + vec;
2397 std::vector<int> indices = { particle->getArrayIndex(), roeParticle->getArrayIndex() };
2398 Particle tempParticle = Particle(tempCombination, pdgCode, flavourType, indices, particle->getArrayPointer());
2399 if (cut->check(&tempParticle)) {
2408 B2FATAL(
"Wrong number of arguments for meta function veto");
2414 if (arguments.size() == 1) {
2415 std::string cutString = arguments[0];
2417 auto func = [cut](
const Particle * particle) ->
int {
2419 for (
auto& daughter : particle->getDaughters())
2421 if (cut->check(daughter))
2428 B2FATAL(
"Wrong number of arguments for meta function countDaughters");
2434 if (arguments.size() == 1) {
2435 std::string cutString = arguments[0];
2437 auto func = [cut](
const Particle * particle) ->
int {
2439 std::vector<const Particle*> fspDaughters;
2440 particle->fillFSPDaughters(fspDaughters);
2443 for (
auto& daughter : fspDaughters)
2445 if (cut->check(daughter))
2452 B2FATAL(
"Wrong number of arguments for meta function countFSPDaughters");
2458 if (arguments.size() == 1) {
2459 std::string cutString = arguments[0];
2461 auto func = [cut](
const Particle * particle) ->
int {
2463 std::vector<const Particle*> allDaughters;
2464 particle->fillAllDaughters(allDaughters);
2467 for (
auto& daughter : allDaughters)
2469 if (cut->check(daughter))
2476 B2FATAL(
"Wrong number of arguments for meta function countDescendants");
2480 Manager::FunctionPtr numberOfNonOverlappingParticles(
const std::vector<std::string>& arguments)
2483 auto func = [arguments](
const Particle * particle) ->
int {
2485 int _numberOfNonOverlappingParticles = 0;
2486 for (
const auto& listName : arguments)
2488 StoreObjPtr<ParticleList> list(listName);
2489 if (not list.isValid()) {
2490 B2FATAL(
"Invalid list named " << listName <<
" encountered in numberOfNonOverlappingParticles.");
2492 for (
unsigned int i = 0; i < list->getListSize(); i++) {
2493 const Particle* p = list->getParticle(i);
2494 if (not particle->overlapsWith(p)) {
2495 _numberOfNonOverlappingParticles++;
2499 return _numberOfNonOverlappingParticles;
2506 void appendDaughtersRecursive(Particle* mother, StoreArray<Particle>& container)
2509 auto* mcmother = mother->getRelated<MCParticle>();
2514 for (
auto* mcdaughter : mcmother->getDaughters()) {
2516 Particle tmp_daughter(mcdaughter);
2517 Particle* new_daughter = container.appendNew(tmp_daughter);
2518 new_daughter->addRelationTo(mcdaughter);
2519 mother->appendDaughter(new_daughter,
false);
2521 if (mcdaughter->getNDaughters() > 0)
2522 appendDaughtersRecursive(new_daughter, container);
2528 if (arguments.size() == 1) {
2530 auto func = [var](
const Particle * particle) ->
double {
2531 const MCParticle* mcp = particle->getMCParticle();
2536 StoreArray<Particle> tempParticles(
"tempParticles");
2537 tempParticles.clear();
2538 Particle tmpPart(mcp);
2539 Particle* newPart = tempParticles.appendNew(tmpPart);
2540 newPart->addRelationTo(mcp);
2542 appendDaughtersRecursive(newPart, tempParticles);
2544 auto var_result = var->function(newPart);
2545 if (std::holds_alternative<double>(var_result))
2547 return std::get<double>(var_result);
2548 }
else if (std::holds_alternative<int>(var_result))
2550 return std::get<int>(var_result);
2551 }
else if (std::holds_alternative<bool>(var_result))
2553 return std::get<bool>(var_result);
2558 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
2564 if (arguments.size() == 1) {
2567 auto func = [var](
const Particle * particle) ->
double {
2569 const ECLCluster* cluster = particle->getECLCluster();
2572 auto mcps = cluster->getRelationsTo<MCParticle>();
2575 std::vector<std::pair<double, int>> weightsAndIndices;
2576 for (
unsigned int i = 0; i < mcps.size(); ++i)
2577 weightsAndIndices.emplace_back(mcps.weight(i), i);
2580 std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
2581 ValueIndexPairSorting::higherPair<
decltype(weightsAndIndices)::value_type>);
2583 const MCParticle* mcp = mcps.object(weightsAndIndices[0].second);
2585 StoreArray<Particle> tempParticles(
"tempParticles");
2586 tempParticles.clear();
2587 Particle tmpPart(mcp);
2588 Particle* newPart = tempParticles.appendNew(tmpPart);
2589 newPart->addRelationTo(mcp);
2591 appendDaughtersRecursive(newPart, tempParticles);
2593 auto var_result = var->function(newPart);
2594 if (std::holds_alternative<double>(var_result))
2596 return std::get<double>(var_result);
2597 }
else if (std::holds_alternative<int>(var_result))
2599 return std::get<int>(var_result);
2600 }
else if (std::holds_alternative<bool>(var_result))
2602 return std::get<bool>(var_result);
2611 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCParticle");
2617 if (arguments.size() == 1) {
2620 auto func = [var](
const Particle * particle) ->
double {
2622 const ECLCluster* cluster = particle->getECLCluster();
2625 auto mcps = cluster->getRelationsTo<MCParticle>();
2628 std::map<int, double> mapMCParticleIndxAndWeight;
2629 getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
2632 if (mapMCParticleIndxAndWeight.size() == 0)
2636 auto maxMap = std::max_element(mapMCParticleIndxAndWeight.begin(), mapMCParticleIndxAndWeight.end(),
2637 [](
const auto & x,
const auto & y) { return x.second < y.second; }
2640 StoreArray<MCParticle> mcparticles;
2641 const MCParticle* mcKlong = mcparticles[maxMap->first];
2643 Particle tmpPart(mcKlong);
2644 auto var_result = var->function(&tmpPart);
2645 if (std::holds_alternative<double>(var_result))
2647 return std::get<double>(var_result);
2648 }
else if (std::holds_alternative<int>(var_result))
2650 return std::get<int>(var_result);
2651 }
else if (std::holds_alternative<bool>(var_result))
2653 return std::get<bool>(var_result);
2662 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCKlong");
2666 double matchedMCHasPDG(
const Particle* particle,
const std::vector<double>& pdgCode)
2668 if (pdgCode.size() != 1) {
2669 B2FATAL(
"Too many arguments provided to matchedMCHasPDG!");
2671 int inputPDG = std::lround(pdgCode[0]);
2673 const MCParticle* mcp = particle->getMCParticle();
2677 return std::abs(mcp->getPDG()) == inputPDG;
2682 if (arguments.size() == 1) {
2683 std::string listName = arguments[0];
2684 auto func = [listName](
const Particle * particle) ->
double {
2687 StoreObjPtr<ParticleList> listOfParticles(listName);
2689 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2690 double totalEnergy = 0;
2691 int nParticles = listOfParticles->getListSize();
2692 for (
int i = 0; i < nParticles; i++)
2694 const Particle* part = listOfParticles->getParticle(i);
2696 totalEnergy += frame.getMomentum(part).E();
2703 B2FATAL(
"Wrong number of arguments for meta function totalEnergyOfParticlesInList");
2709 if (arguments.size() == 1) {
2710 std::string listName = arguments[0];
2711 auto func = [listName](
const Particle*) ->
double {
2712 StoreObjPtr<ParticleList> listOfParticles(listName);
2714 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPxOfParticlesInList");
2716 int nParticles = listOfParticles->getListSize();
2718 for (
int i = 0; i < nParticles; i++)
2720 const Particle* part = listOfParticles->getParticle(i);
2721 totalPx += frame.getMomentum(part).Px();
2727 B2FATAL(
"Wrong number of arguments for meta function totalPxOfParticlesInList");
2733 if (arguments.size() == 1) {
2734 std::string listName = arguments[0];
2735 auto func = [listName](
const Particle*) ->
double {
2736 StoreObjPtr<ParticleList> listOfParticles(listName);
2738 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPyOfParticlesInList");
2740 int nParticles = listOfParticles->getListSize();
2742 for (
int i = 0; i < nParticles; i++)
2744 const Particle* part = listOfParticles->getParticle(i);
2745 totalPy += frame.getMomentum(part).Py();
2751 B2FATAL(
"Wrong number of arguments for meta function totalPyOfParticlesInList");
2757 if (arguments.size() == 1) {
2758 std::string listName = arguments[0];
2759 auto func = [listName](
const Particle*) ->
double {
2760 StoreObjPtr<ParticleList> listOfParticles(listName);
2762 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPzOfParticlesInList");
2764 int nParticles = listOfParticles->getListSize();
2766 for (
int i = 0; i < nParticles; i++)
2768 const Particle* part = listOfParticles->getParticle(i);
2769 totalPz += frame.getMomentum(part).Pz();
2775 B2FATAL(
"Wrong number of arguments for meta function totalPzOfParticlesInList");
2781 if (arguments.size() > 0) {
2783 auto func = [arguments](
const Particle * particle) ->
double {
2785 ROOT::Math::PxPyPzEVector total4Vector;
2787 std::vector<Particle*> particlePool;
2790 for (
const auto& argument : arguments)
2792 StoreObjPtr <ParticleList> listOfParticles(argument);
2794 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << argument <<
" given to invMassInLists");
2795 int nParticles = listOfParticles->getListSize();
2796 for (
int i = 0; i < nParticles; i++) {
2797 bool overlaps =
false;
2798 Particle* part = listOfParticles->getParticle(i);
2799 for (
const auto* poolPart : particlePool) {
2800 if (part->overlapsWith(poolPart)) {
2806 total4Vector += part->get4Vector();
2807 particlePool.push_back(part);
2811 double invariantMass = total4Vector.M();
2812 return invariantMass;
2817 B2FATAL(
"Wrong number of arguments for meta function invMassInLists");
2821 Manager::FunctionPtr totalECLEnergyOfParticlesInList(
const std::vector<std::string>& arguments)
2823 if (arguments.size() == 1) {
2824 std::string listName = arguments[0];
2825 auto func = [listName](
const Particle * particle) ->
double {
2828 StoreObjPtr<ParticleList> listOfParticles(listName);
2830 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2831 double totalEnergy = 0;
2832 int nParticles = listOfParticles->getListSize();
2833 for (
int i = 0; i < nParticles; i++)
2835 const Particle* part = listOfParticles->getParticle(i);
2836 const ECLCluster* cluster = part->getECLCluster();
2838 if (cluster !=
nullptr) {
2839 totalEnergy += cluster->getEnergy(clusterHypothesis);
2847 B2FATAL(
"Wrong number of arguments for meta function totalECLEnergyOfParticlesInList");
2853 if (arguments.size() == 1) {
2854 std::string listName = arguments[0];
2855 auto func = [listName](
const Particle*) ->
double {
2856 StoreObjPtr<ParticleList> listOfParticles(listName);
2858 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxPtInList");
2859 int nParticles = listOfParticles->getListSize();
2862 for (
int i = 0; i < nParticles; i++)
2864 const Particle* part = listOfParticles->getParticle(i);
2865 const double Pt = frame.getMomentum(part).Pt();
2866 if (Pt > maxPt) maxPt = Pt;
2872 B2FATAL(
"Wrong number of arguments for meta function maxPtInList");
2876 Manager::FunctionPtr eclClusterTrackMatchedWithCondition(
const std::vector<std::string>& arguments)
2878 if (arguments.size() <= 1) {
2880 std::string cutString;
2881 if (arguments.size() == 1)
2882 cutString = arguments[0];
2884 auto func = [cut](
const Particle * particle) ->
double {
2886 if (particle ==
nullptr)
2889 const ECLCluster* cluster = particle->getECLCluster();
2893 auto tracks = cluster->getRelationsFrom<Track>();
2895 for (
const auto& track : tracks) {
2898 if (cut->check(&trackParticle))
2907 B2FATAL(
"Wrong number of arguments for meta function eclClusterSpecialTrackMatched");
2913 if (arguments.size() == 2) {
2914 std::string listName = arguments[0];
2917 auto func = [listName, var](
const Particle*) ->
double {
2918 StoreObjPtr<ParticleList> listOfParticles(listName);
2920 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to averageValueInList");
2921 int nParticles = listOfParticles->getListSize();
2922 if (nParticles == 0)
2927 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2929 for (
int i = 0; i < nParticles; i++) {
2930 average += std::get<double>(var->function(listOfParticles->getParticle(i))) / nParticles;
2932 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2934 for (
int i = 0; i < nParticles; i++) {
2935 average += std::get<int>(var->function(listOfParticles->getParticle(i))) / nParticles;
2942 B2FATAL(
"Wrong number of arguments for meta function averageValueInList");
2948 if (arguments.size() == 2) {
2949 std::string listName = arguments[0];
2952 auto func = [listName, var](
const Particle*) ->
double {
2953 StoreObjPtr<ParticleList> listOfParticles(listName);
2955 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to medianValueInList");
2956 int nParticles = listOfParticles->getListSize();
2957 if (nParticles == 0)
2961 std::vector<double> valuesInList;
2962 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2964 for (
int i = 0; i < nParticles; i++) {
2965 valuesInList.push_back(std::get<double>(var->function(listOfParticles->getParticle(i))));
2967 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2969 for (
int i = 0; i < nParticles; i++) {
2970 valuesInList.push_back(std::get<int>(var->function(listOfParticles->getParticle(i))));
2973 std::sort(valuesInList.begin(), valuesInList.end());
2974 if (nParticles % 2 != 0)
2976 return valuesInList[nParticles / 2];
2979 return 0.5 * (valuesInList[nParticles / 2] + valuesInList[nParticles / 2 - 1]);
2984 B2FATAL(
"Wrong number of arguments for meta function medianValueInList");
2990 if (arguments.size() == 2) {
2991 std::string listName = arguments[0];
2994 auto func = [listName, var](
const Particle*) ->
double {
2995 StoreObjPtr<ParticleList> listOfParticles(listName);
2997 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to sumValueInList");
2998 int nParticles = listOfParticles->getListSize();
2999 if (nParticles == 0)
3004 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
3006 for (
int i = 0; i < nParticles; i++) {
3007 sum += std::get<double>(var->function(listOfParticles->getParticle(i)));
3009 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
3011 for (
int i = 0; i < nParticles; i++) {
3012 sum += std::get<int>(var->function(listOfParticles->getParticle(i)));
3019 B2FATAL(
"Wrong number of arguments for meta function sumValueInList");
3025 if (arguments.size() == 2) {
3026 std::string listName = arguments[0];
3029 auto func = [listName, var](
const Particle*) ->
double {
3030 StoreObjPtr<ParticleList> listOfParticles(listName);
3032 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to productValueInList");
3033 int nParticles = listOfParticles->getListSize();
3034 if (nParticles == 0)
3039 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
3041 for (
int i = 0; i < nParticles; i++) {
3042 product *= std::get<double>(var->function(listOfParticles->getParticle(i)));
3044 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
3046 for (
int i = 0; i < nParticles; i++) {
3047 product *= std::get<int>(var->function(listOfParticles->getParticle(i)));
3054 B2FATAL(
"Wrong number of arguments for meta function productValueInList");
3061 if (arguments.size() != 1)
3062 B2FATAL(
"Wrong number of arguments for meta function angleToClosestInList");
3064 std::string listname = arguments[0];
3066 auto func = [listname](
const Particle * particle) ->
double {
3068 StoreObjPtr<ParticleList> list(listname);
3069 if (not list.isValid())
3070 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToClosestInList");
3073 if (list->getListSize() == 0)
3078 const auto p_this = frame.getMomentum(particle);
3081 double minAngle = 2 * M_PI;
3082 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3084 const Particle* compareme = list->getParticle(i);
3085 const auto p_compare = frame.getMomentum(compareme);
3086 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3087 if (minAngle > angle) minAngle = angle;
3097 if (arguments.size() != 2)
3098 B2FATAL(
"Wrong number of arguments for meta function closestInList");
3100 std::string listname = arguments[0];
3105 auto func = [listname, var](
const Particle * particle) ->
double {
3107 StoreObjPtr<ParticleList> list(listname);
3108 if (not list.isValid())
3109 B2FATAL(
"Invalid particle list name " << listname <<
" given to closestInList");
3113 const auto p_this = frame.getMomentum(particle);
3116 double minAngle = 2 * M_PI;
3118 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3120 const Particle* compareme = list->getParticle(i);
3121 const auto p_compare = frame.getMomentum(compareme);
3122 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3123 if (minAngle > angle) {
3131 auto var_result = var->function(list->getParticle(iClosest));
3132 if (std::holds_alternative<double>(var_result))
3134 return std::get<double>(var_result);
3135 }
else if (std::holds_alternative<int>(var_result))
3137 return std::get<int>(var_result);
3138 }
else if (std::holds_alternative<bool>(var_result))
3140 return std::get<bool>(var_result);
3149 if (arguments.size() != 1)
3150 B2FATAL(
"Wrong number of arguments for meta function angleToMostB2BInList");
3152 std::string listname = arguments[0];
3154 auto func = [listname](
const Particle * particle) ->
double {
3156 StoreObjPtr<ParticleList> list(listname);
3157 if (not list.isValid())
3158 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToMostB2BInList");
3161 if (list->getListSize() == 0)
3166 const auto p_this = frame.getMomentum(particle);
3170 double maxAngle = 0;
3171 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3173 const Particle* compareme = list->getParticle(i);
3174 const auto p_compare = frame.getMomentum(compareme);
3175 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3176 if (maxAngle < angle) maxAngle = angle;
3186 if (arguments.size() != 1)
3187 B2FATAL(
"Wrong number of arguments for meta function deltaPhiToMostB2BPhiInList");
3189 std::string listname = arguments[0];
3191 auto func = [listname](
const Particle * particle) ->
double {
3193 StoreObjPtr<ParticleList> list(listname);
3194 if (not list.isValid())
3195 B2FATAL(
"Invalid particle list name " << listname <<
" given to deltaPhiToMostB2BPhiInList");
3198 if (list->getListSize() == 0)
3203 const auto phi_this = frame.getMomentum(particle).Phi();
3206 double maxAngle = 0;
3207 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3209 const Particle* compareme = list->getParticle(i);
3210 const auto phi_compare = frame.getMomentum(compareme).Phi();
3211 double angle = std::abs(phi_compare - phi_this);
3212 if (angle > M_PI) {angle = 2 * M_PI - angle;}
3213 if (maxAngle < angle) maxAngle = angle;
3223 if (arguments.size() != 2)
3224 B2FATAL(
"Wrong number of arguments for meta function mostB2BInList");
3226 std::string listname = arguments[0];
3231 auto func = [listname, var](
const Particle * particle) ->
double {
3233 StoreObjPtr<ParticleList> list(listname);
3234 if (not list.isValid())
3235 B2FATAL(
"Invalid particle list name " << listname <<
" given to mostB2BInList");
3239 const auto p_this = frame.getMomentum(particle);
3243 double maxAngle = -1.0;
3245 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3247 const Particle* compareme = list->getParticle(i);
3248 const auto p_compare = frame.getMomentum(compareme);
3249 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3250 if (maxAngle < angle) {
3258 auto var_result = var->function(list->getParticle(iMostB2B));
3259 if (std::holds_alternative<double>(var_result))
3261 return std::get<double>(var_result);
3262 }
else if (std::holds_alternative<int>(var_result))
3264 return std::get<int>(var_result);
3265 }
else if (std::holds_alternative<bool>(var_result))
3267 return std::get<bool>(var_result);
3275 if (arguments.size() == 1) {
3276 std::string listName = arguments[0];
3277 auto func = [listName](
const Particle*) ->
double {
3278 StoreObjPtr<ParticleList> listOfParticles(listName);
3280 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxOpeningAngleInList");
3281 int nParticles = listOfParticles->getListSize();
3286 double maxOpeningAngle = -1;
3287 for (
int i = 0; i < nParticles; i++)
3289 ROOT::Math::PxPyPzEVector v1 = frame.getMomentum(listOfParticles->getParticle(i));
3290 for (
int j = i + 1; j < nParticles; j++) {
3291 ROOT::Math::PxPyPzEVector v2 = frame.getMomentum(listOfParticles->getParticle(j));
3292 const double angle = ROOT::Math::VectorUtil::Angle(v1, v2);
3293 if (angle > maxOpeningAngle) maxOpeningAngle = angle;
3296 return maxOpeningAngle;
3300 B2FATAL(
"Wrong number of arguments for meta function maxOpeningAngleInList");
3307 if (arguments.size() >= 2) {
3312 auto func = [var, arguments](
const Particle * particle) ->
double {
3313 if (particle ==
nullptr)
3315 B2WARNING(
"Trying to access a daughter that does not exist. Skipping");
3321 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
3325 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++)
3327 auto generalizedIndex = arguments[iCoord];
3328 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
3330 pSum += frame.getMomentum(dauPart);
3332 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
3338 Particle sumOfDaughters(pSum, 100);
3340 auto var_result = var->function(&sumOfDaughters);
3342 if (std::holds_alternative<double>(var_result))
3344 return std::get<double>(var_result);
3345 }
else if (std::holds_alternative<int>(var_result))
3347 return std::get<int>(var_result);
3348 }
else if (std::holds_alternative<bool>(var_result))
3350 return std::get<bool>(var_result);
3355 B2FATAL(
"Wrong number of arguments for meta function daughterCombination");
3358 Manager::FunctionPtr useAlternativeDaughterHypothesis(
const std::vector<std::string>& arguments)
3371 if (arguments.size() >= 2) {
3382 std::unordered_map<unsigned int, int> mapOfReplacedDaughters;
3385 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++) {
3386 auto replacedDauString = arguments[iCoord];
3388 std::vector<std::string> indexAndMass;
3389 boost::split(indexAndMass, replacedDauString, boost::is_any_of(
":"));
3392 if (indexAndMass.size() > 2) {
3393 B2WARNING(
"The string indicating which daughter's mass should be replaced contains more than two elements separated by a colon. Perhaps you tried to pass a generalized index, which is not supported yet for this variable. The offending string is "
3394 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3398 if (indexAndMass.size() < 2) {
3399 B2WARNING(
"The string indicating which daughter's mass should be replaced contains only one colon-separated element instead of two. The offending string is "
3400 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3408 }
catch (std::invalid_argument&) {
3409 B2FATAL(
"Found the string " << indexAndMass[0] <<
"instead of a daughter index.");
3413 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(indexAndMass[1].c_str());
3415 B2WARNING(
"Particle not in evt.pdl file! " << indexAndMass[1]);
3420 int pdgCode = particlePDG->PdgCode();
3421 mapOfReplacedDaughters[dauIndex] = pdgCode;
3425 if (mapOfReplacedDaughters.size() != arguments.size() - 1)
3426 B2FATAL(
"Overlapped daughter's index is detected in the meta-variable useAlternativeDaughterHypothesis");
3434 auto func = [var, mapOfReplacedDaughters](
const Particle * particle) ->
double {
3435 if (particle ==
nullptr)
3437 B2WARNING(
"Trying to access a particle that does not exist. Skipping");
3447 ROOT::Math::PxPyPzMVector pSum(0, 0, 0, 0);
3449 for (
unsigned int iDau = 0; iDau < particle->getNDaughters(); iDau++)
3451 const Particle* dauPart = particle->getDaughter(iDau);
3453 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << iDau);
3457 ROOT::Math::PxPyPzMVector dauMom = ROOT::Math::PxPyPzMVector(frame.getMomentum(dauPart));
3461 pdgCode = mapOfReplacedDaughters.at(iDau);
3462 }
catch (std::out_of_range&) {
3469 double p_x = dauMom.Px();
3470 double p_y = dauMom.Py();
3471 double p_z = dauMom.Pz();
3472 dauMom.SetCoordinates(p_x, p_y, p_z, TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass());
3473 const_cast<Particle*
>(dummy->getDaughter(iDau))->set4VectorDividingByMomentumScaling(ROOT::Math::PxPyPzEVector(dauMom));
3476 const int charge = dummy->getDaughter(iDau)->getCharge();
3477 if (TDatabasePDG::Instance()->GetParticle(pdgCode)->Charge() / 3.0 == charge)
3478 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(pdgCode);
3480 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(-1 * pdgCode);
3486 dummy->set4Vector(ROOT::Math::PxPyPzEVector(pSum));
3488 auto var_result = var->function(dummy);
3491 if (std::holds_alternative<double>(var_result))
3493 return std::get<double>(var_result);
3494 }
else if (std::holds_alternative<int>(var_result))
3496 return std::get<int>(var_result);
3497 }
else if (std::holds_alternative<bool>(var_result))
3499 return std::get<bool>(var_result);
3505 B2FATAL(
"Wrong number of arguments for meta function useAlternativeDaughterHypothesis");
3510 if (arguments.size() == 2) {
3512 std::string arg = arguments[0];
3514 TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(arg.c_str());
3516 if (part !=
nullptr) {
3517 pdg_code = std::abs(part->PdgCode());
3521 }
catch (
const std::exception& e) {}
3524 if (pdg_code == -1) {
3525 B2FATAL(
"Ancestor " + arg +
" is not recognised. Please provide valid PDG code or particle name.");
3528 auto func = [pdg_code, var](
const Particle * particle) ->
double {
3529 const Particle* p = particle;
3531 int ancestor_level = std::get<double>(
Manager::Instance().getVariable(
"hasAncestor(" + std::to_string(pdg_code) +
", 0)")->function(p));
3532 if ((ancestor_level <= 0) or (std::isnan(ancestor_level)))
3537 const MCParticle* i_p = p->getMCParticle();
3539 for (
int a = 0; a < ancestor_level ; a = a + 1)
3541 i_p = i_p->getMother();
3544 StoreArray<Particle> tempParticles(
"tempParticles");
3545 tempParticles.clear();
3547 Particle* newPart = tempParticles.appendNew(m_p);
3548 newPart->addRelationTo(i_p);
3550 appendDaughtersRecursive(newPart, tempParticles);
3552 auto var_result = var->function(newPart);
3553 if (std::holds_alternative<double>(var_result))
3555 return std::get<double>(var_result);
3556 }
else if (std::holds_alternative<int>(var_result))
3558 return std::get<int>(var_result);
3559 }
else if (std::holds_alternative<bool>(var_result))
3561 return std::get<bool>(var_result);
3566 B2FATAL(
"Wrong number of arguments for meta function varForFirstMCAncestorOfType (expected 2: type and variable of interest)");
3572 if (arguments.size() > 4 || arguments.size() < 3) {
3573 B2FATAL(
"Number of arguments for varForNthDaughterOfType must be 3 or 4");
3576 std::string argPtype = arguments[0];
3577 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3578 TParticlePDG* part = pdgDatabase->GetParticle(argPtype.c_str());
3580 if (part !=
nullptr) {
3581 absPdg = std::abs(part->PdgCode());
3585 }
catch (
const std::exception&) { }
3587 if (absPdg == -1 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3588 B2FATAL(
"varForNthDaughterOfType: argument '" << argPtype <<
"' is neither a valid particle name nor a PDG code");
3591 std::string argIndex = arguments[1];
3595 }
catch (
const std::exception&) { }
3597 B2FATAL(
"varForNthDaughterOfType: argument '" << argIndex <<
"' is not a valid positive integer");
3603 if (arguments.size() == 4) {
3604 std::string argDepth = arguments[3];
3607 }
catch (
const std::exception&) {
3611 B2FATAL(
"varForNthDaughterOfType: argument '" << argDepth <<
"' is not a valid positive integer");
3615 auto func = [absPdg, index, var, depth](
const Particle * particle) ->
double {
3617 std::vector<Particle*> currentLevel = particle->getDaughters();
3618 std::vector<Particle*> nextLevel;
3619 for (
int d = 0; d < depth; d++)
3622 for (
unsigned i = 0; i < currentLevel.size(); i++) {
3623 Particle* p = currentLevel[i];
3624 if (std::abs(p->getPDGCode()) == absPdg) {
3626 if (nFound == index) {
3627 auto result = var->function(p);
3628 if (std::holds_alternative<double>(result)) {
3629 return std::get<double>(result);
3630 }
else if (std::holds_alternative<int>(result)) {
3631 return std::get<int>(result);
3632 }
else if (std::holds_alternative<bool>(result)) {
3633 return std::get<bool>(result);
3637 std::vector<Particle*> newParticles = p->getDaughters();
3638 nextLevel.insert(nextLevel.end(), newParticles.begin(), newParticles.end());
3640 currentLevel.clear();
3641 std::swap(currentLevel, nextLevel);
3651 if (arguments.size() != 1) {
3652 B2FATAL(
"Number of arguments for nTrackFitResults must be 1, particleType or PDGcode");
3655 std::string arg = arguments[0];
3656 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3657 TParticlePDG* part = pdgDatabase->GetParticle(arg.c_str());
3659 if (part !=
nullptr) {
3660 absPdg = std::abs(part->PdgCode());
3664 }
catch (
const std::exception&) {
3668 if (absPdg == 0 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3669 B2FATAL(
"nTrackFitResults: argument '" << arg <<
"' is neither a valid particle name nor a PDG code");
3673 auto func = [absPdg](
const Particle*) ->
int {
3675 Const::ChargedStable type(absPdg);
3676 StoreArray<Track> tracks;
3678 int nTrackFitResults = 0;
3680 for (
const auto& track : tracks)
3682 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(type);
3684 if (!trackFit)
continue;
3685 if (trackFit->getChargeSign() == 0)
continue;
3690 return nTrackFitResults;
3699 if (arguments.size() == 2) {
3702 auto func = [var, default_val](
const Particle * particle) ->
int {
3703 auto var_result = var->function(particle);
3704 if (std::holds_alternative<double>(var_result))
3706 double value = std::get<double>(var_result);
3707 if (value > std::numeric_limits<int>::max())
3708 value = std::numeric_limits<int>::max();
3709 if (value < std::numeric_limits<int>::min())
3710 value = std::numeric_limits<int>::min();
3711 if (std::isnan(value))
3712 value = default_val;
3713 return static_cast<int>(value);
3714 }
else if (std::holds_alternative<int>(var_result))
3715 return std::get<int>(var_result);
3716 else if (std::holds_alternative<bool>(var_result))
3717 return static_cast<int>(std::get<bool>(var_result));
3718 else return default_val;
3722 B2FATAL(
"Wrong number of arguments for meta function int, please provide variable name and replacement value for NaN!");
3726 VARIABLE_GROUP(
"MetaFunctions");
3727 REGISTER_METAVARIABLE(
"nCleanedECLClusters(cut)", nCleanedECLClusters,
3728 "[Eventbased] Returns the number of clean Clusters in the event\n"
3729 "Clean clusters are defined by the clusters which pass the given cut assuming a photon hypothesis.",
3730 Manager::VariableDataType::c_int);
3731 REGISTER_METAVARIABLE(
"nCleanedTracks(cut)", nCleanedTracks,
3732 "[Eventbased] Returns the number of clean Tracks in the event\n"
3733 "Clean tracks are defined by the tracks which pass the given cut assuming a pion hypothesis.", Manager::VariableDataType::c_int);
3734 REGISTER_METAVARIABLE(
"formula(v1 + v2 * [v3 - v4] / v5^v6)", formula, R
"DOCSTRING(
3735Returns the result of the given formula, where v1 to vN are variables or floating
3736point numbers. Currently the only supported operations are addition (``+``),
3737subtraction (``-``), multiplication (``*``), division (``/``) and power (``^``
3738or ``**``). Parenthesis can be in the form of square brackets ``[v1 * v2]``
3739or normal brackets ``(v1 * v2)``. It will work also with variables taking
3740arguments. Operator precedence is taken into account. For example ::
3742 (daughter(0, E) + daughter(1, E))**2 - p**2 + 0.138
3744.. versionchanged:: release-03-00-00
3745 now both, ``[]`` and ``()`` can be used for grouping operations, ``**`` can
3746 be used for exponent and float literals are possible directly in the
3748)DOCSTRING", Manager::VariableDataType::c_double);
3749 REGISTER_METAVARIABLE("useRestFrame(variable)", useRestFrame,
3750 "Returns the value of the variable using the rest frame of the given particle as current reference frame.\n"
3751 "E.g. ``useRestFrame(daughter(0, p))`` returns the total momentum of the first daughter in its mother's rest-frame", Manager::VariableDataType::c_double);
3752 REGISTER_METAVARIABLE(
"useCMSFrame(variable)", useCMSFrame,
3753 "Returns the value of the variable using the CMS frame as current reference frame.\n"
3754 "E.g. ``useCMSFrame(E)`` returns the energy of a particle in the CMS frame.", Manager::VariableDataType::c_double);
3755 REGISTER_METAVARIABLE(
"useLabFrame(variable)", useLabFrame, R
"DOC(
3756Returns the value of ``variable`` in the *lab* frame.
3759 The lab frame is the default reference frame, usually you don't need to use this meta-variable.
3760 E.g. ``useLabFrame(E)`` returns the energy of a particle in the Lab frame, same as just ``E``.
3762Specifying the lab frame is useful in some corner-cases. For example:
3763``useRestFrame(daughter(0, formula(E - useLabFrame(E))))`` which is the difference of the first daughter's energy in the rest frame of the mother (current particle) with the same daughter's lab-frame energy.
3764)DOC", Manager::VariableDataType::c_double);
3765 REGISTER_METAVARIABLE("useTagSideRecoilRestFrame(variable, daughterIndexTagB)", useTagSideRecoilRestFrame,
3766 "Returns the value of the variable in the rest frame of the recoiling particle to the tag side B meson.\n"
3767 "The variable should only be applied to an Upsilon(4S) list.\n"
3768 "E.g. ``useTagSideRecoilRestFrame(daughter(1, daughter(1, p)), 0)`` applied on a Upsilon(4S) list (``Upsilon(4S)->B+:tag B-:sig``) returns the momentum of the second daughter of the signal B meson in the signal B meson rest frame.", Manager::VariableDataType::c_double);
3769 REGISTER_METAVARIABLE(
"useParticleRestFrame(variable, particleList)", useParticleRestFrame,
3770 "Returns the value of the variable in the rest frame of the first Particle contained in the given ParticleList.\n"
3771 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3772 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3773 "computing the rest frame and a warning is thrown. If the given ParticleList is empty in an event, it returns NaN.", Manager::VariableDataType::c_double);
3774 REGISTER_METAVARIABLE(
"useRecoilParticleRestFrame(variable, particleList)", useRecoilParticleRestFrame,
3775 "Returns the value of the variable in the rest frame of recoil system against the first Particle contained in the given ParticleList.\n"
3776 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3777 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3778 "computing the rest frame and a warning is thrown. If the given ParticleList is empty in an event, it returns NaN.", Manager::VariableDataType::c_double);
3779 REGISTER_METAVARIABLE(
"useDaughterRestFrame(variable, daughterIndex_1[, daughterIndex_2, ... daughterIndex_3])", useDaughterRestFrame,
3780 "Returns the value of the variable in the rest frame of the selected daughter particle.\n"
3781 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3782 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3783 "If two or more indices are given, the rest frame of the sum of the daughters is used. "
3784 "By default only ``daughterIndex_1`` is given, in which case the rest frame of that single daughter is used.",
3785 Manager::VariableDataType::c_double);
3786 REGISTER_METAVARIABLE(
"useDaughterRecoilRestFrame(variable, daughterIndex_1[, daughterIndex_2, ... daughterIndex_3])", useDaughterRecoilRestFrame,
3787 "Returns the value of the variable in the rest frame of the recoil of the selected daughter particle.\n"
3788 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3789 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3790 "If two or more indices are given, the rest frame of the sum of the daughters is used. "
3791 "By default only ``daughterIndex_1`` is given, in which case the recoil rest frame of that single daughter is used.",
3792 Manager::VariableDataType::c_double);
3793 REGISTER_METAVARIABLE(
"useMCancestorBRestFrame(variable)", useMCancestorBRestFrame,
3794 "Returns the value of the variable in the rest frame of the ancestor B MC particle.\n"
3795 "If no B or no MC-matching is found, it returns NaN.", Manager::VariableDataType::c_double);
3796 REGISTER_METAVARIABLE(
"passesCut(cut)", passesCut,
3797 "Returns 1 if particle passes the cut otherwise 0.\n"
3798 "Useful if you want to write out if a particle would have passed a cut or not.", Manager::VariableDataType::c_bool);
3799 REGISTER_METAVARIABLE(
"passesEventCut(cut)", passesEventCut,
3800 "[Eventbased] Returns 1 if event passes the cut otherwise 0.\n"
3801 "Useful if you want to select events passing a cut without looping into particles, such as for skimming.\n", Manager::VariableDataType::c_bool);
3802 REGISTER_METAVARIABLE(
"countDaughters(cut)", countDaughters,
3803 "Returns number of direct daughters which satisfy the cut.\n"
3804 "Used by the skimming package (for what exactly?)", Manager::VariableDataType::c_int);
3805 REGISTER_METAVARIABLE(
"countFSPDaughters(cut)", countDescendants,
3806 "Returns number of final-state daughters which satisfy the cut.",
3807 Manager::VariableDataType::c_int);
3808 REGISTER_METAVARIABLE(
"countDescendants(cut)", countDescendants,
3809 "Returns number of descendants for all generations which satisfy the cut.",
3810 Manager::VariableDataType::c_int);
3811 REGISTER_METAVARIABLE(
"varFor(pdgCode, variable)", varFor,
3812 "Returns the value of the variable for the given particle if its abs(pdgCode) agrees with the given one.\n"
3813 "E.g. ``varFor(11, p)`` returns the momentum if the particle is an electron or a positron.", Manager::VariableDataType::c_double);
3814 REGISTER_METAVARIABLE(
"varForMCGen(variable)", varForMCGen,
3815 "Returns the value of the variable for the given particle if the MC particle related to it is primary, not virtual, and not initial.\n"
3816 "If no MC particle is related to the given particle, or the MC particle is not primary, virtual, or initial, NaN will be returned.\n"
3817 "E.g. ``varForMCGen(PDG)`` returns the PDG code of the MC particle related to the given particle if it is primary, not virtual, and not initial.", Manager::VariableDataType::c_double);
3818 REGISTER_METAVARIABLE(
"nParticlesInList(particleListName)", nParticlesInList,
3819 "[Eventbased] Returns number of particles in the given particle List.", Manager::VariableDataType::c_int);
3820 REGISTER_METAVARIABLE(
3821 "nParticlesInCone(particleListName, halfAngleDegrees, cut='')",
3824Counts distinct reconstructed final-state particles from Tracks, ECLClusters,
3825or KLMClusters within a cone around this particle in the e+e- centre-of-mass
3826frame. The half-angle is in degrees (0 to 180). The optional cut applies to
3827particles in particleListName. A particle sharing the central particle's MDST
3828source is excluded; each MDST source is counted at most once. An empty list
3829gives zero. Returns NaN if the central particle has an unsupported source or
3832 Manager::VariableDataType::c_double);
3834 REGISTER_METAVARIABLE("isInList(particleListName)", isInList,
3835 "Returns 1 if the particle is in the list provided, 0 if not. Note that this only checks the particle given. For daughters of composite particles, please see :b2:var:`isDaughterOfList`.", Manager::VariableDataType::c_bool);
3836 REGISTER_METAVARIABLE(
"isDaughterOfList(particleListNames)", isDaughterOfList,
3837 "Returns 1 if the given particle is a daughter of at least one of the particles in the given particle Lists.", Manager::VariableDataType::c_bool);
3838 REGISTER_METAVARIABLE(
"isDescendantOfList(particleListName[, anotherParticleListName, ..., generationFlag])", isDescendantOfList, R
"DOC(
3839 Returns 1 if the given particle appears in the decay chain of the particles in the given ParticleLists.
3841 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3843 * ``isDescendantOfList(<particle_list>,1)`` returns 1 if particle is a daughter of the list,
3844 * ``isDescendantOfList(<particle_list>,2)`` returns 1 if particle is a granddaughter of the list,
3845 * ``isDescendantOfList(<particle_list>,3)`` returns 1 if particle is a great-granddaughter of the list, etc.
3846 * Default value is ``-1`` that is inclusive for all generations.
3847 )DOC", Manager::VariableDataType::c_bool);
3848 REGISTER_METAVARIABLE("isMCDescendantOfList(particleListName[, anotherParticleListName, ..., generationFlag])", isMCDescendantOfList, R
"DOC(
3849 Returns 1 if the given particle is linked to the same MC particle as any reconstructed daughter of the decay lists.
3851 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3853 * ``isMCDescendantOfList(<particle_list>,1)`` returns 1 if particle is matched to the same particle as any daughter of the list,
3854 * ``isMCDescendantOfList(<particle_list>,2)`` returns 1 if particle is matched to the same particle as any granddaughter of the list,
3855 * ``isMCDescendantOfList(<particle_list>,3)`` returns 1 if particle is matched to the same particle as any great-granddaughter of the list, etc.
3856 * Default value is ``-1`` that is inclusive for all generations.
3858 It makes only sense for lists created with `fillParticleListFromMC` function with ``addDaughters=True`` argument.
3859 )DOC", Manager::VariableDataType::c_bool);
3861 REGISTER_METAVARIABLE("sourceObjectIsInList(particleListName)", sourceObjectIsInList, R
"DOC(
3862Returns 1 if the underlying mdst object (e.g. track, or cluster) was used to create a particle in ``particleListName``, 0 if not.
3865 This only makes sense for particles that are not composite. Returns -1 for composite particles.
3866)DOC", Manager::VariableDataType::c_int);
3868 REGISTER_METAVARIABLE("mcParticleIsInMCList(particleListName)", mcParticleIsInMCList, R
"DOC(
3869Returns 1 if the particle's matched MC particle is also matched to a particle in ``particleListName``
3870(or if either of the lists were filled from generator level `modularAnalysis.fillParticleListFromMC`.)
3872.. seealso:: :b2:var:`isMCDescendantOfList` to check daughters.
3873)DOC", Manager::VariableDataType::c_bool);
3875 REGISTER_METAVARIABLE("isGrandDaughterOfList(particleListNames)", isGrandDaughterOfList,
3876 "Returns 1 if the given particle is a grand daughter of at least one of the particles in the given particle Lists.", Manager::VariableDataType::c_bool);
3877 REGISTER_METAVARIABLE(
"originalParticle(variable)", originalParticle, R
"DOC(
3878 Returns value of variable for the original particle from which the given particle is copied.
3880 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3881 Returns NaN if the given particle is not copied and so there is no original particle.
3882 )DOC", Manager::VariableDataType::c_double);
3883 REGISTER_METAVARIABLE("daughter(i, variable)", daughter, R
"DOC(
3884 Returns value of variable for the i-th daughter. E.g.
3886 * ``daughter(0, p)`` returns the total momentum of the first daughter.
3887 * ``daughter(0, daughter(1, p)`` returns the total momentum of the second daughter of the first daughter.
3889 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3890 )DOC", Manager::VariableDataType::c_double);
3891 REGISTER_METAVARIABLE("originalDaughter(i, variable)", originalDaughter, R
"DOC(
3892 Returns value of variable for the original particle from which the i-th daughter is copied.
3894 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3895 Returns NaN if the daughter is not copied and so there is no original daughter.
3897 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3898 )DOC", Manager::VariableDataType::c_double);
3899 REGISTER_METAVARIABLE("mcDaughter(i, variable)", mcDaughter, R
"DOC(
3900 Returns the value of the requested variable for the i-th Monte Carlo daughter of the particle.
3902 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3903 or if the i-th MC daughter does not exist.
3905 E.g. ``mcDaughter(0, PDG)`` will return the PDG code of the first MC daughter of the matched MC
3906 particle of the reconstructed particle the function is applied to.
3908 The meta variable can also be nested: ``mcDaughter(0, mcDaughter(1, PDG))``.
3909 )DOC", Manager::VariableDataType::c_double);
3910 REGISTER_METAVARIABLE("mcMother(variable)", mcMother, R
"DOC(
3911 Returns the value of the requested variable for the Monte Carlo mother of the particle.
3913 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3914 or if the MC mother does not exist.
3916 E.g. ``mcMother(PDG)`` will return the PDG code of the MC mother of the matched MC
3917 particle of the reconstructed particle the function is applied to.
3919 The meta variable can also be nested: ``mcMother(mcMother(PDG))``.
3920 )DOC", Manager::VariableDataType::c_double);
3921 REGISTER_METAVARIABLE("genParticle(index, variable)", genParticle, R
"DOC(
3922[Eventbased] Returns the ``variable`` for the ith generator particle.
3923The arguments of the function must be the ``index`` of the particle in the MCParticle Array,
3924and ``variable``, the name of the function or variable for that generator particle.
3925If ``index`` goes beyond the length of the MCParticles array, NaN will be returned.
3927E.g. ``genParticle(0, p)`` returns the total momentum of the first MCParticle, which in a generic decay up to MC15 is
3928the Upsilon(4S) and for MC16 and beyond the initial electron.
3929)DOC", Manager::VariableDataType::c_double);
3930 REGISTER_METAVARIABLE("genUpsilon4S(variable)", genUpsilon4S, R
"DOC(
3931[Eventbased] Returns the ``variable`` evaluated for the generator-level :math:`\Upsilon(4S)`.
3932If no generator level :math:`\Upsilon(4S)` exists for the event, NaN will be returned.
3934E.g. ``genUpsilon4S(p)`` returns the total momentum of the :math:`\Upsilon(4S)` in a generic decay.
3935``genUpsilon4S(mcDaughter(1, p))`` returns the total momentum of the second daughter of the
3936generator-level :math:`\Upsilon(4S)` (i.e. the momentum of the second B meson in a generic decay).
3937)DOC", Manager::VariableDataType::c_double);
3938 REGISTER_METAVARIABLE("daughterProductOf(variable)", daughterProductOf,
3939 "Returns product of a variable over all daughters.\n"
3940 "E.g. ``daughterProductOf(extraInfo(SignalProbability))`` returns the product of the SignalProbabilitys of all daughters.", Manager::VariableDataType::c_double);
3941 REGISTER_METAVARIABLE(
"daughterSumOf(variable)", daughterSumOf,
3942 "Returns sum of a variable over all daughters.\n"
3943 "E.g. ``daughterSumOf(nDaughters)`` returns the number of grand-daughters.", Manager::VariableDataType::c_double);
3944 REGISTER_METAVARIABLE(
"daughterLowest(variable)", daughterLowest,
3945 "Returns the lowest value of the given variable among all daughters.\n"
3946 "E.g. ``useCMSFrame(daughterLowest(p))`` returns the lowest momentum in CMS frame.", Manager::VariableDataType::c_double);
3947 REGISTER_METAVARIABLE(
"daughterHighest(variable)", daughterHighest,
3948 "Returns the highest value of the given variable among all daughters.\n"
3949 "E.g. ``useCMSFrame(daughterHighest(p))`` returns the highest momentum in CMS frame.", Manager::VariableDataType::c_double);
3950 REGISTER_METAVARIABLE(
"daughterDiffOf(daughterIndex_i, daughterIndex_j, variable)", daughterDiffOf, R
"DOC(
3951 Returns the difference of a variable between the two given daughters.
3952 E.g. ``useRestFrame(daughterDiffOf(0, 1, p))`` returns the momentum difference between first and second daughter in the rest frame of the given particle.
3953 (That means that it returns :math:`p_j - p_i`)
3955 The daughters can be provided as generalized daughter indexes, which are simply colon-separated
3956 lists of daughter indexes, ordered starting from the root particle. For example, ``0:1``
3957 identifies the second daughter (1) of the first daughter (0) of the mother particle.
3959 )DOC", Manager::VariableDataType::c_double);
3960 REGISTER_METAVARIABLE("mcDaughterDiffOf(i, j, variable)", mcDaughterDiffOf,
3961 "MC matched version of the `daughterDiffOf` function.", Manager::VariableDataType::c_double);
3962 REGISTER_METAVARIABLE(
"grandDaughterDiffOf(i, j, variable)", grandDaughterDiffOf,
3963 "Returns the difference of a variable between the first daughters of the two given daughters.\n"
3964 "E.g. ``useRestFrame(grandDaughterDiffOf(0, 1, p))`` returns the momentum difference between the first daughters of the first and second daughter in the rest frame of the given particle.\n"
3965 "(That means that it returns :math:`p_j - p_i`)", Manager::VariableDataType::c_double);
3966 MAKE_DEPRECATED(
"grandDaughterDiffOf",
false,
"light-2402-ocicat", R
"DOC(
3967 The difference between any combination of (grand-)daughters can be calculated with the more general variable :b2:var:`daughterDiffOf`
3968 by using generalized daughter indexes.)DOC");
3969 REGISTER_METAVARIABLE("daughterNormDiffOf(i, j, variable)", daughterNormDiffOf,
3970 "Returns the normalized difference of a variable between the two given daughters.\n"
3971 "E.g. ``daughterNormDiffOf(0, 1, p)`` returns the normalized momentum difference between first and second daughter in the lab frame.", Manager::VariableDataType::c_double);
3972 REGISTER_METAVARIABLE(
"daughterMotherDiffOf(i, variable)", daughterMotherDiffOf,
3973 "Returns the difference of a variable between the given daughter and the mother particle itself.\n"
3974 "E.g. ``useRestFrame(daughterMotherDiffOf(0, p))`` returns the momentum difference between the given particle and its first daughter in the rest frame of the mother.", Manager::VariableDataType::c_double);
3975 REGISTER_METAVARIABLE(
"daughterMotherNormDiffOf(i, variable)", daughterMotherNormDiffOf,
3976 "Returns the normalized difference of a variable between the given daughter and the mother particle itself.\n"
3977 "E.g. ``daughterMotherNormDiffOf(1, p)`` returns the normalized momentum difference between the given particle and its second daughter in the lab frame.", Manager::VariableDataType::c_double);
3978 REGISTER_METAVARIABLE(
"angleBetweenDaughterAndRecoil(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndRecoil, R
"DOC(
3979 Returns the angle between the momentum recoiling against the particle and the sum of the momenta of the given daughters.
3980 The unit of the angle is ``rad``.
3982 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3983 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3984 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3985 identifies the second daughter of the root particle.
3987 At least one generalized index has to be given to ``angleBetweenDaughterAndRecoil``.
3990 ``angleBetweenDaughterAndRecoil(0)`` will return the angle between pRecoil and the momentum of the first daughter.
3992 ``angleBetweenDaughterAndRecoil(0, 1)`` will return the angle between pRecoil and the sum of the momenta of the first and second daughter.
3994 ``angleBetweenDaughterAndRecoil(0:0, 3:0)`` will return the angle between pRecoil and the sum of the momenta of the: first daughter of the first daughter, and
3995 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3996 REGISTER_METAVARIABLE("angleBetweenDaughterAndMissingMomentum(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndMissingMomentum, R
"DOC(
3997 Returns the angle between the missing momentum in the event and the sum of the momenta of the given daughters.
3998 The unit of the angle is ``rad``. EventKinematics module has to be called to use this.
4000 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
4001 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
4002 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
4003 identifies the second daughter of the root particle.
4005 At least one generalized index has to be given to ``angleBetweenDaughterAndMissingMomentum``.
4008 ``angleBetweenDaughterAndMissingMomentum(0)`` will return the angle between missMom and the momentum of the first daughter.
4010 ``angleBetweenDaughterAndMissingMomentum(0, 1)`` will return the angle between missMom and the sum of the momenta of the first and second daughter.
4012 ``angleBetweenDaughterAndMissingMomentum(0:0, 3:0)`` will return the angle between missMom and the sum of the momenta of the: first daughter of the first daughter, and
4013 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
4014 REGISTER_METAVARIABLE("daughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", daughterAngle, R
"DOC(
4015 Returns the angle in between any pair of particles belonging to the same decay tree.
4016 The unit of the angle is ``rad``.
4018 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
4019 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
4020 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
4021 identifies the second daughter of the root particle.
4023 Both two and three generalized indexes can be given to ``daughterAngle``. By default two indices are given, in
4024 which case the variable returns the angle between the momenta of the two given particles. If three indices are given, the
4025 variable returns the angle between the momentum of the third particle and a vector which is the sum of the
4026 first two daughter momenta.
4029 ``daughterAngle(0, 3)`` will return the angle between the first and fourth daughter.
4030 ``daughterAngle(0, 1, 3)`` will return the angle between the fourth daughter and the sum of the first and
4032 ``daughterAngle(0:0, 3:0)`` will return the angle between the first daughter of the first daughter, and
4033 the first daughter of the fourth daughter.
4035 )DOC", Manager::VariableDataType::c_double);
4036 REGISTER_METAVARIABLE("mcDaughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", mcDaughterAngle,
4037 "MC matched version of the `daughterAngle` function. Also works if applied directly to MC particles. "
4038 "As for `daughterAngle`, by default two indices are given and the angle between the momenta of the two given particles is returned; "
4039 "if a third index is given, the angle between the momentum of the third particle and the sum of the first two daughter momenta is returned. "
4040 "The unit of the angle is ``rad``", Manager::VariableDataType::c_double);
4041 REGISTER_VARIABLE(
"grandDaughterDecayAngle(i, j)", grandDaughterDecayAngle,
4042 "Returns the decay angle of the granddaughter in the daughter particle's rest frame.\n"
4043 "It is calculated with respect to the reverted momentum vector of the particle.\n"
4044 "Two arguments representing the daughter and granddaughter indices have to be provided as arguments.\n\n",
"rad");
4045 REGISTER_VARIABLE(
"daughterClusterAngleInBetween(i, j)", daughterClusterAngleInBetween,
4046 "Returns the angle between clusters associated to the two daughters."
4047 "If two indices given: returns the angle between the momenta of the clusters associated to the two given daughters."
4048 "If three indices given: returns the angle between the momentum of the third particle's cluster and a vector "
4049 "which is the sum of the first two daughter's cluster momenta."
4050 "Returns nan if any of the daughters specified don't have an associated cluster."
4051 "The arguments in the argument vector must be integers corresponding to the ith and jth (and kth) daughters.\n\n",
"rad");
4052 REGISTER_METAVARIABLE(
"daughterInvM(i[, j, ...])", daughterInvM, R
"DOC(
4053 Returns the invariant mass adding the Lorentz vectors of the given daughters. The unit of the invariant mass is GeV/:math:`\text{c}^2`
4054 E.g. ``daughterInvM(0, 1, 2)`` returns the invariant Mass :math:`m = \sqrt{(p_0 + p_1 + p_2)^2}` of the first, second and third daughter.
4055 At least the first index ``i`` is required; by default no further indices are given, in which case the mass of the single given daughter is returned.
4057 Daughters from different generations of the decay tree can be combined using generalized daughter indexes,
4058 which are simply colon-separated daughter indexes for each generation, starting from the root particle. For
4059 example, ``0:1:3`` identifies the fourth daughter (3) of the second daughter (1) of the first daughter(0) of
4060 the mother particle.
4062 Returns NaN if the given daughter-index is out of bound (>= number of daughters))DOC", Manager::VariableDataType::c_double);
4063 REGISTER_METAVARIABLE("extraInfo(name)", extraInfo,
4064 "Returns extra info stored under the given name.\n"
4065 "The extraInfo has to be set by a module first.\n"
4066 "E.g. ``extraInfo(SignalProbability)`` returns the SignalProbability calculated by the ``MVAExpert`` module.\n"
4067 "If nothing is set under the given name or if the particle is a nullptr, NaN is returned.\n"
4068 "In the latter case please use `eventExtraInfo` if you want to access an EventExtraInfo variable.", Manager::VariableDataType::c_double);
4069 REGISTER_METAVARIABLE(
"eventExtraInfo(name)", eventExtraInfo,
4070 "[Eventbased] Returns extra info stored under the given name in the event extra info.\n"
4071 "The extraInfo has to be set first by another module like MVAExpert in event mode.\n"
4072 "If nothing is set under this name, NaN is returned.", Manager::VariableDataType::c_double);
4073 REGISTER_METAVARIABLE(
"eventCached(variable)", eventCached,
4074 "[Eventbased] Returns value of event-based variable and caches this value in the EventExtraInfo.\n"
4075 "The result of second call to this variable in the same event will be provided from the cache.\n"
4076 "It is recommended to use this variable in order to declare custom aliases as event-based. This is "
4077 "necessary if using the eventwise mode of variablesToNtuple).", Manager::VariableDataType::c_double);
4078 REGISTER_METAVARIABLE(
"particleCached(variable)", particleCached,
4079 "Returns value of given variable and caches this value in the ParticleExtraInfo of the provided particle.\n"
4080 "The result of second call to this variable on the same particle will be provided from the cache.", Manager::VariableDataType::c_double);
4081 REGISTER_METAVARIABLE(
"modulo(variable, n)", modulo,
4082 "Returns rest of division of variable by n.", Manager::VariableDataType::c_int);
4083 REGISTER_METAVARIABLE(
"abs(variable)", abs,
4084 "Returns absolute value of the given variable.\n"
4085 "E.g. abs(mcPDG) returns the absolute value of the mcPDG, which is often useful for cuts.", Manager::VariableDataType::c_double);
4086 REGISTER_METAVARIABLE(
"max(var1,var2)", max,
"Returns max value of two variables.\n", Manager::VariableDataType::c_double);
4087 REGISTER_METAVARIABLE(
"min(var1,var2)", min,
"Returns min value of two variables.\n", Manager::VariableDataType::c_double);
4088 REGISTER_METAVARIABLE(
"sin(variable)", sin,
"Returns sine value of the given variable.", Manager::VariableDataType::c_double);
4089 REGISTER_METAVARIABLE(
"asin(variable)", asin,
"Returns arcsine of the given variable. The unit of the asin() is ``rad``", Manager::VariableDataType::c_double);
4090 REGISTER_METAVARIABLE(
"cos(variable)", cos,
"Returns cosine value of the given variable.", Manager::VariableDataType::c_double);
4091 REGISTER_METAVARIABLE(
"acos(variable)", acos,
"Returns arccosine value of the given variable. The unit of the acos() is ``rad``", Manager::VariableDataType::c_double);
4092 REGISTER_METAVARIABLE(
"tan(variable)", tan,
"Returns tangent value of the given variable.", Manager::VariableDataType::c_double);
4093 REGISTER_METAVARIABLE(
"atan(variable)", atan,
"Returns arctangent value of the given variable. The unit of the atan() is ``rad``", Manager::VariableDataType::c_double);
4094 REGISTER_METAVARIABLE(
"atan2(variableY, variableX)", atan2,
"Returns the atan2 value (arctangent of y/x). The result is in ``rad``, and the correct quadrant is determined by the signs of the two arguments. Both arguments must not be zero at the same time.", Manager::VariableDataType::c_double);
4095 REGISTER_METAVARIABLE(
"exp(variable)", exp,
"Returns exponential evaluated for the given variable.", Manager::VariableDataType::c_double);
4096 REGISTER_METAVARIABLE(
"log(variable)", log,
"Returns natural logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
4097 REGISTER_METAVARIABLE(
"log10(variable)", log10,
"Returns base-10 logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
4098 REGISTER_METAVARIABLE(
"int(variable, nan_replacement)", convertToInt, R
"DOC(
4099 Casts the output of the variable to an integer value.
4102 Overflow and underflow are clipped at maximum and minimum values, respectively. NaN values are replaced with the value of the 2nd argument.
4104 )DOC", Manager::VariableDataType::c_int);
4105 REGISTER_METAVARIABLE("isNAN(variable)", isNAN,
4106 "Returns true if variable value evaluates to nan (determined via std::isnan(double)).\n"
4107 "Useful for debugging.", Manager::VariableDataType::c_bool);
4108 REGISTER_METAVARIABLE(
"ifNANgiveX(variable, x)", ifNANgiveX,
4109 "Returns x (has to be a number) if variable value is nan (determined via std::isnan(double)).\n"
4110 "Useful for technical purposes while training MVAs.", Manager::VariableDataType::c_double);
4111 REGISTER_METAVARIABLE(
"isInfinity(variable)", isInfinity,
4112 "Returns true if variable value evaluates to infinity (determined via std::isinf(double)).\n"
4113 "Useful for debugging.", Manager::VariableDataType::c_bool);
4114 REGISTER_METAVARIABLE(
"unmask(variable, flag1, flag2, ...)", unmask,
4115 "unmask(variable, flag1, flag2, ...) or unmask(variable, mask) sets certain bits in the variable to zero.\n"
4116 "For example, if you want to set the second, fourth and fifth bits to zero, you could call \n"
4117 "``unmask(variable, 2, 8, 16)`` or ``unmask(variable, 26)``.\n"
4118 "", Manager::VariableDataType::c_double);
4119 REGISTER_METAVARIABLE(
"conditionalVariableSelector(cut, variableIfTrue, variableIfFalse)", conditionalVariableSelector,
4120 "Returns one of the two supplied variables, depending on whether the particle passes the supplied cut.\n"
4121 "The first variable is returned if the particle passes the cut, and the second variable is returned otherwise.", Manager::VariableDataType::c_double);
4122 REGISTER_METAVARIABLE(
"pValueCombination(p1, p2, ...)", pValueCombination,
4123 "Returns the combined p-value of the provided p-values according to the formula given in `Nucl. Instr. and Meth. A 411 (1998) 449 <https://doi.org/10.1016/S0168-9002(98)00293-9>`_ .\n"
4124 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4125 REGISTER_METAVARIABLE(
"pValueCombinationOfDaughters(variable)", pValueCombinationOfDaughters,
4126 "Returns the combined p-value of the daughter p-values according to the formula given in `Nucl. Instr. and Meth. A 411 (1998) 449 <https://doi.org/10.1016/S0168-9002(98)00293-9>`_ .\n"
4127 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4128 REGISTER_METAVARIABLE(
"veto(particleList, cut[, pdgCode])", veto,
4129 "Combines current particle with particles from the given particle list and returns 1 if the combination passes the provided cut. \n"
4130 "For instance one can apply this function on a signal Photon and provide a list of all photons in the rest of event and a cut \n"
4131 "around the neutral Pion mass (e.g. ``0.130 < M < 0.140``). \n"
4132 "If a combination of the signal Photon with a ROE photon fits this criteria, hence looks like a neutral pion, the veto-Metavariable will return 1 \n"
4133 "The default value of ``pdgCode`` is 11 (electron).", Manager::VariableDataType::c_bool);
4134 REGISTER_METAVARIABLE(
"matchedMC(variable)", matchedMC,
4135 "Returns variable output for the matched MCParticle by constructing a temporary Particle from it.\n"
4136 "This may not work too well if your variable requires accessing daughters of the particle.\n"
4137 "E.g. ``matchedMC(p)`` returns the total momentum of the related MCParticle.\n"
4138 "Returns NaN if no matched MCParticle exists.", Manager::VariableDataType::c_double);
4139 REGISTER_METAVARIABLE(
"clusterBestMatchedMCParticle(variable)", clusterBestMatchedMCParticle,
4140 "Returns variable output for the MCParticle that is best-matched with the ECLCluster of the given Particle.\n"
4141 "E.g. To get the energy of the MCParticle that matches best with an ECLCluster, one could use ``clusterBestMatchedMCParticle(E)``\n"
4142 "When the variable is called for ``gamma`` and if the ``gamma`` is matched with MCParticle, it works same as `matchedMC`.\n"
4143 "If the variable is called for ``gamma`` that fails to match with an MCParticle, it provides the mdst-level MCMatching information abouth the ECLCluster.\n"
4144 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching MCParticles", Manager::VariableDataType::c_double);
4145 REGISTER_METAVARIABLE(
"varForBestMatchedMCKlong(variable)", clusterBestMatchedMCKlong,
4146 "Returns variable output for the Klong MCParticle which has the best match with the ECLCluster of the given Particle.\n"
4147 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching Klong MCParticle", Manager::VariableDataType::c_double);
4149 REGISTER_METAVARIABLE(
"countInList(particleList[, cut])", countInList,
"[Eventbased] "
4150 "Returns number of particle which pass given in cut in the specified particle list.\n"
4151 "Useful for creating statistics about the number of particles in a list.\n"
4152 "E.g. ``countInList(e+, isSignal == 1)`` returns the number of correctly reconstructed electrons in the event.\n"
4153 "The default value of ``cut`` is an empty string, so all particles in the list are counted.\n"
4154 "The variable is event-based and does not need a valid particle pointer as input.", Manager::VariableDataType::c_int);
4155 REGISTER_METAVARIABLE(
"getVariableByRank(particleList, rankedVariableName, variableName, rank)", getVariableByRank, R
"DOC(
4156 [Eventbased] Returns the value of ``variableName`` for the candidate in the ``particleList`` with the requested ``rank``.
4159 The `BestCandidateSelection` module available via `rankByHighest` / `rankByLowest` has to be used before.
4162 The first candidate matching the given rank is used.
4163 Thus, it is not recommended to use this variable in conjunction with ``allowMultiRank`` in the `BestCandidateSelection` module.
4165 The suffix ``_rank`` is automatically added to the argument ``rankedVariableName``,
4166 which either has to be the name of the variable used to order the candidates or the selected outputVariable name without the ending ``_rank``.
4167 This means that your selected name for the rank variable has to end with ``_rank``.
4169 An example of this variable's usage is given in the tutorial `B2A602-BestCandidateSelection <https://gitlab.desy.de/belle2/software/basf2/-/tree/main/analysis/examples/tutorials/B2A602-BestCandidateSelection.py>`_
4170 )DOC", Manager::VariableDataType::c_double);
4171 REGISTER_VARIABLE("matchedMCHasPDG(PDGCode)", matchedMCHasPDG,
4172 "Returns if the absolute value of the PDGCode of the MCParticle related to the Particle matches a given PDGCode."
4173 "Returns 0/NAN/1 if PDGCode does not match/is not available/ matches");
4174 REGISTER_METAVARIABLE(
"numberOfNonOverlappingParticles(pList1, pList2, ...)", numberOfNonOverlappingParticles,
4175 "Returns the number of non-overlapping particles in the given particle lists"
4176 "Useful to check if there is additional physics going on in the detector if one reconstructed the Y4S", Manager::VariableDataType::c_int);
4177 REGISTER_METAVARIABLE(
"totalEnergyOfParticlesInList(particleListName)", totalEnergyOfParticlesInList,
4178 "[Eventbased] Returns the total energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4179 REGISTER_METAVARIABLE(
"totalPxOfParticlesInList(particleListName)", totalPxOfParticlesInList,
4180 "[Eventbased] Returns the total momentum Px of particles in the given particle List. The unit of the momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4181 REGISTER_METAVARIABLE(
"totalPyOfParticlesInList(particleListName)", totalPyOfParticlesInList,
4182 "[Eventbased] Returns the total momentum Py of particles in the given particle List. The unit of the momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4183 REGISTER_METAVARIABLE(
"totalPzOfParticlesInList(particleListName)", totalPzOfParticlesInList,
4184 "[Eventbased] Returns the total momentum Pz of particles in the given particle List. The unit of the momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4185 REGISTER_METAVARIABLE(
"invMassInLists(pList1, pList2, ...)", invMassInLists,
4186 "[Eventbased] Returns the invariant mass of the combination of particles in the given particle lists. The unit of the invariant mass is GeV/:math:`\\text{c}^2` ", Manager::VariableDataType::c_double);
4187 REGISTER_METAVARIABLE(
"totalECLEnergyOfParticlesInList(particleListName)", totalECLEnergyOfParticlesInList,
4188 "[Eventbased] Returns the total ECL energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4189 REGISTER_METAVARIABLE(
"maxPtInList(particleListName)", maxPtInList,
4190 "[Eventbased] Returns maximum transverse momentum Pt in the given particle List. The unit of the transverse momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4191 REGISTER_METAVARIABLE(
"eclClusterSpecialTrackMatched(cut)", eclClusterTrackMatchedWithCondition,
4192 "Returns if at least one Track that satisfies the given condition is related to the ECLCluster of the Particle.", Manager::VariableDataType::c_double);
4193 REGISTER_METAVARIABLE(
"averageValueInList(particleListName, variable)", averageValueInList,
4194 "[Eventbased] Returns the arithmetic mean of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4195 REGISTER_METAVARIABLE(
"medianValueInList(particleListName, variable)", medianValueInList,
4196 "[Eventbased] Returns the median value of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4197 REGISTER_METAVARIABLE(
"sumValueInList(particleListName, variable)", sumValueInList,
4198 "[Eventbased] Returns the sum of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4199 REGISTER_METAVARIABLE(
"productValueInList(particleListName, variable)", productValueInList,
4200 "[Eventbased] Returns the product of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4201 REGISTER_METAVARIABLE(
"angleToClosestInList(particleListName)", angleToClosestInList,
4202 "Returns the angle between this particle and the closest particle (smallest opening angle) in the list provided. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4203 REGISTER_METAVARIABLE(
"closestInList(particleListName, variable)", closestInList,
4204 "Returns `variable` for the closest particle (smallest opening angle) in the list provided.", Manager::VariableDataType::c_double);
4205 REGISTER_METAVARIABLE(
"angleToMostB2BInList(particleListName)", angleToMostB2BInList,
4206 "Returns the angle between this particle and the most back-to-back particle (closest opening angle to 180) in the list provided. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4207 REGISTER_METAVARIABLE(
"deltaPhiToMostB2BPhiInList(particleListName)", deltaPhiToMostB2BPhiInList,
4208 "Returns the abs(delta phi) between this particle and the most back-to-back particle in phi (closest opening angle to 180) in the list provided. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4209 REGISTER_METAVARIABLE(
"mostB2BInList(particleListName, variable)", mostB2BInList,
4210 "Returns `variable` for the most back-to-back particle (closest opening angle to 180) in the list provided.", Manager::VariableDataType::c_double);
4211 REGISTER_METAVARIABLE(
"maxOpeningAngleInList(particleListName)", maxOpeningAngleInList,
4212 "[Eventbased] Returns maximum opening angle in the given particle List. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4213 REGISTER_METAVARIABLE(
"daughterCombination(variable, daughterIndex_1, daughterIndex_2 ... daughterIndex_n)", daughterCombination,R
"DOC(
4214Returns a ``variable`` function only of the 4-momentum calculated on an arbitrary set of (grand)daughters.
4217 ``variable`` can only be a function of the daughters' 4-momenta.
4219Daughters from different generations of the decay tree can be combined using generalized daughter indexes, which are simply colon-separated
4220the list of daughter indexes, starting from the root particle: for example, ``0:1:3`` identifies the fourth
4221daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle.
4224 ``daughterCombination(M, 0, 3, 4)`` will return the invariant mass of the system made of the first, fourth and fifth daughter of particle.
4225 ``daughterCombination(M, 0:0, 3:0)`` will return the invariant mass of the system made of the first daughter of the first daughter and the first daughter of the fourth daughter.
4227)DOC", Manager::VariableDataType::c_double);
4228 REGISTER_METAVARIABLE("useAlternativeDaughterHypothesis(variable, daughterIndex_1:newMassHyp_1, ..., daughterIndex_n:newMassHyp_n)", useAlternativeDaughterHypothesis,R
"DOC(
4229Returns a ``variable`` calculated using new mass hypotheses for (some of) the particle's daughters.
4232 ``variable`` can only be a function of the particle 4-momentum, which is re-calculated as the sum of the daughters' 4-momenta, and the daughters' 4-momentum.
4233 This means that if you made a kinematic fit without updating the daughters' momenta, the result of this variable will not reflect the effect of the kinematic fit.
4234 Also, the track fit is not performed again: the variable only re-calculates the 4-vectors using different mass assumptions.
4235 In the variable, a copy of the given particle is created with daughters' alternative mass assumption (i.e. the original particle and daughters are not changed).
4238 Generalized daughter indexes are not supported (yet!): this variable can be used only on first-generation daughters.
4241 ``useAlternativeDaughterHypothesis(M, 0:K+, 2:pi-)`` will return the invariant mass of the particle assuming that the first daughter is a kaon and the third is a pion, instead of whatever was used in reconstructing the decay.
4242 ``useAlternativeDaughterHypothesis(mRecoil, 1:p+)`` will return the recoil mass of the particle assuming that the second daughter is a proton instead of whatever was used in reconstructing the decay.
4244)DOC", Manager::VariableDataType::c_double);
4245 REGISTER_METAVARIABLE("varForFirstMCAncestorOfType(type, variable)",varForFirstMCAncestorOfType,R
"DOC(Returns requested variable of the first ancestor of the given type.
4246Ancestor type can be set up by PDG code or by particle name (check evt.pdl for valid particle names))DOC", Manager::VariableDataType::c_double);
4247 REGISTER_METAVARIABLE("varForNthDaughterOfType(type, n, variable[, maxDepth])",varForNthDaughterOfType,R
"DOC(Returns requested variable for nth daughter (``n`` starting at 1) of the given type.
4248Particle type can be given as pdg code or by particle name (particles and antiparticles are treated the same, so e.g. ``211``, ``-211``, ``pi+`` and ``pi-`` will all match all charged pions).
4249Maximal depth controls how many generations of daughters are searched (``maxDepth=1`` only direct daughters, ``maxDepth=2`` also granddaughters, ...). The default value of ``maxDepth`` is 1.
4250As an example, when reconstructing ``B0:my_list -> [K_S0:pipi -> pi+:all pi-:all] [pi0:gg -> gamma:all gamma:all]`` then ``varForNthDaughterOfType(pi+, 1, E, 2)`` will return the energy of the first charged pion found searching all daughters and then granddaughters of the given particle, so in this case the pi+, and ``varForNthDaughterOfType(22, 2, E, 2)`` will return the energy of the second daughter of the pi0. (Note that the kinematic distributions of the two pi0 daughters are not the same, unless the ``gamma:all`` list was shuffled beforehand!)
4251If no nth daughter of the given type can be found at given maximal depth, returns NaN.)DOC", Manager::VariableDataType::c_double);
4253 REGISTER_METAVARIABLE("nTrackFitResults(particleType)", nTrackFitResults,
4254 "[Eventbased] Returns the total number of TrackFitResults for a given particleType. The argument can be the name of particle (e.g. pi+) or PDG code (e.g. 211).",
4255 Manager::VariableDataType::c_int);
4257 REGISTER_METAVARIABLE(
"convertToDaughterIndex(variable)", convertToDaughterIndex, R
"DOC(Converts the variable of the given particle into integer and returns it if it is a valid daughter index, else returns -1.)DOC", Manager::VariableDataType::c_int);
int getPDGCode() const
PDG code.
static const ChargedStable pion
charged pion particle
static const double doubleNaN
quiet_NaN
static const ChargedStable electron
electron particle
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
@ c_nPhotons
CR is split into n photons (N1)
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
@ c_Initial
bit 5: Particle is initial such as e+ or e- and not going to Geant4
@ c_PrimaryParticle
bit 0: Particle is primary particle.
@ c_IsVirtual
bit 4: Particle is virtual and not going to Geant4.
static std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
EParticleSourceObject
particle source enumerators
@ c_Flavored
Is either particle or antiparticle.
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
std::variant< double, int, bool > VarVariant
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
static Manager & Instance()
get singleton instance.
#define MAKE_DEPRECATED(name, make_fatal, version, description)
Registers a variable as deprecated.
T convertString(const std::string &str)
Converts a string to type T (one of float, double, long double, int, long int, unsigned long int).
bool hasAntiParticle(int pdgCode)
Checks if the particle with given pdg code has an anti-particle or not.
Particle * copyParticle(const Particle *original)
Function takes argument Particle and creates a copy of it and copies of all its (grand-)^n-daughters.
Abstract base class for different kinds of events.