39 #include <boost/assign.hpp>
41 #include "libconfig.h++"
43 #include "physUtils.hpp"
44 #include "spinUtils.hpp"
45 #include "conversionUtils.hpp"
46 #include "libConfigUtils.hpp"
47 #include "arrayUtils.hpp"
54 using namespace boost;
55 using namespace boost::tuples;
56 using namespace libconfig;
60 bool waveSetGenerator::_debug =
false;
63 waveSetGenerator::waveSetGenerator()
69 waveSetGenerator::~waveSetGenerator()
74 waveSetGenerator::setWaveSetParameters(
const string& templateKeyFileName)
77 _templateTopo.reset();
81 printWarn <<
"problems constructing template decay topology from key file "
82 <<
"'" << templateKeyFileName <<
"'. cannot generate wave set." << endl;
86 printInfo <<
"reading wave set parameters from key file '" << templateKeyFileName <<
"'" << endl;
88 if (not parseLibConfigFile(templateKeyFileName, key, _debug)) {
89 printWarn <<
"problems reading wave set parameters from '" << templateKeyFileName <<
"'. "
90 <<
"cannot generate wave set." << endl;
94 const Setting* waveSetParKey = findLibConfigGroup(key.getRoot(),
"waveSetParameters",
false);
96 const Setting* isoSpinRangeKey = findLibConfigArray(*waveSetParKey,
"isospinRange",
false);
98 _isospinRange = make_tuple<int, int>((*isoSpinRangeKey)[0], (*isoSpinRangeKey)[1]);
99 const Setting* JRangeKey = findLibConfigArray(*waveSetParKey,
"JRange",
false);
101 _JRange = make_tuple<int, int>((*JRangeKey)[0], (*JRangeKey)[1]);
102 const Setting* MRangeKey = findLibConfigArray(*waveSetParKey,
"MRange",
false);
103 waveSetParKey->lookupValue(
"reflectivity", _reflectivity );
104 waveSetParKey->lookupValue(
"useReflectivity", _useReflectivity );
105 waveSetParKey->lookupValue(
"allowSpinExotics", _allowSpinExotics);
107 _spinProjRange = make_tuple<int, int>((*MRangeKey)[0], (*MRangeKey)[1]);
108 const Setting* LRangeKey = findLibConfigArray(*waveSetParKey,
"LRange",
false);
110 _LRange = make_tuple<int, int>((*LRangeKey)[0], (*LRangeKey)[1]);
111 const Setting* SRangeKey = findLibConfigArray(*waveSetParKey,
"SRange",
false);
113 _SRange = make_tuple<int, int>((*SRangeKey)[0], (*SRangeKey)[1]);
114 const Setting* isobarBlackListKey = findLibConfigArray(*waveSetParKey,
115 "isobarBlackList",
false);
116 if (isobarBlackListKey) {
117 _isobarBlackList.clear();
118 for (
int i = 0;
i < isobarBlackListKey->getLength(); ++
i)
119 _isobarBlackList.push_back((*isobarBlackListKey)[
i]);
121 const Setting* isobarWhiteListKey = findLibConfigArray(*waveSetParKey,
122 "isobarWhiteList",
false);
123 if (isobarWhiteListKey) {
124 _isobarWhiteList.clear();
125 for (
int i = 0;
i < isobarWhiteListKey->getLength(); ++
i)
126 _isobarWhiteList.push_back((*isobarWhiteListKey)[
i]);
128 waveSetParKey->lookupValue(
"requireMinIsobarMass", _requireMinIsobarMass );
129 waveSetParKey->lookupValue(
"isobarMassWindowSigma", _isobarMassWindowSigma);
132 printDebug <<
"parameters of " << *
this;
138 waveSetGenerator::generateWaveSet()
140 if (not _templateTopo) {
141 printWarn <<
"template decay topology was not yet constructed. "
142 <<
"did you call waveSetGenerator::setWaveSetParameters()?" << endl;
145 if (not _templateTopo->checkTopology()) {
146 printWarn <<
"ill-formed template decay topology. cannot generate wave set." << endl;
150 vector<nodeDesc> startNds
151 = _templateTopo->sortNodesDfs(_templateTopo->XIsobarDecayVertex());
153 vector<isobarDecayTopology> subDecays(startNds.size());
154 for (
size_t i = 0;
i < startNds.size(); ++
i)
155 subDecays[
i] = _templateTopo->subDecay(startNds[
i]);
157 reverse(startNds.begin (), startNds.end ());
158 reverse(subDecays.begin(), subDecays.end());
161 map<nodeDesc, vector<isobarDecayTopology> > decayPossibilities;
162 for (
size_t iStart = 0; iStart < startNds.size(); ++iStart) {
165 if (_templateTopo->isFsVertex(_templateTopo->vertex(startNds[iStart]))) {
168 decayPossibilities[startNds[iStart]].push_back(subDecays[iStart]);
173 printDebug <<
"generating decay topologies for subdecay[" << iStart <<
"]: "
174 << subDecays[iStart];
177 vector<vector<isobarDecayTopology>* > daughterDecays;
179 for (tie(iNd, iNdEnd) = _templateTopo->adjacentVertices(startNds[iStart]); iNd != iNdEnd; ++iNd)
180 daughterDecays.push_back(&decayPossibilities[*iNd]);
184 for (iDaughter[0] = 0; iDaughter[0] < daughterDecays[0]->size(); ++iDaughter[0])
185 for (iDaughter[1] = 0; iDaughter[1] < daughterDecays[1]->size(); ++iDaughter[1]) {
189 {(*daughterDecays[0])[iDaughter[0]].topNode(),
190 (*daughterDecays[1])[iDaughter[1]].topNode()};
192 {(*daughterDecays[0])[iDaughter[0]].vertex(topNodes[0])->inParticles()[0],
193 (*daughterDecays[1])[iDaughter[1]].vertex(topNodes[1])->inParticles()[0]};
195 printDebug <<
"combining decay[" << iDaughter[0] <<
"] of first daughter "
196 <<
"'" << daughters[0]->name() <<
"' "
197 <<
"with decay[" << iDaughter[1] <<
"] of second daughter "
198 <<
"'" << daughters[1]->name() <<
"'" << endl
199 << (*daughterDecays[0])[iDaughter[0]]
200 << (*daughterDecays[1])[iDaughter[1]];
205 (_templateTopo->vertex(startNds[iStart]))));
208 parentVertex->daughter1() = daughters[0];
209 parentVertex->daughter2() = daughters[1];
213 (*daughterDecays[0])[iDaughter[0]],
214 (*daughterDecays[1])[iDaughter[1]]);
217 const int parentBaryonNmb = daughters[0]->baryonNmb() + daughters[1]->baryonNmb();
218 const int parentCharge = daughters[0]->charge() + daughters[1]->charge();
219 const int parentStrangeness = daughters[0]->strangeness() + daughters[1]->strangeness();
220 const int parentCharm = daughters[0]->charm() + daughters[1]->charm();
221 const int parentBeauty = daughters[0]->beauty() + daughters[1]->beauty();
222 const int parentG = daughters[0]->G() * daughters[1]->G();
224 const int daughterI [2] = {daughters[0]->isospin(), daughters[1]->isospin() };
225 const int daughterI_z[2] = {daughters[0]->isospinProj(), daughters[1]->isospinProj()};
226 const int daughterJ [2] = {daughters[0]->J(), daughters[1]->J() };
231 for (tie(S, SMax) = getSpinRange(daughterJ[0], daughterJ[1], _SRange); S <= SMax; S += 2) {
233 printDebug <<
"setting total spin = " << spinQn(S) <<
" "
234 <<
"(max spin = " << spinQn(SMax) <<
")" << endl;
237 for (
int L = max(0, get<0>(_LRange)); L <= get<1>(_LRange); L += 2) {
239 printDebug <<
"setting relative orbital angular momentum = " << spinQn(L) <<
" "
240 <<
"(max L = " << spinQn(get<1>(_LRange)) <<
")" << endl;
241 const int parentP = daughters[0]->P() * daughters[1]->P() * powMinusOne(L / 2);
244 int parentJ, parentJMax;
245 for (tie(parentJ, parentJMax) = getSpinRange(L, S, _JRange);
246 parentJ <= parentJMax; parentJ += 2) {
248 printDebug <<
"setting parent spin = " << spinQn(parentJ) <<
" "
249 <<
"(max spin = " << spinQn(parentJMax) <<
")" << endl;
252 int parentI, parentIMax;
253 for (tie(parentI, parentIMax) = getSpinRange(daughterI[0], daughterI[1], _isospinRange);
254 parentI <= parentIMax; parentI += 2) {
256 printDebug <<
"setting parent isospin = " << spinQn(parentI) <<
" "
257 <<
"(max isospin = " << spinQn(parentIMax) <<
")" << endl;
260 const int parentI_z = 2 * parentCharge - (parentBaryonNmb + parentStrangeness
261 + parentCharm + parentBeauty);
266 if ((parentBaryonNmb == 0) and (parentI_z == 0) and (parentStrangeness == 0)
267 and (parentCharm == 0) and (parentBeauty == 0))
268 parentC = parentG * powMinusOne(parentI / 2);
270 printDebug <<
"trying isobar quantum numbers IG(JPC) = "
271 << spinQn(parentI) << sign(parentG)
272 <<
"(" << spinQn(parentJ) << sign(parentP) << sign(parentC) <<
")"
273 <<
", with L = " << spinQn(L) <<
", S = " << spinQn(S) << endl;
276 if (not spinStatesCanCouple(daughterI, daughterI_z, parentI, parentI_z)) {
278 cout <<
" rejected, because (I, I_z)[0] = (" << spinQn(daughterI[0])
279 <<
", " << spinQn(daughterI_z[0]) <<
") and (I, I_z)[1] = ("
280 << spinQn(daughterI[1]) <<
", " << spinQn(daughterI_z[1])
281 <<
") cannot couple to parent (I, I_z) = ("
282 << spinQn(parentI) <<
", " << spinQn(parentI_z) <<
")" << endl;
285 if (not _allowSpinExotics)
287 if (igjpIsExotic(parentI, parentG, parentJ, parentP)) {
289 cout <<
" rejected, because quantum number combination IG(JPC) = "
290 << spinQn(parentI) << sign(parentG) <<
"(" << spinQn(parentJ)
291 << sign(parentP) << sign(parentC) <<
") is spin-exotic" << endl;
296 if ( daughters[1]->antiPartProperties()
297 == *(static_pointer_cast<particleProperties>(daughters[0]))) {
302 if (parentG != powMinusOne((parentI + L + S) / 2)) {
304 cout <<
" rejected, because I[= " << spinQn(parentI) <<
"], "
305 <<
"L[= " << spinQn(L) <<
"], and S[= " << spinQn(S) <<
"] "
306 <<
"are not consistent with G-parity[= " << sign(parentG) <<
"]. "
307 <<
"for particle-antiparticle system ["
308 << daughters[0]->name() <<
", " << daughters[1]->name() <<
"] "
309 <<
"(-)^(I + L + S) = " << sign(powMinusOne((parentI + L + S) / 2))
310 <<
" must be equal to G-parity." << endl;
316 assert(parentI_z == 0);
317 assert(parentC == powMinusOne((L + S) / 2));
323 if (*(daughters[0]) == *(daughters[1]))
324 if (powMinusOne((parentI + L + S) / 2) != powMinusOne(daughterI[0])) {
326 cout <<
" rejected, because system with two identical particles ["
327 << daughters[0]->name() <<
", " << daughters[1]->name() <<
"] must have "
328 << ((powMinusOne(daughterI[0]) == +1) ?
"even" :
"odd")
329 <<
" (I[= " << spinQn(parentI) <<
"] + L[= " << spinQn(L) <<
"] "
330 <<
"+ S[= " << spinQn(S) <<
"]) = "
331 << spinQn(parentI) + spinQn(L) + spinQn(S) << endl;
338 isobarProp.
setSCB (parentStrangeness, parentCharm, parentBeauty);
339 isobarProp.
setIGJPC (parentI, parentG, parentJ, parentP, parentC);
342 if (parent->isXParticle()) {
344 tuple<int, int> parentMRange =
345 make_tuple(spinQnLargerEqual((_useReflectivity) ?
346 spinQnSmallerEqual(parentJ, 0) : -parentJ,
347 get<0>(_spinProjRange)),
348 spinQnSmallerEqual(parentJ, get<1>(_spinProjRange)));
349 tuple<int, int> parentReflRange(0, 0);
350 if (_useReflectivity) {
351 if (_reflectivity == 0)
352 parentReflRange = make_tuple(-1, +1);
354 parentReflRange = make_tuple(signum(_reflectivity), signum(_reflectivity));
356 for (
int parentM = get<0>(parentMRange); parentM <= get<1>(parentMRange);
359 printDebug <<
"setting X spin projection to " << spinQn(parentM) <<
" "
360 <<
"(max spin projection = " << spinQn(get<1>(parentMRange))
362 for (
int parentRefl = get<0>(parentReflRange);
363 parentRefl <= get<1>(parentReflRange); parentRefl += 2) {
364 if (_debug and (parentRefl != 0))
365 printDebug <<
"setting X reflectivity to "
366 << parityQn(parentRefl) << endl;
369 if ( _useReflectivity and (parentM == 0)
370 and (reflectivityFactor(parentJ, parentP, parentM, parentRefl) == +1)) {
372 printDebug <<
"rejected, because for quantum number combination "
373 <<
"JP(M refl) = " << spinQn(parentJ) << sign(parentP) <<
"("
374 << spinQn(parentM) << sign(parentRefl) <<
") "
375 <<
"amplitude is always zero"<< endl;
381 = createNewDecayTopology(parentDecay, parentVertex, L, S,
382 isobarProp, parentCharge);
383 decayCopy->XDecayVertex()->inParticles()[0]->setSpinProj(parentM);
384 decayCopy->XDecayVertex()->inParticles()[0]->setReflectivity(parentRefl);
385 decayPossibilities[startNds[iStart]].push_back(*decayCopy);
390 const double minIsobarMass = (_requireMinIsobarMass) ?
391 (daughters[0]->
mass() - _isobarMassWindowSigma * daughters[0]->width())
392 + (daughters[1]->
mass() - _isobarMassWindowSigma * daughters[1]->width())
396 decay(assign::list_of(daughters[0]->name())(daughters[1]->name()), L, S);
397 vector<const particleProperties*> possibleIsobars
398 = particleDataTable::entriesMatching(isobarProp,
"allQn",
399 minIsobarMass, _isobarMassWindowSigma,
400 _isobarWhiteList, _isobarBlackList,
401 decay, _forceDecayCheck);
403 if (possibleIsobars.empty())
404 printDebug <<
"rejected, because no matching isobar could be found for "
405 << isobarProp.
qnSummary() <<
" in particle data table" << endl;
407 printDebug <<
"found " << possibleIsobars.size() <<
" isobar candidate(s) for "
408 << isobarProp.
qnSummary() <<
" in particle data table" << endl;
412 for (
size_t iIsobar = 0; iIsobar < possibleIsobars.size(); ++iIsobar) {
414 printDebug <<
"setting isobar = '"
415 << possibleIsobars[iIsobar]->name() <<
"'" << endl;
418 = createNewDecayTopology(parentDecay, parentVertex, L, S,
419 *possibleIsobars[iIsobar], parentCharge);
420 decayPossibilities[startNds[iStart]].push_back(*decayCopy);
431 _waveSet = decayPossibilities[startNds.back()];
432 for (
size_t i = 0; i < _waveSet.size(); ++
i) {
435 (_templateTopo->productionVertex()->clone(
false,
false)));
436 const particlePtr& newX = _waveSet[
i].XIsobarDecayVertex()->parent();
437 newProdVert->outParticles()[0] = newX;
439 _waveSet[
i].setProductionVertex(newProdVert);
441 _waveSet[
i].calcIsobarCharges();
442 _waveSet[
i].productionVertex()->setXFlavorQN();
446 set<size_t> boseSymWaveIndices = findBoseSymDecays();
447 if (boseSymWaveIndices.size() > 0) {
448 _waveSet.erase(remove_if(_waveSet.begin(), _waveSet.end(),
449 rpwa::isInListOfIndices<isobarDecayTopology>(_waveSet.begin(),
450 boseSymWaveIndices)),
452 printSucc <<
"removed " << boseSymWaveIndices.size() <<
" Bose duplicates "
453 <<
"from wave set" << endl;
455 return _waveSet.size();
460 waveSetGenerator::writeKeyFiles(
const string& dirName,
461 const bool newKeyFileNameConvention)
463 size_t countSuccess = 0;
464 for (
size_t i = 0;
i < _waveSet.size(); ++
i) {
465 const string keyFileName = dirName +
"/"
466 + waveDescription::waveNameFromTopology(_waveSet[
i], newKeyFileNameConvention) +
".key";
467 if (waveDescription::writeKeyFile(keyFileName, _waveSet[i]))
470 printInfo <<
"wrote " << countSuccess <<
" out of " << _waveSet.size() <<
" key files" << endl;
471 if (countSuccess != _waveSet.size()) {
472 printWarn <<
"writing of " << _waveSet.size() - countSuccess <<
" key files failed" << endl;
480 waveSetGenerator::reset()
482 _isospinRange = make_tuple(0, 2);
483 _JRange = make_tuple(0, 0);
484 _spinProjRange = make_tuple(0, 0);
486 _useReflectivity =
false;
487 _allowSpinExotics =
false;
488 _LRange = make_tuple(0, 0);
489 _SRange = make_tuple(0, 0);
490 _requireMinIsobarMass =
false;
491 _forceDecayCheck =
false;
492 _isobarMassWindowSigma = 0;
493 _isobarBlackList.clear();
494 _isobarWhiteList.clear();
495 _templateTopo.reset();
501 waveSetGenerator::print(ostream& out)
const
503 out <<
"wave set generator:" << endl
504 <<
" isospin range .............. [" << spinQn(get<0>(_isospinRange)) <<
", "
505 << spinQn(get<1>(_isospinRange)) <<
"]" << endl
506 <<
" J range .................... [" << spinQn(get<0>(_JRange)) <<
", "
507 << spinQn(get<1>(_JRange)) <<
"]" << endl
508 <<
" M range .................... [" << spinQn(get<0>(_spinProjRange)) <<
", "
509 << spinQn(get<1>(_spinProjRange)) <<
"]" << endl
510 <<
" allow spin-exotics ......... " << yesNo(_allowSpinExotics) << endl;
511 if (_useReflectivity)
512 out <<
" generate reflectivity ...... " << ((_reflectivity == 0) ?
"both"
513 : sign(_reflectivity)) << endl;
514 out <<
" L range .................... [" << spinQn(get<0>(_LRange)) <<
", "
515 << spinQn(get<1>(_LRange)) <<
"]" << endl
516 <<
" S range .................... [" << spinQn(get<0>(_SRange)) <<
", "
517 << spinQn(get<1>(_SRange)) <<
"]" << endl
518 <<
" require min. isobar mass ... " << yesNo(_requireMinIsobarMass) << endl
519 <<
" isobar mass window par. .... " << _isobarMassWindowSigma <<
" [Gamma]" << endl
520 <<
" force decay checks ......... " << yesNo(_forceDecayCheck) << endl;
521 out <<
" isobar black list:";
522 if (_isobarBlackList.size() == 0)
523 out <<
" empty" << endl;
526 for (
size_t i = 0;
i < _isobarBlackList.size(); ++
i)
527 out <<
" " << _isobarBlackList[
i] << endl;
529 out <<
" isobar white list:";
530 if (_isobarWhiteList.size() == 0)
531 out <<
" all isobars" << endl;
534 for (
size_t i = 0;
i < _isobarWhiteList.size(); ++
i)
535 out <<
" " << _isobarWhiteList[
i] << endl;
538 out <<
"template " << *_templateTopo;
549 const int parentCharge)
555 = static_pointer_cast<
isobarDecayVertex>(decayCopy->vertex(parentDecay.node(parentVertex)));
556 parentVertexCopy->setL(L);
557 parentVertexCopy->setS(S);
559 const particlePtr& parentCopy = parentVertexCopy->parent();
560 parentCopy->setProperties(isobar);
561 parentCopy->setCharge(parentCharge);
563 printDebug <<
"created decay topology for " << *parentVertexCopy << endl;
569 waveSetGenerator::findBoseSymDecays()
const
571 printInfo <<
"looking for Bose duplicates in wave set..." << endl;
572 set<size_t> waveIndicesToRemove;
573 set<size_t> waveIndicesToKeep;
574 for (
size_t waveIndex = 0; waveIndex < _waveSet.size(); ++waveIndex) {
577 set<size_t>::const_iterator indexEntry = waveIndicesToRemove.find(waveIndex);
578 if (indexEntry != waveIndicesToRemove.end())
580 indexEntry = waveIndicesToKeep.find(waveIndex);
581 if (indexEntry != waveIndicesToKeep.end())
586 const vector<unsigned int> boseSymVertIds = topo->findIsobarBoseSymVertices();
587 const size_t nmbBoseSymVertIds = boseSymVertIds.size();
588 if (nmbBoseSymVertIds > 1) {
589 printErr <<
"the code has not yet been tested for decay topologies with "
590 << nmbBoseSymVertIds <<
" Bose-symmetric decay vertices. aborting." << endl;
593 if (nmbBoseSymVertIds != 1)
598 const particlePtr daughters[2] = {vert->daughter1(), vert->daughter2()};
599 if (*(daughters[0]) == *(daughters[1]))
602 topo->
subDecay(topo->toNode(daughters[1]))};
604 printDebug <<
"wave[" << waveIndex <<
"] "
605 << waveDescription::waveNameFromTopology(*topo,
true)
606 <<
" has Bose-symmetric vertex " << *vert <<
". "
607 <<
"looking for partner waves in wave set." << endl;
610 vector<unsigned int> nonSymVertIds;
613 const vector<nodeDesc> nodes = topo->sortNodesDfs(vert);
614 for (
unsigned int i = 0;
i < topo->nmbDecayVertices(); ++
i) {
615 const nodeDesc nd = topo->node(topo->isobarDecayVertices()[
i]);
616 bool isSymNode =
false;
617 for (
unsigned int j = 0; j < nodes.size(); ++j)
618 if (nd == nodes[j]) {
623 nonSymVertIds.push_back(
i);
630 for (
size_t i = 0;
i < _waveSet.size(); ++
i) {
636 bool foundSymTopo =
true;
637 for (
size_t j = 0; j < nonSymVertIds.size(); ++j)
638 if ( *(topo->isobarDecayVertices ()[nonSymVertIds[j]])
639 != *(symTopo->isobarDecayVertices()[nonSymVertIds[j]])) {
640 foundSymTopo =
false;
643 if (not foundSymTopo)
648 swap(symVert->outParticles()[0], symVert->outParticles()[1]);
649 if (*symVert != *vert)
651 swap(symVert->outParticles()[1], symVert->outParticles()[0]);
653 const particlePtr symDaughters [2] = {symVert->daughter2(), symVert->daughter1()};
655 = {symTopo->
subDecay(symTopo->toNode(symDaughters[0])),
656 symTopo->
subDecay(symTopo->toNode(symDaughters[1]))};
657 for (
unsigned int k = 0; k < 2; ++k)
659 if ( *(daughterTopos [k].decayVertices()[l])
661 foundSymTopo =
false;
664 if (not foundSymTopo)
667 printDebug <<
"found Bose-partner wave[" <<
i <<
"] "
668 << waveDescription::waveNameFromTopology(*symTopo,
true) << endl;
670 if (daughters[0]->
mass() > daughters[1]->
mass()) {
671 if ( not waveIndicesToRemove.insert(
i).second
672 or not waveIndicesToKeep.insert(waveIndex).second) {
673 printErr <<
"wave[" <<
i <<
"]([" << waveIndex <<
"]) was tagged for "
674 <<
"removal(for keeping) twice. this should never happen. aborting." << endl;
677 printInfo <<
"tagged wave " << waveDescription::waveNameFromTopology(*symTopo,
true)
678 <<
" as superfluous" << endl;
680 if ( not waveIndicesToRemove.insert(waveIndex).second
681 or not waveIndicesToKeep.insert(
i).second) {
682 printErr <<
"wave[" << waveIndex <<
"]([" <<
i <<
"]) was tagged for "
683 <<
"removal(for keeping) twice. this should never happen. aborting." << endl;
686 printInfo <<
"tagged wave " << waveDescription::waveNameFromTopology(*topo,
true)
687 <<
" as superfluous" << endl;
693 printSucc <<
"found " << waveIndicesToRemove.size() <<
" Bose duplicates "
694 <<
"in wave set" << endl;
695 return waveIndicesToRemove;