41 #include "spinUtils.hpp"
45 using namespace boost;
49 bool isobarDecayTopology::_debug =
false;
52 isobarDecayTopology::isobarDecayTopology()
58 const vector<isobarDecayVertexPtr>& isobarDecayVertices,
59 const vector<particlePtr>& fsParticles,
60 const bool performTopologyCheck)
63 constructDecay(productionVertex, isobarDecayVertices, fsParticles, performTopologyCheck);
68 const vector<interactionVertexPtr>& isobarDecayVertices,
69 const vector<particlePtr>& fsParticles,
70 const bool performTopologyCheck)
73 constructDecay(productionVertex, isobarDecayVertices, fsParticles, performTopologyCheck);
119 const bool cloneProdKinematics)
const
122 printDebug <<
"cloning isobar decay topology '" << name() <<
"'; "
123 << ((cloneFsParticles ) ?
"in" :
"ex") <<
"cluding final-state particles, "
124 << ((cloneProdKinematics) ?
"in" :
"ex") <<
"cluding production kinematics particles"
129 return isobarTopoClone;
143 const vector<isobarDecayVertexPtr>& isobarDecayVertices,
144 const vector<particlePtr>& fsParticles,
145 const bool performTopologyCheck)
147 const unsigned int nmbVert = isobarDecayVertices.size();
149 printDebug <<
"constructing isobar decay topology with "
150 << fsParticles.size() <<
" final-state particles and "
151 << nmbVert <<
" isobar decay vertices" << endl;
152 vector<interactionVertexPtr> intVertices(nmbVert);
153 for (
unsigned int i = 0;
i < nmbVert; ++
i)
154 intVertices[
i] = isobarDecayVertices[
i];
160 <<
" does not match number of vertices given in parameter array = " << nmbVert
161 <<
". aborting." << endl;
170 const vector<interactionVertexPtr>& isobarDecayVertices,
171 const vector<particlePtr>& fsParticles,
172 const bool performTopologyCheck)
174 const unsigned int nmbVert = isobarDecayVertices.size();
176 for (
unsigned int i = 0;
i < nmbVert; ++
i) {
178 if (not decayVertices[
i]) {
179 printErr <<
"interaction vertex[" << i <<
"] is not an isobarDecayVertex. aborting." << endl;
183 return constructDecay(productionVertex, decayVertices, fsParticles, performTopologyCheck);
198 printWarn <<
"number of incoming edges of node[" << nd <<
"] is "
199 << nmbIn <<
" != 1" << endl;
200 topologyIsOkay =
false;
202 printDebug <<
"number of incoming edges of node[" << nd <<
"] = " << nmbIn
203 <<
" is correct" << endl;
207 printWarn <<
"number of outgoing edges of node[" << nd <<
"] is "
208 << nmbOut <<
" != 2" << endl;
209 topologyIsOkay =
false;
211 printDebug <<
"number of outgoing edges of node[" << nd <<
"] = " << nmbOut
212 <<
" is correct" << endl;
216 printDebug <<
"isobar decay topology passed all tests" << endl;
218 printWarn <<
"isobar decay topology did not pass all tests" << endl;
220 return topologyIsOkay;
227 bool allVertConsistent =
true;
230 if (not vertexConsistent) {
231 allVertConsistent =
false;
233 if (vertexConsistent)
235 <<
" is consistent" << endl;
237 printWarn <<
"isobar decay vertex " << *
_isobarVertices[
i] <<
" is not consistent" << endl;
242 if (allVertConsistent)
243 printDebug <<
"success: information in isobar decay vertices is consistent" << endl;
245 printWarn <<
"information in isobar decay vertices is not consistent" << endl;
247 return allVertConsistent;
251 const TLorentzVector&
257 printDebug <<
"calculating Lorentz-vector of parent isobar '"
272 if (
_debug && warnIfNotExistent)
273 printDebug <<
"calculating charge of parent isobar '"
274 << isobar->name() <<
"' "
276 const int isobarCharge = isobar->charge();
279 if(warnIfNotExistent) {
280 printWarn <<
"fixed charge of isobar '" << isobar->name() <<
"' "
281 <<
"from " << isobarCharge <<
" to " << isobar->charge() <<
". "
282 <<
"please fix wave definition." << endl;
284 isobar->fillFromDataTable(isobar->name(), warnIfNotExistent);
289 if(warnIfNotExistent) {
290 printWarn <<
"X is charged, but has C-parity = " <<
XParticle()->C()
291 <<
". setting C-parity to zero. please fix wave definition." << endl;
296 name() =
"\"" +
XParticle()->qnSummary() +
"\"";
306 printDebug <<
"calculating baryon number of parent isobar '"
318 out <<
"isobar decay topology '" << name() <<
"' has " << nmbNodes() <<
" node(s):" << endl;
323 out <<
" topology has no production node." << endl;
325 out <<
" isobar decay node[" << node(
decayVertices()[
i]) <<
"] = "
327 nodeIterator iNd, iNdEnd;
328 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd)
330 out <<
" final-state node[" << *iNd <<
"] = " << *vertex(*iNd) << endl;
332 out <<
"isobar decay topology '" << name() <<
"' has " << nmbEdges() <<
" edge(s):" << endl;
333 edgeIterator iEd, iEdEnd;
334 for (tie(iEd, iEdEnd) = edges(); iEd != iEdEnd; ++iEd) {
336 out <<
" edge[" << *iEd <<
"] = " << part->name();
339 out <<
"[" << fsIndex <<
"] (final state)";
350 printDebug <<
"generating graphViz file for graph '" << name() <<
"'" << endl;
352 graphNodeAttribute()[
"style" ] =
"filled";
353 graphNodeAttribute()[
"fillcolor"] =
"white";
355 nodeIterator iNd, iNdEnd;
356 for (tie(iNd, iNdEnd) = nodes(); iNd != iNdEnd; ++iNd) {
358 label << vertex(*iNd)->name();
361 label <<
": L = " << spinQn(vert->L()) <<
", S = " << spinQn(vert->S());
362 nodeAttribute(*iNd)[
"label"] = label.str();
367 nodeAttribute(toNode(
fsParticles()[
i]))[
"shape"] =
"diamond";
368 nodeAttribute(toNode(
fsParticles()[
i]))[
"style"] =
"dashed,filled";
371 edgeIterator iEd, iEdEnd;
372 for (tie(iEd, iEdEnd) = edges(); iEd != iEdEnd; ++iEd)
384 ofstream graphVizFile(outFileName.c_str());
385 if (not graphVizFile) {
386 printWarn <<
"cannot create file '" << outFileName <<
"'. graph is not written." << endl;
403 printWarn << *v <<
" is not of type isobarDecayVertex." << endl;
408 printErr <<
"incompatible topology. some interaction vertices are "
409 <<
"not of type isobarDecayVertex. aborting." << endl;
417 const bool linkToParentTopo)
420 subTopo.name() =
"\"" + vertex(startNd)->inParticles()[0]->qnSummary() +
"\"";
435 const vector<isobarDecayTopology>& daughterDecays)
438 printDebug <<
"joining " << daughterDecays.size() <<
" daughter graphs with parent "
439 << *parentVertex << endl;
442 newTopo.addVertex(parentVertex);
443 for (
unsigned int i = 0;
i < daughterDecays.size(); ++
i)
454 vector<isobarDecayTopology> daughterDecays(2);
455 daughterDecays[0] = daughter1Decay;
456 daughterDecays[1] = daughter2Decay;
471 const double clebsch = clebschGordanCoeff<double>(daughter1->isospin(), daughter1->isospinProj(),
472 daughter2->isospin(), daughter2->isospinProj(),
473 parent->isospin (), parent->isospinProj ());
474 double clebschDaughter1 = 1.;
475 double clebschDaughter2 = 1.;
482 return clebsch * clebschDaughter1 * clebschDaughter2;
496 vector< vector<unsigned int> > groups;
497 for(
unsigned int i = 0;
i < fsParts.size(); ++
i) {
499 bool inserted =
false;
500 for(
unsigned int j = 0; j < groups.size(); ++j) {
501 const particlePtr& compPart = fsParts.at(groups.at(j).at(0));
502 if(particle->isospin() == compPart->isospin() &&
503 particle->J() == compPart->J() &&
504 particle->P() == compPart->P())
506 groups.at(j).push_back(
i);
511 groups.push_back(vector<unsigned int>(1,
i));
516 printDebug <<
"Found isospin symmetrization groups:" << endl;
517 for(
unsigned int i = 0;
i < groups.size(); ++
i) {
518 printDebug <<
"Group " <<
i << endl;
519 for(
unsigned int j = 0; j < groups.at(
i).size(); ++j) {
520 printDebug << j <<
": " << groups.at(
i).at(j)
521 <<
" (" << fsParts.at(groups.at(
i).at(j))->name() <<
")" << endl;
529 vector<int> isospinProjs;
530 for(
unsigned int j = 0; j < fsParts.size(); ++j) {
531 isospinProjs.push_back(fsParts.at(j)->isospinProj());
535 vector<symTermMap> symAmplitudes;
540 for(
unsigned int i = 0;
i < groups.size(); ++
i) {
541 vector<unsigned int> group = groups.at(
i);
545 printDebug <<
"Group permutations " <<
i << endl;
550 vector<unsigned int> permutations;
551 for(
unsigned int j = 0; j < group.size(); ++j) {
552 permutations.push_back(j);
560 vector<unsigned int> map;
561 for(
unsigned int j = 0; j < fsParts.size(); ++j) {
569 for(
unsigned int j = 0; j < group.size(); ++j) {
570 map.at(group.at(j)) = group.at(permutations.at(j));
574 bool breaking =
false;
575 for(
unsigned int j = 0; j < map.size(); ++j) {
582 if(fsParts.at(j)->name() == fsParts.at(map.at(j))->name()) {
588 for(
unsigned int k = 0; k < map.size(); ++k) {
589 if((map.at(k) == k) || (j == k))
continue;
590 if(fromVertex(fsParts.at(j)) == fromVertex(fsParts.at(k))) {
605 for(
unsigned int j = 0; j < map.size(); ++j) {
606 fsParts.at(j)->setIsospinProj(isospinProjs.at(map.at(j)));
615 if(!spinStatesCanCouple(d1->isospin(), d1->isospinProj(),
616 d2->isospin(), d2->isospinProj(),
617 p->isospin(), p->isospinProj())) {
624 for(
unsigned int j = 0; j < fsParts.size(); ++j) {
625 fsParts.at(j)->setIsospinProj(isospinProjs.at(j));
635 symAmplitudes.push_back(symTerm);
638 printDebug <<
"Found valid permutation: ";
639 for(
unsigned int j = 0; j < map.size(); ++j) {
643 for(
unsigned int j = 0; j < map.size(); ++j) {
644 cout << fsParts.at(j)->name();
646 cout <<
"), clebsch-gordan=" << clebsch << endl;
650 for(
unsigned int j = 0; j < fsParts.size(); ++j) {
651 fsParts.at(j)->setIsospinProj(isospinProjs.at(j));
655 }
while(next_permutation(permutations.begin(), permutations.end()));
660 for(
unsigned int i = 0;
i < symAmplitudes.size(); ++
i) {
661 symAmplitudes[
i].factor = signum(symAmplitudes[
i].factor.real()) / sqrt(symAmplitudes.size());
664 return symAmplitudes;
672 typedef map<string, unsigned int>::const_iterator indistFsPartIt;
674 printInfo <<
"indistinguishable final-state multiplicities "
675 <<
"(marked FS particles will be Bose symmetrized): ";
676 for (indistFsPartIt
i = indistFsPart.begin();
i != indistFsPart.end(); ++
i)
677 cout <<
i->first <<
" = " <<
i->second << ((
i->second) >= 2 ?
" <<< " :
" ");
681 double nmbCombinations = 1;
682 for (indistFsPartIt
i = indistFsPart.begin();
i != indistFsPart.end(); ++
i)
683 nmbCombinations *= factorial<double>(
i->second);
684 const double normFactor = 1 / sqrt(nmbCombinations);
688 map<string, vector<unsigned int> > origFsPartIndices;
691 origFsPartIndices[partName].push_back(
i);
693 map<string, vector<unsigned int> > newFsPartIndices = origFsPartIndices;
694 map<string, vector<unsigned int> >::iterator firstEntry = newFsPartIndices.begin();
695 vector<symTermMap> symTermMaps;
697 for(
unsigned int i = 0;
i < symTermMaps.size(); ++
i) {
698 symTermMaps[
i].factor = normFactor;
706 const vector<unsigned int>& permutation)
const
709 for(
unsigned int i = 0;
i < permutation.size(); ++
i) {
710 if(permutation[
i] ==
i) {
713 if((find(fsPartIndices.begin(), fsPartIndices.end(), permutation[
i]) == fsPartIndices.end() and
714 find(fsPartIndices.begin(), fsPartIndices.end(),
i) != fsPartIndices.end()) or
715 (find(fsPartIndices.begin(), fsPartIndices.end(),
i) == fsPartIndices.end() and
716 find(fsPartIndices.begin(), fsPartIndices.end(), permutation[
i]) != fsPartIndices.end()))
727 const vector<unsigned int>& permutation)
const
729 vector<isobarDecayVertexPtr> verticesToTest(1, vertex);
732 daughter = dynamic_pointer_cast<
isobarDecayVertex>(toVertex(vertex->daughter1()));
734 printErr <<
"Got NULL pointer while getting toVertex. Aborting..." << endl;
737 verticesToTest.push_back(daughter);
740 daughter = dynamic_pointer_cast<
isobarDecayVertex>(toVertex(vertex->daughter2()));
742 printErr <<
"Got NULL pointer while getting toVertex. Aborting..." << endl;
745 verticesToTest.push_back(daughter);
747 for(
unsigned int i = 0;
i < verticesToTest.size(); ++
i) {
758 vector<unsigned int> indices;
762 indices.push_back(static_cast<unsigned int>(index1));
764 const particlePtr& daughter1 = vertex->daughter1();
767 if(not daughterVertex1) {
768 printErr <<
"Got NULL pointer while getting toVertex. Aborting..." << endl;
772 indices.insert(indices.end(), indices1.begin(), indices1.end());
776 indices.push_back(static_cast<unsigned int>(index2));
778 const particlePtr& daughter2 = vertex->daughter2();
781 if(not daughterVertex2) {
782 printErr <<
"Got NULL pointer while getting toVertex. Aborting..." << endl;
786 indices.insert(indices.end(), indices2.begin(), indices2.end());
794 (
const map<
string, vector<unsigned int> >& origFsPartIndices,
795 const map<
string, vector<unsigned int> >& newFsPartIndices,
796 map<
string, vector<unsigned int> >::iterator& newFsPartIndicesEntry,
797 vector<symTermMap>& newSymTermMaps)
const
801 map<string, vector<unsigned int> >::iterator nextFsPartIndicesEntry = newFsPartIndicesEntry;
802 if (++nextFsPartIndicesEntry != newFsPartIndices.end())
804 genBoseSymTermMaps(origFsPartIndices, newFsPartIndices, nextFsPartIndicesEntry,
808 vector<unsigned int> bosePermMap(nmbFsParticles(), 0);
810 printDebug <<
"Bose-symmetrization final-state permutation: ";
811 for (map<
string, vector<unsigned int> >::const_iterator
i = origFsPartIndices.begin();
812 i != origFsPartIndices.end(); ++
i) {
813 const string partName =
i->first;
814 map<string, vector<unsigned int> >::const_iterator entry = newFsPartIndices.find(partName);
815 assert(entry != newFsPartIndices.end());
816 for (
unsigned int j = 0; j <
i->second.size(); ++j) {
817 assert(entry->second.size() ==
i->second.size());
818 const unsigned int origFsPartIndex =
i->second[j];
819 const unsigned int newFsPartIndex = entry->second[j];
821 cout << partName <<
"[" << origFsPartIndex <<
" -> " << newFsPartIndex <<
"] ";
822 bosePermMap[origFsPartIndex] = newFsPartIndex;
829 vector<unsigned int> fsPartPermMap(bosePermMap.size(), 0);
830 for (
unsigned int i = 0;
i < fsPartPermMap.size(); ++
i) {
831 fsPartPermMap[
i] = bosePermMap[
i];
834 printDebug <<
"effective Bose-symmetrization is: final-state permutation map = "
835 << fsPartPermMap << endl;
837 newSymTermMaps.push_back(symTerm);
839 }
while (next_permutation(newFsPartIndicesEntry->second.begin(),
840 newFsPartIndicesEntry->second.end()));
847 vector<unsigned int> boseSymVertices;
849 for (
unsigned int i = 0;
i < topo->nmbDecayVertices(); ++
i) {
852 const particlePtr daughters[2] = {vert->daughter1(), vert->daughter2()};
853 if (topo->isFsParticle(daughters[0]) or topo->isFsParticle(daughters[1]))
857 topo->
subDecay(topo->toNode(daughters[1]))};
860 printDebug <<
"found isobar decay vertex " << *vert <<
" "
861 <<
"that has two isobar daughters which decay into the same final state: " << endl
862 <<
"daughter 1 " << isobarTopos[0]
863 <<
"daughter 2 " << isobarTopos[1];
864 boseSymVertices.push_back(
i);
867 return boseSymVertices;