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>
45#include <TDatabasePDG.h>
46#include <Math/Vector4D.h>
47#include <Math/VectorUtil.h>
55 double requireDoubleForFrameVariable(
const Variable::Manager::Var* var,
57 const std::string& frameFunction)
59 if (std::holds_alternative<double>(value)) {
60 return std::get<double>(value);
63 const char* returnedType = std::holds_alternative<int>(value) ?
"int" :
"bool";
64 B2ERROR(
"Meta function " << frameFunction <<
" expects a double variable, but '" << var->name
65 <<
"' returned " << returnedType <<
". Returning NaN.");
71 if (arguments.size() == 1) {
73 auto func = [var](
const Particle * particle) ->
double {
74 UseReferenceFrame<RestFrame> frame(particle);
75 return requireDoubleForFrameVariable(var, var->function(particle),
"useRestFrame");
79 B2FATAL(
"Wrong number of arguments for meta function useRestFrame");
85 if (arguments.size() == 1) {
87 auto func = [var](
const Particle * particle) ->
double {
88 UseReferenceFrame<CMSFrame> frame;
89 return requireDoubleForFrameVariable(var, var->function(particle),
"useCMSFrame");
93 B2FATAL(
"Wrong number of arguments for meta function useCMSFrame");
99 if (arguments.size() == 1) {
101 auto func = [var](
const Particle * particle) ->
double {
102 UseReferenceFrame<LabFrame> frame;
103 return requireDoubleForFrameVariable(var, var->function(particle),
"useLabFrame");
107 B2FATAL(
"Wrong number of arguments for meta function useLabFrame");
113 if (arguments.size() == 2) {
115 auto daughterFunction = convertToDaughterIndex({arguments[1]});
116 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
117 int daughterIndexTagB = std::get<int>(daughterFunction(particle));
118 if (daughterIndexTagB < 0)
121 if (particle->getPDGCode() != 300553)
123 B2ERROR(
"Variable should only be used on a Upsilon(4S) Particle List!");
128 ROOT::Math::PxPyPzEVector pSigB = T.getBeamFourMomentum() - particle->getDaughter(daughterIndexTagB)->get4Vector();
129 Particle tmp(pSigB, -particle->getDaughter(daughterIndexTagB)->getPDGCode());
131 UseReferenceFrame<RestFrame> frame(&tmp);
132 return requireDoubleForFrameVariable(var, var->function(particle),
"useTagSideRecoilRestFrame");
137 B2FATAL(
"Wrong number of arguments for meta function useTagSideRecoilRestFrame");
143 if (arguments.size() == 2) {
145 std::string listName = arguments[1];
146 auto func = [var, listName](
const Particle * particle) ->
double {
147 StoreObjPtr<ParticleList> list(listName);
148 unsigned listSize = list->getListSize();
152 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."
153 << LogVar(
"ParticleList", listName)
154 << LogVar(
"Number of candidates in the list", listSize));
155 const Particle* p = list->getParticle(0);
156 UseReferenceFrame<RestFrame> frame(p);
157 return requireDoubleForFrameVariable(var, var->function(particle),
"useParticleRestFrame");
161 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
167 if (arguments.size() == 2) {
169 std::string listName = arguments[1];
170 auto func = [var, listName](
const Particle * particle) ->
double {
171 StoreObjPtr<ParticleList> list(listName);
172 unsigned listSize = list->getListSize();
176 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."
177 << LogVar(
"ParticleList", listName)
178 << LogVar(
"Number of candidates in the list", listSize));
179 const Particle* p = list->getParticle(0);
181 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - p->get4Vector();
183 Particle pRecoil(recoil, 0);
184 pRecoil.setVertex(particle->getVertex());
185 UseReferenceFrame<RestFrame> frame(&pRecoil);
186 return requireDoubleForFrameVariable(var, var->function(particle),
"useRecoilParticleRestFrame");
190 B2FATAL(
"Wrong number of arguments for meta function useParticleRestFrame.");
196 if (arguments.size() >= 2) {
198 auto func = [var, arguments](
const Particle * particle) ->
double {
201 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
203 for (
unsigned int i = 1; i < arguments.size(); i++)
205 auto generalizedIndex = arguments[i];
206 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
208 pSum += dauPart->get4Vector();
212 Particle tmp(pSum, 0);
213 UseReferenceFrame<RestFrame> frame(&tmp);
214 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRestFrame");
218 B2FATAL(
"Wrong number of arguments for meta function useDaughterRestFrame.");
224 if (arguments.size() >= 2) {
226 auto func = [var, arguments](
const Particle * particle) ->
double {
229 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
231 for (
unsigned int i = 1; i < arguments.size(); i++)
233 auto generalizedIndex = arguments[i];
234 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
236 pSum += dauPart->get4Vector();
241 ROOT::Math::PxPyPzEVector recoil = T.getBeamFourMomentum() - pSum;
243 Particle pRecoil(recoil, 0);
244 UseReferenceFrame<RestFrame> frame(&pRecoil);
245 return requireDoubleForFrameVariable(var, var->function(particle),
"useDaughterRecoilRestFrame");
249 B2FATAL(
"Wrong number of arguments for meta function useDaughterRecoilRestFrame.");
255 if (arguments.size() == 1) {
257 auto func = [var](
const Particle * particle) ->
double {
258 int index = ancestorBIndex(particle);
260 StoreArray<MCParticle> mcparticles;
261 Particle temp(mcparticles[index]);
262 UseReferenceFrame<RestFrame> frame(&temp);
263 return requireDoubleForFrameVariable(var, var->function(particle),
"useMCancestorBRestFrame");
267 B2FATAL(
"Wrong number of arguments for meta function useMCancestorBRestFrame.");
273 if (arguments.size() == 1) {
274 auto extraInfoName = arguments[0];
275 auto func = [extraInfoName](
const Particle * particle) ->
double {
276 if (particle ==
nullptr)
278 B2WARNING(
"Returns NaN because the particle is nullptr! If you want EventExtraInfo variables, please use eventExtraInfo() instead");
281 if (particle->hasExtraInfo(extraInfoName))
283 return particle->getExtraInfo(extraInfoName);
291 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
297 if (arguments.size() == 1) {
298 auto extraInfoName = arguments[0];
299 auto func = [extraInfoName](
const Particle*) ->
double {
300 StoreObjPtr<EventExtraInfo> eventExtraInfo;
301 if (not eventExtraInfo.isValid())
303 if (eventExtraInfo->hasExtraInfo(extraInfoName))
305 return eventExtraInfo->getExtraInfo(extraInfoName);
313 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
319 if (arguments.size() == 1) {
322 auto func = [var, key](
const Particle*) ->
double {
324 StoreObjPtr<EventExtraInfo> eventExtraInfo;
325 if (not eventExtraInfo.isValid())
326 eventExtraInfo.create();
327 if (eventExtraInfo->hasExtraInfo(key))
329 return eventExtraInfo->getExtraInfo(key);
333 auto var_result = var->function(
nullptr);
334 if (std::holds_alternative<double>(var_result)) {
335 value = std::get<double>(var_result);
336 }
else if (std::holds_alternative<int>(var_result)) {
337 return std::get<int>(var_result);
338 }
else if (std::holds_alternative<bool>(var_result)) {
339 return std::get<bool>(var_result);
341 eventExtraInfo->addExtraInfo(key, value);
347 B2FATAL(
"Wrong number of arguments for meta function eventCached");
353 if (arguments.size() == 1) {
356 auto func = [var, key](
const Particle * particle) ->
double {
358 if (particle->hasExtraInfo(key))
360 return particle->getExtraInfo(key);
363 double value = std::get<double>(var->function(particle));
371 const_cast<Particle*
>(particle)->addExtraInfo(key, value);
377 B2FATAL(
"Wrong number of arguments for meta function particleCached");
386 if (arguments.size() != 1) B2FATAL(
"Wrong number of arguments for meta function formula");
387 FormulaParser<VariableFormulaConstructor> parser;
389 return parser.parse(arguments[0]);
390 }
catch (std::runtime_error& e) {
397 if (arguments.size() <= 1) {
399 std::string cutString;
400 if (arguments.size() == 1)
401 cutString = arguments[0];
403 auto func = [cut](
const Particle*) ->
int {
405 int number_of_tracks = 0;
406 StoreArray<Track> tracks;
407 for (
const auto& track : tracks)
409 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(
Const::pion);
410 if (!trackFit)
continue;
411 if (trackFit->getChargeSign() == 0) {
415 if (cut->check(&particle))
420 return number_of_tracks;
425 B2FATAL(
"Wrong number of arguments for meta function nCleanedTracks");
431 if (arguments.size() <= 1) {
433 std::string cutString;
434 if (arguments.size() == 1)
435 cutString = arguments[0];
437 auto func = [cut](
const Particle*) ->
int {
439 int number_of_clusters = 0;
440 StoreArray<ECLCluster> clusters;
441 for (
const auto& cluster : clusters)
447 Particle particle(&cluster);
448 if (cut->check(&particle))
449 number_of_clusters++;
452 return number_of_clusters;
457 B2FATAL(
"Wrong number of arguments for meta function nCleanedECLClusters");
463 if (arguments.size() == 1) {
464 std::string cutString = arguments[0];
466 auto func = [cut](
const Particle * particle) ->
bool {
467 if (cut->check(particle))
474 B2FATAL(
"Wrong number of arguments for meta function passesCut");
480 if (arguments.size() == 1) {
481 std::string cutString = arguments[0];
483 auto func = [cut](
const Particle*) ->
bool {
484 if (cut->check(
nullptr))
491 B2FATAL(
"Wrong number of arguments for meta function passesEventCut");
497 if (arguments.size() == 2) {
501 }
catch (std::invalid_argument&) {
502 B2FATAL(
"The first argument of varFor meta function must be a positive integer!");
505 auto func = [pdgCode, var](
const Particle * particle) ->
double {
506 if (std::abs(particle->getPDGCode()) == std::abs(pdgCode))
508 auto var_result = var->function(particle);
509 if (std::holds_alternative<double>(var_result)) {
510 return std::get<double>(var_result);
511 }
else if (std::holds_alternative<int>(var_result)) {
512 return std::get<int>(var_result);
513 }
else if (std::holds_alternative<bool>(var_result)) {
514 return std::get<bool>(var_result);
520 B2FATAL(
"Wrong number of arguments for meta function varFor");
526 if (arguments.size() == 1) {
528 auto func = [var](
const Particle * particle) ->
double {
529 if (particle->getMCParticle())
534 auto var_result = var->function(particle);
535 if (std::holds_alternative<double>(var_result)) {
536 return std::get<double>(var_result);
537 }
else if (std::holds_alternative<int>(var_result)) {
538 return std::get<int>(var_result);
539 }
else if (std::holds_alternative<bool>(var_result)) {
540 return std::get<bool>(var_result);
547 B2FATAL(
"Wrong number of arguments for meta function varForMCGen");
553 if (arguments.size() == 1) {
554 std::string listName = arguments[0];
555 auto func = [listName](
const Particle * particle) ->
int {
558 StoreObjPtr<ParticleList> listOfParticles(listName);
560 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to nParticlesInList");
562 return listOfParticles->getListSize();
567 B2FATAL(
"Wrong number of arguments for meta function nParticlesInList");
574 if (arguments.size() != 1) {
575 B2FATAL(
"Wrong number of arguments for isInList");
577 auto listName = arguments[0];
579 auto func = [listName](
const Particle * particle) ->
bool {
582 StoreObjPtr<ParticleList> list(listName);
583 if (!(list.isValid()))
585 B2FATAL(
"Invalid Listname " << listName <<
" given to isInList");
589 return list->contains(particle);
598 if (arguments.size() != 1) {
599 B2FATAL(
"Wrong number of arguments for sourceObjectIsInList");
601 auto listName = arguments[0];
603 auto func = [listName](
const Particle * particle) ->
int {
606 StoreObjPtr<ParticleList> list(listName);
607 if (!(list.isValid()))
609 B2FATAL(
"Invalid Listname " << listName <<
" given to sourceObjectIsInList");
615 if (particlesource == Particle::EParticleSourceObject::c_Composite
616 or particlesource == Particle::EParticleSourceObject::c_Undefined)
622 for (
unsigned i = 0; i < list->getListSize(); ++i)
624 const Particle* iparticle = list->getParticle(i);
625 if (particle->getMdstSource() == iparticle->getMdstSource())
637 if (arguments.size() != 1) {
638 B2FATAL(
"Wrong number of arguments for mcParticleIsInMCList");
640 auto listName = arguments[0];
642 auto func = [listName](
const Particle * particle) ->
bool {
645 StoreObjPtr<ParticleList> list(listName);
646 if (!(list.isValid()))
647 B2FATAL(
"Invalid Listname " << listName <<
" given to mcParticleIsInMCList");
650 const MCParticle* mcp = particle->getMCParticle();
651 if (mcp ==
nullptr)
return false;
654 for (
unsigned i = 0; i < list->getListSize(); ++i)
656 const MCParticle* imcp = list->getParticle(i)->getMCParticle();
657 if ((imcp !=
nullptr) and (mcp->getArrayIndex() == imcp->getArrayIndex()))
667 B2WARNING(
"isDaughterOfList is outdated and replaced by isDescendantOfList.");
668 std::vector<std::string> new_arguments = arguments;
669 new_arguments.push_back(std::string(
"1"));
670 return isDescendantOfList(new_arguments);
675 B2WARNING(
"isGrandDaughterOfList is outdated and replaced by isDescendantOfList.");
676 std::vector<std::string> new_arguments = arguments;
677 new_arguments.push_back(std::string(
"2"));
678 return isDescendantOfList(new_arguments);
683 if (arguments.size() > 0) {
684 auto listNames = arguments;
685 auto func = [listNames](
const Particle * particle) ->
bool {
687 int generation_flag = -1;
691 }
catch (
const std::exception& e) {}
693 for (
const auto& iListName : listNames)
698 }
catch (
const std::exception& e) {}
701 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
703 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
705 const Particle* daughter = m->getDaughter(i);
706 if ((flag == 1.) or (flag < 0)) {
707 if (p->isCopyOf(daughter)) {
713 if (daughter->getNDaughters() > 0) {
714 result = self(self, daughter, p, flag - 1);
724 StoreObjPtr<ParticleList> listOfParticles(iListName);
726 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isDescendantOfList");
728 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
729 Particle* iParticle = listOfParticles->getParticle(i);
730 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
740 B2FATAL(
"Wrong number of arguments for meta function isDescendantOfList");
746 if (arguments.size() > 0) {
747 auto listNames = arguments;
748 auto func = [listNames](
const Particle * particle) ->
bool {
750 int generation_flag = -1;
754 }
catch (
const std::exception& e) {}
756 if (particle->getMCParticle() ==
nullptr)
761 for (
const auto& iListName : listNames)
766 std::stod(iListName);
768 }
catch (
const std::exception& e) {}
770 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
772 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
774 const Particle* daughter = m->getDaughter(i);
775 if ((flag == 1.) or (flag < 0)) {
776 if (daughter->getMCParticle() !=
nullptr) {
777 if (p->getMCParticle()->getArrayIndex() == daughter->getMCParticle()->getArrayIndex()) {
783 if (daughter->getNDaughters() > 0) {
784 result = self(self, daughter, p, flag - 1);
794 StoreObjPtr<ParticleList> listOfParticles(iListName);
796 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isMCDescendantOfList");
798 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
799 Particle* iParticle = listOfParticles->getParticle(i);
800 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
810 B2FATAL(
"Wrong number of arguments for meta function isMCDescendantOfList");
816 if (arguments.size() == 1) {
818 auto func = [var](
const Particle * particle) ->
double {
819 double product = 1.0;
820 if (particle->getNDaughters() == 0)
824 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
826 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
827 product *= std::get<double>(var->function(particle->getDaughter(j)));
829 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
831 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
832 product *= std::get<int>(var->function(particle->getDaughter(j)));
839 B2FATAL(
"Wrong number of arguments for meta function daughterProductOf");
845 if (arguments.size() == 1) {
847 auto func = [var](
const Particle * particle) ->
double {
849 if (particle->getNDaughters() == 0)
853 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
855 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
856 sum += std::get<double>(var->function(particle->getDaughter(j)));
858 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
860 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
861 sum += std::get<int>(var->function(particle->getDaughter(j)));
868 B2FATAL(
"Wrong number of arguments for meta function daughterSumOf");
874 if (arguments.size() == 1) {
876 auto func = [var](
const Particle * particle) ->
double {
878 if (particle->getNDaughters() == 0)
882 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
884 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
885 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
886 if (std::isnan(iValue))
continue;
887 if (std::isnan(min)) min = iValue;
888 if (iValue < min) min = iValue;
890 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
892 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
893 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
894 if (std::isnan(min)) min = iValue;
895 if (iValue < min) min = iValue;
902 B2FATAL(
"Wrong number of arguments for meta function daughterLowest");
908 if (arguments.size() == 1) {
910 auto func = [var](
const Particle * particle) ->
double {
912 if (particle->getNDaughters() == 0)
916 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
918 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
919 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
920 if (std::isnan(iValue))
continue;
921 if (std::isnan(max)) max = iValue;
922 if (iValue > max) max = iValue;
924 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
926 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
927 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
928 if (std::isnan(max)) max = iValue;
929 if (iValue > max) max = iValue;
936 B2FATAL(
"Wrong number of arguments for meta function daughterHighest");
942 if (arguments.size() == 3) {
943 auto func = [arguments](
const Particle * particle) ->
double {
944 if (particle ==
nullptr)
946 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
947 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
948 auto variablename = arguments[2];
949 if (dau_i ==
nullptr || dau_j ==
nullptr)
951 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
955 auto result_j = var->function(dau_j);
956 auto result_i = var->function(dau_i);
958 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
960 diff = std::get<double>(result_j) - std::get<double>(result_i);
961 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
963 diff = std::get<int>(result_j) - std::get<int>(result_i);
966 throw std::runtime_error(
"Bad variant access");
968 if (variablename ==
"phi" or variablename ==
"clusterPhi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)"))
969 or std::regex_match(variablename, std::regex(
"use.*Frame\\(clusterPhi\\)")))
971 if (fabs(diff) > M_PI) {
973 diff = diff - 2 * M_PI;
975 diff = 2 * M_PI + diff;
983 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOf");
989 if (arguments.size() == 3) {
990 auto func = [arguments](
const Particle * particle) ->
double {
991 if (particle ==
nullptr)
993 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
994 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
995 auto variablename = arguments[2];
996 if (dau_i ==
nullptr || dau_j ==
nullptr)
998 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1001 const MCParticle* iMcDaughter = dau_i->getMCParticle();
1002 const MCParticle* jMcDaughter = dau_j->getMCParticle();
1003 if (iMcDaughter ==
nullptr || jMcDaughter ==
nullptr)
1005 Particle iTmpPart(iMcDaughter);
1006 Particle jTmpPart(jMcDaughter);
1008 auto result_j = var->function(&jTmpPart);
1009 auto result_i = var->function(&iTmpPart);
1011 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1013 diff = std::get<double>(result_j) - std::get<double>(result_i);
1014 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1016 diff = std::get<int>(result_j) - std::get<int>(result_i);
1019 throw std::runtime_error(
"Bad variant access");
1021 if (variablename ==
"phi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)")))
1023 if (fabs(diff) > M_PI) {
1025 diff = diff - 2 * M_PI;
1027 diff = 2 * M_PI + diff;
1035 B2FATAL(
"Wrong number of arguments for meta function mcDaughterDiffOf");
1041 if (arguments.size() == 5) {
1047 }
catch (std::invalid_argument&) {
1048 B2FATAL(
"First four arguments of grandDaughterDiffOf meta function must be integers!");
1050 std::vector<std::string> new_arguments;
1051 new_arguments.push_back(std::string(arguments[0] +
":" + arguments[2]));
1052 new_arguments.push_back(std::string(arguments[1] +
":" + arguments[3]));
1053 new_arguments.push_back(arguments[4]);
1054 return daughterDiffOf(new_arguments);
1056 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOf");
1062 if (arguments.size() == 3) {
1063 auto func = [arguments](
const Particle * particle) ->
double {
1064 if (particle ==
nullptr)
1066 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1067 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1068 if (!(dau_i && dau_j))
1070 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1074 double iValue, jValue;
1075 if (std::holds_alternative<double>(var->function(dau_j)))
1077 iValue = std::get<double>(var->function(dau_i));
1078 jValue = std::get<double>(var->function(dau_j));
1079 }
else if (std::holds_alternative<int>(var->function(dau_j)))
1081 iValue = std::get<int>(var->function(dau_i));
1082 jValue = std::get<int>(var->function(dau_j));
1084 return (jValue - iValue) / (jValue + iValue);
1088 B2FATAL(
"Wrong number of arguments for meta function daughterNormDiffOf");
1094 if (arguments.size() == 2) {
1095 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1096 std::string variableName = arguments[1];
1097 auto func = [daughterFunction, variableName](
const Particle * particle) ->
double {
1098 if (particle ==
nullptr)
1100 int daughterNumber = std::get<int>(daughterFunction(particle));
1101 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1104 auto result_mother = var->function(particle);
1105 auto result_daughter = var->function(particle->getDaughter(daughterNumber));
1107 if (std::holds_alternative<double>(result_mother) && std::holds_alternative<double>(result_daughter))
1109 diff = std::get<double>(result_mother) - std::get<double>(result_daughter);
1110 }
else if (std::holds_alternative<int>(result_mother) && std::holds_alternative<int>(result_daughter))
1112 diff = std::get<int>(result_mother) - std::get<int>(result_daughter);
1115 throw std::runtime_error(
"Bad variant access");
1118 if (variableName ==
"phi" or variableName ==
"useCMSFrame(phi)")
1120 if (fabs(diff) > M_PI) {
1122 diff = diff - 2 * M_PI;
1124 diff = 2 * M_PI + diff;
1132 B2FATAL(
"Wrong number of arguments for meta function daughterMotherDiffOf");
1138 if (arguments.size() == 2) {
1139 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1141 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
1142 if (particle ==
nullptr)
1144 int daughterNumber = std::get<int>(daughterFunction(particle));
1145 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1147 double daughterValue = 0.0, motherValue = 0.0;
1148 if (std::holds_alternative<double>(var->function(particle)))
1150 daughterValue = std::get<double>(var->function(particle->getDaughter(daughterNumber)));
1151 motherValue = std::get<double>(var->function(particle));
1152 }
else if (std::holds_alternative<int>(var->function(particle)))
1154 daughterValue = std::get<int>(var->function(particle->getDaughter(daughterNumber)));
1155 motherValue = std::get<int>(var->function(particle));
1157 return (motherValue - daughterValue) / (motherValue + daughterValue);
1161 B2FATAL(
"Wrong number of arguments for meta function daughterMotherNormDiffOf");
1167 if (arguments.size() >= 1) {
1169 auto func = [arguments](
const Particle * particle) ->
double {
1170 if (particle ==
nullptr)
1175 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1176 for (
const auto& generalizedIndex : arguments)
1178 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1179 if (dauPart) pSum += frame.getMomentum(dauPart);
1181 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1187 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
1188 ROOT::Math::PxPyPzEVector pRecoil = frame.getMomentum(pIN - particle->get4Vector());
1190 return ROOT::Math::VectorUtil::Angle(pRecoil, pSum);
1194 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndRecoil");
1198 Manager::FunctionPtr angleBetweenDaughterAndMissingMomentum(
const std::vector<std::string>& arguments)
1200 if (arguments.size() >= 1) {
1201 auto func = [arguments](
const Particle * particle) ->
double {
1202 if (particle ==
nullptr)
1205 StoreObjPtr<EventKinematics> evtShape;
1208 B2WARNING(
"Cannot find missing momentum information, did you forget to run EventKinematicsModule?");
1211 ROOT::Math::XYZVector missingMomentumCMS = evtShape->getMissingMomentumCMS();
1212 ROOT::Math::PxPyPzEVector missingTotalMomentumCMS(missingMomentumCMS.X(),
1213 missingMomentumCMS.Y(),
1214 missingMomentumCMS.Z(),
1215 evtShape->getMissingEnergyCMS());
1217 ROOT::Math::PxPyPzEVector missingTotalMomentumLab = T.rotateCmsToLab() * missingTotalMomentumCMS;
1220 ROOT::Math::PxPyPzEVector pMiss = frame.getMomentum(missingTotalMomentumLab);
1222 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1223 for (
const auto& generalizedIndex : arguments)
1225 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1226 if (dauPart) pSum += frame.getMomentum(dauPart);
1228 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1233 return ROOT::Math::VectorUtil::Angle(pMiss, pSum);
1237 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndMissingMomentum");
1243 if (arguments.size() == 2 || arguments.size() == 3) {
1245 auto func = [arguments](
const Particle * particle) ->
double {
1246 if (particle ==
nullptr)
1249 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1253 for (
const auto& generalizedIndex : arguments)
1255 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1257 pDaus.push_back(frame.getMomentum(dauPart));
1259 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1265 if (pDaus.size() == 2)
1266 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1268 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1272 B2FATAL(
"Wrong number of arguments for meta function daughterAngle");
1276 double grandDaughterDecayAngle(
const Particle* particle,
const std::vector<double>& arguments)
1278 if (arguments.size() == 2) {
1283 int daughterIndex = std::lround(arguments[0]);
1284 if (daughterIndex >=
int(particle->getNDaughters()))
1286 const Particle* dau = particle->getDaughter(daughterIndex);
1288 int grandDaughterIndex = std::lround(arguments[1]);
1289 if (grandDaughterIndex >=
int(dau->getNDaughters()))
1292 ROOT::Math::XYZVector boost = dau->get4Vector().BoostToCM();
1294 ROOT::Math::PxPyPzEVector motherMomentum = - particle->get4Vector();
1295 motherMomentum = ROOT::Math::Boost(boost) * motherMomentum;
1297 ROOT::Math::PxPyPzEVector grandDaughterMomentum = dau->getDaughter(grandDaughterIndex)->get4Vector();
1298 grandDaughterMomentum = ROOT::Math::Boost(boost) * grandDaughterMomentum;
1300 return ROOT::Math::VectorUtil::Angle(motherMomentum, grandDaughterMomentum);
1303 B2FATAL(
"The variable grandDaughterDecayAngle needs exactly two integers as arguments!");
1309 if (arguments.size() == 2 || arguments.size() == 3) {
1311 auto func = [arguments](
const Particle * particle) ->
double {
1312 if (particle ==
nullptr)
1315 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1319 if (particle->getParticleSource() == Particle::EParticleSourceObject::c_MCParticle)
1321 for (
const auto& generalizedIndex : arguments) {
1322 const MCParticle* mcPart = particle->getMCParticle();
1323 if (mcPart ==
nullptr)
1325 const MCParticle* dauMcPart = mcPart->getParticleFromGeneralizedIndexString(generalizedIndex);
1326 if (dauMcPart ==
nullptr)
1329 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1333 for (
const auto& generalizedIndex : arguments) {
1334 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1335 if (dauPart ==
nullptr)
1338 const MCParticle* dauMcPart = dauPart->getMCParticle();
1339 if (dauMcPart ==
nullptr)
1342 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1347 if (pDaus.size() == 2)
1348 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1350 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1354 B2FATAL(
"Wrong number of arguments for meta function mcDaughterAngle");
1358 double daughterClusterAngleInBetween(
const Particle* particle,
const std::vector<double>& daughterIndices)
1360 if (daughterIndices.size() == 2) {
1361 int daughterIndexi = std::lround(daughterIndices[0]);
1362 int daughterIndexj = std::lround(daughterIndices[1]);
1363 if (std::max(daughterIndexi, daughterIndexj) >=
int(particle->getNDaughters())) {
1366 const ECLCluster* clusteri = particle->getDaughter(daughterIndexi)->getECLCluster();
1367 const ECLCluster* clusterj = particle->getDaughter(daughterIndexj)->getECLCluster();
1368 if (clusteri and clusterj) {
1372 ClusterUtils clusutils;
1373 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1374 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1375 return ROOT::Math::VectorUtil::Angle(pi, pj);
1379 }
else if (daughterIndices.size() == 3) {
1380 int daughterIndexi = std::lround(daughterIndices[0]);
1381 int daughterIndexj = std::lround(daughterIndices[1]);
1382 int daughterIndexk = std::lround(daughterIndices[2]);
1383 if (std::max(std::max(daughterIndexi, daughterIndexj), daughterIndexk) >=
int(particle->getNDaughters())) {
1386 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1387 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1388 const ECLCluster* clusterk = (particle->getDaughter(daughterIndices[2]))->getECLCluster();
1389 if (clusteri and clusterj and clusterk) {
1394 ClusterUtils clusutils;
1395 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1396 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1397 ROOT::Math::PxPyPzEVector pk = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterk, clusterkBit));
1398 return ROOT::Math::VectorUtil::Angle(pk, pi + pj);
1403 B2FATAL(
"Wrong number of arguments for daughterClusterAngleInBetween!");
1409 if (arguments.size() > 1) {
1410 auto func = [arguments](
const Particle * particle) ->
double {
1412 ROOT::Math::PxPyPzEVector pSum;
1414 for (
const auto& generalizedIndex : arguments)
1416 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1418 pSum += frame.getMomentum(dauPart);
1427 B2FATAL(
"Wrong number of arguments for meta function daughterInvM. At least two integers are needed.");
1433 if (arguments.size() == 2) {
1438 }
catch (std::invalid_argument&) {
1439 B2FATAL(
"Second argument of modulo meta function must be integer!");
1441 auto func = [var, divideBy](
const Particle * particle) ->
int {
1442 auto var_result = var->function(particle);
1443 if (std::holds_alternative<double>(var_result))
1445 return int(std::get<double>(var_result)) % divideBy;
1446 }
else if (std::holds_alternative<int>(var_result))
1448 return std::get<int>(var_result) % divideBy;
1449 }
else if (std::holds_alternative<bool>(var_result))
1451 return int(std::get<bool>(var_result)) % divideBy;
1456 B2FATAL(
"Wrong number of arguments for meta function modulo");
1462 if (arguments.size() == 1) {
1465 auto func = [var](
const Particle * particle) ->
bool {
return std::isnan(std::get<double>(var->function(particle))); };
1468 B2FATAL(
"Wrong number of arguments for meta function isNAN");
1474 if (arguments.size() == 2) {
1476 double defaultOutput;
1479 }
catch (std::invalid_argument&) {
1480 B2FATAL(
"The second argument of ifNANgiveX meta function must be a number!");
1482 auto func = [var, defaultOutput](
const Particle * particle) ->
double {
1483 double output = std::get<double>(var->function(particle));
1484 if (std::isnan(output))
return defaultOutput;
1489 B2FATAL(
"Wrong number of arguments for meta function ifNANgiveX");
1495 if (arguments.size() == 1) {
1498 auto func = [var](
const Particle * particle) ->
bool {
return std::isinf(std::get<double>(var->function(particle))); };
1501 B2FATAL(
"Wrong number of arguments for meta function isInfinity");
1507 if (arguments.size() >= 2) {
1513 for (
size_t i = 1; i < arguments.size(); ++i) {
1516 }
catch (std::invalid_argument&) {
1517 B2FATAL(
"The input flags to meta function unmask() should be integer!");
1523 auto func = [var, finalMask](
const Particle * particle) ->
double {
1525 auto var_result = var->function(particle);
1526 if (std::holds_alternative<double>(var_result))
1529 if (std::isnan(std::get<double>(var_result))) {
1532 value = int(std::get<double>(var_result));
1533 }
else if (std::holds_alternative<int>(var_result))
1535 value = std::get<int>(var_result);
1539 value &= (~finalMask);
1546 B2FATAL(
"Meta function unmask needs at least two arguments!");
1552 if (arguments.size() == 3) {
1554 std::string cutString = arguments[0];
1560 auto func = [cut, variableIfTrue, variableIfFalse](
const Particle * particle) ->
double {
1561 if (particle ==
nullptr)
1563 if (cut->check(particle))
1565 auto var_result = variableIfTrue->function(particle);
1566 if (std::holds_alternative<double>(var_result)) {
1567 return std::get<double>(var_result);
1568 }
else if (std::holds_alternative<int>(var_result)) {
1569 return std::get<int>(var_result);
1570 }
else if (std::holds_alternative<bool>(var_result)) {
1571 return std::get<bool>(var_result);
1575 auto var_result = variableIfFalse->function(particle);
1576 if (std::holds_alternative<double>(var_result)) {
1577 return std::get<double>(var_result);
1578 }
else if (std::holds_alternative<int>(var_result)) {
1579 return std::get<int>(var_result);
1580 }
else if (std::holds_alternative<bool>(var_result)) {
1581 return std::get<bool>(var_result);
1588 B2FATAL(
"Wrong number of arguments for meta function conditionalVariableSelector");
1594 if (arguments.size() > 0) {
1595 std::vector<const Variable::Manager::Var*> variables;
1596 for (
const auto& argument : arguments)
1599 auto func = [variables, arguments](
const Particle * particle) ->
double {
1600 double pValueProduct = 1.;
1601 for (
auto variable : variables)
1603 double pValue = std::get<double>(variable->function(particle));
1607 pValueProduct *= pValue;
1609 double pValueSum = 1.;
1610 double factorial = 1.;
1611 for (
unsigned int i = 1; i < arguments.size(); ++i)
1614 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1616 return pValueProduct * pValueSum;
1620 B2FATAL(
"Wrong number of arguments for meta function pValueCombination");
1626 if (arguments.size() == 1) {
1628 auto func = [var](
const Particle * particle) ->
double {
1629 double pValueProduct = 1.;
1630 if (particle->getNDaughters() == 0)
1635 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
1637 double pValue = std::get<double>(var->function(particle->getDaughter(j)));
1638 if (pValue < 0)
return -1;
1639 else pValueProduct *= pValue;
1642 double pValueSum = 1.;
1643 double factorial = 1.;
1644 for (
unsigned int i = 1; i < particle->getNDaughters(); ++i)
1647 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1649 return pValueProduct * pValueSum;
1653 B2FATAL(
"Wrong number of arguments for meta function pValueCombinationOfDaughters");
1659 if (arguments.size() == 1) {
1661 auto func = [var](
const Particle * particle) ->
double {
1662 auto var_result = var->function(particle);
1663 if (std::holds_alternative<double>(var_result))
1665 return std::abs(std::get<double>(var_result));
1666 }
else if (std::holds_alternative<int>(var_result))
1668 return std::abs(std::get<int>(var_result));
1673 B2FATAL(
"Wrong number of arguments for meta function abs");
1679 if (arguments.size() == 2) {
1684 B2FATAL(
"One or both of the used variables doesn't exist!");
1686 auto func = [var1, var2](
const Particle * particle) ->
double {
1687 double val1 = 0.0, val2 = 0.0;
1688 auto var_result1 = var1->function(particle);
1689 auto var_result2 = var2->function(particle);
1690 if (std::holds_alternative<double>(var_result1))
1692 val1 = std::get<double>(var_result1);
1693 }
else if (std::holds_alternative<int>(var_result1))
1695 val1 = std::get<int>(var_result1);
1696 }
else if (std::holds_alternative<bool>(var_result1))
1698 val1 = std::get<bool>(var_result1);
1701 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1703 if (std::holds_alternative<double>(var_result2))
1705 val2 = std::get<double>(var_result2);
1706 }
else if (std::holds_alternative<int>(var_result2))
1708 val2 = std::get<int>(var_result2);
1709 }
else if (std::holds_alternative<bool>(var_result2))
1711 val2 = std::get<bool>(var_result2);
1714 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1716 return std::max(val1, val2);
1720 B2FATAL(
"Wrong number of arguments for meta function max");
1726 if (arguments.size() == 2) {
1731 B2FATAL(
"One or both of the used variables doesn't exist!");
1733 auto func = [var1, var2](
const Particle * particle) ->
double {
1734 double val1 = 0.0, val2 = 0.0;
1735 auto var_result1 = var1->function(particle);
1736 auto var_result2 = var2->function(particle);
1737 if (std::holds_alternative<double>(var_result1))
1739 val1 = std::get<double>(var_result1);
1740 }
else if (std::holds_alternative<int>(var_result1))
1742 val1 = std::get<int>(var_result1);
1743 }
else if (std::holds_alternative<bool>(var_result1))
1745 val1 = std::get<bool>(var_result1);
1748 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1750 if (std::holds_alternative<double>(var_result2))
1752 val2 = std::get<double>(var_result2);
1753 }
else if (std::holds_alternative<int>(var_result2))
1755 val2 = std::get<int>(var_result2);
1756 }
else if (std::holds_alternative<bool>(var_result2))
1758 val2 = std::get<bool>(var_result2);
1761 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1763 return std::min(val1, val2);
1767 B2FATAL(
"Wrong number of arguments for meta function min");
1773 if (arguments.size() == 1) {
1775 auto func = [var](
const Particle * particle) ->
double {
1776 auto var_result = var->function(particle);
1777 if (std::holds_alternative<double>(var_result))
1778 return std::sin(std::get<double>(var_result));
1779 else if (std::holds_alternative<int>(var_result))
1780 return std::sin(std::get<int>(var_result));
1785 B2FATAL(
"Wrong number of arguments for meta function sin");
1791 if (arguments.size() == 1) {
1793 auto func = [var](
const Particle * particle) ->
double {
1794 auto var_result = var->function(particle);
1795 if (std::holds_alternative<double>(var_result))
1796 return std::asin(std::get<double>(var_result));
1797 else if (std::holds_alternative<int>(var_result))
1798 return std::asin(std::get<int>(var_result));
1803 B2FATAL(
"Wrong number of arguments for meta function asin");
1809 if (arguments.size() == 1) {
1811 auto func = [var](
const Particle * particle) ->
double {
1812 auto var_result = var->function(particle);
1813 if (std::holds_alternative<double>(var_result))
1814 return std::cos(std::get<double>(var_result));
1815 else if (std::holds_alternative<int>(var_result))
1816 return std::cos(std::get<int>(var_result));
1821 B2FATAL(
"Wrong number of arguments for meta function cos");
1827 if (arguments.size() == 1) {
1829 auto func = [var](
const Particle * particle) ->
double {
1830 auto var_result = var->function(particle);
1831 if (std::holds_alternative<double>(var_result))
1832 return std::acos(std::get<double>(var_result));
1833 else if (std::holds_alternative<int>(var_result))
1834 return std::acos(std::get<int>(var_result));
1839 B2FATAL(
"Wrong number of arguments for meta function acos");
1845 if (arguments.size() == 1) {
1847 auto func = [var](
const Particle * particle) ->
double {
return std::tan(std::get<double>(var->function(particle))); };
1850 B2FATAL(
"Wrong number of arguments for meta function tan");
1856 if (arguments.size() == 1) {
1858 auto func = [var](
const Particle * particle) ->
double {
return std::atan(std::get<double>(var->function(particle))); };
1861 B2FATAL(
"Wrong number of arguments for meta function atan");
1867 if (arguments.size() == 2) {
1870 auto func = [varY, varX](
const Particle * particle) ->
double {
1871 double y = std::get<double>(varY->function(particle));
1872 double x = std::get<double>(varX->function(particle));
1873 return std::atan2(y, x);
1877 B2FATAL(
"Wrong number of arguments for meta function atan2");
1883 if (arguments.size() == 1) {
1885 auto func = [var](
const Particle * particle) ->
double {
1886 auto var_result = var->function(particle);
1887 if (std::holds_alternative<double>(var_result))
1888 return std::exp(std::get<double>(var_result));
1889 else if (std::holds_alternative<int>(var_result))
1890 return std::exp(std::get<int>(var_result));
1895 B2FATAL(
"Wrong number of arguments for meta function exp");
1901 if (arguments.size() == 1) {
1903 auto func = [var](
const Particle * particle) ->
double {
1904 auto var_result = var->function(particle);
1905 if (std::holds_alternative<double>(var_result))
1906 return std::log(std::get<double>(var_result));
1907 else if (std::holds_alternative<int>(var_result))
1908 return std::log(std::get<int>(var_result));
1913 B2FATAL(
"Wrong number of arguments for meta function log");
1919 if (arguments.size() == 1) {
1921 auto func = [var](
const Particle * particle) ->
double {
1922 auto var_result = var->function(particle);
1923 if (std::holds_alternative<double>(var_result))
1924 return std::log10(std::get<double>(var_result));
1925 else if (std::holds_alternative<int>(var_result))
1926 return std::log10(std::get<int>(var_result));
1931 B2FATAL(
"Wrong number of arguments for meta function log10");
1937 if (arguments.size() == 1) {
1939 auto func = [var](
const Particle * particle) ->
double {
1940 if (particle ==
nullptr)
1943 StoreArray<Particle> particles;
1944 if (!particle->hasExtraInfo(
"original_index"))
1947 auto originalParticle = particles[particle->getExtraInfo(
"original_index")];
1948 if (!originalParticle)
1950 auto var_result = var->function(originalParticle);
1951 if (std::holds_alternative<double>(var_result))
1953 return std::get<double>(var_result);
1954 }
else if (std::holds_alternative<int>(var_result))
1956 return std::get<int>(var_result);
1957 }
else if (std::holds_alternative<bool>(var_result))
1959 return std::get<bool>(var_result);
1964 B2FATAL(
"Wrong number of arguments for meta function originalParticle");
1970 if (arguments.size() == 2) {
1971 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1973 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
1974 if (particle ==
nullptr)
1976 int daughterNumber = std::get<int>(daughterFunction(particle));
1977 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1979 auto var_result = var->function(particle->getDaughter(daughterNumber));
1980 if (std::holds_alternative<double>(var_result))
1982 return std::get<double>(var_result);
1983 }
else if (std::holds_alternative<int>(var_result))
1985 return std::get<int>(var_result);
1986 }
else if (std::holds_alternative<bool>(var_result))
1988 return std::get<bool>(var_result);
1993 B2FATAL(
"Wrong number of arguments for meta function daughter");
1999 if (arguments.size() == 2) {
2000 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2002 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2003 if (particle ==
nullptr)
2005 int daughterNumber = std::get<int>(daughterFunction(particle));
2006 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2010 StoreArray<Particle> particles;
2011 if (!particle->getDaughter(daughterNumber)->hasExtraInfo(
"original_index"))
2013 auto originalDaughter = particles[particle->getDaughter(daughterNumber)->getExtraInfo(
"original_index")];
2014 if (!originalDaughter)
2017 auto var_result = var->function(originalDaughter);
2018 if (std::holds_alternative<double>(var_result)) {
2019 return std::get<double>(var_result);
2020 }
else if (std::holds_alternative<int>(var_result)) {
2021 return std::get<int>(var_result);
2022 }
else if (std::holds_alternative<bool>(var_result)) {
2023 return std::get<bool>(var_result);
2029 B2FATAL(
"Wrong number of arguments for meta function daughter");
2035 if (arguments.size() == 1) {
2036 std::string daughterString = arguments[0];
2037 auto func = [daughterString](
const Particle * particle) ->
int {
2038 if (particle ==
nullptr)
2040 int daughterNumber = 0;
2044 }
catch (std::invalid_argument&)
2046 auto daughterFunction = convertToInt({daughterString,
"-1"});
2047 auto daughterVarResult = daughterFunction(particle);
2048 daughterNumber = std::get<int>(daughterVarResult);
2050 return daughterNumber;
2054 B2FATAL(
"Wrong number of arguments for meta function convertToDaughterIndex");
2060 if (arguments.size() == 2) {
2061 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2063 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2064 if (particle ==
nullptr)
2066 if (particle->getMCParticle())
2068 int daughterNumber = std::get<int>(daughterFunction(particle));
2069 if (daughterNumber >=
int(particle->getMCParticle()->getNDaughters()) or daughterNumber < 0)
2071 Particle tempParticle = Particle(particle->getMCParticle()->getDaughters().at(daughterNumber));
2072 auto var_result = var->function(&tempParticle);
2073 if (std::holds_alternative<double>(var_result)) {
2074 return std::get<double>(var_result);
2075 }
else if (std::holds_alternative<int>(var_result)) {
2076 return std::get<int>(var_result);
2077 }
else if (std::holds_alternative<bool>(var_result)) {
2078 return std::get<bool>(var_result);
2089 B2FATAL(
"Wrong number of arguments for meta function mcDaughter");
2095 if (arguments.size() == 1) {
2097 auto func = [var](
const Particle * particle) ->
double {
2098 if (particle ==
nullptr)
2100 if (particle->getMCParticle())
2102 if (particle->getMCParticle()->getMother() ==
nullptr) {
2105 Particle tempParticle = Particle(particle->getMCParticle()->getMother());
2106 auto var_result = var->function(&tempParticle);
2107 if (std::holds_alternative<double>(var_result)) {
2108 return std::get<double>(var_result);
2109 }
else if (std::holds_alternative<int>(var_result)) {
2110 return std::get<int>(var_result);
2111 }
else if (std::holds_alternative<bool>(var_result)) {
2112 return std::get<bool>(var_result);
2121 B2FATAL(
"Wrong number of arguments for meta function mcMother");
2127 if (arguments.size() == 2) {
2128 std::string indexString = arguments[0];
2131 auto func = [var, indexString](
const Particle * particle) ->
double {
2133 int particleNumber = 0;
2137 }
catch (std::invalid_argument&)
2139 auto indexFunction = convertToInt({indexString,
"-1"});
2140 auto indexVarResult = indexFunction(particle);
2141 particleNumber = std::get<int>(indexVarResult);
2144 StoreArray<MCParticle> mcParticles(
"MCParticles");
2145 if (particleNumber < 0 or particleNumber >= mcParticles.getEntries())
2150 const MCParticle* mcParticle = mcParticles[particleNumber];
2151 Particle part = Particle(mcParticle);
2152 auto var_result = var->function(&part);
2153 if (std::holds_alternative<double>(var_result))
2155 return std::get<double>(var_result);
2156 }
else if (std::holds_alternative<int>(var_result))
2158 return std::get<int>(var_result);
2159 }
else if (std::holds_alternative<bool>(var_result))
2161 return std::get<bool>(var_result);
2166 B2FATAL(
"Wrong number of arguments for meta function genParticle");
2172 if (arguments.size() == 1) {
2175 auto func = [var](
const Particle*) ->
double {
2176 StoreArray<MCParticle> mcParticles(
"MCParticles");
2177 if (mcParticles.getEntries() == 0)
2182 const MCParticle* mcUpsilon4S = mcParticles[0];
2183 if (mcUpsilon4S->isInitial()) mcUpsilon4S = mcParticles[2];
2184 if (mcUpsilon4S->getPDG() != 300553)
2189 Particle upsilon4S = Particle(mcUpsilon4S);
2190 auto var_result = var->function(&upsilon4S);
2191 if (std::holds_alternative<double>(var_result))
2193 return std::get<double>(var_result);
2194 }
else if (std::holds_alternative<int>(var_result))
2196 return std::get<int>(var_result);
2197 }
else if (std::holds_alternative<bool>(var_result))
2199 return std::get<bool>(var_result);
2204 B2FATAL(
"Wrong number of arguments for meta function genUpsilon4S");
2210 if (arguments.size() == 4) {
2211 std::string listName = arguments[0];
2212 std::string rankedVariableName = arguments[1];
2213 std::string returnVariableName = arguments[2];
2214 std::string extraInfoName = rankedVariableName +
"_rank";
2218 }
catch (std::invalid_argument&) {
2219 B2ERROR(
"3rd argument of getVariableByRank meta function (Rank) must be an integer!");
2224 auto func = [var, rank, extraInfoName, listName](
const Particle*)->
double {
2225 StoreObjPtr<ParticleList> list(listName);
2227 const unsigned int numParticles = list->getListSize();
2228 for (
unsigned int i = 0; i < numParticles; i++)
2230 const Particle* p = list->getParticle(i);
2231 if (p->getExtraInfo(extraInfoName) == rank) {
2232 auto var_result = var->function(p);
2233 if (std::holds_alternative<double>(var_result)) {
2234 return std::get<double>(var_result);
2235 }
else if (std::holds_alternative<int>(var_result)) {
2236 return std::get<int>(var_result);
2237 }
else if (std::holds_alternative<bool>(var_result)) {
2238 return std::get<bool>(var_result);
2243 return std::numeric_limits<double>::signaling_NaN();
2247 B2FATAL(
"Wrong number of arguments for meta function getVariableByRank");
2253 if (arguments.size() == 1 or arguments.size() == 2) {
2255 std::string listName = arguments[0];
2256 std::string cutString =
"";
2258 if (arguments.size() == 2) {
2259 cutString = arguments[1];
2264 auto func = [listName, cut](
const Particle*) ->
int {
2266 StoreObjPtr<ParticleList> list(listName);
2268 for (
unsigned int i = 0; i < list->getListSize(); i++)
2270 const Particle* particle = list->getParticle(i);
2271 if (cut->check(particle)) {
2279 B2FATAL(
"Wrong number of arguments for meta function countInList");
2285 if (arguments.size() == 2 or arguments.size() == 3) {
2287 std::string roeListName = arguments[0];
2288 std::string cutString = arguments[1];
2290 if (arguments.size() == 2) {
2291 B2INFO(
"Use pdgCode of electron as default in meta variable veto, other arguments: " << roeListName <<
", " << cutString);
2295 }
catch (std::invalid_argument&) {
2296 B2FATAL(
"Third argument of veto meta function must be integer!");
2303 auto func = [roeListName, cut, pdgCode, flavourType](
const Particle * particle) ->
bool {
2304 StoreObjPtr<ParticleList> roeList(roeListName);
2305 ROOT::Math::PxPyPzEVector vec = particle->get4Vector();
2306 for (
unsigned int i = 0; i < roeList->getListSize(); i++)
2308 const Particle* roeParticle = roeList->getParticle(i);
2309 if (not particle->overlapsWith(roeParticle)) {
2310 ROOT::Math::PxPyPzEVector tempCombination = roeParticle->get4Vector() + vec;
2311 std::vector<int> indices = { particle->getArrayIndex(), roeParticle->getArrayIndex() };
2312 Particle tempParticle = Particle(tempCombination, pdgCode, flavourType, indices, particle->getArrayPointer());
2313 if (cut->check(&tempParticle)) {
2322 B2FATAL(
"Wrong number of arguments for meta function veto");
2328 if (arguments.size() == 1) {
2329 std::string cutString = arguments[0];
2331 auto func = [cut](
const Particle * particle) ->
int {
2333 for (
auto& daughter : particle->getDaughters())
2335 if (cut->check(daughter))
2342 B2FATAL(
"Wrong number of arguments for meta function countDaughters");
2348 if (arguments.size() == 1) {
2349 std::string cutString = arguments[0];
2351 auto func = [cut](
const Particle * particle) ->
int {
2353 std::vector<const Particle*> fspDaughters;
2354 particle->fillFSPDaughters(fspDaughters);
2357 for (
auto& daughter : fspDaughters)
2359 if (cut->check(daughter))
2366 B2FATAL(
"Wrong number of arguments for meta function countFSPDaughters");
2372 if (arguments.size() == 1) {
2373 std::string cutString = arguments[0];
2375 auto func = [cut](
const Particle * particle) ->
int {
2377 std::vector<const Particle*> allDaughters;
2378 particle->fillAllDaughters(allDaughters);
2381 for (
auto& daughter : allDaughters)
2383 if (cut->check(daughter))
2390 B2FATAL(
"Wrong number of arguments for meta function countDescendants");
2394 Manager::FunctionPtr numberOfNonOverlappingParticles(
const std::vector<std::string>& arguments)
2397 auto func = [arguments](
const Particle * particle) ->
int {
2399 int _numberOfNonOverlappingParticles = 0;
2400 for (
const auto& listName : arguments)
2402 StoreObjPtr<ParticleList> list(listName);
2403 if (not list.isValid()) {
2404 B2FATAL(
"Invalid list named " << listName <<
" encountered in numberOfNonOverlappingParticles.");
2406 for (
unsigned int i = 0; i < list->getListSize(); i++) {
2407 const Particle* p = list->getParticle(i);
2408 if (not particle->overlapsWith(p)) {
2409 _numberOfNonOverlappingParticles++;
2413 return _numberOfNonOverlappingParticles;
2420 void appendDaughtersRecursive(Particle* mother, StoreArray<Particle>& container)
2423 auto* mcmother = mother->getRelated<MCParticle>();
2428 for (
auto* mcdaughter : mcmother->getDaughters()) {
2430 Particle tmp_daughter(mcdaughter);
2431 Particle* new_daughter = container.appendNew(tmp_daughter);
2432 new_daughter->addRelationTo(mcdaughter);
2433 mother->appendDaughter(new_daughter,
false);
2435 if (mcdaughter->getNDaughters() > 0)
2436 appendDaughtersRecursive(new_daughter, container);
2442 if (arguments.size() == 1) {
2444 auto func = [var](
const Particle * particle) ->
double {
2445 const MCParticle* mcp = particle->getMCParticle();
2450 StoreArray<Particle> tempParticles(
"tempParticles");
2451 tempParticles.clear();
2452 Particle tmpPart(mcp);
2453 Particle* newPart = tempParticles.appendNew(tmpPart);
2454 newPart->addRelationTo(mcp);
2456 appendDaughtersRecursive(newPart, tempParticles);
2458 auto var_result = var->function(newPart);
2459 if (std::holds_alternative<double>(var_result))
2461 return std::get<double>(var_result);
2462 }
else if (std::holds_alternative<int>(var_result))
2464 return std::get<int>(var_result);
2465 }
else if (std::holds_alternative<bool>(var_result))
2467 return std::get<bool>(var_result);
2472 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
2478 if (arguments.size() == 1) {
2481 auto func = [var](
const Particle * particle) ->
double {
2483 const ECLCluster* cluster = particle->getECLCluster();
2486 auto mcps = cluster->getRelationsTo<MCParticle>();
2489 std::vector<std::pair<double, int>> weightsAndIndices;
2490 for (
unsigned int i = 0; i < mcps.size(); ++i)
2491 weightsAndIndices.emplace_back(mcps.weight(i), i);
2494 std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
2495 ValueIndexPairSorting::higherPair<
decltype(weightsAndIndices)::value_type>);
2497 const MCParticle* mcp = mcps.object(weightsAndIndices[0].second);
2499 StoreArray<Particle> tempParticles(
"tempParticles");
2500 tempParticles.clear();
2501 Particle tmpPart(mcp);
2502 Particle* newPart = tempParticles.appendNew(tmpPart);
2503 newPart->addRelationTo(mcp);
2505 appendDaughtersRecursive(newPart, tempParticles);
2507 auto var_result = var->function(newPart);
2508 if (std::holds_alternative<double>(var_result))
2510 return std::get<double>(var_result);
2511 }
else if (std::holds_alternative<int>(var_result))
2513 return std::get<int>(var_result);
2514 }
else if (std::holds_alternative<bool>(var_result))
2516 return std::get<bool>(var_result);
2525 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCParticle");
2531 if (arguments.size() == 1) {
2534 auto func = [var](
const Particle * particle) ->
double {
2536 const ECLCluster* cluster = particle->getECLCluster();
2539 auto mcps = cluster->getRelationsTo<MCParticle>();
2542 std::map<int, double> mapMCParticleIndxAndWeight;
2543 getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
2546 if (mapMCParticleIndxAndWeight.size() == 0)
2550 auto maxMap = std::max_element(mapMCParticleIndxAndWeight.begin(), mapMCParticleIndxAndWeight.end(),
2551 [](
const auto & x,
const auto & y) { return x.second < y.second; }
2554 StoreArray<MCParticle> mcparticles;
2555 const MCParticle* mcKlong = mcparticles[maxMap->first];
2557 Particle tmpPart(mcKlong);
2558 auto var_result = var->function(&tmpPart);
2559 if (std::holds_alternative<double>(var_result))
2561 return std::get<double>(var_result);
2562 }
else if (std::holds_alternative<int>(var_result))
2564 return std::get<int>(var_result);
2565 }
else if (std::holds_alternative<bool>(var_result))
2567 return std::get<bool>(var_result);
2576 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCKlong");
2580 double matchedMCHasPDG(
const Particle* particle,
const std::vector<double>& pdgCode)
2582 if (pdgCode.size() != 1) {
2583 B2FATAL(
"Too many arguments provided to matchedMCHasPDG!");
2585 int inputPDG = std::lround(pdgCode[0]);
2587 const MCParticle* mcp = particle->getMCParticle();
2591 return std::abs(mcp->getPDG()) == inputPDG;
2596 if (arguments.size() == 1) {
2597 std::string listName = arguments[0];
2598 auto func = [listName](
const Particle * particle) ->
double {
2601 StoreObjPtr<ParticleList> listOfParticles(listName);
2603 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2604 double totalEnergy = 0;
2605 int nParticles = listOfParticles->getListSize();
2606 for (
int i = 0; i < nParticles; i++)
2608 const Particle* part = listOfParticles->getParticle(i);
2610 totalEnergy += frame.getMomentum(part).E();
2617 B2FATAL(
"Wrong number of arguments for meta function totalEnergyOfParticlesInList");
2623 if (arguments.size() == 1) {
2624 std::string listName = arguments[0];
2625 auto func = [listName](
const Particle*) ->
double {
2626 StoreObjPtr<ParticleList> listOfParticles(listName);
2628 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPxOfParticlesInList");
2630 int nParticles = listOfParticles->getListSize();
2632 for (
int i = 0; i < nParticles; i++)
2634 const Particle* part = listOfParticles->getParticle(i);
2635 totalPx += frame.getMomentum(part).Px();
2641 B2FATAL(
"Wrong number of arguments for meta function totalPxOfParticlesInList");
2647 if (arguments.size() == 1) {
2648 std::string listName = arguments[0];
2649 auto func = [listName](
const Particle*) ->
double {
2650 StoreObjPtr<ParticleList> listOfParticles(listName);
2652 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPyOfParticlesInList");
2654 int nParticles = listOfParticles->getListSize();
2656 for (
int i = 0; i < nParticles; i++)
2658 const Particle* part = listOfParticles->getParticle(i);
2659 totalPy += frame.getMomentum(part).Py();
2665 B2FATAL(
"Wrong number of arguments for meta function totalPyOfParticlesInList");
2671 if (arguments.size() == 1) {
2672 std::string listName = arguments[0];
2673 auto func = [listName](
const Particle*) ->
double {
2674 StoreObjPtr<ParticleList> listOfParticles(listName);
2676 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPzOfParticlesInList");
2678 int nParticles = listOfParticles->getListSize();
2680 for (
int i = 0; i < nParticles; i++)
2682 const Particle* part = listOfParticles->getParticle(i);
2683 totalPz += frame.getMomentum(part).Pz();
2689 B2FATAL(
"Wrong number of arguments for meta function totalPzOfParticlesInList");
2695 if (arguments.size() > 0) {
2697 auto func = [arguments](
const Particle * particle) ->
double {
2699 ROOT::Math::PxPyPzEVector total4Vector;
2701 std::vector<Particle*> particlePool;
2704 for (
const auto& argument : arguments)
2706 StoreObjPtr <ParticleList> listOfParticles(argument);
2708 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << argument <<
" given to invMassInLists");
2709 int nParticles = listOfParticles->getListSize();
2710 for (
int i = 0; i < nParticles; i++) {
2711 bool overlaps =
false;
2712 Particle* part = listOfParticles->getParticle(i);
2713 for (
const auto* poolPart : particlePool) {
2714 if (part->overlapsWith(poolPart)) {
2720 total4Vector += part->get4Vector();
2721 particlePool.push_back(part);
2725 double invariantMass = total4Vector.M();
2726 return invariantMass;
2731 B2FATAL(
"Wrong number of arguments for meta function invMassInLists");
2735 Manager::FunctionPtr totalECLEnergyOfParticlesInList(
const std::vector<std::string>& arguments)
2737 if (arguments.size() == 1) {
2738 std::string listName = arguments[0];
2739 auto func = [listName](
const Particle * particle) ->
double {
2742 StoreObjPtr<ParticleList> listOfParticles(listName);
2744 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2745 double totalEnergy = 0;
2746 int nParticles = listOfParticles->getListSize();
2747 for (
int i = 0; i < nParticles; i++)
2749 const Particle* part = listOfParticles->getParticle(i);
2750 const ECLCluster* cluster = part->getECLCluster();
2752 if (cluster !=
nullptr) {
2753 totalEnergy += cluster->getEnergy(clusterHypothesis);
2761 B2FATAL(
"Wrong number of arguments for meta function totalECLEnergyOfParticlesInList");
2767 if (arguments.size() == 1) {
2768 std::string listName = arguments[0];
2769 auto func = [listName](
const Particle*) ->
double {
2770 StoreObjPtr<ParticleList> listOfParticles(listName);
2772 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxPtInList");
2773 int nParticles = listOfParticles->getListSize();
2776 for (
int i = 0; i < nParticles; i++)
2778 const Particle* part = listOfParticles->getParticle(i);
2779 const double Pt = frame.getMomentum(part).Pt();
2780 if (Pt > maxPt) maxPt = Pt;
2786 B2FATAL(
"Wrong number of arguments for meta function maxPtInList");
2790 Manager::FunctionPtr eclClusterTrackMatchedWithCondition(
const std::vector<std::string>& arguments)
2792 if (arguments.size() <= 1) {
2794 std::string cutString;
2795 if (arguments.size() == 1)
2796 cutString = arguments[0];
2798 auto func = [cut](
const Particle * particle) ->
double {
2800 if (particle ==
nullptr)
2803 const ECLCluster* cluster = particle->getECLCluster();
2807 auto tracks = cluster->getRelationsFrom<Track>();
2809 for (
const auto& track : tracks) {
2812 if (cut->check(&trackParticle))
2821 B2FATAL(
"Wrong number of arguments for meta function eclClusterSpecialTrackMatched");
2827 if (arguments.size() == 2) {
2828 std::string listName = arguments[0];
2831 auto func = [listName, var](
const Particle*) ->
double {
2832 StoreObjPtr<ParticleList> listOfParticles(listName);
2834 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to averageValueInList");
2835 int nParticles = listOfParticles->getListSize();
2836 if (nParticles == 0)
2841 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2843 for (
int i = 0; i < nParticles; i++) {
2844 average += std::get<double>(var->function(listOfParticles->getParticle(i))) / nParticles;
2846 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2848 for (
int i = 0; i < nParticles; i++) {
2849 average += std::get<int>(var->function(listOfParticles->getParticle(i))) / nParticles;
2856 B2FATAL(
"Wrong number of arguments for meta function averageValueInList");
2862 if (arguments.size() == 2) {
2863 std::string listName = arguments[0];
2866 auto func = [listName, var](
const Particle*) ->
double {
2867 StoreObjPtr<ParticleList> listOfParticles(listName);
2869 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to medianValueInList");
2870 int nParticles = listOfParticles->getListSize();
2871 if (nParticles == 0)
2875 std::vector<double> valuesInList;
2876 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2878 for (
int i = 0; i < nParticles; i++) {
2879 valuesInList.push_back(std::get<double>(var->function(listOfParticles->getParticle(i))));
2881 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2883 for (
int i = 0; i < nParticles; i++) {
2884 valuesInList.push_back(std::get<int>(var->function(listOfParticles->getParticle(i))));
2887 std::sort(valuesInList.begin(), valuesInList.end());
2888 if (nParticles % 2 != 0)
2890 return valuesInList[nParticles / 2];
2893 return 0.5 * (valuesInList[nParticles / 2] + valuesInList[nParticles / 2 - 1]);
2898 B2FATAL(
"Wrong number of arguments for meta function medianValueInList");
2904 if (arguments.size() == 2) {
2905 std::string listName = arguments[0];
2908 auto func = [listName, var](
const Particle*) ->
double {
2909 StoreObjPtr<ParticleList> listOfParticles(listName);
2911 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to sumValueInList");
2912 int nParticles = listOfParticles->getListSize();
2913 if (nParticles == 0)
2918 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2920 for (
int i = 0; i < nParticles; i++) {
2921 sum += std::get<double>(var->function(listOfParticles->getParticle(i)));
2923 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2925 for (
int i = 0; i < nParticles; i++) {
2926 sum += std::get<int>(var->function(listOfParticles->getParticle(i)));
2933 B2FATAL(
"Wrong number of arguments for meta function sumValueInList");
2939 if (arguments.size() == 2) {
2940 std::string listName = arguments[0];
2943 auto func = [listName, var](
const Particle*) ->
double {
2944 StoreObjPtr<ParticleList> listOfParticles(listName);
2946 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to productValueInList");
2947 int nParticles = listOfParticles->getListSize();
2948 if (nParticles == 0)
2953 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2955 for (
int i = 0; i < nParticles; i++) {
2956 product *= std::get<double>(var->function(listOfParticles->getParticle(i)));
2958 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2960 for (
int i = 0; i < nParticles; i++) {
2961 product *= std::get<int>(var->function(listOfParticles->getParticle(i)));
2968 B2FATAL(
"Wrong number of arguments for meta function productValueInList");
2975 if (arguments.size() != 1)
2976 B2FATAL(
"Wrong number of arguments for meta function angleToClosestInList");
2978 std::string listname = arguments[0];
2980 auto func = [listname](
const Particle * particle) ->
double {
2982 StoreObjPtr<ParticleList> list(listname);
2983 if (not list.isValid())
2984 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToClosestInList");
2987 if (list->getListSize() == 0)
2992 const auto p_this = frame.getMomentum(particle);
2995 double minAngle = 2 * M_PI;
2996 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2998 const Particle* compareme = list->getParticle(i);
2999 const auto p_compare = frame.getMomentum(compareme);
3000 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3001 if (minAngle > angle) minAngle = angle;
3011 if (arguments.size() != 2)
3012 B2FATAL(
"Wrong number of arguments for meta function closestInList");
3014 std::string listname = arguments[0];
3019 auto func = [listname, var](
const Particle * particle) ->
double {
3021 StoreObjPtr<ParticleList> list(listname);
3022 if (not list.isValid())
3023 B2FATAL(
"Invalid particle list name " << listname <<
" given to closestInList");
3027 const auto p_this = frame.getMomentum(particle);
3030 double minAngle = 2 * M_PI;
3032 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3034 const Particle* compareme = list->getParticle(i);
3035 const auto p_compare = frame.getMomentum(compareme);
3036 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3037 if (minAngle > angle) {
3045 auto var_result = var->function(list->getParticle(iClosest));
3046 if (std::holds_alternative<double>(var_result))
3048 return std::get<double>(var_result);
3049 }
else if (std::holds_alternative<int>(var_result))
3051 return std::get<int>(var_result);
3052 }
else if (std::holds_alternative<bool>(var_result))
3054 return std::get<bool>(var_result);
3063 if (arguments.size() != 1)
3064 B2FATAL(
"Wrong number of arguments for meta function angleToMostB2BInList");
3066 std::string listname = arguments[0];
3068 auto func = [listname](
const Particle * particle) ->
double {
3070 StoreObjPtr<ParticleList> list(listname);
3071 if (not list.isValid())
3072 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToMostB2BInList");
3075 if (list->getListSize() == 0)
3080 const auto p_this = frame.getMomentum(particle);
3084 double maxAngle = 0;
3085 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3087 const Particle* compareme = list->getParticle(i);
3088 const auto p_compare = frame.getMomentum(compareme);
3089 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3090 if (maxAngle < angle) maxAngle = angle;
3100 if (arguments.size() != 1)
3101 B2FATAL(
"Wrong number of arguments for meta function deltaPhiToMostB2BPhiInList");
3103 std::string listname = arguments[0];
3105 auto func = [listname](
const Particle * particle) ->
double {
3107 StoreObjPtr<ParticleList> list(listname);
3108 if (not list.isValid())
3109 B2FATAL(
"Invalid particle list name " << listname <<
" given to deltaPhiToMostB2BPhiInList");
3112 if (list->getListSize() == 0)
3117 const auto phi_this = frame.getMomentum(particle).Phi();
3120 double maxAngle = 0;
3121 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3123 const Particle* compareme = list->getParticle(i);
3124 const auto phi_compare = frame.getMomentum(compareme).Phi();
3125 double angle = std::abs(phi_compare - phi_this);
3126 if (angle > M_PI) {angle = 2 * M_PI - angle;}
3127 if (maxAngle < angle) maxAngle = angle;
3137 if (arguments.size() != 2)
3138 B2FATAL(
"Wrong number of arguments for meta function mostB2BInList");
3140 std::string listname = arguments[0];
3145 auto func = [listname, var](
const Particle * particle) ->
double {
3147 StoreObjPtr<ParticleList> list(listname);
3148 if (not list.isValid())
3149 B2FATAL(
"Invalid particle list name " << listname <<
" given to mostB2BInList");
3153 const auto p_this = frame.getMomentum(particle);
3157 double maxAngle = -1.0;
3159 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3161 const Particle* compareme = list->getParticle(i);
3162 const auto p_compare = frame.getMomentum(compareme);
3163 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3164 if (maxAngle < angle) {
3172 auto var_result = var->function(list->getParticle(iMostB2B));
3173 if (std::holds_alternative<double>(var_result))
3175 return std::get<double>(var_result);
3176 }
else if (std::holds_alternative<int>(var_result))
3178 return std::get<int>(var_result);
3179 }
else if (std::holds_alternative<bool>(var_result))
3181 return std::get<bool>(var_result);
3189 if (arguments.size() == 1) {
3190 std::string listName = arguments[0];
3191 auto func = [listName](
const Particle*) ->
double {
3192 StoreObjPtr<ParticleList> listOfParticles(listName);
3194 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxOpeningAngleInList");
3195 int nParticles = listOfParticles->getListSize();
3200 double maxOpeningAngle = -1;
3201 for (
int i = 0; i < nParticles; i++)
3203 ROOT::Math::PxPyPzEVector v1 = frame.getMomentum(listOfParticles->getParticle(i));
3204 for (
int j = i + 1; j < nParticles; j++) {
3205 ROOT::Math::PxPyPzEVector v2 = frame.getMomentum(listOfParticles->getParticle(j));
3206 const double angle = ROOT::Math::VectorUtil::Angle(v1, v2);
3207 if (angle > maxOpeningAngle) maxOpeningAngle = angle;
3210 return maxOpeningAngle;
3214 B2FATAL(
"Wrong number of arguments for meta function maxOpeningAngleInList");
3221 if (arguments.size() >= 2) {
3226 auto func = [var, arguments](
const Particle * particle) ->
double {
3227 if (particle ==
nullptr)
3229 B2WARNING(
"Trying to access a daughter that does not exist. Skipping");
3235 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
3239 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++)
3241 auto generalizedIndex = arguments[iCoord];
3242 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
3244 pSum += frame.getMomentum(dauPart);
3246 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
3252 Particle sumOfDaughters(pSum, 100);
3254 auto var_result = var->function(&sumOfDaughters);
3256 if (std::holds_alternative<double>(var_result))
3258 return std::get<double>(var_result);
3259 }
else if (std::holds_alternative<int>(var_result))
3261 return std::get<int>(var_result);
3262 }
else if (std::holds_alternative<bool>(var_result))
3264 return std::get<bool>(var_result);
3269 B2FATAL(
"Wrong number of arguments for meta function daughterCombination");
3272 Manager::FunctionPtr useAlternativeDaughterHypothesis(
const std::vector<std::string>& arguments)
3285 if (arguments.size() >= 2) {
3296 std::unordered_map<unsigned int, int> mapOfReplacedDaughters;
3299 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++) {
3300 auto replacedDauString = arguments[iCoord];
3302 std::vector<std::string> indexAndMass;
3303 boost::split(indexAndMass, replacedDauString, boost::is_any_of(
":"));
3306 if (indexAndMass.size() > 2) {
3307 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 "
3308 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3312 if (indexAndMass.size() < 2) {
3313 B2WARNING(
"The string indicating which daughter's mass should be replaced contains only one colon-separated element instead of two. The offending string is "
3314 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3322 }
catch (std::invalid_argument&) {
3323 B2FATAL(
"Found the string " << indexAndMass[0] <<
"instead of a daughter index.");
3327 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(indexAndMass[1].c_str());
3329 B2WARNING(
"Particle not in evt.pdl file! " << indexAndMass[1]);
3334 int pdgCode = particlePDG->PdgCode();
3335 mapOfReplacedDaughters[dauIndex] = pdgCode;
3339 if (mapOfReplacedDaughters.size() != arguments.size() - 1)
3340 B2FATAL(
"Overlapped daughter's index is detected in the meta-variable useAlternativeDaughterHypothesis");
3348 auto func = [var, mapOfReplacedDaughters](
const Particle * particle) ->
double {
3349 if (particle ==
nullptr)
3351 B2WARNING(
"Trying to access a particle that does not exist. Skipping");
3361 ROOT::Math::PxPyPzMVector pSum(0, 0, 0, 0);
3363 for (
unsigned int iDau = 0; iDau < particle->getNDaughters(); iDau++)
3365 const Particle* dauPart = particle->getDaughter(iDau);
3367 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << iDau);
3371 ROOT::Math::PxPyPzMVector dauMom = ROOT::Math::PxPyPzMVector(frame.getMomentum(dauPart));
3375 pdgCode = mapOfReplacedDaughters.at(iDau);
3376 }
catch (std::out_of_range&) {
3383 double p_x = dauMom.Px();
3384 double p_y = dauMom.Py();
3385 double p_z = dauMom.Pz();
3386 dauMom.SetCoordinates(p_x, p_y, p_z, TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass());
3387 const_cast<Particle*
>(dummy->getDaughter(iDau))->set4VectorDividingByMomentumScaling(ROOT::Math::PxPyPzEVector(dauMom));
3390 const int charge = dummy->getDaughter(iDau)->getCharge();
3391 if (TDatabasePDG::Instance()->GetParticle(pdgCode)->Charge() / 3.0 == charge)
3392 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(pdgCode);
3394 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(-1 * pdgCode);
3400 dummy->set4Vector(ROOT::Math::PxPyPzEVector(pSum));
3402 auto var_result = var->function(dummy);
3405 if (std::holds_alternative<double>(var_result))
3407 return std::get<double>(var_result);
3408 }
else if (std::holds_alternative<int>(var_result))
3410 return std::get<int>(var_result);
3411 }
else if (std::holds_alternative<bool>(var_result))
3413 return std::get<bool>(var_result);
3419 B2FATAL(
"Wrong number of arguments for meta function useAlternativeDaughterHypothesis");
3424 if (arguments.size() == 2) {
3426 std::string arg = arguments[0];
3428 TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(arg.c_str());
3430 if (part !=
nullptr) {
3431 pdg_code = std::abs(part->PdgCode());
3435 }
catch (
const std::exception& e) {}
3438 if (pdg_code == -1) {
3439 B2FATAL(
"Ancestor " + arg +
" is not recognised. Please provide valid PDG code or particle name.");
3442 auto func = [pdg_code, var](
const Particle * particle) ->
double {
3443 const Particle* p = particle;
3445 int ancestor_level = std::get<double>(
Manager::Instance().getVariable(
"hasAncestor(" + std::to_string(pdg_code) +
", 0)")->function(p));
3446 if ((ancestor_level <= 0) or (std::isnan(ancestor_level)))
3451 const MCParticle* i_p = p->getMCParticle();
3453 for (
int a = 0; a < ancestor_level ; a = a + 1)
3455 i_p = i_p->getMother();
3458 StoreArray<Particle> tempParticles(
"tempParticles");
3459 tempParticles.clear();
3461 Particle* newPart = tempParticles.appendNew(m_p);
3462 newPart->addRelationTo(i_p);
3464 appendDaughtersRecursive(newPart, tempParticles);
3466 auto var_result = var->function(newPart);
3467 if (std::holds_alternative<double>(var_result))
3469 return std::get<double>(var_result);
3470 }
else if (std::holds_alternative<int>(var_result))
3472 return std::get<int>(var_result);
3473 }
else if (std::holds_alternative<bool>(var_result))
3475 return std::get<bool>(var_result);
3480 B2FATAL(
"Wrong number of arguments for meta function varForFirstMCAncestorOfType (expected 2: type and variable of interest)");
3486 if (arguments.size() > 4 || arguments.size() < 3) {
3487 B2FATAL(
"Number of arguments for varForNthDaughterOfType must be 3 or 4");
3490 std::string argPtype = arguments[0];
3491 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3492 TParticlePDG* part = pdgDatabase->GetParticle(argPtype.c_str());
3494 if (part !=
nullptr) {
3495 absPdg = std::abs(part->PdgCode());
3499 }
catch (
const std::exception&) { }
3501 if (absPdg == -1 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3502 B2FATAL(
"varForNthDaughterOfType: argument '" << argPtype <<
"' is neither a valid particle name nor a PDG code");
3505 std::string argIndex = arguments[1];
3509 }
catch (
const std::exception&) { }
3511 B2FATAL(
"varForNthDaughterOfType: argument '" << argIndex <<
"' is not a valid positive integer");
3517 if (arguments.size() == 4) {
3518 std::string argDepth = arguments[3];
3521 }
catch (
const std::exception&) {
3525 B2FATAL(
"varForNthDaughterOfType: argument '" << argDepth <<
"' is not a valid positive integer");
3529 auto func = [absPdg, index, var, depth](
const Particle * particle) ->
double {
3531 std::vector<Particle*> currentLevel = particle->getDaughters();
3532 std::vector<Particle*> nextLevel;
3533 for (
int d = 0; d < depth; d++)
3536 for (
unsigned i = 0; i < currentLevel.size(); i++) {
3537 Particle* p = currentLevel[i];
3538 if (std::abs(p->getPDGCode()) == absPdg) {
3540 if (nFound == index) {
3541 auto result = var->function(p);
3542 if (std::holds_alternative<double>(result)) {
3543 return std::get<double>(result);
3544 }
else if (std::holds_alternative<int>(result)) {
3545 return std::get<int>(result);
3546 }
else if (std::holds_alternative<bool>(result)) {
3547 return std::get<bool>(result);
3551 std::vector<Particle*> newParticles = p->getDaughters();
3552 nextLevel.insert(nextLevel.end(), newParticles.begin(), newParticles.end());
3554 currentLevel.clear();
3555 std::swap(currentLevel, nextLevel);
3565 if (arguments.size() != 1) {
3566 B2FATAL(
"Number of arguments for nTrackFitResults must be 1, particleType or PDGcode");
3569 std::string arg = arguments[0];
3570 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3571 TParticlePDG* part = pdgDatabase->GetParticle(arg.c_str());
3573 if (part !=
nullptr) {
3574 absPdg = std::abs(part->PdgCode());
3578 }
catch (
const std::exception&) {
3582 if (absPdg == 0 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3583 B2FATAL(
"nTrackFitResults: argument '" << arg <<
"' is neither a valid particle name nor a PDG code");
3587 auto func = [absPdg](
const Particle*) ->
int {
3589 Const::ChargedStable type(absPdg);
3590 StoreArray<Track> tracks;
3592 int nTrackFitResults = 0;
3594 for (
const auto& track : tracks)
3596 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(type);
3598 if (!trackFit)
continue;
3599 if (trackFit->getChargeSign() == 0)
continue;
3604 return nTrackFitResults;
3613 if (arguments.size() == 2) {
3616 auto func = [var, default_val](
const Particle * particle) ->
int {
3617 auto var_result = var->function(particle);
3618 if (std::holds_alternative<double>(var_result))
3620 double value = std::get<double>(var_result);
3621 if (value > std::numeric_limits<int>::max())
3622 value = std::numeric_limits<int>::max();
3623 if (value < std::numeric_limits<int>::min())
3624 value = std::numeric_limits<int>::min();
3625 if (std::isnan(value))
3626 value = default_val;
3627 return static_cast<int>(value);
3628 }
else if (std::holds_alternative<int>(var_result))
3629 return std::get<int>(var_result);
3630 else if (std::holds_alternative<bool>(var_result))
3631 return static_cast<int>(std::get<bool>(var_result));
3632 else return default_val;
3636 B2FATAL(
"Wrong number of arguments for meta function int, please provide variable name and replacement value for NaN!");
3640 VARIABLE_GROUP(
"MetaFunctions");
3641 REGISTER_METAVARIABLE(
"nCleanedECLClusters(cut)", nCleanedECLClusters,
3642 "[Eventbased] Returns the number of clean Clusters in the event\n"
3643 "Clean clusters are defined by the clusters which pass the given cut assuming a photon hypothesis.",
3644 Manager::VariableDataType::c_int);
3645 REGISTER_METAVARIABLE(
"nCleanedTracks(cut)", nCleanedTracks,
3646 "[Eventbased] Returns the number of clean Tracks in the event\n"
3647 "Clean tracks are defined by the tracks which pass the given cut assuming a pion hypothesis.", Manager::VariableDataType::c_int);
3648 REGISTER_METAVARIABLE(
"formula(v1 + v2 * [v3 - v4] / v5^v6)", formula, R
"DOCSTRING(
3649Returns the result of the given formula, where v1 to vN are variables or floating
3650point numbers. Currently the only supported operations are addition (``+``),
3651subtraction (``-``), multiplication (``*``), division (``/``) and power (``^``
3652or ``**``). Parenthesis can be in the form of square brackets ``[v1 * v2]``
3653or normal brackets ``(v1 * v2)``. It will work also with variables taking
3654arguments. Operator precedence is taken into account. For example ::
3656 (daughter(0, E) + daughter(1, E))**2 - p**2 + 0.138
3658.. versionchanged:: release-03-00-00
3659 now both, ``[]`` and ``()`` can be used for grouping operations, ``**`` can
3660 be used for exponent and float literals are possible directly in the
3662)DOCSTRING", Manager::VariableDataType::c_double);
3663 REGISTER_METAVARIABLE("useRestFrame(variable)", useRestFrame,
3664 "Returns the value of the variable using the rest frame of the given particle as current reference frame.\n"
3665 "E.g. ``useRestFrame(daughter(0, p))`` returns the total momentum of the first daughter in its mother's rest-frame", Manager::VariableDataType::c_double);
3666 REGISTER_METAVARIABLE(
"useCMSFrame(variable)", useCMSFrame,
3667 "Returns the value of the variable using the CMS frame as current reference frame.\n"
3668 "E.g. ``useCMSFrame(E)`` returns the energy of a particle in the CMS frame.", Manager::VariableDataType::c_double);
3669 REGISTER_METAVARIABLE(
"useLabFrame(variable)", useLabFrame, R
"DOC(
3670Returns the value of ``variable`` in the *lab* frame.
3673 The lab frame is the default reference frame, usually you don't need to use this meta-variable.
3674 E.g. ``useLabFrame(E)`` returns the energy of a particle in the Lab frame, same as just ``E``.
3676Specifying the lab frame is useful in some corner-cases. For example:
3677``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.
3678)DOC", Manager::VariableDataType::c_double);
3679 REGISTER_METAVARIABLE("useTagSideRecoilRestFrame(variable, daughterIndexTagB)", useTagSideRecoilRestFrame,
3680 "Returns the value of the variable in the rest frame of the recoiling particle to the tag side B meson.\n"
3681 "The variable should only be applied to an Upsilon(4S) list.\n"
3682 "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);
3683 REGISTER_METAVARIABLE(
"useParticleRestFrame(variable, particleList)", useParticleRestFrame,
3684 "Returns the value of the variable in the rest frame of the first Particle contained in the given ParticleList.\n"
3685 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3686 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3687 "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);
3688 REGISTER_METAVARIABLE(
"useRecoilParticleRestFrame(variable, particleList)", useRecoilParticleRestFrame,
3689 "Returns the value of the variable in the rest frame of recoil system against the first Particle contained in the given ParticleList.\n"
3690 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3691 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3692 "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);
3693 REGISTER_METAVARIABLE(
"useDaughterRestFrame(variable, daughterIndex_1, [daughterIndex_2, ... daughterIndex_3])", useDaughterRestFrame,
3694 "Returns the value of the variable in the rest frame of the selected daughter particle.\n"
3695 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3696 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3697 "If two or more indices are given, the rest frame of the sum of the daughters is used.",
3698 Manager::VariableDataType::c_double);
3699 REGISTER_METAVARIABLE(
"useDaughterRecoilRestFrame(variable, daughterIndex_1, [daughterIndex_2, ... daughterIndex_3])", useDaughterRecoilRestFrame,
3700 "Returns the value of the variable in the rest frame of the recoil of the selected daughter particle.\n"
3701 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3702 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3703 "If two or more indices are given, the rest frame of the sum of the daughters is used.",
3704 Manager::VariableDataType::c_double);
3705 REGISTER_METAVARIABLE(
"useMCancestorBRestFrame(variable)", useMCancestorBRestFrame,
3706 "Returns the value of the variable in the rest frame of the ancestor B MC particle.\n"
3707 "If no B or no MC-matching is found, it returns NaN.", Manager::VariableDataType::c_double);
3708 REGISTER_METAVARIABLE(
"passesCut(cut)", passesCut,
3709 "Returns 1 if particle passes the cut otherwise 0.\n"
3710 "Useful if you want to write out if a particle would have passed a cut or not.", Manager::VariableDataType::c_bool);
3711 REGISTER_METAVARIABLE(
"passesEventCut(cut)", passesEventCut,
3712 "[Eventbased] Returns 1 if event passes the cut otherwise 0.\n"
3713 "Useful if you want to select events passing a cut without looping into particles, such as for skimming.\n", Manager::VariableDataType::c_bool);
3714 REGISTER_METAVARIABLE(
"countDaughters(cut)", countDaughters,
3715 "Returns number of direct daughters which satisfy the cut.\n"
3716 "Used by the skimming package (for what exactly?)", Manager::VariableDataType::c_int);
3717 REGISTER_METAVARIABLE(
"countFSPDaughters(cut)", countDescendants,
3718 "Returns number of final-state daughters which satisfy the cut.",
3719 Manager::VariableDataType::c_int);
3720 REGISTER_METAVARIABLE(
"countDescendants(cut)", countDescendants,
3721 "Returns number of descendants for all generations which satisfy the cut.",
3722 Manager::VariableDataType::c_int);
3723 REGISTER_METAVARIABLE(
"varFor(pdgCode, variable)", varFor,
3724 "Returns the value of the variable for the given particle if its abs(pdgCode) agrees with the given one.\n"
3725 "E.g. ``varFor(11, p)`` returns the momentum if the particle is an electron or a positron.", Manager::VariableDataType::c_double);
3726 REGISTER_METAVARIABLE(
"varForMCGen(variable)", varForMCGen,
3727 "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"
3728 "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"
3729 "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);
3730 REGISTER_METAVARIABLE(
"nParticlesInList(particleListName)", nParticlesInList,
3731 "[Eventbased] Returns number of particles in the given particle List.", Manager::VariableDataType::c_int);
3732 REGISTER_METAVARIABLE(
"isInList(particleListName)", isInList,
3733 "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);
3734 REGISTER_METAVARIABLE(
"isDaughterOfList(particleListNames)", isDaughterOfList,
3735 "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);
3736 REGISTER_METAVARIABLE(
"isDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isDescendantOfList, R
"DOC(
3737 Returns 1 if the given particle appears in the decay chain of the particles in the given ParticleLists.
3739 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3741 * ``isDescendantOfList(<particle_list>,1)`` returns 1 if particle is a daughter of the list,
3742 * ``isDescendantOfList(<particle_list>,2)`` returns 1 if particle is a granddaughter of the list,
3743 * ``isDescendantOfList(<particle_list>,3)`` returns 1 if particle is a great-granddaughter of the list, etc.
3744 * Default value is ``-1`` that is inclusive for all generations.
3745 )DOC", Manager::VariableDataType::c_bool);
3746 REGISTER_METAVARIABLE("isMCDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isMCDescendantOfList, R
"DOC(
3747 Returns 1 if the given particle is linked to the same MC particle as any reconstructed daughter of the decay lists.
3749 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3751 * ``isMCDescendantOfList(<particle_list>,1)`` returns 1 if particle is matched to the same particle as any daughter of the list,
3752 * ``isMCDescendantOfList(<particle_list>,2)`` returns 1 if particle is matched to the same particle as any granddaughter of the list,
3753 * ``isMCDescendantOfList(<particle_list>,3)`` returns 1 if particle is matched to the same particle as any great-granddaughter of the list, etc.
3754 * Default value is ``-1`` that is inclusive for all generations.
3756 It makes only sense for lists created with `fillParticleListFromMC` function with ``addDaughters=True`` argument.
3757 )DOC", Manager::VariableDataType::c_bool);
3759 REGISTER_METAVARIABLE("sourceObjectIsInList(particleListName)", sourceObjectIsInList, R
"DOC(
3760Returns 1 if the underlying mdst object (e.g. track, or cluster) was used to create a particle in ``particleListName``, 0 if not.
3763 This only makes sense for particles that are not composite. Returns -1 for composite particles.
3764)DOC", Manager::VariableDataType::c_int);
3766 REGISTER_METAVARIABLE("mcParticleIsInMCList(particleListName)", mcParticleIsInMCList, R
"DOC(
3767Returns 1 if the particle's matched MC particle is also matched to a particle in ``particleListName``
3768(or if either of the lists were filled from generator level `modularAnalysis.fillParticleListFromMC`.)
3770.. seealso:: :b2:var:`isMCDescendantOfList` to check daughters.
3771)DOC", Manager::VariableDataType::c_bool);
3773 REGISTER_METAVARIABLE("isGrandDaughterOfList(particleListNames)", isGrandDaughterOfList,
3774 "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);
3775 REGISTER_METAVARIABLE(
"originalParticle(variable)", originalParticle, R
"DOC(
3776 Returns value of variable for the original particle from which the given particle is copied.
3778 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3779 Returns NaN if the given particle is not copied and so there is no original particle.
3780 )DOC", Manager::VariableDataType::c_double);
3781 REGISTER_METAVARIABLE("daughter(i, variable)", daughter, R
"DOC(
3782 Returns value of variable for the i-th daughter. E.g.
3784 * ``daughter(0, p)`` returns the total momentum of the first daughter.
3785 * ``daughter(0, daughter(1, p)`` returns the total momentum of the second daughter of the first daughter.
3787 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3788 )DOC", Manager::VariableDataType::c_double);
3789 REGISTER_METAVARIABLE("originalDaughter(i, variable)", originalDaughter, R
"DOC(
3790 Returns value of variable for the original particle from which the i-th daughter is copied.
3792 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3793 Returns NaN if the daughter is not copied and so there is no original daughter.
3795 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3796 )DOC", Manager::VariableDataType::c_double);
3797 REGISTER_METAVARIABLE("mcDaughter(i, variable)", mcDaughter, R
"DOC(
3798 Returns the value of the requested variable for the i-th Monte Carlo daughter of the particle.
3800 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3801 or if the i-th MC daughter does not exist.
3803 E.g. ``mcDaughter(0, PDG)`` will return the PDG code of the first MC daughter of the matched MC
3804 particle of the reconstructed particle the function is applied to.
3806 The meta variable can also be nested: ``mcDaughter(0, mcDaughter(1, PDG))``.
3807 )DOC", Manager::VariableDataType::c_double);
3808 REGISTER_METAVARIABLE("mcMother(variable)", mcMother, R
"DOC(
3809 Returns the value of the requested variable for the Monte Carlo mother of the particle.
3811 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3812 or if the MC mother does not exist.
3814 E.g. ``mcMother(PDG)`` will return the PDG code of the MC mother of the matched MC
3815 particle of the reconstructed particle the function is applied to.
3817 The meta variable can also be nested: ``mcMother(mcMother(PDG))``.
3818 )DOC", Manager::VariableDataType::c_double);
3819 REGISTER_METAVARIABLE("genParticle(index, variable)", genParticle, R
"DOC(
3820[Eventbased] Returns the ``variable`` for the ith generator particle.
3821The arguments of the function must be the ``index`` of the particle in the MCParticle Array,
3822and ``variable``, the name of the function or variable for that generator particle.
3823If ``index`` goes beyond the length of the MCParticles array, NaN will be returned.
3825E.g. ``genParticle(0, p)`` returns the total momentum of the first MCParticle, which in a generic decay up to MC15 is
3826the Upsilon(4S) and for MC16 and beyond the initial electron.
3827)DOC", Manager::VariableDataType::c_double);
3828 REGISTER_METAVARIABLE("genUpsilon4S(variable)", genUpsilon4S, R
"DOC(
3829[Eventbased] Returns the ``variable`` evaluated for the generator-level :math:`\Upsilon(4S)`.
3830If no generator level :math:`\Upsilon(4S)` exists for the event, NaN will be returned.
3832E.g. ``genUpsilon4S(p)`` returns the total momentum of the :math:`\Upsilon(4S)` in a generic decay.
3833``genUpsilon4S(mcDaughter(1, p))`` returns the total momentum of the second daughter of the
3834generator-level :math:`\Upsilon(4S)` (i.e. the momentum of the second B meson in a generic decay).
3835)DOC", Manager::VariableDataType::c_double);
3836 REGISTER_METAVARIABLE("daughterProductOf(variable)", daughterProductOf,
3837 "Returns product of a variable over all daughters.\n"
3838 "E.g. ``daughterProductOf(extraInfo(SignalProbability))`` returns the product of the SignalProbabilitys of all daughters.", Manager::VariableDataType::c_double);
3839 REGISTER_METAVARIABLE(
"daughterSumOf(variable)", daughterSumOf,
3840 "Returns sum of a variable over all daughters.\n"
3841 "E.g. ``daughterSumOf(nDaughters)`` returns the number of grand-daughters.", Manager::VariableDataType::c_double);
3842 REGISTER_METAVARIABLE(
"daughterLowest(variable)", daughterLowest,
3843 "Returns the lowest value of the given variable among all daughters.\n"
3844 "E.g. ``useCMSFrame(daughterLowest(p))`` returns the lowest momentum in CMS frame.", Manager::VariableDataType::c_double);
3845 REGISTER_METAVARIABLE(
"daughterHighest(variable)", daughterHighest,
3846 "Returns the highest value of the given variable among all daughters.\n"
3847 "E.g. ``useCMSFrame(daughterHighest(p))`` returns the highest momentum in CMS frame.", Manager::VariableDataType::c_double);
3848 REGISTER_METAVARIABLE(
"daughterDiffOf(daughterIndex_i, daughterIndex_j, variable)", daughterDiffOf, R
"DOC(
3849 Returns the difference of a variable between the two given daughters.
3850 E.g. ``useRestFrame(daughterDiffOf(0, 1, p))`` returns the momentum difference between first and second daughter in the rest frame of the given particle.
3851 (That means that it returns :math:`p_j - p_i`)
3853 The daughters can be provided as generalized daughter indexes, which are simply colon-separated
3854 lists of daughter indexes, ordered starting from the root particle. For example, ``0:1``
3855 identifies the second daughter (1) of the first daughter (0) of the mother particle.
3857 )DOC", Manager::VariableDataType::c_double);
3858 REGISTER_METAVARIABLE("mcDaughterDiffOf(i, j, variable)", mcDaughterDiffOf,
3859 "MC matched version of the `daughterDiffOf` function.", Manager::VariableDataType::c_double);
3860 REGISTER_METAVARIABLE(
"grandDaughterDiffOf(i, j, variable)", grandDaughterDiffOf,
3861 "Returns the difference of a variable between the first daughters of the two given daughters.\n"
3862 "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"
3863 "(That means that it returns :math:`p_j - p_i`)", Manager::VariableDataType::c_double);
3864 MAKE_DEPRECATED(
"grandDaughterDiffOf",
false,
"light-2402-ocicat", R
"DOC(
3865 The difference between any combination of (grand-)daughters can be calculated with the more general variable :b2:var:`daughterDiffOf`
3866 by using generalized daughter indexes.)DOC");
3867 REGISTER_METAVARIABLE("daughterNormDiffOf(i, j, variable)", daughterNormDiffOf,
3868 "Returns the normalized difference of a variable between the two given daughters.\n"
3869 "E.g. ``daughterNormDiffOf(0, 1, p)`` returns the normalized momentum difference between first and second daughter in the lab frame.", Manager::VariableDataType::c_double);
3870 REGISTER_METAVARIABLE(
"daughterMotherDiffOf(i, variable)", daughterMotherDiffOf,
3871 "Returns the difference of a variable between the given daughter and the mother particle itself.\n"
3872 "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);
3873 REGISTER_METAVARIABLE(
"daughterMotherNormDiffOf(i, variable)", daughterMotherNormDiffOf,
3874 "Returns the normalized difference of a variable between the given daughter and the mother particle itself.\n"
3875 "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);
3876 REGISTER_METAVARIABLE(
"angleBetweenDaughterAndRecoil(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndRecoil, R
"DOC(
3877 Returns the angle between the momentum recoiling against the particle and the sum of the momenta of the given daughters.
3878 The unit of the angle is ``rad``.
3880 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3881 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3882 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3883 identifies the second daughter of the root particle.
3885 At least one generalized index has to be given to ``angleBetweenDaughterAndRecoil``.
3888 ``angleBetweenDaughterAndRecoil(0)`` will return the angle between pRecoil and the momentum of the first daughter.
3890 ``angleBetweenDaughterAndRecoil(0, 1)`` will return the angle between pRecoil and the sum of the momenta of the first and second daughter.
3892 ``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
3893 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3894 REGISTER_METAVARIABLE("angleBetweenDaughterAndMissingMomentum(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndMissingMomentum, R
"DOC(
3895 Returns the angle between the missing momentum in the event and the sum of the momenta of the given daughters.
3896 The unit of the angle is ``rad``. EventKinematics module has to be called to use this.
3898 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3899 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3900 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3901 identifies the second daughter of the root particle.
3903 At least one generalized index has to be given to ``angleBetweenDaughterAndMissingMomentum``.
3906 ``angleBetweenDaughterAndMissingMomentum(0)`` will return the angle between missMom and the momentum of the first daughter.
3908 ``angleBetweenDaughterAndMissingMomentum(0, 1)`` will return the angle between missMom and the sum of the momenta of the first and second daughter.
3910 ``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
3911 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3912 REGISTER_METAVARIABLE("daughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", daughterAngle, R
"DOC(
3913 Returns the angle in between any pair of particles belonging to the same decay tree.
3914 The unit of the angle is ``rad``.
3916 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3917 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3918 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3919 identifies the second daughter of the root particle.
3921 Both two and three generalized indexes can be given to ``daughterAngle``. If two indices are given, the
3922 variable returns the angle between the momenta of the two given particles. If three indices are given, the
3923 variable returns the angle between the momentum of the third particle and a vector which is the sum of the
3924 first two daughter momenta.
3927 ``daughterAngle(0, 3)`` will return the angle between the first and fourth daughter.
3928 ``daughterAngle(0, 1, 3)`` will return the angle between the fourth daughter and the sum of the first and
3930 ``daughterAngle(0:0, 3:0)`` will return the angle between the first daughter of the first daughter, and
3931 the first daughter of the fourth daughter.
3933 )DOC", Manager::VariableDataType::c_double);
3934 REGISTER_METAVARIABLE("mcDaughterAngle(daughterIndex_1, daughterIndex_2, [daughterIndex_3])", mcDaughterAngle,
3935 "MC matched version of the `daughterAngle` function. Also works if applied directly to MC particles. The unit of the angle is ``rad``", Manager::VariableDataType::c_double);
3936 REGISTER_VARIABLE(
"grandDaughterDecayAngle(i, j)", grandDaughterDecayAngle,
3937 "Returns the decay angle of the granddaughter in the daughter particle's rest frame.\n"
3938 "It is calculated with respect to the reverted momentum vector of the particle.\n"
3939 "Two arguments representing the daughter and granddaughter indices have to be provided as arguments.\n\n",
"rad");
3940 REGISTER_VARIABLE(
"daughterClusterAngleInBetween(i, j)", daughterClusterAngleInBetween,
3941 "Returns the angle between clusters associated to the two daughters."
3942 "If two indices given: returns the angle between the momenta of the clusters associated to the two given daughters."
3943 "If three indices given: returns the angle between the momentum of the third particle's cluster and a vector "
3944 "which is the sum of the first two daughter's cluster momenta."
3945 "Returns nan if any of the daughters specified don't have an associated cluster."
3946 "The arguments in the argument vector must be integers corresponding to the ith and jth (and kth) daughters.\n\n",
"rad");
3947 REGISTER_METAVARIABLE(
"daughterInvM(i[, j, ...])", daughterInvM, R
"DOC(
3948 Returns the invariant mass adding the Lorentz vectors of the given daughters. The unit of the invariant mass is GeV/:math:`\text{c}^2`
3949 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.
3951 Daughters from different generations of the decay tree can be combined using generalized daughter indexes,
3952 which are simply colon-separated daughter indexes for each generation, starting from the root particle. For
3953 example, ``0:1:3`` identifies the fourth daughter (3) of the second daughter (1) of the first daughter(0) of
3954 the mother particle.
3956 Returns NaN if the given daughter-index is out of bound (>= number of daughters))DOC", Manager::VariableDataType::c_double);
3957 REGISTER_METAVARIABLE("extraInfo(name)", extraInfo,
3958 "Returns extra info stored under the given name.\n"
3959 "The extraInfo has to be set by a module first.\n"
3960 "E.g. ``extraInfo(SignalProbability)`` returns the SignalProbability calculated by the ``MVAExpert`` module.\n"
3961 "If nothing is set under the given name or if the particle is a nullptr, NaN is returned.\n"
3962 "In the latter case please use `eventExtraInfo` if you want to access an EventExtraInfo variable.", Manager::VariableDataType::c_double);
3963 REGISTER_METAVARIABLE(
"eventExtraInfo(name)", eventExtraInfo,
3964 "[Eventbased] Returns extra info stored under the given name in the event extra info.\n"
3965 "The extraInfo has to be set first by another module like MVAExpert in event mode.\n"
3966 "If nothing is set under this name, NaN is returned.", Manager::VariableDataType::c_double);
3967 REGISTER_METAVARIABLE(
"eventCached(variable)", eventCached,
3968 "[Eventbased] Returns value of event-based variable and caches this value in the EventExtraInfo.\n"
3969 "The result of second call to this variable in the same event will be provided from the cache.\n"
3970 "It is recommended to use this variable in order to declare custom aliases as event-based. This is "
3971 "necessary if using the eventwise mode of variablesToNtuple).", Manager::VariableDataType::c_double);
3972 REGISTER_METAVARIABLE(
"particleCached(variable)", particleCached,
3973 "Returns value of given variable and caches this value in the ParticleExtraInfo of the provided particle.\n"
3974 "The result of second call to this variable on the same particle will be provided from the cache.", Manager::VariableDataType::c_double);
3975 REGISTER_METAVARIABLE(
"modulo(variable, n)", modulo,
3976 "Returns rest of division of variable by n.", Manager::VariableDataType::c_int);
3977 REGISTER_METAVARIABLE(
"abs(variable)", abs,
3978 "Returns absolute value of the given variable.\n"
3979 "E.g. abs(mcPDG) returns the absolute value of the mcPDG, which is often useful for cuts.", Manager::VariableDataType::c_double);
3980 REGISTER_METAVARIABLE(
"max(var1,var2)", max,
"Returns max value of two variables.\n", Manager::VariableDataType::c_double);
3981 REGISTER_METAVARIABLE(
"min(var1,var2)", min,
"Returns min value of two variables.\n", Manager::VariableDataType::c_double);
3982 REGISTER_METAVARIABLE(
"sin(variable)", sin,
"Returns sine value of the given variable.", Manager::VariableDataType::c_double);
3983 REGISTER_METAVARIABLE(
"asin(variable)", asin,
"Returns arcsine of the given variable. The unit of the asin() is ``rad``", Manager::VariableDataType::c_double);
3984 REGISTER_METAVARIABLE(
"cos(variable)", cos,
"Returns cosine value of the given variable.", Manager::VariableDataType::c_double);
3985 REGISTER_METAVARIABLE(
"acos(variable)", acos,
"Returns arccosine value of the given variable. The unit of the acos() is ``rad``", Manager::VariableDataType::c_double);
3986 REGISTER_METAVARIABLE(
"tan(variable)", tan,
"Returns tangent value of the given variable.", Manager::VariableDataType::c_double);
3987 REGISTER_METAVARIABLE(
"atan(variable)", atan,
"Returns arctangent value of the given variable. The unit of the atan() is ``rad``", Manager::VariableDataType::c_double);
3988 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);
3989 REGISTER_METAVARIABLE(
"exp(variable)", exp,
"Returns exponential evaluated for the given variable.", Manager::VariableDataType::c_double);
3990 REGISTER_METAVARIABLE(
"log(variable)", log,
"Returns natural logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
3991 REGISTER_METAVARIABLE(
"log10(variable)", log10,
"Returns base-10 logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
3992 REGISTER_METAVARIABLE(
"int(variable, nan_replacement)", convertToInt, R
"DOC(
3993 Casts the output of the variable to an integer value.
3996 Overflow and underflow are clipped at maximum and minimum values, respectively. NaN values are replaced with the value of the 2nd argument.
3998 )DOC", Manager::VariableDataType::c_int);
3999 REGISTER_METAVARIABLE("isNAN(variable)", isNAN,
4000 "Returns true if variable value evaluates to nan (determined via std::isnan(double)).\n"
4001 "Useful for debugging.", Manager::VariableDataType::c_bool);
4002 REGISTER_METAVARIABLE(
"ifNANgiveX(variable, x)", ifNANgiveX,
4003 "Returns x (has to be a number) if variable value is nan (determined via std::isnan(double)).\n"
4004 "Useful for technical purposes while training MVAs.", Manager::VariableDataType::c_double);
4005 REGISTER_METAVARIABLE(
"isInfinity(variable)", isInfinity,
4006 "Returns true if variable value evaluates to infinity (determined via std::isinf(double)).\n"
4007 "Useful for debugging.", Manager::VariableDataType::c_bool);
4008 REGISTER_METAVARIABLE(
"unmask(variable, flag1, flag2, ...)", unmask,
4009 "unmask(variable, flag1, flag2, ...) or unmask(variable, mask) sets certain bits in the variable to zero.\n"
4010 "For example, if you want to set the second, fourth and fifth bits to zero, you could call \n"
4011 "``unmask(variable, 2, 8, 16)`` or ``unmask(variable, 26)``.\n"
4012 "", Manager::VariableDataType::c_double);
4013 REGISTER_METAVARIABLE(
"conditionalVariableSelector(cut, variableIfTrue, variableIfFalse)", conditionalVariableSelector,
4014 "Returns one of the two supplied variables, depending on whether the particle passes the supplied cut.\n"
4015 "The first variable is returned if the particle passes the cut, and the second variable is returned otherwise.", Manager::VariableDataType::c_double);
4016 REGISTER_METAVARIABLE(
"pValueCombination(p1, p2, ...)", pValueCombination,
4017 "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"
4018 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4019 REGISTER_METAVARIABLE(
"pValueCombinationOfDaughters(variable)", pValueCombinationOfDaughters,
4020 "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"
4021 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
4022 REGISTER_METAVARIABLE(
"veto(particleList, cut, pdgCode = 11)", veto,
4023 "Combines current particle with particles from the given particle list and returns 1 if the combination passes the provided cut. \n"
4024 "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"
4025 "around the neutral Pion mass (e.g. ``0.130 < M < 0.140``). \n"
4026 "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", Manager::VariableDataType::c_bool);
4027 REGISTER_METAVARIABLE(
"matchedMC(variable)", matchedMC,
4028 "Returns variable output for the matched MCParticle by constructing a temporary Particle from it.\n"
4029 "This may not work too well if your variable requires accessing daughters of the particle.\n"
4030 "E.g. ``matchedMC(p)`` returns the total momentum of the related MCParticle.\n"
4031 "Returns NaN if no matched MCParticle exists.", Manager::VariableDataType::c_double);
4032 REGISTER_METAVARIABLE(
"clusterBestMatchedMCParticle(variable)", clusterBestMatchedMCParticle,
4033 "Returns variable output for the MCParticle that is best-matched with the ECLCluster of the given Particle.\n"
4034 "E.g. To get the energy of the MCParticle that matches best with an ECLCluster, one could use ``clusterBestMatchedMCParticle(E)``\n"
4035 "When the variable is called for ``gamma`` and if the ``gamma`` is matched with MCParticle, it works same as `matchedMC`.\n"
4036 "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"
4037 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching MCParticles", Manager::VariableDataType::c_double);
4038 REGISTER_METAVARIABLE(
"varForBestMatchedMCKlong(variable)", clusterBestMatchedMCKlong,
4039 "Returns variable output for the Klong MCParticle which has the best match with the ECLCluster of the given Particle.\n"
4040 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching Klong MCParticle", Manager::VariableDataType::c_double);
4042 REGISTER_METAVARIABLE(
"countInList(particleList, cut='')", countInList,
"[Eventbased] "
4043 "Returns number of particle which pass given in cut in the specified particle list.\n"
4044 "Useful for creating statistics about the number of particles in a list.\n"
4045 "E.g. ``countInList(e+, isSignal == 1)`` returns the number of correctly reconstructed electrons in the event.\n"
4046 "The variable is event-based and does not need a valid particle pointer as input.", Manager::VariableDataType::c_int);
4047 REGISTER_METAVARIABLE(
"getVariableByRank(particleList, rankedVariableName, variableName, rank)", getVariableByRank, R
"DOC(
4048 [Eventbased] Returns the value of ``variableName`` for the candidate in the ``particleList`` with the requested ``rank``.
4051 The `BestCandidateSelection` module available via `rankByHighest` / `rankByLowest` has to be used before.
4054 The first candidate matching the given rank is used.
4055 Thus, it is not recommended to use this variable in conjunction with ``allowMultiRank`` in the `BestCandidateSelection` module.
4057 The suffix ``_rank`` is automatically added to the argument ``rankedVariableName``,
4058 which either has to be the name of the variable used to order the candidates or the selected outputVariable name without the ending ``_rank``.
4059 This means that your selected name for the rank variable has to end with ``_rank``.
4061 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>`_
4062 )DOC", Manager::VariableDataType::c_double);
4063 REGISTER_VARIABLE("matchedMCHasPDG(PDGCode)", matchedMCHasPDG,
4064 "Returns if the absolute value of the PDGCode of the MCParticle related to the Particle matches a given PDGCode."
4065 "Returns 0/NAN/1 if PDGCode does not match/is not available/ matches");
4066 REGISTER_METAVARIABLE(
"numberOfNonOverlappingParticles(pList1, pList2, ...)", numberOfNonOverlappingParticles,
4067 "Returns the number of non-overlapping particles in the given particle lists"
4068 "Useful to check if there is additional physics going on in the detector if one reconstructed the Y4S", Manager::VariableDataType::c_int);
4069 REGISTER_METAVARIABLE(
"totalEnergyOfParticlesInList(particleListName)", totalEnergyOfParticlesInList,
4070 "[Eventbased] Returns the total energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4071 REGISTER_METAVARIABLE(
"totalPxOfParticlesInList(particleListName)", totalPxOfParticlesInList,
4072 "[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);
4073 REGISTER_METAVARIABLE(
"totalPyOfParticlesInList(particleListName)", totalPyOfParticlesInList,
4074 "[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);
4075 REGISTER_METAVARIABLE(
"totalPzOfParticlesInList(particleListName)", totalPzOfParticlesInList,
4076 "[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);
4077 REGISTER_METAVARIABLE(
"invMassInLists(pList1, pList2, ...)", invMassInLists,
4078 "[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);
4079 REGISTER_METAVARIABLE(
"totalECLEnergyOfParticlesInList(particleListName)", totalECLEnergyOfParticlesInList,
4080 "[Eventbased] Returns the total ECL energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4081 REGISTER_METAVARIABLE(
"maxPtInList(particleListName)", maxPtInList,
4082 "[Eventbased] Returns maximum transverse momentum Pt in the given particle List. The unit of the transverse momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4083 REGISTER_METAVARIABLE(
"eclClusterSpecialTrackMatched(cut)", eclClusterTrackMatchedWithCondition,
4084 "Returns if at least one Track that satisfies the given condition is related to the ECLCluster of the Particle.", Manager::VariableDataType::c_double);
4085 REGISTER_METAVARIABLE(
"averageValueInList(particleListName, variable)", averageValueInList,
4086 "[Eventbased] Returns the arithmetic mean of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4087 REGISTER_METAVARIABLE(
"medianValueInList(particleListName, variable)", medianValueInList,
4088 "[Eventbased] Returns the median value of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4089 REGISTER_METAVARIABLE(
"sumValueInList(particleListName, variable)", sumValueInList,
4090 "[Eventbased] Returns the sum of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4091 REGISTER_METAVARIABLE(
"productValueInList(particleListName, variable)", productValueInList,
4092 "[Eventbased] Returns the product of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4093 REGISTER_METAVARIABLE(
"angleToClosestInList(particleListName)", angleToClosestInList,
4094 "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);
4095 REGISTER_METAVARIABLE(
"closestInList(particleListName, variable)", closestInList,
4096 "Returns `variable` for the closest particle (smallest opening angle) in the list provided.", Manager::VariableDataType::c_double);
4097 REGISTER_METAVARIABLE(
"angleToMostB2BInList(particleListName)", angleToMostB2BInList,
4098 "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);
4099 REGISTER_METAVARIABLE(
"deltaPhiToMostB2BPhiInList(particleListName)", deltaPhiToMostB2BPhiInList,
4100 "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);
4101 REGISTER_METAVARIABLE(
"mostB2BInList(particleListName, variable)", mostB2BInList,
4102 "Returns `variable` for the most back-to-back particle (closest opening angle to 180) in the list provided.", Manager::VariableDataType::c_double);
4103 REGISTER_METAVARIABLE(
"maxOpeningAngleInList(particleListName)", maxOpeningAngleInList,
4104 "[Eventbased] Returns maximum opening angle in the given particle List. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4105 REGISTER_METAVARIABLE(
"daughterCombination(variable, daughterIndex_1, daughterIndex_2 ... daughterIndex_n)", daughterCombination,R
"DOC(
4106Returns a ``variable`` function only of the 4-momentum calculated on an arbitrary set of (grand)daughters.
4109 ``variable`` can only be a function of the daughters' 4-momenta.
4111Daughters from different generations of the decay tree can be combined using generalized daughter indexes, which are simply colon-separated
4112the list of daughter indexes, starting from the root particle: for example, ``0:1:3`` identifies the fourth
4113daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle.
4116 ``daughterCombination(M, 0, 3, 4)`` will return the invariant mass of the system made of the first, fourth and fifth daughter of particle.
4117 ``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.
4119)DOC", Manager::VariableDataType::c_double);
4120 REGISTER_METAVARIABLE("useAlternativeDaughterHypothesis(variable, daughterIndex_1:newMassHyp_1, ..., daughterIndex_n:newMassHyp_n)", useAlternativeDaughterHypothesis,R
"DOC(
4121Returns a ``variable`` calculated using new mass hypotheses for (some of) the particle's daughters.
4124 ``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.
4125 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.
4126 Also, the track fit is not performed again: the variable only re-calculates the 4-vectors using different mass assumptions.
4127 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).
4130 Generalized daughter indexes are not supported (yet!): this variable can be used only on first-generation daughters.
4133 ``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.
4134 ``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.
4136)DOC", Manager::VariableDataType::c_double);
4137 REGISTER_METAVARIABLE("varForFirstMCAncestorOfType(type, variable)",varForFirstMCAncestorOfType,R
"DOC(Returns requested variable of the first ancestor of the given type.
4138Ancestor type can be set up by PDG code or by particle name (check evt.pdl for valid particle names))DOC", Manager::VariableDataType::c_double);
4139 REGISTER_METAVARIABLE("varForNthDaughterOfType(type, n, variable, maxDepth = 1)",varForNthDaughterOfType,R
"DOC(Returns requested variable for nth daughter (``n`` starting at 1) of the given type.
4140Particle 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).
4141Maximal depth controls how many generations of daughters are searched (``maxDepth=1`` only direct daughters, ``maxDepth=2`` also granddaughters, ...).
4142As 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!)
4143If no nth daughter of the given type can be found at given maximal depth, returns NaN.)DOC", Manager::VariableDataType::c_double);
4145 REGISTER_METAVARIABLE("nTrackFitResults(particleType)", nTrackFitResults,
4146 "[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).",
4147 Manager::VariableDataType::c_int);
4149 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.