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 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 (std::exception& e) {}
693 for (
auto& iListName : listNames)
698 }
catch (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 (std::exception& e) {}
756 if (particle->getMCParticle() ==
nullptr)
761 for (
auto& iListName : listNames)
764 std::stod(iListName);
766 }
catch (std::exception& e) {}
768 auto list_comparison = [](
auto&& self,
const Particle * m,
const Particle * p,
int flag)->
bool {
770 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
772 const Particle* daughter = m->getDaughter(i);
773 if ((flag == 1.) or (flag < 0)) {
774 if (daughter->getMCParticle() !=
nullptr) {
775 if (p->getMCParticle()->getArrayIndex() == daughter->getMCParticle()->getArrayIndex()) {
781 if (daughter->getNDaughters() > 0) {
782 result = self(self, daughter, p, flag - 1);
792 StoreObjPtr<ParticleList> listOfParticles(iListName);
794 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isMCDescendantOfList");
796 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
797 Particle* iParticle = listOfParticles->getParticle(i);
798 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
808 B2FATAL(
"Wrong number of arguments for meta function isMCDescendantOfList");
814 if (arguments.size() == 1) {
816 auto func = [var](
const Particle * particle) ->
double {
817 double product = 1.0;
818 if (particle->getNDaughters() == 0)
822 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
824 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
825 product *= std::get<double>(var->function(particle->getDaughter(j)));
827 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
829 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
830 product *= std::get<int>(var->function(particle->getDaughter(j)));
837 B2FATAL(
"Wrong number of arguments for meta function daughterProductOf");
843 if (arguments.size() == 1) {
845 auto func = [var](
const Particle * particle) ->
double {
847 if (particle->getNDaughters() == 0)
851 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
853 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
854 sum += std::get<double>(var->function(particle->getDaughter(j)));
856 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
858 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
859 sum += std::get<int>(var->function(particle->getDaughter(j)));
866 B2FATAL(
"Wrong number of arguments for meta function daughterSumOf");
872 if (arguments.size() == 1) {
874 auto func = [var](
const Particle * particle) ->
double {
876 if (particle->getNDaughters() == 0)
880 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
882 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
883 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
884 if (std::isnan(iValue))
continue;
885 if (std::isnan(min)) min = iValue;
886 if (iValue < min) min = iValue;
888 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
890 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
891 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
892 if (std::isnan(min)) min = iValue;
893 if (iValue < min) min = iValue;
900 B2FATAL(
"Wrong number of arguments for meta function daughterLowest");
906 if (arguments.size() == 1) {
908 auto func = [var](
const Particle * particle) ->
double {
910 if (particle->getNDaughters() == 0)
914 if (std::holds_alternative<double>(var->function(particle->getDaughter(0))))
916 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
917 double iValue = std::get<double>(var->function(particle->getDaughter(j)));
918 if (std::isnan(iValue))
continue;
919 if (std::isnan(max)) max = iValue;
920 if (iValue > max) max = iValue;
922 }
else if (std::holds_alternative<int>(var->function(particle->getDaughter(0))))
924 for (
unsigned j = 0; j < particle->getNDaughters(); ++j) {
925 int iValue = std::get<int>(var->function(particle->getDaughter(j)));
926 if (std::isnan(max)) max = iValue;
927 if (iValue > max) max = iValue;
934 B2FATAL(
"Wrong number of arguments for meta function daughterHighest");
940 if (arguments.size() == 3) {
941 auto func = [arguments](
const Particle * particle) ->
double {
942 if (particle ==
nullptr)
944 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
945 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
946 auto variablename = arguments[2];
947 if (dau_i ==
nullptr || dau_j ==
nullptr)
949 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
953 auto result_j = var->function(dau_j);
954 auto result_i = var->function(dau_i);
956 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
958 diff = std::get<double>(result_j) - std::get<double>(result_i);
959 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
961 diff = std::get<int>(result_j) - std::get<int>(result_i);
964 throw std::runtime_error(
"Bad variant access");
966 if (variablename ==
"phi" or variablename ==
"clusterPhi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)"))
967 or std::regex_match(variablename, std::regex(
"use.*Frame\\(clusterPhi\\)")))
969 if (fabs(diff) > M_PI) {
971 diff = diff - 2 * M_PI;
973 diff = 2 * M_PI + diff;
981 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOf");
987 if (arguments.size() == 3) {
988 auto func = [arguments](
const Particle * particle) ->
double {
989 if (particle ==
nullptr)
991 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
992 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
993 auto variablename = arguments[2];
994 if (dau_i ==
nullptr || dau_j ==
nullptr)
996 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
999 const MCParticle* iMcDaughter = dau_i->getMCParticle();
1000 const MCParticle* jMcDaughter = dau_j->getMCParticle();
1001 if (iMcDaughter ==
nullptr || jMcDaughter ==
nullptr)
1003 Particle iTmpPart(iMcDaughter);
1004 Particle jTmpPart(jMcDaughter);
1006 auto result_j = var->function(&jTmpPart);
1007 auto result_i = var->function(&iTmpPart);
1009 if (std::holds_alternative<double>(result_j) && std::holds_alternative<double>(result_i))
1011 diff = std::get<double>(result_j) - std::get<double>(result_i);
1012 }
else if (std::holds_alternative<int>(result_j) && std::holds_alternative<int>(result_i))
1014 diff = std::get<int>(result_j) - std::get<int>(result_i);
1017 throw std::runtime_error(
"Bad variant access");
1019 if (variablename ==
"phi" or std::regex_match(variablename, std::regex(
"use.*Frame\\(phi\\)")))
1021 if (fabs(diff) > M_PI) {
1023 diff = diff - 2 * M_PI;
1025 diff = 2 * M_PI + diff;
1033 B2FATAL(
"Wrong number of arguments for meta function mcDaughterDiffOf");
1039 if (arguments.size() == 5) {
1045 }
catch (std::invalid_argument&) {
1046 B2FATAL(
"First four arguments of grandDaughterDiffOf meta function must be integers!");
1048 std::vector<std::string> new_arguments;
1049 new_arguments.push_back(std::string(arguments[0] +
":" + arguments[2]));
1050 new_arguments.push_back(std::string(arguments[1] +
":" + arguments[3]));
1051 new_arguments.push_back(arguments[4]);
1052 return daughterDiffOf(new_arguments);
1054 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOf");
1060 if (arguments.size() == 3) {
1061 auto func = [arguments](
const Particle * particle) ->
double {
1062 if (particle ==
nullptr)
1064 const Particle* dau_i = particle->getParticleFromGeneralizedIndexString(arguments[0]);
1065 const Particle* dau_j = particle->getParticleFromGeneralizedIndexString(arguments[1]);
1066 if (!(dau_i && dau_j))
1068 B2ERROR(
"One of the first two arguments doesn't specify a valid (grand-)daughter!");
1072 double iValue, jValue;
1073 if (std::holds_alternative<double>(var->function(dau_j)))
1075 iValue = std::get<double>(var->function(dau_i));
1076 jValue = std::get<double>(var->function(dau_j));
1077 }
else if (std::holds_alternative<int>(var->function(dau_j)))
1079 iValue = std::get<int>(var->function(dau_i));
1080 jValue = std::get<int>(var->function(dau_j));
1082 return (jValue - iValue) / (jValue + iValue);
1086 B2FATAL(
"Wrong number of arguments for meta function daughterNormDiffOf");
1092 if (arguments.size() == 2) {
1093 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1094 std::string variableName = arguments[1];
1095 auto func = [daughterFunction, variableName](
const Particle * particle) ->
double {
1096 if (particle ==
nullptr)
1098 int daughterNumber = std::get<int>(daughterFunction(particle));
1099 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1102 auto result_mother = var->function(particle);
1103 auto result_daughter = var->function(particle->getDaughter(daughterNumber));
1105 if (std::holds_alternative<double>(result_mother) && std::holds_alternative<double>(result_daughter))
1107 diff = std::get<double>(result_mother) - std::get<double>(result_daughter);
1108 }
else if (std::holds_alternative<int>(result_mother) && std::holds_alternative<int>(result_daughter))
1110 diff = std::get<int>(result_mother) - std::get<int>(result_daughter);
1113 throw std::runtime_error(
"Bad variant access");
1116 if (variableName ==
"phi" or variableName ==
"useCMSFrame(phi)")
1118 if (fabs(diff) > M_PI) {
1120 diff = diff - 2 * M_PI;
1122 diff = 2 * M_PI + diff;
1130 B2FATAL(
"Wrong number of arguments for meta function daughterMotherDiffOf");
1136 if (arguments.size() == 2) {
1137 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1139 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
1140 if (particle ==
nullptr)
1142 int daughterNumber = std::get<int>(daughterFunction(particle));
1143 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1145 double daughterValue = 0.0, motherValue = 0.0;
1146 if (std::holds_alternative<double>(var->function(particle)))
1148 daughterValue = std::get<double>(var->function(particle->getDaughter(daughterNumber)));
1149 motherValue = std::get<double>(var->function(particle));
1150 }
else if (std::holds_alternative<int>(var->function(particle)))
1152 daughterValue = std::get<int>(var->function(particle->getDaughter(daughterNumber)));
1153 motherValue = std::get<int>(var->function(particle));
1155 return (motherValue - daughterValue) / (motherValue + daughterValue);
1159 B2FATAL(
"Wrong number of arguments for meta function daughterMotherNormDiffOf");
1165 if (arguments.size() >= 1) {
1167 auto func = [arguments](
const Particle * particle) ->
double {
1168 if (particle ==
nullptr)
1173 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1174 for (
auto& generalizedIndex : arguments)
1176 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1177 if (dauPart) pSum += frame.getMomentum(dauPart);
1179 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1185 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
1186 ROOT::Math::PxPyPzEVector pRecoil = frame.getMomentum(pIN - particle->get4Vector());
1188 return ROOT::Math::VectorUtil::Angle(pRecoil, pSum);
1192 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndRecoil");
1196 Manager::FunctionPtr angleBetweenDaughterAndMissingMomentum(
const std::vector<std::string>& arguments)
1198 if (arguments.size() >= 1) {
1199 auto func = [arguments](
const Particle * particle) ->
double {
1200 if (particle ==
nullptr)
1203 StoreObjPtr<EventKinematics> evtShape;
1206 B2WARNING(
"Cannot find missing momentum information, did you forget to run EventKinematicsModule?");
1209 ROOT::Math::XYZVector missingMomentumCMS = evtShape->getMissingMomentumCMS();
1210 ROOT::Math::PxPyPzEVector missingTotalMomentumCMS(missingMomentumCMS.X(),
1211 missingMomentumCMS.Y(),
1212 missingMomentumCMS.Z(),
1213 evtShape->getMissingEnergyCMS());
1215 ROOT::Math::PxPyPzEVector missingTotalMomentumLab = T.rotateCmsToLab() * missingTotalMomentumCMS;
1218 ROOT::Math::PxPyPzEVector pMiss = frame.getMomentum(missingTotalMomentumLab);
1220 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
1221 for (
auto& generalizedIndex : arguments)
1223 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1224 if (dauPart) pSum += frame.getMomentum(dauPart);
1226 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1231 return ROOT::Math::VectorUtil::Angle(pMiss, pSum);
1235 B2FATAL(
"Wrong number of arguments for meta function angleBetweenDaughterAndMissingMomentum");
1241 if (arguments.size() == 2 || arguments.size() == 3) {
1243 auto func = [arguments](
const Particle * particle) ->
double {
1244 if (particle ==
nullptr)
1247 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1251 for (
auto& generalizedIndex : arguments)
1253 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1255 pDaus.push_back(frame.getMomentum(dauPart));
1257 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1263 if (pDaus.size() == 2)
1264 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1266 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1270 B2FATAL(
"Wrong number of arguments for meta function daughterAngle");
1274 double grandDaughterDecayAngle(
const Particle* particle,
const std::vector<double>& arguments)
1276 if (arguments.size() == 2) {
1281 int daughterIndex = std::lround(arguments[0]);
1282 if (daughterIndex >=
int(particle->getNDaughters()))
1284 const Particle* dau = particle->getDaughter(daughterIndex);
1286 int grandDaughterIndex = std::lround(arguments[1]);
1287 if (grandDaughterIndex >=
int(dau->getNDaughters()))
1290 ROOT::Math::XYZVector boost = dau->get4Vector().BoostToCM();
1292 ROOT::Math::PxPyPzEVector motherMomentum = - particle->get4Vector();
1293 motherMomentum = ROOT::Math::Boost(boost) * motherMomentum;
1295 ROOT::Math::PxPyPzEVector grandDaughterMomentum = dau->getDaughter(grandDaughterIndex)->get4Vector();
1296 grandDaughterMomentum = ROOT::Math::Boost(boost) * grandDaughterMomentum;
1298 return ROOT::Math::VectorUtil::Angle(motherMomentum, grandDaughterMomentum);
1301 B2FATAL(
"The variable grandDaughterDecayAngle needs exactly two integers as arguments!");
1307 if (arguments.size() == 2 || arguments.size() == 3) {
1309 auto func = [arguments](
const Particle * particle) ->
double {
1310 if (particle ==
nullptr)
1313 std::vector<ROOT::Math::PxPyPzEVector> pDaus;
1317 if (particle->getParticleSource() == Particle::EParticleSourceObject::c_MCParticle)
1319 for (
auto& generalizedIndex : arguments) {
1320 const MCParticle* mcPart = particle->getMCParticle();
1321 if (mcPart ==
nullptr)
1323 const MCParticle* dauMcPart = mcPart->getParticleFromGeneralizedIndexString(generalizedIndex);
1324 if (dauMcPart ==
nullptr)
1327 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1331 for (
auto& generalizedIndex : arguments) {
1332 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1333 if (dauPart ==
nullptr)
1336 const MCParticle* dauMcPart = dauPart->getMCParticle();
1337 if (dauMcPart ==
nullptr)
1340 pDaus.push_back(frame.getMomentum(dauMcPart->get4Vector()));
1345 if (pDaus.size() == 2)
1346 return ROOT::Math::VectorUtil::Angle(pDaus[0], pDaus[1]);
1348 return ROOT::Math::VectorUtil::Angle(pDaus[2], pDaus[0] + pDaus[1]);
1352 B2FATAL(
"Wrong number of arguments for meta function mcDaughterAngle");
1356 double daughterClusterAngleInBetween(
const Particle* particle,
const std::vector<double>& daughterIndices)
1358 if (daughterIndices.size() == 2) {
1359 int daughterIndexi = std::lround(daughterIndices[0]);
1360 int daughterIndexj = std::lround(daughterIndices[1]);
1361 if (std::max(daughterIndexi, daughterIndexj) >=
int(particle->getNDaughters())) {
1364 const ECLCluster* clusteri = particle->getDaughter(daughterIndexi)->getECLCluster();
1365 const ECLCluster* clusterj = particle->getDaughter(daughterIndexj)->getECLCluster();
1366 if (clusteri and clusterj) {
1370 ClusterUtils clusutils;
1371 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1372 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1373 return ROOT::Math::VectorUtil::Angle(pi, pj);
1377 }
else if (daughterIndices.size() == 3) {
1378 int daughterIndexi = std::lround(daughterIndices[0]);
1379 int daughterIndexj = std::lround(daughterIndices[1]);
1380 int daughterIndexk = std::lround(daughterIndices[2]);
1381 if (std::max(std::max(daughterIndexi, daughterIndexj), daughterIndexk) >=
int(particle->getNDaughters())) {
1384 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1385 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1386 const ECLCluster* clusterk = (particle->getDaughter(daughterIndices[2]))->getECLCluster();
1387 if (clusteri and clusterj and clusterk) {
1392 ClusterUtils clusutils;
1393 ROOT::Math::PxPyPzEVector pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit));
1394 ROOT::Math::PxPyPzEVector pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit));
1395 ROOT::Math::PxPyPzEVector pk = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterk, clusterkBit));
1396 return ROOT::Math::VectorUtil::Angle(pk, pi + pj);
1401 B2FATAL(
"Wrong number of arguments for daughterClusterAngleInBetween!");
1407 if (arguments.size() > 1) {
1408 auto func = [arguments](
const Particle * particle) ->
double {
1410 ROOT::Math::PxPyPzEVector pSum;
1412 for (
auto& generalizedIndex : arguments)
1414 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1416 pSum += frame.getMomentum(dauPart);
1425 B2FATAL(
"Wrong number of arguments for meta function daughterInvM. At least two integers are needed.");
1431 if (arguments.size() == 2) {
1436 }
catch (std::invalid_argument&) {
1437 B2FATAL(
"Second argument of modulo meta function must be integer!");
1439 auto func = [var, divideBy](
const Particle * particle) ->
int {
1440 auto var_result = var->function(particle);
1441 if (std::holds_alternative<double>(var_result))
1443 return int(std::get<double>(var_result)) % divideBy;
1444 }
else if (std::holds_alternative<int>(var_result))
1446 return std::get<int>(var_result) % divideBy;
1447 }
else if (std::holds_alternative<bool>(var_result))
1449 return int(std::get<bool>(var_result)) % divideBy;
1454 B2FATAL(
"Wrong number of arguments for meta function modulo");
1460 if (arguments.size() == 1) {
1463 auto func = [var](
const Particle * particle) ->
bool {
return std::isnan(std::get<double>(var->function(particle))); };
1466 B2FATAL(
"Wrong number of arguments for meta function isNAN");
1472 if (arguments.size() == 2) {
1474 double defaultOutput;
1477 }
catch (std::invalid_argument&) {
1478 B2FATAL(
"The second argument of ifNANgiveX meta function must be a number!");
1480 auto func = [var, defaultOutput](
const Particle * particle) ->
double {
1481 double output = std::get<double>(var->function(particle));
1482 if (std::isnan(output))
return defaultOutput;
1487 B2FATAL(
"Wrong number of arguments for meta function ifNANgiveX");
1493 if (arguments.size() == 1) {
1496 auto func = [var](
const Particle * particle) ->
bool {
return std::isinf(std::get<double>(var->function(particle))); };
1499 B2FATAL(
"Wrong number of arguments for meta function isInfinity");
1505 if (arguments.size() >= 2) {
1511 for (
size_t i = 1; i < arguments.size(); ++i) {
1514 }
catch (std::invalid_argument&) {
1515 B2FATAL(
"The input flags to meta function unmask() should be integer!");
1521 auto func = [var, finalMask](
const Particle * particle) ->
double {
1523 auto var_result = var->function(particle);
1524 if (std::holds_alternative<double>(var_result))
1527 if (std::isnan(std::get<double>(var_result))) {
1530 value = int(std::get<double>(var_result));
1531 }
else if (std::holds_alternative<int>(var_result))
1533 value = std::get<int>(var_result);
1537 value &= (~finalMask);
1544 B2FATAL(
"Meta function unmask needs at least two arguments!");
1550 if (arguments.size() == 3) {
1552 std::string cutString = arguments[0];
1558 auto func = [cut, variableIfTrue, variableIfFalse](
const Particle * particle) ->
double {
1559 if (particle ==
nullptr)
1561 if (cut->check(particle))
1563 auto var_result = variableIfTrue->function(particle);
1564 if (std::holds_alternative<double>(var_result)) {
1565 return std::get<double>(var_result);
1566 }
else if (std::holds_alternative<int>(var_result)) {
1567 return std::get<int>(var_result);
1568 }
else if (std::holds_alternative<bool>(var_result)) {
1569 return std::get<bool>(var_result);
1573 auto var_result = variableIfFalse->function(particle);
1574 if (std::holds_alternative<double>(var_result)) {
1575 return std::get<double>(var_result);
1576 }
else if (std::holds_alternative<int>(var_result)) {
1577 return std::get<int>(var_result);
1578 }
else if (std::holds_alternative<bool>(var_result)) {
1579 return std::get<bool>(var_result);
1586 B2FATAL(
"Wrong number of arguments for meta function conditionalVariableSelector");
1592 if (arguments.size() > 0) {
1593 std::vector<const Variable::Manager::Var*> variables;
1594 for (
auto& argument : arguments)
1597 auto func = [variables, arguments](
const Particle * particle) ->
double {
1598 double pValueProduct = 1.;
1599 for (
auto variable : variables)
1601 double pValue = std::get<double>(variable->function(particle));
1605 pValueProduct *= pValue;
1607 double pValueSum = 1.;
1608 double factorial = 1.;
1609 for (
unsigned int i = 1; i < arguments.size(); ++i)
1612 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1614 return pValueProduct * pValueSum;
1618 B2FATAL(
"Wrong number of arguments for meta function pValueCombination");
1624 if (arguments.size() == 1) {
1626 auto func = [var](
const Particle * particle) ->
double {
1627 double pValueProduct = 1.;
1628 if (particle->getNDaughters() == 0)
1633 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
1635 double pValue = std::get<double>(var->function(particle->getDaughter(j)));
1636 if (pValue < 0)
return -1;
1637 else pValueProduct *= pValue;
1640 double pValueSum = 1.;
1641 double factorial = 1.;
1642 for (
unsigned int i = 1; i < particle->getNDaughters(); ++i)
1645 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1647 return pValueProduct * pValueSum;
1651 B2FATAL(
"Wrong number of arguments for meta function pValueCombinationOfDaughters");
1657 if (arguments.size() == 1) {
1659 auto func = [var](
const Particle * particle) ->
double {
1660 auto var_result = var->function(particle);
1661 if (std::holds_alternative<double>(var_result))
1663 return std::abs(std::get<double>(var_result));
1664 }
else if (std::holds_alternative<int>(var_result))
1666 return std::abs(std::get<int>(var_result));
1671 B2FATAL(
"Wrong number of arguments for meta function abs");
1677 if (arguments.size() == 2) {
1682 B2FATAL(
"One or both of the used variables doesn't exist!");
1684 auto func = [var1, var2](
const Particle * particle) ->
double {
1686 auto var_result1 = var1->function(particle);
1687 auto var_result2 = var2->function(particle);
1688 if (std::holds_alternative<double>(var_result1))
1690 val1 = std::get<double>(var_result1);
1691 }
else if (std::holds_alternative<int>(var_result1))
1693 val1 = std::get<int>(var_result1);
1694 }
else if (std::holds_alternative<bool>(var_result1))
1696 val1 = std::get<bool>(var_result1);
1699 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1701 if (std::holds_alternative<double>(var_result2))
1703 val2 = std::get<double>(var_result2);
1704 }
else if (std::holds_alternative<int>(var_result2))
1706 val2 = std::get<int>(var_result2);
1707 }
else if (std::holds_alternative<bool>(var_result2))
1709 val2 = std::get<bool>(var_result2);
1712 B2FATAL(
"A variable in meta function max holds no double, int or bool values");
1714 return std::max(val1, val2);
1718 B2FATAL(
"Wrong number of arguments for meta function max");
1724 if (arguments.size() == 2) {
1729 B2FATAL(
"One or both of the used variables doesn't exist!");
1731 auto func = [var1, var2](
const Particle * particle) ->
double {
1733 auto var_result1 = var1->function(particle);
1734 auto var_result2 = var2->function(particle);
1735 if (std::holds_alternative<double>(var_result1))
1737 val1 = std::get<double>(var_result1);
1738 }
else if (std::holds_alternative<int>(var_result1))
1740 val1 = std::get<int>(var_result1);
1741 }
else if (std::holds_alternative<bool>(var_result1))
1743 val1 = std::get<bool>(var_result1);
1746 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1748 if (std::holds_alternative<double>(var_result2))
1750 val2 = std::get<double>(var_result2);
1751 }
else if (std::holds_alternative<int>(var_result2))
1753 val2 = std::get<int>(var_result2);
1754 }
else if (std::holds_alternative<bool>(var_result2))
1756 val2 = std::get<bool>(var_result2);
1759 B2FATAL(
"A variable in meta function min holds no double, int or bool values");
1761 return std::min(val1, val2);
1765 B2FATAL(
"Wrong number of arguments for meta function min");
1771 if (arguments.size() == 1) {
1773 auto func = [var](
const Particle * particle) ->
double {
1774 auto var_result = var->function(particle);
1775 if (std::holds_alternative<double>(var_result))
1776 return std::sin(std::get<double>(var_result));
1777 else if (std::holds_alternative<int>(var_result))
1778 return std::sin(std::get<int>(var_result));
1783 B2FATAL(
"Wrong number of arguments for meta function sin");
1789 if (arguments.size() == 1) {
1791 auto func = [var](
const Particle * particle) ->
double {
1792 auto var_result = var->function(particle);
1793 if (std::holds_alternative<double>(var_result))
1794 return std::asin(std::get<double>(var_result));
1795 else if (std::holds_alternative<int>(var_result))
1796 return std::asin(std::get<int>(var_result));
1801 B2FATAL(
"Wrong number of arguments for meta function asin");
1807 if (arguments.size() == 1) {
1809 auto func = [var](
const Particle * particle) ->
double {
1810 auto var_result = var->function(particle);
1811 if (std::holds_alternative<double>(var_result))
1812 return std::cos(std::get<double>(var_result));
1813 else if (std::holds_alternative<int>(var_result))
1814 return std::cos(std::get<int>(var_result));
1819 B2FATAL(
"Wrong number of arguments for meta function cos");
1825 if (arguments.size() == 1) {
1827 auto func = [var](
const Particle * particle) ->
double {
1828 auto var_result = var->function(particle);
1829 if (std::holds_alternative<double>(var_result))
1830 return std::acos(std::get<double>(var_result));
1831 else if (std::holds_alternative<int>(var_result))
1832 return std::acos(std::get<int>(var_result));
1837 B2FATAL(
"Wrong number of arguments for meta function acos");
1843 if (arguments.size() == 1) {
1845 auto func = [var](
const Particle * particle) ->
double {
return std::tan(std::get<double>(var->function(particle))); };
1848 B2FATAL(
"Wrong number of arguments for meta function tan");
1854 if (arguments.size() == 1) {
1856 auto func = [var](
const Particle * particle) ->
double {
return std::atan(std::get<double>(var->function(particle))); };
1859 B2FATAL(
"Wrong number of arguments for meta function atan");
1865 if (arguments.size() == 2) {
1868 auto func = [varY, varX](
const Particle * particle) ->
double {
1869 double y = std::get<double>(varY->function(particle));
1870 double x = std::get<double>(varX->function(particle));
1871 return std::atan2(y, x);
1875 B2FATAL(
"Wrong number of arguments for meta function atan2");
1881 if (arguments.size() == 1) {
1883 auto func = [var](
const Particle * particle) ->
double {
1884 auto var_result = var->function(particle);
1885 if (std::holds_alternative<double>(var_result))
1886 return std::exp(std::get<double>(var_result));
1887 else if (std::holds_alternative<int>(var_result))
1888 return std::exp(std::get<int>(var_result));
1893 B2FATAL(
"Wrong number of arguments for meta function exp");
1899 if (arguments.size() == 1) {
1901 auto func = [var](
const Particle * particle) ->
double {
1902 auto var_result = var->function(particle);
1903 if (std::holds_alternative<double>(var_result))
1904 return std::log(std::get<double>(var_result));
1905 else if (std::holds_alternative<int>(var_result))
1906 return std::log(std::get<int>(var_result));
1911 B2FATAL(
"Wrong number of arguments for meta function log");
1917 if (arguments.size() == 1) {
1919 auto func = [var](
const Particle * particle) ->
double {
1920 auto var_result = var->function(particle);
1921 if (std::holds_alternative<double>(var_result))
1922 return std::log10(std::get<double>(var_result));
1923 else if (std::holds_alternative<int>(var_result))
1924 return std::log10(std::get<int>(var_result));
1929 B2FATAL(
"Wrong number of arguments for meta function log10");
1935 if (arguments.size() == 1) {
1937 auto func = [var](
const Particle * particle) ->
double {
1938 if (particle ==
nullptr)
1941 StoreArray<Particle> particles;
1942 if (!particle->hasExtraInfo(
"original_index"))
1945 auto originalParticle = particles[particle->getExtraInfo(
"original_index")];
1946 if (!originalParticle)
1948 auto var_result = var->function(originalParticle);
1949 if (std::holds_alternative<double>(var_result))
1951 return std::get<double>(var_result);
1952 }
else if (std::holds_alternative<int>(var_result))
1954 return std::get<int>(var_result);
1955 }
else if (std::holds_alternative<bool>(var_result))
1957 return std::get<bool>(var_result);
1962 B2FATAL(
"Wrong number of arguments for meta function originalParticle");
1968 if (arguments.size() == 2) {
1969 auto daughterFunction = convertToDaughterIndex({arguments[0]});
1971 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
1972 if (particle ==
nullptr)
1974 int daughterNumber = std::get<int>(daughterFunction(particle));
1975 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
1977 auto var_result = var->function(particle->getDaughter(daughterNumber));
1978 if (std::holds_alternative<double>(var_result))
1980 return std::get<double>(var_result);
1981 }
else if (std::holds_alternative<int>(var_result))
1983 return std::get<int>(var_result);
1984 }
else if (std::holds_alternative<bool>(var_result))
1986 return std::get<bool>(var_result);
1991 B2FATAL(
"Wrong number of arguments for meta function daughter");
1997 if (arguments.size() == 2) {
1998 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2000 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2001 if (particle ==
nullptr)
2003 int daughterNumber = std::get<int>(daughterFunction(particle));
2004 if (daughterNumber >=
int(particle->getNDaughters()) or daughterNumber < 0)
2008 StoreArray<Particle> particles;
2009 if (!particle->getDaughter(daughterNumber)->hasExtraInfo(
"original_index"))
2011 auto originalDaughter = particles[particle->getDaughter(daughterNumber)->getExtraInfo(
"original_index")];
2012 if (!originalDaughter)
2015 auto var_result = var->function(originalDaughter);
2016 if (std::holds_alternative<double>(var_result)) {
2017 return std::get<double>(var_result);
2018 }
else if (std::holds_alternative<int>(var_result)) {
2019 return std::get<int>(var_result);
2020 }
else if (std::holds_alternative<bool>(var_result)) {
2021 return std::get<bool>(var_result);
2027 B2FATAL(
"Wrong number of arguments for meta function daughter");
2033 if (arguments.size() == 1) {
2034 std::string daughterString = arguments[0];
2035 auto func = [daughterString](
const Particle * particle) ->
int {
2036 if (particle ==
nullptr)
2038 int daughterNumber = 0;
2042 }
catch (std::invalid_argument&)
2044 auto daughterFunction = convertToInt({daughterString,
"-1"});
2045 auto daughterVarResult = daughterFunction(particle);
2046 daughterNumber = std::get<int>(daughterVarResult);
2048 return daughterNumber;
2052 B2FATAL(
"Wrong number of arguments for meta function convertToDaughterIndex");
2058 if (arguments.size() == 2) {
2059 auto daughterFunction = convertToDaughterIndex({arguments[0]});
2061 auto func = [var, daughterFunction](
const Particle * particle) ->
double {
2062 if (particle ==
nullptr)
2064 if (particle->getMCParticle())
2066 int daughterNumber = std::get<int>(daughterFunction(particle));
2067 if (daughterNumber >=
int(particle->getMCParticle()->getNDaughters()) or daughterNumber < 0)
2069 Particle tempParticle = Particle(particle->getMCParticle()->getDaughters().at(daughterNumber));
2070 auto var_result = var->function(&tempParticle);
2071 if (std::holds_alternative<double>(var_result)) {
2072 return std::get<double>(var_result);
2073 }
else if (std::holds_alternative<int>(var_result)) {
2074 return std::get<int>(var_result);
2075 }
else if (std::holds_alternative<bool>(var_result)) {
2076 return std::get<bool>(var_result);
2087 B2FATAL(
"Wrong number of arguments for meta function mcDaughter");
2093 if (arguments.size() == 1) {
2095 auto func = [var](
const Particle * particle) ->
double {
2096 if (particle ==
nullptr)
2098 if (particle->getMCParticle())
2100 if (particle->getMCParticle()->getMother() ==
nullptr) {
2103 Particle tempParticle = Particle(particle->getMCParticle()->getMother());
2104 auto var_result = var->function(&tempParticle);
2105 if (std::holds_alternative<double>(var_result)) {
2106 return std::get<double>(var_result);
2107 }
else if (std::holds_alternative<int>(var_result)) {
2108 return std::get<int>(var_result);
2109 }
else if (std::holds_alternative<bool>(var_result)) {
2110 return std::get<bool>(var_result);
2119 B2FATAL(
"Wrong number of arguments for meta function mcMother");
2125 if (arguments.size() == 2) {
2126 std::string indexString = arguments[0];
2129 auto func = [var, indexString](
const Particle * particle) ->
double {
2131 int particleNumber = 0;
2135 }
catch (std::invalid_argument&)
2137 auto indexFunction = convertToInt({indexString,
"-1"});
2138 auto indexVarResult = indexFunction(particle);
2139 particleNumber = std::get<int>(indexVarResult);
2142 StoreArray<MCParticle> mcParticles(
"MCParticles");
2143 if (particleNumber >= mcParticles.getEntries())
2148 MCParticle* mcParticle = mcParticles[particleNumber];
2149 Particle part = Particle(mcParticle);
2150 auto var_result = var->function(&part);
2151 if (std::holds_alternative<double>(var_result))
2153 return std::get<double>(var_result);
2154 }
else if (std::holds_alternative<int>(var_result))
2156 return std::get<int>(var_result);
2157 }
else if (std::holds_alternative<bool>(var_result))
2159 return std::get<bool>(var_result);
2164 B2FATAL(
"Wrong number of arguments for meta function genParticle");
2170 if (arguments.size() == 1) {
2173 auto func = [var](
const Particle*) ->
double {
2174 StoreArray<MCParticle> mcParticles(
"MCParticles");
2175 if (mcParticles.getEntries() == 0)
2180 MCParticle* mcUpsilon4S = mcParticles[0];
2181 if (mcUpsilon4S->isInitial()) mcUpsilon4S = mcParticles[2];
2182 if (mcUpsilon4S->getPDG() != 300553)
2187 Particle upsilon4S = Particle(mcUpsilon4S);
2188 auto var_result = var->function(&upsilon4S);
2189 if (std::holds_alternative<double>(var_result))
2191 return std::get<double>(var_result);
2192 }
else if (std::holds_alternative<int>(var_result))
2194 return std::get<int>(var_result);
2195 }
else if (std::holds_alternative<bool>(var_result))
2197 return std::get<bool>(var_result);
2202 B2FATAL(
"Wrong number of arguments for meta function genUpsilon4S");
2208 if (arguments.size() == 4) {
2209 std::string listName = arguments[0];
2210 std::string rankedVariableName = arguments[1];
2211 std::string returnVariableName = arguments[2];
2212 std::string extraInfoName = rankedVariableName +
"_rank";
2216 }
catch (std::invalid_argument&) {
2217 B2ERROR(
"3rd argument of getVariableByRank meta function (Rank) must be an integer!");
2222 auto func = [var, rank, extraInfoName, listName](
const Particle*)->
double {
2223 StoreObjPtr<ParticleList> list(listName);
2225 const unsigned int numParticles = list->getListSize();
2226 for (
unsigned int i = 0; i < numParticles; i++)
2228 const Particle* p = list->getParticle(i);
2229 if (p->getExtraInfo(extraInfoName) == rank) {
2230 auto var_result = var->function(p);
2231 if (std::holds_alternative<double>(var_result)) {
2232 return std::get<double>(var_result);
2233 }
else if (std::holds_alternative<int>(var_result)) {
2234 return std::get<int>(var_result);
2235 }
else if (std::holds_alternative<bool>(var_result)) {
2236 return std::get<bool>(var_result);
2241 return std::numeric_limits<double>::signaling_NaN();
2245 B2FATAL(
"Wrong number of arguments for meta function getVariableByRank");
2251 if (arguments.size() == 1 or arguments.size() == 2) {
2253 std::string listName = arguments[0];
2254 std::string cutString =
"";
2256 if (arguments.size() == 2) {
2257 cutString = arguments[1];
2262 auto func = [listName, cut](
const Particle*) ->
int {
2264 StoreObjPtr<ParticleList> list(listName);
2266 for (
unsigned int i = 0; i < list->getListSize(); i++)
2268 const Particle* particle = list->getParticle(i);
2269 if (cut->check(particle)) {
2277 B2FATAL(
"Wrong number of arguments for meta function countInList");
2283 if (arguments.size() == 2 or arguments.size() == 3) {
2285 std::string roeListName = arguments[0];
2286 std::string cutString = arguments[1];
2288 if (arguments.size() == 2) {
2289 B2INFO(
"Use pdgCode of electron as default in meta variable veto, other arguments: " << roeListName <<
", " << cutString);
2293 }
catch (std::invalid_argument&) {
2294 B2FATAL(
"Third argument of veto meta function must be integer!");
2301 auto func = [roeListName, cut, pdgCode, flavourType](
const Particle * particle) ->
bool {
2302 StoreObjPtr<ParticleList> roeList(roeListName);
2303 ROOT::Math::PxPyPzEVector vec = particle->get4Vector();
2304 for (
unsigned int i = 0; i < roeList->getListSize(); i++)
2306 const Particle* roeParticle = roeList->getParticle(i);
2307 if (not particle->overlapsWith(roeParticle)) {
2308 ROOT::Math::PxPyPzEVector tempCombination = roeParticle->get4Vector() + vec;
2309 std::vector<int> indices = { particle->getArrayIndex(), roeParticle->getArrayIndex() };
2310 Particle tempParticle = Particle(tempCombination, pdgCode, flavourType, indices, particle->getArrayPointer());
2311 if (cut->check(&tempParticle)) {
2320 B2FATAL(
"Wrong number of arguments for meta function veto");
2326 if (arguments.size() == 1) {
2327 std::string cutString = arguments[0];
2329 auto func = [cut](
const Particle * particle) ->
int {
2331 for (
auto& daughter : particle->getDaughters())
2333 if (cut->check(daughter))
2340 B2FATAL(
"Wrong number of arguments for meta function countDaughters");
2346 if (arguments.size() == 1) {
2347 std::string cutString = arguments[0];
2349 auto func = [cut](
const Particle * particle) ->
int {
2351 std::vector<const Particle*> fspDaughters;
2352 particle->fillFSPDaughters(fspDaughters);
2355 for (
auto& daughter : fspDaughters)
2357 if (cut->check(daughter))
2364 B2FATAL(
"Wrong number of arguments for meta function countFSPDaughters");
2370 if (arguments.size() == 1) {
2371 std::string cutString = arguments[0];
2373 auto func = [cut](
const Particle * particle) ->
int {
2375 std::vector<const Particle*> allDaughters;
2376 particle->fillAllDaughters(allDaughters);
2379 for (
auto& daughter : allDaughters)
2381 if (cut->check(daughter))
2388 B2FATAL(
"Wrong number of arguments for meta function countDescendants");
2392 Manager::FunctionPtr numberOfNonOverlappingParticles(
const std::vector<std::string>& arguments)
2395 auto func = [arguments](
const Particle * particle) ->
int {
2397 int _numberOfNonOverlappingParticles = 0;
2398 for (
const auto& listName : arguments)
2400 StoreObjPtr<ParticleList> list(listName);
2401 if (not list.isValid()) {
2402 B2FATAL(
"Invalid list named " << listName <<
" encountered in numberOfNonOverlappingParticles.");
2404 for (
unsigned int i = 0; i < list->getListSize(); i++) {
2405 const Particle* p = list->getParticle(i);
2406 if (not particle->overlapsWith(p)) {
2407 _numberOfNonOverlappingParticles++;
2411 return _numberOfNonOverlappingParticles;
2418 void appendDaughtersRecursive(Particle* mother, StoreArray<Particle>& container)
2421 auto* mcmother = mother->getRelated<MCParticle>();
2426 for (
auto* mcdaughter : mcmother->getDaughters()) {
2428 Particle tmp_daughter(mcdaughter);
2429 Particle* new_daughter = container.appendNew(tmp_daughter);
2430 new_daughter->addRelationTo(mcdaughter);
2431 mother->appendDaughter(new_daughter,
false);
2433 if (mcdaughter->getNDaughters() > 0)
2434 appendDaughtersRecursive(new_daughter, container);
2440 if (arguments.size() == 1) {
2442 auto func = [var](
const Particle * particle) ->
double {
2443 const MCParticle* mcp = particle->getMCParticle();
2448 StoreArray<Particle> tempParticles(
"tempParticles");
2449 tempParticles.clear();
2450 Particle tmpPart(mcp);
2451 Particle* newPart = tempParticles.appendNew(tmpPart);
2452 newPart->addRelationTo(mcp);
2454 appendDaughtersRecursive(newPart, tempParticles);
2456 auto var_result = var->function(newPart);
2457 if (std::holds_alternative<double>(var_result))
2459 return std::get<double>(var_result);
2460 }
else if (std::holds_alternative<int>(var_result))
2462 return std::get<int>(var_result);
2463 }
else if (std::holds_alternative<bool>(var_result))
2465 return std::get<bool>(var_result);
2470 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
2476 if (arguments.size() == 1) {
2479 auto func = [var](
const Particle * particle) ->
double {
2481 const ECLCluster* cluster = particle->getECLCluster();
2484 auto mcps = cluster->getRelationsTo<MCParticle>();
2487 std::vector<std::pair<double, int>> weightsAndIndices;
2488 for (
unsigned int i = 0; i < mcps.size(); ++i)
2489 weightsAndIndices.emplace_back(mcps.weight(i), i);
2492 std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
2493 ValueIndexPairSorting::higherPair<
decltype(weightsAndIndices)::value_type>);
2495 const MCParticle* mcp = mcps.object(weightsAndIndices[0].second);
2497 StoreArray<Particle> tempParticles(
"tempParticles");
2498 tempParticles.clear();
2499 Particle tmpPart(mcp);
2500 Particle* newPart = tempParticles.appendNew(tmpPart);
2501 newPart->addRelationTo(mcp);
2503 appendDaughtersRecursive(newPart, tempParticles);
2505 auto var_result = var->function(newPart);
2506 if (std::holds_alternative<double>(var_result))
2508 return std::get<double>(var_result);
2509 }
else if (std::holds_alternative<int>(var_result))
2511 return std::get<int>(var_result);
2512 }
else if (std::holds_alternative<bool>(var_result))
2514 return std::get<bool>(var_result);
2523 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCParticle");
2529 if (arguments.size() == 1) {
2532 auto func = [var](
const Particle * particle) ->
double {
2534 const ECLCluster* cluster = particle->getECLCluster();
2537 auto mcps = cluster->getRelationsTo<MCParticle>();
2540 std::map<int, double> mapMCParticleIndxAndWeight;
2541 getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
2544 if (mapMCParticleIndxAndWeight.size() == 0)
2548 auto maxMap = std::max_element(mapMCParticleIndxAndWeight.begin(), mapMCParticleIndxAndWeight.end(),
2549 [](
const auto & x,
const auto & y) { return x.second < y.second; }
2552 StoreArray<MCParticle> mcparticles;
2553 const MCParticle* mcKlong = mcparticles[maxMap->first];
2555 Particle tmpPart(mcKlong);
2556 auto var_result = var->function(&tmpPart);
2557 if (std::holds_alternative<double>(var_result))
2559 return std::get<double>(var_result);
2560 }
else if (std::holds_alternative<int>(var_result))
2562 return std::get<int>(var_result);
2563 }
else if (std::holds_alternative<bool>(var_result))
2565 return std::get<bool>(var_result);
2574 B2FATAL(
"Wrong number of arguments for meta function clusterBestMatchedMCKlong");
2578 double matchedMCHasPDG(
const Particle* particle,
const std::vector<double>& pdgCode)
2580 if (pdgCode.size() != 1) {
2581 B2FATAL(
"Too many arguments provided to matchedMCHasPDG!");
2583 int inputPDG = std::lround(pdgCode[0]);
2585 const MCParticle* mcp = particle->getMCParticle();
2589 return std::abs(mcp->getPDG()) == inputPDG;
2594 if (arguments.size() == 1) {
2595 std::string listName = arguments[0];
2596 auto func = [listName](
const Particle * particle) ->
double {
2599 StoreObjPtr<ParticleList> listOfParticles(listName);
2601 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2602 double totalEnergy = 0;
2603 int nParticles = listOfParticles->getListSize();
2604 for (
int i = 0; i < nParticles; i++)
2606 const Particle* part = listOfParticles->getParticle(i);
2608 totalEnergy += frame.getMomentum(part).E();
2615 B2FATAL(
"Wrong number of arguments for meta function totalEnergyOfParticlesInList");
2621 if (arguments.size() == 1) {
2622 std::string listName = arguments[0];
2623 auto func = [listName](
const Particle*) ->
double {
2624 StoreObjPtr<ParticleList> listOfParticles(listName);
2626 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPxOfParticlesInList");
2628 int nParticles = listOfParticles->getListSize();
2630 for (
int i = 0; i < nParticles; i++)
2632 const Particle* part = listOfParticles->getParticle(i);
2633 totalPx += frame.getMomentum(part).Px();
2639 B2FATAL(
"Wrong number of arguments for meta function totalPxOfParticlesInList");
2645 if (arguments.size() == 1) {
2646 std::string listName = arguments[0];
2647 auto func = [listName](
const Particle*) ->
double {
2648 StoreObjPtr<ParticleList> listOfParticles(listName);
2650 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPyOfParticlesInList");
2652 int nParticles = listOfParticles->getListSize();
2654 for (
int i = 0; i < nParticles; i++)
2656 const Particle* part = listOfParticles->getParticle(i);
2657 totalPy += frame.getMomentum(part).Py();
2663 B2FATAL(
"Wrong number of arguments for meta function totalPyOfParticlesInList");
2669 if (arguments.size() == 1) {
2670 std::string listName = arguments[0];
2671 auto func = [listName](
const Particle*) ->
double {
2672 StoreObjPtr<ParticleList> listOfParticles(listName);
2674 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPzOfParticlesInList");
2676 int nParticles = listOfParticles->getListSize();
2678 for (
int i = 0; i < nParticles; i++)
2680 const Particle* part = listOfParticles->getParticle(i);
2681 totalPz += frame.getMomentum(part).Pz();
2687 B2FATAL(
"Wrong number of arguments for meta function totalPzOfParticlesInList");
2693 if (arguments.size() > 0) {
2695 auto func = [arguments](
const Particle * particle) ->
double {
2697 ROOT::Math::PxPyPzEVector total4Vector;
2699 std::vector<Particle*> particlePool;
2702 for (
const auto& argument : arguments)
2704 StoreObjPtr <ParticleList> listOfParticles(argument);
2706 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << argument <<
" given to invMassInLists");
2707 int nParticles = listOfParticles->getListSize();
2708 for (
int i = 0; i < nParticles; i++) {
2709 bool overlaps =
false;
2710 Particle* part = listOfParticles->getParticle(i);
2711 for (
auto poolPart : particlePool) {
2712 if (part->overlapsWith(poolPart)) {
2718 total4Vector += part->get4Vector();
2719 particlePool.push_back(part);
2723 double invariantMass = total4Vector.M();
2724 return invariantMass;
2729 B2FATAL(
"Wrong number of arguments for meta function invMassInLists");
2733 Manager::FunctionPtr totalECLEnergyOfParticlesInList(
const std::vector<std::string>& arguments)
2735 if (arguments.size() == 1) {
2736 std::string listName = arguments[0];
2737 auto func = [listName](
const Particle * particle) ->
double {
2740 StoreObjPtr<ParticleList> listOfParticles(listName);
2742 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2743 double totalEnergy = 0;
2744 int nParticles = listOfParticles->getListSize();
2745 for (
int i = 0; i < nParticles; i++)
2747 const Particle* part = listOfParticles->getParticle(i);
2748 const ECLCluster* cluster = part->getECLCluster();
2750 if (cluster !=
nullptr) {
2751 totalEnergy += cluster->getEnergy(clusterHypothesis);
2759 B2FATAL(
"Wrong number of arguments for meta function totalECLEnergyOfParticlesInList");
2765 if (arguments.size() == 1) {
2766 std::string listName = arguments[0];
2767 auto func = [listName](
const Particle*) ->
double {
2768 StoreObjPtr<ParticleList> listOfParticles(listName);
2770 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxPtInList");
2771 int nParticles = listOfParticles->getListSize();
2774 for (
int i = 0; i < nParticles; i++)
2776 const Particle* part = listOfParticles->getParticle(i);
2777 const double Pt = frame.getMomentum(part).Pt();
2778 if (Pt > maxPt) maxPt = Pt;
2784 B2FATAL(
"Wrong number of arguments for meta function maxPtInList");
2788 Manager::FunctionPtr eclClusterTrackMatchedWithCondition(
const std::vector<std::string>& arguments)
2790 if (arguments.size() <= 1) {
2792 std::string cutString;
2793 if (arguments.size() == 1)
2794 cutString = arguments[0];
2796 auto func = [cut](
const Particle * particle) ->
double {
2798 if (particle ==
nullptr)
2801 const ECLCluster* cluster = particle->getECLCluster();
2805 auto tracks = cluster->getRelationsFrom<Track>();
2807 for (
const auto& track : tracks) {
2810 if (cut->check(&trackParticle))
2819 B2FATAL(
"Wrong number of arguments for meta function eclClusterSpecialTrackMatched");
2825 if (arguments.size() == 2) {
2826 std::string listName = arguments[0];
2829 auto func = [listName, var](
const Particle*) ->
double {
2830 StoreObjPtr<ParticleList> listOfParticles(listName);
2832 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to averageValueInList");
2833 int nParticles = listOfParticles->getListSize();
2834 if (nParticles == 0)
2839 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2841 for (
int i = 0; i < nParticles; i++) {
2842 average += std::get<double>(var->function(listOfParticles->getParticle(i))) / nParticles;
2844 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2846 for (
int i = 0; i < nParticles; i++) {
2847 average += std::get<int>(var->function(listOfParticles->getParticle(i))) / nParticles;
2854 B2FATAL(
"Wrong number of arguments for meta function averageValueInList");
2860 if (arguments.size() == 2) {
2861 std::string listName = arguments[0];
2864 auto func = [listName, var](
const Particle*) ->
double {
2865 StoreObjPtr<ParticleList> listOfParticles(listName);
2867 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to medianValueInList");
2868 int nParticles = listOfParticles->getListSize();
2869 if (nParticles == 0)
2873 std::vector<double> valuesInList;
2874 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2876 for (
int i = 0; i < nParticles; i++) {
2877 valuesInList.push_back(std::get<double>(var->function(listOfParticles->getParticle(i))));
2879 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2881 for (
int i = 0; i < nParticles; i++) {
2882 valuesInList.push_back(std::get<int>(var->function(listOfParticles->getParticle(i))));
2885 std::sort(valuesInList.begin(), valuesInList.end());
2886 if (nParticles % 2 != 0)
2888 return valuesInList[nParticles / 2];
2891 return 0.5 * (valuesInList[nParticles / 2] + valuesInList[nParticles / 2 - 1]);
2896 B2FATAL(
"Wrong number of arguments for meta function medianValueInList");
2902 if (arguments.size() == 2) {
2903 std::string listName = arguments[0];
2906 auto func = [listName, var](
const Particle*) ->
double {
2907 StoreObjPtr<ParticleList> listOfParticles(listName);
2909 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to sumValueInList");
2910 int nParticles = listOfParticles->getListSize();
2911 if (nParticles == 0)
2916 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2918 for (
int i = 0; i < nParticles; i++) {
2919 sum += std::get<double>(var->function(listOfParticles->getParticle(i)));
2921 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2923 for (
int i = 0; i < nParticles; i++) {
2924 sum += std::get<int>(var->function(listOfParticles->getParticle(i)));
2931 B2FATAL(
"Wrong number of arguments for meta function sumValueInList");
2937 if (arguments.size() == 2) {
2938 std::string listName = arguments[0];
2941 auto func = [listName, var](
const Particle*) ->
double {
2942 StoreObjPtr<ParticleList> listOfParticles(listName);
2944 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to productValueInList");
2945 int nParticles = listOfParticles->getListSize();
2946 if (nParticles == 0)
2951 if (std::holds_alternative<double>(var->function(listOfParticles->getParticle(0))))
2953 for (
int i = 0; i < nParticles; i++) {
2954 product *= std::get<double>(var->function(listOfParticles->getParticle(i)));
2956 }
else if (std::holds_alternative<int>(var->function(listOfParticles->getParticle(0))))
2958 for (
int i = 0; i < nParticles; i++) {
2959 product *= std::get<int>(var->function(listOfParticles->getParticle(i)));
2966 B2FATAL(
"Wrong number of arguments for meta function productValueInList");
2973 if (arguments.size() != 1)
2974 B2FATAL(
"Wrong number of arguments for meta function angleToClosestInList");
2976 std::string listname = arguments[0];
2978 auto func = [listname](
const Particle * particle) ->
double {
2980 StoreObjPtr<ParticleList> list(listname);
2981 if (not list.isValid())
2982 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToClosestInList");
2985 if (list->getListSize() == 0)
2990 const auto p_this = frame.getMomentum(particle);
2993 double minAngle = 2 * M_PI;
2994 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2996 const Particle* compareme = list->getParticle(i);
2997 const auto p_compare = frame.getMomentum(compareme);
2998 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
2999 if (minAngle > angle) minAngle = angle;
3009 if (arguments.size() != 2)
3010 B2FATAL(
"Wrong number of arguments for meta function closestInList");
3012 std::string listname = arguments[0];
3017 auto func = [listname, var](
const Particle * particle) ->
double {
3019 StoreObjPtr<ParticleList> list(listname);
3020 if (not list.isValid())
3021 B2FATAL(
"Invalid particle list name " << listname <<
" given to closestInList");
3025 const auto p_this = frame.getMomentum(particle);
3028 double minAngle = 2 * M_PI;
3030 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3032 const Particle* compareme = list->getParticle(i);
3033 const auto p_compare = frame.getMomentum(compareme);
3034 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3035 if (minAngle > angle) {
3043 auto var_result = var->function(list->getParticle(iClosest));
3044 if (std::holds_alternative<double>(var_result))
3046 return std::get<double>(var_result);
3047 }
else if (std::holds_alternative<int>(var_result))
3049 return std::get<int>(var_result);
3050 }
else if (std::holds_alternative<bool>(var_result))
3052 return std::get<bool>(var_result);
3061 if (arguments.size() != 1)
3062 B2FATAL(
"Wrong number of arguments for meta function angleToMostB2BInList");
3064 std::string listname = arguments[0];
3066 auto func = [listname](
const Particle * particle) ->
double {
3068 StoreObjPtr<ParticleList> list(listname);
3069 if (not list.isValid())
3070 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToMostB2BInList");
3073 if (list->getListSize() == 0)
3078 const auto p_this = frame.getMomentum(particle);
3082 double maxAngle = 0;
3083 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3085 const Particle* compareme = list->getParticle(i);
3086 const auto p_compare = frame.getMomentum(compareme);
3087 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3088 if (maxAngle < angle) maxAngle = angle;
3098 if (arguments.size() != 1)
3099 B2FATAL(
"Wrong number of arguments for meta function deltaPhiToMostB2BPhiInList");
3101 std::string listname = arguments[0];
3103 auto func = [listname](
const Particle * particle) ->
double {
3105 StoreObjPtr<ParticleList> list(listname);
3106 if (not list.isValid())
3107 B2FATAL(
"Invalid particle list name " << listname <<
" given to deltaPhiToMostB2BPhiInList");
3110 if (list->getListSize() == 0)
3115 const auto phi_this = frame.getMomentum(particle).Phi();
3118 double maxAngle = 0;
3119 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3121 const Particle* compareme = list->getParticle(i);
3122 const auto phi_compare = frame.getMomentum(compareme).Phi();
3123 double angle = std::abs(phi_compare - phi_this);
3124 if (angle > M_PI) {angle = 2 * M_PI - angle;}
3125 if (maxAngle < angle) maxAngle = angle;
3135 if (arguments.size() != 2)
3136 B2FATAL(
"Wrong number of arguments for meta function mostB2BInList");
3138 std::string listname = arguments[0];
3143 auto func = [listname, var](
const Particle * particle) ->
double {
3145 StoreObjPtr<ParticleList> list(listname);
3146 if (not list.isValid())
3147 B2FATAL(
"Invalid particle list name " << listname <<
" given to mostB2BInList");
3151 const auto p_this = frame.getMomentum(particle);
3155 double maxAngle = -1.0;
3157 for (
unsigned int i = 0; i < list->getListSize(); ++i)
3159 const Particle* compareme = list->getParticle(i);
3160 const auto p_compare = frame.getMomentum(compareme);
3161 double angle = ROOT::Math::VectorUtil::Angle(p_compare, p_this);
3162 if (maxAngle < angle) {
3170 auto var_result = var->function(list->getParticle(iMostB2B));
3171 if (std::holds_alternative<double>(var_result))
3173 return std::get<double>(var_result);
3174 }
else if (std::holds_alternative<int>(var_result))
3176 return std::get<int>(var_result);
3177 }
else if (std::holds_alternative<bool>(var_result))
3179 return std::get<bool>(var_result);
3187 if (arguments.size() == 1) {
3188 std::string listName = arguments[0];
3189 auto func = [listName](
const Particle*) ->
double {
3190 StoreObjPtr<ParticleList> listOfParticles(listName);
3192 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxOpeningAngleInList");
3193 int nParticles = listOfParticles->getListSize();
3198 double maxOpeningAngle = -1;
3199 for (
int i = 0; i < nParticles; i++)
3201 ROOT::Math::PxPyPzEVector v1 = frame.getMomentum(listOfParticles->getParticle(i));
3202 for (
int j = i + 1; j < nParticles; j++) {
3203 ROOT::Math::PxPyPzEVector v2 = frame.getMomentum(listOfParticles->getParticle(j));
3204 const double angle = ROOT::Math::VectorUtil::Angle(v1, v2);
3205 if (angle > maxOpeningAngle) maxOpeningAngle = angle;
3208 return maxOpeningAngle;
3212 B2FATAL(
"Wrong number of arguments for meta function maxOpeningAngleInList");
3219 if (arguments.size() >= 2) {
3224 auto func = [var, arguments](
const Particle * particle) ->
double {
3225 if (particle ==
nullptr)
3227 B2WARNING(
"Trying to access a daughter that does not exist. Skipping");
3233 ROOT::Math::PxPyPzEVector pSum(0, 0, 0, 0);
3237 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++)
3239 auto generalizedIndex = arguments[iCoord];
3240 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
3242 pSum += frame.getMomentum(dauPart);
3244 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
3250 Particle sumOfDaughters(pSum, 100);
3252 auto var_result = var->function(&sumOfDaughters);
3254 if (std::holds_alternative<double>(var_result))
3256 return std::get<double>(var_result);
3257 }
else if (std::holds_alternative<int>(var_result))
3259 return std::get<int>(var_result);
3260 }
else if (std::holds_alternative<bool>(var_result))
3262 return std::get<bool>(var_result);
3267 B2FATAL(
"Wrong number of arguments for meta function daughterCombination");
3270 Manager::FunctionPtr useAlternativeDaughterHypothesis(
const std::vector<std::string>& arguments)
3283 if (arguments.size() >= 2) {
3294 std::unordered_map<unsigned int, int> mapOfReplacedDaughters;
3297 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++) {
3298 auto replacedDauString = arguments[iCoord];
3300 std::vector<std::string> indexAndMass;
3301 boost::split(indexAndMass, replacedDauString, boost::is_any_of(
":"));
3304 if (indexAndMass.size() > 2) {
3305 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 "
3306 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3310 if (indexAndMass.size() < 2) {
3311 B2WARNING(
"The string indicating which daughter's mass should be replaced contains only one colon-separated element instead of two. The offending string is "
3312 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
3320 }
catch (std::invalid_argument&) {
3321 B2FATAL(
"Found the string " << indexAndMass[0] <<
"instead of a daughter index.");
3325 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(indexAndMass[1].c_str());
3327 B2WARNING(
"Particle not in evt.pdl file! " << indexAndMass[1]);
3332 int pdgCode = particlePDG->PdgCode();
3333 mapOfReplacedDaughters[dauIndex] = pdgCode;
3337 if (mapOfReplacedDaughters.size() != arguments.size() - 1)
3338 B2FATAL(
"Overlapped daughter's index is detected in the meta-variable useAlternativeDaughterHypothesis");
3346 auto func = [var, mapOfReplacedDaughters](
const Particle * particle) ->
double {
3347 if (particle ==
nullptr)
3349 B2WARNING(
"Trying to access a particle that does not exist. Skipping");
3359 ROOT::Math::PxPyPzMVector pSum(0, 0, 0, 0);
3361 for (
unsigned int iDau = 0; iDau < particle->getNDaughters(); iDau++)
3363 const Particle* dauPart = particle->getDaughter(iDau);
3365 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << iDau);
3369 ROOT::Math::PxPyPzMVector dauMom = ROOT::Math::PxPyPzMVector(frame.getMomentum(dauPart));
3373 pdgCode = mapOfReplacedDaughters.at(iDau);
3374 }
catch (std::out_of_range&) {
3381 double p_x = dauMom.Px();
3382 double p_y = dauMom.Py();
3383 double p_z = dauMom.Pz();
3384 dauMom.SetCoordinates(p_x, p_y, p_z, TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass());
3385 const_cast<Particle*
>(dummy->getDaughter(iDau))->set4VectorDividingByMomentumScaling(ROOT::Math::PxPyPzEVector(dauMom));
3388 const int charge = dummy->getDaughter(iDau)->getCharge();
3389 if (TDatabasePDG::Instance()->GetParticle(pdgCode)->Charge() / 3.0 == charge)
3390 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(pdgCode);
3392 const_cast<Particle*
>(dummy->getDaughter(iDau))->setPDGCode(-1 * pdgCode);
3398 dummy->set4Vector(ROOT::Math::PxPyPzEVector(pSum));
3400 auto var_result = var->function(dummy);
3403 if (std::holds_alternative<double>(var_result))
3405 return std::get<double>(var_result);
3406 }
else if (std::holds_alternative<int>(var_result))
3408 return std::get<int>(var_result);
3409 }
else if (std::holds_alternative<bool>(var_result))
3411 return std::get<bool>(var_result);
3417 B2FATAL(
"Wrong number of arguments for meta function useAlternativeDaughterHypothesis");
3422 if (arguments.size() == 2) {
3424 std::string arg = arguments[0];
3426 TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(arg.c_str());
3428 if (part !=
nullptr) {
3429 pdg_code = std::abs(part->PdgCode());
3433 }
catch (std::exception& e) {}
3436 if (pdg_code == -1) {
3437 B2FATAL(
"Ancestor " + arg +
" is not recognised. Please provide valid PDG code or particle name.");
3440 auto func = [pdg_code, var](
const Particle * particle) ->
double {
3441 const Particle* p = particle;
3443 int ancestor_level = std::get<double>(
Manager::Instance().getVariable(
"hasAncestor(" + std::to_string(pdg_code) +
", 0)")->function(p));
3444 if ((ancestor_level <= 0) or (std::isnan(ancestor_level)))
3449 const MCParticle* i_p = p->getMCParticle();
3451 for (
int a = 0; a < ancestor_level ; a = a + 1)
3453 i_p = i_p->getMother();
3456 StoreArray<Particle> tempParticles(
"tempParticles");
3457 tempParticles.clear();
3459 Particle* newPart = tempParticles.appendNew(m_p);
3460 newPart->addRelationTo(i_p);
3462 appendDaughtersRecursive(newPart, tempParticles);
3464 auto var_result = var->function(newPart);
3465 if (std::holds_alternative<double>(var_result))
3467 return std::get<double>(var_result);
3468 }
else if (std::holds_alternative<int>(var_result))
3470 return std::get<int>(var_result);
3471 }
else if (std::holds_alternative<bool>(var_result))
3473 return std::get<bool>(var_result);
3478 B2FATAL(
"Wrong number of arguments for meta function varForFirstMCAncestorOfType (expected 2: type and variable of interest)");
3484 if (arguments.size() != 1) {
3485 B2FATAL(
"Number of arguments for nTrackFitResults must be 1, particleType or PDGcode");
3488 std::string arg = arguments[0];
3489 TDatabasePDG* pdgDatabase = TDatabasePDG::Instance();
3490 TParticlePDG* part = pdgDatabase->GetParticle(arg.c_str());
3492 if (part !=
nullptr) {
3493 absPdg = std::abs(part->PdgCode());
3497 }
catch (
const std::exception&) {
3501 if (absPdg == 0 || pdgDatabase->GetParticle(absPdg) ==
nullptr) {
3502 B2FATAL(
"nTrackFitResults: argument '" << arg <<
"' is neither a valid particle name nor a PDG code");
3506 auto func = [absPdg](
const Particle*) ->
int {
3508 Const::ChargedStable type(absPdg);
3509 StoreArray<Track> tracks;
3511 int nTrackFitResults = 0;
3513 for (
const auto& track : tracks)
3515 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(type);
3517 if (!trackFit)
continue;
3518 if (trackFit->getChargeSign() == 0)
continue;
3523 return nTrackFitResults;
3532 if (arguments.size() == 2) {
3535 auto func = [var, default_val](
const Particle * particle) ->
int {
3536 auto var_result = var->function(particle);
3537 if (std::holds_alternative<double>(var_result))
3539 double value = std::get<double>(var_result);
3540 if (value > std::numeric_limits<int>::max())
3541 value = std::numeric_limits<int>::max();
3542 if (value < std::numeric_limits<int>::min())
3543 value = std::numeric_limits<int>::min();
3544 if (std::isnan(value))
3545 value = default_val;
3546 return static_cast<int>(value);
3547 }
else if (std::holds_alternative<int>(var_result))
3548 return std::get<int>(var_result);
3549 else if (std::holds_alternative<bool>(var_result))
3550 return static_cast<int>(std::get<bool>(var_result));
3551 else return default_val;
3555 B2FATAL(
"Wrong number of arguments for meta function int, please provide variable name and replacement value for NaN!");
3559 VARIABLE_GROUP(
"MetaFunctions");
3560 REGISTER_METAVARIABLE(
"nCleanedECLClusters(cut)", nCleanedECLClusters,
3561 "[Eventbased] Returns the number of clean Clusters in the event\n"
3562 "Clean clusters are defined by the clusters which pass the given cut assuming a photon hypothesis.",
3563 Manager::VariableDataType::c_int);
3564 REGISTER_METAVARIABLE(
"nCleanedTracks(cut)", nCleanedTracks,
3565 "[Eventbased] Returns the number of clean Tracks in the event\n"
3566 "Clean tracks are defined by the tracks which pass the given cut assuming a pion hypothesis.", Manager::VariableDataType::c_int);
3567 REGISTER_METAVARIABLE(
"formula(v1 + v2 * [v3 - v4] / v5^v6)", formula, R
"DOCSTRING(
3568Returns the result of the given formula, where v1 to vN are variables or floating
3569point numbers. Currently the only supported operations are addition (``+``),
3570subtraction (``-``), multiplication (``*``), division (``/``) and power (``^``
3571or ``**``). Parenthesis can be in the form of square brackets ``[v1 * v2]``
3572or normal brackets ``(v1 * v2)``. It will work also with variables taking
3573arguments. Operator precedence is taken into account. For example ::
3575 (daughter(0, E) + daughter(1, E))**2 - p**2 + 0.138
3577.. versionchanged:: release-03-00-00
3578 now both, ``[]`` and ``()`` can be used for grouping operations, ``**`` can
3579 be used for exponent and float literals are possible directly in the
3581)DOCSTRING", Manager::VariableDataType::c_double);
3582 REGISTER_METAVARIABLE("useRestFrame(variable)", useRestFrame,
3583 "Returns the value of the variable using the rest frame of the given particle as current reference frame.\n"
3584 "E.g. ``useRestFrame(daughter(0, p))`` returns the total momentum of the first daughter in its mother's rest-frame", Manager::VariableDataType::c_double);
3585 REGISTER_METAVARIABLE(
"useCMSFrame(variable)", useCMSFrame,
3586 "Returns the value of the variable using the CMS frame as current reference frame.\n"
3587 "E.g. ``useCMSFrame(E)`` returns the energy of a particle in the CMS frame.", Manager::VariableDataType::c_double);
3588 REGISTER_METAVARIABLE(
"useLabFrame(variable)", useLabFrame, R
"DOC(
3589Returns the value of ``variable`` in the *lab* frame.
3592 The lab frame is the default reference frame, usually you don't need to use this meta-variable.
3593 E.g. ``useLabFrame(E)`` returns the energy of a particle in the Lab frame, same as just ``E``.
3595Specifying the lab frame is useful in some corner-cases. For example:
3596``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.
3597)DOC", Manager::VariableDataType::c_double);
3598 REGISTER_METAVARIABLE("useTagSideRecoilRestFrame(variable, daughterIndexTagB)", useTagSideRecoilRestFrame,
3599 "Returns the value of the variable in the rest frame of the recoiling particle to the tag side B meson.\n"
3600 "The variable should only be applied to an Upsilon(4S) list.\n"
3601 "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);
3602 REGISTER_METAVARIABLE(
"useParticleRestFrame(variable, particleList)", useParticleRestFrame,
3603 "Returns the value of the variable in the rest frame of the first Particle contained in the given ParticleList.\n"
3604 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3605 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3606 "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);
3607 REGISTER_METAVARIABLE(
"useRecoilParticleRestFrame(variable, particleList)", useRecoilParticleRestFrame,
3608 "Returns the value of the variable in the rest frame of recoil system against the first Particle contained in the given ParticleList.\n"
3609 "It is strongly recommended to pass a ParticleList that contains at most only one Particle in each event. "
3610 "When more than one Particle is present in the ParticleList, only the first Particle in the list is used for "
3611 "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);
3612 REGISTER_METAVARIABLE(
"useDaughterRestFrame(variable, daughterIndex_1, [daughterIndex_2, ... daughterIndex_3])", useDaughterRestFrame,
3613 "Returns the value of the variable in the rest frame of the selected daughter particle.\n"
3614 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3615 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3616 "If two or more indices are given, the rest frame of the sum of the daughters is used.",
3617 Manager::VariableDataType::c_double);
3618 REGISTER_METAVARIABLE(
"useDaughterRecoilRestFrame(variable, daughterIndex_1, [daughterIndex_2, ... daughterIndex_3])", useDaughterRecoilRestFrame,
3619 "Returns the value of the variable in the rest frame of the recoil of the selected daughter particle.\n"
3620 "The daughter is identified via generalized daughter index, e.g. ``0:1`` identifies the second daughter (1) "
3621 "of the first daughter (0). If the daughter index is invalid, it returns NaN.\n"
3622 "If two or more indices are given, the rest frame of the sum of the daughters is used.",
3623 Manager::VariableDataType::c_double);
3624 REGISTER_METAVARIABLE(
"useMCancestorBRestFrame(variable)", useMCancestorBRestFrame,
3625 "Returns the value of the variable in the rest frame of the ancestor B MC particle.\n"
3626 "If no B or no MC-matching is found, it returns NaN.", Manager::VariableDataType::c_double);
3627 REGISTER_METAVARIABLE(
"passesCut(cut)", passesCut,
3628 "Returns 1 if particle passes the cut otherwise 0.\n"
3629 "Useful if you want to write out if a particle would have passed a cut or not.", Manager::VariableDataType::c_bool);
3630 REGISTER_METAVARIABLE(
"passesEventCut(cut)", passesEventCut,
3631 "[Eventbased] Returns 1 if event passes the cut otherwise 0.\n"
3632 "Useful if you want to select events passing a cut without looping into particles, such as for skimming.\n", Manager::VariableDataType::c_bool);
3633 REGISTER_METAVARIABLE(
"countDaughters(cut)", countDaughters,
3634 "Returns number of direct daughters which satisfy the cut.\n"
3635 "Used by the skimming package (for what exactly?)", Manager::VariableDataType::c_int);
3636 REGISTER_METAVARIABLE(
"countFSPDaughters(cut)", countDescendants,
3637 "Returns number of final-state daughters which satisfy the cut.",
3638 Manager::VariableDataType::c_int);
3639 REGISTER_METAVARIABLE(
"countDescendants(cut)", countDescendants,
3640 "Returns number of descendants for all generations which satisfy the cut.",
3641 Manager::VariableDataType::c_int);
3642 REGISTER_METAVARIABLE(
"varFor(pdgCode, variable)", varFor,
3643 "Returns the value of the variable for the given particle if its abs(pdgCode) agrees with the given one.\n"
3644 "E.g. ``varFor(11, p)`` returns the momentum if the particle is an electron or a positron.", Manager::VariableDataType::c_double);
3645 REGISTER_METAVARIABLE(
"varForMCGen(variable)", varForMCGen,
3646 "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"
3647 "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"
3648 "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);
3649 REGISTER_METAVARIABLE(
"nParticlesInList(particleListName)", nParticlesInList,
3650 "[Eventbased] Returns number of particles in the given particle List.", Manager::VariableDataType::c_int);
3651 REGISTER_METAVARIABLE(
"isInList(particleListName)", isInList,
3652 "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);
3653 REGISTER_METAVARIABLE(
"isDaughterOfList(particleListNames)", isDaughterOfList,
3654 "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);
3655 REGISTER_METAVARIABLE(
"isDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isDescendantOfList, R
"DOC(
3656 Returns 1 if the given particle appears in the decay chain of the particles in the given ParticleLists.
3658 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3660 * ``isDescendantOfList(<particle_list>,1)`` returns 1 if particle is a daughter of the list,
3661 * ``isDescendantOfList(<particle_list>,2)`` returns 1 if particle is a granddaughter of the list,
3662 * ``isDescendantOfList(<particle_list>,3)`` returns 1 if particle is a great-granddaughter of the list, etc.
3663 * Default value is ``-1`` that is inclusive for all generations.
3664 )DOC", Manager::VariableDataType::c_bool);
3665 REGISTER_METAVARIABLE("isMCDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isMCDescendantOfList, R
"DOC(
3666 Returns 1 if the given particle is linked to the same MC particle as any reconstructed daughter of the decay lists.
3668 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
3670 * ``isMCDescendantOfList(<particle_list>,1)`` returns 1 if particle is matched to the same particle as any daughter of the list,
3671 * ``isMCDescendantOfList(<particle_list>,2)`` returns 1 if particle is matched to the same particle as any granddaughter of the list,
3672 * ``isMCDescendantOfList(<particle_list>,3)`` returns 1 if particle is matched to the same particle as any great-granddaughter of the list, etc.
3673 * Default value is ``-1`` that is inclusive for all generations.
3675 It makes only sense for lists created with `fillParticleListFromMC` function with ``addDaughters=True`` argument.
3676 )DOC", Manager::VariableDataType::c_bool);
3678 REGISTER_METAVARIABLE("sourceObjectIsInList(particleListName)", sourceObjectIsInList, R
"DOC(
3679Returns 1 if the underlying mdst object (e.g. track, or cluster) was used to create a particle in ``particleListName``, 0 if not.
3682 This only makes sense for particles that are not composite. Returns -1 for composite particles.
3683)DOC", Manager::VariableDataType::c_int);
3685 REGISTER_METAVARIABLE("mcParticleIsInMCList(particleListName)", mcParticleIsInMCList, R
"DOC(
3686Returns 1 if the particle's matched MC particle is also matched to a particle in ``particleListName``
3687(or if either of the lists were filled from generator level `modularAnalysis.fillParticleListFromMC`.)
3689.. seealso:: :b2:var:`isMCDescendantOfList` to check daughters.
3690)DOC", Manager::VariableDataType::c_bool);
3692 REGISTER_METAVARIABLE("isGrandDaughterOfList(particleListNames)", isGrandDaughterOfList,
3693 "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);
3694 REGISTER_METAVARIABLE(
"originalParticle(variable)", originalParticle, R
"DOC(
3695 Returns value of variable for the original particle from which the given particle is copied.
3697 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3698 Returns NaN if the given particle is not copied and so there is no original particle.
3699 )DOC", Manager::VariableDataType::c_double);
3700 REGISTER_METAVARIABLE("daughter(i, variable)", daughter, R
"DOC(
3701 Returns value of variable for the i-th daughter. E.g.
3703 * ``daughter(0, p)`` returns the total momentum of the first daughter.
3704 * ``daughter(0, daughter(1, p)`` returns the total momentum of the second daughter of the first daughter.
3706 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3707 )DOC", Manager::VariableDataType::c_double);
3708 REGISTER_METAVARIABLE("originalDaughter(i, variable)", originalDaughter, R
"DOC(
3709 Returns value of variable for the original particle from which the i-th daughter is copied.
3711 The copy of particle is created, for example, when the vertex fit updates the daughters and `modularAnalysis.copyParticles` is called.
3712 Returns NaN if the daughter is not copied and so there is no original daughter.
3714 Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).
3715 )DOC", Manager::VariableDataType::c_double);
3716 REGISTER_METAVARIABLE("mcDaughter(i, variable)", mcDaughter, R
"DOC(
3717 Returns the value of the requested variable for the i-th Monte Carlo daughter of the particle.
3719 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3720 or if the i-th MC daughter does not exist.
3722 E.g. ``mcDaughter(0, PDG)`` will return the PDG code of the first MC daughter of the matched MC
3723 particle of the reconstructed particle the function is applied to.
3725 The meta variable can also be nested: ``mcDaughter(0, mcDaughter(1, PDG))``.
3726 )DOC", Manager::VariableDataType::c_double);
3727 REGISTER_METAVARIABLE("mcMother(variable)", mcMother, R
"DOC(
3728 Returns the value of the requested variable for the Monte Carlo mother of the particle.
3730 Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,
3731 or if the MC mother does not exist.
3733 E.g. ``mcMother(PDG)`` will return the PDG code of the MC mother of the matched MC
3734 particle of the reconstructed particle the function is applied to.
3736 The meta variable can also be nested: ``mcMother(mcMother(PDG))``.
3737 )DOC", Manager::VariableDataType::c_double);
3738 REGISTER_METAVARIABLE("genParticle(index, variable)", genParticle, R
"DOC(
3739[Eventbased] Returns the ``variable`` for the ith generator particle.
3740The arguments of the function must be the ``index`` of the particle in the MCParticle Array,
3741and ``variable``, the name of the function or variable for that generator particle.
3742If ``index`` goes beyond the length of the MCParticles array, NaN will be returned.
3744E.g. ``genParticle(0, p)`` returns the total momentum of the first MCParticle, which in a generic decay up to MC15 is
3745the Upsilon(4S) and for MC16 and beyond the initial electron.
3746)DOC", Manager::VariableDataType::c_double);
3747 REGISTER_METAVARIABLE("genUpsilon4S(variable)", genUpsilon4S, R
"DOC(
3748[Eventbased] Returns the ``variable`` evaluated for the generator-level :math:`\Upsilon(4S)`.
3749If no generator level :math:`\Upsilon(4S)` exists for the event, NaN will be returned.
3751E.g. ``genUpsilon4S(p)`` returns the total momentum of the :math:`\Upsilon(4S)` in a generic decay.
3752``genUpsilon4S(mcDaughter(1, p))`` returns the total momentum of the second daughter of the
3753generator-level :math:`\Upsilon(4S)` (i.e. the momentum of the second B meson in a generic decay).
3754)DOC", Manager::VariableDataType::c_double);
3755 REGISTER_METAVARIABLE("daughterProductOf(variable)", daughterProductOf,
3756 "Returns product of a variable over all daughters.\n"
3757 "E.g. ``daughterProductOf(extraInfo(SignalProbability))`` returns the product of the SignalProbabilitys of all daughters.", Manager::VariableDataType::c_double);
3758 REGISTER_METAVARIABLE(
"daughterSumOf(variable)", daughterSumOf,
3759 "Returns sum of a variable over all daughters.\n"
3760 "E.g. ``daughterSumOf(nDaughters)`` returns the number of grand-daughters.", Manager::VariableDataType::c_double);
3761 REGISTER_METAVARIABLE(
"daughterLowest(variable)", daughterLowest,
3762 "Returns the lowest value of the given variable among all daughters.\n"
3763 "E.g. ``useCMSFrame(daughterLowest(p))`` returns the lowest momentum in CMS frame.", Manager::VariableDataType::c_double);
3764 REGISTER_METAVARIABLE(
"daughterHighest(variable)", daughterHighest,
3765 "Returns the highest value of the given variable among all daughters.\n"
3766 "E.g. ``useCMSFrame(daughterHighest(p))`` returns the highest momentum in CMS frame.", Manager::VariableDataType::c_double);
3767 REGISTER_METAVARIABLE(
"daughterDiffOf(daughterIndex_i, daughterIndex_j, variable)", daughterDiffOf, R
"DOC(
3768 Returns the difference of a variable between the two given daughters.
3769 E.g. ``useRestFrame(daughterDiffOf(0, 1, p))`` returns the momentum difference between first and second daughter in the rest frame of the given particle.
3770 (That means that it returns :math:`p_j - p_i`)
3772 The daughters can be provided as generalized daughter indexes, which are simply colon-separated
3773 lists of daughter indexes, ordered starting from the root particle. For example, ``0:1``
3774 identifies the second daughter (1) of the first daughter (0) of the mother particle.
3776 )DOC", Manager::VariableDataType::c_double);
3777 REGISTER_METAVARIABLE("mcDaughterDiffOf(i, j, variable)", mcDaughterDiffOf,
3778 "MC matched version of the `daughterDiffOf` function.", Manager::VariableDataType::c_double);
3779 REGISTER_METAVARIABLE(
"grandDaughterDiffOf(i, j, variable)", grandDaughterDiffOf,
3780 "Returns the difference of a variable between the first daughters of the two given daughters.\n"
3781 "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"
3782 "(That means that it returns :math:`p_j - p_i`)", Manager::VariableDataType::c_double);
3783 MAKE_DEPRECATED(
"grandDaughterDiffOf",
false,
"light-2402-ocicat", R
"DOC(
3784 The difference between any combination of (grand-)daughters can be calculated with the more general variable :b2:var:`daughterDiffOf`
3785 by using generalized daughter indexes.)DOC");
3786 REGISTER_METAVARIABLE("daughterNormDiffOf(i, j, variable)", daughterNormDiffOf,
3787 "Returns the normalized difference of a variable between the two given daughters.\n"
3788 "E.g. ``daughterNormDiffOf(0, 1, p)`` returns the normalized momentum difference between first and second daughter in the lab frame.", Manager::VariableDataType::c_double);
3789 REGISTER_METAVARIABLE(
"daughterMotherDiffOf(i, variable)", daughterMotherDiffOf,
3790 "Returns the difference of a variable between the given daughter and the mother particle itself.\n"
3791 "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);
3792 REGISTER_METAVARIABLE(
"daughterMotherNormDiffOf(i, variable)", daughterMotherNormDiffOf,
3793 "Returns the normalized difference of a variable between the given daughter and the mother particle itself.\n"
3794 "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);
3795 REGISTER_METAVARIABLE(
"angleBetweenDaughterAndRecoil(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndRecoil, R
"DOC(
3796 Returns the angle between the momentum recoiling against the particle and the sum of the momenta of the given daughters.
3797 The unit of the angle is ``rad``.
3799 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3800 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3801 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3802 identifies the second daughter of the root particle.
3804 At least one generalized index has to be given to ``angleBetweenDaughterAndRecoil``.
3807 ``angleBetweenDaughterAndRecoil(0)`` will return the angle between pRecoil and the momentum of the first daughter.
3809 ``angleBetweenDaughterAndRecoil(0, 1)`` will return the angle between pRecoil and the sum of the momenta of the first and second daughter.
3811 ``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
3812 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3813 REGISTER_METAVARIABLE("angleBetweenDaughterAndMissingMomentum(daughterIndex_1, daughterIndex_2, ... )", angleBetweenDaughterAndMissingMomentum, R
"DOC(
3814 Returns the angle between the missing momentum in the event and the sum of the momenta of the given daughters.
3815 The unit of the angle is ``rad``. EventKinematics module has to be called to use this.
3817 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3818 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3819 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3820 identifies the second daughter of the root particle.
3822 At least one generalized index has to be given to ``angleBetweenDaughterAndMissingMomentum``.
3825 ``angleBetweenDaughterAndMissingMomentum(0)`` will return the angle between missMom and the momentum of the first daughter.
3827 ``angleBetweenDaughterAndMissingMomentum(0, 1)`` will return the angle between missMom and the sum of the momenta of the first and second daughter.
3829 ``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
3830 the first daughter of the fourth daughter.)DOC", Manager::VariableDataType::c_double);
3831 REGISTER_METAVARIABLE("daughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", daughterAngle, R
"DOC(
3832 Returns the angle in between any pair of particles belonging to the same decay tree.
3833 The unit of the angle is ``rad``.
3835 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
3836 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
3837 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
3838 identifies the second daughter of the root particle.
3840 Both two and three generalized indexes can be given to ``daughterAngle``. If two indices are given, the
3841 variable returns the angle between the momenta of the two given particles. If three indices are given, the
3842 variable returns the angle between the momentum of the third particle and a vector which is the sum of the
3843 first two daughter momenta.
3846 ``daughterAngle(0, 3)`` will return the angle between the first and fourth daughter.
3847 ``daughterAngle(0, 1, 3)`` will return the angle between the fourth daughter and the sum of the first and
3849 ``daughterAngle(0:0, 3:0)`` will return the angle between the first daughter of the first daughter, and
3850 the first daughter of the fourth daughter.
3852 )DOC", Manager::VariableDataType::c_double);
3853 REGISTER_METAVARIABLE("mcDaughterAngle(daughterIndex_1, daughterIndex_2, [daughterIndex_3])", mcDaughterAngle,
3854 "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);
3855 REGISTER_VARIABLE(
"grandDaughterDecayAngle(i, j)", grandDaughterDecayAngle,
3856 "Returns the decay angle of the granddaughter in the daughter particle's rest frame.\n"
3857 "It is calculated with respect to the reverted momentum vector of the particle.\n"
3858 "Two arguments representing the daughter and granddaughter indices have to be provided as arguments.\n\n",
"rad");
3859 REGISTER_VARIABLE(
"daughterClusterAngleInBetween(i, j)", daughterClusterAngleInBetween,
3860 "Returns the angle between clusters associated to the two daughters."
3861 "If two indices given: returns the angle between the momenta of the clusters associated to the two given daughters."
3862 "If three indices given: returns the angle between the momentum of the third particle's cluster and a vector "
3863 "which is the sum of the first two daughter's cluster momenta."
3864 "Returns nan if any of the daughters specified don't have an associated cluster."
3865 "The arguments in the argument vector must be integers corresponding to the ith and jth (and kth) daughters.\n\n",
"rad");
3866 REGISTER_METAVARIABLE(
"daughterInvM(i[, j, ...])", daughterInvM, R
"DOC(
3867 Returns the invariant mass adding the Lorentz vectors of the given daughters. The unit of the invariant mass is GeV/:math:`\text{c}^2`
3868 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.
3870 Daughters from different generations of the decay tree can be combined using generalized daughter indexes,
3871 which are simply colon-separated daughter indexes for each generation, starting from the root particle. For
3872 example, ``0:1:3`` identifies the fourth daughter (3) of the second daughter (1) of the first daughter(0) of
3873 the mother particle.
3875 Returns NaN if the given daughter-index is out of bound (>= number of daughters))DOC", Manager::VariableDataType::c_double);
3876 REGISTER_METAVARIABLE("extraInfo(name)", extraInfo,
3877 "Returns extra info stored under the given name.\n"
3878 "The extraInfo has to be set by a module first.\n"
3879 "E.g. ``extraInfo(SignalProbability)`` returns the SignalProbability calculated by the ``MVAExpert`` module.\n"
3880 "If nothing is set under the given name or if the particle is a nullptr, NaN is returned.\n"
3881 "In the latter case please use `eventExtraInfo` if you want to access an EventExtraInfo variable.", Manager::VariableDataType::c_double);
3882 REGISTER_METAVARIABLE(
"eventExtraInfo(name)", eventExtraInfo,
3883 "[Eventbased] Returns extra info stored under the given name in the event extra info.\n"
3884 "The extraInfo has to be set first by another module like MVAExpert in event mode.\n"
3885 "If nothing is set under this name, NaN is returned.", Manager::VariableDataType::c_double);
3886 REGISTER_METAVARIABLE(
"eventCached(variable)", eventCached,
3887 "[Eventbased] Returns value of event-based variable and caches this value in the EventExtraInfo.\n"
3888 "The result of second call to this variable in the same event will be provided from the cache.\n"
3889 "It is recommended to use this variable in order to declare custom aliases as event-based. This is "
3890 "necessary if using the eventwise mode of variablesToNtuple).", Manager::VariableDataType::c_double);
3891 REGISTER_METAVARIABLE(
"particleCached(variable)", particleCached,
3892 "Returns value of given variable and caches this value in the ParticleExtraInfo of the provided particle.\n"
3893 "The result of second call to this variable on the same particle will be provided from the cache.", Manager::VariableDataType::c_double);
3894 REGISTER_METAVARIABLE(
"modulo(variable, n)", modulo,
3895 "Returns rest of division of variable by n.", Manager::VariableDataType::c_int);
3896 REGISTER_METAVARIABLE(
"abs(variable)", abs,
3897 "Returns absolute value of the given variable.\n"
3898 "E.g. abs(mcPDG) returns the absolute value of the mcPDG, which is often useful for cuts.", Manager::VariableDataType::c_double);
3899 REGISTER_METAVARIABLE(
"max(var1,var2)", max,
"Returns max value of two variables.\n", Manager::VariableDataType::c_double);
3900 REGISTER_METAVARIABLE(
"min(var1,var2)", min,
"Returns min value of two variables.\n", Manager::VariableDataType::c_double);
3901 REGISTER_METAVARIABLE(
"sin(variable)", sin,
"Returns sine value of the given variable.", Manager::VariableDataType::c_double);
3902 REGISTER_METAVARIABLE(
"asin(variable)", asin,
"Returns arcsine of the given variable. The unit of the asin() is ``rad``", Manager::VariableDataType::c_double);
3903 REGISTER_METAVARIABLE(
"cos(variable)", cos,
"Returns cosine value of the given variable.", Manager::VariableDataType::c_double);
3904 REGISTER_METAVARIABLE(
"acos(variable)", acos,
"Returns arccosine value of the given variable. The unit of the acos() is ``rad``", Manager::VariableDataType::c_double);
3905 REGISTER_METAVARIABLE(
"tan(variable)", tan,
"Returns tangent value of the given variable.", Manager::VariableDataType::c_double);
3906 REGISTER_METAVARIABLE(
"atan(variable)", atan,
"Returns arctangent value of the given variable. The unit of the atan() is ``rad``", Manager::VariableDataType::c_double);
3907 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);
3908 REGISTER_METAVARIABLE(
"exp(variable)", exp,
"Returns exponential evaluated for the given variable.", Manager::VariableDataType::c_double);
3909 REGISTER_METAVARIABLE(
"log(variable)", log,
"Returns natural logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
3910 REGISTER_METAVARIABLE(
"log10(variable)", log10,
"Returns base-10 logarithm evaluated for the given variable.", Manager::VariableDataType::c_double);
3911 REGISTER_METAVARIABLE(
"int(variable, nan_replacement)", convertToInt, R
"DOC(
3912 Casts the output of the variable to an integer value.
3915 Overflow and underflow are clipped at maximum and minimum values, respectively. NaN values are replaced with the value of the 2nd argument.
3917 )DOC", Manager::VariableDataType::c_int);
3918 REGISTER_METAVARIABLE("isNAN(variable)", isNAN,
3919 "Returns true if variable value evaluates to nan (determined via std::isnan(double)).\n"
3920 "Useful for debugging.", Manager::VariableDataType::c_bool);
3921 REGISTER_METAVARIABLE(
"ifNANgiveX(variable, x)", ifNANgiveX,
3922 "Returns x (has to be a number) if variable value is nan (determined via std::isnan(double)).\n"
3923 "Useful for technical purposes while training MVAs.", Manager::VariableDataType::c_double);
3924 REGISTER_METAVARIABLE(
"isInfinity(variable)", isInfinity,
3925 "Returns true if variable value evaluates to infinity (determined via std::isinf(double)).\n"
3926 "Useful for debugging.", Manager::VariableDataType::c_bool);
3927 REGISTER_METAVARIABLE(
"unmask(variable, flag1, flag2, ...)", unmask,
3928 "unmask(variable, flag1, flag2, ...) or unmask(variable, mask) sets certain bits in the variable to zero.\n"
3929 "For example, if you want to set the second, fourth and fifth bits to zero, you could call \n"
3930 "``unmask(variable, 2, 8, 16)`` or ``unmask(variable, 26)``.\n"
3931 "", Manager::VariableDataType::c_double);
3932 REGISTER_METAVARIABLE(
"conditionalVariableSelector(cut, variableIfTrue, variableIfFalse)", conditionalVariableSelector,
3933 "Returns one of the two supplied variables, depending on whether the particle passes the supplied cut.\n"
3934 "The first variable is returned if the particle passes the cut, and the second variable is returned otherwise.", Manager::VariableDataType::c_double);
3935 REGISTER_METAVARIABLE(
"pValueCombination(p1, p2, ...)", pValueCombination,
3936 "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"
3937 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
3938 REGISTER_METAVARIABLE(
"pValueCombinationOfDaughters(variable)", pValueCombinationOfDaughters,
3939 "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"
3940 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.", Manager::VariableDataType::c_double);
3941 REGISTER_METAVARIABLE(
"veto(particleList, cut, pdgCode = 11)", veto,
3942 "Combines current particle with particles from the given particle list and returns 1 if the combination passes the provided cut. \n"
3943 "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"
3944 "around the neutral Pion mass (e.g. ``0.130 < M < 0.140``). \n"
3945 "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);
3946 REGISTER_METAVARIABLE(
"matchedMC(variable)", matchedMC,
3947 "Returns variable output for the matched MCParticle by constructing a temporary Particle from it.\n"
3948 "This may not work too well if your variable requires accessing daughters of the particle.\n"
3949 "E.g. ``matchedMC(p)`` returns the total momentum of the related MCParticle.\n"
3950 "Returns NaN if no matched MCParticle exists.", Manager::VariableDataType::c_double);
3951 REGISTER_METAVARIABLE(
"clusterBestMatchedMCParticle(variable)", clusterBestMatchedMCParticle,
3952 "Returns variable output for the MCParticle that is best-matched with the ECLCluster of the given Particle.\n"
3953 "E.g. To get the energy of the MCParticle that matches best with an ECLCluster, one could use ``clusterBestMatchedMCParticle(E)``\n"
3954 "When the variable is called for ``gamma`` and if the ``gamma`` is matched with MCParticle, it works same as `matchedMC`.\n"
3955 "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"
3956 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching MCParticles", Manager::VariableDataType::c_double);
3957 REGISTER_METAVARIABLE(
"varForBestMatchedMCKlong(variable)", clusterBestMatchedMCKlong,
3958 "Returns variable output for the Klong MCParticle which has the best match with the ECLCluster of the given Particle.\n"
3959 "Returns NaN if the particle is not matched to an ECLCluster, or if the ECLCluster has no matching Klong MCParticle", Manager::VariableDataType::c_double);
3961 REGISTER_METAVARIABLE(
"countInList(particleList, cut='')", countInList,
"[Eventbased] "
3962 "Returns number of particle which pass given in cut in the specified particle list.\n"
3963 "Useful for creating statistics about the number of particles in a list.\n"
3964 "E.g. ``countInList(e+, isSignal == 1)`` returns the number of correctly reconstructed electrons in the event.\n"
3965 "The variable is event-based and does not need a valid particle pointer as input.", Manager::VariableDataType::c_int);
3966 REGISTER_METAVARIABLE(
"getVariableByRank(particleList, rankedVariableName, variableName, rank)", getVariableByRank, R
"DOC(
3967 [Eventbased] Returns the value of ``variableName`` for the candidate in the ``particleList`` with the requested ``rank``.
3970 The `BestCandidateSelection` module available via `rankByHighest` / `rankByLowest` has to be used before.
3973 The first candidate matching the given rank is used.
3974 Thus, it is not recommended to use this variable in conjunction with ``allowMultiRank`` in the `BestCandidateSelection` module.
3976 The suffix ``_rank`` is automatically added to the argument ``rankedVariableName``,
3977 which either has to be the name of the variable used to order the candidates or the selected outputVariable name without the ending ``_rank``.
3978 This means that your selected name for the rank variable has to end with ``_rank``.
3980 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>`_
3981 )DOC", Manager::VariableDataType::c_double);
3982 REGISTER_VARIABLE("matchedMCHasPDG(PDGCode)", matchedMCHasPDG,
3983 "Returns if the absolute value of the PDGCode of the MCParticle related to the Particle matches a given PDGCode."
3984 "Returns 0/NAN/1 if PDGCode does not match/is not available/ matches");
3985 REGISTER_METAVARIABLE(
"numberOfNonOverlappingParticles(pList1, pList2, ...)", numberOfNonOverlappingParticles,
3986 "Returns the number of non-overlapping particles in the given particle lists"
3987 "Useful to check if there is additional physics going on in the detector if one reconstructed the Y4S", Manager::VariableDataType::c_int);
3988 REGISTER_METAVARIABLE(
"totalEnergyOfParticlesInList(particleListName)", totalEnergyOfParticlesInList,
3989 "[Eventbased] Returns the total energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
3990 REGISTER_METAVARIABLE(
"totalPxOfParticlesInList(particleListName)", totalPxOfParticlesInList,
3991 "[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);
3992 REGISTER_METAVARIABLE(
"totalPyOfParticlesInList(particleListName)", totalPyOfParticlesInList,
3993 "[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);
3994 REGISTER_METAVARIABLE(
"totalPzOfParticlesInList(particleListName)", totalPzOfParticlesInList,
3995 "[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);
3996 REGISTER_METAVARIABLE(
"invMassInLists(pList1, pList2, ...)", invMassInLists,
3997 "[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);
3998 REGISTER_METAVARIABLE(
"totalECLEnergyOfParticlesInList(particleListName)", totalECLEnergyOfParticlesInList,
3999 "[Eventbased] Returns the total ECL energy of particles in the given particle List. The unit of the energy is ``GeV``", Manager::VariableDataType::c_double);
4000 REGISTER_METAVARIABLE(
"maxPtInList(particleListName)", maxPtInList,
4001 "[Eventbased] Returns maximum transverse momentum Pt in the given particle List. The unit of the transverse momentum is ``GeV/c``", Manager::VariableDataType::c_double);
4002 REGISTER_METAVARIABLE(
"eclClusterSpecialTrackMatched(cut)", eclClusterTrackMatchedWithCondition,
4003 "Returns if at least one Track that satisfies the given condition is related to the ECLCluster of the Particle.", Manager::VariableDataType::c_double);
4004 REGISTER_METAVARIABLE(
"averageValueInList(particleListName, variable)", averageValueInList,
4005 "[Eventbased] Returns the arithmetic mean of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4006 REGISTER_METAVARIABLE(
"medianValueInList(particleListName, variable)", medianValueInList,
4007 "[Eventbased] Returns the median value of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4008 REGISTER_METAVARIABLE(
"sumValueInList(particleListName, variable)", sumValueInList,
4009 "[Eventbased] Returns the sum of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4010 REGISTER_METAVARIABLE(
"productValueInList(particleListName, variable)", productValueInList,
4011 "[Eventbased] Returns the product of the given variable of the particles in the given particle list.", Manager::VariableDataType::c_double);
4012 REGISTER_METAVARIABLE(
"angleToClosestInList(particleListName)", angleToClosestInList,
4013 "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);
4014 REGISTER_METAVARIABLE(
"closestInList(particleListName, variable)", closestInList,
4015 "Returns `variable` for the closest particle (smallest opening angle) in the list provided.", Manager::VariableDataType::c_double);
4016 REGISTER_METAVARIABLE(
"angleToMostB2BInList(particleListName)", angleToMostB2BInList,
4017 "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);
4018 REGISTER_METAVARIABLE(
"deltaPhiToMostB2BPhiInList(particleListName)", deltaPhiToMostB2BPhiInList,
4019 "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);
4020 REGISTER_METAVARIABLE(
"mostB2BInList(particleListName, variable)", mostB2BInList,
4021 "Returns `variable` for the most back-to-back particle (closest opening angle to 180) in the list provided.", Manager::VariableDataType::c_double);
4022 REGISTER_METAVARIABLE(
"maxOpeningAngleInList(particleListName)", maxOpeningAngleInList,
4023 "[Eventbased] Returns maximum opening angle in the given particle List. The unit of the angle is ``rad`` ", Manager::VariableDataType::c_double);
4024 REGISTER_METAVARIABLE(
"daughterCombination(variable, daughterIndex_1, daughterIndex_2 ... daughterIndex_n)", daughterCombination,R
"DOC(
4025Returns a ``variable`` function only of the 4-momentum calculated on an arbitrary set of (grand)daughters.
4028 ``variable`` can only be a function of the daughters' 4-momenta.
4030Daughters from different generations of the decay tree can be combined using generalized daughter indexes, which are simply colon-separated
4031the list of daughter indexes, starting from the root particle: for example, ``0:1:3`` identifies the fourth
4032daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle.
4035 ``daughterCombination(M, 0, 3, 4)`` will return the invariant mass of the system made of the first, fourth and fifth daughter of particle.
4036 ``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.
4038)DOC", Manager::VariableDataType::c_double);
4039 REGISTER_METAVARIABLE("useAlternativeDaughterHypothesis(variable, daughterIndex_1:newMassHyp_1, ..., daughterIndex_n:newMassHyp_n)", useAlternativeDaughterHypothesis,R
"DOC(
4040Returns a ``variable`` calculated using new mass hypotheses for (some of) the particle's daughters.
4043 ``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.
4044 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.
4045 Also, the track fit is not performed again: the variable only re-calculates the 4-vectors using different mass assumptions.
4046 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).
4049 Generalized daughter indexes are not supported (yet!): this variable can be used only on first-generation daughters.
4052 ``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.
4053 ``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.
4055)DOC", Manager::VariableDataType::c_double);
4056 REGISTER_METAVARIABLE("varForFirstMCAncestorOfType(type, variable)",varForFirstMCAncestorOfType,R
"DOC(Returns requested variable of the first ancestor of the given type.
4057Ancestor type can be set up by PDG code or by particle name (check evt.pdl for valid particle names))DOC", Manager::VariableDataType::c_double);
4059 REGISTER_METAVARIABLE("nTrackFitResults(particleType)", nTrackFitResults,
4060 "[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).",
4061 Manager::VariableDataType::c_int);
4063 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.