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.");
72 if (arguments.size() == 1) {
74 auto func = [var](
const Particle * particle) ->
double {
75 UseReferenceFrame<RestFrame> frame(particle);
76 return requireDoubleForFrameVariable(var, var->function(particle),
"useRestFrame");
80 B2FATAL(
"Wrong number of arguments for meta function useRestFrame");
86 if (arguments.size() == 1) {
88 auto func = [var](
const Particle * particle) ->
double {
89 UseReferenceFrame<CMSFrame> frame;
90 return requireDoubleForFrameVariable(var, var->function(particle),
"useCMSFrame");
94 B2FATAL(
"Wrong number of arguments for meta function useCMSFrame");
100 if (arguments.size() == 1) {
102 auto func = [var](
const Particle * particle) ->
double {
103 UseReferenceFrame<LabFrame> frame;
104 return requireDoubleForFrameVariable(var, var->function(particle),
"useLabFrame");
108 B2FATAL(
"Wrong number of arguments for meta function useLabFrame");
114 if (arguments.size() == 2) {
116 auto daughterFunction = convertToDaughterIndex({arguments[1]});
117 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
118 int daughterIndexTagB = std::get<int>(daughterFunction(particle));
119 if (daughterIndexTagB < 0)
122 if (particle->getPDGCode() != 300553)
124 B2ERROR(
"Variable should only be used on a Upsilon(4S) Particle List!");
129 ROOT::Math::PxPyPzEVector pSigB = T.getBeamFourMomentum() - particle->getDaughter(daughterIndexTagB)->get4Vector();
130 Particle tmp(pSigB, -particle->getDaughter(daughterIndexTagB)->getPDGCode());
132 UseReferenceFrame<RestFrame> frame(&tmp);
133 return requireDoubleForFrameVariable(var, var->function(particle),
"useTagSideRecoilRestFrame");
138 B2FATAL(
"Wrong number of arguments for meta function useTagSideRecoilRestFrame");
144 if (arguments.size() == 2) {
146 std::string listName = arguments[1];
147 auto func = [var, listName](
const Particle * particle) ->
double {
148 StoreObjPtr<ParticleList> list(listName);
149 unsigned listSize = list->getListSize();
153 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."
154 << LogVar(
"ParticleList", listName)
155 << LogVar(
"Number of candidates in the list", listSize));
156 const Particle* p = list->getParticle(0);
157 UseReferenceFrame<RestFrame> frame(p);
158 return requireDoubleForFrameVariable(var, var->function(particle),
"useParticleRestFrame");
162 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
168 if (arguments.size() == 2) {
170 std::string listName = arguments[1];
171 auto func = [var, listName](
const Particle * particle) ->
double {
172 StoreObjPtr<ParticleList> list(listName);
173 unsigned listSize = list->getListSize();
177 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."
178 << LogVar(
"ParticleList", listName)
179 << LogVar(
"Number of candidates in the list", listSize));
180 const Particle* p = list->getParticle(0);
182 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - p->get4Vector();
184 Particle pRecoil(recoil, 0);
185 pRecoil.setVertex(particle->getVertex());
186 UseReferenceFrame<RestFrame> frame(&pRecoil);
187 return requireDoubleForFrameVariable(var, var->function(particle),
"useRecoilParticleRestFrame");
191 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
197 if (arguments.size() >= 2) {
199 auto func = [var, arguments](
const Particle * particle) ->
double {
202 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
204 for (
unsigned int i = 1; i < arguments.size(); i++)
206 auto generalizedIndex = arguments[i];
207 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
209 pSum += dauPart->get4Vector();
213 Particle tmp(pSum, 0);
214 UseReferenceFrame<RestFrame> frame(&tmp);
215 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRestFrame");
219 B2FATAL(
"Wrong number of arguments for meta function useDaughterRestFrame.");
225 if (arguments.size() >= 2) {
227 auto func = [var, arguments](
const Particle * particle) ->
double {
230 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
232 for (
unsigned int i = 1; i < arguments.size(); i++)
234 auto generalizedIndex = arguments[i];
235 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
237 pSum += dauPart->get4Vector();
242 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - pSum;
244 Particle pRecoil(recoil, 0);
245 UseReferenceFrame<RestFrame> frame(&pRecoil);
246 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRecoilRestFrame");
250 B2FATAL(
"Wrong number of arguments for meta function useDaughterRecoilRestFrame.");
256 if (arguments.size() == 1) {
258 auto func = [var](
const Particle * particle) ->
double {
259 int index = ancestorBIndex(particle);
261 StoreArray<MCParticle> mcparticles;
262 Particle temp(mcparticles[index]);
263 UseReferenceFrame<RestFrame> frame(&temp);
264 return requireDoubleForFrameVariable(var, var->function(particle),
"useMCancestorBRestFrame");
268 B2FATAL(
"Wrong number of arguments for meta function useMCancestorBRestFrame.");
274 if (arguments.size() == 1) {
275 auto extraInfoName = arguments[0];
276 auto func = [extraInfoName](
const Particle * particle) ->
double {
277 if (particle ==
nullptr)
279 B2WARNING(
"Returns NaN because the particle is nullptr! If you want EventExtraInfo variables, please use eventExtraInfo() instead");
282 if (particle->hasExtraInfo(extraInfoName))
284 return particle->getExtraInfo(extraInfoName);
292 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
298 if (arguments.size() == 1) {
299 auto extraInfoName = arguments[0];
300 auto func = [extraInfoName](
const Particle*) ->
double {
301 StoreObjPtr<EventExtraInfo> eventExtraInfo;
302 if (not eventExtraInfo.isValid())
304 if (eventExtraInfo->hasExtraInfo(extraInfoName))
306 return eventExtraInfo->getExtraInfo(extraInfoName);
314 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
320 if (arguments.size() == 1) {
323 auto func = [var, key](
const Particle*) ->
double {
325 StoreObjPtr<EventExtraInfo> eventExtraInfo;
326 if (not eventExtraInfo.isValid())
327 eventExtraInfo.create();
328 if (eventExtraInfo->hasExtraInfo(key))
330 return eventExtraInfo->getExtraInfo(key);
334 auto var_result = var->function(
nullptr);
335 if (std::holds_alternative<double>(var_result)) {
336 value = std::get<double>(var_result);
337 }
else if (std::holds_alternative<int>(var_result)) {
338 return std::get<int>(var_result);
339 }
else if (std::holds_alternative<bool>(var_result)) {
340 return std::get<bool>(var_result);
342 eventExtraInfo->addExtraInfo(key, value);
348 B2FATAL(
"Wrong number of arguments for meta function eventCached");
354 if (arguments.size() == 1) {
357 auto func = [var, key](
const Particle * particle) ->
double {
359 if (particle->hasExtraInfo(key))
361 return particle->getExtraInfo(key);
364 double value = std::get<double>(var->function(particle));
372 const_cast<Particle*
>(particle)->addExtraInfo(key, value);
378 B2FATAL(
"Wrong number of arguments for meta function particleCached");
387 if (arguments.size() != 1) B2FATAL(
"Wrong number of arguments for meta function formula");
388 FormulaParser<VariableFormulaConstructor> parser;
390 return parser.parse(arguments[0]);
391 }
catch (std::runtime_error& e) {
398 if (arguments.size() <= 1) {
400 std::string cutString;
401 if (arguments.size() == 1)
402 cutString = arguments[0];
404 auto func = [cut](
const Particle*) ->
int {
406 int number_of_tracks = 0;
407 StoreArray<Track> tracks;
408 for (
const auto& track : tracks)
410 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(
Const::pion);
411 if (!trackFit)
continue;
412 if (trackFit->getChargeSign() == 0) {
416 if (cut->check(&particle))
421 return number_of_tracks;
426 B2FATAL(
"Wrong number of arguments for meta function nCleanedTracks");
432 if (arguments.size() <= 1) {
434 std::string cutString;
435 if (arguments.size() == 1)
436 cutString = arguments[0];
438 auto func = [cut](
const Particle*) ->
int {
440 int number_of_clusters = 0;
441 StoreArray<ECLCluster> clusters;
442 for (
const auto& cluster : clusters)
448 Particle particle(&cluster);
449 if (cut->check(&particle))
450 number_of_clusters++;
453 return number_of_clusters;
458 B2FATAL(
"Wrong number of arguments for meta function nCleanedECLClusters");
464 if (arguments.size() == 1) {
465 std::string cutString = arguments[0];
467 auto func = [cut](
const Particle * particle) ->
bool {
468 if (cut->check(particle))
475 B2FATAL(
"Wrong number of arguments for meta function passesCut");
481 if (arguments.size() == 1) {
482 std::string cutString = arguments[0];
484 auto func = [cut](
const Particle*) ->
bool {
485 if (cut->check(
nullptr))
492 B2FATAL(
"Wrong number of arguments for meta function passesEventCut");
498 if (arguments.size() == 2) {
502 }
catch (std::invalid_argument&) {
503 B2FATAL(
"The first argument of varFor meta function must be a positive integer!");
506 auto func = [pdgCode, var](
const Particle * particle) ->
double {
507 if (std::abs(particle->getPDGCode()) == std::abs(pdgCode))
509 auto var_result = var->function(particle);
510 if (std::holds_alternative<double>(var_result)) {
511 return std::get<double>(var_result);
512 }
else if (std::holds_alternative<int>(var_result)) {
513 return std::get<int>(var_result);
514 }
else if (std::holds_alternative<bool>(var_result)) {
515 return std::get<bool>(var_result);
521 B2FATAL(
"Wrong number of arguments for meta function varFor");
527 if (arguments.size() == 1) {
529 auto func = [var](
const Particle * particle) ->
double {
530 if (particle->getMCParticle())
535 auto var_result = var->function(particle);
536 if (std::holds_alternative<double>(var_result)) {
537 return std::get<double>(var_result);
538 }
else if (std::holds_alternative<int>(var_result)) {
539 return std::get<int>(var_result);
540 }
else if (std::holds_alternative<bool>(var_result)) {
541 return std::get<bool>(var_result);
548 B2FATAL(
"Wrong number of arguments for meta function varForMCGen");
554 if (arguments.size() == 1) {
555 std::string listName = arguments[0];
556 auto func = [listName](
const Particle * particle) ->
int {
559 StoreObjPtr<ParticleList> listOfParticles(listName);
561 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to nParticlesInList");
563 return listOfParticles->getListSize();
568 B2FATAL(
"Wrong number of arguments for meta function nParticlesInList");
574 if (arguments.size() != 2 && arguments.size() != 3) {
575 B2FATAL(
"nParticlesInCone requires a particle list, a cone half-angle in degrees, "
576 "and optionally a particle cut");
579 const std::string listName = arguments[0];
581 double angleDegrees = 0.;
584 }
catch (
const std::exception&) {
585 B2FATAL(
"Invalid cone half-angle: " << arguments[1]);
587 if (!std::isfinite(angleDegrees) || angleDegrees < 0. || angleDegrees > 180.) {
588 B2FATAL(
"The cone half-angle must be between 0 and 180 degrees");
590 const double cosineThreshold = std::cos(angleDegrees * std::acos(-1.) / 180.);
592 std::shared_ptr<Variable::Cut> cut;
593 if (arguments.size() == 3 && !arguments[2].empty()) {
597 return [listName, cosineThreshold, cut](
const Particle * particle) ->
double {
598 StoreObjPtr<ParticleList> particles(listName);
599 if (!particles.isValid())
601 B2FATAL(
"Invalid particle list in nParticlesInCone: " << listName);
604 const auto isSupported = [](
const Particle * candidate)
606 if (!candidate)
return false;
607 const auto source = candidate->getParticleSource();
608 return source == Particle::c_Track ||
609 source == Particle::c_ECLCluster ||
610 source == Particle::c_KLMCluster;
615 const auto labToCms = PCmsLabTransform().rotateLabToCms();
616 const auto central = labToCms * particle->get4Vector();
617 const double cx = central.Px();
618 const double cy = central.Py();
619 const double cz = central.Pz();
620 const double c2 = cx * cx + cy * cy + cz * cz;
623 const int ownSource = particle->getMdstSource();
624 std::unordered_set<int> countedSources;
627 for (
unsigned i = 0; i < particles->getListSize(); ++i)
629 const Particle* other = particles->getParticle(i);
630 if (!isSupported(other))
continue;
632 const int source = other->getMdstSource();
633 if (source == ownSource || countedSources.count(source))
continue;
634 if (cut && !cut->check(other))
continue;
636 const auto momentum = labToCms * other->get4Vector();
637 const double px = momentum.Px();
638 const double py = momentum.Py();
639 const double pz = momentum.Pz();
640 const double p2 = px * px + py * py + pz * pz;
641 if (!std::isfinite(p2) || p2 <= 0.)
continue;
643 double cosine = (cx * px + cy * py + cz * pz) / std::sqrt(c2 * p2);
644 if (cosine > 1.) cosine = 1.;
645 if (cosine < -1.) cosine = -1.;
647 if (cosine >= cosineThreshold && countedSources.insert(source).second) {
658 if (arguments.size() != 1) {
659 B2FATAL(
"Wrong number of arguments for isInList");
661 auto listName = arguments[0];
663 auto func = [listName](
const Particle * particle) ->
bool {
666 StoreObjPtr<ParticleList> list(listName);
667 if (!(list.isValid()))
669 B2FATAL(
"Invalid Listname " << listName <<
" given to isInList");
673 return list->contains(particle);
682 if (arguments.size() != 1) {
683 B2FATAL(
"Wrong number of arguments for sourceObjectIsInList");
685 auto listName = arguments[0];
687 auto func = [listName](
const Particle * particle) ->
int {
690 StoreObjPtr<ParticleList> list(listName);
691 if (!(list.isValid()))
693 B2FATAL(
"Invalid Listname " << listName <<
" given to sourceObjectIsInList");
699 if (particlesource == Particle::EParticleSourceObject::c_Composite
700 or particlesource == Particle::EParticleSourceObject::c_Undefined)
706 for (
unsigned i = 0; i < list->getListSize(); ++i)
708 const Particle* iparticle = list->getParticle(i);
709 if (particle->getMdstSource() == iparticle->getMdstSource())
721 if (arguments.size() != 1) {
722 B2FATAL(
"Wrong number of arguments for mcParticleIsInMCList");
724 auto listName = arguments[0];
726 auto func = [listName](
const Particle * particle) ->
bool {
729 StoreObjPtr<ParticleList> list(listName);
730 if (!(list.isValid()))
731 B2FATAL(
"Invalid Listname " << listName <<
" given to mcParticleIsInMCList");
734 const MCParticle* mcp = particle->getMCParticle();
735 if (mcp ==
nullptr)
return false;
738 for (
unsigned i = 0; i < list->getListSize(); ++i)
740 const MCParticle* imcp = list->getParticle(i)->getMCParticle();
741 if ((imcp !=
nullptr) and (mcp->getArrayIndex() == imcp->getArrayIndex()))
751 B2WARNING(
"isDaughterOfList is outdated and replaced by isDescendantOfList.");
752 std::vector<std::string> new_arguments = arguments;
753 new_arguments.push_back(std::string(
"1"));
754 return isDescendantOfList(new_arguments);
759 B2WARNING(
"isGrandDaughterOfList is outdated and replaced by isDescendantOfList.");
760 std::vector<std::string> new_arguments = arguments;
761 new_arguments.push_back(std::string(
"2"));
762 return isDescendantOfList(new_arguments);
767 if (arguments.size() > 0) {
768 auto listNames = arguments;
769 auto func = [listNames](
const Particle * particle) ->
bool {
771 int generation_flag = -1;
775 }
catch (
const std::exception& e) {}
777 for (
const auto& iListName : listNames)
782 }
catch (
const std::exception& e) {}
785 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
787 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
789 const Particle* daughter = m->getDaughter(i);
790 if ((flag == 1.) or (flag < 0)) {
791 if (p->isCopyOf(daughter)) {
797 if (daughter->getNDaughters() > 0) {
798 result = self(self, daughter, p, flag - 1);
808 StoreObjPtr<ParticleList> listOfParticles(iListName);
810 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isDescendantOfList");
812 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
813 Particle* iParticle = listOfParticles->getParticle(i);
814 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
824 B2FATAL(
"Wrong number of arguments for meta function isDescendantOfList");
830 if (arguments.size() > 0) {
831 auto listNames = arguments;
832 auto func = [listNames](
const Particle * particle) ->
bool {
834 int generation_flag = -1;
838 }
catch (
const std::exception& e) {}
840 if (particle->getMCParticle() ==
nullptr)
845 for (
const auto& iListName : listNames)
850 std::stod(iListName);
852 }
catch (
const std::exception& e) {}
854 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
856 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
858 const Particle* daughter = m->getDaughter(i);
859 if ((flag == 1.) or (flag < 0)) {
860 if (daughter->getMCParticle() !=
nullptr) {
861 if (p->getMCParticle()->getArrayIndex() == daughter->getMCParticle()->getArrayIndex()) {
867 if (daughter->getNDaughters() > 0) {
868 result = self(self, daughter, p, flag - 1);
878 StoreObjPtr<ParticleList> listOfParticles(iListName);
880 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isMCDescendantOfList");
882 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
883 Particle* iParticle = listOfParticles->getParticle(i);
884 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
894 B2FATAL(
"Wrong number of arguments for meta function isMCDescendantOfList");
900 if (arguments.size() == 1) {
902 auto func = [var](
const Particle * particle) ->
double {
903 double product = 1.0;
904 if (particle->getNDaughters() == 0)
908 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
910 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
911 product *= std::get<double>(var->function(particle->getDaughter(j)));
913 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
915 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
916 product *= std::get<int>(var->function(particle->getDaughter(j)));
923 B2FATAL(
"Wrong number of arguments for meta function daughterProductOf");
929 if (arguments.size() == 1) {
931 auto func = [var](
const Particle * particle) ->
double {
933 if (particle->getNDaughters() == 0)
937 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
939 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
940 sum += std::get<double>(var->function(particle->getDaughter(j)));
942 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
944 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
945 sum += std::get<int>(var->function(particle->getDaughter(j)));
952 B2FATAL(
"Wrong number of arguments for meta function daughterSumOf");
958 if (arguments.size() == 1) {
960 auto func = [var](
const Particle * particle) ->
double {
962 if (particle->getNDaughters() == 0)
966 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
968 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
969 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
970 if (std::isnan(iValue))
continue;
971 if (std::isnan(min)) min = iValue;
972 if (iValue < min) min = iValue;
974 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
976 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
977 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
978 if (std::isnan(min)) min = iValue;
979 if (iValue < min) min = iValue;
986 B2FATAL(
"Wrong number of arguments for meta function daughterLowest");
992 if (arguments.size() == 1) {
994 auto func = [var](
const Particle * particle) ->
double {
996 if (particle->getNDaughters() == 0)
1000 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
1002 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
1003 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
1004 if (std::isnan(iValue))
continue;
1005 if (std::isnan(max)) max = iValue;
1006 if (iValue > max) max = iValue;
1008 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
1010 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
1011 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
1012 if (std::isnan(max)) max = iValue;
1013 if (iValue > max) max = iValue;
1020 B2FATAL(
"Wrong number of arguments for meta function daughterHighest");
1026 if (arguments.size() == 3) {
1027 auto func = [arguments](
const Particle * particle) ->
double {
1028 if (particle ==
nullptr)
1030 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1031 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1032 auto variablename = arguments[2];
1033 if (dau_i ==
nullptr || dau_j ==
nullptr)
1035 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1039 auto result_j = var->function(dau_j);
1040 auto result_i = var->function(dau_i);
1042 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1044 diff = std::get<double>(result_j) - std::get<double>(result_i);
1045 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1047 diff = std::get<int>(result_j) - std::get<int>(result_i);
1050 throw std::runtime_error(
"Bad variant access");
1052 if (variablename ==
"phi" or variablename ==
"clusterPhi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)"))
1053 or std::regex_match(variablename, std::regex(
"use.*Frame\\(clusterPhi\\)")))
1055 if (fabs(diff) > M_PI) {
1057 diff = diff - 2 * M_PI;
1059 diff = 2 * M_PI + diff;
1067 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOf");
1073 if (arguments.size() == 3) {
1074 auto func = [arguments](
const Particle * particle) ->
double {
1075 if (particle ==
nullptr)
1077 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1078 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1079 auto variablename = arguments[2];
1080 if (dau_i ==
nullptr || dau_j ==
nullptr)
1082 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1085 const MCParticle* iMcDaughter = dau_i->getMCParticle();
1086 const MCParticle* jMcDaughter = dau_j->getMCParticle();
1087 if (iMcDaughter ==
nullptr || jMcDaughter ==
nullptr)
1089 Particle iTmpPart(iMcDaughter);
1090 Particle jTmpPart(jMcDaughter);
1092 auto result_j = var->function(&jTmpPart);
1093 auto result_i = var->function(&iTmpPart);
1095 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1097 diff = std::get<double>(result_j) - std::get<double>(result_i);
1098 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1100 diff = std::get<int>(result_j) - std::get<int>(result_i);
1103 throw std::runtime_error(
"Bad variant access");
1105 if (variablename ==
"phi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)")))
1107 if (fabs(diff) > M_PI) {
1109 diff = diff - 2 * M_PI;
1111 diff = 2 * M_PI + diff;
1119 B2FATAL(
"Wrong number of arguments for meta function mcDaughterDiffOf");
1125 if (arguments.size() == 5) {
1131 }
catch (std::invalid_argument&) {
1132 B2FATAL(
"First four arguments of grandDaughterDiffOf meta function must be integers!");
1134 std::vector<std::string> new_arguments;
1135 new_arguments.push_back(std::string(arguments[0] +
":" + arguments[2]));
1136 new_arguments.push_back(std::string(arguments[1] +
":" + arguments[3]));
1137 new_arguments.push_back(arguments[4]);
1138 return daughterDiffOf(new_arguments);
1140 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOf");
1146 if (arguments.size() == 3) {
1147 auto func = [arguments](
const Particle * particle) ->
double {
1148 if (particle ==
nullptr)
1150 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1151 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1152 if (!(dau_i && dau_j))
1154 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1158 double iValue, jValue;
1159 if (std::holds_alternative<double>(var->function(dau_j)))
1161 iValue = std::get<double>(var->function(dau_i));
1162 jValue = std::get<double>(var->function(dau_j));
1163 }
else if (std::holds_alternative<int>(var->function(dau_j)))
1165 iValue = std::get<int>(var->function(dau_i));
1166 jValue = std::get<int>(var->function(dau_j));
1168 return (jValue - iValue) / (jValue + iValue);
1172 B2FATAL(
"Wrong number of arguments for meta function daughterNormDiffOf");
1178 if (arguments.size() == 2) {
1179 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1180 std::string variableName = arguments[1];
1181 auto func = [daughterFunction, variableName](
const Particle * particle) ->
double {
1182 if (particle ==
nullptr)
1184 int daughterNumber = std::get<int>(daughterFunction(particle));
1185 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1188 auto result_mother = var->function(particle);
1189 auto result_daughter = var->function(particle->getDaughter(daughterNumber));
1191 if (std::holds_alternative<double>(result_mother) && std::holds_alternative<double>(result_daughter))
1193 diff = std::get<double>(result_mother) - std::get<double>(result_daughter);
1194 }
else if (std::holds_alternative<int>(result_mother) && std::holds_alternative<int>(result_daughter))
1196 diff = std::get<int>(result_mother) - std::get<int>(result_daughter);
1199 throw std::runtime_error(
"Bad variant access");
1202 if (variableName ==
"phi" or variableName ==
"useCMSFrame(phi)")
1204 if (fabs(diff) > M_PI) {
1206 diff = diff - 2 * M_PI;
1208 diff = 2 * M_PI + diff;
1216 B2FATAL(
"Wrong number of arguments for meta function daughterMotherDiffOf");
1222 if (arguments.size() == 2) {
1223 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1225 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
1226 if (particle ==
nullptr)
1228 int daughterNumber = std::get<int>(daughterFunction(particle));
1229 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1231 double daughterValue = 0.0, motherValue = 0.0;
1232 if (std::holds_alternative<double>(var->function(particle)))
1234 daughterValue = std::get<double>(var->function(particle->getDaughter(daughterNumber)));
1235 motherValue = std::get<double>(var->function(particle));
1236 }
else if (std::holds_alternative<int>(var->function(particle)))
1238 daughterValue = std::get<int>(var->function(particle->getDaughter(daughterNumber)));
1239 motherValue = std::get<int>(var->function(particle));
1241 return (motherValue - daughterValue) / (motherValue + daughterValue);
1245 B2FATAL(
"Wrong number of arguments for meta function daughterMotherNormDiffOf");
1251 if (arguments.size() >= 1) {
1253 auto func = [arguments](
const Particle * particle) ->
double {
1254 if (particle ==
nullptr)
1259 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1260 for (
const auto& generalizedIndex : arguments)
1262 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1263 if (dauPart) pSum += frame.getMomentum(dauPart);
1265 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1271 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
1272 ROOT::Math::PxPyPzEVector pRecoil = frame.getMomentum(pIN - particle->get4Vector());
1274 return ROOT::Math::VectorUtil::Angle(pRecoil, pSum);
1278 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndRecoil");
1282 Manager::FunctionPtr angleBetweenDaughterAndMissingMomentum(
const std::vector<std::string>& arguments)
1284 if (arguments.size() >= 1) {
1285 auto func = [arguments](
const Particle * particle) ->
double {
1286 if (particle ==
nullptr)
1289 StoreObjPtr<EventKinematics> evtShape;
1292 B2WARNING(
"Cannot find missing momentum information, did you forget to run EventKinematicsModule?");
1295 ROOT::Math::XYZVector missingMomentumCMS = evtShape->getMissingMomentumCMS();
1296 ROOT::Math::PxPyPzEVector missingTotalMomentumCMS(missingMomentumCMS.X(),
1297 missingMomentumCMS.Y(),
1298 missingMomentumCMS.Z(),
1299 evtShape->getMissingEnergyCMS());
1301 ROOT::Math::PxPyPzEVector missingTotalMomentumLab = T.rotateCmsToLab() * missingTotalMomentumCMS;
1304 ROOT::Math::PxPyPzEVector pMiss = frame.getMomentum(missingTotalMomentumLab);
1306 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1307 for (
const auto& generalizedIndex : arguments)
1309 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1310 if (dauPart) pSum += frame.getMomentum(dauPart);
1312 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1317 return ROOT::Math::VectorUtil::Angle(pMiss, pSum);
1321 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndMissingMomentum");
1327 if (arguments.size() == 2 || arguments.size() == 3) {
1329 auto func = [arguments](
const Particle * particle) ->
double {
1330 if (particle ==
nullptr)
1333 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1337 for (
const auto& generalizedIndex : arguments)
1339 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1341 pDaus.push_back(frame.getMomentum(dauPart));
1343 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1349 if (pDaus.size() == 2)
1350 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1352 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1356 B2FATAL(
"Wrong number of arguments for meta function daughterAngle");
1360 double grandDaughterDecayAngle(
const Particle* particle,
const std::vector<double>& arguments)
1362 if (arguments.size() == 2) {
1367 int daughterIndex = std::lround(arguments[0]);
1368 if (daughterIndex >=
int(particle->getNDaughters()))
1370 const Particle* dau = particle->getDaughter(daughterIndex);
1372 int grandDaughterIndex = std::lround(arguments[1]);
1373 if (grandDaughterIndex >=
int(dau->getNDaughters()))
1376 ROOT::Math::XYZVector boost = dau->get4Vector().BoostToCM();
1378 ROOT::Math::PxPyPzEVector motherMomentum = - particle->get4Vector();
1379 motherMomentum = ROOT::Math::Boost(boost) * motherMomentum;
1381 ROOT::Math::PxPyPzEVector grandDaughterMomentum = dau->getDaughter(grandDaughterIndex)->get4Vector();
1382 grandDaughterMomentum = ROOT::Math::Boost(boost) * grandDaughterMomentum;
1384 return ROOT::Math::VectorUtil::Angle(motherMomentum, grandDaughterMomentum);
1387 B2FATAL(
"The variable grandDaughterDecayAngle needs exactly two integers as arguments!");
1393 if (arguments.size() == 2 || arguments.size() == 3) {
1395 auto func = [arguments](
const Particle * particle) ->
double {
1396 if (particle ==
nullptr)
1399 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1403 if (particle->getParticleSource() == Particle::EParticleSourceObject::c_MCParticle)
1405 for (
const auto& generalizedIndex : arguments) {
1406 const MCParticle* mcPart = particle->getMCParticle();
1407 if (mcPart ==
nullptr)
1409 const MCParticle* dauMcPart = mcPart->getParticleFromGeneralizedIndexString(generalizedIndex);
1410 if (dauMcPart ==
nullptr)
1413 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1417 for (
const auto& generalizedIndex : arguments) {
1418 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1419 if (dauPart ==
nullptr)
1422 const MCParticle* dauMcPart = dauPart->getMCParticle();
1423 if (dauMcPart ==
nullptr)
1426 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1431 if (pDaus.size() == 2)
1432 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1434 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1438 B2FATAL(
"Wrong number of arguments for meta function mcDaughterAngle");
1442 double daughterClusterAngleInBetween(
const Particle* particle,
const std::vector<double>& daughterIndices)
1444 if (daughterIndices.size() == 2) {
1445 int daughterIndexi = std::lround(daughterIndices[0]);
1446 int daughterIndexj = std::lround(daughterIndices[1]);
1447 if (std::max(daughterIndexi, daughterIndexj) >=
int(particle->getNDaughters())) {
1450 const ECLCluster* clusteri = particle->getDaughter(daughterIndexi)->getECLCluster();
1451 const ECLCluster* clusterj = particle->getDaughter(daughterIndexj)->getECLCluster();
1452 if (clusteri and clusterj) {
1456 ClusterUtils clusutils;
1457 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1458 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1459 return ROOT::Math::VectorUtil::Angle(pi, pj);
1463 }
else if (daughterIndices.size() == 3) {
1464 int daughterIndexi = std::lround(daughterIndices[0]);
1465 int daughterIndexj = std::lround(daughterIndices[1]);
1466 int daughterIndexk = std::lround(daughterIndices[2]);
1467 if (std::max(std::max(daughterIndexi, daughterIndexj), daughterIndexk) >=
int(particle->getNDaughters())) {
1470 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1471 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1472 const ECLCluster* clusterk = (particle->getDaughter(daughterIndices[2]))->getECLCluster();
1473 if (clusteri and clusterj and clusterk) {
1478 ClusterUtils clusutils;
1479 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1480 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1481 ROOT::Math::PxPyPzEVector pk = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterk, clusterkBit));
1482 return ROOT::Math::VectorUtil::Angle(pk, pi + pj);
1487 B2FATAL(
"Wrong number of arguments for daughterClusterAngleInBetween!");
1493 if (arguments.size() > 1) {
1494 auto func = [arguments](
const Particle * particle) ->
double {
1496 ROOT::Math::PxPyPzEVector pSum;
1498 for (
const auto& generalizedIndex : arguments)
1500 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1502 pSum += frame.getMomentum(dauPart);
1511 B2FATAL(
"Wrong number of arguments for meta function daughterInvM. At least two integers are needed.");
1517 if (arguments.size() == 2) {
1522 }
catch (std::invalid_argument&) {
1523 B2FATAL(
"Second argument of modulo meta function must be integer!");
1525 auto func = [var, divideBy](
const Particle * particle) ->
int {
1526 auto var_result = var->function(particle);
1527 if (std::holds_alternative<double>(var_result))
1529 return int(std::get<double>(var_result)) % divideBy;
1530 }
else if (std::holds_alternative<int>(var_result))
1532 return std::get<int>(var_result) % divideBy;
1533 }
else if (std::holds_alternative<bool>(var_result))
1535 return int(std::get<bool>(var_result)) % divideBy;
1540 B2FATAL(
"Wrong number of arguments for meta function modulo");
1546 if (arguments.size() == 1) {
1549 auto func = [var](
const Particle * particle) ->
bool {
return std::isnan(std::get<double>(var->function(particle))); };
1552 B2FATAL(
"Wrong number of arguments for meta function isNAN");
1558 if (arguments.size() == 2) {
1560 double defaultOutput;
1563 }
catch (std::invalid_argument&) {
1564 B2FATAL(
"The second argument of ifNANgiveX meta function must be a number!");
1566 auto func = [var, defaultOutput](
const Particle * particle) ->
double {
1567 double output = std::get<double>(var->function(particle));
1568 if (std::isnan(output))
return defaultOutput;
1573 B2FATAL(
"Wrong number of arguments for meta function ifNANgiveX");
1579 if (arguments.size() == 1) {
1582 auto func = [var](
const Particle * particle) ->
bool {
return std::isinf(std::get<double>(var->function(particle))); };
1585 B2FATAL(
"Wrong number of arguments for meta function isInfinity");
1591 if (arguments.size() >= 2) {
1597 for (
size_t i = 1; i < arguments.size(); ++i) {
1600 }
catch (std::invalid_argument&) {
1601 B2FATAL(
"The input flags to meta function unmask() should be integer!");
1607 auto func = [var, finalMask](
const Particle * particle) ->
double {
1609 auto var_result = var->function(particle);
1610 if (std::holds_alternative<double>(var_result))
1613 if (std::isnan(std::get<double>(var_result))) {
1616 value = int(std::get<double>(var_result));
1617 }
else if (std::holds_alternative<int>(var_result))
1619 value = std::get<int>(var_result);
1623 value &= (~finalMask);
1630 B2FATAL(
"Meta function unmask needs at least two arguments!");
1636 if (arguments.size() == 3) {
1638 std::string cutString = arguments[0];
1644 auto func = [cut, variableIfTrue, variableIfFalse](
const Particle * particle) ->
double {
1645 if (particle ==
nullptr)
1647 if (cut->check(particle))
1649 auto var_result = variableIfTrue->function(particle);
1650 if (std::holds_alternative<double>(var_result)) {
1651 return std::get<double>(var_result);
1652 }
else if (std::holds_alternative<int>(var_result)) {
1653 return std::get<int>(var_result);
1654 }
else if (std::holds_alternative<bool>(var_result)) {
1655 return std::get<bool>(var_result);
1659 auto var_result = variableIfFalse->function(particle);
1660 if (std::holds_alternative<double>(var_result)) {
1661 return std::get<double>(var_result);
1662 }
else if (std::holds_alternative<int>(var_result)) {
1663 return std::get<int>(var_result);
1664 }
else if (std::holds_alternative<bool>(var_result)) {
1665 return std::get<bool>(var_result);
1672 B2FATAL(
"Wrong number of arguments for meta function conditionalVariableSelector");
1678 if (arguments.size() > 0) {
1679 std::vector<const Variable::Manager::Var*> variables;
1680 for (
const auto& argument : arguments)
1683 auto func = [variables, arguments](
const Particle * particle) ->
double {
1684 double pValueProduct = 1.;
1685 for (
auto variable : variables)
1687 double pValue = std::get<double>(variable->function(particle));
1691 pValueProduct *= pValue;
1693 double pValueSum = 1.;
1694 double factorial = 1.;
1695 for (
unsigned int i = 1; i < arguments.size(); ++i)
1698 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1700 return pValueProduct * pValueSum;
1704 B2FATAL(
"Wrong number of arguments for meta function pValueCombination");
1710 if (arguments.size() == 1) {
1712 auto func = [var](
const Particle * particle) ->
double {
1713 double pValueProduct = 1.;
1714 if (particle->getNDaughters() == 0)
1719 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
1721 double pValue = std::get<double>(var->function(particle->getDaughter(j)));
1722 if (pValue < 0)
return -1;
1723 else pValueProduct *= pValue;
1726 double pValueSum = 1.;
1727 double factorial = 1.;
1728 for (
unsigned int i = 1; i < particle->getNDaughters(); ++i)
1731 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1733 return pValueProduct * pValueSum;
1737 B2FATAL(
"Wrong number of arguments for meta function pValueCombinationOfDaughters");
1743 if (arguments.size() == 1) {
1745 auto func = [var](
const Particle * particle) ->
double {
1746 auto var_result = var->function(particle);
1747 if (std::holds_alternative<double>(var_result))
1749 return std::abs(std::get<double>(var_result));
1750 }
else if (std::holds_alternative<int>(var_result))
1752 return std::abs(std::get<int>(var_result));
1757 B2FATAL(
"Wrong number of arguments for meta function abs");
1763 if (arguments.size() == 2) {
1768 B2FATAL(
"One or both of the used variables doesn't exist!");
1770 auto func = [var1, var2](
const Particle * particle) ->
double {
1771 double val1 = 0.0, val2 = 0.0;
1772 auto var_result1 = var1->function(particle);
1773 auto var_result2 = var2->function(particle);
1774 if (std::holds_alternative<double>(var_result1))
1776 val1 = std::get<double>(var_result1);
1777 }
else if (std::holds_alternative<int>(var_result1))
1779 val1 = std::get<int>(var_result1);
1780 }
else if (std::holds_alternative<bool>(var_result1))
1782 val1 = std::get<bool>(var_result1);
1785 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1787 if (std::holds_alternative<double>(var_result2))
1789 val2 = std::get<double>(var_result2);
1790 }
else if (std::holds_alternative<int>(var_result2))
1792 val2 = std::get<int>(var_result2);
1793 }
else if (std::holds_alternative<bool>(var_result2))
1795 val2 = std::get<bool>(var_result2);
1798 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1800 return std::max(val1, val2);
1804 B2FATAL(
"Wrong number of arguments for meta function max");
1810 if (arguments.size() == 2) {
1815 B2FATAL(
"One or both of the used variables doesn't exist!");
1817 auto func = [var1, var2](
const Particle * particle) ->
double {
1818 double val1 = 0.0, val2 = 0.0;
1819 auto var_result1 = var1->function(particle);
1820 auto var_result2 = var2->function(particle);
1821 if (std::holds_alternative<double>(var_result1))
1823 val1 = std::get<double>(var_result1);
1824 }
else if (std::holds_alternative<int>(var_result1))
1826 val1 = std::get<int>(var_result1);
1827 }
else if (std::holds_alternative<bool>(var_result1))
1829 val1 = std::get<bool>(var_result1);
1832 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1834 if (std::holds_alternative<double>(var_result2))
1836 val2 = std::get<double>(var_result2);
1837 }
else if (std::holds_alternative<int>(var_result2))
1839 val2 = std::get<int>(var_result2);
1840 }
else if (std::holds_alternative<bool>(var_result2))
1842 val2 = std::get<bool>(var_result2);
1845 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1847 return std::min(val1, val2);
1851 B2FATAL(
"Wrong number of arguments for meta function min");
1857 if (arguments.size() == 1) {
1859 auto func = [var](
const Particle * particle) ->
double {
1860 auto var_result = var->function(particle);
1861 if (std::holds_alternative<double>(var_result))
1862 return std::sin(std::get<double>(var_result));
1863 else if (std::holds_alternative<int>(var_result))
1864 return std::sin(std::get<int>(var_result));
1869 B2FATAL(
"Wrong number of arguments for meta function sin");
1875 if (arguments.size() == 1) {
1877 auto func = [var](
const Particle * particle) ->
double {
1878 auto var_result = var->function(particle);
1879 if (std::holds_alternative<double>(var_result))
1880 return std::asin(std::get<double>(var_result));
1881 else if (std::holds_alternative<int>(var_result))
1882 return std::asin(std::get<int>(var_result));
1887 B2FATAL(
"Wrong number of arguments for meta function asin");
1893 if (arguments.size() == 1) {
1895 auto func = [var](
const Particle * particle) ->
double {
1896 auto var_result = var->function(particle);
1897 if (std::holds_alternative<double>(var_result))
1898 return std::cos(std::get<double>(var_result));
1899 else if (std::holds_alternative<int>(var_result))
1900 return std::cos(std::get<int>(var_result));
1905 B2FATAL(
"Wrong number of arguments for meta function cos");
1911 if (arguments.size() == 1) {
1913 auto func = [var](
const Particle * particle) ->
double {
1914 auto var_result = var->function(particle);
1915 if (std::holds_alternative<double>(var_result))
1916 return std::acos(std::get<double>(var_result));
1917 else if (std::holds_alternative<int>(var_result))
1918 return std::acos(std::get<int>(var_result));
1923 B2FATAL(
"Wrong number of arguments for meta function acos");
1929 if (arguments.size() == 1) {
1931 auto func = [var](
const Particle * particle) ->
double {
return std::tan(std::get<double>(var->function(particle))); };
1934 B2FATAL(
"Wrong number of arguments for meta function tan");
1940 if (arguments.size() == 1) {
1942 auto func = [var](
const Particle * particle) ->
double {
return std::atan(std::get<double>(var->function(particle))); };
1945 B2FATAL(
"Wrong number of arguments for meta function atan");
1951 if (arguments.size() == 2) {
1954 auto func = [varY, varX](
const Particle * particle) ->
double {
1955 double y = std::get<double>(varY->function(particle));
1956 double x = std::get<double>(varX->function(particle));
1957 return std::atan2(y, x);
1961 B2FATAL(
"Wrong number of arguments for meta function atan2");
1967 if (arguments.size() == 1) {
1969 auto func = [var](
const Particle * particle) ->
double {
1970 auto var_result = var->function(particle);
1971 if (std::holds_alternative<double>(var_result))
1972 return std::exp(std::get<double>(var_result));
1973 else if (std::holds_alternative<int>(var_result))
1974 return std::exp(std::get<int>(var_result));
1979 B2FATAL(
"Wrong number of arguments for meta function exp");
1985 if (arguments.size() == 1) {
1987 auto func = [var](
const Particle * particle) ->
double {
1988 auto var_result = var->function(particle);
1989 if (std::holds_alternative<double>(var_result))
1990 return std::log(std::get<double>(var_result));
1991 else if (std::holds_alternative<int>(var_result))
1992 return std::log(std::get<int>(var_result));
1997 B2FATAL(
"Wrong number of arguments for meta function log");
2003 if (arguments.size() == 1) {
2005 auto func = [var](
const Particle * particle) ->
double {
2006 auto var_result = var->function(particle);
2007 if (std::holds_alternative<double>(var_result))
2008 return std::log10(std::get<double>(var_result));
2009 else if (std::holds_alternative<int>(var_result))
2010 return std::log10(std::get<int>(var_result));
2015 B2FATAL(
"Wrong number of arguments for meta function log10");
2021 if (arguments.size() == 1) {
2023 auto func = [var](
const Particle * particle) ->
double {
2024 if (particle ==
nullptr)
2027 StoreArray<Particle> particles;
2028 if (!particle->hasExtraInfo(
"original_index"))
2031 auto originalParticle = particles[particle->getExtraInfo(
"original_index")];
2032 if (!originalParticle)
2034 auto var_result = var->function(originalParticle);
2035 if (std::holds_alternative<double>(var_result))
2037 return std::get<double>(var_result);
2038 }
else if (std::holds_alternative<int>(var_result))
2040 return std::get<int>(var_result);
2041 }
else if (std::holds_alternative<bool>(var_result))
2043 return std::get<bool>(var_result);
2048 B2FATAL(
"Wrong number of arguments for meta function originalParticle");
2054 if (arguments.size() == 2) {
2055 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2057 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2058 if (particle ==
nullptr)
2060 int daughterNumber = std::get<int>(daughterFunction(particle));
2061 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2063 auto var_result = var->function(particle->getDaughter(daughterNumber));
2064 if (std::holds_alternative<double>(var_result))
2066 return std::get<double>(var_result);
2067 }
else if (std::holds_alternative<int>(var_result))
2069 return std::get<int>(var_result);
2070 }
else if (std::holds_alternative<bool>(var_result))
2072 return std::get<bool>(var_result);
2077 B2FATAL(
"Wrong number of arguments for meta function daughter");
2083 if (arguments.size() == 2) {
2084 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2086 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2087 if (particle ==
nullptr)
2089 int daughterNumber = std::get<int>(daughterFunction(particle));
2090 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2094 StoreArray<Particle> particles;
2095 if (!particle->getDaughter(daughterNumber)->hasExtraInfo(
"original_index"))
2097 auto originalDaughter = particles[particle->getDaughter(daughterNumber)->getExtraInfo(
"original_index")];
2098 if (!originalDaughter)
2101 auto var_result = var->function(originalDaughter);
2102 if (std::holds_alternative<double>(var_result)) {
2103 return std::get<double>(var_result);
2104 }
else if (std::holds_alternative<int>(var_result)) {
2105 return std::get<int>(var_result);
2106 }
else if (std::holds_alternative<bool>(var_result)) {
2107 return std::get<bool>(var_result);
2113 B2FATAL(
"Wrong number of arguments for meta function daughter");
2119 if (arguments.size() == 1) {
2120 std::string daughterString = arguments[0];
2121 auto func = [daughterString](
const Particle * particle) ->
int {
2122 if (particle ==
nullptr)
2124 int daughterNumber = 0;
2128 }
catch (std::invalid_argument&)
2130 auto daughterFunction = convertToInt({daughterString,
"-1"});
2131 auto daughterVarResult = daughterFunction(particle);
2132 daughterNumber = std::get<int>(daughterVarResult);
2134 return daughterNumber;
2138 B2FATAL(
"Wrong number of arguments for meta function convertToDaughterIndex");
2144 if (arguments.size() == 2) {
2145 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2147 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2148 if (particle ==
nullptr)
2150 if (particle->getMCParticle())
2152 int daughterNumber = std::get<int>(daughterFunction(particle));
2153 if (daughterNumber >=
int(particle->getMCParticle()->getNDaughters()) or daughterNumber < 0)
2155 Particle tempParticle = Particle(particle->getMCParticle()->getDaughters().at(daughterNumber));
2156 auto var_result = var->function(&tempParticle);
2157 if (std::holds_alternative<double>(var_result)) {
2158 return std::get<double>(var_result);
2159 }
else if (std::holds_alternative<int>(var_result)) {
2160 return std::get<int>(var_result);
2161 }
else if (std::holds_alternative<bool>(var_result)) {
2162 return std::get<bool>(var_result);
2173 B2FATAL(
"Wrong number of arguments for meta function mcDaughter");
2179 if (arguments.size() == 1) {
2181 auto func = [var](
const Particle * particle) ->
double {
2182 if (particle ==
nullptr)
2184 if (particle->getMCParticle())
2186 if (particle->getMCParticle()->getMother() ==
nullptr) {
2189 Particle tempParticle = Particle(particle->getMCParticle()->getMother());
2190 auto var_result = var->function(&tempParticle);
2191 if (std::holds_alternative<double>(var_result)) {
2192 return std::get<double>(var_result);
2193 }
else if (std::holds_alternative<int>(var_result)) {
2194 return std::get<int>(var_result);
2195 }
else if (std::holds_alternative<bool>(var_result)) {
2196 return std::get<bool>(var_result);
2205 B2FATAL(
"Wrong number of arguments for meta function mcMother");
2211 if (arguments.size() == 2) {
2212 std::string indexString = arguments[0];
2215 auto func = [var, indexString](
const Particle * particle) ->
double {
2217 int particleNumber = 0;
2221 }
catch (std::invalid_argument&)
2223 auto indexFunction = convertToInt({indexString,
"-1"});
2224 auto indexVarResult = indexFunction(particle);
2225 particleNumber = std::get<int>(indexVarResult);
2228 StoreArray<MCParticle> mcParticles(
"MCParticles");
2229 if (particleNumber < 0 or particleNumber >= mcParticles.getEntries())
2234 const MCParticle* mcParticle = mcParticles[particleNumber];
2235 Particle part = Particle(mcParticle);
2236 auto var_result = var->function(&part);
2237 if (std::holds_alternative<double>(var_result))
2239 return std::get<double>(var_result);
2240 }
else if (std::holds_alternative<int>(var_result))
2242 return std::get<int>(var_result);
2243 }
else if (std::holds_alternative<bool>(var_result))
2245 return std::get<bool>(var_result);
2250 B2FATAL(
"Wrong number of arguments for meta function genParticle");
2256 if (arguments.size() == 1) {
2259 auto func = [var](
const Particle*) ->
double {
2260 StoreArray<MCParticle> mcParticles(
"MCParticles");
2261 if (mcParticles.getEntries() == 0)
2266 const MCParticle* mcUpsilon4S = mcParticles[0];
2267 if (mcUpsilon4S->isInitial()) mcUpsilon4S = mcParticles[2];
2268 if (mcUpsilon4S->getPDG() != 300553)
2273 Particle upsilon4S = Particle(mcUpsilon4S);
2274 auto var_result = var->function(&upsilon4S);
2275 if (std::holds_alternative<double>(var_result))
2277 return std::get<double>(var_result);
2278 }
else if (std::holds_alternative<int>(var_result))
2280 return std::get<int>(var_result);
2281 }
else if (std::holds_alternative<bool>(var_result))
2283 return std::get<bool>(var_result);
2288 B2FATAL(
"Wrong number of arguments for meta function genUpsilon4S");
2294 if (arguments.size() == 4) {
2295 std::string listName = arguments[0];
2296 std::string rankedVariableName = arguments[1];
2297 std::string returnVariableName = arguments[2];
2298 std::string extraInfoName = rankedVariableName +
"_rank";
2302 }
catch (std::invalid_argument&) {
2303 B2ERROR(
"3rd argument of getVariableByRank meta function (Rank) must be an integer!");
2308 auto func = [var, rank, extraInfoName, listName](
const Particle*)->
double {
2309 StoreObjPtr<ParticleList> list(listName);
2311 const unsigned int numParticles = list->getListSize();
2312 for (
unsigned int i = 0; i < numParticles; i++)
2314 const Particle* p = list->getParticle(i);
2315 if (p->getExtraInfo(extraInfoName) == rank) {
2316 auto var_result = var->function(p);
2317 if (std::holds_alternative<double>(var_result)) {
2318 return std::get<double>(var_result);
2319 }
else if (std::holds_alternative<int>(var_result)) {
2320 return std::get<int>(var_result);
2321 }
else if (std::holds_alternative<bool>(var_result)) {
2322 return std::get<bool>(var_result);
2327 return std::numeric_limits<double>::signaling_NaN();
2331 B2FATAL(
"Wrong number of arguments for meta function getVariableByRank");
2337 if (arguments.size() == 1 or arguments.size() == 2) {
2339 std::string listName = arguments[0];
2340 std::string cutString =
"";
2342 if (arguments.size() == 2) {
2343 cutString = arguments[1];
2348 auto func = [listName, cut](
const Particle*) ->
int {
2350 StoreObjPtr<ParticleList> list(listName);
2352 for (
unsigned int i = 0; i < list->getListSize(); i++)
2354 const Particle* particle = list->getParticle(i);
2355 if (cut->check(particle)) {
2363 B2FATAL(
"Wrong number of arguments for meta function countInList");
2369 if (arguments.size() == 2 or arguments.size() == 3) {
2371 std::string roeListName = arguments[0];
2372 std::string cutString = arguments[1];
2374 if (arguments.size() == 2) {
2375 B2INFO(
"Use pdgCode of electron as default in meta variable veto, other arguments: " << roeListName <<
", " << cutString);
2379 }
catch (std::invalid_argument&) {
2380 B2FATAL(
"Third argument of veto meta function must be integer!");
2387 auto func = [roeListName, cut, pdgCode, flavourType](
const Particle * particle) ->
bool {
2388 StoreObjPtr<ParticleList> roeList(roeListName);
2389 ROOT::Math::PxPyPzEVector vec = particle->get4Vector();
2390 for (
unsigned int i = 0; i < roeList->getListSize(); i++)
2392 const Particle* roeParticle = roeList->getParticle(i);
2393 if (not particle->overlapsWith(roeParticle)) {
2394 ROOT::Math::PxPyPzEVector tempCombination = roeParticle->get4Vector() + vec;
2395 std::vector<int> indices = { particle->getArrayIndex(), roeParticle->getArrayIndex() };
2396 Particle tempParticle = Particle(tempCombination, pdgCode, flavourType, indices, particle->getArrayPointer());
2397 if (cut->check(&tempParticle)) {
2406 B2FATAL(
"Wrong number of arguments for meta function veto");
2412 if (arguments.size() == 1) {
2413 std::string cutString = arguments[0];
2415 auto func = [cut](
const Particle * particle) ->
int {
2417 for (
auto& daughter : particle->getDaughters())
2419 if (cut->check(daughter))
2426 B2FATAL(
"Wrong number of arguments for meta function countDaughters");
2432 if (arguments.size() == 1) {
2433 std::string cutString = arguments[0];
2435 auto func = [cut](
const Particle * particle) ->
int {
2437 std::vector<const Particle*> fspDaughters;
2438 particle->fillFSPDaughters(fspDaughters);
2441 for (
auto& daughter : fspDaughters)
2443 if (cut->check(daughter))
2450 B2FATAL(
"Wrong number of arguments for meta function countFSPDaughters");
2456 if (arguments.size() == 1) {
2457 std::string cutString = arguments[0];
2459 auto func = [cut](
const Particle * particle) ->
int {
2461 std::vector<const Particle*> allDaughters;
2462 particle->fillAllDaughters(allDaughters);
2465 for (
auto& daughter : allDaughters)
2467 if (cut->check(daughter))
2474 B2FATAL(
"Wrong number of arguments for meta function countDescendants");
2478 Manager::FunctionPtr numberOfNonOverlappingParticles(
const std::vector<std::string>& arguments)
2481 auto func = [arguments](
const Particle * particle) ->
int {
2483 int _numberOfNonOverlappingParticles = 0;
2484 for (
const auto& listName : arguments)
2486 StoreObjPtr<ParticleList> list(listName);
2487 if (not list.isValid()) {
2488 B2FATAL(
"Invalid list named " << listName <<
" encountered in numberOfNonOverlappingParticles.");
2490 for (
unsigned int i = 0; i < list->getListSize(); i++) {
2491 const Particle* p = list->getParticle(i);
2492 if (not particle->overlapsWith(p)) {
2493 _numberOfNonOverlappingParticles++;
2497 return _numberOfNonOverlappingParticles;
2504 void appendDaughtersRecursive(Particle* mother, StoreArray<Particle>& container)
2507 auto* mcmother = mother->getRelated<MCParticle>();
2512 for (
auto* mcdaughter : mcmother->getDaughters()) {
2514 Particle tmp_daughter(mcdaughter);
2515 Particle* new_daughter = container.appendNew(tmp_daughter);
2516 new_daughter->addRelationTo(mcdaughter);
2517 mother->appendDaughter(new_daughter,
false);
2519 if (mcdaughter->getNDaughters() > 0)
2520 appendDaughtersRecursive(new_daughter, container);
2526 if (arguments.size() == 1) {
2528 auto func = [var](
const Particle * particle) ->
double {
2529 const MCParticle* mcp = particle->getMCParticle();
2534 StoreArray<Particle> tempParticles(
"tempParticles");
2535 tempParticles.clear();
2536 Particle tmpPart(mcp);
2537 Particle* newPart = tempParticles.appendNew(tmpPart);
2538 newPart->addRelationTo(mcp);
2540 appendDaughtersRecursive(newPart, tempParticles);
2542 auto var_result = var->function(newPart);
2543 if (std::holds_alternative<double>(var_result))
2545 return std::get<double>(var_result);
2546 }
else if (std::holds_alternative<int>(var_result))
2548 return std::get<int>(var_result);
2549 }
else if (std::holds_alternative<bool>(var_result))
2551 return std::get<bool>(var_result);
2556 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
2562 if (arguments.size() == 1) {
2565 auto func = [var](
const Particle * particle) ->
double {
2567 const ECLCluster* cluster = particle->getECLCluster();
2570 auto mcps = cluster->getRelationsTo<MCParticle>();
2573 std::vector<std::pair<double, int>> weightsAndIndices;
2574 for (
unsigned int i = 0; i < mcps.size(); ++i)
2575 weightsAndIndices.emplace_back(mcps.weight(i), i);
2578 std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
2579 ValueIndexPairSorting::higherPair<
decltype(weightsAndIndices)::value_type>);
2581 const MCParticle* mcp = mcps.object(weightsAndIndices[0].second);
2583 StoreArray<Particle> tempParticles(
"tempParticles");
2584 tempParticles.clear();
2585 Particle tmpPart(mcp);
2586 Particle* newPart = tempParticles.appendNew(tmpPart);
2587 newPart->addRelationTo(mcp);
2589 appendDaughtersRecursive(newPart, tempParticles);
2591 auto var_result = var->function(newPart);
2592 if (std::holds_alternative<double>(var_result))
2594 return std::get<double>(var_result);
2595 }
else if (std::holds_alternative<int>(var_result))
2597 return std::get<int>(var_result);
2598 }
else if (std::holds_alternative<bool>(var_result))
2600 return std::get<bool>(var_result);
2609 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCParticle");
2615 if (arguments.size() == 1) {
2618 auto func = [var](
const Particle * particle) ->
double {
2620 const ECLCluster* cluster = particle->getECLCluster();
2623 auto mcps = cluster->getRelationsTo<MCParticle>();
2626 std::map<int, double> mapMCParticleIndxAndWeight;
2627 getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
2630 if (mapMCParticleIndxAndWeight.size() == 0)
2634 auto maxMap = std::max_element(mapMCParticleIndxAndWeight.begin(), mapMCParticleIndxAndWeight.end(),
2635 [](
const auto & x,
const auto & y) { return x.second < y.second; }
2638 StoreArray<MCParticle> mcparticles;
2639 const MCParticle* mcKlong = mcparticles[maxMap->first];
2641 Particle tmpPart(mcKlong);
2642 auto var_result = var->function(&tmpPart);
2643 if (std::holds_alternative<double>(var_result))
2645 return std::get<double>(var_result);
2646 }
else if (std::holds_alternative<int>(var_result))
2648 return std::get<int>(var_result);
2649 }
else if (std::holds_alternative<bool>(var_result))
2651 return std::get<bool>(var_result);
2660 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCKlong");
2664 double matchedMCHasPDG(
const Particle* particle,
const std::vector<double>& pdgCode)
2666 if (pdgCode.size() != 1) {
2667 B2FATAL(
"Too many arguments provided to matchedMCHasPDG!");
2669 int inputPDG = std::lround(pdgCode[0]);
2671 const MCParticle* mcp = particle->getMCParticle();
2675 return std::abs(mcp->getPDG()) == inputPDG;
2680 if (arguments.size() == 1) {
2681 std::string listName = arguments[0];
2682 auto func = [listName](
const Particle * particle) ->
double {
2685 StoreObjPtr<ParticleList> listOfParticles(listName);
2687 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2688 double totalEnergy = 0;
2689 int nParticles = listOfParticles->getListSize();
2690 for (
int i = 0; i < nParticles; i++)
2692 const Particle* part = listOfParticles->getParticle(i);
2694 totalEnergy += frame.getMomentum(part).E();
2701 B2FATAL(
"Wrong number of arguments for meta function totalEnergyOfParticlesInList");
2707 if (arguments.size() == 1) {
2708 std::string listName = arguments[0];
2709 auto func = [listName](
const Particle*) ->
double {
2710 StoreObjPtr<ParticleList> listOfParticles(listName);
2712 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPxOfParticlesInList");
2714 int nParticles = listOfParticles->getListSize();
2716 for (
int i = 0; i < nParticles; i++)
2718 const Particle* part = listOfParticles->getParticle(i);
2719 totalPx += frame.getMomentum(part).Px();
2725 B2FATAL(
"Wrong number of arguments for meta function totalPxOfParticlesInList");
2731 if (arguments.size() == 1) {
2732 std::string listName = arguments[0];
2733 auto func = [listName](
const Particle*) ->
double {
2734 StoreObjPtr<ParticleList> listOfParticles(listName);
2736 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPyOfParticlesInList");
2738 int nParticles = listOfParticles->getListSize();
2740 for (
int i = 0; i < nParticles; i++)
2742 const Particle* part = listOfParticles->getParticle(i);
2743 totalPy += frame.getMomentum(part).Py();
2749 B2FATAL(
"Wrong number of arguments for meta function totalPyOfParticlesInList");
2755 if (arguments.size() == 1) {
2756 std::string listName = arguments[0];
2757 auto func = [listName](
const Particle*) ->
double {
2758 StoreObjPtr<ParticleList> listOfParticles(listName);
2760 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPzOfParticlesInList");
2762 int nParticles = listOfParticles->getListSize();
2764 for (
int i = 0; i < nParticles; i++)
2766 const Particle* part = listOfParticles->getParticle(i);
2767 totalPz += frame.getMomentum(part).Pz();
2773 B2FATAL(
"Wrong number of arguments for meta function totalPzOfParticlesInList");
2779 if (arguments.size() > 0) {
2781 auto func = [arguments](
const Particle * particle) ->
double {
2783 ROOT::Math::PxPyPzEVector total4Vector;
2785 std::vector<Particle*> particlePool;
2788 for (
const auto& argument : arguments)
2790 StoreObjPtr <ParticleList> listOfParticles(argument);
2792 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << argument <<
" given to invMassInLists");
2793 int nParticles = listOfParticles->getListSize();
2794 for (
int i = 0; i < nParticles; i++) {
2795 bool overlaps =
false;
2796 Particle* part = listOfParticles->getParticle(i);
2797 for (
const auto* poolPart : particlePool) {
2798 if (part->overlapsWith(poolPart)) {
2804 total4Vector += part->get4Vector();
2805 particlePool.push_back(part);
2809 double invariantMass = total4Vector.M();
2810 return invariantMass;
2815 B2FATAL(
"Wrong number of arguments for meta function invMassInLists");
2819 Manager::FunctionPtr totalECLEnergyOfParticlesInList(
const std::vector<std::string>& arguments)
2821 if (arguments.size() == 1) {
2822 std::string listName = arguments[0];
2823 auto func = [listName](
const Particle * particle) ->
double {
2826 StoreObjPtr<ParticleList> listOfParticles(listName);
2828 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2829 double totalEnergy = 0;
2830 int nParticles = listOfParticles->getListSize();
2831 for (
int i = 0; i < nParticles; i++)
2833 const Particle* part = listOfParticles->getParticle(i);
2834 const ECLCluster* cluster = part->getECLCluster();
2836 if (cluster !=
nullptr) {
2837 totalEnergy += cluster->getEnergy(clusterHypothesis);
2845 B2FATAL(
"Wrong number of arguments for meta function totalECLEnergyOfParticlesInList");
2851 if (arguments.size() == 1) {
2852 std::string listName = arguments[0];
2853 auto func = [listName](
const Particle*) ->
double {
2854 StoreObjPtr<ParticleList> listOfParticles(listName);
2856 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxPtInList");
2857 int nParticles = listOfParticles->getListSize();
2860 for (
int i = 0; i < nParticles; i++)
2862 const Particle* part = listOfParticles->getParticle(i);
2863 const double Pt = frame.getMomentum(part).Pt();
2864 if (Pt > maxPt) maxPt = Pt;
2870 B2FATAL(
"Wrong number of arguments for meta function maxPtInList");
2874 Manager::FunctionPtr eclClusterTrackMatchedWithCondition(
const std::vector<std::string>& arguments)
2876 if (arguments.size() <= 1) {
2878 std::string cutString;
2879 if (arguments.size() == 1)
2880 cutString = arguments[0];
2882 auto func = [cut](
const Particle * particle) ->
double {
2884 if (particle ==
nullptr)
2887 const ECLCluster* cluster = particle->getECLCluster();
2891 auto tracks = cluster->getRelationsFrom<Track>();
2893 for (
const auto& track : tracks) {
2896 if (cut->check(&trackParticle))
2905 B2FATAL(
"Wrong number of arguments for meta function eclClusterSpecialTrackMatched");
2911 if (arguments.size() == 2) {
2912 std::string listName = arguments[0];
2915 auto func = [listName, var](
const Particle*) ->
double {
2916 StoreObjPtr<ParticleList> listOfParticles(listName);
2918 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to averageValueInList");
2919 int nParticles = listOfParticles->getListSize();
2920 if (nParticles == 0)
2925 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2927 for (
int i = 0; i < nParticles; i++) {
2928 average += std::get<double>(var->function(listOfParticles->getParticle(i))) / nParticles;
2930 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2932 for (
int i = 0; i < nParticles; i++) {
2933 average += std::get<int>(var->function(listOfParticles->getParticle(i))) / nParticles;
2940 B2FATAL(
"Wrong number of arguments for meta function averageValueInList");
2946 if (arguments.size() == 2) {
2947 std::string listName = arguments[0];
2950 auto func = [listName, var](
const Particle*) ->
double {
2951 StoreObjPtr<ParticleList> listOfParticles(listName);
2953 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to medianValueInList");
2954 int nParticles = listOfParticles->getListSize();
2955 if (nParticles == 0)
2959 std::vector<double> valuesInList;
2960 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2962 for (
int i = 0; i < nParticles; i++) {
2963 valuesInList.push_back(std::get<double>(var->function(listOfParticles->getParticle(i))));
2965 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2967 for (
int i = 0; i < nParticles; i++) {
2968 valuesInList.push_back(std::get<int>(var->function(listOfParticles->getParticle(i))));
2971 std::sort(valuesInList.begin(), valuesInList.end());
2972 if (nParticles % 2 != 0)
2974 return valuesInList[nParticles / 2];
2977 return 0.5 * (valuesInList[nParticles / 2] + valuesInList[nParticles / 2 - 1]);
2982 B2FATAL(
"Wrong number of arguments for meta function medianValueInList");
2988 if (arguments.size() == 2) {
2989 std::string listName = arguments[0];
2992 auto func = [listName, var](
const Particle*) ->
double {
2993 StoreObjPtr<ParticleList> listOfParticles(listName);
2995 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to sumValueInList");
2996 int nParticles = listOfParticles->getListSize();
2997 if (nParticles == 0)
3002 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
3004 for (
int i = 0; i < nParticles; i++) {
3005 sum += std::get<double>(var->function(listOfParticles->getParticle(i)));
3007 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
3009 for (
int i = 0; i < nParticles; i++) {
3010 sum += std::get<int>(var->function(listOfParticles->getParticle(i)));
3017 B2FATAL(
"Wrong number of arguments for meta function sumValueInList");
3023 if (arguments.size() == 2) {
3024 std::string listName = arguments[0];
3027 auto func = [listName, var](
const Particle*) ->
double {
3028 StoreObjPtr<ParticleList> listOfParticles(listName);
3030 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to productValueInList");
3031 int nParticles = listOfParticles->getListSize();
3032 if (nParticles == 0)
3037 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
3039 for (
int i = 0; i < nParticles; i++) {
3040 product *= std::get<double>(var->function(listOfParticles->getParticle(i)));
3042 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
3044 for (
int i = 0; i < nParticles; i++) {
3045 product *= std::get<int>(var->function(listOfParticles->getParticle(i)));
3052 B2FATAL(
"Wrong number of arguments for meta function productValueInList");
3059 if (arguments.size() != 1)
3060 B2FATAL(
"Wrong number of arguments for meta function angleToClosestInList");
3062 std::string listname = arguments[0];
3064 auto func = [listname](
const Particle * particle) ->
double {
3066 StoreObjPtr<ParticleList> list(listname);
3067 if (not list.isValid())
3068 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToClosestInList");
3071 if (list->getListSize() == 0)
3076 const auto p_this = frame.getMomentum(particle);
3079 double minAngle = 2 * M_PI;
3080 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3082 const Particle* compareme = list->getParticle(i);
3083 const auto p_compare = frame.getMomentum(compareme);
3084 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3085 if (minAngle > angle) minAngle = angle;
3095 if (arguments.size() != 2)
3096 B2FATAL(
"Wrong number of arguments for meta function closestInList");
3098 std::string listname = arguments[0];
3103 auto func = [listname, var](
const Particle * particle) ->
double {
3105 StoreObjPtr<ParticleList> list(listname);
3106 if (not list.isValid())
3107 B2FATAL(
"Invalid particle list name " << listname <<
" given to closestInList");
3111 const auto p_this = frame.getMomentum(particle);
3114 double minAngle = 2 * M_PI;
3116 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3118 const Particle* compareme = list->getParticle(i);
3119 const auto p_compare = frame.getMomentum(compareme);
3120 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3121 if (minAngle > angle) {
3129 auto var_result = var->function(list->getParticle(iClosest));
3130 if (std::holds_alternative<double>(var_result))
3132 return std::get<double>(var_result);
3133 }
else if (std::holds_alternative<int>(var_result))
3135 return std::get<int>(var_result);
3136 }
else if (std::holds_alternative<bool>(var_result))
3138 return std::get<bool>(var_result);
3147 if (arguments.size() != 1)
3148 B2FATAL(
"Wrong number of arguments for meta function angleToMostB2BInList");
3150 std::string listname = arguments[0];
3152 auto func = [listname](
const Particle * particle) ->
double {
3154 StoreObjPtr<ParticleList> list(listname);
3155 if (not list.isValid())
3156 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToMostB2BInList");
3159 if (list->getListSize() == 0)
3164 const auto p_this = frame.getMomentum(particle);
3168 double maxAngle = 0;
3169 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3171 const Particle* compareme = list->getParticle(i);
3172 const auto p_compare = frame.getMomentum(compareme);
3173 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3174 if (maxAngle < angle) maxAngle = angle;
3184 if (arguments.size() != 1)
3185 B2FATAL(
"Wrong number of arguments for meta function deltaPhiToMostB2BPhiInList");
3187 std::string listname = arguments[0];
3189 auto func = [listname](
const Particle * particle) ->
double {
3191 StoreObjPtr<ParticleList> list(listname);
3192 if (not list.isValid())
3193 B2FATAL(
"Invalid particle list name " << listname <<
" given to deltaPhiToMostB2BPhiInList");
3196 if (list->getListSize() == 0)
3201 const auto phi_this = frame.getMomentum(particle).Phi();
3204 double maxAngle = 0;
3205 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3207 const Particle* compareme = list->getParticle(i);
3208 const auto phi_compare = frame.getMomentum(compareme).Phi();
3209 double angle = std::abs(phi_compare - phi_this);
3210 if (angle > M_PI) {angle = 2 * M_PI - angle;}
3211 if (maxAngle < angle) maxAngle = angle;
3221 if (arguments.size() != 2)
3222 B2FATAL(
"Wrong number of arguments for meta function mostB2BInList");
3224 std::string listname = arguments[0];
3229 auto func = [listname, var](
const Particle * particle) ->
double {
3231 StoreObjPtr<ParticleList> list(listname);
3232 if (not list.isValid())
3233 B2FATAL(
"Invalid particle list name " << listname <<
" given to mostB2BInList");
3237 const auto p_this = frame.getMomentum(particle);
3241 double maxAngle = -1.0;
3243 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3245 const Particle* compareme = list->getParticle(i);
3246 const auto p_compare = frame.getMomentum(compareme);
3247 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3248 if (maxAngle < angle) {
3256 auto var_result = var->function(list->getParticle(iMostB2B));
3257 if (std::holds_alternative<double>(var_result))
3259 return std::get<double>(var_result);
3260 }
else if (std::holds_alternative<int>(var_result))
3262 return std::get<int>(var_result);
3263 }
else if (std::holds_alternative<bool>(var_result))
3265 return std::get<bool>(var_result);
3273 if (arguments.size() == 1) {
3274 std::string listName = arguments[0];
3275 auto func = [listName](
const Particle*) ->
double {
3276 StoreObjPtr<ParticleList> listOfParticles(listName);
3278 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxOpeningAngleInList");
3279 int nParticles = listOfParticles->getListSize();
3284 double maxOpeningAngle = -1;
3285 for (
int i = 0; i < nParticles; i++)
3287 ROOT::Math::PxPyPzEVector v1 = frame.getMomentum(listOfParticles->getParticle(i));
3288 for (
int j = i + 1; j < nParticles; j++) {
3289 ROOT::Math::PxPyPzEVector v2 = frame.getMomentum(listOfParticles->getParticle(j));
3290 const double angle = ROOT::Math::VectorUtil::Angle(v1, v2);
3291 if (angle > maxOpeningAngle) maxOpeningAngle = angle;
3294 return maxOpeningAngle;
3298 B2FATAL(
"Wrong number of arguments for meta function maxOpeningAngleInList");
3305 if (arguments.size() >= 2) {
3310 auto func = [var, arguments](
const Particle * particle) ->
double {
3311 if (particle ==
nullptr)
3313 B2WARNING(
"Trying to access a daughter that does not exist. Skipping");
3319 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
3323 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++)
3325 auto generalizedIndex = arguments[iCoord];
3326 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
3328 pSum += frame.getMomentum(dauPart);
3330 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
3336 Particle sumOfDaughters(pSum, 100);
3338 auto var_result = var->function(&sumOfDaughters);
3340 if (std::holds_alternative<double>(var_result))
3342 return std::get<double>(var_result);
3343 }
else if (std::holds_alternative<int>(var_result))
3345 return std::get<int>(var_result);
3346 }
else if (std::holds_alternative<bool>(var_result))
3348 return std::get<bool>(var_result);
3353 B2FATAL(
"Wrong number of arguments for meta function daughterCombination");
3356 Manager::FunctionPtr useAlternativeDaughterHypothesis(
const std::vector<std::string>& arguments)
3369 if (arguments.size() >= 2) {
3380 std::unordered_map<unsigned int, int> mapOfReplacedDaughters;
3383 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++) {
3384 auto replacedDauString = arguments[iCoord];
3386 std::vector<std::string> indexAndMass;
3387 boost::split(indexAndMass, replacedDauString, boost::is_any_of(
":"));
3390 if (indexAndMass.size() > 2) {
3391 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 "
3392 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3396 if (indexAndMass.size() < 2) {
3397 B2WARNING(
"The string indicating which daughter's mass should be replaced contains only one colon-separated element instead of two. The offending string is "
3398 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3406 }
catch (std::invalid_argument&) {
3407 B2FATAL(
"Found the string " << indexAndMass[0] <<
"instead of a daughter index.");
3411 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(indexAndMass[1].c_str());
3413 B2WARNING(
"Particle not in evt.pdl file! " << indexAndMass[1]);
3418 int pdgCode = particlePDG->PdgCode();
3419 mapOfReplacedDaughters[dauIndex] = pdgCode;
3423 if (mapOfReplacedDaughters.size() != arguments.size() - 1)
3424 B2FATAL(
"Overlapped daughter's index is detected in the meta-variable useAlternativeDaughterHypothesis");
3432 auto func = [var, mapOfReplacedDaughters](
const Particle * particle) ->
double {
3433 if (particle ==
nullptr)
3435 B2WARNING(
"Trying to access a particle that does not exist. Skipping");
3445 ROOT::Math::PxPyPzMVector pSum(0, 0, 0, 0);
3447 for (
unsigned int iDau = 0; iDau < particle->getNDaughters(); iDau++)
3449 const Particle* dauPart = particle->getDaughter(iDau);
3451 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << iDau);
3455 ROOT::Math::PxPyPzMVector dauMom = ROOT::Math::PxPyPzMVector(frame.getMomentum(dauPart));
3459 pdgCode = mapOfReplacedDaughters.at(iDau);
3460 }
catch (std::out_of_range&) {
3467 double p_x = dauMom.Px();
3468 double p_y = dauMom.Py();
3469 double p_z = dauMom.Pz();
3470 dauMom.SetCoordinates(p_x, p_y, p_z, TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass());
3471 const_cast<Particle*
>(dummy->getDaughter(iDau))->set4VectorDividingByMomentumScaling(ROOT::Math::PxPyPzEVector(dauMom));
3474 const int charge = dummy->getDaughter(iDau)->getCharge();
3475 if (TDatabasePDG::Instance()->GetParticle(pdgCode)->Charge() / 3.0 == charge)
3476 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(pdgCode);
3478 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(-1 * pdgCode);
3484 dummy->set4Vector(ROOT::Math::PxPyPzEVector(pSum));
3486 auto var_result = var->function(dummy);
3489 if (std::holds_alternative<double>(var_result))
3491 return std::get<double>(var_result);
3492 }
else if (std::holds_alternative<int>(var_result))
3494 return std::get<int>(var_result);
3495 }
else if (std::holds_alternative<bool>(var_result))
3497 return std::get<bool>(var_result);
3503 B2FATAL(
"Wrong number of arguments for meta function useAlternativeDaughterHypothesis");
3508 if (arguments.size() == 2) {
3510 std::string arg = arguments[0];
3512 TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(arg.c_str());
3514 if (part !=
nullptr) {
3515 pdg_code = std::abs(part->PdgCode());
3519 }
catch (
const std::exception& e) {}
3522 if (pdg_code == -1) {
3523 B2FATAL(
"Ancestor " + arg +
" is not recognised. Please provide valid PDG code or particle name.");
3526 auto func = [pdg_code, var](
const Particle * particle) ->
double {
3527 const Particle* p = particle;
3529 int ancestor_level = std::get<double>(
Manager::Instance().getVariable(
"hasAncestor(" + std::to_string(pdg_code) +
", 0)")->function(p));
3530 if ((ancestor_level <= 0) or (std::isnan(ancestor_level)))
3535 const MCParticle* i_p = p->getMCParticle();
3537 for (
int a = 0; a < ancestor_level ; a = a + 1)
3539 i_p = i_p->getMother();
3542 StoreArray<Particle> tempParticles(
"tempParticles");
3543 tempParticles.clear();
3545 Particle* newPart = tempParticles.appendNew(m_p);
3546 newPart->addRelationTo(i_p);
3548 appendDaughtersRecursive(newPart, tempParticles);
3550 auto var_result = var->function(newPart);
3551 if (std::holds_alternative<double>(var_result))
3553 return std::get<double>(var_result);
3554 }
else if (std::holds_alternative<int>(var_result))
3556 return std::get<int>(var_result);
3557 }
else if (std::holds_alternative<bool>(var_result))
3559 return std::get<bool>(var_result);
3564 B2FATAL(
"Wrong number of arguments for meta function varForFirstMCAncestorOfType (expected 2: type and variable of interest)");
3570 if (arguments.size() > 4 || arguments.size() < 3) {
3571 B2FATAL(
"Number of arguments for varForNthDaughterOfType must be 3 or 4");
3574 std::string argPtype = arguments[0];
3575 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3576 TParticlePDG* part = pdgDatabase->GetParticle(argPtype.c_str());
3578 if (part !=
nullptr) {
3579 absPdg = std::abs(part->PdgCode());
3583 }
catch (
const std::exception&) { }
3585 if (absPdg == -1 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3586 B2FATAL(
"varForNthDaughterOfType: argument '" << argPtype <<
"' is neither a valid particle name nor a PDG code");
3589 std::string argIndex = arguments[1];
3593 }
catch (
const std::exception&) { }
3595 B2FATAL(
"varForNthDaughterOfType: argument '" << argIndex <<
"' is not a valid positive integer");
3601 if (arguments.size() == 4) {
3602 std::string argDepth = arguments[3];
3605 }
catch (
const std::exception&) {
3609 B2FATAL(
"varForNthDaughterOfType: argument '" << argDepth <<
"' is not a valid positive integer");
3613 auto func = [absPdg, index, var, depth](
const Particle * particle) ->
double {
3615 std::vector<Particle*> currentLevel = particle->getDaughters();
3616 std::vector<Particle*> nextLevel;
3617 for (
int d = 0; d < depth; d++)
3620 for (
unsigned i = 0; i < currentLevel.size(); i++) {
3621 Particle* p = currentLevel[i];
3622 if (std::abs(p->getPDGCode()) == absPdg) {
3624 if (nFound == index) {
3625 auto result = var->function(p);
3626 if (std::holds_alternative<double>(result)) {
3627 return std::get<double>(result);
3628 }
else if (std::holds_alternative<int>(result)) {
3629 return std::get<int>(result);
3630 }
else if (std::holds_alternative<bool>(result)) {
3631 return std::get<bool>(result);
3635 std::vector<Particle*> newParticles = p->getDaughters();
3636 nextLevel.insert(nextLevel.end(), newParticles.begin(), newParticles.end());
3638 currentLevel.clear();
3639 std::swap(currentLevel, nextLevel);
3649 if (arguments.size() != 1) {
3650 B2FATAL(
"Number of arguments for nTrackFitResults must be 1, particleType or PDGcode");
3653 std::string arg = arguments[0];
3654 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3655 TParticlePDG* part = pdgDatabase->GetParticle(arg.c_str());
3657 if (part !=
nullptr) {
3658 absPdg = std::abs(part->PdgCode());
3662 }
catch (
const std::exception&) {
3666 if (absPdg == 0 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3667 B2FATAL(
"nTrackFitResults: argument '" << arg <<
"' is neither a valid particle name nor a PDG code");
3671 auto func = [absPdg](
const Particle*) ->
int {
3673 Const::ChargedStable type(absPdg);
3674 StoreArray<Track> tracks;
3676 int nTrackFitResults = 0;
3678 for (
const auto& track : tracks)
3680 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(type);
3682 if (!trackFit)
continue;
3683 if (trackFit->getChargeSign() == 0)
continue;
3688 return nTrackFitResults;
3697 if (arguments.size() == 2) {
3700 auto func = [var, default_val](
const Particle * particle) ->
int {
3701 auto var_result = var->function(particle);
3702 if (std::holds_alternative<double>(var_result))
3704 double value = std::get<double>(var_result);
3705 if (value > std::numeric_limits<int>::max())
3706 value = std::numeric_limits<int>::max();
3707 if (value < std::numeric_limits<int>::min())
3708 value = std::numeric_limits<int>::min();
3709 if (std::isnan(value))
3710 value = default_val;
3711 return static_cast<int>(value);
3712 }
else if (std::holds_alternative<int>(var_result))
3713 return std::get<int>(var_result);
3714 else if (std::holds_alternative<bool>(var_result))
3715 return static_cast<int>(std::get<bool>(var_result));
3716 else return default_val;
3720 B2FATAL(
"Wrong number of arguments for meta function int, please provide variable name and replacement value for NaN!");
3724 VARIABLE_GROUP(
"MetaFunctions");
3725 REGISTER_METAVARIABLE(
"nCleanedECLClusters(cut)", nCleanedECLClusters,
3726 "[Eventbased] Returns the number of clean Clusters in the event\n"
3727 "Clean clusters are defined by the clusters which pass the given cut assuming a photon hypothesis.",
3728 Manager::VariableDataType::c_int);
3729 REGISTER_METAVARIABLE(
"nCleanedTracks(cut)", nCleanedTracks,
3730 "[Eventbased] Returns the number of clean Tracks in the event\n"
3731 "Clean tracks are defined by the tracks which pass the given cut assuming a pion hypothesis.", Manager::VariableDataType::c_int);
3732 REGISTER_METAVARIABLE(
"formula(v1 + v2 * [v3 - v4] / v5^v6)", formula, R
"DOCSTRING(
3733Returns the result of the given formula, where v1 to vN are variables or floating
3734point numbers. Currently the only supported operations are addition (``+``),
3735subtraction (``-``), multiplication (``*``), division (``/``) and power (``^``
3736or ``**``). Parenthesis can be in the form of square brackets ``[v1 * v2]``
3737or normal brackets ``(v1 * v2)``. It will work also with variables taking
3738arguments. Operator precedence is taken into account. For example ::
3740 (daughter(0, E) + daughter(1, E))**2 - p**2 + 0.138
3742.. versionchanged:: release-03-00-00
3743 now both, ``[]`` and ``()`` can be used for grouping operations, ``**`` can
3744 be used for exponent and float literals are possible directly in the
3746)DOCSTRING", Manager::VariableDataType::c_double);
3747 REGISTER_METAVARIABLE("useRestFrame(variable)", useRestFrame,
3748 "Returns the value of the variable using the rest frame of the given particle as current reference frame.\n"
3749 "E.g. ``useRestFrame(daughter(0, p))`` returns the total momentum of the first daughter in its mother's rest-frame", Manager::VariableDataType::c_double);
3750 REGISTER_METAVARIABLE(
"useCMSFrame(variable)", useCMSFrame,
3751 "Returns the value of the variable using the CMS frame as current reference frame.\n"
3752 "E.g. ``useCMSFrame(E)`` returns the energy of a particle in the CMS frame.", Manager::VariableDataType::c_double);
3753 REGISTER_METAVARIABLE(
"useLabFrame(variable)", useLabFrame, R
"DOC(
3754Returns the value of ``variable`` in the *lab* frame.
3757 The lab frame is the default reference frame, usually you don't need to use this meta-variable.
3758 E.g. ``useLabFrame(E)`` returns the energy of a particle in the Lab frame, same as just ``E``.
3760Specifying the lab frame is useful in some corner-cases. For example:
3761``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.
3762)DOC", Manager::VariableDataType::c_double);
3763 REGISTER_METAVARIABLE("useTagSideRecoilRestFrame(variable, daughterIndexTagB)", useTagSideRecoilRestFrame,
3764 "Returns the value of the variable in the rest frame of the recoiling particle to the tag side B meson.\n"
3765 "The variable should only be applied to an Upsilon(4S) list.\n"
3766 "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);
3767 REGISTER_METAVARIABLE(
"useParticleRestFrame(variable, particleList)", useParticleRestFrame,
3768 "Returns the value of the variable in the rest frame of the first Particle contained in the given ParticleList.\n"
3769 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3770 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3771 "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);
3772 REGISTER_METAVARIABLE(
"useRecoilParticleRestFrame(variable, particleList)", useRecoilParticleRestFrame,
3773 "Returns the value of the variable in the rest frame of recoil system against the first Particle contained in the given ParticleList.\n"
3774 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3775 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3776 "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);
3777 REGISTER_METAVARIABLE(
"useDaughterRestFrame(variable, daughterIndex_1[, daughterIndex_2, ... daughterIndex_3])", useDaughterRestFrame,
3778 "Returns the value of the variable in the rest frame of the selected daughter particle.\n"
3779 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3780 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3781 "If two or more indices are given, the rest frame of the sum of the daughters is used. "
3782 "By default only ``daughterIndex_1`` is given, in which case the rest frame of that single daughter is used.",
3783 Manager::VariableDataType::c_double);
3784 REGISTER_METAVARIABLE(
"useDaughterRecoilRestFrame(variable, daughterIndex_1[, daughterIndex_2, ... daughterIndex_3])", useDaughterRecoilRestFrame,
3785 "Returns the value of the variable in the rest frame of the recoil of the selected daughter particle.\n"
3786 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3787 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3788 "If two or more indices are given, the rest frame of the sum of the daughters is used. "
3789 "By default only ``daughterIndex_1`` is given, in which case the recoil rest frame of that single daughter is used.",
3790 Manager::VariableDataType::c_double);
3791 REGISTER_METAVARIABLE(
"useMCancestorBRestFrame(variable)", useMCancestorBRestFrame,
3792 "Returns the value of the variable in the rest frame of the ancestor B MC particle.\n"
3793 "If no B or no MC-matching is found, it returns NaN.", Manager::VariableDataType::c_double);
3794 REGISTER_METAVARIABLE(
"passesCut(cut)", passesCut,
3795 "Returns 1 if particle passes the cut otherwise 0.\n"
3796 "Useful if you want to write out if a particle would have passed a cut or not.", Manager::VariableDataType::c_bool);
3797 REGISTER_METAVARIABLE(
"passesEventCut(cut)", passesEventCut,
3798 "[Eventbased] Returns 1 if event passes the cut otherwise 0.\n"
3799 "Useful if you want to select events passing a cut without looping into particles, such as for skimming.\n", Manager::VariableDataType::c_bool);
3800 REGISTER_METAVARIABLE(
"countDaughters(cut)", countDaughters,
3801 "Returns number of direct daughters which satisfy the cut.\n"
3802 "Used by the skimming package (for what exactly?)", Manager::VariableDataType::c_int);
3803 REGISTER_METAVARIABLE(
"countFSPDaughters(cut)", countDescendants,
3804 "Returns number of final-state daughters which satisfy the cut.",
3805 Manager::VariableDataType::c_int);
3806 REGISTER_METAVARIABLE(
"countDescendants(cut)", countDescendants,
3807 "Returns number of descendants for all generations which satisfy the cut.",
3808 Manager::VariableDataType::c_int);
3809 REGISTER_METAVARIABLE(
"varFor(pdgCode, variable)", varFor,
3810 "Returns the value of the variable for the given particle if its abs(pdgCode) agrees with the given one.\n"
3811 "E.g. ``varFor(11, p)`` returns the momentum if the particle is an electron or a positron.", Manager::VariableDataType::c_double);
3812 REGISTER_METAVARIABLE(
"varForMCGen(variable)", varForMCGen,
3813 "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"
3814 "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"
3815 "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);
3816 REGISTER_METAVARIABLE(
"nParticlesInList(particleListName)", nParticlesInList,
3817 "[Eventbased] Returns number of particles in the given particle List.", Manager::VariableDataType::c_int);
3818 REGISTER_METAVARIABLE(
3819 "nParticlesInCone(particleListName, halfAngleDegrees, cut='')",
3822Counts distinct reconstructed final-state particles from Tracks, ECLClusters,
3823or KLMClusters within a cone around this particle in the e+e- centre-of-mass
3824frame. The half-angle is in degrees (0 to 180). The optional cut applies to
3825particles in particleListName. A particle sharing the central particle's MDST
3826source is excluded; each MDST source is counted at most once. An empty list
3827gives zero. Returns NaN if the central particle has an unsupported source or
3830 Manager::VariableDataType::c_double);
3832 REGISTER_METAVARIABLE("isInList(particleListName)", isInList,
3833 "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);
3834 REGISTER_METAVARIABLE(
"isDaughterOfList(particleListNames)", isDaughterOfList,
3835 "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);
3836 REGISTER_METAVARIABLE(
"isDescendantOfList(particleListName[, anotherParticleListName, ..., generationFlag])", isDescendantOfList, R
"DOC(
3837 Returns 1 if the given particle appears in the decay chain of the particles in the given ParticleLists.
3839 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3841 * ``isDescendantOfList(<particle_list>,1)`` returns 1 if particle is a daughter of the list,
3842 * ``isDescendantOfList(<particle_list>,2)`` returns 1 if particle is a granddaughter of the list,
3843 * ``isDescendantOfList(<particle_list>,3)`` returns 1 if particle is a great-granddaughter of the list, etc.
3844 * Default value is ``-1`` that is inclusive for all generations.
3845 )DOC", Manager::VariableDataType::c_bool);
3846 REGISTER_METAVARIABLE("isMCDescendantOfList(particleListName[, anotherParticleListName, ..., generationFlag])", isMCDescendantOfList, R
"DOC(
3847 Returns 1 if the given particle is linked to the same MC particle as any reconstructed daughter of the decay lists.
3849 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3851 * ``isMCDescendantOfList(<particle_list>,1)`` returns 1 if particle is matched to the same particle as any daughter of the list,
3852 * ``isMCDescendantOfList(<particle_list>,2)`` returns 1 if particle is matched to the same particle as any granddaughter of the list,
3853 * ``isMCDescendantOfList(<particle_list>,3)`` returns 1 if particle is matched to the same particle as any great-granddaughter of the list, etc.
3854 * Default value is ``-1`` that is inclusive for all generations.
3856 It makes only sense for lists created with `fillParticleListFromMC` function with ``addDaughters=True`` argument.
3857 )DOC", Manager::VariableDataType::c_bool);
3859 REGISTER_METAVARIABLE("sourceObjectIsInList(particleListName)", sourceObjectIsInList, R
"DOC(
3860Returns 1 if the underlying mdst object (e.g. track, or cluster) was used to create a particle in ``particleListName``, 0 if not.
3863 This only makes sense for particles that are not composite. Returns -1 for composite particles.
3864)DOC", Manager::VariableDataType::c_int);
3866 REGISTER_METAVARIABLE("mcParticleIsInMCList(particleListName)", mcParticleIsInMCList, R
"DOC(
3867Returns 1 if the particle's matched MC particle is also matched to a particle in ``particleListName``
3868(or if either of the lists were filled from generator level `modularAnalysis.fillParticleListFromMC`.)
3870.. seealso:: :b2:var:`isMCDescendantOfList` to check daughters.
3871)DOC", Manager::VariableDataType::c_bool);
3873 REGISTER_METAVARIABLE("isGrandDaughterOfList(particleListNames)", isGrandDaughterOfList,
3874 "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);
3875 REGISTER_METAVARIABLE(
"originalParticle(variable)", originalParticle, R
"DOC(
3876 Returns value of variable for the original particle from which the given particle is copied.
3878 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3879 Returns NaN if the given particle is not copied and so there is no original particle.
3880 )DOC", Manager::VariableDataType::c_double);
3881 REGISTER_METAVARIABLE("daughter(i, variable)", daughter, R
"DOC(
3882 Returns value of variable for the i-th daughter. E.g.
3884 * ``daughter(0, p)`` returns the total momentum of the first daughter.
3885 * ``daughter(0, daughter(1, p)`` returns the total momentum of the second daughter of the first daughter.
3887 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3888 )DOC", Manager::VariableDataType::c_double);
3889 REGISTER_METAVARIABLE("originalDaughter(i, variable)", originalDaughter, R
"DOC(
3890 Returns value of variable for the original particle from which the i-th daughter is copied.
3892 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3893 Returns NaN if the daughter is not copied and so there is no original daughter.
3895 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3896 )DOC", Manager::VariableDataType::c_double);
3897 REGISTER_METAVARIABLE("mcDaughter(i, variable)", mcDaughter, R
"DOC(
3898 Returns the value of the requested variable for the i-th Monte Carlo daughter of the particle.
3900 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3901 or if the i-th MC daughter does not exist.
3903 E.g. ``mcDaughter(0, PDG)`` will return the PDG code of the first MC daughter of the matched MC
3904 particle of the reconstructed particle the function is applied to.
3906 The meta variable can also be nested: ``mcDaughter(0, mcDaughter(1, PDG))``.
3907 )DOC", Manager::VariableDataType::c_double);
3908 REGISTER_METAVARIABLE("mcMother(variable)", mcMother, R
"DOC(
3909 Returns the value of the requested variable for the Monte Carlo mother of the particle.
3911 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3912 or if the MC mother does not exist.
3914 E.g. ``mcMother(PDG)`` will return the PDG code of the MC mother of the matched MC
3915 particle of the reconstructed particle the function is applied to.
3917 The meta variable can also be nested: ``mcMother(mcMother(PDG))``.
3918 )DOC", Manager::VariableDataType::c_double);
3919 REGISTER_METAVARIABLE("genParticle(index, variable)", genParticle, R
"DOC(
3920[Eventbased] Returns the ``variable`` for the ith generator particle.
3921The arguments of the function must be the ``index`` of the particle in the MCParticle Array,
3922and ``variable``, the name of the function or variable for that generator particle.
3923If ``index`` goes beyond the length of the MCParticles array, NaN will be returned.
3925E.g. ``genParticle(0, p)`` returns the total momentum of the first MCParticle, which in a generic decay up to MC15 is
3926the Upsilon(4S) and for MC16 and beyond the initial electron.
3927)DOC", Manager::VariableDataType::c_double);
3928 REGISTER_METAVARIABLE("genUpsilon4S(variable)", genUpsilon4S, R
"DOC(
3929[Eventbased] Returns the ``variable`` evaluated for the generator-level :math:`\Upsilon(4S)`.
3930If no generator level :math:`\Upsilon(4S)` exists for the event, NaN will be returned.
3932E.g. ``genUpsilon4S(p)`` returns the total momentum of the :math:`\Upsilon(4S)` in a generic decay.
3933``genUpsilon4S(mcDaughter(1, p))`` returns the total momentum of the second daughter of the
3934generator-level :math:`\Upsilon(4S)` (i.e. the momentum of the second B meson in a generic decay).
3935)DOC", Manager::VariableDataType::c_double);
3936 REGISTER_METAVARIABLE("daughterProductOf(variable)", daughterProductOf,
3937 "Returns product of a variable over all daughters.\n"
3938 "E.g. ``daughterProductOf(extraInfo(SignalProbability))`` returns the product of the SignalProbabilitys of all daughters.", Manager::VariableDataType::c_double);
3939 REGISTER_METAVARIABLE(
"daughterSumOf(variable)", daughterSumOf,
3940 "Returns sum of a variable over all daughters.\n"
3941 "E.g. ``daughterSumOf(nDaughters)`` returns the number of grand-daughters.", Manager::VariableDataType::c_double);
3942 REGISTER_METAVARIABLE(
"daughterLowest(variable)", daughterLowest,
3943 "Returns the lowest value of the given variable among all daughters.\n"
3944 "E.g. ``useCMSFrame(daughterLowest(p))`` returns the lowest momentum in CMS frame.", Manager::VariableDataType::c_double);
3945 REGISTER_METAVARIABLE(
"daughterHighest(variable)", daughterHighest,
3946 "Returns the highest value of the given variable among all daughters.\n"
3947 "E.g. ``useCMSFrame(daughterHighest(p))`` returns the highest momentum in CMS frame.", Manager::VariableDataType::c_double);
3948 REGISTER_METAVARIABLE(
"daughterDiffOf(daughterIndex_i, daughterIndex_j, variable)", daughterDiffOf, R
"DOC(
3949 Returns the difference of a variable between the two given daughters.
3950 E.g. ``useRestFrame(daughterDiffOf(0, 1, p))`` returns the momentum difference between first and second daughter in the rest frame of the given particle.
3951 (That means that it returns :math:`p_j - p_i`)
3953 The daughters can be provided as generalized daughter indexes, which are simply colon-separated
3954 lists of daughter indexes, ordered starting from the root particle. For example, ``0:1``
3955 identifies the second daughter (1) of the first daughter (0) of the mother particle.
3957 )DOC", Manager::VariableDataType::c_double);
3958 REGISTER_METAVARIABLE("mcDaughterDiffOf(i, j, variable)", mcDaughterDiffOf,
3959 "MC matched version of the `daughterDiffOf` function.", Manager::VariableDataType::c_double);
3960 REGISTER_METAVARIABLE(
"grandDaughterDiffOf(i, j, variable)", grandDaughterDiffOf,
3961 "Returns the difference of a variable between the first daughters of the two given daughters.\n"
3962 "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"
3963 "(That means that it returns :math:`p_j - p_i`)", Manager::VariableDataType::c_double);
3964 MAKE_DEPRECATED(
"grandDaughterDiffOf",
false,
"light-2402-ocicat", R
"DOC(
3965 The difference between any combination of (grand-)daughters can be calculated with the more general variable :b2:var:`daughterDiffOf`
3966 by using generalized daughter indexes.)DOC");
3967 REGISTER_METAVARIABLE("daughterNormDiffOf(i, j, variable)", daughterNormDiffOf,
3968 "Returns the normalized difference of a variable between the two given daughters.\n"
3969 "E.g. ``daughterNormDiffOf(0, 1, p)`` returns the normalized momentum difference between first and second daughter in the lab frame.", Manager::VariableDataType::c_double);
3970 REGISTER_METAVARIABLE(
"daughterMotherDiffOf(i, variable)", daughterMotherDiffOf,
3971 "Returns the difference of a variable between the given daughter and the mother particle itself.\n"
3972 "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);
3973 REGISTER_METAVARIABLE(
"daughterMotherNormDiffOf(i, variable)", daughterMotherNormDiffOf,
3974 "Returns the normalized difference of a variable between the given daughter and the mother particle itself.\n"
3975 "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);
3976 REGISTER_METAVARIABLE(
"angleBetweenDaughterAndRecoil(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndRecoil, R
"DOC(
3977 Returns the angle between the momentum recoiling against the particle and the sum of the momenta of the given daughters.
3978 The unit of the angle is ``rad``.
3980 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3981 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3982 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3983 identifies the second daughter of the root particle.
3985 At least one generalized index has to be given to ``angleBetweenDaughterAndRecoil``.
3988 ``angleBetweenDaughterAndRecoil(0)`` will return the angle between pRecoil and the momentum of the first daughter.
3990 ``angleBetweenDaughterAndRecoil(0, 1)`` will return the angle between pRecoil and the sum of the momenta of the first and second daughter.
3992 ``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
3993 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3994 REGISTER_METAVARIABLE("angleBetweenDaughterAndMissingMomentum(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndMissingMomentum, R
"DOC(
3995 Returns the angle between the missing momentum in the event and the sum of the momenta of the given daughters.
3996 The unit of the angle is ``rad``. EventKinematics module has to be called to use this.
3998 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3999 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
4000 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
4001 identifies the second daughter of the root particle.
4003 At least one generalized index has to be given to ``angleBetweenDaughterAndMissingMomentum``.
4006 ``angleBetweenDaughterAndMissingMomentum(0)`` will return the angle between missMom and the momentum of the first daughter.
4008 ``angleBetweenDaughterAndMissingMomentum(0, 1)`` will return the angle between missMom and the sum of the momenta of the first and second daughter.
4010 ``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
4011 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
4012 REGISTER_METAVARIABLE("daughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", daughterAngle, R
"DOC(
4013 Returns the angle in between any pair of particles belonging to the same decay tree.
4014 The unit of the angle is ``rad``.
4016 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
4017 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
4018 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
4019 identifies the second daughter of the root particle.
4021 Both two and three generalized indexes can be given to ``daughterAngle``. By default two indices are given, in
4022 which case the variable returns the angle between the momenta of the two given particles. If three indices are given, the
4023 variable returns the angle between the momentum of the third particle and a vector which is the sum of the
4024 first two daughter momenta.
4027 ``daughterAngle(0, 3)`` will return the angle between the first and fourth daughter.
4028 ``daughterAngle(0, 1, 3)`` will return the angle between the fourth daughter and the sum of the first and
4030 ``daughterAngle(0:0, 3:0)`` will return the angle between the first daughter of the first daughter, and
4031 the first daughter of the fourth daughter.
4033 )DOC", Manager::VariableDataType::c_double);
4034 REGISTER_METAVARIABLE("mcDaughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", mcDaughterAngle,
4035 "MC matched version of the `daughterAngle` function. Also works if applied directly to MC particles. "
4036 "As for `daughterAngle`, by default two indices are given and the angle between the momenta of the two given particles is returned; "
4037 "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. "
4038 "The unit of the angle is ``rad``", Manager::VariableDataType::c_double);
4039 REGISTER_VARIABLE(
"grandDaughterDecayAngle(i, j)", grandDaughterDecayAngle,
4040 "Returns the decay angle of the granddaughter in the daughter particle's rest frame.\n"
4041 "It is calculated with respect to the reverted momentum vector of the particle.\n"
4042 "Two arguments representing the daughter and granddaughter indices have to be provided as arguments.\n\n",
"rad");
4043 REGISTER_VARIABLE(
"daughterClusterAngleInBetween(i, j)", daughterClusterAngleInBetween,
4044 "Returns the angle between clusters associated to the two daughters."
4045 "If two indices given: returns the angle between the momenta of the clusters associated to the two given daughters."
4046 "If three indices given: returns the angle between the momentum of the third particle's cluster and a vector "
4047 "which is the sum of the first two daughter's cluster momenta."
4048 "Returns nan if any of the daughters specified don't have an associated cluster."
4049 "The arguments in the argument vector must be integers corresponding to the ith and jth (and kth) daughters.\n\n",
"rad");
4050 REGISTER_METAVARIABLE(
"daughterInvM(i[, j, ...])", daughterInvM, R
"DOC(
4051 Returns the invariant mass adding the Lorentz vectors of the given daughters. The unit of the invariant mass is GeV/:math:`\text{c}^2`
4052 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.
4053 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.
4055 Daughters from different generations of the decay tree can be combined using generalized daughter indexes,
4056 which are simply colon-separated daughter indexes for each generation, starting from the root particle. For
4057 example, ``0:1:3`` identifies the fourth daughter (3) of the second daughter (1) of the first daughter(0) of
4058 the mother particle.
4060 Returns NaN if the given daughter-index is out of bound (>= number of daughters))DOC", Manager::VariableDataType::c_double);
4061 REGISTER_METAVARIABLE("extraInfo(name)", extraInfo,
4062 "Returns extra info stored under the given name.\n"
4063 "The extraInfo has to be set by a module first.\n"
4064 "E.g. ``extraInfo(SignalProbability)`` returns the SignalProbability calculated by the ``MVAExpert`` module.\n"
4065 "If nothing is set under the given name or if the particle is a nullptr, NaN is returned.\n"
4066 "In the latter case please use `eventExtraInfo` if you want to access an EventExtraInfo variable.", Manager::VariableDataType::c_double);
4067 REGISTER_METAVARIABLE(
"eventExtraInfo(name)", eventExtraInfo,
4068 "[Eventbased] Returns extra info stored under the given name in the event extra info.\n"
4069 "The extraInfo has to be set first by another module like MVAExpert in event mode.\n"
4070 "If nothing is set under this name, NaN is returned.", Manager::VariableDataType::c_double);
4071 REGISTER_METAVARIABLE(
"eventCached(variable)", eventCached,
4072 "[Eventbased] Returns value of event-based variable and caches this value in the EventExtraInfo.\n"
4073 "The result of second call to this variable in the same event will be provided from the cache.\n"
4074 "It is recommended to use this variable in order to declare custom aliases as event-based. This is "
4075 "necessary if using the eventwise mode of variablesToNtuple).", Manager::VariableDataType::c_double);
4076 REGISTER_METAVARIABLE(
"particleCached(variable)", particleCached,
4077 "Returns value of given variable and caches this value in the ParticleExtraInfo of the provided particle.\n"
4078 "The result of second call to this variable on the same particle will be provided from the cache.", Manager::VariableDataType::c_double);
4079 REGISTER_METAVARIABLE(
"modulo(variable, n)", modulo,
4080 "Returns rest of division of variable by n.", Manager::VariableDataType::c_int);
4081 REGISTER_METAVARIABLE(
"abs(variable)", abs,
4082 "Returns absolute value of the given variable.\n"
4083 "E.g. abs(mcPDG) returns the absolute value of the mcPDG, which is often useful for cuts.", Manager::VariableDataType::c_double);
4084 REGISTER_METAVARIABLE(
"max(var1,var2)", max,
"Returns max value of two variables.\n", Manager::VariableDataType::c_double);
4085 REGISTER_METAVARIABLE(
"min(var1,var2)", min,
"Returns min value of two variables.\n", Manager::VariableDataType::c_double);
4086 REGISTER_METAVARIABLE(
"sin(variable)", sin,
"Returns sine value of the given variable.", Manager::VariableDataType::c_double);
4087 REGISTER_METAVARIABLE(
"asin(variable)", asin,
"Returns arcsine of the given variable. The unit of the asin() is ``rad``", Manager::VariableDataType::c_double);
4088 REGISTER_METAVARIABLE(
"cos(variable)", cos,
"Returns cosine value of the given variable.", Manager::VariableDataType::c_double);
4089 REGISTER_METAVARIABLE(
"acos(variable)", acos,
"Returns arccosine value of the given variable. The unit of the acos() is ``rad``", Manager::VariableDataType::c_double);
4090 REGISTER_METAVARIABLE(
"tan(variable)", tan,
"Returns tangent value of the given variable.", Manager::VariableDataType::c_double);
4091 REGISTER_METAVARIABLE(
"atan(variable)", atan,
"Returns arctangent value of the given variable. The unit of the atan() is ``rad``", Manager::VariableDataType::c_double);
4092 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);
4093 REGISTER_METAVARIABLE(
"exp(variable)", exp,
"Returns exponential evaluated for the given variable.", Manager::VariableDataType::c_double);
4094 REGISTER_METAVARIABLE(
"log(variable)", log,
"Returns natural logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
4095 REGISTER_METAVARIABLE(
"log10(variable)", log10,
"Returns base-10 logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
4096 REGISTER_METAVARIABLE(
"int(variable, nan_replacement)", convertToInt, R
"DOC(
4097 Casts the output of the variable to an integer value.
4100 Overflow and underflow are clipped at maximum and minimum values, respectively. NaN values are replaced with the value of the 2nd argument.
4102 )DOC", Manager::VariableDataType::c_int);
4103 REGISTER_METAVARIABLE("isNAN(variable)", isNAN,
4104 "Returns true if variable value evaluates to nan (determined via std::isnan(double)).\n"
4105 "Useful for debugging.", Manager::VariableDataType::c_bool);
4106 REGISTER_METAVARIABLE(
"ifNANgiveX(variable, x)", ifNANgiveX,
4107 "Returns x (has to be a number) if variable value is nan (determined via std::isnan(double)).\n"
4108 "Useful for technical purposes while training MVAs.", Manager::VariableDataType::c_double);
4109 REGISTER_METAVARIABLE(
"isInfinity(variable)", isInfinity,
4110 "Returns true if variable value evaluates to infinity (determined via std::isinf(double)).\n"
4111 "Useful for debugging.", Manager::VariableDataType::c_bool);
4112 REGISTER_METAVARIABLE(
"unmask(variable, flag1, flag2, ...)", unmask,
4113 "unmask(variable, flag1, flag2, ...) or unmask(variable, mask) sets certain bits in the variable to zero.\n"
4114 "For example, if you want to set the second, fourth and fifth bits to zero, you could call \n"
4115 "``unmask(variable, 2, 8, 16)`` or ``unmask(variable, 26)``.\n"
4116 "", Manager::VariableDataType::c_double);
4117 REGISTER_METAVARIABLE(
"conditionalVariableSelector(cut, variableIfTrue, variableIfFalse)", conditionalVariableSelector,
4118 "Returns one of the two supplied variables, depending on whether the particle passes the supplied cut.\n"
4119 "The first variable is returned if the particle passes the cut, and the second variable is returned otherwise.", Manager::VariableDataType::c_double);
4120 REGISTER_METAVARIABLE(
"pValueCombination(p1, p2, ...)", pValueCombination,
4121 "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"
4122 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4123 REGISTER_METAVARIABLE(
"pValueCombinationOfDaughters(variable)", pValueCombinationOfDaughters,
4124 "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"
4125 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4126 REGISTER_METAVARIABLE(
"veto(particleList, cut[, pdgCode])", veto,
4127 "Combines current particle with particles from the given particle list and returns 1 if the combination passes the provided cut. \n"
4128 "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"
4129 "around the neutral Pion mass (e.g. ``0.130 < M < 0.140``). \n"
4130 "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"
4131 "The default value of ``pdgCode`` is 11 (electron).", Manager::VariableDataType::c_bool);
4132 REGISTER_METAVARIABLE(
"matchedMC(variable)", matchedMC,
4133 "Returns variable output for the matched MCParticle by constructing a temporary Particle from it.\n"
4134 "This may not work too well if your variable requires accessing daughters of the particle.\n"
4135 "E.g. ``matchedMC(p)`` returns the total momentum of the related MCParticle.\n"
4136 "Returns NaN if no matched MCParticle exists.", Manager::VariableDataType::c_double);
4137 REGISTER_METAVARIABLE(
"clusterBestMatchedMCParticle(variable)", clusterBestMatchedMCParticle,
4138 "Returns variable output for the MCParticle that is best-matched with the ECLCluster of the given Particle.\n"
4139 "E.g. To get the energy of the MCParticle that matches best with an ECLCluster, one could use ``clusterBestMatchedMCParticle(E)``\n"
4140 "When the variable is called for ``gamma`` and if the ``gamma`` is matched with MCParticle, it works same as `matchedMC`.\n"
4141 "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"
4142 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching MCParticles", Manager::VariableDataType::c_double);
4143 REGISTER_METAVARIABLE(
"varForBestMatchedMCKlong(variable)", clusterBestMatchedMCKlong,
4144 "Returns variable output for the Klong MCParticle which has the best match with the ECLCluster of the given Particle.\n"
4145 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching Klong MCParticle", Manager::VariableDataType::c_double);
4147 REGISTER_METAVARIABLE(
"countInList(particleList[, cut])", countInList,
"[Eventbased] "
4148 "Returns number of particle which pass given in cut in the specified particle list.\n"
4149 "Useful for creating statistics about the number of particles in a list.\n"
4150 "E.g. ``countInList(e+, isSignal == 1)`` returns the number of correctly reconstructed electrons in the event.\n"
4151 "The default value of ``cut`` is an empty string, so all particles in the list are counted.\n"
4152 "The variable is event-based and does not need a valid particle pointer as input.", Manager::VariableDataType::c_int);
4153 REGISTER_METAVARIABLE(
"getVariableByRank(particleList, rankedVariableName, variableName, rank)", getVariableByRank, R
"DOC(
4154 [Eventbased] Returns the value of ``variableName`` for the candidate in the ``particleList`` with the requested ``rank``.
4157 The `BestCandidateSelection` module available via `rankByHighest` / `rankByLowest` has to be used before.
4160 The first candidate matching the given rank is used.
4161 Thus, it is not recommended to use this variable in conjunction with ``allowMultiRank`` in the `BestCandidateSelection` module.
4163 The suffix ``_rank`` is automatically added to the argument ``rankedVariableName``,
4164 which either has to be the name of the variable used to order the candidates or the selected outputVariable name without the ending ``_rank``.
4165 This means that your selected name for the rank variable has to end with ``_rank``.
4167 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>`_
4168 )DOC", Manager::VariableDataType::c_double);
4169 REGISTER_VARIABLE("matchedMCHasPDG(PDGCode)", matchedMCHasPDG,
4170 "Returns if the absolute value of the PDGCode of the MCParticle related to the Particle matches a given PDGCode."
4171 "Returns 0/NAN/1 if PDGCode does not match/is not available/ matches");
4172 REGISTER_METAVARIABLE(
"numberOfNonOverlappingParticles(pList1, pList2, ...)", numberOfNonOverlappingParticles,
4173 "Returns the number of non-overlapping particles in the given particle lists"
4174 "Useful to check if there is additional physics going on in the detector if one reconstructed the Y4S", Manager::VariableDataType::c_int);
4175 REGISTER_METAVARIABLE(
"totalEnergyOfParticlesInList(particleListName)", totalEnergyOfParticlesInList,
4176 "[Eventbased] Returns the total energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4177 REGISTER_METAVARIABLE(
"totalPxOfParticlesInList(particleListName)", totalPxOfParticlesInList,
4178 "[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);
4179 REGISTER_METAVARIABLE(
"totalPyOfParticlesInList(particleListName)", totalPyOfParticlesInList,
4180 "[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);
4181 REGISTER_METAVARIABLE(
"totalPzOfParticlesInList(particleListName)", totalPzOfParticlesInList,
4182 "[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);
4183 REGISTER_METAVARIABLE(
"invMassInLists(pList1, pList2, ...)", invMassInLists,
4184 "[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);
4185 REGISTER_METAVARIABLE(
"totalECLEnergyOfParticlesInList(particleListName)", totalECLEnergyOfParticlesInList,
4186 "[Eventbased] Returns the total ECL energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4187 REGISTER_METAVARIABLE(
"maxPtInList(particleListName)", maxPtInList,
4188 "[Eventbased] Returns maximum transverse momentum Pt in the given particle List. The unit of the transverse momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4189 REGISTER_METAVARIABLE(
"eclClusterSpecialTrackMatched(cut)", eclClusterTrackMatchedWithCondition,
4190 "Returns if at least one Track that satisfies the given condition is related to the ECLCluster of the Particle.", Manager::VariableDataType::c_double);
4191 REGISTER_METAVARIABLE(
"averageValueInList(particleListName, variable)", averageValueInList,
4192 "[Eventbased] Returns the arithmetic mean of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4193 REGISTER_METAVARIABLE(
"medianValueInList(particleListName, variable)", medianValueInList,
4194 "[Eventbased] Returns the median value of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4195 REGISTER_METAVARIABLE(
"sumValueInList(particleListName, variable)", sumValueInList,
4196 "[Eventbased] Returns the sum of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4197 REGISTER_METAVARIABLE(
"productValueInList(particleListName, variable)", productValueInList,
4198 "[Eventbased] Returns the product of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4199 REGISTER_METAVARIABLE(
"angleToClosestInList(particleListName)", angleToClosestInList,
4200 "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);
4201 REGISTER_METAVARIABLE(
"closestInList(particleListName, variable)", closestInList,
4202 "Returns `variable` for the closest particle (smallest opening angle) in the list provided.", Manager::VariableDataType::c_double);
4203 REGISTER_METAVARIABLE(
"angleToMostB2BInList(particleListName)", angleToMostB2BInList,
4204 "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);
4205 REGISTER_METAVARIABLE(
"deltaPhiToMostB2BPhiInList(particleListName)", deltaPhiToMostB2BPhiInList,
4206 "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);
4207 REGISTER_METAVARIABLE(
"mostB2BInList(particleListName, variable)", mostB2BInList,
4208 "Returns `variable` for the most back-to-back particle (closest opening angle to 180) in the list provided.", Manager::VariableDataType::c_double);
4209 REGISTER_METAVARIABLE(
"maxOpeningAngleInList(particleListName)", maxOpeningAngleInList,
4210 "[Eventbased] Returns maximum opening angle in the given particle List. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4211 REGISTER_METAVARIABLE(
"daughterCombination(variable, daughterIndex_1, daughterIndex_2 ... daughterIndex_n)", daughterCombination,R
"DOC(
4212Returns a ``variable`` function only of the 4-momentum calculated on an arbitrary set of (grand)daughters.
4215 ``variable`` can only be a function of the daughters' 4-momenta.
4217Daughters from different generations of the decay tree can be combined using generalized daughter indexes, which are simply colon-separated
4218the list of daughter indexes, starting from the root particle: for example, ``0:1:3`` identifies the fourth
4219daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle.
4222 ``daughterCombination(M, 0, 3, 4)`` will return the invariant mass of the system made of the first, fourth and fifth daughter of particle.
4223 ``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.
4225)DOC", Manager::VariableDataType::c_double);
4226 REGISTER_METAVARIABLE("useAlternativeDaughterHypothesis(variable, daughterIndex_1:newMassHyp_1, ..., daughterIndex_n:newMassHyp_n)", useAlternativeDaughterHypothesis,R
"DOC(
4227Returns a ``variable`` calculated using new mass hypotheses for (some of) the particle's daughters.
4230 ``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.
4231 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.
4232 Also, the track fit is not performed again: the variable only re-calculates the 4-vectors using different mass assumptions.
4233 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).
4236 Generalized daughter indexes are not supported (yet!): this variable can be used only on first-generation daughters.
4239 ``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.
4240 ``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.
4242)DOC", Manager::VariableDataType::c_double);
4243 REGISTER_METAVARIABLE("varForFirstMCAncestorOfType(type, variable)",varForFirstMCAncestorOfType,R
"DOC(Returns requested variable of the first ancestor of the given type.
4244Ancestor type can be set up by PDG code or by particle name (check evt.pdl for valid particle names))DOC", Manager::VariableDataType::c_double);
4245 REGISTER_METAVARIABLE("varForNthDaughterOfType(type, n, variable[, maxDepth])",varForNthDaughterOfType,R
"DOC(Returns requested variable for nth daughter (``n`` starting at 1) of the given type.
4246Particle 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).
4247Maximal 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.
4248As 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!)
4249If no nth daughter of the given type can be found at given maximal depth, returns NaN.)DOC", Manager::VariableDataType::c_double);
4251 REGISTER_METAVARIABLE("nTrackFitResults(particleType)", nTrackFitResults,
4252 "[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).",
4253 Manager::VariableDataType::c_int);
4255 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.