9 #include "Pythia8/ResonanceDecays.h"
24 const int ResonanceDecays::NTRYCHANNEL = 10;
27 const int ResonanceDecays::NTRYMASSES = 10000;
30 const double ResonanceDecays::MSAFETY = 0.01;
33 const double ResonanceDecays::WIDTHCUT = 5.;
36 const double ResonanceDecays::TINY = 1e-10;
39 const double ResonanceDecays::TINYBWRANGE = 1e-8;
43 const double ResonanceDecays::WTCORRECTION[11] = { 1., 1., 1.,
44 2., 5., 15., 60., 250., 1250., 7000., 50000. };
48 bool ResonanceDecays::next(
Event& process,
int iDecNow) {
54 Particle& decayer = process[iDec];
55 if (decayer.isFinal() && decayer.canDecay() && decayer.mayDecay()
56 && decayer.isResonance() ) {
63 idProd.push_back( id0 );
64 mProd.push_back( m0 );
67 int idIn = process[decayer.mother1()].id();
70 if (!decayer.particleDataEntry().preparePick(id0, m0, idIn)) {
72 osWarn <<
"for id = " << id0;
73 infoPtr->errorMsg(
"Error in ResonanceDecays::next:"
74 " no open decay channel", osWarn.str());
79 bool foundChannel =
false;
80 for (
int iTryChannel = 0; iTryChannel < NTRYCHANNEL; ++iTryChannel) {
83 DecayChannel& channel = decayer.particleDataEntry().pickChannel();
84 mult = channel.multiplicity();
89 for (
int i = 1; i <= mult; ++i) {
90 idNow = channel.product(i - 1);
91 if (id0 < 0 && particleDataPtr->hasAnti(idNow)) idNow = -idNow;
92 idProd.push_back( idNow);
97 if (!pickMasses())
continue;
104 ostringstream osWarn;
105 osWarn <<
"for id = " << id0;
106 infoPtr->errorMsg(
"Error in ResonanceDecays::next:"
107 " failed to find workable decay channel", osWarn.str());
112 if (!pickColours(iDec, process))
return false;
116 pProd.push_back( decayer.p() );
117 if (!pickKinematics())
return false;
120 int iFirst = process.size();
121 for (
int i = 1; i <= mult; ++i) {
122 process.append( idProd[i], 23, iDec, 0, 0, 0, cols[i], acols[i],
123 pProd[i], mProd[i], m0);
125 int iLast = process.size() - 1;
128 if (process[iDec].hasVertex() || process[iDec].tau() > 0.) {
129 Vec4 vDec = process[iDec].vDec();
130 for (
int i = iFirst; i <= iLast; ++i) process[i].vProd( vDec );
134 for (
int i = iFirst; i <= iLast; ++i)
135 process[i].tau( process[i].tau0() * rndmPtr->exp() );
139 decayer.daughters(iFirst, iLast);
143 }
while (iDecNow == 0 && ++iDec < process.size());
154 bool ResonanceDecays::pickMasses() {
158 vector<double> m0BW, mMinBW, mMaxBW, widthBW;
159 double mMother = mProd[0];
160 double m2Mother = mMother * mMother;
161 useBW.push_back(
false );
162 m0BW.push_back( mMother );
163 mMinBW.push_back( mMother );
164 mMaxBW.push_back( mMother );
165 widthBW.push_back( 0. );
169 double m0Now, mMinNow, mMaxNow, widthNow;
170 for (
int i = 1; i <= mult; ++i) {
171 useBWNow = particleDataPtr->useBreitWigner( idProd[i] );
172 m0Now = particleDataPtr->m0( idProd[i] );
173 mMinNow = particleDataPtr->m0Min( idProd[i] );
174 mMaxNow = particleDataPtr->m0Max( idProd[i] );
175 if (useBWNow && mMaxNow < mMinNow) mMaxNow = mMother;
176 widthNow = particleDataPtr->mWidth( idProd[i] );
177 useBW.push_back( useBWNow );
178 m0BW.push_back( m0Now );
179 mMinBW.push_back( mMinNow );
180 mMaxBW.push_back( mMaxNow );
181 widthBW.push_back( widthNow );
182 mProd.push_back( m0Now );
189 for (
int i = 1; i <= mult; ++i) {
191 mSum += max( m0BW[i], mMinBW[i]);
192 mSumMin += mMinBW[i];
196 if (mSumMin + MSAFETY > mMother)
return false;
199 if (mSum + 0.5 * MSAFETY < mMother && nBW == 0)
return true;
202 if (mSum + MSAFETY < mMother) {
203 double wtMax = 2. * sqrtpos(1. - mSum*mSum / m2Mother);
205 for (
int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) {
206 if (iTryMasses == NTRYMASSES)
return false;
208 for (
int i = 1; i <= mult; ++i) {
209 if (useBW[i]) mProd[i] = particleDataPtr->mSel( idProd[i] );
212 wt = (mSum + 0.5 * MSAFETY < mMother)
213 ? sqrtpos(1. - mSum*mSum / m2Mother) : 0.;
214 if (wt > rndmPtr->flat() * wtMax)
break;
224 for (
int i = 1; i <= mult; ++i) {
225 if (useBW[i]) iBW.push_back(i);
226 else mSum0 += mProd[i];
228 for (
int i = 1; i < nBW; ++i) {
229 for (
int j = i - 1; j >= 0; --j) {
230 if (widthBW[iBW[j+1]] > widthBW[iBW[j]]) swap (iBW[j+1], iBW[j]);
237 int iMin = (nBW == 1) ? 0 : 2;
238 for (
int i = nBW - 1; i >= iMin; --i) {
242 double mMax = mMother - mSum0 - MSAFETY;
243 if (nBW != 1)
for (
int j = 0; j < i; ++j) mMax -= mMinBW[iBW[j]];
244 mMax = min( mMaxBW[iBWi], mMax );
245 double mMin = min( mMinBW[iBWi], mMax - MSAFETY);
246 if (mMin < 0.)
return false;
249 double m2Nom = pow2( m0BW[iBWi] );
250 double m2Max = mMax * mMax;
251 double m2Min = mMin * mMin;
252 double mmWid = m0BW[iBWi] * widthBW[iBWi];
253 double atanMin = atan( (m2Min - m2Nom) / mmWid );
254 double atanMax = atan( (m2Max - m2Nom) / mmWid );
255 double atanDif = atanMax - atanMin;
258 if (atanDif < TINYBWRANGE)
return false;
261 double mr1 = mSum0*mSum0 / m2Mother;
262 double mr2 = m2Min / m2Mother;
263 double wtMax = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 );
265 for (
int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) {
266 if (iTryMasses == NTRYMASSES)
return false;
267 m2Now = m2Nom + mmWid * tan(atanMin + rndmPtr->flat() * atanDif);
268 mr2 = m2Now / m2Mother;
269 wt = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 );
270 if (wt > rndmPtr->flat() * wtMax)
break;
274 mProd[iBWi] = sqrt(m2Now);
275 mSum0 += mProd[iBWi];
277 if (nBW == 1)
return true;
283 int idMother = abs(idProd[0]);
284 int idDau1 = abs(idProd[iBW1]);
285 int idDau2 = abs(idProd[iBW2]);
289 if ( (idMother == 25 || idMother == 35) && idDau1 < 19
290 && idDau2 == idDau1 ) psMode = 3;
291 if ( (idMother == 25 || idMother == 35 )
292 && (idDau1 == 23 || idDau1 == 24) && idDau2 == idDau1 ) psMode = 5;
294 && (idDau1 == 23 || idDau1 == 24) && idDau2 == idDau1 ) psMode = 6;
297 double mRem = mMother - mSum0 - MSAFETY;
298 double mMax1 = min( mMaxBW[iBW1], mRem - mMinBW[iBW2] );
299 double mMin1 = min( mMinBW[iBW1], mMax1 - MSAFETY);
300 double mMax2 = min( mMaxBW[iBW2], mRem - mMinBW[iBW1] );
301 double mMin2 = min( mMinBW[iBW2], mMax2 - MSAFETY);
304 if (mMin1 + mMin2 > mRem)
return false;
305 double mMid = 0.5 * mRem;
306 bool hasMid1 = (mMin1 < mMid);
307 bool hasMid2 = (mMin2 < mMid);
308 if (!hasMid1 && !hasMid2)
return false;
311 double m2Nom1 = pow2( m0BW[iBW1] );
312 double m2Max1 = mMax1 * mMax1;
313 double m2Min1 = mMin1 * mMin1;
314 double m2Mid1 = min( mMid * mMid, m2Max1);
315 double mmWid1 = m0BW[iBW1] * widthBW[iBW1];
316 double atanMin1 = atan( (m2Min1 - m2Nom1) / mmWid1 );
317 double atanMax1 = atan( (m2Max1 - m2Nom1) / mmWid1 );
318 double atanMid1 = (hasMid1) ? atan( (m2Mid1 - m2Nom1) / mmWid1 ) : 0.;
319 double m2Nom2 = pow2( m0BW[iBW2] );
320 double m2Max2 = mMax2 * mMax2;
321 double m2Min2 = mMin2 * mMin2;
322 double m2Mid2 = min( mMid * mMid, m2Max2);
323 double mmWid2 = m0BW[iBW2] * widthBW[iBW2];
324 double atanMin2 = atan( (m2Min2 - m2Nom2) / mmWid2 );
325 double atanMax2 = atan( (m2Max2 - m2Nom2) / mmWid2 );
326 double atanMid2 = (hasMid2) ? atan( (m2Mid2 - m2Nom2) / mmWid2 ) : 0.;
329 double probLow1 = (hasMid1) ? 1. : 0.;
330 if (hasMid1 && hasMid2) {
331 double intLow1 = (atanMid1 - atanMin1) * (atanMax2 - atanMin2);
332 double intLow2 = (atanMax1 - atanMin1) * (atanMid2 - atanMin2);
333 probLow1 = intLow1 / (intLow1 + intLow2);
337 double m2Rem = mRem * mRem;
338 double mr1 = m2Min1 / m2Rem;
339 double mr2 = m2Min2 / m2Rem;
340 double psMax = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 );
342 if (psMode == 1) wtMax = psMax;
343 else if (psMode == 3) wtMax = pow3(psMax);
344 else if (psMode == 5) wtMax = psMax
345 * (pow2(1. - mr1 - mr2) + 8. * mr1 * mr2);
346 else if (psMode == 6) wtMax = pow3(psMax);
349 double atanDif1, atanDif2, m2Now1, m2Now2, mNow1, mNow2, ps, wt;
350 for (
int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) {
351 if (iTryMasses == NTRYMASSES)
return false;
354 bool pickLow1 =
false;
355 if (rndmPtr->flat() < probLow1) {
356 atanDif1 = atanMid1 - atanMin1;
357 atanDif2 = atanMax2 - atanMin2;
360 atanDif1 = atanMax1 - atanMin1;
361 atanDif2 = atanMid2 - atanMin2;
363 m2Now1 = m2Nom1 + mmWid1 * tan(atanMin1 + rndmPtr->flat() * atanDif1);
364 m2Now2 = m2Nom2 + mmWid2 * tan(atanMin2 + rndmPtr->flat() * atanDif2);
365 mNow1 = sqrt(m2Now1);
366 mNow2 = sqrt(m2Now2);
369 bool rejectRegion = (pickLow1) ? (mNow1 > mNow2) : (mNow2 > mNow1);
370 if (rejectRegion)
continue;
373 mr1 = m2Now1 / m2Rem;
374 mr2 = m2Now2 / m2Rem;
376 if (mNow1 + mNow2 + MSAFETY < mMother) {
377 ps = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 );
379 if (psMode == 1) wt = ps;
380 else if (psMode == 3) wt = pow3(ps);
381 else if (psMode == 5) wt = ps
382 * (pow2(1. - mr1 - mr2) + 8. * mr1 * mr2);
383 else if (psMode == 6) wt = pow3(ps)*mr1*mr2;
385 if (wt > rndmPtr->flat() * wtMax)
break;
399 bool ResonanceDecays::pickColours(
int iDec,
Event& process) {
404 vector<int> iTriplet, iAtriplet, iOctet, iDipCol, iDipAcol;
407 int col0 = process[iDec].col();
408 int acol0 = process[iDec].acol();
409 int colType0 = process[iDec].colType();
410 cols.push_back( col0);
411 acols.push_back(acol0);
415 for (
int i = 1; i <= mult; ++i) {
420 colTypeNow = particleDataPtr->colType( idProd[i] );
421 if (colTypeNow == 0);
422 else if (colTypeNow == 1) iTriplet.push_back(i);
423 else if (colTypeNow == -1) iAtriplet.push_back(i);
424 else if (colTypeNow == 2) iOctet.push_back(i);
426 else if (colTypeNow == 3) {
427 iTriplet.push_back(i);
428 iTriplet.push_back(i);
429 }
else if (colTypeNow == -3) {
430 iAtriplet.push_back(i);
431 iAtriplet.push_back(i);
433 infoPtr->errorMsg(
"Error in ResonanceDecays::pickColours:"
434 " unknown colour type encountered");
440 int nCol = iTriplet.size();
441 if (colType0 == 1 || colType0 == 2) nCol -= 1;
442 else if (colType0 == 3) nCol -= 2;
443 int nAcol = iAtriplet.size();
444 if (colType0 == -1 || colType0 == 2) nAcol -= 1;
445 else if (colType0 == -3) nAcol -= 2;
451 if (nCol - nAcol == 3) {
452 int kindJun = (colType0 == 0 || colType0 == 1 || colType0 == 3) ? 1 : 3;
456 colJun[0] = (kindJun == 1) ? process.nextColTag() : acol0;
457 colJun[1] = process.nextColTag();
458 colJun[2] = process.nextColTag();
459 process.appendJunction( kindJun, colJun[0], colJun[1], colJun[2]);
462 for (
int leg = 0; leg < 3; ++leg) {
463 if (leg == 0 && kindJun != 1) acol0 = 0;
467 int pickT = (iTriplet.size() == 1) ? 0
468 :
int( TINY + rndmPtr->flat() * (iTriplet.size() - TINY) );
469 int iPickT = iTriplet[pickT];
470 cols[iPickT] = colJun[leg];
473 iTriplet[pickT] = iTriplet.back();
475 iDipCol.push_back(iPickT);
476 iDipAcol.push_back(0);
488 if (nAcol - nCol == 3) {
489 int kindJun = (colType0 == 0 || colType0 == -1 || colType0 == -3) ? 2 : 4;
493 acolJun[0] = (kindJun == 2) ? process.nextColTag() : col0;
494 acolJun[1] = process.nextColTag();
495 acolJun[2] = process.nextColTag();
496 process.appendJunction( kindJun, acolJun[0], acolJun[1], acolJun[2]);
499 for (
int leg = 0; leg < 3; ++leg) {
500 if (leg == 0 && kindJun != 2) col0 = 0;
504 int pickA = (iAtriplet.size() == 1) ? 0
505 :
int( TINY + rndmPtr->flat() * (iAtriplet.size() - TINY) );
506 int iPickA = iAtriplet[pickA];
507 acols[iPickA] = acolJun[leg];
510 iAtriplet[pickA] = iAtriplet.back();
511 iAtriplet.pop_back();
512 iDipCol.push_back(0);
513 iDipAcol.push_back(iPickA);
523 infoPtr->errorMsg(
"Error in ResonanceDecays::pickColours:"
524 " inconsistent colour tags");
529 if (col0 > 0 && iTriplet.size() > 0) {
530 int pickT = (iTriplet.size() == 1) ? 0
531 :
int( TINY + rndmPtr->flat() * (iTriplet.size() - TINY) );
532 int iPickT = iTriplet[pickT];
537 iTriplet[pickT] = iTriplet.back();
539 iDipCol.push_back(iPickT);
540 iDipAcol.push_back(0);
544 if (acol0 > 0 && iAtriplet.size() > 0) {
545 int pickA = (iAtriplet.size() == 1) ? 0
546 :
int( TINY + rndmPtr->flat() * (iAtriplet.size() - TINY) );
547 int iPickA = iAtriplet[pickA];
548 acols[iPickA] = acol0;
552 iAtriplet[pickA] = iAtriplet.back();
553 iAtriplet.pop_back();
554 iDipCol.push_back(0);
555 iDipAcol.push_back(iPickA);
559 if (acol0 < 0 && iTriplet.size() > 0) {
560 int pickT = (iTriplet.size() == 1) ? 0
561 :
int( TINY + rndmPtr->flat() * (iTriplet.size() - TINY) );
562 int iPickT = iTriplet[pickT];
563 cols[iPickT] = -acol0;
567 iTriplet[pickT] = iTriplet.back();
569 iDipCol.push_back(iPickT);
570 iDipAcol.push_back(0);
574 if (col0 < 0 && iAtriplet.size() > 0) {
575 int pickA = (iAtriplet.size() == 1) ? 0
576 :
int( TINY + rndmPtr->flat() * (iAtriplet.size() - TINY) );
577 int iPickA = iAtriplet[pickA];
578 acols[iPickA] = -col0;
582 iAtriplet[pickA] = iAtriplet.back();
583 iAtriplet.pop_back();
584 iDipCol.push_back(0);
585 iDipAcol.push_back(iPickA);
589 if ( (iTriplet.size() != iAtriplet.size())
590 || (col0 != 0 && acol0 == 0) || (col0 == 0 && acol0 != 0) ) {
591 infoPtr->errorMsg(
"Error in ResonanceDecays::pickColours:"
592 " inconsistent colour tags");
597 for (
int pickT = 0; pickT < int(iTriplet.size()); ++pickT) {
598 int iPickT = iTriplet[pickT];
599 int pickA = (iAtriplet.size() == 1) ? 0
600 :
int( TINY + rndmPtr->flat() * (iAtriplet.size() - TINY) );
601 int iPickA = iAtriplet[pickA];
604 cols[iPickT] = process.nextColTag();
605 acols[iPickA] = cols[iPickT];
608 iAtriplet[pickA] = iAtriplet.back();
609 iAtriplet.pop_back();
610 iDipCol.push_back(iPickT);
611 iDipAcol.push_back(iPickA);
615 if (col0 == 0 && acol0 == 0 && iOctet.size() == 0)
return true;
619 iDipCol.push_back(0);
620 iDipAcol.push_back(0);
624 for (
int i = 0; i < int(iOctet.size()); ++i) {
625 int iOct = iOctet[i];
628 if (iDipCol.size() == 0) {
629 cols[iOct] = process.nextColTag();
630 acols[iOct] = cols[iOct] ;
631 iDipCol.push_back(iOct);
632 iDipAcol.push_back(iOct);
637 int pickDip = (iDipCol.size() == 1) ? 0
638 :
int( TINY + rndmPtr->flat() * (iDipCol.size() - TINY) );
641 if (iDipCol[pickDip] == 0 && iDipAcol[pickDip] == 0) {
644 iDipAcol[pickDip] = iOct;
645 iDipCol.push_back(iOct);
646 iDipAcol.push_back(0);
649 }
else if (iDipAcol[pickDip] == 0) {
650 int iPickCol = iDipCol[pickDip];
651 cols[iOct] = cols[iPickCol];
652 acols[iOct] = process.nextColTag();
653 cols[iPickCol] = acols[iOct];
654 iDipCol[pickDip] = iOct;
655 iDipCol.push_back(iPickCol);
656 iDipAcol.push_back(iOct);
661 int iPickAcol = iDipAcol[pickDip];
662 acols[iOct] = acols[iPickAcol];
663 cols[iOct] = process.nextColTag();
664 acols[iPickAcol] = cols[iOct];
665 iDipAcol[pickDip] = iOct;
666 iDipCol.push_back(iOct);
667 iDipAcol.push_back(iPickAcol);
673 if (iDipCol.size() < 2) {
674 infoPtr->errorMsg(
"Error in ResonanceDecays::pickColours:"
675 " inconsistent colour tags");
689 bool ResonanceDecays::pickKinematics() {
696 double m1 = mProd[1];
697 double m2 = mProd[2];
700 pair<Vec4, Vec4> ps = rndmPtr->phaseSpace2(m0, m1, m2);
701 pProd.push_back(ps.first);
702 pProd.push_back(ps.second);
703 pProd[1].bst( pProd[0] );
704 pProd[2].bst( pProd[0] );
715 double m1 = mProd[1];
716 double m2 = mProd[2];
717 double m3 = mProd[3];
718 double mDiff = m0 - (m1 + m2 + m3);
721 double m23Min = m2 + m3;
722 double m23Max = m0 - m1;
723 double p1Max = 0.5 * sqrtpos( (m0 - m1 - m23Min) * (m0 + m1 + m23Min)
724 * (m0 + m1 - m23Min) * (m0 - m1 + m23Min) ) / m0;
725 double p23Max = 0.5 * sqrtpos( (m23Max - m2 - m3) * (m23Max + m2 + m3)
726 * (m23Max + m2 - m3) * (m23Max - m2 + m3) ) / m23Max;
727 double wtPSmax = 0.5 * p1Max * p23Max;
730 double wtPS, m23, p1Abs, p23Abs;
732 m23 = m23Min + rndmPtr->flat() * mDiff;
735 p1Abs = 0.5 * sqrtpos( (m0 - m1 - m23) * (m0 + m1 + m23)
736 * (m0 + m1 - m23) * (m0 - m1 + m23) ) / m0;
737 p23Abs = 0.5 * sqrtpos( (m23 - m2 - m3) * (m23 + m2 + m3)
738 * (m23 + m2 - m3) * (m23 - m2 + m3) ) / m23;
739 wtPS = p1Abs * p23Abs;
742 }
while ( wtPS < rndmPtr->flat() * wtPSmax );
745 pair<Vec4, Vec4> ps23 = rndmPtr->phaseSpace2(m23, m2, m3);
747 Vec4 p3(ps23.second);
750 pair<Vec4, Vec4> ps123 = rndmPtr->phaseSpace2(m0, m1, m23);
751 pProd.push_back(ps123.first);
754 p2.bst( ps123.second );
755 p3.bst( ps123.second );
756 pProd.push_back( p2 );
757 pProd.push_back( p3 );
760 pProd[1].bst( pProd[0] );
761 pProd[2].bst( pProd[0] );
762 pProd[3].bst( pProd[0] );
772 double mSum = mProd[1];
773 for (
int i = 2; i <= mult; ++i) mSum += mProd[i];
774 double mDiff = m0 - mSum;
778 for (
int i = 0; i <= mult; ++i) mInv.push_back( mProd[i]);
781 double wtPSmax = 1. / WTCORRECTION[mult];
782 double mMax = mDiff + mProd[mult];
784 for (
int i = mult - 1; i > 0; --i) {
787 double mNow = mProd[i];
788 wtPSmax *= 0.5 * sqrtpos( (mMax - mMin - mNow) * (mMax + mMin + mNow)
789 * (mMax + mMin - mNow) * (mMax - mMin + mNow) ) / mMax;
793 vector<double> rndmOrd;
800 rndmOrd.push_back(1.);
801 for (
int i = 1; i < mult - 1; ++i) {
802 double rndm = rndmPtr->flat();
803 rndmOrd.push_back(rndm);
804 for (
int j = i - 1; j > 0; --j) {
805 if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] );
809 rndmOrd.push_back(0.);
812 for (
int i = mult - 1; i > 0; --i) {
813 mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff;
814 wtPS *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i])
815 * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i])
816 * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i];
820 }
while ( wtPS < rndmPtr->flat() * wtPSmax );
824 pInv.resize(mult + 1);
825 for (
int i = 1; i < mult; ++i) {
827 pair<Vec4, Vec4> ps = rndmPtr->phaseSpace2(mInv[i], mInv[i+1], mProd[i]);
828 pInv[i+1].p(ps.first);
829 pProd.push_back(ps.second);
831 pProd.push_back( pInv[mult] );
835 for (
int iFrame = mult - 1; iFrame > 0; --iFrame)
836 for (
int i = iFrame; i <= mult; ++i) pProd[i].bst(pInv[iFrame]);