8 #include "Pythia8/HadronWidths.h"
16 static string attributeValue(
string line,
string attribute) {
17 if (line.find(attribute) == string::npos)
return "";
18 int iBegAttri = line.find(attribute);
19 int iBegQuote = line.find(
"\"", iBegAttri + 1);
20 int iEndQuote = line.find(
"\"", iBegQuote + 1);
21 return line.substr(iBegQuote + 1, iEndQuote - iBegQuote - 1);
24 static int intAttributeValue(
string line,
string attribute) {
25 string valString = attributeValue(line, attribute);
26 if (valString ==
"")
return 0;
27 istringstream valStream(valString);
33 static double doubleAttributeValue(
string line,
string attribute) {
34 string valString = attributeValue(line, attribute);
35 if (valString ==
"")
return 0.;
36 istringstream valStream(valString);
38 valStream >> doubleVal;
42 static void completeTag(istream& stream,
string& line) {
43 while (line.find(
">") == string::npos) {
45 if (!getline(stream, addLine))
break;
46 line +=
" " + addLine;
58 bool HadronWidths::init(
string path) {
60 ifstream stream(path);
61 if (!stream.is_open()) {
62 infoPtr->errorMsg(
"Error in HadronWidths::init: "
63 "unable to open file");
74 bool HadronWidths::init(istream& stream) {
78 while (getline(stream, line)) {
81 if (!(istringstream(line) >> word1))
84 if (word1 ==
"<width") {
85 completeTag(stream, line);
87 int id = intAttributeValue(line,
"id");
89 if (entries.find(
id) != entries.end()) {
90 infoPtr->errorMsg(
"Error in HadronWidths::readXML: "
91 "resonance is defined more than once",
96 double left = doubleAttributeValue(line,
"left");
97 double right = doubleAttributeValue(line,
"right");
99 istringstream dataStr(attributeValue(line,
"data"));
102 while (dataStr >> currentData)
103 data.push_back(currentData);
106 LinearInterpolator widths(left, right, data);
107 entries.emplace(
id, HadronWidthEntry{ widths, {} });
110 int signature = getSignature(particleDataPtr->isBaryon(
id),
111 particleDataPtr->chargeType(
id));
113 auto iter = signatureToParticles.find(signature);
114 if (iter == signatureToParticles.end())
116 signatureToParticles.emplace(signature, vector<int> {
id });
119 iter->second.push_back(
id);
121 else if (word1 ==
"<partialWidth") {
122 completeTag(stream, line);
124 int id = intAttributeValue(line,
"id");
126 auto entryIter = entries.find(
id);
127 if (entryIter == entries.end()) {
128 infoPtr->errorMsg(
"Error in HadronWidths::readXML: "
129 "got partial width for a particle with undefined total width",
134 int lType = intAttributeValue(line,
"lType");
136 istringstream productStr(attributeValue(line,
"products"));
141 istringstream dataStr(attributeValue(line,
"data"));
144 while (dataStr >> currentData)
145 data.push_back(currentData);
147 HadronWidthEntry& entry = entryIter->second;
148 LinearInterpolator widths(entry.width.left(), entry.width.right(), data);
151 pair<int, int> key = getKey(
id, prod1, prod2);
152 double mThreshold = particleDataPtr->mMin(key.first)
153 + particleDataPtr->mMin(key.second);
156 entry.decayChannels.emplace(key, ResonanceDecayChannel {
157 widths, key.first, key.second, lType, mThreshold });
169 bool HadronWidths::check() {
172 for (
auto& entryPair : entries) {
173 int id = entryPair.first;
174 HadronWidthEntry& entry = entryPair.second;
177 if (!particleDataPtr->isParticle(
id)) {
178 infoPtr->errorMsg(
"Error in HadronWidths::check: "
179 "resonance is not a particle", std::to_string(
id));
185 infoPtr->errorMsg(
"Error in HadronWidths::check: "
186 "resonance is an antiparticle", std::to_string(
id));
191 if (!particleDataPtr->isHadron(
id)) {
192 infoPtr->errorMsg(
"Error in HadronWidths::check: "
193 "resonance is not a hadron", std::to_string(
id));
198 if (particleDataPtr->mMin(
id) < entry.width.left()) {
199 infoPtr->errorMsg(
"Warning in HadronWidths::check: "
200 "inconsistent lower mass bound", std::to_string(
id));
202 if (particleDataPtr->mMax(
id) > entry.width.right()) {
203 infoPtr->errorMsg(
"Warning in HadronWidths::check: "
204 "inconsistent upper mass bound", std::to_string(
id));
208 for (
auto channelPair : entry.decayChannels) {
209 ResonanceDecayChannel& channel = channelPair.second;
210 int idA = channel.prodA, idB = channel.prodB;
211 string channelStr = std::to_string(
id) +
" --> "
212 + std::to_string(idA) +
" + " + std::to_string(idB);
215 for (
int idProd : { idA, idB })
216 if (!particleDataPtr->isParticle(idProd)) {
217 infoPtr->errorMsg(
"Error in HadronWidths::check: "
218 "decay product is not a particle", std::to_string(idProd));
222 if (channel.lType <= 0) {
223 infoPtr->errorMsg(
"Error in HadronWidths::check: "
224 "decay channel does not specify a valid lType", channelStr);
229 if (particleDataPtr->chargeType(idA) + particleDataPtr->chargeType(idB)
230 != particleDataPtr->chargeType(
id)) {
231 infoPtr->errorMsg(
"Error in HadronWidths::check: "
232 "decay does not conserve charge", channelStr);
238 for (
auto& entry : *particleDataPtr) {
239 if (entry.second.varWidth() && !hasData(entry.first)) {
240 infoPtr->errorMsg(
"Warning in HadronWidths::check: "
241 "particle uses mass dependent width, but width is not defined",
242 std::to_string(entry.first));
253 pair<int, int> HadronWidths::getKey(
int& idR,
int idA,
int idB)
const {
257 idA = particleDataPtr->antiId(idA);
258 idB = particleDataPtr->antiId(idB);
261 if (abs(idA) < abs(idB))
271 int HadronWidths::getSignature(
int baryonNumber,
int charge)
const {
272 return 100 * baryonNumber
273 + 10 * ((charge >= 0) ? charge : (10 + charge));
280 vector<int> HadronWidths::getResonances()
const {
281 vector<int> resonances;
282 for (
auto& p : entries)
283 resonances.push_back(p.first);
290 bool HadronWidths::hasResonances(
int idA,
int idB)
const {
292 ParticleDataEntry* entryA = particleDataPtr->findParticle(idA);
293 ParticleDataEntry* entryB = particleDataPtr->findParticle(idB);
294 if (!entryA || !entryB) {
295 infoPtr->errorMsg(
"Error in HadronWidths::possibleResonances: "
296 "invalid input particle ids");
301 int baryonNumber = entryA->isBaryon() + entryB->isBaryon();
302 int charge = entryA->chargeType(idA) + entryB->chargeType(idB);
303 int signature = getSignature(baryonNumber, charge);
304 auto iter = signatureToParticles.find(signature);
305 if (iter == signatureToParticles.end())
309 for (
int res : iter->second)
310 if (canDecay(res, idA, idB))
321 vector<int> HadronWidths::possibleResonances(
int idA,
int idB)
const {
323 vector<int> resonances;
324 ParticleDataEntry* entryA = particleDataPtr->findParticle(idA);
325 ParticleDataEntry* entryB = particleDataPtr->findParticle(idB);
326 if (!entryA || !entryB) {
327 infoPtr->errorMsg(
"Error in HadronWidths::possibleResonances: "
328 "invalid input particle ids");
333 int baryonNumber = entryA->isBaryon() + entryB->isBaryon();
334 int charge = entryA->chargeType(idA) + entryB->chargeType(idB);
335 int signature = getSignature(baryonNumber, charge);
336 auto iter = signatureToParticles.find(signature);
337 if (iter == signatureToParticles.end())
338 return vector<int>();
341 for (
int res : iter->second)
342 if (canDecay(res, idA, idB))
343 resonances.push_back(res);
346 if ( (idA == 111 && idB == 111)
347 || (abs(idA) == 211 && abs(idB) == 211 && idA * idB < 0) )
348 resonances.push_back(9000221);
358 bool HadronWidths::canDecay(
int idR,
int idA,
int idB)
const {
360 auto entryIter = entries.find(idR);
361 if (entryIter == entries.end())
364 pair<int, int> key = getKey(idR, idA, idB);
365 auto channelIter = entryIter->second.decayChannels.find(key);
366 return channelIter != entryIter->second.decayChannels.end();
373 double HadronWidths::width(
int id,
double m)
const {
374 auto iter = entries.find(abs(
id));
375 return (iter != entries.end()) ? iter->second.width(m)
376 : particleDataPtr->mWidth(
id);
383 double HadronWidths::partialWidth(
int idR,
int idA,
int idB,
double m)
const {
385 auto entryIter = entries.find(idR);
386 if (entryIter == entries.end())
389 pair<int, int> key = getKey(idR, idA, idB);
390 auto channelIter = entryIter->second.decayChannels.find(key);
391 if (channelIter == entryIter->second.decayChannels.end())
394 return (m <= channelIter->second.mThreshold) ? 0.
395 : channelIter->second.partialWidth(m);
402 double HadronWidths::br(
int idR,
int idA,
int idB,
double m)
const {
404 auto entryIter = entries.find(idR);
405 if (entryIter == entries.end())
408 pair<int, int> key = getKey(idR, idA, idB);
409 auto channelIter = entryIter->second.decayChannels.find(key);
410 if (channelIter == entryIter->second.decayChannels.end())
413 double widthNow = entryIter->second.width(m);
417 return (m <= channelIter->second.mThreshold) ? 0.
418 : channelIter->second.partialWidth(m) / widthNow;
425 double HadronWidths::mDistr(
int id,
double m)
const {
426 auto iter = entries.find(abs(
id));
427 double w = (iter == entries.end()) ? particleDataPtr->mWidth(
id)
428 : iter->second.width(m);
429 double m0 = particleDataPtr->m0(
id);
430 return 0.5 / M_PI * w / (pow2(m - m0) + 0.25 * w * w);
438 bool HadronWidths::pickDecay(
int idDec,
double m,
int& idAOut,
int& idBOut,
439 double& mAOut,
double& mBOut) {
442 bool isAnti = (idDec < 0);
443 if (isAnti) idDec = -idDec;
444 auto entriesIter = entries.find(idDec);
445 if (entriesIter == entries.end()) {
446 infoPtr->errorMsg(
"Error in HadronWidths::pickDecay: "
447 "particle not found", std::to_string(idDec));
450 HadronWidthEntry& entry = entriesIter->second;
453 vector<pair<int, int>> prodsList;
454 vector<double> sigmas;
456 for (
auto& channel : entry.decayChannels) {
457 if (m <= channel.second.mThreshold)
459 double sigma = channel.second.partialWidth(m);
462 prodsList.push_back(channel.first);
463 sigmas.push_back(sigma);
467 infoPtr->errorMsg(
"Error in HadronWidths::pickDecay: "
468 "no channels have positive widths",
469 "for " + to_string(idDec) +
" @ " + to_string(m) +
" GeV");
474 pair<int, int> prods = prodsList[rndmPtr->pick(sigmas)];
475 int idA = prods.first;
476 int idB = prods.second;
477 int lType = entry.decayChannels.at(prods).lType;
481 if (!pickMasses(idA, idB, m, mA, mB, lType)) {
482 infoPtr->errorMsg(
"Error in HadronWidths::pickDecay: failed to pick "
483 "masses",
"for " + to_string(idDec) +
" --> " + to_string(idA)
484 +
" + " + to_string(idB) +
" @ " + to_string(m));
489 idAOut = isAnti ? particleDataPtr->antiId(idA) : idA;
490 idBOut = isAnti ? particleDataPtr->antiId(idB) : idB;
500 static constexpr
int MAXLOOP = 100;
501 static constexpr
double MINWIDTH = 0.001;
502 static constexpr
double MAXWIDTHGROWTH = 2.;
508 bool HadronWidths::pickMasses(
int idA,
int idB,
double eCM,
509 double& mAOut,
double& mBOut,
int lType) {
512 double mAMin = particleDataPtr->mMin(idA);
513 double mBMin = particleDataPtr->mMin(idB);
514 if (mAMin + mBMin >= eCM) {
515 infoPtr->errorMsg(
"Error in HadronWidths::pickMasses: "
516 "energy is smaller than minimum masses");
521 infoPtr->errorMsg(
"Error in HadronWidths::pickMasses: "
522 "invalid angular momentum",
"2l+1 = " + to_string(lType));
527 double mAFix = particleDataPtr->m0(idA);
528 double gammaAFix = particleDataPtr->mWidth(idA);
529 bool hasFixWidthA = (gammaAFix > MINWIDTH);
530 double mBFix = particleDataPtr->m0(idB);
531 double gammaBFix = particleDataPtr->mWidth(idB);
532 bool hasFixWidthB = (gammaBFix > MINWIDTH);
535 if (!hasFixWidthA && !hasFixWidthB)
return true;
538 bool hasVarWidthA = hasData(idA) && particleDataPtr->varWidth(idA);
539 bool hasWidthA = hasFixWidthA || hasVarWidthA;
540 HadronWidthEntry* entryA =
nullptr;
542 auto iterA = entries.find( abs(idA) );
543 if (iterA == entries.end()) {
544 infoPtr->errorMsg(
"Error in HadronWidths::pickMasses: "
545 "mass distribution for particle is not defined", std::to_string(idA));
548 entryA = &iterA->second;
550 bool hasVarWidthB = hasData(idB) && particleDataPtr->varWidth(idB);
551 bool hasWidthB = hasFixWidthB || hasVarWidthB;
552 HadronWidthEntry* entryB =
nullptr;
554 auto iterB = entries.find( abs(idB) );
555 if (iterB == entries.end()) {
556 infoPtr->errorMsg(
"Error in HadronWidths::pickMasses: "
557 "mass distribution for particle is not defined", std::to_string(idB));
560 entryB = &iterB->second;
564 double mAMax = min(particleDataPtr->mMax(idA), eCM - mBMin);
565 if (hasVarWidthA) gammaAFix = entryA->width(mAFix);
566 double bwAMin = (hasWidthA) ? atan(2. * (mAMin - mAFix) / gammaAFix) : 0.;
567 double bwAMax = (hasWidthA) ? atan(2. * (mAMax - mAFix) / gammaAFix) : 0.;
568 double mBMax = min(particleDataPtr->mMax(idB), eCM - mAMin);
569 if (hasVarWidthB) gammaBFix = entryB->width(mBFix);
570 double bwBMin = (hasWidthB) ? atan(2. * (mBMin - mBFix) / gammaBFix) : 0.;
571 double bwBMax = (hasWidthB) ? atan(2. * (mBMax - mBFix) / gammaBFix) : 0.;
572 double p2Max = (eCM*eCM - pow2(mAMin + mBMin))
573 * (eCM*eCM - pow2(mAMin - mBMin));
576 double wtTot, gammaAVar, gammaBVar, bwAFix, bwBFix, bwAVar, bwBVar;
577 for (
int i = 0; i < MAXLOOP; ++i) {
581 if (2 * i > MAXLOOP) {
582 hasVarWidthA =
false;
583 hasVarWidthB =
false;
585 if (4 * i > 3 * MAXLOOP) lType = 0;
588 if (hasWidthA) mAOut = mAFix + 0.5 * gammaAFix * tan(bwAMin
589 + rndmPtr->flat() * (bwAMax - bwAMin));
590 if (hasWidthB) mBOut = mBFix + 0.5 * gammaBFix * tan(bwBMin
591 + rndmPtr->flat() * (bwBMax - bwBMin));
596 gammaAVar = min(entryA->width(mAOut), MAXWIDTHGROWTH * gammaAFix);
597 bwAVar = gammaAVar / (pow2( mAOut - mAFix) + 0.25 * pow2(gammaAVar));
598 bwAFix = gammaAFix / (pow2( mAOut - mAFix) + 0.25 * pow2(gammaAFix));
599 wtTot *= bwAVar / (bwAFix * MAXWIDTHGROWTH);
602 gammaBVar = min(entryB->width(mBOut), MAXWIDTHGROWTH * gammaBFix);
603 bwBVar = gammaBVar / (pow2( mBOut - mBFix) + 0.25 * pow2(gammaBVar));
604 bwBFix = gammaBFix / (pow2( mBOut - mBFix) + 0.25 * pow2(gammaBFix));
605 wtTot *= bwBVar / (bwBFix * MAXWIDTHGROWTH);
609 if (mAOut + mBOut >= eCM)
continue;
610 double p2Ratio = (eCM*eCM - pow2(mAOut + mBOut))
611 * (eCM*eCM - pow2(mAOut - mBOut)) / p2Max;
612 if (lType > 0) wtTot *= pow(p2Ratio, 0.5 * lType);
613 if (wtTot > rndmPtr->flat()) {
615 if (4 * i > 3 * MAXLOOP) infoPtr->errorMsg(
"Warning in HadronWidths::"
616 "pickMasses: angular momentum and running widths not used");
622 infoPtr->errorMsg(
"Warning in HadronWidths::pickMasses: "
623 "using last-resort simplified description");
624 double mSpanNorm = (eCM - mAMin - mBMin) / (gammaAFix + gammaBFix);
625 mAOut = mAMin + rndmPtr->flat() * mSpanNorm * gammaAFix;
626 mBOut = mBMin + rndmPtr->flat() * mSpanNorm * gammaBFix;
637 double HadronWidths::widthCalc(
int id,
double m)
const {
640 ParticleDataEntry* entry = particleDataPtr->findParticle(
id);
641 if (entry ==
nullptr) {
642 infoPtr->errorMsg(
"Error in HadronWidths::widthCalc: "
643 "particle not found", to_string(
id));
649 for (
int iChan = 0; iChan < entry->sizeChannels(); ++iChan)
650 w += widthCalc(
id, entry->channel(iChan), m);
658 double HadronWidths::widthCalc(
int id,
int prodA,
int prodB,
double m)
const {
661 pair<int, int> key = getKey(
id, prodA, prodB);
662 ParticleDataEntry* entry = particleDataPtr->findParticle(
id);
663 if (entry ==
nullptr)
667 for (
int iChan = 0; iChan < entry->sizeChannels(); ++iChan) {
668 DecayChannel& channel = entry->channel(iChan);
669 if (channel.multiplicity() > 2)
671 if ( (channel.product(0) == key.first && channel.product(1) == key.second)
672 || (channel.product(1) == key.first && channel.product(0) == key.second))
673 return widthCalc(
id, channel, m);
677 infoPtr->errorMsg(
"Error in HadronWidths::widthCalc: "
678 "decay channel not found",
679 to_string(
id) +
" --> " + to_string(prodA) +
" " + to_string(prodB));
691 ParticleDataEntry* entry = particleDataPtr->findParticle(
id);
692 if (entry ==
nullptr) {
693 infoPtr->errorMsg(
"Error in HadronWidths::widthCalc: "
694 "particle not found", to_string(
id));
699 double m0 = entry->m0(), gamma0 = channel.bRatio() * entry->mWidth();
702 if (channel.multiplicity() != 2)
703 return channel.bRatio();
704 auto& prodA = *particleDataPtr->findParticle(channel.product(0));
705 auto& prodB = *particleDataPtr->findParticle(channel.product(1));
707 if (m < prodA.mMin() + prodB.mMin())
712 if (channel.meMode() >= 3 && channel.meMode() <= 7)
713 lType = 2 * (channel.meMode() - 3) + 1;
714 else if (channel.meMode() == 2)
720 double pM = psSize(m, prodA, prodB, lType);
723 double pMS = psSize(m, prodA, prodB, lType - 1);
728 double pM0 = psSize(m0, prodA, prodB, lType);
729 double pM0S = psSize(m0, prodA, prodB, lType - 1);
730 if (pM0 <= 0 || pM0S <= 0) {
731 infoPtr->errorMsg(
"Error in HadronWidths::widthCalc: "
732 "on-shell decay is not possible",
733 to_string(
id) +
" --> " + to_string(prodA.id())
734 +
" " + to_string(prodB.id()));
739 return gamma0 * (m0 / m) * (pM / pM0) * 1.2 / (1. + 0.2 * pMS / pM0S);
746 bool HadronWidths::parameterize(
int id,
int precision) {
749 ParticleDataEntry* entry = particleDataPtr->findParticle(
id);
751 if (entry ==
nullptr) {
752 infoPtr->errorMsg(
"Error in HadronWidths::parameterize: "
753 "particle does not exist", to_string(
id));
756 if (precision <= 1) {
757 infoPtr->errorMsg(
"Error in HadronWidths::parameterize: "
758 "precision must be at least 2");
761 if (entry->mMin() >= entry->mMax()) {
762 infoPtr->errorMsg(
"Error in HadronWidths::parameterize: "
763 "particle has fixed mass", to_string(
id));
767 if (!entry->varWidth())
768 infoPtr->errorMsg(
"Warning in HadronWidths::parameterize: "
769 "particle does not have mass-dependent width", to_string(
id));
771 map<pair<int, int>, ResonanceDecayChannel> partialWidths;
772 vector<double> totalWidthData(precision);
774 double mMin = entry->mMin(), mMax = entry->mMax();
775 double dm = (mMax - mMin) / (precision - 1);
778 for (
int iChan = 0; iChan < entry->sizeChannels(); ++iChan) {
781 DecayChannel& channel = entry->channel(iChan);
782 if (channel.multiplicity() != 2)
786 pair<int, int> key = getKey(
id, channel.product(0), channel.product(1));
787 int prodA = key.first, prodB = key.second;
790 vector<double> widthData(precision);
791 for (
int j = 0; j < precision; ++j) {
792 double m = mMin + j * dm;
793 widthData[j] = widthCalc(entry->id(), channel, m);
794 totalWidthData[j] += widthData[j];
799 if (channel.meMode() >= 3 && channel.meMode() <= 7)
800 lType = 2 * (channel.meMode() - 3) + 1;
801 else if (channel.meMode() == 2)
807 partialWidths.emplace(make_pair(prodA, prodB), ResonanceDecayChannel {
808 LinearInterpolator(mMin, mMax, widthData),
810 max(mMin, particleDataPtr->mMin(prodA) + particleDataPtr->mMin(prodB))
815 HadronWidthEntry newEntry {
816 LinearInterpolator(mMin, mMax, totalWidthData),
819 auto iter = entries.find(
id);
820 if (iter == entries.end())
821 entries.emplace(
id, newEntry);
823 entries[id] = newEntry;
833 static double pCMS(
double eCM,
double mA,
double mB) {
834 if (eCM <= mA + mB)
return 0;
835 double sCM = eCM * eCM;
836 return sqrt((sCM - pow2(mA + mB)) * (sCM - pow2(mA - mB))) / (2. * eCM);
843 double HadronWidths::psSize(
double eCM, ParticleDataEntry& prodA,
844 ParticleDataEntry& prodB,
double lType)
const {
847 int idA = prodA.id(), idB = prodB.id();
848 double m0A = prodA.m0(), m0B = prodB.m0();
849 double mMinA = prodA.mMin(), mMinB = prodB.mMin();
850 double mMaxA = prodA.mMax(), mMaxB = prodB.mMax();
851 bool varA = mMaxA > mMinA, varB = mMaxB > mMinB;
853 if (eCM < mMinA + mMinB)
861 return pow(pCMS(eCM, m0A, m0B), lType);
864 else if (varA && !varB) {
865 if (eCM <= mMinA + m0B)
869 auto f = [=](
double mA) {
870 return pow(pCMS(eCM, mA, m0B), lType) * mDistr(idA, mA); };
871 if (!integrateGauss(result, f, mMinA, min(mMaxA, eCM - m0B)))
876 else if (!varA && varB) {
877 if (eCM <= m0A + mMinB)
881 auto f = [=](
double mB) {
882 return pow(pCMS(eCM, m0A, mB), lType) * mDistr(idB, mB); };
883 if (!integrateGauss(result, f, mMinB, min(mMaxB, eCM - m0A)))
889 if (eCM <= mMinA + mMinB)
893 auto I = [=, &success](
double mA) {
896 auto f = [=](
double mB) {
897 return pow(pCMS(eCM, mA, mB), lType)
898 * mDistr(idA, mA) * mDistr(idB, mB); };
902 if (!integrateGauss(res, f, mMinB, min(mMaxB, eCM - mA)))
909 if (!integrateGauss(result, I, mMinA, min(mMaxA, eCM - mMinB)))
917 infoPtr->errorMsg(
"Error in HadronWidths::psSize: Unable to integrate");
926 bool HadronWidths::parameterizeRecursive(
int id,
int precision) {
933 ParticleDataEntry& entry = *particleDataPtr->findParticle(
id);
936 for (
int iChannel = 0; iChannel < entry.sizeChannels(); ++iChannel) {
937 DecayChannel& channel = entry.channel(iChannel);
938 if (channel.multiplicity() == 2) {
939 auto& prodA = *particleDataPtr->findParticle(channel.product(0));
940 auto& prodB = *particleDataPtr->findParticle(channel.product(1));
943 if (prodA.varWidth() && !hasData(prodA.id()))
944 if (!parameterizeRecursive(prodA.id(), precision))
return false;
945 if (prodB.varWidth() && !hasData(prodB.id()))
946 if (!parameterizeRecursive(prodB.id(), precision))
return false;
951 infoPtr->errorMsg(
"Info from HadronWidths::parameterizeAll: "
952 "parameterizing", to_string(
id),
true);
953 return parameterize(
id, precision);
960 void HadronWidths::parameterizeAll(
int precision) {
963 vector<ParticleDataEntry*> variableWidthEntries;
964 for (
auto& mapEntry : *particleDataPtr) {
965 ParticleDataEntry& entry = mapEntry.second;
966 if (entry.varWidth())
967 variableWidthEntries.push_back(&entry);
973 for (ParticleDataEntry* entry : variableWidthEntries) {
974 if (!parameterizeRecursive(entry->id(), precision)) {
975 infoPtr->errorMsg(
"Abort from HadronWidths::parameterizeAll: "
976 "parameterization failed");
986 bool HadronWidths::save(ostream& stream)
const {
993 for (
auto& mapEntry : entries) {
994 int id = mapEntry.first;
995 const HadronWidthEntry& entry = mapEntry.second;
1001 stream <<
"<width id=\"" <<
id <<
"\" "
1002 <<
"left=\"" << entry.width.left() <<
"\" "
1003 <<
"right=\"" << entry.width.right() <<
"\" "
1005 for (
double dataPoint : entry.width.data()) {
1006 stream <<
" " << dataPoint;
1012 stream <<
"\"/> \n \n";
1015 for (
auto& channelEntry : entry.decayChannels) {
1016 const ResonanceDecayChannel& channel = channelEntry.second;
1017 stream <<
"<partialWidth id=\"" <<
id <<
"\" "
1018 <<
"products=\"" << channel.prodA <<
" " << channel.prodB <<
"\" "
1019 <<
"lType=\"" << channel.lType <<
"\" data=\" \n";
1021 for (
double dataPoint : channel.partialWidth.data()){
1022 stream <<
" " << dataPoint;
1028 stream <<
"\"/> \n \n";