12 #include <analysis/variables/MetaVariables.h>
13 #include <analysis/VariableManager/Utility.h>
14 #include <analysis/dataobjects/EventExtraInfo.h>
15 #include <analysis/dataobjects/Particle.h>
16 #include <analysis/dataobjects/ParticleList.h>
17 #include <analysis/dataobjects/RestOfEvent.h>
18 #include <analysis/utility/PCmsLabTransform.h>
19 #include <analysis/utility/ReferenceFrame.h>
20 #include <analysis/utility/EvtPDLUtil.h>
21 #include <analysis/ClusterUtility/ClusterUtils.h>
22 #include <analysis/variables/VariableFormulaConstructor.h>
24 #include <framework/logging/Logger.h>
25 #include <framework/datastore/StoreArray.h>
26 #include <framework/datastore/StoreObjPtr.h>
27 #include <framework/utilities/Conversion.h>
28 #include <framework/utilities/MakeROOTCompatible.h>
30 #include <mdst/dataobjects/Track.h>
31 #include <mdst/dataobjects/MCParticle.h>
32 #include <mdst/dataobjects/ECLCluster.h>
33 #include <mdst/dataobjects/TrackFitResult.h>
35 #include <boost/algorithm/string.hpp>
43 #include <TDatabasePDG.h>
54 if (arguments.size() == 1) {
56 auto func = [var](
const Particle * particle) ->
double {
57 UseReferenceFrame<RestFrame> frame(particle);
58 double result = var->function(particle);
63 B2FATAL(
"Wrong number of arguments for meta function useRestFrame");
69 if (arguments.size() == 1) {
71 auto func = [var](
const Particle * particle) ->
double {
72 UseReferenceFrame<CMSFrame> frame;
73 double result = var->function(particle);
78 B2FATAL(
"Wrong number of arguments for meta function useCMSFrame");
84 if (arguments.size() == 1) {
86 auto func = [var](
const Particle * particle) ->
double {
87 UseReferenceFrame<LabFrame> frame;
88 double result = var->function(particle);
93 B2FATAL(
"Wrong number of arguments for meta function useLabFrame");
99 if (arguments.size() == 2) {
102 int daughterIndexTagB = 0;
104 daughterIndexTagB = Belle2::convertString<int>(arguments[1]);
105 }
catch (std::invalid_argument&) {
106 B2FATAL(
"Second argument of useTagSideRecoilRestFrame meta function must be integer!");
109 auto func = [var, daughterIndexTagB](
const Particle * particle) ->
double {
110 if (particle->getPDGCode() != 300553)
112 B2ERROR(
"Variable should only be used on a Upsilon(4S) Particle List!");
113 return std::numeric_limits<float>::quiet_NaN();
117 TLorentzVector pSigB = T.getBeamFourMomentum() - particle->getDaughter(daughterIndexTagB)->get4Vector();
118 Particle tmp(pSigB, -particle->getDaughter(daughterIndexTagB)->getPDGCode());
120 UseReferenceFrame<RestFrame> frame(&tmp);
121 double result = var->function(particle);
127 B2FATAL(
"Wrong number of arguments for meta function useTagSideRecoilRestFrame");
135 if (arguments.size() == 1) {
136 auto extraInfoName = arguments[0];
137 auto func = [extraInfoName](
const Particle * particle) ->
double {
138 if (particle ==
nullptr)
140 B2WARNING(
"Returns NaN because the particle is nullptr! If you want EventExtraInfo variables, please use eventExtraInfo() instead");
141 return std::numeric_limits<float>::quiet_NaN();
143 if (particle->hasExtraInfo(extraInfoName))
145 return particle->getExtraInfo(extraInfoName);
147 return std::numeric_limits<float>::quiet_NaN();
152 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
158 if (arguments.size() == 1) {
159 auto extraInfoName = arguments[0];
160 auto func = [extraInfoName](
const Particle*) ->
double {
161 StoreObjPtr<EventExtraInfo> eventExtraInfo;
162 if (not eventExtraInfo.isValid())
163 return std::numeric_limits<float>::quiet_NaN();
164 if (eventExtraInfo->hasExtraInfo(extraInfoName))
166 return eventExtraInfo->getExtraInfo(extraInfoName);
168 return std::numeric_limits<float>::quiet_NaN();
173 B2FATAL(
"Wrong number of arguments for meta function extraInfo");
179 if (arguments.size() == 1) {
182 auto func = [var, key](
const Particle*) ->
double {
184 StoreObjPtr<EventExtraInfo> eventExtraInfo;
185 if (not eventExtraInfo.isValid())
186 eventExtraInfo.create();
187 if (eventExtraInfo->hasExtraInfo(key))
189 return eventExtraInfo->getExtraInfo(key);
191 double value = var->function(
nullptr);
192 eventExtraInfo->addExtraInfo(key, value);
198 B2FATAL(
"Wrong number of arguments for meta function eventCached");
204 if (arguments.size() == 1) {
207 auto func = [var, key](
const Particle * particle) ->
double {
209 if (particle->hasExtraInfo(key))
211 return particle->getExtraInfo(key);
213 double value = var->function(particle);
221 const_cast<Particle*
>(particle)->addExtraInfo(key, value);
227 B2FATAL(
"Wrong number of arguments for meta function particleCached");
236 if (arguments.size() != 1) B2FATAL(
"Wrong number of arguments for meta function formula");
237 FormulaParser<VariableFormulaConstructor> parser;
239 return parser.parse(arguments[0]);
240 }
catch (std::runtime_error& e) {
247 if (arguments.size() <= 1) {
249 std::string cutString;
250 if (arguments.size() == 1)
251 cutString = arguments[0];
253 auto func = [cut](
const Particle*) ->
double {
255 unsigned int number_of_tracks = 0;
256 StoreArray<Track> tracks;
257 for (
const auto& track : tracks)
259 const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(
Const::pion);
260 if (trackFit->getChargeSign() == 0) {
264 if (cut->check(&particle))
269 return static_cast<double>(number_of_tracks);
274 B2FATAL(
"Wrong number of arguments for meta function nCleanedTracks");
280 if (arguments.size() <= 1) {
282 std::string cutString;
283 if (arguments.size() == 1)
284 cutString = arguments[0];
286 auto func = [cut](
const Particle*) ->
double {
288 unsigned int number_of_clusters = 0;
289 StoreArray<ECLCluster> clusters;
290 for (
const auto& cluster : clusters)
296 Particle particle(&cluster);
297 if (cut->check(&particle))
298 number_of_clusters++;
301 return static_cast<double>(number_of_clusters);
306 B2FATAL(
"Wrong number of arguments for meta function nCleanedECLClusters");
312 if (arguments.size() == 1) {
313 std::string cutString = arguments[0];
315 auto func = [cut](
const Particle * particle) ->
double {
317 if (particle ==
nullptr)
318 return std::numeric_limits<float>::quiet_NaN();
319 if (cut->check(particle))
327 B2FATAL(
"Wrong number of arguments for meta function passesCut");
333 if (arguments.size() == 1) {
334 std::string cutString = arguments[0];
336 auto func = [cut](
const Particle*) ->
double {
337 if (cut->check(
nullptr))
345 B2FATAL(
"Wrong number of arguments for meta function passesEventCut");
351 if (arguments.size() == 2) {
354 pdgCode = Belle2::convertString<int>(arguments[0]);
355 }
catch (std::invalid_argument&) {
356 B2FATAL(
"The first argument of varFor meta function must be a positive integer!");
359 auto func = [pdgCode, var](
const Particle * particle) ->
double {
361 if (std::abs(particle -> getPDGCode()) == std::abs(pdgCode))
362 return var ->
function(particle);
363 else return std::numeric_limits<float>::quiet_NaN();
367 B2FATAL(
"Wrong number of arguments for meta function varFor");
373 if (arguments.size() == 1) {
375 auto func = [var](
const Particle * particle) ->
double {
377 if (particle -> getMCParticle())
382 return var ->
function(particle);
383 }
else return std::numeric_limits<float>::quiet_NaN();
384 }
else return std::numeric_limits<float>::quiet_NaN();
388 B2FATAL(
"Wrong number of arguments for meta function varForMCGen");
394 if (arguments.size() == 1) {
395 std::string listName = arguments[0];
396 auto func = [listName](
const Particle * particle) ->
double {
399 StoreObjPtr<ParticleList> listOfParticles(listName);
401 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to nParticlesInList");
403 return listOfParticles->getListSize();
408 B2FATAL(
"Wrong number of arguments for meta function nParticlesInList");
415 if (arguments.size() != 1) {
416 B2FATAL(
"Wrong number of arguments for isInList");
418 auto listName = arguments[0];
420 auto func = [listName](
const Particle * particle) ->
double {
423 StoreObjPtr<ParticleList> list(listName);
424 if (!(list.isValid()))
426 B2FATAL(
"Invalid Listname " << listName <<
" given to isInList");
430 bool isIn = list->contains(particle);
440 if (arguments.size() != 1) {
441 B2FATAL(
"Wrong number of arguments for sourceObjectIsInList");
443 auto listName = arguments[0];
445 auto func = [listName](
const Particle * particle) ->
double {
448 StoreObjPtr<ParticleList> list(listName);
449 if (!(list.isValid()))
451 B2FATAL(
"Invalid Listname " << listName <<
" given to sourceObjectIsInList");
457 if (particlesource == Particle::EParticleSourceObject::c_Composite
458 or particlesource == Particle::EParticleSourceObject::c_Undefined)
464 for (
unsigned i = 0; i < list->getListSize(); ++i)
466 Particle* iparticle = list->getParticle(i);
467 if (particlesource == iparticle->getParticleSource())
468 if (particle->getMdstArrayIndex() == iparticle->getMdstArrayIndex())
480 if (arguments.size() != 1) {
481 B2FATAL(
"Wrong number of arguments for mcParticleIsInMCList");
483 auto listName = arguments[0];
485 auto func = [listName](
const Particle * particle) ->
double {
488 StoreObjPtr<ParticleList> list(listName);
489 if (!(list.isValid()))
490 B2FATAL(
"Invalid Listname " << listName <<
" given to mcParticleIsInMCList");
493 const MCParticle* mcp = particle->getMCParticle();
494 if (mcp ==
nullptr)
return 0.0;
497 for (
unsigned i = 0; i < list->getListSize(); ++i)
499 const MCParticle* imcp = list->getParticle(i)->
getMCParticle();
500 if ((imcp !=
nullptr) and (mcp->getArrayIndex() == imcp->getArrayIndex()))
510 B2WARNING(
"isDaughterOfList is outdated and replaced by isDescendantOfList.");
511 std::vector<std::string> new_arguments = arguments;
512 new_arguments.push_back(std::string(
"1"));
513 return isDescendantOfList(new_arguments);
518 B2WARNING(
"isGrandDaughterOfList is outdated and replaced by isDescendantOfList.");
519 std::vector<std::string> new_arguments = arguments;
520 new_arguments.push_back(std::string(
"2"));
521 return isDescendantOfList(new_arguments);
526 if (arguments.size() > 0) {
527 auto listNames = arguments;
528 auto func = [listNames](
const Particle * particle) ->
double {
530 int generation_flag = -1;
532 generation_flag = Belle2::convertString<int>(listNames.back());
533 }
catch (std::exception& e) {}
536 for (
auto& iListName : listNames)
539 Belle2::convertString<int>(iListName);
541 }
catch (std::exception& e) {}
544 auto list_comparison = [](
auto &&
self,
const Particle * m,
const Particle * p,
int flag)->
int {
546 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
548 const Particle* daughter = m->getDaughter(i);
549 if ((flag == 1.) or (flag < 0)) {
550 if (p->isCopyOf(daughter)) {
556 if (daughter->getNDaughters() > 0) {
557 result =
self(
self, daughter, p, flag - 1);
568 StoreObjPtr<ParticleList> listOfParticles(iListName);
570 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isDescendantOfList");
572 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
573 Particle* iParticle = listOfParticles->getParticle(i);
574 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
584 B2FATAL(
"Wrong number of arguments for meta function isDescendantOfList");
590 if (arguments.size() > 0) {
591 auto listNames = arguments;
592 auto func = [listNames](
const Particle * particle) ->
double {
594 int generation_flag = -1;
596 generation_flag = Belle2::convertString<int>(listNames.back());
597 }
catch (std::exception& e) {}
599 if (particle->getMCParticle() ==
nullptr)
604 for (
auto& iListName : listNames)
607 std::stod(iListName);
609 }
catch (std::exception& e) {}
611 auto list_comparison = [](
auto &&
self,
const Particle * m,
const Particle * p,
int flag)->
int {
613 for (
unsigned i = 0; i < m->getNDaughters(); ++i)
615 const Particle* daughter = m->getDaughter(i);
616 if ((flag == 1.) or (flag < 0)) {
617 if (daughter->getMCParticle() !=
nullptr) {
618 if (p->getMCParticle()->getArrayIndex() == daughter->getMCParticle()->getArrayIndex()) {
624 if (daughter->getNDaughters() > 0) {
625 result =
self(
self, daughter, p, flag - 1);
636 StoreObjPtr<ParticleList> listOfParticles(iListName);
638 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << iListName <<
" given to isMCDescendantOfList");
640 for (
unsigned i = 0; i < listOfParticles->getListSize(); ++i) {
641 Particle* iParticle = listOfParticles->getParticle(i);
642 output = list_comparison(list_comparison, iParticle, particle, generation_flag);
652 B2FATAL(
"Wrong number of arguments for meta function isMCDescendantOfList");
658 if (arguments.size() == 1) {
660 auto func = [var](
const Particle * particle) ->
double {
661 double product = 1.0;
662 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
664 product *= var->function(particle->getDaughter(j));
670 B2FATAL(
"Wrong number of arguments for meta function daughterProductOf");
676 if (arguments.size() == 1) {
678 auto func = [var](
const Particle * particle) ->
double {
680 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
682 sum += var->function(particle->getDaughter(j));
688 B2FATAL(
"Wrong number of arguments for meta function daughterSumOf");
694 if (arguments.size() == 1) {
696 auto func = [var](
const Particle * particle) ->
double {
697 double min = std::numeric_limits<double>::quiet_NaN();
698 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
700 double iValue = var->function(particle->getDaughter(j));
701 if (std::isnan(iValue))
continue;
702 if (std::isnan(min)) min = iValue;
703 if (iValue < min) min = iValue;
709 B2FATAL(
"Wrong number of arguments for meta function daughterLowest");
715 if (arguments.size() == 1) {
717 auto func = [var](
const Particle * particle) ->
double {
718 double max = std::numeric_limits<double>::quiet_NaN();
719 for (
unsigned j = 0; j < particle->getNDaughters(); ++j)
721 double iValue = var->function(particle->getDaughter(j));
722 if (std::isnan(iValue))
continue;
723 if (std::isnan(max)) max = iValue;
724 if (iValue > max) max = iValue;
730 B2FATAL(
"Wrong number of arguments for meta function daughterHighest");
736 if (arguments.size() == 3) {
737 int iDaughterNumber = 0;
738 int jDaughterNumber = 0;
740 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
741 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
742 }
catch (std::invalid_argument&) {
743 B2FATAL(
"First two arguments of daughterDiffOf meta function must be integers!");
746 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
747 if (particle ==
nullptr)
748 return std::numeric_limits<double>::quiet_NaN();
749 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
750 return std::numeric_limits<double>::quiet_NaN();
752 double diff = var->function(particle->getDaughter(jDaughterNumber)) - var->function(particle->getDaughter(iDaughterNumber));
757 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOf");
763 if (arguments.size() == 5) {
764 int iDaughterNumber = 0, jDaughterNumber = 0, agrandDaughterNumber = 0, bgrandDaughterNumber = 0;
766 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
767 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
768 agrandDaughterNumber = Belle2::convertString<int>(arguments[2]);
769 bgrandDaughterNumber = Belle2::convertString<int>(arguments[3]);
770 }
catch (std::invalid_argument&) {
771 B2FATAL(
"First four arguments of grandDaughterDiffOf meta function must be integers!");
774 auto func = [var, iDaughterNumber, jDaughterNumber, agrandDaughterNumber,
775 bgrandDaughterNumber](
const Particle * particle) ->
double {
776 if (particle ==
nullptr)
777 return std::numeric_limits<double>::quiet_NaN();
778 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
779 return std::numeric_limits<double>::quiet_NaN();
780 if (agrandDaughterNumber >=
int((particle->getDaughter(iDaughterNumber))->getNDaughters()) || bgrandDaughterNumber >=
int((particle->getDaughter(jDaughterNumber))->getNDaughters()))
781 return std::numeric_limits<double>::quiet_NaN();
783 double diff = var->function((particle->getDaughter(jDaughterNumber))->getDaughter(bgrandDaughterNumber)) - var->function((particle->getDaughter(iDaughterNumber))->getDaughter(agrandDaughterNumber));
788 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOf");
794 if (arguments.size() == 2) {
795 int iDaughterNumber = 0;
796 int jDaughterNumber = 0;
798 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
799 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
800 }
catch (std::invalid_argument&) {
801 B2FATAL(
"The two arguments of daughterDiffOfPhi meta function must be integers!");
804 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
805 if (particle ==
nullptr)
806 return std::numeric_limits<double>::quiet_NaN();
807 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
808 return std::numeric_limits<double>::quiet_NaN();
811 double diff = var->function(particle->getDaughter(jDaughterNumber)) - var->function(particle->getDaughter(iDaughterNumber));
812 if (fabs(diff) > M_PI)
815 diff = diff - 2 * M_PI;
817 diff = 2 * M_PI + diff;
825 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOfPhi");
831 if (arguments.size() == 4) {
832 int iDaughterNumber = 0, jDaughterNumber = 0, agrandDaughterNumber = 0, bgrandDaughterNumber = 0;
834 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
835 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
836 agrandDaughterNumber = Belle2::convertString<int>(arguments[2]);
837 bgrandDaughterNumber = Belle2::convertString<int>(arguments[3]);
838 }
catch (std::invalid_argument&) {
839 B2FATAL(
"The four arguments of grandDaughterDiffOfPhi meta function must be integers!");
842 auto func = [var, iDaughterNumber, jDaughterNumber, agrandDaughterNumber,
843 bgrandDaughterNumber](
const Particle * particle) ->
double {
844 if (particle ==
nullptr)
845 return std::numeric_limits<double>::quiet_NaN();
846 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
847 return std::numeric_limits<double>::quiet_NaN();
848 if (agrandDaughterNumber >=
int((particle->getDaughter(iDaughterNumber))->getNDaughters()) || bgrandDaughterNumber >=
int((particle->getDaughter(jDaughterNumber))->getNDaughters()))
849 return std::numeric_limits<double>::quiet_NaN();
852 double diff = var->function((particle->getDaughter(jDaughterNumber))->getDaughter(bgrandDaughterNumber)) - var->function((particle->getDaughter(iDaughterNumber))->getDaughter(agrandDaughterNumber));
853 if (fabs(diff) > M_PI)
856 diff = diff - 2 * M_PI;
858 diff = 2 * M_PI + diff;
866 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOfPhi");
872 if (arguments.size() == 2) {
873 int iDaughterNumber = 0;
874 int jDaughterNumber = 0;
876 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
877 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
878 }
catch (std::invalid_argument&) {
879 B2FATAL(
"The two arguments of daughterDiffOfClusterPhi meta function must be integers!");
882 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
883 if (particle ==
nullptr)
884 return std::numeric_limits<double>::quiet_NaN();
885 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
886 return std::numeric_limits<double>::quiet_NaN();
889 if (std::isnan(var->function(particle->getDaughter(iDaughterNumber))) or std::isnan(var->function(particle->getDaughter(jDaughterNumber))))
890 return std::numeric_limits<float>::quiet_NaN();
892 double diff = var->function(particle->getDaughter(jDaughterNumber)) - var->function(particle->getDaughter(iDaughterNumber));
893 if (fabs(diff) > M_PI)
896 diff = diff - 2 * M_PI;
898 diff = 2 * M_PI + diff;
906 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOfClusterPhi");
912 if (arguments.size() == 4) {
913 int iDaughterNumber = 0, jDaughterNumber = 0, agrandDaughterNumber = 0, bgrandDaughterNumber = 0;
915 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
916 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
917 agrandDaughterNumber = Belle2::convertString<int>(arguments[2]);
918 bgrandDaughterNumber = Belle2::convertString<int>(arguments[3]);
919 }
catch (std::invalid_argument&) {
920 B2FATAL(
"The four arguments of grandDaughterDiffOfClusterPhi meta function must be integers!");
923 auto func = [var, iDaughterNumber, jDaughterNumber, agrandDaughterNumber,
924 bgrandDaughterNumber](
const Particle * particle) ->
double {
925 if (particle ==
nullptr)
926 return std::numeric_limits<double>::quiet_NaN();
927 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
928 return std::numeric_limits<double>::quiet_NaN();
929 if (agrandDaughterNumber >=
int((particle->getDaughter(iDaughterNumber))->getNDaughters()) || bgrandDaughterNumber >=
int((particle->getDaughter(jDaughterNumber))->getNDaughters()))
930 return std::numeric_limits<double>::quiet_NaN();
933 if (std::isnan(var->function((particle->getDaughter(iDaughterNumber))->getDaughter(agrandDaughterNumber))) or std::isnan(var->function((particle->getDaughter(jDaughterNumber))->getDaughter(bgrandDaughterNumber))))
934 return std::numeric_limits<float>::quiet_NaN();
936 double diff = var->function((particle->getDaughter(jDaughterNumber))->getDaughter(bgrandDaughterNumber)) - var->function((particle->getDaughter(iDaughterNumber))->getDaughter(agrandDaughterNumber));
937 if (fabs(diff) > M_PI)
940 diff = diff - 2 * M_PI;
942 diff = 2 * M_PI + diff;
950 B2FATAL(
"Wrong number of arguments for meta function grandDaughterDiffOfClusterPhi");
956 if (arguments.size() == 2) {
957 int iDaughterNumber = 0;
958 int jDaughterNumber = 0;
960 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
961 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
962 }
catch (std::invalid_argument&) {
963 B2FATAL(
"The two arguments of daughterDiffOfPhi meta function must be integers!");
966 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
967 if (particle ==
nullptr)
968 return std::numeric_limits<double>::quiet_NaN();
969 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
970 return std::numeric_limits<double>::quiet_NaN();
973 double diff = var->function(particle->getDaughter(jDaughterNumber)) - var->function(particle->getDaughter(iDaughterNumber));
974 if (fabs(diff) > M_PI)
977 diff = diff - 2 * M_PI;
979 diff = 2 * M_PI + diff;
987 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOfPhi");
993 if (arguments.size() == 2) {
994 int iDaughterNumber = 0;
995 int jDaughterNumber = 0;
997 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
998 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
999 }
catch (std::invalid_argument&) {
1000 B2FATAL(
"The two arguments of daughterDiffOfClusterPhi meta function must be integers!");
1003 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
1004 if (particle ==
nullptr)
1005 return std::numeric_limits<double>::quiet_NaN();
1006 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
1007 return std::numeric_limits<double>::quiet_NaN();
1010 if (std::isnan(var->function(particle->getDaughter(iDaughterNumber))) or std::isnan(var->function(particle->getDaughter(jDaughterNumber))))
1011 return std::numeric_limits<float>::quiet_NaN();
1013 double diff = var->function(particle->getDaughter(jDaughterNumber)) - var->function(particle->getDaughter(iDaughterNumber));
1014 if (fabs(diff) > M_PI)
1017 diff = diff - 2 * M_PI;
1019 diff = 2 * M_PI + diff;
1027 B2FATAL(
"Wrong number of arguments for meta function daughterDiffOfClusterPhi");
1033 if (arguments.size() == 3) {
1034 int iDaughterNumber = 0;
1035 int jDaughterNumber = 0;
1037 iDaughterNumber = Belle2::convertString<int>(arguments[0]);
1038 jDaughterNumber = Belle2::convertString<int>(arguments[1]);
1039 }
catch (std::invalid_argument&) {
1040 B2FATAL(
"First two arguments of daughterDiffOf meta function must be integers!");
1043 auto func = [var, iDaughterNumber, jDaughterNumber](
const Particle * particle) ->
double {
1044 if (particle ==
nullptr)
1045 return std::numeric_limits<double>::quiet_NaN();
1046 if (iDaughterNumber >=
int(particle->getNDaughters()) || jDaughterNumber >=
int(particle->getNDaughters()))
1047 return std::numeric_limits<double>::quiet_NaN();
1049 double iValue = var->function(particle->getDaughter(iDaughterNumber));
1050 double jValue = var->function(particle->getDaughter(jDaughterNumber));
1051 return (jValue - iValue) / (jValue + iValue);}
1055 B2FATAL(
"Wrong number of arguments for meta function daughterNormDiffOf");
1061 if (arguments.size() == 2) {
1062 int daughterNumber = 0;
1064 daughterNumber = Belle2::convertString<int>(arguments[0]);
1065 }
catch (std::invalid_argument&) {
1066 B2FATAL(
"First argument of daughterMotherDiffOf meta function must be integer!");
1069 auto func = [var, daughterNumber](
const Particle * particle) ->
double {
1070 if (particle ==
nullptr)
1071 return std::numeric_limits<double>::quiet_NaN();
1072 if (daughterNumber >=
int(particle->getNDaughters()))
1073 return std::numeric_limits<double>::quiet_NaN();
1075 double diff = var->function(particle) - var->function(particle->getDaughter(daughterNumber));
1080 B2FATAL(
"Wrong number of arguments for meta function daughterMotherDiffOf");
1086 if (arguments.size() == 2) {
1087 int daughterNumber = 0;
1089 daughterNumber = Belle2::convertString<int>(arguments[0]);
1090 }
catch (std::invalid_argument&) {
1091 B2FATAL(
"First argument of daughterMotherDiffOf meta function must be integer!");
1094 auto func = [var, daughterNumber](
const Particle * particle) ->
double {
1095 if (particle ==
nullptr)
1096 return std::numeric_limits<double>::quiet_NaN();
1097 if (daughterNumber >=
int(particle->getNDaughters()))
1098 return std::numeric_limits<double>::quiet_NaN();
1100 double daughterValue = var->function(particle->getDaughter(daughterNumber));
1101 double motherValue = var->function(particle);
1102 return (motherValue - daughterValue) / (motherValue + daughterValue);}
1106 B2FATAL(
"Wrong number of arguments for meta function daughterMotherNormDiffOf");
1112 if (arguments.size() == 2 || arguments.size() == 3) {
1114 auto func = [arguments](
const Particle * particle) ->
double {
1115 if (particle ==
nullptr)
1116 return std::numeric_limits<double>::quiet_NaN();
1118 std::vector<TLorentzVector> pDaus;
1122 for (
auto& generalizedIndex : arguments)
1124 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
1126 pDaus.push_back(frame.getMomentum(dauPart));
1128 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
1129 return std::numeric_limits<double>::quiet_NaN();
1134 if (pDaus.size() == 2)
1135 return pDaus[0].Vect().Angle(pDaus[1].Vect());
1137 return pDaus[2].Vect().Angle(pDaus[0].Vect() + pDaus[1].Vect());
1141 B2FATAL(
"Wrong number of arguments for meta function daughterAngle");
1147 if (arguments.size() == 2) {
1149 auto func = [arguments](
const Particle * particle) ->
double {
1151 return std::numeric_limits<double>::quiet_NaN();
1153 unsigned daughterIndex, grandDaughterIndex;
1155 daughterIndex = Belle2::convertString<int>(arguments[0]);
1156 grandDaughterIndex = Belle2::convertString<int>(arguments[1]);
1157 }
catch (std::invalid_argument&)
1159 B2FATAL(
"The arguments of grandDaughterDecayAngle have to be integers!");
1162 if (daughterIndex >= particle->getNDaughters())
1163 return std::numeric_limits<float>::quiet_NaN();
1165 const Particle* daughter = particle->getDaughter(daughterIndex);
1167 if (grandDaughterIndex >= daughter->getNDaughters())
1168 return std::numeric_limits<float>::quiet_NaN();
1170 TVector3 boost = - (daughter->get4Vector().BoostVector());
1172 TLorentzVector motherMomentum = - particle->get4Vector();
1173 motherMomentum.Boost(boost);
1175 TLorentzVector grandDaughterMomentum = daughter->getDaughter(grandDaughterIndex)->get4Vector();
1176 grandDaughterMomentum.Boost(boost);
1178 return motherMomentum.Angle(grandDaughterMomentum.Vect());
1182 B2FATAL(
"The meta variable grandDaughterDecayAngle needs exactly two integers as arguments!");
1188 if (arguments.size() == 2 || arguments.size() == 3) {
1189 std::vector<int> daughterIndices;
1191 for (
auto& argument : arguments) daughterIndices.push_back(Belle2::convertString<int>(argument));
1192 }
catch (std::invalid_argument&) {
1193 B2FATAL(
"The arguments of daughterClusterAngleInBetween meta function must be integers!");
1195 auto func = [daughterIndices](
const Particle * particle) ->
double {
1196 if (particle ==
nullptr)
1197 return std::numeric_limits<double>::quiet_NaN();
1198 if (daughterIndices.size() == 2)
1200 if (daughterIndices[0] >=
int(particle->getNDaughters()) || daughterIndices[1] >=
int(particle->getNDaughters()))
1201 return std::numeric_limits<double>::quiet_NaN();
1204 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1205 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1208 if (clusteri and clusterj) {
1209 ClusterUtils clusutils;
1210 TVector3 pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit)).Vect();
1211 TVector3 pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit)).Vect();
1212 return pi.Angle(pj);
1214 return std::numeric_limits<float>::quiet_NaN();
1216 }
else if (daughterIndices.size() == 3)
1218 if (daughterIndices[0] >=
int(particle->getNDaughters()) || daughterIndices[1] >=
int(particle->getNDaughters())
1219 || daughterIndices[2] >=
int(particle->getNDaughters()))
return std::numeric_limits<double>::quiet_NaN();
1222 const ECLCluster* clusteri = (particle->getDaughter(daughterIndices[0]))->getECLCluster();
1223 const ECLCluster* clusterj = (particle->getDaughter(daughterIndices[1]))->getECLCluster();
1224 const ECLCluster* clusterk = (particle->getDaughter(daughterIndices[2]))->getECLCluster();
1229 if (clusteri and clusterj and clusterk) {
1230 ClusterUtils clusutils;
1231 TVector3 pi = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusteri, clusteriBit)).Vect();
1232 TVector3 pj = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterj, clusterjBit)).Vect();
1233 TVector3 pk = frame.getMomentum(clusutils.Get4MomentumFromCluster(clusterk, clusterkBit)).Vect();
1234 return pk.Angle(pi + pj);
1236 return std::numeric_limits<float>::quiet_NaN();
1238 }
else return std::numeric_limits<double>::quiet_NaN();
1243 B2FATAL(
"Wrong number of arguments for meta function daughterClusterAngleInBetween");
1249 if (arguments.size() > 1) {
1250 std::vector<int> daughterIndices;
1252 for (
auto& argument : arguments) daughterIndices.push_back(Belle2::convertString<int>(argument));
1253 }
catch (std::invalid_argument&) {
1254 B2FATAL(
"The arguments of daughterInvM meta function must be integers!");
1256 auto func = [daughterIndices](
const Particle * particle) ->
double {
1257 if (particle ==
nullptr)
1258 return std::numeric_limits<float>::quiet_NaN();
1261 TLorentzVector pSum;
1263 for (
auto& index : daughterIndices)
1265 if (index >=
int(particle->getNDaughters())) {
1266 return std::numeric_limits<float>::quiet_NaN();
1267 }
else pSum += frame.getMomentum(particle->getDaughter(index));
1274 B2FATAL(
"Wrong number of arguments for meta function daughterInvM. At least two integers are needed.");
1280 if (arguments.size() == 2) {
1284 divideBy = Belle2::convertString<int>(arguments[1]);
1285 }
catch (std::invalid_argument&) {
1286 B2FATAL(
"Second argument of modulo meta function must be integer!");
1288 auto func = [var, divideBy](
const Particle * particle) ->
double {
return int(var->function(particle)) % divideBy; };
1291 B2FATAL(
"Wrong number of arguments for meta function modulo");
1297 if (arguments.size() == 1) {
1300 auto func = [var](
const Particle * particle) ->
double {
return std::isnan(var->function(particle)); };
1303 B2FATAL(
"Wrong number of arguments for meta function isNAN");
1309 if (arguments.size() == 2) {
1311 double defaultOutput;
1313 defaultOutput = Belle2::convertString<double>(arguments[1]);
1314 }
catch (std::invalid_argument&) {
1315 B2FATAL(
"The second argument of ifNANgiveX meta function must be a number!");
1317 auto func = [var, defaultOutput](
const Particle * particle) ->
double {
1318 double output = var->function(particle);
1319 if (std::isnan(output))
return defaultOutput;
1324 B2FATAL(
"Wrong number of arguments for meta function ifNANgiveX");
1330 if (arguments.size() == 1) {
1333 auto func = [var](
const Particle * particle) ->
double {
return std::isinf(var->function(particle)); };
1336 B2FATAL(
"Wrong number of arguments for meta function isInfinity");
1342 if (arguments.size() >= 2) {
1348 for (
size_t i = 1; i < arguments.size(); ++i) {
1350 finalMask |= Belle2::convertString<int>(arguments[i]);
1351 }
catch (std::invalid_argument&) {
1352 B2FATAL(
"The input flags to meta function unmask() should be integer!");
1358 auto func = [var, finalMask](
const Particle * particle) ->
double {
1359 int value = int(var->function(particle));
1362 if (std::isnan(value))
1363 return std::numeric_limits<double>::quiet_NaN();
1366 value &= (~finalMask);
1373 B2FATAL(
"Meta function unmask needs at least two arguments!");
1380 if (arguments.size() == 3) {
1382 std::string cutString = arguments[0];
1388 auto func = [cut, variableIfTrue, variableIfFalse](
const Particle * particle) ->
double {
1389 if (particle ==
nullptr)
1390 return std::numeric_limits<float>::quiet_NaN();
1391 if (cut->check(particle))
1392 return variableIfTrue->function(particle);
1394 return variableIfFalse->function(particle);
1399 B2FATAL(
"Wrong number of arguments for meta function conditionalVariableSelector");
1406 if (arguments.size() > 0) {
1407 std::vector<const Variable::Manager::Var*> variables;
1408 for (
auto& argument : arguments)
1411 auto func = [variables, arguments](
const Particle * particle) ->
double {
1412 double pValueProduct = 1.;
1413 for (
auto variable : variables)
1415 double pValue = variable->function(particle);
1419 pValueProduct *= pValue;
1421 double pValueSum = 1.;
1422 double factorial = 1.;
1423 for (
unsigned int i = 1; i < arguments.size(); ++i)
1426 pValueSum += pow(-std::log(pValueProduct), i) / factorial;
1428 return pValueProduct * pValueSum;
1432 B2FATAL(
"Wrong number of arguments for meta function pValueCombination");
1438 if (arguments.size() == 1) {
1440 auto func = [var](
const Particle * particle) ->
double {
return std::abs(var->function(particle)); };
1443 B2FATAL(
"Wrong number of arguments for meta function abs");
1449 if (arguments.size() == 2) {
1454 B2FATAL(
"One or both of the used variables doesn't exist!");
1456 auto func = [var1, var2](
const Particle * particle) ->
double {
1457 double max = var1->function(particle);
1458 if (max < var2->
function(particle))
1459 max = var2->function(particle);
1464 B2FATAL(
"Wrong number of arguments for meta function max");
1470 if (arguments.size() == 2) {
1475 B2FATAL(
"One or both of the used variables doesn't exist!");
1477 auto func = [var1, var2](
const Particle * particle) ->
double {
1478 double min = var1->function(particle);
1479 if (min > var2->function(particle))
1480 min = var2->function(particle);
1485 B2FATAL(
"Wrong number of arguments for meta function min");
1491 if (arguments.size() == 1) {
1493 auto func = [var](
const Particle * particle) ->
double {
return std::sin(var->function(particle)); };
1496 B2FATAL(
"Wrong number of arguments for meta function sin");
1502 if (arguments.size() == 1) {
1504 auto func = [var](
const Particle * particle) ->
double {
return std::cos(var->function(particle)); };
1507 B2FATAL(
"Wrong number of arguments for meta function cos");
1513 if (arguments.size() == 1) {
1515 auto func = [var](
const Particle * particle) ->
double {
return std::acos(var->function(particle)); };
1518 B2FATAL(
"Wrong number of arguments for meta function acos");
1524 if (arguments.size() == 1) {
1526 auto func = [var](
const Particle * particle) ->
double {
return std::exp(var->function(particle)); };
1529 B2FATAL(
"Wrong number of arguments for meta function exp");
1535 if (arguments.size() == 1) {
1537 auto func = [var](
const Particle * particle) ->
double {
return std::log(var->function(particle)); };
1540 B2FATAL(
"Wrong number of arguments for meta function log");
1546 if (arguments.size() == 1) {
1548 auto func = [var](
const Particle * particle) ->
double {
return std::log10(var->function(particle)); };
1551 B2FATAL(
"Wrong number of arguments for meta function log10");
1557 if (arguments.size() == 2) {
1558 int daughterNumber = 0;
1560 daughterNumber = Belle2::convertString<int>(arguments[0]);
1561 }
catch (std::invalid_argument&) {
1562 B2FATAL(
"First argument of daughter meta function must be integer!");
1565 auto func = [var, daughterNumber](
const Particle * particle) ->
double {
1566 if (particle ==
nullptr)
1567 return std::numeric_limits<float>::quiet_NaN();
1568 if (daughterNumber >=
int(particle->getNDaughters()))
1569 return std::numeric_limits<float>::quiet_NaN();
1571 return var->function(particle->getDaughter(daughterNumber));
1575 B2FATAL(
"Wrong number of arguments for meta function daughter");
1581 if (arguments.size() == 2) {
1582 int daughterNumber = 0;
1584 daughterNumber = Belle2::convertString<int>(arguments[0]);
1585 }
catch (std::invalid_argument&) {
1586 B2FATAL(
"First argument of mcDaughter meta function must be integer!");
1589 auto func = [var, daughterNumber](
const Particle * particle) ->
double {
1590 if (particle ==
nullptr)
1591 return std::numeric_limits<float>::quiet_NaN();
1592 if (particle->getMCParticle())
1594 if (daughterNumber >=
int(particle->getMCParticle()->getNDaughters())) {
1595 return std::numeric_limits<float>::quiet_NaN();
1597 Particle tempParticle = Particle(particle->getMCParticle()->getDaughters().at(daughterNumber));
1598 return var->function(&tempParticle);
1600 return std::numeric_limits<float>::quiet_NaN();
1605 B2FATAL(
"Wrong number of arguments for meta function mcDaughter");
1611 if (arguments.size() == 1) {
1613 auto func = [var](
const Particle * particle) ->
double {
1614 if (particle ==
nullptr)
1615 return std::numeric_limits<float>::quiet_NaN();
1616 if (particle->getMCParticle())
1618 if (particle->getMCParticle()->getMother() ==
nullptr) {
1619 return std::numeric_limits<float>::quiet_NaN();
1621 Particle tempParticle = Particle(particle->getMCParticle()->getMother());
1622 return var->function(&tempParticle);
1624 return std::numeric_limits<float>::quiet_NaN();
1629 B2FATAL(
"Wrong number of arguments for meta function mcMother");
1635 if (arguments.size() == 2) {
1636 int particleNumber = 0;
1638 particleNumber = Belle2::convertString<int>(arguments[0]);
1639 }
catch (std::invalid_argument&) {
1640 B2FATAL(
"First argument of genParticle meta function must be integer!");
1644 auto func = [var, particleNumber](
const Particle*) ->
double {
1645 StoreArray<MCParticle> mcParticles(
"MCParticles");
1646 if (particleNumber >= mcParticles.getEntries())
1648 return std::numeric_limits<float>::quiet_NaN();
1651 MCParticle* mcParticle = mcParticles[particleNumber];
1652 Particle part = Particle(mcParticle);
1653 return var->function(&part);
1657 B2FATAL(
"Wrong number of arguments for meta function genParticle");
1663 if (arguments.size() == 1) {
1666 auto func = [var](
const Particle*) ->
double {
1667 StoreArray<MCParticle> mcParticles(
"MCParticles");
1668 if (mcParticles.getEntries() == 0)
1670 return std::numeric_limits<float>::quiet_NaN();
1673 MCParticle* mcUpsilon4S = mcParticles[0];
1674 if (mcUpsilon4S->getPDG() != 300553)
1676 return std::numeric_limits<float>::quiet_NaN();
1679 Particle upsilon4S = Particle(mcUpsilon4S);
1680 return var->function(&upsilon4S);
1684 B2FATAL(
"Wrong number of arguments for meta function genUpsilon4S");
1690 if (arguments.size() == 4) {
1691 std::string listName = arguments[0];
1692 std::string rankedVariableName = arguments[1];
1693 std::string returnVariableName = arguments[2];
1694 std::string extraInfoName = rankedVariableName +
"_rank";
1697 rank = Belle2::convertString<int>(arguments[3]);
1698 }
catch (std::invalid_argument&) {
1699 B2ERROR(
"3rd argument of getVariableByRank meta function (Rank) must be an integer!");
1704 auto func = [var, rank, extraInfoName, listName](
const Particle*)->
double {
1705 StoreObjPtr<ParticleList> list(listName);
1707 const unsigned int numParticles = list->getListSize();
1708 for (
unsigned int i = 0; i < numParticles; i++)
1710 const Particle* p = list->getParticle(i);
1711 if (p->getExtraInfo(extraInfoName) == rank)
1712 return var->function(p);
1715 return std::numeric_limits<double>::signaling_NaN();
1719 B2FATAL(
"Wrong number of arguments for meta function getVariableByRank");
1725 if (arguments.size() == 1 or arguments.size() == 2) {
1727 std::string listName = arguments[0];
1728 std::string cutString =
"";
1730 if (arguments.size() == 2) {
1731 cutString = arguments[1];
1736 auto func = [listName, cut](
const Particle*) ->
double {
1738 StoreObjPtr<ParticleList> list(listName);
1740 for (
unsigned int i = 0; i < list->getListSize(); i++)
1742 const Particle* particle = list->getParticle(i);
1743 if (cut->check(particle)) {
1751 B2FATAL(
"Wrong number of arguments for meta function countInList");
1757 if (arguments.size() == 2 or arguments.size() == 3) {
1759 std::string roeListName = arguments[0];
1760 std::string cutString = arguments[1];
1762 if (arguments.size() == 2) {
1763 B2INFO(
"Use pdgCode 11 as default in meta variable veto, other arguments: " << roeListName <<
", " << cutString);
1766 pdgCode = Belle2::convertString<int>(arguments[2]);;
1767 }
catch (std::invalid_argument&) {
1768 B2FATAL(
"Third argument of veto meta function must be integer!");
1775 auto func = [roeListName, cut, pdgCode, flavourType](
const Particle * particle) ->
double {
1776 if (particle ==
nullptr)
1777 return std::numeric_limits<float>::quiet_NaN();
1778 StoreObjPtr<ParticleList> roeList(roeListName);
1779 TLorentzVector vec = particle->get4Vector();
1780 for (
unsigned int i = 0; i < roeList->getListSize(); i++)
1782 const Particle* roeParticle = roeList->getParticle(i);
1783 if (not particle->overlapsWith(roeParticle)) {
1784 TLorentzVector tempCombination = roeParticle->get4Vector() + vec;
1785 std::vector<int> indices = { particle->getArrayIndex(), roeParticle->getArrayIndex() };
1786 Particle tempParticle = Particle(tempCombination, pdgCode, flavourType, indices, particle->getArrayPointer());
1787 if (cut->check(&tempParticle)) {
1796 B2FATAL(
"Wrong number of arguments for meta function veto");
1802 if (arguments.size() == 1) {
1803 std::string cutString = arguments[0];
1805 auto func = [cut](
const Particle * particle) ->
double {
1806 if (particle ==
nullptr)
1807 return std::numeric_limits<float>::quiet_NaN();
1809 for (
auto& daughter : particle->getDaughters())
1811 if (cut->check(daughter))
1818 B2FATAL(
"Wrong number of arguments for meta function countDaughters");
1822 Manager::FunctionPtr numberOfNonOverlappingParticles(
const std::vector<std::string>& arguments)
1825 auto func = [arguments](
const Particle * particle) ->
double {
1827 unsigned _numberOfNonOverlappingParticles = 0;
1828 for (
const auto& listName : arguments)
1830 StoreObjPtr<ParticleList> list(listName);
1831 if (not list.isValid()) {
1832 B2FATAL(
"Invalid list named " << listName <<
" encountered in numberOfNonOverlappingParticles.");
1834 for (
unsigned int i = 0; i < list->getListSize(); i++) {
1835 const Particle* p = list->getParticle(i);
1836 if (not particle->overlapsWith(p)) {
1837 _numberOfNonOverlappingParticles++;
1841 return _numberOfNonOverlappingParticles;
1850 if (arguments.size() == 1) {
1852 auto func = [var](
const Particle * particle) ->
double {
1853 const MCParticle* mcp = particle->getMCParticle();
1856 return std::numeric_limits<float>::quiet_NaN();
1858 Particle tmpPart(mcp);
1859 return var->function(&tmpPart);
1863 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
1869 if (arguments.size() == 1) {
1872 inputPDG = Belle2::convertString<int>(arguments[0]);
1873 }
catch (std::invalid_argument&) {
1874 B2FATAL(
"Argument must be an integer value.");
1877 auto func = [inputPDG](
const Particle * particle) ->
double{
1878 const MCParticle* mcp = particle->getRelated<MCParticle>();
1882 if (std::abs(mcp->getPDG()) == inputPDG)
1891 B2FATAL(
"Wrong number of arguments for meta function matchedMC");
1896 if (arguments.size() == 1) {
1897 std::string listName = arguments[0];
1898 auto func = [listName](
const Particle * particle) ->
double {
1901 StoreObjPtr<ParticleList> listOfParticles(listName);
1903 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
1904 double totalEnergy = 0;
1905 int nParticles = listOfParticles->getListSize();
1906 for (
int i = 0; i < nParticles; i++)
1908 const Particle* part = listOfParticles->getParticle(i);
1910 totalEnergy += frame.getMomentum(part).E();
1917 B2FATAL(
"Wrong number of arguments for meta function totalEnergyOfParticlesInList");
1923 if (arguments.size() == 1) {
1924 std::string listName = arguments[0];
1925 auto func = [listName](
const Particle*) ->
double {
1926 StoreObjPtr<ParticleList> listOfParticles(listName);
1928 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPxOfParticlesInList");
1930 int nParticles = listOfParticles->getListSize();
1932 for (
int i = 0; i < nParticles; i++)
1934 const Particle* part = listOfParticles->getParticle(i);
1935 totalPx += frame.getMomentum(part).Px();
1941 B2FATAL(
"Wrong number of arguments for meta function totalPxOfParticlesInList");
1947 if (arguments.size() == 1) {
1948 std::string listName = arguments[0];
1949 auto func = [listName](
const Particle*) ->
double {
1950 StoreObjPtr<ParticleList> listOfParticles(listName);
1952 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPyOfParticlesInList");
1954 int nParticles = listOfParticles->getListSize();
1956 for (
int i = 0; i < nParticles; i++)
1958 const Particle* part = listOfParticles->getParticle(i);
1959 totalPy += frame.getMomentum(part).Py();
1965 B2FATAL(
"Wrong number of arguments for meta function totalPyOfParticlesInList");
1971 if (arguments.size() == 1) {
1972 std::string listName = arguments[0];
1973 auto func = [listName](
const Particle*) ->
double {
1974 StoreObjPtr<ParticleList> listOfParticles(listName);
1976 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalPzOfParticlesInList");
1978 int nParticles = listOfParticles->getListSize();
1980 for (
int i = 0; i < nParticles; i++)
1982 const Particle* part = listOfParticles->getParticle(i);
1983 totalPz += frame.getMomentum(part).Pz();
1989 B2FATAL(
"Wrong number of arguments for meta function totalPzOfParticlesInList");
1995 if (arguments.size() > 0) {
1997 auto func = [arguments](
const Particle * particle) ->
double {
1999 TLorentzVector total4Vector;
2001 std::vector<Particle*> particlePool;
2004 for (
const auto& argument : arguments)
2006 StoreObjPtr <ParticleList> listOfParticles(argument);
2008 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << argument <<
" given to invMassInLists");
2009 int nParticles = listOfParticles->getListSize();
2010 for (
int i = 0; i < nParticles; i++) {
2011 bool overlaps =
false;
2012 Particle* part = listOfParticles->getParticle(i);
2013 for (
auto poolPart : particlePool) {
2014 if (part->overlapsWith(poolPart)) {
2020 total4Vector += part->get4Vector();
2021 particlePool.push_back(part);
2025 double invariantMass = total4Vector.M();
2026 return invariantMass;
2031 B2FATAL(
"Wrong number of arguments for meta function invMassInLists");
2035 Manager::FunctionPtr totalECLEnergyOfParticlesInList(
const std::vector<std::string>& arguments)
2037 if (arguments.size() == 1) {
2038 std::string listName = arguments[0];
2039 auto func = [listName](
const Particle * particle) ->
double {
2042 StoreObjPtr<ParticleList> listOfParticles(listName);
2044 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to totalEnergyOfParticlesInList");
2045 double totalEnergy = 0;
2046 int nParticles = listOfParticles->getListSize();
2047 for (
int i = 0; i < nParticles; i++)
2049 const Particle* part = listOfParticles->getParticle(i);
2050 const ECLCluster* cluster = part->getECLCluster();
2052 if (cluster !=
nullptr) {
2053 totalEnergy += cluster->getEnergy(clusterHypothesis);
2061 B2FATAL(
"Wrong number of arguments for meta function totalECLEnergyOfParticlesInList");
2067 if (arguments.size() == 1) {
2068 std::string listName = arguments[0];
2069 auto func = [listName](
const Particle*) ->
double {
2070 StoreObjPtr<ParticleList> listOfParticles(listName);
2072 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxPtInList");
2073 int nParticles = listOfParticles->getListSize();
2076 for (
int i = 0; i < nParticles; i++)
2078 const Particle* part = listOfParticles->getParticle(i);
2079 const double Pt = frame.getMomentum(part).Pt();
2080 if (Pt > maxPt) maxPt = Pt;
2086 B2FATAL(
"Wrong number of arguments for meta function maxPtInList");
2090 Manager::FunctionPtr eclClusterTrackMatchedWithCondition(
const std::vector<std::string>& arguments)
2092 if (arguments.size() <= 1) {
2094 std::string cutString;
2095 if (arguments.size() == 1)
2096 cutString = arguments[0];
2098 auto func = [cut](
const Particle * particle) ->
double {
2100 if (particle ==
nullptr)
2101 return std::numeric_limits<double>::quiet_NaN();
2103 const ECLCluster* cluster = particle->getECLCluster();
2107 auto tracks = cluster->getRelationsFrom<Track>();
2109 for (
const auto& track : tracks) {
2112 if (cut->check(&trackParticle))
2117 return std::numeric_limits<double>::quiet_NaN();
2121 B2FATAL(
"Wrong number of arguments for meta function eclClusterSpecialTrackMatched");
2127 if (arguments.size() == 2) {
2128 std::string listName = arguments[0];
2131 auto func = [listName, var](
const Particle*) ->
double {
2132 StoreObjPtr<ParticleList> listOfParticles(listName);
2134 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to averageValueInList");
2135 int nParticles = listOfParticles->getListSize();
2137 for (
int i = 0; i < nParticles; i++)
2139 const Particle* part = listOfParticles->getParticle(i);
2140 average += var->function(part) / nParticles;
2146 B2FATAL(
"Wrong number of arguments for meta function averageValueInList");
2152 if (arguments.size() == 2) {
2153 std::string listName = arguments[0];
2156 auto func = [listName, var](
const Particle*) ->
double {
2157 StoreObjPtr<ParticleList> listOfParticles(listName);
2159 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid list name " << listName <<
" given to medianValueInList");
2160 int nParticles = listOfParticles->getListSize();
2161 if (nParticles == 0)
2163 return std::numeric_limits<double>::quiet_NaN();
2165 std::vector<double> valuesInList;
2166 for (
int i = 0; i < nParticles; i++)
2168 const Particle* part = listOfParticles->getParticle(i);
2169 valuesInList.push_back(var->function(part));
2171 std::sort(valuesInList.begin(), valuesInList.end());
2172 if (nParticles % 2 != 0)
2174 return valuesInList[nParticles / 2];
2176 return 0.5 * (valuesInList[nParticles / 2] + valuesInList[nParticles / 2 - 1]);
2181 B2FATAL(
"Wrong number of arguments for meta function medianValueInList");
2188 if (arguments.size() != 1)
2189 B2FATAL(
"Wrong number of arguments for meta function angleToClosestInList");
2191 std::string listname = arguments[0];
2193 auto func = [listname](
const Particle * particle) ->
double {
2195 StoreObjPtr<ParticleList> list(listname);
2196 if (not list.isValid())
2197 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToClosestInList");
2200 if (list->getListSize() == 0)
2201 return std::numeric_limits<double>::quiet_NaN();
2205 const auto p_this = frame.getMomentum(particle).Vect();
2208 double minAngle = 2 * M_PI;
2209 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2211 const Particle* compareme = list->getParticle(i);
2212 const auto p_compare = frame.getMomentum(compareme).Vect();
2213 double angle = p_compare.Angle(p_this);
2214 if (minAngle > angle) minAngle = angle;
2224 if (arguments.size() != 2)
2225 B2FATAL(
"Wrong number of arguments for meta function closestInList");
2227 std::string listname = arguments[0];
2232 auto func = [listname, var](
const Particle * particle) ->
double {
2234 StoreObjPtr<ParticleList> list(listname);
2235 if (not list.isValid())
2236 B2FATAL(
"Invalid particle list name " << listname <<
" given to closestInList");
2240 const auto p_this = frame.getMomentum(particle).Vect();
2243 double minAngle = 2 * M_PI;
2245 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2247 const Particle* compareme = list->getParticle(i);
2248 const auto p_compare = frame.getMomentum(compareme).Vect();
2249 double angle = p_compare.Angle(p_this);
2250 if (minAngle > angle) {
2257 if (iClosest == -1)
return std::numeric_limits<double>::quiet_NaN();
2259 return var->function(list->getParticle(iClosest));
2267 if (arguments.size() != 1)
2268 B2FATAL(
"Wrong number of arguments for meta function angleToMostB2BInList");
2270 std::string listname = arguments[0];
2272 auto func = [listname](
const Particle * particle) ->
double {
2274 StoreObjPtr<ParticleList> list(listname);
2275 if (not list.isValid())
2276 B2FATAL(
"Invalid particle list name " << listname <<
" given to angleToMostB2BInList");
2279 if (list->getListSize() == 0)
2280 return std::numeric_limits<double>::quiet_NaN();
2284 const auto p_this = frame.getMomentum(particle).Vect();
2288 double maxAngle = 0;
2289 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2291 const Particle* compareme = list->getParticle(i);
2292 const auto p_compare = frame.getMomentum(compareme).Vect();
2293 double angle = p_compare.Angle(p_this);
2294 if (maxAngle < angle) maxAngle = angle;
2304 if (arguments.size() != 2)
2305 B2FATAL(
"Wrong number of arguments for meta function mostB2BInList");
2307 std::string listname = arguments[0];
2312 auto func = [listname, var](
const Particle * particle) ->
double {
2314 StoreObjPtr<ParticleList> list(listname);
2315 if (not list.isValid())
2316 B2FATAL(
"Invalid particle list name " << listname <<
" given to mostB2BInList");
2320 const auto p_this = frame.getMomentum(particle).Vect();
2324 double maxAngle = -1.0;
2326 for (
unsigned int i = 0; i < list->getListSize(); ++i)
2328 const Particle* compareme = list->getParticle(i);
2329 const auto p_compare = frame.getMomentum(compareme).Vect();
2330 double angle = p_compare.Angle(p_this);
2331 if (maxAngle < angle) {
2338 if (iMostB2B == -1)
return std::numeric_limits<double>::quiet_NaN();
2340 return var->function(list->getParticle(iMostB2B));
2347 if (arguments.size() == 1) {
2348 std::string listName = arguments[0];
2349 auto func = [listName](
const Particle*) ->
double {
2350 StoreObjPtr<ParticleList> listOfParticles(listName);
2352 if (!(listOfParticles.isValid())) B2FATAL(
"Invalid Listname " << listName <<
" given to maxOpeningAngleInList");
2353 int nParticles = listOfParticles->getListSize();
2355 if (nParticles < 2)
return std::numeric_limits<double>::quiet_NaN();
2358 double maxOpeningAngle = -1;
2359 for (
int i = 0; i < nParticles; i++)
2361 TVector3
v1 = frame.getMomentum(listOfParticles->getParticle(i)).Vect();
2362 for (
int j = i + 1; j < nParticles; j++) {
2363 TVector3
v2 = frame.getMomentum(listOfParticles->getParticle(j)).Vect();
2364 const double angle =
v1.Angle(v2);
2365 if (angle > maxOpeningAngle) maxOpeningAngle = angle;
2368 return maxOpeningAngle;
2372 B2FATAL(
"Wrong number of arguments for meta function maxOpeningAngleInList");
2379 if (arguments.size() >= 2) {
2384 auto func = [var, arguments](
const Particle * particle) ->
double {
2385 if (particle ==
nullptr)
2387 B2WARNING(
"Trying to access a daughter that does not exist. Skipping");
2388 return std::numeric_limits<float>::quiet_NaN();
2393 TLorentzVector pSum(0, 0, 0, 0);
2397 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++)
2399 auto generalizedIndex = arguments[iCoord];
2400 const Particle* dauPart = particle->getParticleFromGeneralizedIndexString(generalizedIndex);
2402 pSum += frame.getMomentum(dauPart);
2404 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << generalizedIndex);
2405 return std::numeric_limits<float>::quiet_NaN();
2410 Particle* sumOfDaughters =
new Particle(pSum, 100);
2413 return var->function(sumOfDaughters);
2417 B2FATAL(
"Wrong number of arguments for meta function daughterCombination");
2422 Manager::FunctionPtr useAlternativeDaughterHypothesis(
const std::vector<std::string>& arguments)
2435 if (arguments.size() >= 2) {
2446 std::vector<unsigned int>indexesToBeReplaced = {};
2447 std::vector<double>massesToBeReplaced = {};
2450 for (
unsigned int iCoord = 1; iCoord < arguments.size(); iCoord++) {
2451 auto replacedDauString = arguments[iCoord];
2453 std::vector<std::string> indexAndMass;
2454 boost::split(indexAndMass, replacedDauString, boost::is_any_of(
":"));
2457 if (indexAndMass.size() > 2) {
2458 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 "
2459 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
2463 if (indexAndMass.size() < 2) {
2464 B2WARNING(
"The string indicating which daughter's mass should be replaced contains only one colon-separated element instead of two. The offending string is "
2465 << replacedDauString <<
", while a correct syntax looks like 0:K+.");
2472 dauIndex = Belle2::convertString<int>(indexAndMass[0]);
2473 }
catch (std::invalid_argument&) {
2474 B2FATAL(
"Found the string " << indexAndMass[0] <<
"instead of a daughter index.");
2478 TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(indexAndMass[1].c_str());
2480 B2WARNING(
"Particle not in evt.pdl file! " << indexAndMass[1]);
2485 int pdgCode = particlePDG->PdgCode();
2486 double dauNewMass = TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass() ;
2487 indexesToBeReplaced.push_back(dauIndex);
2488 massesToBeReplaced.push_back(dauNewMass);
2497 auto func = [var, indexesToBeReplaced, massesToBeReplaced](
const Particle * particle) ->
double {
2498 if (particle ==
nullptr)
2500 B2WARNING(
"Trying to access a particle that does not exist. Skipping");
2501 return std::numeric_limits<float>::quiet_NaN();
2507 TLorentzVector pSum(0, 0, 0, 0);
2509 for (
unsigned int iDau = 0; iDau < particle->getNDaughters(); iDau++)
2511 const Particle* dauPart = particle->getDaughter(iDau);
2513 B2WARNING(
"Trying to access a daughter that does not exist. Index = " << iDau);
2514 return std::numeric_limits<float>::quiet_NaN();
2517 TLorentzVector dauMom = frame.getMomentum(dauPart);
2521 for (
unsigned int iReplace = 0; iReplace < indexesToBeReplaced.size(); iReplace++) {
2522 if (indexesToBeReplaced[iReplace] == iDau) {
2523 double p_x = dauMom.Vect().Px();
2524 double p_y = dauMom.Vect().Py();
2525 double p_z = dauMom.Vect().Pz();
2526 dauMom.SetXYZM(p_x, p_y, p_z, massesToBeReplaced[iReplace]);
2530 pSum = pSum + dauMom;
2534 Particle* sumOfDaughters =
new Particle(pSum, 100);
2537 return var->function(sumOfDaughters);
2542 B2FATAL(
"Wrong number of arguments for meta function useAlternativeDaughterHypothesis");
2548 if (arguments.size() == 2) {
2550 std::string arg = arguments[0];
2551 std::string variable_of_interest = arguments[1];
2552 TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(arg.c_str());
2554 if (part !=
nullptr) {
2555 pdg_code = std::abs(part->PdgCode());
2558 pdg_code = Belle2::convertString<int>(arg);
2559 }
catch (std::exception& e) {}
2562 if (pdg_code == -1) {
2563 B2FATAL(
"Ancestor " + arg +
" is not recognised. Please provide valid PDG code or particle name.");
2566 auto func = [pdg_code, variable_of_interest](
const Particle * particle) ->
double {
2567 const Particle* p = particle;
2570 if ((ancestor_level <= 0) or (std::isnan(ancestor_level)))
2572 return std::numeric_limits<float>::quiet_NaN();
2575 const MCParticle* i_p = p->getMCParticle();
2577 for (
int a = 0; a < ancestor_level ; a = a + 1)
2579 i_p = i_p->getMother();
2581 const Particle* m_p =
new Particle(i_p);
2586 B2FATAL(
"Wrong number of arguments for meta function varForFirstMCAncestorOfType (expected 2: type and variable of interest)");
2594 VARIABLE_GROUP(
"MetaFunctions");
2595 REGISTER_VARIABLE(
"nCleanedECLClusters(cut)", nCleanedECLClusters,
2596 "[Eventbased] Returns the number of clean Clusters in the event\n"
2597 "Clean clusters are defined by the clusters which pass the given cut assuming a photon hypothesis.");
2598 REGISTER_VARIABLE(
"nCleanedTracks(cut)", nCleanedTracks,
2599 "[Eventbased] Returns the number of clean Tracks in the event\n"
2600 "Clean tracks are defined by the tracks which pass the given cut assuming a pion hypothesis.");
2601 REGISTER_VARIABLE(
"formula(v1 + v2 * [v3 - v4] / v5^v6)", formula, R
"DOCSTRING(
2602 Returns the result of the given formula, where v1 to vN are variables or floating
2603 point numbers. Currently the only supported operations are addition (``+``),
2604 subtraction (``-``), multiplication (``*``), division (``/``) and power (``^``
2605 or ``**``). Parenthesis can be in the form of square brackets ``[v1 * v2]``
2606 or normal brackets ``(v1 * v2)``. It will work also with variables taking
2607 arguments. Operator precedence is taken into account. For example ::
2609 (daughter(0, E) + daughter(1, E))**2 - p**2 + 0.138
2611 .. versionchanged:: release-03-00-00
2612 now both, ``[]`` and ``()`` can be used for grouping operations, ``**`` can
2613 be used for exponent and float literals are possible directly in the
2616 REGISTER_VARIABLE("useRestFrame(variable)", useRestFrame,
2617 "Returns the value of the variable using the rest frame of the given particle as current reference frame.\n"
2618 "E.g. ``useRestFrame(daughter(0, p))`` returns the total momentum of the first daughter in its mother's rest-frame");
2619 REGISTER_VARIABLE(
"useCMSFrame(variable)", useCMSFrame,
2620 "Returns the value of the variable using the CMS frame as current reference frame.\n"
2621 "E.g. ``useCMSFrame(E)`` returns the energy of a particle in the CMS frame.");
2622 REGISTER_VARIABLE(
"useLabFrame(variable)", useLabFrame, R
"DOC(
2623 Returns the value of ``variable`` in the *lab* frame.
2626 The lab frame is the default reference frame, usually you don't need to use this meta-variable.
2627 E.g. ``useLabFrame(E)`` returns the energy of a particle in the Lab frame, same as just ``E``.
2629 Specifying the lab frame is useful in some corner-cases. For example:
2630 ``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.
2632 REGISTER_VARIABLE("useTagSideRecoilRestFrame(variable, daughterIndexTagB)", useTagSideRecoilRestFrame,
2633 "Returns the value of the variable in the rest frame of the recoiling particle to the tag side B meson.\n"
2634 "The variable should only be applied to an Upsilon(4S) list.\n"
2635 "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.");
2636 REGISTER_VARIABLE(
"passesCut(cut)", passesCut,
2637 "Returns 1 if particle passes the cut otherwise 0.\n"
2638 "Useful if you want to write out if a particle would have passed a cut or not.\n"
2639 "Returns NaN if particle is a nullptr.");
2640 REGISTER_VARIABLE(
"passesEventCut(cut)", passesEventCut,
2641 "[Eventbased] Returns 1 if event passes the cut otherwise 0.\n"
2642 "Useful if you want to select events passing a cut without looping into particles, such as for skimming.\n");
2643 REGISTER_VARIABLE(
"countDaughters(cut)", countDaughters,
2644 "Returns number of direct daughters which satisfy the cut.\n"
2645 "Used by the skimming package (for what exactly?)\n"
2646 "Returns NaN if particle is a nullptr.");
2647 REGISTER_VARIABLE(
"varFor(pdgCode, variable)", varFor,
2648 "Returns the value of the variable for the given particle if its abs(pdgCode) agrees with the given one.\n"
2649 "E.g. ``varFor(11, p)`` returns the momentum if the particle is an electron or a positron.");
2650 REGISTER_VARIABLE(
"varForMCGen(variable)", varForMCGen,
2651 "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"
2652 "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"
2653 "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.");
2654 REGISTER_VARIABLE(
"nParticlesInList(particleListName)", nParticlesInList,
2655 "[Eventbased] Returns number of particles in the given particle List.");
2656 REGISTER_VARIABLE(
"isInList(particleListName)", isInList,
2657 "Returns 1.0 if the particle is in the list provided, 0.0 if not. Note that this only checks the particle given. For daughters of composite particles, please see :b2:var:`isDaughterOfList`.");
2658 REGISTER_VARIABLE(
"isDaughterOfList(particleListNames)", isDaughterOfList,
2659 "Returns 1 if the given particle is a daughter of at least one of the particles in the given particle Lists.");
2660 REGISTER_VARIABLE(
"isDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isDescendantOfList, R
"DOC(
2661 Returns 1 if the given particle appears in the decay chain of the particles in the given ParticleLists.
2663 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
2665 * ``isDescendantOfList(<particle_list>,1)`` returns 1 if particle is a daughter of the list,
2666 * ``isDescendantOfList(<particle_list>,2)`` returns 1 if particle is a granddaughter of the list,
2667 * ``isDescendantOfList(<particle_list>,3)`` returns 1 if particle is a great-granddaughter of the list, etc.
2668 * Default value is ``-1`` that is inclusive for all generations.
2670 REGISTER_VARIABLE("isMCDescendantOfList(particleListName[, anotherParticleListName][, generationFlag = -1])", isMCDescendantOfList, R
"DOC(
2671 Returns 1 if the given particle is linked to the same MC particle as any reconstructed daughter of the decay lists.
2673 Passing an integer as the last argument, allows to check if the particle belongs to the specific generation:
2675 * ``isMCDescendantOfList(<particle_list>,1)`` returns 1 if particle is matched to the same particle as any daughter of the list,
2676 * ``isMCDescendantOfList(<particle_list>,2)`` returns 1 if particle is matched to the same particle as any granddaughter of the list,
2677 * ``isMCDescendantOfList(<particle_list>,3)`` returns 1 if particle is matched to the same particle as any great-granddaughter of the list, etc.
2678 * Default value is ``-1`` that is inclusive for all generations.
2680 It makes only sense for lists created with `fillParticleListFromMC` function with ``addDaughters=True`` argument.
2683 REGISTER_VARIABLE("sourceObjectIsInList(particleListName)", sourceObjectIsInList, R
"DOC(
2684 Returns 1.0 if the underlying mdst object (e.g. track, or cluster) was used to create a particle in ``particleListName``, 0.0 if not.
2687 This only makes sense for particles that are not composite. Returns -1 for composite particles.
2690 REGISTER_VARIABLE("mcParticleIsInMCList(particleListName)", mcParticleIsInMCList, R
"DOC(
2691 Returns 1.0 if the particle's matched MC particle is also matched to a particle in ``particleListName``
2692 (or if either of the lists were filled from generator level `modularAnalysis.fillParticleListFromMC`.)
2694 .. seealso:: :b2:var:`isMCDescendantOfList` to check daughters.
2697 REGISTER_VARIABLE("isGrandDaughterOfList(particleListNames)", isGrandDaughterOfList,
2698 "Returns 1 if the given particle is a grand daughter of at least one of the particles in the given particle Lists.");
2699 REGISTER_VARIABLE(
"daughter(i, variable)", daughter,
2700 "Returns value of variable for the i-th daughter. E.g.\n"
2701 " - ``daughter(0, p)`` returns the total momentum of the first daughter.\n"
2702 " - ``daughter(0, daughter(1, p)`` returns the total momentum of the second daughter of the first daughter.\n\n"
2703 "Returns NaN if particle is nullptr or if the given daughter-index is out of bound (>= amount of daughters).");
2704 REGISTER_VARIABLE(
"mcDaughter(i, variable)", mcDaughter,
2705 "Returns the value of the requested variable for the i-th Monte Carlo daughter of the particle.\n"
2706 "Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,"
2707 "or if the i-th MC daughter does not exist.\n"
2708 "E.g. ``mcDaughter(0, PDG)`` will return the PDG code of the first MC daughter of the matched MC"
2709 "particle of the reconstructed particle the function is applied to./n"
2710 "The meta variable can also be nested: ``mcDaughter(0, mcDaughter(1, PDG))``.");
2711 REGISTER_VARIABLE(
"mcMother(variable)", mcMother,
2712 "Returns the value of the requested variable for the Monte Carlo mother of the particle.\n"
2713 "Returns NaN if the particle is nullptr, if the particle is not matched to an MC particle,"
2714 "or if the MC mother does not exist.\n"
2715 "E.g. ``mcMother(PDG)`` will return the PDG code of the MC mother of the matched MC"
2716 "particle of the reconstructed particle the function is applied to.\n"
2717 "The meta variable can also be nested: ``mcMother(mcMother(PDG))``.");
2718 REGISTER_VARIABLE(
"genParticle(index, variable)", genParticle, R
"DOC(
2719 [Eventbased] Returns the ``variable`` for the ith generator particle.
2720 The arguments of the function must be the ``index`` of the particle in the MCParticle Array,
2721 and ``variable``, the name of the function or variable for that generator particle.
2722 If ``index`` goes beyond the length of the MCParticles array, NaN will be returned.
2724 E.g. ``genParticle(0, p)`` returns the total momentum of the first MCParticle, which is
2725 the Upsilon(4S) in a generic decay.
2726 ``genParticle(0, mcDaughter(1, p)`` returns the total momentum of the second daughter of
2727 the first MC Particle, which is the momentum of the second B meson in a generic decay.
2729 REGISTER_VARIABLE("genUpsilon4S(variable)", genUpsilon4S, R
"DOC(
2730 [Eventbased] Returns the ``variable`` evaluated for the generator-level :math:`\Upsilon(4S)`.
2731 If no generator level :math:`\Upsilon(4S)` exists for the event, NaN will be returned.
2733 E.g. ``genUpsilon4S(p)`` returns the total momentum of the :math:`\Upsilon(4S)` in a generic decay.
2734 ``genUpsilon4S(mcDaughter(1, p)`` returns the total momentum of the second daughter of the
2735 generator-level :math:`\Upsilon(4S)` (i.e. the momentum of the second B meson in a generic decay.
2737 REGISTER_VARIABLE("daughterProductOf(variable)", daughterProductOf,
2738 "Returns product of a variable over all daughters.\n"
2739 "E.g. ``daughterProductOf(extraInfo(SignalProbability))`` returns the product of the SignalProbabilitys of all daughters.");
2740 REGISTER_VARIABLE(
"daughterSumOf(variable)", daughterSumOf,
2741 "Returns sum of a variable over all daughters.\n"
2742 "E.g. ``daughterSumOf(nDaughters)`` returns the number of grand-daughters.");
2743 REGISTER_VARIABLE(
"daughterLowest(variable)", daughterLowest,
2744 "Returns the lowest value of the given variable among all daughters.\n"
2745 "E.g. ``useCMSFrame(daughterLowest(p))`` returns the lowest momentum in CMS frame.");
2746 REGISTER_VARIABLE(
"daughterHighest(variable)", daughterHighest,
2747 "Returns the highest value of the given variable among all daughters.\n"
2748 "E.g. ``useCMSFrame(daughterHighest(p))`` returns the highest momentum in CMS frame.");
2749 REGISTER_VARIABLE(
"daughterDiffOf(i, j, variable)", daughterDiffOf,
2750 "Returns the difference of a variable between the two given daughters.\n"
2751 "E.g. ``useRestFrame(daughterDiffOf(0, 1, p))`` returns the momentum difference between first and second daughter in the rest frame of the given particle.\n"
2752 "(That means that it returns :math:`p_j - p_i`)\n"
2753 "Nota Bene: for the particular case 'variable=phi' you should use the :b2:var:`daughterDiffOfPhi` function.");
2754 REGISTER_VARIABLE(
"grandDaughterDiffOf(i, j, variable)", grandDaughterDiffOf,
2755 "Returns the difference of a variable between the first daughters of the two given daughters.\n"
2756 "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"
2757 "(That means that it returns :math:`p_j - p_i`)\n"
2758 "Nota Bene: for the particular case 'variable=phi' you should use the :b2:var:`grandDaughterDiffOfPhi` function.");
2759 REGISTER_VARIABLE(
"daughterDiffOfPhi(i, j)", daughterDiffOfPhi,
2760 "Returns the difference in :math:`\\phi` between the two given daughters.\n"
2761 "The difference is signed and takes account of the ordering of the given daughters.\n"
2762 "The function returns :math:`\\phi_j - \\phi_i`.\n"
2763 "For a generic variable difference, see :b2:var:`daughterDiffOf`.");
2764 REGISTER_VARIABLE(
"grandDaughterDiffOfPhi(i, j)", grandDaughterDiffOfPhi,
2765 "Returns the difference in :math:`\\phi` between the first daughters of the two given daughters.\n"
2766 "The difference is signed and takes account of the ordering of the given daughters.\n"
2767 "The function returns :math:`\\phi_j - \\phi_i`.\n");
2768 REGISTER_VARIABLE(
"daughterDiffOfClusterPhi(i, j)", daughterDiffOfClusterPhi,
2769 "Returns the difference in :math:`\\phi` between the ECLClusters of two given daughters.\n"
2770 "The difference is signed and takes account of the ordering of the given daughters.\n"
2771 "The function returns :math:`\\phi_j - \\phi_i`.\n"
2772 "The function returns NaN if at least one of the daughters is not matched to or not based on an ECLCluster.\n"
2773 "For a generic variable difference, see :b2:var:`daughterDiffOf`.");
2774 REGISTER_VARIABLE(
"grandDaughterDiffOfClusterPhi(i, j)", grandDaughterDiffOfClusterPhi,
2775 "Returns the difference in :math:`\\phi` between the ECLClusters of the daughters of the two given daughters.\n"
2776 "The difference is signed and takes account of the ordering of the given daughters.\n"
2777 "The function returns :math:`\\phi_j - \\phi_i`.\n"
2778 "The function returns NaN if at least one of the daughters is not matched to or not based on an ECLCluster.\n");
2779 REGISTER_VARIABLE(
"daughterDiffOfPhiCMS(i, j)", daughterDiffOfPhiCMS,
2780 "Returns the difference in :math:`\\phi` between the two given daughters in the CMS frame.\n"
2781 "The difference is signed and takes account of the ordering of the given daughters.\n"
2782 "The function returns :math:`\\phi_j - \\phi_i`.\n"
2783 "For a generic variable difference, see :b2:var:`daughterDiffOf`.");
2784 REGISTER_VARIABLE(
"daughterDiffOfClusterPhiCMS(i, j)", daughterDiffOfClusterPhiCMS,
2785 "Returns the difference in :math:`\\phi` between the ECLClusters of two given daughters in the CMS frame.\n"
2786 "The difference is signed and takes account of the ordering of the given daughters.\n"
2787 "The function returns :math:`\\phi_j - \\phi_i``.\n"
2788 "The function returns NaN if at least one of the daughters is not matched to or not based on an ECLCluster.\n"
2789 "For a generic variable difference, see :b2:var:`daughterDiffOf`.");
2790 REGISTER_VARIABLE(
"daughterNormDiffOf(i, j, variable)", daughterNormDiffOf,
2791 "Returns the normalized difference of a variable between the two given daughters.\n"
2792 "E.g. ``daughterNormDiffOf(0, 1, p)`` returns the normalized momentum difference between first and second daughter in the lab frame.");
2793 REGISTER_VARIABLE(
"daughterMotherDiffOf(i, variable)", daughterMotherDiffOf,
2794 "Returns the difference of a variable between the given daughter and the mother particle itself.\n"
2795 "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.");
2796 REGISTER_VARIABLE(
"daughterMotherNormDiffOf(i, variable)", daughterMotherNormDiffOf,
2797 "Returns the normalized difference of a variable between the given daughter and the mother particle itself.\n"
2798 "E.g. ``daughterMotherNormDiffOf(1, p)`` returns the normalized momentum difference between the given particle and its second daughter in the lab frame.");
2799 REGISTER_VARIABLE(
"daughterAngle(daughterIndex_1, daughterIndex_2[, daughterIndex_3])", daughterAngle, R
"DOC(
2800 Returns the angle in between any pair of particles belonging to the same decay tree.
2802 The particles are identified via generalized daughter indexes, which are simply colon-separated lists of
2803 daughter indexes, ordered starting from the root particle. For example, ``0:1:3`` identifies the fourth
2804 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle. ``1`` simply
2805 identifies the second daughter of the root particle.
2807 Both two and three generalized indexes can be given to ``daughterAngle``. If two indices are given, the
2808 variable returns the angle between the momenta of the two given particles. If three indices are given, the
2809 variable returns the angle between the momentum of the third particle and a vector which is the sum of the
2810 first two daughter momenta.
2813 ``daughterAngle(0, 3)`` will return the angle between the first and fourth daughter.
2814 ``daughterAngle(0, 1, 3)`` will return the angle between the fourth daughter and the sum of the first and
2816 ``daughterAngle(0:0, 3:0)`` will return the angle between the first daughter of the first daughter, and
2817 the first daughter of the fourth daughter.
2820 REGISTER_VARIABLE("grandDaughterDecayAngle(i, j)", grandDaughterDecayAngle,
2821 "Returns the decay angle of the granddaughter in the daughter particle's rest frame.\n"
2822 "It is calculated with respect to the reverted momentum vector of the particle.\n"
2823 "Two arguments representing the daughter and granddaughter indices have to be provided as arguments.");
2824 REGISTER_VARIABLE(
"daughterClusterAngleInBetween(i, j)", daughterClusterAngleInBetween,
2825 "Returns function which returns the angle between clusters associated to the two daughters."
2826 "If two indices given: returns the angle between the momenta of the clusters associated to the two given daughters."
2827 "If three indices given: returns the angle between the momentum of the third particle's cluster and a vector "
2828 "which is the sum of the first two daughter's cluster momenta."
2829 "Returns nan if any of the daughters specified don't have an associated cluster."
2830 "The arguments in the argument vector must be integers corresponding to the ith and jth (and kth) daughters.");
2831 REGISTER_VARIABLE(
"daughterInvM(i, j)", daughterInvM,
2832 "Returns the invariant Mass adding the Lorentz vectors of the given daughters.\n"
2833 "E.g. ``daughterInvM(0, 1, 2)`` returns the invariant Mass :math:`m = \\sqrt{(p_0 + p_1 + p_2)^2}`` of first, second and third daughter.");
2834 REGISTER_VARIABLE(
"extraInfo(name)", extraInfo,
2835 "Returns extra info stored under the given name.\n"
2836 "The extraInfo has to be set by a module first.\n"
2837 "E.g. ``extraInfo(SignalProbability)`` returns the SignalProbability calculated by the ``MVAExpert`` module.\n"
2838 "If nothing is set under the given name or if the particle is a nullptr, NaN is returned.\n"
2839 "In the latter case please use `eventExtraInfo` if you want to access an EventExtraInfo variable.");
2840 REGISTER_VARIABLE(
"eventExtraInfo(name)", eventExtraInfo,
2841 "[Eventbased] Returns extra info stored under the given name in the event extra info.\n"
2842 "The extraInfo has to be set first by another module like MVAExpert in event mode.\n"
2843 "If nothing is set under this name, NaN is returned.");
2844 REGISTER_VARIABLE(
"eventCached(variable)", eventCached,
2845 "[Eventbased] Returns value of event-based variable and caches this value in the EventExtraInfo.\n"
2846 "The result of second call to this variable in the same event will be provided from the cache.\n"
2847 "It is recommended to use this variable in order to declare custom aliases as event-based. This is "
2848 "necessary if using the eventwise mode of variablesToNtuple).");
2849 REGISTER_VARIABLE(
"particleCached(variable)", particleCached,
2850 "Returns value of given variable and caches this value in the ParticleExtraInfo of the provided particle.\n"
2851 "The result of second call to this variable on the same particle will be provided from the cache.");
2852 REGISTER_VARIABLE(
"modulo(variable, n)", modulo,
2853 "Returns rest of division of variable by n.");
2854 REGISTER_VARIABLE(
"abs(variable)", abs,
2855 "Returns absolute value of the given variable.\n"
2856 "E.g. abs(mcPDG) returns the absolute value of the mcPDG, which is often useful for cuts.");
2857 REGISTER_VARIABLE(
"max(var1,var2)", max,
"Returns max value of two variables.\n");
2858 REGISTER_VARIABLE(
"min(var1,var2)", min,
"Returns min value of two variables.\n");
2859 REGISTER_VARIABLE(
"sin(variable)", sin,
"Returns sine value of the given variable.");
2860 REGISTER_VARIABLE(
"cos(variable)", cos,
"Returns cosine value of the given variable.");
2861 REGISTER_VARIABLE(
"acos(variable)", acos,
"Returns arccosine value of the given variable.");
2862 REGISTER_VARIABLE(
"exp(variable)", exp,
"Returns exponential evaluated for the given variable.");
2863 REGISTER_VARIABLE(
"log(variable)", log,
"Returns natural logarithm evaluated for the given variable.");
2864 REGISTER_VARIABLE(
"log10(variable)", log10,
"Returns base-10 logarithm evaluated for the given variable.");
2865 REGISTER_VARIABLE(
"isNAN(variable)", isNAN,
2866 "Returns true if variable value evaluates to nan (determined via std::isnan(double)).\n"
2867 "Useful for debugging.");
2868 REGISTER_VARIABLE(
"ifNANgiveX(variable, x)", ifNANgiveX,
2869 "Returns x (has to be a number) if variable value is nan (determined via std::isnan(double)).\n"
2870 "Useful for technical purposes while training MVAs.");
2871 REGISTER_VARIABLE(
"isInfinity(variable)", isInfinity,
2872 "Returns true if variable value evaluates to infinity (determined via std::isinf(double)).\n"
2873 "Useful for debugging.");
2874 REGISTER_VARIABLE(
"unmask(variable, flag1, flag2, ...)", unmask,
2875 "unmask(variable, flag1, flag2, ...) or unmask(variable, mask) sets certain bits in the variable to zero.\n"
2876 "For example, if you want to set the second, fourth and fifth bits to zero, you could call \n"
2877 "``unmask(variable, 2, 8, 16)`` or ``unmask(variable, 26)``.\n"
2879 REGISTER_VARIABLE(
"conditionalVariableSelector(cut, variableIfTrue, variableIfFalse)", conditionalVariableSelector,
2880 "Returns one of the two supplied variables, depending on whether the particle passes the supplied cut.\n"
2881 "The first variable is returned if the particle passes the cut, and the second variable is returned otherwise.");
2882 REGISTER_VARIABLE(
"pValueCombination(p1, p2, ...)", pValueCombination,
2883 "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"
2884 "If any of the p-values is invalid, i.e. smaller than zero, -1 is returned.");
2885 REGISTER_VARIABLE(
"veto(particleList, cut, pdgCode = 11)", veto,
2886 "Combines current particle with particles from the given particle list and returns 1 if the combination passes the provided cut. \n"
2887 "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"
2888 "around the neutral Pion mass (e.g. ``0.130 < M < 0.140``). \n"
2889 "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");
2890 REGISTER_VARIABLE(
"matchedMC(variable)", matchedMC,
2891 "Returns variable output for the matched MCParticle by constructing a temporary Particle from it.\n"
2892 "This may not work too well if your variable requires accessing daughters of the particle.\n"
2893 "E.g. ``matchedMC(p)`` returns the total momentum of the related MCParticle.\n"
2894 "Returns NaN if no matched MCParticle exists.");
2895 REGISTER_VARIABLE(
"countInList(particleList, cut='')", countInList,
2896 "Returns number of particle which pass given in cut in the specified particle list.\n"
2897 "Useful for creating statistics about the number of particles in a list.\n"
2898 "E.g. ``countInList(e+, isSignal == 1)`` returns the number of correctly reconstructed electrons in the event.\n"
2899 "The variable is event-based and does not need a valid particle pointer as input.");
2900 REGISTER_VARIABLE(
"getVariableByRank(particleList, rankedVariableName, variableName, rank)", getVariableByRank, R
"DOC(
2901 Returns the value of ``variableName`` for the candidate in the ``particleList`` with the requested ``rank``.
2904 The `BestCandidateSelection` module available via `rankByHighest` / `rankByLowest` has to be used before.
2907 The first candidate matching the given rank is used.
2908 Thus, it is not recommended to use this variable in conjunction with ``allowMultiRank`` in the `BestCandidateSelection` module.
2910 The suffix ``_rank`` is automatically added to the argument ``rankedVariableName``,
2911 which either has to be the name of the variable used to order the candidates or the selected outputVariable name without the ending ``_rank``.
2912 This means that your selected name for the rank variable has to end with ``_rank``.
2914 An example of this variable's usage is given in the tutorial `B2A602-BestCandidateSelection <https://stash.desy.de/projects/B2/repos/software/browse/analysis/examples/tutorials/B2A602-BestCandidateSelection.py>`_
2916 REGISTER_VARIABLE("matchedMCHasPDG(PDGCode)", matchedMCHasPDG,
2917 "Returns if the absolute value of aPDGCode of a MCParticle related to a Particle matches a given PDGCode."
2918 "Returns 0/0.5/1 if PDGCode does not match/is not available/ matches");
2919 REGISTER_VARIABLE(
"numberOfNonOverlappingParticles(pList1, pList2, ...)", numberOfNonOverlappingParticles,
2920 "Returns the number of non-overlapping particles in the given particle lists"
2921 "Useful to check if there is additional physics going on in the detector if one reconstructed the Y4S");
2922 REGISTER_VARIABLE(
"totalEnergyOfParticlesInList(particleListName)", totalEnergyOfParticlesInList,
2923 "Returns the total energy of particles in the given particle List.");
2924 REGISTER_VARIABLE(
"totalPxOfParticlesInList(particleListName)", totalPxOfParticlesInList,
2925 "Returns the total momentum Px of particles in the given particle List.");
2926 REGISTER_VARIABLE(
"totalPyOfParticlesInList(particleListName)", totalPyOfParticlesInList,
2927 "Returns the total momentum Py of particles in the given particle List.");
2928 REGISTER_VARIABLE(
"totalPzOfParticlesInList(particleListName)", totalPzOfParticlesInList,
2929 "Returns the total momentum Pz of particles in the given particle List.");
2930 REGISTER_VARIABLE(
"invMassInLists(pList1, pList2, ...)", invMassInLists,
2931 "Returns the invariant mass of the combination of particles in the given particle lists.");
2932 REGISTER_VARIABLE(
"totalECLEnergyOfParticlesInList(particleListName)", totalECLEnergyOfParticlesInList,
2933 "Returns the total ECL energy of particles in the given particle List.");
2934 REGISTER_VARIABLE(
"maxPtInList(particleListName)", maxPtInList,
2935 "Returns maximum transverse momentum Pt in the given particle List.");
2936 REGISTER_VARIABLE(
"eclClusterSpecialTrackMatched(cut)", eclClusterTrackMatchedWithCondition,
2937 "Returns if at least one Track that satisfies the given condition is related to the ECLCluster of the Particle.");
2938 REGISTER_VARIABLE(
"averageValueInList(particleListName, variable)", averageValueInList,
2939 "Returns the arithmetic mean of the given variable of the particles in the given particle list.");
2940 REGISTER_VARIABLE(
"medianValueInList(particleListName, variable)", medianValueInList,
2941 "Returns the median value of the given variable of the particles in the given particle list.");
2942 REGISTER_VARIABLE(
"angleToClosestInList(particleListName)", angleToClosestInList,
2943 "Returns the angle between this particle and the closest particle (smallest opening angle) in the list provided.");
2944 REGISTER_VARIABLE(
"closestInList(particleListName, variable)", closestInList,
2945 "Returns `variable` for the closest particle (smallest opening angle) in the list provided.");
2946 REGISTER_VARIABLE(
"angleToMostB2BInList(particleListName)", angleToMostB2BInList,
2947 "Returns the angle between this particle and the most back-to-back particle (closest opening angle to 180) in the list provided.");
2948 REGISTER_VARIABLE(
"mostB2BInList(particleListName, variable)", mostB2BInList,
2949 "Returns `variable` for the most back-to-back particle (closest opening angle to 180) in the list provided.");
2950 REGISTER_VARIABLE(
"maxOpeningAngleInList(particleListName)", maxOpeningAngleInList,
2951 "Returns maximum opening angle in the given particle List.");
2952 REGISTER_VARIABLE(
"daughterCombination(variable, daughterIndex_1, daughterIndex_2 ... daughterIndex_n)", daughterCombination,R
"DOC(
2953 Returns a ``variable`` function only of the 4-momentum calculated on an arbitrary set of (grand)daughters.
2956 ``variable`` can only be a function of the daughters' 4-momenta.
2958 Daughters from different generations of the decay tree can be combined using generalized daughter indexes, which are simply colon-separated
2959 the list of daughter indexes, starting from the root particle: for example, ``0:1:3`` identifies the fourth
2960 daughter (3) of the second daughter (1) of the first daughter (0) of the mother particle.
2963 ``daughterCombination(M, 0, 3, 4)`` will return the invariant mass of the system made of the first, fourth and fifth daughter of particle.
2964 ``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.
2967 REGISTER_VARIABLE("useAlternativeDaughterHypothesis(variable, daughterIndex_1:newMassHyp_1, ..., daughterIndex_n:newMassHyp_n)", useAlternativeDaughterHypothesis,R
"DOC(
2968 Returns a ``variable`` calculated using new mass hypotheses for (some of) the particle's daughers.
2971 ``variable`` can only be a function of the particle 4-momentum, which is re-calculated as the sum of the daughters' 4-momenta.
2972 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.
2973 Also, the track fit is not performed again: the variable only re-calculates the 4-vectors using different mass assumptions. The alternative mass assumpion is
2974 used only internally by the variable, and is not stored in the datastore (i.e the daughters are not permanently changed).
2977 Generalized daughter indexes are not supported (yet!): this variable can be used only on first-generation daughters.
2980 ``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.
2981 ``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.
2984 REGISTER_VARIABLE("varForFirstMCAncestorOfType(type, variable)",varForFirstMCAncestorOfType,R
"DOC(Returns requested variable of the first ancestor of the given type.
2985 Ancestor type can be set up by PDG code or by particle name (check evt.pdl for valid particle names))DOC")