52 #include "TClonesArray.h"
54 #include "TObjString.h"
57 #include "reportingUtilsRoot.hpp"
58 #include "conversionUtils.hpp"
63 using namespace boost;
67 bool decayTopology::_debug =
false;
70 decayTopology::decayTopology()
75 _fsDataPartIndexMap (),
76 _fsDataPartMomCache ()
82 const vector<interactionVertexPtr>& decayVertices,
83 const vector<particlePtr>& fsParticles,
84 const bool performTopologyCheck)
86 constructDecay(productionVertex, decayVertices, fsParticles, performTopologyCheck);
124 if (
this != &graph) {
134 const bool cloneProdKinematics)
const
137 printDebug <<
"cloning decay topology '" << name() <<
"' "
138 << ((cloneFsParticles ) ?
"in" :
"ex") <<
"cluding final-state particles, "
139 << ((cloneProdKinematics) ?
"in" :
"ex") <<
"cluding production kinematics particles"
144 nodeIterator iNd, iNdEnd;
145 vector<interactionVertexPtr> newVerts;
146 for (tie(iNd, iNdEnd) = topoClone->nodes(); iNd != iNdEnd; ++iNd) {
153 newVerts.push_back(topoClone->
cloneNode(*iNd));
158 for (
unsigned int i = 0;
i < newVerts.size(); ++
i) {
160 for (
unsigned int j = 0; j < newVerts[
i]->nmbInParticles(); ++j) {
162 if (not topoClone->
isFsParticle(part) or cloneFsParticles) {
163 if (topoClone->isEdge(part))
164 topoClone->
cloneEdge(topoClone->edge(part));
168 printDebug <<
"cloning dangling " << *part << endl;
171 newVerts[
i]->inParticles()[j] = newPart;
176 topoClone->name() =
"topoClone";
193 map<string, unsigned int>
196 map<string, unsigned int> partMult;
199 map<string, unsigned int>::iterator entry = partMult.find(partName);
200 if (entry != partMult.end())
203 partMult[partName] = 1;
213 int intrinsicParity = 1;
216 return intrinsicParity;
250 nodeIterator iNd, iNdEnd;
251 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
252 if (vert == vertex(*iNd))
263 edgeIterator iEd, iEdEnd;
264 for (tie(iEd, iEdEnd) = edges(); iEd != iEdEnd; ++iEd)
310 if (dynamic_pointer_cast<fsVertex>(vert))
343 bool topologyIsOkay =
true;
345 nodeIterator iNd, iNdEnd;
346 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd) {
349 printWarn <<
"node[" << *iNd <<
"] has vertex null pointer" << endl;
350 topologyIsOkay =
false;
355 if (not isEdge(static_pointer_cast<rpwa::productionVertex>(vert)->
XParticle())) {
356 printWarn <<
"X particle of " << *vert <<
" has no associated edge" << endl;
357 topologyIsOkay =
false;
359 printDebug <<
"success: X particle of " << *vert <<
" has associated edge" << endl;
361 for (
unsigned int i = 0;
i < vert->nmbInParticles(); ++
i)
362 if (not isEdge(vert->inParticles()[
i])) {
363 printWarn <<
"incoming particle[" <<
i <<
"] of " << *vert
364 <<
" has no associated edge" << endl;
365 topologyIsOkay =
false;
367 printDebug <<
"success: incoming particle[" <<
i <<
"] of " << *vert
368 <<
" has associated edge" << endl;
369 for (
unsigned int i = 0;
i < vert->nmbOutParticles(); ++
i)
370 if (not isEdge(vert->outParticles()[
i])) {
371 printWarn <<
"outgoing particle[" <<
i <<
"] of " << *vert
372 <<
" has no associated edge" << endl;
373 topologyIsOkay =
false;
375 printDebug <<
"success: outgoing particle[" <<
i <<
"] of " << *vert
376 <<
" has associated edge" << endl;
381 printWarn <<
"production vertex is null pointer" << endl;
382 topologyIsOkay =
false;
385 printWarn << *
_prodVertex <<
" has no associated node" << endl;
386 topologyIsOkay =
false;
388 printDebug <<
"success: " << *
_prodVertex <<
" has associated node" << endl;
391 <<
"outgoing edges" << endl;
392 topologyIsOkay =
false;
395 <<
"incoming edges" << endl;
396 topologyIsOkay =
false;
399 <<
" has exactly 1 outgoing and no incoming edges" << endl;
402 vector<nodeDesc> sortedNds;
408 nodeDesc topNd = topNode();
410 printDebug <<
"using node[" << topNd <<
"] as top node" << endl;
411 sortedNds = sortNodesDfs(topNd);
413 if (sortedNds.size() != nmbVertices) {
414 printWarn <<
"number of nodes reachable from top node is "
415 << sortedNds.size() <<
" != " << nmbVertices << endl;
416 topologyIsOkay =
false;
418 printDebug <<
"success: all nodes are reachable from top node" << endl;
423 printWarn <<
"interaction vertex[" <<
i <<
"] is null pointer" << endl;
424 topologyIsOkay =
false;
427 if (not isNode(vert) or (vertex(node(vert)) != vert)) {
428 printWarn << *vert <<
" at " << vert <<
" has no associated node" << endl;
429 topologyIsOkay =
false;
431 printDebug <<
"success: " << *vert <<
" has associated node" << endl;
432 if (nmbOutEdges(vert) < 1) {
433 printWarn << *vert <<
" has " << nmbOutEdges(vert) <<
" < 1 "
434 <<
"outgoing edges" << endl;
435 topologyIsOkay =
false;
436 }
else if (nmbInEdges(vert) < 1) {
437 printWarn << *vert <<
" has " << nmbInEdges(vert) <<
" < 1 "
438 <<
"incoming edges" << endl;
439 topologyIsOkay =
false;
441 printDebug <<
"success: " << *vert
442 <<
" has at least 1 outgoing and 1 incoming edge" << endl;
448 printWarn <<
"final-state particle[" <<
i <<
"] is null pointer" << endl;
449 topologyIsOkay =
false;
452 if (not isEdge(part) or (
particle(this->edge(part)) != part)) {
453 printWarn <<
"final state " << *part <<
" has no associated edge" << endl;
454 topologyIsOkay =
false;
456 printDebug <<
"success: final state " << *part <<
" has associated edge" << endl;
457 if (isEdge(part) and not
isFsVertex(toVertex(part))) {
458 printWarn <<
"vertex associated to final-state particle "
459 <<
"'" << part->name() <<
"' is not a final-state vertex" << endl;
460 topologyIsOkay =
false;
462 printDebug <<
"success: vertex associated to final-state particle "
463 <<
"'" << part->name() <<
"' is a final-state vertex" << endl;
466 edgeIterator iEd, iEdEnd;
467 for (tie(iEd, iEdEnd) = edges(); iEd != iEdEnd; ++iEd) {
471 bool isInFromVert =
false;
472 for (
unsigned int i = 0;
i < fromVert->nmbOutParticles(); ++
i)
473 if (part == fromVert->outParticles()[
i]) {
477 if (not isInFromVert) {
478 printWarn <<
"particle '" << part->name() <<
"' = " << part <<
" associated to edge " << *iEd
479 <<
" is not in list of outgoing particles of " << *fromVert <<
" at " << fromVert
481 for (
unsigned int i = 0;
i < fromVert->nmbOutParticles(); ++
i)
482 cout <<
"[" <<
i <<
"] = " << fromVert->outParticles()[
i] <<
" ";
484 topologyIsOkay =
false;
486 printDebug <<
"success: found particle '" << part->name() <<
"' "
487 <<
"in list of outgoing particles of vertex " << *fromVert << endl;
490 bool isInToVert =
false;
491 for (
unsigned int i = 0;
i < toVert->nmbInParticles(); ++
i)
492 if (part == toVert->inParticles()[
i]) {
496 if (not isInToVert) {
497 printWarn <<
"particle '" << part->name() <<
"' = " << part <<
" associated to edge " << *iEd
498 <<
" is not in list of incoming particles of " << *toVert <<
" at " << toVert
500 for (
unsigned int i = 0;
i < toVert->nmbOutParticles(); ++
i)
501 cout <<
"[" <<
i <<
"] = " << toVert->outParticles()[
i] <<
" ";
503 topologyIsOkay =
false;
505 printDebug <<
"success: found particle '" << part->name() <<
"' "
506 <<
"in list of incoming particles of vertex " << *toVert << endl;
514 map<string, vector<particlePtr> > fsPartSorted;
515 bool allIndicesAtDefault =
true;
518 fsPartSorted[part->name()].push_back(part);
519 if (part->index() >= 0)
520 allIndicesAtDefault =
false;
522 if (allIndicesAtDefault) {
524 printDebug <<
"success: all final-state particles have default indices" << endl;
526 for (map<
string, vector<particlePtr> >::iterator
i = fsPartSorted.begin();
527 i != fsPartSorted.end(); ++
i) {
529 vector<particlePtr>& parts =
i->second;
533 for (
unsigned int j = 0; j < parts.size(); ++j)
534 if (parts[j]->index() != (
int)j) {
535 printWarn <<
"indices for final-state particles '" <<
i->first <<
"' are not consecutive. "
536 <<
"expected index [" << j <<
"], found [" << parts[j]->index() <<
"]." << endl;
537 topologyIsOkay =
false;
539 printDebug <<
"success: final-state particle '" <<
i->first <<
"' "
540 <<
"has expected index [" << j <<
"]" << endl;
543 printDebug <<
"decay topology " << ((topologyIsOkay) ?
"passed" :
"did not pass")
544 <<
" all tests" << endl;
545 return topologyIsOkay;
551 const bool linkToMotherTopo)
553 decayTopology subTopo(dfsSubGraph(startNd, linkToMotherTopo));
554 subTopo.name() =
"subdecay";
562 decayTopologyGraphType::addGraph(topo);
569 if (not productionVertex) {
570 printErr <<
"null pointer for production vertex. aborting." << endl;
573 if (not productionVertex->XParticle()) {
574 printErr <<
"null pointer for particle[0] coming out of production vertex. aborting." << endl;
577 name() =
"\"" + productionVertex->XParticle()->qnSummary() +
"\"";
580 addVertex(productionVertex);
592 const TClonesArray& decayKinPartNames)
608 const string partClassName = decayKinPartNames.GetClass()->GetName();
609 if (partClassName !=
"TObjString") {
610 printWarn <<
"decay kinematics particle names are of type '" << partClassName
611 <<
"' and not TObjString. cannot read decay kinematics." << endl;
614 const int nmbFsPart = decayKinPartNames.GetEntriesFast();
615 if ((nmbFsPart < 0) or ((
unsigned int)nmbFsPart !=
nmbFsParticles())) {
616 printWarn <<
"array of decay kinematics particle names has wrong size: "
623 map<string, vector<unsigned int> > fsDataPartIndices;
624 map<string, unsigned int> fsDataPartCount;
626 const string name = ((TObjString*)decayKinPartNames[
i])->GetString().Data();
627 fsDataPartIndices[name].push_back(i);
628 fsDataPartCount[name] = 0;
635 const string partName = part->name();
636 map<string, vector<unsigned int> >::const_iterator entry = fsDataPartIndices.find(partName);
637 if (entry != fsDataPartIndices.end()) {
638 int partIndex = part->index();
640 partIndex = fsDataPartCount[partName];
641 ++fsDataPartCount[partName];
643 if ((
unsigned int)partIndex < entry->second.size()) {
645 printDebug <<
"assigning decay kinematics data index [" << entry->second[partIndex] <<
"] "
646 <<
"to final-state particle '" << partName <<
"'[" << partIndex <<
"] "
647 <<
"at index [" <<
i <<
"]" << endl;
650 printWarn <<
"index [" << partIndex <<
"] for final-state particle "
651 <<
"'" << partName <<
"' out of range. input data contain only "
652 << entry->second.size() <<
" entries for this particle type." << endl;
656 printWarn <<
"cannot find entry for final-state particle '" << part->name() <<
"' "
657 <<
"in input data." << endl;
662 printWarn <<
"could not find all final-state particles in input data." << endl;
672 const TClonesArray& decayKinMomenta)
678 const int nmbFsPart = decayKinMomenta.GetEntriesFast();
679 if ((nmbFsPart < 0) or ((
unsigned int)nmbFsPart !=
nmbFsParticles())) {
680 printWarn <<
"array of decay kinematics particle momenta has wrong size: "
682 <<
"cannot read decay kinematics." << endl;
692 const TVector3* mom =
dynamic_cast<TVector3*
>(decayKinMomenta[partIndex]);
694 printWarn <<
"decay kinematics data entry [" << partIndex <<
"] is not of type TVector3. "
695 <<
"cannot read decay kinematics momentum for particle '" << part->name() <<
"'. "
696 <<
"skipping." << endl;
701 printDebug <<
"setting momentum of final-state particle '" << part->name() <<
"' "
702 <<
"at index [" <<
i <<
"] to " << *mom <<
" GeV "
703 <<
"at input data index [" << partIndex <<
"]" << endl;
704 part->setMomentum(*mom);
733 printWarn <<
"cache for final-state particle momenta has size "
742 printDebug <<
"resetting momentum of final-state particle '" << part->name() <<
"'"
758 printWarn <<
"cache size for final-state particle momenta (= "
760 << fsPartPermMap.size() <<
") do not match # of final-state particles (= "
765 const unsigned int newIndex = fsPartPermMap[
i];
769 printDebug <<
"(re)setting momentum of final-state particle "
770 <<
"'" << part->name() <<
"'[" <<
i <<
"] "
771 <<
"to that of '" <<
fsParticles()[newIndex]->name()
782 out <<
"decay topology '" << name() <<
"' has " << nmbNodes() <<
" node(s):" << endl;
787 out <<
" topology has no production node." << endl;
791 nodeIterator iNd, iNdEnd;
792 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
794 out <<
" final-state node[" << *iNd <<
"] = " << vertex(*iNd) <<
": "
795 << *vertex(*iNd) << endl;
797 out <<
"decay topology '" << name() <<
"' has " << nmbEdges() <<
" edge(s):" << endl;
798 edgeIterator iEd, iEdEnd;
799 for (tie(iEd, iEdEnd) = edges(); iEd != iEdEnd; ++iEd) {
801 out <<
" edge[" << *iEd <<
"] = [" << fromNode(*iEd) <<
", "
802 << toNode(*iEd) <<
"] = " << part <<
": '" << part->name() <<
"'";
804 out <<
" (final state)";
814 out <<
"production kinematics particles:" << endl;
817 out <<
" incoming particle[" <<
i <<
"]: " << part->qnSummary() <<
", "
818 <<
"index = " << part->index() <<
", p = " << part->lzVec() <<
" GeV" << endl;
822 out <<
" outgoing particle[" <<
i <<
"]: " << part->qnSummary() <<
", "
823 <<
"index = " << part->index() <<
", p = " << part->lzVec() <<
" GeV" << endl;
832 out <<
"decay kinematics particles:" << endl;
835 out <<
" particle[" <<
i <<
"]: " << part->qnSummary() <<
", "
836 <<
"index = " << part->index() <<
", p = " << part->lzVec() <<
" GeV" << endl;
844 const vector<interactionVertexPtr>& decayVertices,
845 const vector<particlePtr>& fsParticles,
846 const bool performTopologyCheck)
849 const unsigned int nmbDecayVert = decayVertices.size();
850 const unsigned int nmbFsPart = fsParticles.size();
852 printDebug <<
"constructing decay topology with " << nmbDecayVert <<
" decay vertices and "
853 << nmbFsPart <<
" final-state particles" << endl;
855 printErr <<
"cannot construct decay topology without final-state particles. aborting." << endl;
858 if (nmbDecayVert < 1) {
859 printWarn <<
"need at least production and X-decay vertex "
860 <<
"to construct decay topology. aborting." << endl;
865 if (not productionVertex) {
866 printErr <<
"null pointer for production vertex. aborting." << endl;
869 if (not productionVertex->XParticle()) {
870 printErr <<
"null pointer for X particle coming out of production vertex. aborting." << endl;
873 name() =
"\"" + productionVertex->XParticle()->qnSummary() +
"\"";
875 addVertex(productionVertex);
877 for (
unsigned int i = 0;
i < nmbDecayVert; ++
i) {
878 if (not decayVertices[
i]) {
879 printErr <<
"null pointer for decay vertex[" << i <<
"]. aborting." << endl;
882 addVertex(decayVertices[i]);
885 for (
unsigned int i = 0;
i < nmbFsPart; ++
i) {
886 if (not fsParticles[
i]) {
887 printErr <<
"null pointer for final-state particle[" << i <<
"]. aborting." << endl;
894 vector<nodeDesc> sortedNds = sortNodesDfs(node(
_prodVertex));
895 for (
unsigned int i = 0;
i < sortedNds.size(); ++
i) {
900 for (
unsigned int i = 0; i < nmbFsPart; ++
i)
901 if (part == fsParticles[i]) {
906 for (
unsigned int i = 0; i < nmbDecayVert; ++
i)
907 if (vert == decayVertices[i]) {
915 printErr <<
"topology has problems that need to be fixed. aborting." << endl;
930 unsigned int nmbProdVertCandidates = 0;
931 nodeIterator iNd, iNdEnd;
932 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
933 if ((nmbInEdges(*iNd) == 0) and (nmbOutEdges(*iNd) == 1)) {
936 ++nmbProdVertCandidates;
940 vector<nodeDesc> sortedNds;
946 unsigned int nmbTopVertCandidates = 0;
947 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
948 if ((nmbInEdges(*iNd) == 0) and not
isFsVertex(vertex(*iNd))) {
950 ++nmbTopVertCandidates;
952 if (nmbTopVertCandidates == 1)
953 sortedNds = sortNodesDfs(topNode);
956 printWarn <<
"ill-formed graph. vertex order will be undefined." << endl;
957 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
958 sortedNds.push_back(*iNd);
961 for (
unsigned int i = 0;
i < sortedNds.size(); ++
i) {
966 if (nmbProdVertCandidates > 1) {
967 printWarn <<
"found " << nmbProdVertCandidates <<
" instead of 0 or 1 candidate "
968 <<
"for production vertex in graph '" << name() <<
"'" << endl;
972 printWarn <<
"cannot find final-state particles in graph '" << name() <<
"'" << endl;
976 printErr <<
"cannot construct decay topology from graph '" << name() <<
"'. aborting." << endl;
981 for (
unsigned int i = 0;
i < sortedNds.size(); ++
i) {
991 const bool cloneInParticles,
992 const bool cloneOutParticles)
1001 else if (isDecayVert)