StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RHadrons.cc
1 // RHadrons.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2020 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
4 // Please respect the MCnet Guidelines, see GUIDELINES for details.
5 
6 // Function definitions (not found in the header) for the RHadrons class.
7 
8 #include "Pythia8/RHadrons.h"
9 
10 namespace Pythia8 {
11 
12 //==========================================================================
13 
14 // The RHadrons class.
15 
16 //--------------------------------------------------------------------------
17 
18 // Constants: could be changed here if desired, but normally should not.
19 // These are of technical nature, as described for each.
20 
21 const int RHadrons::IDRHADSB[14] = { 1000512, 1000522, 1000532,
22  1000542, 1000552, 1005113, 1005211, 1005213, 1005223, 1005311,
23  1005313, 1005321, 1005323, 1005333 };
24 
25 const int RHadrons::IDRHADST[14] = { 1000612, 1000622, 1000632,
26  1000642, 1000652, 1006113, 1006211, 1006213, 1006223, 1006311,
27  1006313, 1006321, 1006323, 1006333 };
28 
29 // Gluino code and list of gluino R-hadron codes.
30 const int RHadrons::IDRHADGO[38] = { 1000993, 1009113, 1009213,
31  1009223, 1009313, 1009323, 1009333, 1009413, 1009423, 1009433,
32  1009443, 1009513, 1009523, 1009533, 1009543, 1009553, 1091114,
33  1092114, 1092214, 1092224, 1093114, 1093214, 1093224, 1093314,
34  1093324, 1093334, 1094114, 1094214, 1094224, 1094314, 1094324,
35  1094334, 1095114, 1095214, 1095224, 1095314, 1095324, 1095334 };
36 
37 // Allow a few tries for flavour selection since failure is allowed.
38 const int RHadrons::NTRYMAX = 10;
39 
40 // Safety margin (in GeV) when constructing kinematics of system.
41 const double RHadrons::MSAFETY = 0.1;
42 
43 // Maximal energy to borrow for gluon to insert on leg in to junction.
44 const double RHadrons::EGBORROWMAX = 4.;
45 
46 //--------------------------------------------------------------------------
47 
48 // Main routine to initialize R-hadron handling.
49 
50 bool RHadrons::init() {
51 
52  // Flags and parameters related to R-hadron formation and decay.
53  allowRH = flag("RHadrons:allow");
54  maxWidthRH = parm("RHadrons:maxWidth");
55  idRSb = mode("RHadrons:idSbottom");
56  idRSt = mode("RHadrons:idStop");
57  idRGo = mode("RHadrons:idGluino");
58  setMassesRH = flag("RHadrons:setMasses");
59  probGluinoballRH = parm("RHadrons:probGluinoball");
60  mOffsetCloudRH = parm("RHadrons:mOffsetCloud");
61  mCollapseRH = parm("RHadrons:mCollapse");
62  diquarkSpin1RH = parm("RHadrons:diquarkSpin1");
63 
64  // Check whether sbottom, stop or gluino should form R-hadrons.
65  allowRSb = allowRH && idRSb > 0
66  && (particleDataPtr->mWidth(idRSb) < maxWidthRH);
67  allowRSt = allowRH && idRSt > 0
68  && (particleDataPtr->mWidth(idRSt) < maxWidthRH);
69  allowRGo = allowRH && idRGo > 0
70  && (particleDataPtr->mWidth(idRGo) < maxWidthRH);
71  allowSomeR = allowRSb || allowRSt || allowRGo;
72 
73  // Set nominal masses of sbottom R-mesons and R-baryons.
74  if (allowRSb) {
75  m0Sb = particleDataPtr->m0(idRSb);
76  if (setMassesRH) {
77  for (int i = 0; i < 14; ++i) {
78  int idR = IDRHADSB[i];
79  double m0RHad = m0Sb + mOffsetCloudRH;
80  m0RHad += particleDataPtr->constituentMass( (idR%100)/10);
81  if (i > 4)
82  m0RHad += particleDataPtr->constituentMass( (idR%1000)/100 );
83  particleDataPtr->m0( idR, m0RHad);
84  }
85  }
86 
87  // Set widths and lifetimes of sbottom R-hadrons.
88  double mWidthRHad = particleDataPtr->mWidth(idRSb);
89  double tau0RHad = particleDataPtr->tau0( idRSb);
90  for (int i = 0; i < 14; ++i) {
91  particleDataPtr->mWidth( IDRHADSB[i], mWidthRHad);
92  particleDataPtr->tau0( IDRHADSB[i], tau0RHad);
93  }
94  }
95 
96  // Set nominal masses of stop R-mesons and R-baryons.
97  if (allowRSt) {
98  m0St = particleDataPtr->m0(idRSt);
99  if (setMassesRH) {
100  for (int i = 0; i < 14; ++i) {
101  int idR = IDRHADST[i];
102  double m0RHad = m0St + mOffsetCloudRH;
103  m0RHad += particleDataPtr->constituentMass( (idR%100)/10);
104  if (i > 4)
105  m0RHad += particleDataPtr->constituentMass( (idR%1000)/100 );
106  particleDataPtr->m0( idR, m0RHad);
107  }
108  }
109 
110  // Set widths and lifetimes of stop R-hadrons.
111  double mWidthRHad = particleDataPtr->mWidth(idRSt);
112  double tau0RHad = particleDataPtr->tau0( idRSt);
113  for (int i = 0; i < 14; ++i) {
114  particleDataPtr->mWidth( IDRHADST[i], mWidthRHad);
115  particleDataPtr->tau0( IDRHADST[i], tau0RHad);
116  }
117  }
118 
119  // Set nominal masses of gluino R-glueballs, R-mesons and R-baryons.
120  if (allowRGo) {
121  m0Go = particleDataPtr->m0(idRGo);
122  if (setMassesRH) {
123  particleDataPtr->m0( IDRHADGO[0], m0Go + 2. * mOffsetCloudRH
124  + particleDataPtr->constituentMass(21) );
125  for (int i = 1; i < 38; ++i) {
126  int idR = IDRHADGO[i];
127  double m0RHad = m0Go + 2. * mOffsetCloudRH;
128  m0RHad += particleDataPtr->constituentMass( (idR%1000)/100 );
129  m0RHad += particleDataPtr->constituentMass( (idR%100)/10);
130  if (i > 15)
131  m0RHad += particleDataPtr->constituentMass( (idR%10000)/1000 );
132  particleDataPtr->m0( idR, m0RHad);
133  }
134  }
135 
136  // Set widths and lifetimes of gluino R-hadrons.
137  double mWidthRHad = particleDataPtr->mWidth(idRGo);
138  double tau0RHad = particleDataPtr->tau0( idRGo);
139  for (int i = 0; i < 38; ++i) {
140  particleDataPtr->mWidth( IDRHADGO[i], mWidthRHad);
141  particleDataPtr->tau0( IDRHADGO[i], tau0RHad);
142  }
143  }
144 
145  // Done.
146  return true;
147 
148 }
149 //--------------------------------------------------------------------------
150 
151 // Check if a given particle can produce R-hadrons.
152 
153 bool RHadrons::givesRHadron( int id) {
154  if (allowRSb && abs(id) == idRSb) return true;
155  if (allowRSt && abs(id) == idRSt) return true;
156  if (allowRGo && id == idRGo) return true;
157  return false;
158 
159 }
160 
161 //--------------------------------------------------------------------------
162 
163 // Produce R-hadrons by fragmenting them off from existing strings.
164 
165 bool RHadrons::produce( ColConfig& colConfig, Event& event) {
166 
167  // Check whether some sparticles are allowed to hadronize.
168  if (!allowSomeR) return true;
169 
170  // Reset arrays and values.
171  iBefRHad.resize(0);
172  iCreRHad.resize(0);
173  iRHadron.resize(0);
174  iAftRHad.resize(0);
175  isTriplet.resize(0);
176  nRHad = 0;
177 
178  // Loop over event and identify hadronizing sparticles.
179  for (int i = 0; i < event.size(); ++i)
180  if (event[i].isFinal() && givesRHadron(event[i].id())) {
181  iBefRHad.push_back(i);
182  iCreRHad.push_back(i);
183  iRHadron.push_back(0);
184  iAftRHad.push_back(0);
185  isTriplet.push_back(true);
186  }
187  nRHad = iRHadron.size();
188 
189  // Done if no hadronizing sparticles.
190  if (nRHad == 0) return true;
191 
192  // Max two R-hadrons. Randomize order of processing.
193  if (nRHad > 2) {
194  infoPtr->errorMsg("Error in RHadrons::produce: "
195  "cannot handle more than two R-hadrons");
196  return false;
197  }
198  if (nRHad > 1 && rndmPtr->flat() > 0.5) swap( iBefRHad[0], iBefRHad[1]);
199 
200  // Split a system with both a sparticle and a junction.
201  iBef = iBefRHad[0];
202  iSys = colConfig.findSinglet( iBef);
203  systemPtr = &colConfig[iSys];
204  if (systemPtr->hasJunction && !splitOffJunction( colConfig, event)) {
205  infoPtr->errorMsg("Error in RHadrons::produce: "
206  "cannot handle system with junction");
207  return false;
208  }
209  if (nRHad == 2) {
210  iBef = iBefRHad[1];
211  iSys = colConfig.findSinglet( iBef);
212  systemPtr = &colConfig[iSys];
213  if (systemPtr->hasJunction && !splitOffJunction( colConfig, event)) {
214  infoPtr->errorMsg("Error in RHadrons::produce: "
215  "cannot handle system with junction");
216  return false;
217  }
218  }
219 
220  // Open up a closed gluon/gluino loop.
221  iBef = iBefRHad[0];
222  iSys = colConfig.findSinglet( iBef);
223  systemPtr = &colConfig[iSys];
224  if (systemPtr->isClosed && !openClosedLoop( colConfig, event)) {
225  infoPtr->errorMsg("Error in RHadrons::produce: "
226  "cannot open up closed gluon/gluino loop");
227  return false;
228  }
229  if (nRHad == 2) {
230  iBef = iBefRHad[1];
231  iSys = colConfig.findSinglet( iBef);
232  systemPtr = &colConfig[iSys];
233  if (systemPtr->isClosed && !openClosedLoop( colConfig, event)) {
234  infoPtr->errorMsg("Error in RHadrons::produce: "
235  "cannot open up closed gluon/gluino loop");
236  return false;
237  }
238  }
239 
240  // Split up a colour singlet system that should give two R-hadrons.
241  if (nRHad == 2) {
242  int iSys1 = colConfig.findSinglet( iBefRHad[0]);
243  int iSys2 = colConfig.findSinglet( iBefRHad[1]);
244  if (iSys2 == iSys1) {
245  iSys = iSys1;
246  systemPtr = &colConfig[iSys];
247  if ( !splitSystem( colConfig, event) ) {
248  infoPtr->errorMsg("Error in RHadrons::produce: "
249  "failed to handle two sparticles in same system");
250  return false;
251  }
252  }
253  }
254 
255  // Loop over R-hadrons to be formed. Find its colour singlet system.
256  for (iRHad = 0; iRHad < nRHad; ++iRHad) {
257  iBef = iBefRHad[iRHad];
258  iSys = colConfig.findSinglet( iBef);
259  if (iSys < 0) {
260  infoPtr->errorMsg("Error in RHadrons::produce: "
261  "sparticle not in any colour singlet");
262  return false;
263  }
264  systemPtr = &colConfig[iSys];
265 
266  // For now don't handle systems involving junctions or loops.
267  if (systemPtr->hasJunction) {
268  infoPtr->errorMsg("Error in RHadrons::produce: "
269  "cannot handle system with junction");
270  return false;
271  }
272  if (systemPtr->isClosed) {
273  infoPtr->errorMsg("Error in RHadrons::produce: "
274  "cannot handle closed colour loop");
275  return false;
276  }
277 
278  // Handle formation of R-hadron separately for gluino and squark.
279  if (event[iBef].id() == idRGo) isTriplet[iRHad] = false;
280  bool formed = (isTriplet[iRHad]) ? produceSquark( colConfig, event)
281  : produceGluino( colConfig, event);
282  if (!formed) return false;
283 
284  // End of loop over R-hadrons. Done.
285  }
286  return true;
287 
288 }
289 
290 //--------------------------------------------------------------------------
291 
292 // Decay R-hadrons by resolving them into string systems and letting the
293 // heavy unstable particle decay as normal.
294 
295 bool RHadrons::decay( Event& event) {
296 
297  // Loop over R-hadrons to decay.
298  for (iRHad = 0; iRHad < nRHad; ++iRHad) {
299  int iRNow = iRHadron[iRHad];
300  int iRBef = iBefRHad[iRHad];
301  int idRHad = event[iRNow].id();
302  double mRHad = event[iRNow].m();
303  double mRBef = event[iRBef].m();
304  int iR0 = 0;
305  int iR2 = 0;
306 
307  // Find flavour content of squark or gluino R-hadron.
308  pair<int,int> idPair = (isTriplet[iRHad])
309  ? fromIdWithSquark( idRHad) : fromIdWithGluino( idRHad);
310  int id1 = idPair.first;
311  int id2 = idPair.second;
312 
313  // Sharing of momentum: the squark/gluino should be restored
314  // to original mass, but error if negative-mass spectators.
315  double fracR = mRBef / mRHad;
316  if (fracR >= 1.) {
317  infoPtr->errorMsg("Error in RHadrons::decay: "
318  "too low R-hadron mass for decay");
319  return false;
320  }
321 
322  // Squark: new colour needed in the breakup.
323  if (isTriplet[iRHad]) {
324  int colNew = event.nextColTag();
325  int col = (event[iRBef].col() != 0) ? colNew : 0;
326  int acol = (col == 0) ? colNew : 0;
327 
328  // Store the constituents of a squark R-hadron.
329  iR0 = event.append( id1, 106, iRNow, 0, 0, 0, col, acol,
330  fracR * event[iRNow].p(), fracR * mRHad, 0.);
331  iR2 = event.append( id2, 106, iRNow, 0, 0, 0, acol, col,
332  (1. - fracR) * event[iRNow].p(), (1. - fracR) * mRHad, 0.);
333 
334  // Gluino: set mass sharing between two spectators.
335  } else {
336  double m1Eff = particleDataPtr->constituentMass(id1) + mOffsetCloudRH;
337  double m2Eff = particleDataPtr->constituentMass(id2) + mOffsetCloudRH;
338  double frac1 = (1. - fracR) * m1Eff / ( m1Eff + m2Eff);
339  double frac2 = (1. - fracR) * m2Eff / ( m1Eff + m2Eff);
340 
341  // Two new colours needed in the breakups.
342  int col1 = event.nextColTag();
343  int col2 = event.nextColTag();
344 
345  // Store the constituents of a gluino R-hadron.
346  iR0 = event.append( idRGo, 106, iRNow, 0, 0, 0, col2, col1,
347  fracR * event[iRNow].p(), fracR * mRHad, 0.);
348  event.append( id1, 106, iRNow, 0, 0, 0, col1, 0,
349  frac1 * event[iRNow].p(), frac1 * mRHad, 0.);
350  iR2 = event.append( id2, 106, iRNow, 0, 0, 0, 0, col2,
351  frac2 * event[iRNow].p(), frac2 * mRHad, 0.);
352  }
353 
354  // Mark R-hadron as decayed and update history.
355  event[iRNow].statusNeg();
356  event[iRNow].daughters( iR0, iR2);
357  iAftRHad[iRHad] = iR0;
358 
359  // Set secondary vertex for decay products, but no lifetime.
360  Vec4 vDec = event[iRNow].vProd() + event[iRNow].tau()
361  * event[iR0].p() / event[iR0].m();
362  for (int iRd = iR0; iRd <= iR2; ++iRd) event[iRd].vProd( vDec);
363 
364  // End loop over R-hadron decays, based on velocity of squark.
365 
366  }
367 
368  // Done.
369  return true;
370 
371 }
372 
373 //--------------------------------------------------------------------------
374 
375 // Split a system that contains both a sparticle and a junction.
376 
377 bool RHadrons::splitOffJunction( ColConfig& colConfig, Event& event) {
378 
379  // Classify system into three legs, and find sparticle location.
380  vector<int> leg1, leg2, leg3;
381  int iLegSP = 0;
382  int iPosSP = 0;
383  int iLeg = 0;
384  int iPos = 0;
385  for (int i = 0; i < systemPtr->size(); ++i) {
386  ++iPos;
387  int iP = systemPtr->iParton[i];
388  if (iP < 0) {
389  ++iLeg;
390  iPos = -1;
391  } else if (iLeg == 1) leg1.push_back( iP);
392  else if (iLeg == 2) leg2.push_back( iP);
393  else if (iLeg == 3) leg3.push_back( iP);
394  if (iP == iBef) {
395  iLegSP = iLeg;
396  iPosSP = iPos;
397  }
398  }
399  if (iLegSP == 0) return false;
400 
401  // Swap so leg 1 contains sparticle. If not innermost sparticle then
402  // skip for now, and wait for this other (gluino!) to be split off.
403  if (iLegSP == 2) swap(leg2, leg1);
404  else if (iLegSP == 3) swap(leg3, leg1);
405  for (int i = 0; i < iPosSP; ++i)
406  if (event[leg1[i]].id() != 21) return true;
407 
408  // No gluon between sparticle and junction: find kinetic energy of system.
409  if (iPosSP == 0) {
410  Vec4 pSP = event[iBef].p();
411  Vec4 pRec = 0.;
412  for (int i = 0; i < int(leg2.size()); ++i) pRec += event[leg2[i]].p();
413  for (int i = 0; i < int(leg3.size()); ++i) pRec += event[leg3[i]].p();
414  double mSys = (pSP + pRec).mCalc();
415  double mSP = pSP.mCalc();
416  double mRec = pRec.mCalc();
417  double eKin = mSys - mSP - mRec;
418 
419  // Insert new gluon that borrows part of kinetic energy.
420  double mNewG = EGBORROWMAX * eKin / (EGBORROWMAX + eKin) ;
421  Vec4 pNewG = (mNewG / mSys) * (pSP + pRec);
422  int newCol = event.nextColTag();
423  bool isCol = (event[leg1.back()].col() > 0);
424  int colNG = (isCol)? newCol : event[iBef].acol();
425  int acolNG = (isCol) ? event[iBef].col() : newCol;
426  int iNewG = event.append( 21, 101, iBef, 0, 0, 0, colNG, acolNG,
427  pNewG, mNewG, 0.);
428  leg1.insert( leg1.begin(), iNewG);
429  ++iPosSP;
430 
431  // Boosts for remainder systems that gave up energy.
432  double mNewSys = mSys - mNewG;
433  double pAbsOld = 0.5 * sqrtpos( pow2(mSys*mSys - mSP*mSP - mRec*mRec)
434  - pow2(2. * mSP * mRec) ) / mSys;
435  double pAbsNew = 0.5 * sqrtpos( pow2(mNewSys*mNewSys - mSP*mSP - mRec*mRec)
436  - pow2(2. * mSP * mRec) ) / mNewSys;
437  RotBstMatrix MtoCM, MfromCM, MSP, MRec;
438  MtoCM.toCMframe( pSP, pRec);
439  MfromCM = MtoCM;
440  MfromCM.invert();
441  MSP = MtoCM;
442  MSP.bst( 0., 0., -pAbsOld / sqrt(mSP * mSP + pAbsOld * pAbsOld));
443  MSP.bst( 0., 0., pAbsNew / sqrt(mSP * mSP + pAbsNew * pAbsNew));
444  MSP.rotbst( MfromCM);
445  MRec = MtoCM;
446  MRec.bst( 0., 0., pAbsOld / sqrt(mRec * mRec + pAbsOld * pAbsOld));
447  MRec.bst( 0., 0., -pAbsNew / sqrt(mRec * mRec + pAbsNew * pAbsNew));
448  MRec.rotbst( MfromCM);
449 
450  // Copy down recoling partons and boost their momenta.
451  int iNewSP = event.copy( iBef, 101);
452  event[iNewSP].mother2(0);
453  event[iBef].daughter1(iNewG);
454  event[iNewSP].rotbst( MSP);
455  leg1[iPosSP] = iNewSP;
456  if (iBefRHad[0] == iBef) iBefRHad[0] = iNewSP;
457  else if (nRHad > 1 && iBefRHad[1] == iBef) iBefRHad[1] = iNewSP;
458  iBef = iNewSP;
459  for (int i = 0; i < int(leg2.size()); ++i) {
460  int iCopy = event.copy( leg2[i], 101);
461  event[iCopy].rotbst( MRec);
462  if (iBefRHad[0] == leg2[i]) iBefRHad[0] = iCopy;
463  else if (nRHad > 1 && iBefRHad[1] == leg2[i]) iBefRHad[1] = iCopy;
464  leg2[i] = iCopy;
465  }
466  for (int i = 0; i < int(leg3.size()); ++i) {
467  int iCopy = event.copy( leg3[i], 101);
468  event[iCopy].rotbst( MRec);
469  if (iBefRHad[0] == leg3[i]) iBefRHad[0] = iCopy;
470  else if (nRHad > 1 && iBefRHad[1] == leg3[i]) iBefRHad[1] = iCopy;
471  leg3[i] = iCopy;
472  }
473 
474  // Now always at least one gluon between sparticle and junction.
475  }
476 
477  // Find gluon with largest energy in sparticle rest frame.
478  int iGspl = 0;
479  double eGspl = event[leg1[0]].p() * event[iBef].p();
480  for (int i = 1; i < iPosSP; ++i) {
481  double eGnow = event[leg1[i]].p() * event[iBef].p();
482  if (eGnow > eGspl) {
483  iGspl = i;
484  eGspl = eGnow;
485  }
486  }
487  int iG = leg1[iGspl];
488 
489  // Split this gluon into a collinear quark.antiquark pair.
490  int idNewQ = flavSelPtr->pickLightQ();
491  int iNewQ = event.append( idNewQ, 101, iG, 0, 0, 0, event[iG].col(), 0,
492  0.5 * event[iG].p(), 0.5 * event[iG].m(), 0.);
493  int iNewQb = event.append( -idNewQ, 101, iG, 0, 0, 0, 0, event[iG].acol(),
494  0.5 * event[iG].p(), 0.5 * event[iG].m(), 0.);
495  event[iG].statusNeg();
496  event[iG].daughters( iNewQ, iNewQb);
497  if (event[leg1.back()].col() == 0) swap( iNewQ, iNewQb);
498 
499  // Collect two new systems after split.
500  vector<int> iNewSys1, iNewSys2;
501  iNewSys1.push_back( iNewQb);
502  for (int i = iGspl + 1; i < int(leg1.size()); ++i)
503  iNewSys1.push_back( leg1[i]);
504  iNewSys2.push_back( -10);
505  for (int i = 0; i < iGspl; ++i) iNewSys2.push_back( leg1[i]);
506  iNewSys2.push_back( iNewQ);
507  iNewSys2.push_back( -11);
508  for (int i = 0; i < int(leg2.size()); ++i) iNewSys2.push_back( leg2[i]);
509  iNewSys2.push_back( -12);
510  for (int i = 0; i < int(leg3.size()); ++i) iNewSys2.push_back( leg3[i]);
511 
512  // Remove old system and insert two new ones.
513  colConfig.erase(iSys);
514  colConfig.insert( iNewSys1, event);
515  colConfig.insert( iNewSys2, event);
516 
517  // Done.
518  return true;
519 
520 }
521 
522 //--------------------------------------------------------------------------
523 
524 // Open up a closed gluon/gluino loop.
525 
526 bool RHadrons::openClosedLoop( ColConfig& colConfig, Event& event) {
527 
528  // Find gluon with largest energy in gluino rest frame.
529  int iGspl = -1;
530  double eGspl = 0.;
531  for (int i = 0; i < systemPtr->size(); ++i) {
532  int iGNow = systemPtr->iParton[i];
533  if (event[iGNow].id() == 21) {
534  double eGnow = event[iGNow].p() * event[iBef].p();
535  if (eGnow > eGspl) {
536  iGspl = i;
537  eGspl = eGnow;
538  }
539  }
540  }
541  if (iGspl == -1) return false;
542 
543  // Split this gluon into a collinear quark.antiquark pair.
544  int iG = systemPtr->iParton[iGspl];
545  int idNewQ = flavSelPtr->pickLightQ();
546  int iNewQ = event.append( idNewQ, 101, iG, 0, 0, 0, event[iG].col(), 0,
547  0.5 * event[iG].p(), 0.5 * event[iG].m(), 0.);
548  int iNewQb = event.append( -idNewQ, 101, iG, 0, 0, 0, 0, event[iG].acol(),
549  0.5 * event[iG].p(), 0.5 * event[iG].m(), 0.);
550  event[iG].statusNeg();
551  event[iG].daughters( iNewQ, iNewQb);
552 
553  // Order partons in new system. Note order of colour flow.
554  int iNext = iGspl + 1;
555  if (iNext == systemPtr->size()) iNext = 0;
556  if (event[ systemPtr->iParton[iNext]].acol() != event[iNewQ].col())
557  swap( iNewQ, iNewQb);
558  vector<int> iNewSys;
559  iNewSys.push_back( iNewQ);
560  for (int i = iGspl + 1; i < systemPtr->size(); ++i)
561  iNewSys.push_back( systemPtr->iParton[i]);
562  for (int i = 0; i < iGspl; ++i)
563  iNewSys.push_back( systemPtr->iParton[i]);
564  iNewSys.push_back( iNewQb);
565 
566  // Erase the old system and insert the new one instead.
567  colConfig.erase(iSys);
568  colConfig.insert( iNewSys, event);
569 
570  // Done.
571  return true;
572 
573 }
574 
575 //--------------------------------------------------------------------------
576 
577 // Split a single colour singlet that contains two sparticles.
578 // To fix : if nLeg >= 3 && mMin large handle as in nLeg == 1??
579 
580 bool RHadrons::splitSystem( ColConfig& colConfig, Event& event) {
581 
582  // First and second R-hadron mother. Number of legs in between.
583  int iFirst = -1;
584  int iSecond = -1;
585  for (int i = 0; i < int(systemPtr->size()); ++i) {
586  int iTmp = systemPtr->iParton[i];
587  if ( givesRHadron( event[iTmp].id()) ) {
588  if (iFirst == -1) iFirst = i;
589  else iSecond = i;
590  }
591  }
592  int nLeg = iSecond - iFirst;
593 
594  // New flavour pair for breaking the string, and its mass.
595  int idNewQ = flavSelPtr->pickLightQ();
596  double mNewQ = particleDataPtr->constituentMass( idNewQ);
597  vector<int> iNewSys1, iNewSys2;
598 
599  // If sparticles are neighbours then need new q-qbar pair in between.
600  if (nLeg == 1) {
601 
602  // The location of the two sparticles.
603  int i1Old = systemPtr->iParton[iFirst];
604  int i2Old = systemPtr->iParton[iSecond];
605 
606  // Take a fraction of momentum to give breakup quark pair.
607  double mHat = (event[i1Old].p() + event[i2Old].p()).mCalc();
608  double mMax = mHat - event[i1Old].m() - event[i2Old].m();
609  if (mMax < 2. * (mNewQ + MSAFETY)) return false;
610  double mEff = min( 2. * (mNewQ + mOffsetCloudRH), mMax - 2. * MSAFETY);
611  double frac = mEff / mHat;
612  Vec4 pEff = frac * (event[i1Old].p() + event[i2Old].p());
613 
614  // New kinematics by (1) go to same mHat with bigger masses, and
615  // (2) rescale back down to original masses and reduced mHat.
616  Vec4 p1New, p2New;
617  if ( !newKin( event[i1Old].p(), event[i2Old].p(),
618  event[i1Old].m() / (1. - frac), event[i2Old].m() / (1. - frac),
619  p1New, p2New) ) return false;
620  p1New *= 1. - frac;
621  p2New *= 1. - frac;
622 
623  // Fill in new partons after branching, with correct colour/flavour sign.
624  int i1New, i2New, i3New, i4New;
625  int newCol = event.nextColTag();
626  i1New = event.copy( i1Old, 101);
627  if (event[i2Old].acol() == event[i1Old].col()) {
628  i3New = event.append( -idNewQ, 101, i1Old, 0, 0, 0,
629  0, event[i2Old].acol(), 0.5 * pEff, 0.5 * mEff, 0.);
630  i2New = event.copy( i2Old, 101);
631  event[i2New].acol( newCol);
632  i4New = event.append( idNewQ, 101, i2Old, 0, 0, 0,
633  newCol, 0, 0.5 * pEff, 0.5 * mEff, 0.);
634  } else {
635  i3New = event.append( idNewQ, 101, i1Old, 0, 0, 0,
636  event[i2Old].col(), 0, 0.5 * pEff, 0.5 * mEff, 0.);
637  i2New = event.copy( i2Old, 101);
638  event[i2New].col( newCol);
639  i4New = event.append( -idNewQ, 101, i2Old, 0, 0, 0,
640  0, newCol, 0.5 * pEff, 0.5 * mEff, 0.);
641  }
642 
643  // Modify momenta and history. For iBotCopyId tracing asymmetric
644  // bookkeeping where one sparticle is radiator and the other recoiler.
645  event[i1New].p( p1New);
646  event[i2New].p( p2New);
647  event[i1Old].daughters( i1New, i3New);
648  event[i1New].mother2( 0);
649  event[i2Old].daughters( i2New, i4New);
650  event[i2New].mother2( 0);
651  iBefRHad[0] = i1New;
652  iBefRHad[1] = i2New;
653 
654  // Partons in the two new systems.
655  for (int i = 0; i < iFirst; ++i)
656  iNewSys1.push_back( systemPtr->iParton[i]);
657  iNewSys1.push_back( i1New);
658  iNewSys1.push_back( i3New);
659  iNewSys2.push_back( i4New);
660  iNewSys2.push_back( i2New);
661  for (int i = iSecond + 1; i < int(systemPtr->size()); ++i)
662  iNewSys2.push_back( systemPtr->iParton[i]);
663 
664  // If one gluon between sparticles then split it into a
665  // collinear q-qbar pair.
666  } else if (nLeg == 2) {
667 
668  // Gluon to be split and its two daughters.
669  int iOld = systemPtr->iParton[iFirst + 1];
670  int i1New = event.append( idNewQ, 101, iOld, 0, 0, 0,
671  event[iOld].col(), 0, 0.5 * event[iOld].p(),
672  0.5 * event[iOld].m(), 0.);
673  int i2New = event.append( -idNewQ, 101, iOld, 0, 0, 0,
674  0, event[iOld].acol(), 0.5 * event[iOld].p(),
675  0.5 * event[iOld].m(), 0.);
676  event[iOld].statusNeg();
677  event[iOld].daughters( i1New, i2New);
678 
679  // Partons in the two new systems.
680  if (event[systemPtr->iParton[iFirst]].col() == event[i2New].acol())
681  swap( i1New, i2New);
682  for (int i = 0; i <= iFirst; ++i)
683  iNewSys1.push_back( systemPtr->iParton[i]);
684  iNewSys1.push_back( i1New);
685  iNewSys2.push_back( i2New);
686  for (int i = iSecond; i < int(systemPtr->size()); ++i)
687  iNewSys2.push_back( systemPtr->iParton[i]);
688 
689  // If several gluons between sparticles then find lowest-mass gluon pair
690  // and replace it by a q-qbar pair.
691  } else {
692 
693  // Find lowest-mass gluon pair and adjust effective quark mass.
694  int iMin = 0;
695  int i1Old = 0;
696  int i2Old = 0;
697  double mMin = 1e20;
698  for (int i = iFirst + 1; i < iSecond - 1; ++i) {
699  int i1Tmp = systemPtr->iParton[i];
700  int i2Tmp = systemPtr->iParton[i + 1];
701  double mTmp = (event[i1Tmp].p() + event[i2Tmp].p()).mCalc();
702  if (mTmp < mMin) {
703  iMin = i;
704  i1Old = i1Tmp;
705  i2Old = i2Tmp;
706  mMin = mTmp;
707  }
708  }
709  double mEff = min( mNewQ + mOffsetCloudRH, 0.4 * mMin);
710 
711  // New kinematics by sharing mHat appropriately.
712  Vec4 p1New, p2New;
713  if ( !newKin( event[i1Old].p(), event[i2Old].p(),
714  mEff, mEff, p1New, p2New, false) ) return false;
715 
716  // Insert new partons and update history.
717  int i1New, i2New;
718  if (event[systemPtr->iParton[0]].acol() == 0) {
719  i1New = event.append( -idNewQ, 101, i1Old, 0, 0, 0,
720  0, event[i1Old].acol(), p1New, mEff, 0.);
721  i2New = event.append( idNewQ, 101, i2Old, 0, 0, 0,
722  event[i2Old].col(), 0, p2New, mEff, 0.);
723  } else {
724  i1New = event.append( idNewQ, 101, i1Old, 0, 0, 0,
725  event[i1Old].col(), 0, p1New, mEff, 0.);
726  i2New = event.append( -idNewQ, 101, i2Old, 0, 0, 0,
727  0, event[i2Old].acol(), p2New, mEff, 0.);
728  }
729  event[i1Old].statusNeg();
730  event[i2Old].statusNeg();
731  event[i1Old].daughters( i1New, 0);
732  event[i2Old].daughters( i2New, 0);
733 
734  // Partons in the two new systems.
735  for (int i = 0; i < iMin; ++i)
736  iNewSys1.push_back( systemPtr->iParton[i]);
737  iNewSys1.push_back( i1New);
738  iNewSys2.push_back( i2New);
739  for (int i = iMin + 2; i < int(systemPtr->size()); ++i)
740  iNewSys2.push_back( systemPtr->iParton[i]);
741  }
742 
743  // Erase the old system and insert the two new ones instead.
744  colConfig.erase(iSys);
745  colConfig.insert( iNewSys1, event);
746  colConfig.insert( iNewSys2, event);
747 
748  // Done.
749  return true;
750 
751 }
752 
753 //--------------------------------------------------------------------------
754 
755 // Produce a R-hadron from a squark and another string end.
756 
757 bool RHadrons::produceSquark( ColConfig& colConfig, Event& event) {
758 
759  // Initial values.
760  int nBody = 0;
761  int iRNow = 0;
762  int iNewQ = 0;
763  int iNewL = 0;
764 
765  // Check at which end of the string the squark is located.
766  int idAbsTop = event[ systemPtr->iParton[0] ].idAbs();
767  bool sqAtTop = (allowRSb && idAbsTop == idRSb)
768  || (allowRSt && idAbsTop == idRSt);
769 
770  // Copy down system consecutively from squark end.
771  int iBeg = event.size();
772  iCreRHad[iRHad] = iBeg;
773  if (sqAtTop) for (int i = 0; i < systemPtr->size(); ++i)
774  event.copy( systemPtr->iParton[i], 102);
775  else for (int i = systemPtr->size() - 1; i >= 0; --i)
776  event.copy( systemPtr->iParton[i], 102);
777  int iEnd = event.size() - 1;
778 
779  // Input flavours. From now on H = heavy and L = light string ends.
780  int idOldH = event[iBeg].id();
781  int idOldL = event[iEnd].id();
782 
783  // Pick new flavour to form R-hadron.
784  FlavContainer flavOld( idOldH%10);
785  int idNewQ = flavSelPtr->pick(flavOld).id;
786  int idRHad = toIdWithSquark( idOldH, idNewQ);
787  if (idRHad == 0) {
788  infoPtr->errorMsg("Error in RHadrons::produceSquark: "
789  "cannot form R-hadron code");
790  return false;
791  }
792 
793  // Target mass of R-hadron and z value of fragmentation function.
794  double mRHad = particleDataPtr->m0(idRHad) + event[iBeg].m()
795  - ( (abs(idOldH) == idRSb) ? m0Sb : m0St );
796  double z = zSelPtr->zFrag( idOldH, idNewQ, mRHad*mRHad);
797 
798  // Basic kinematics of string piece where break is to occur.
799  Vec4 pOldH = event[iBeg].p();
800  int iOldL = iBeg + 1;
801  Vec4 pOldL = event[iOldL].p();
802  double mOldL = event[iOldL].m();
803  double mNewH = mRHad / z;
804  double sSys = (pOldH + pOldL).m2Calc();
805  double sRem = (1. - z) * (sSys - mNewH*mNewH);
806  double sMin = pow2(mOldL + mCollapseRH);
807 
808  // If too low remaining mass in system then add one more parton to it.
809  while ( ( sRem < sMin || sSys < pow2(mNewH + mOldL + MSAFETY) )
810  && iOldL < iEnd ) {
811  ++iOldL;
812  pOldL += event[iOldL].p();
813  mOldL = event[iOldL].m();
814  sSys = (pOldH + pOldL).m2Calc();
815  sRem = (1. - z) * (sSys - mNewH*mNewH);
816  sMin = pow2(mOldL + mCollapseRH);
817  }
818 
819  // If enough mass then split off R-hadron and reduced system.
820  if ( sRem > sMin && sSys > pow2(mNewH + mOldL + MSAFETY) ) {
821  Vec4 pNewH, pNewL;
822  if ( !newKin( pOldH, pOldL, mNewH, mOldL, pNewH, pNewL) ) {
823  infoPtr->errorMsg("Error in RHadrons::produceSquark: "
824  "failed to construct kinematics with reduced system");
825  return false;
826  }
827 
828  // Insert R-hadron with new momentum.
829  iRNow = event.append( idRHad, 104, iBeg, iOldL, 0, 0, 0, 0,
830  z * pNewH, mRHad, 0.);
831 
832  // Reduced system with new string endpoint and modified recoiler.
833  idNewQ = -idNewQ;
834  bool hasCol = (idNewQ > 0 && idNewQ < 10) || idNewQ < -10;
835  int col = (hasCol) ? event[iOldL].acol() : 0;
836  int acol = (hasCol) ? 0 : event[iOldL].col();
837  iNewQ = event.append( idNewQ, 105, iBeg, iOldL, 0, 0, col, acol,
838  (1. - z) * pNewH, (1. - z) * mNewH, 0.);
839  iNewL = event.copy( iOldL, 105);
840  event[iNewL].mothers( iBeg, iOldL);
841  event[iNewL].p( pNewL);
842 
843  // Done with processing of split to R-hadron and reduced system.
844  nBody = 3;
845  }
846 
847  // Two-body final state: form light hadron from endpoint and new flavour.
848  if (nBody == 0) {
849  FlavContainer flav1( idOldL);
850  FlavContainer flav2( -idNewQ);
851  int iTry = 0;
852  int idNewL = flavSelPtr->combine( flav1, flav2);
853  while (++iTry < NTRYMAX && idNewL == 0)
854  idNewL = flavSelPtr->combine( flav1, flav2);
855  if (idNewL == 0) {
856  infoPtr->errorMsg("Error in RHadrons::produceSquark: "
857  "cannot form light hadron code");
858  return false;
859  }
860  double mNewL = particleDataPtr->mSel( idNewL);
861 
862  // Check that energy enough for light hadron and R-hadron.
863  if ( sSys > pow2(mRHad + mNewL + MSAFETY) ) {
864  Vec4 pRHad, pNewL;
865  if ( !newKin( pOldH, pOldL, mRHad, mNewL, pRHad, pNewL) ) {
866  infoPtr->errorMsg("Error in RHadrons::produceSquark: "
867  "failed to construct kinematics for two-hadron decay");
868  return false;
869  }
870 
871  // Insert R-hadron and light hadron.
872  iRNow = event.append( idRHad, 104, iBeg, iOldL, 0, 0, 0, 0,
873  pRHad, mRHad, 0.);
874  event.append( idNewL, 105, iBeg, iOldL, 0, 0, 0, 0,
875  pNewL, mNewL, 0.);
876 
877  // Done for two-body case.
878  nBody = 2;
879  }
880  }
881 
882  // Final case: for very low mass collapse to one single R-hadron.
883  if (nBody == 0) {
884  idRHad = toIdWithSquark( idOldH, idOldL);
885  if (idRHad == 0) {
886  infoPtr->errorMsg("Error in RHadrons::produceSquark: "
887  "cannot form R-hadron code");
888  return false;
889  }
890 
891  // Insert R-hadron with new momentum.
892  iRNow = event.append( idRHad, 104, iBeg, iOldL, 0, 0, 0, 0,
893  systemPtr->pSum, systemPtr->mass, 0.);
894 
895  // Done with one-body case.
896  nBody = 1;
897  }
898 
899  // History bookkeeping: the R-hadron and processed partons.
900  iRHadron[iRHad] = iRNow;
901  int iLast = event.size() - 1;
902  for (int i = iBeg; i <= iOldL; ++i) {
903  event[i].statusNeg();
904  event[i].daughters( iRNow, iLast);
905  }
906 
907  // Remove old string system and, if needed, insert a new one.
908  colConfig.erase(iSys);
909  if (nBody == 3) {
910  vector<int> iNewSys;
911  iNewSys.push_back( iNewQ);
912  iNewSys.push_back( iNewL);
913  for ( int i = iOldL + 1; i <= iEnd; ++i) iNewSys.push_back( i);
914  colConfig.insert( iNewSys, event);
915  }
916 
917  // Copy lifetime and vertex from sparticle to R-hadron.
918  event[iRNow].tau( event[iBef].tau() );
919  if (event[iBef].hasVertex()) event[iRNow].vProd( event[iBef].vProd() );
920 
921  // Done with production of a R-hadron from a squark.
922  return true;
923 
924 }
925 
926 //--------------------------------------------------------------------------
927 
928 // Produce a R-hadron from a gluino and two string ends (or a gluon).
929 
930 bool RHadrons::produceGluino( ColConfig& colConfig, Event& event) {
931 
932  // Initial values.
933  int iGlui = 0;
934  int idSave = 0;
935  int idQLeap = 0;
936  bool isDiq1 = false;
937  vector<int> iSide1, iSide2, iSideTmp, iNewSys1, iNewSys2;
938  Vec4 pGlui, pSide1, pSide2;
939 
940  // Decide whether to produce a gluinoball or not.
941  bool isGBall = (rndmPtr->flat() < probGluinoballRH);
942 
943  // Extract one string system on either side of the gluino.
944  for (int i = 0; i < systemPtr->size(); ++i) {
945  int iTmp = systemPtr->iParton[i];
946  if (iGlui == 0 && event[ iTmp ].id() == idRGo) {
947  iGlui = iTmp;
948  pGlui = event[ iTmp ].p();
949  } else if (iGlui == 0) {
950  iSideTmp.push_back( iTmp);
951  pSide1 += event[ iTmp ].p();
952  } else {
953  iSide2.push_back( iTmp);
954  pSide2 += event[ iTmp ].p();
955  }
956  }
957  int iGluiFix = iGlui;
958 
959  // Order sides from gluino outwards and with lowest relative mass first.
960  for (int i = int(iSideTmp.size()) - 1; i >= 0; --i)
961  iSide1.push_back( iSideTmp[i]);
962  double m1H = (pGlui + pSide1).mCalc() - event[ iSide1.back() ].m();
963  double m2H = (pGlui + pSide2).mCalc() - event[ iSide2.back() ].m();
964  if (m2H < m1H) {
965  swap( iSide1, iSide2);
966  swap( pSide1, pSide2);
967  }
968 
969  // Begin loop over two sides of gluino, with lowest relative mass first.
970  for (int iSide = 1; iSide < 3; ++iSide) {
971 
972  // Begin processing of lower-mass string side.
973  int idRHad = 0;
974  double mRHad = 0.;
975  int nBody = 0;
976  int iRNow = 0;
977  int iNewQ = 0;
978  int iNewL = 0;
979  int statusRHad = 0;
980 
981  // Copy down system consecutively from gluino end.
982  int iBeg = event.size();
983  if (iSide == 1) {
984  iCreRHad[iRHad] = iBeg;
985  event.copy( iGlui, 102);
986  for (int i = 0; i < int(iSide1.size()); ++i)
987  event.copy( iSide1[i], 102);
988  } else {
989  event.copy( iGlui, 102);
990  for (int i = 0; i < int(iSide2.size()); ++i)
991  event.copy( iSide2[i], 102);
992  }
993  int iEnd = event.size() - 1;
994 
995  // Pick new flavour to help form R-hadron. Initial colour values.
996  int idOldL = event[iEnd].id();
997  int idNewQ = 21;
998  if (!isGBall) {
999  do {
1000  FlavContainer flavOld( idOldL);
1001  idNewQ = -flavSelPtr->pick(flavOld).id;
1002  } while (iSide == 2 && isDiq1 && abs(idNewQ) > 10);
1003  if (iSide == 1) isDiq1 = (abs(idNewQ) > 10);
1004  }
1005  bool hasCol = (event[iEnd].col() > 0);
1006  int colR = 0;
1007  int acolR = 0;
1008 
1009  // Target intermediary mass or R-hadron mass.
1010  if (iSide == 1) {
1011  idSave = idNewQ;
1012  idRHad = (hasCol) ? 1009002 : -1009002;
1013  if (hasCol) colR = event[iBeg].col();
1014  else acolR = event[iBeg].acol();
1015  statusRHad = 103;
1016  double mNewQ = particleDataPtr->constituentMass( idNewQ);
1017  if (isGBall) mNewQ *= 0.5;
1018  mRHad = event[iBeg].m() + mOffsetCloudRH + mNewQ;
1019  } else {
1020  idRHad = toIdWithGluino( idSave, idNewQ);
1021  if (idRHad == 0) {
1022  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1023  "cannot form R-hadron code");
1024  return false;
1025  }
1026  statusRHad = 104;
1027  mRHad = particleDataPtr->m0(idRHad) + event[iGluiFix].m() - m0Go;
1028  }
1029 
1030  // z value of fragmentation function.
1031  double z = zSelPtr->zFrag( idRGo, idNewQ, mRHad*mRHad);
1032 
1033  // Basic kinematics of string piece where break is to occur.
1034  Vec4 pOldH = event[iBeg].p();
1035  int iOldL = iBeg + 1;
1036  Vec4 pOldL = event[iOldL].p();
1037  double mOldL = event[iOldL].m();
1038  double mNewH = mRHad / z;
1039  double sSys = (pOldH + pOldL).m2Calc();
1040  double sRem = (1. - z) * (sSys - mNewH*mNewH);
1041  double sMin = pow2(mOldL + mCollapseRH);
1042 
1043  // If too low remaining mass in system then add one more parton to it.
1044  while ( ( sRem < sMin || sSys < pow2(mNewH + mOldL + MSAFETY) )
1045  && iOldL < iEnd ) {
1046  ++iOldL;
1047  pOldL += event[iOldL].p();
1048  mOldL = event[iOldL].m();
1049  sSys = (pOldH + pOldL).m2Calc();
1050  sRem = (1. - z) * (sSys - mNewH*mNewH);
1051  sMin = pow2(mOldL + mCollapseRH);
1052  }
1053 
1054  // If enough mass then split off R-hadron and reduced system.
1055  if ( sRem > sMin && sSys > pow2(mNewH + mOldL + MSAFETY) ) {
1056  Vec4 pNewH, pNewL;
1057  if ( !newKin( pOldH, pOldL, mNewH, mOldL, pNewH, pNewL) ) {
1058  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1059  "failed to construct kinematics with reduced system");
1060  return false;
1061  }
1062 
1063  // Insert intermediary or R-hadron with new momentum, less colour.
1064  iRNow = event.append( idRHad, statusRHad, iBeg, iOldL,
1065  0, 0, colR, acolR, z * pNewH, mRHad, 0.);
1066 
1067  // Reduced system with new string endpoint and modified recoiler.
1068  if (!isGBall) idNewQ = -idNewQ;
1069  int colN = (hasCol) ? 0 : event[iOldL].acol();
1070  int acolN = (hasCol) ? event[iOldL].col() : 0;
1071  iNewQ = event.append( idNewQ, 105, iBeg, iOldL, 0, 0,
1072  colN, acolN, (1. - z) * pNewH, (1. - z) * mNewH, 0.);
1073  iNewL = event.copy( iOldL, 105);
1074  event[iNewL].mothers( iBeg, iOldL);
1075  event[iNewL].p( pNewL);
1076 
1077  // Collect partons of new string system.
1078  if (iSide == 1) {
1079  iNewSys1.push_back( iNewQ);
1080  iNewSys1.push_back( iNewL);
1081  for ( int i = iOldL + 1; i <= iEnd; ++i) iNewSys1.push_back( i);
1082  } else {
1083  iNewSys2.push_back( iNewQ);
1084  iNewSys2.push_back( iNewL);
1085  for ( int i = iOldL + 1; i <= iEnd; ++i) iNewSys2.push_back( i);
1086  }
1087 
1088  // Done with processing of split to R-hadron and reduced system.
1089  nBody = 3;
1090  }
1091 
1092  // For side-1 low-mass glueball system reabsorb full momentum.
1093  if (nBody == 0 && isGBall && iSide == 1) {
1094  idQLeap = event[iOldL].id();
1095  Vec4 pNewH = event[iBeg].p() + pOldL;
1096 
1097  // Insert intermediary R-hadron with new momentum, less colour.
1098  iRNow = event.append( idRHad, statusRHad, iBeg, iEnd,
1099  0, 0, colR, acolR, pNewH, pNewH.mCalc(), 0.);
1100  nBody = 1;
1101  }
1102 
1103  // Two-body final state: form light hadron from endpoint and new flavour.
1104  // Also for side 2 if gluinoball formation gives quark from side 1.
1105  if (nBody == 0 && (!isGBall || (iSide == 2 && idQLeap != 0) )) {
1106  if (isGBall) idNewQ = -idQLeap;
1107  FlavContainer flav1( idOldL);
1108  FlavContainer flav2( -idNewQ);
1109  int iTry = 0;
1110  int idNewL = flavSelPtr->combine( flav1, flav2);
1111  while (++iTry < NTRYMAX && idNewL == 0)
1112  idNewL = flavSelPtr->combine( flav1, flav2);
1113  if (idNewL == 0) {
1114  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1115  "cannot form light hadron code");
1116  return false;
1117  }
1118  double mNewL = particleDataPtr->mSel( idNewL);
1119 
1120  // Check that energy enough for light hadron and R-hadron.
1121  if ( sSys > pow2(mRHad + mNewL + MSAFETY) ) {
1122  Vec4 pRHad, pNewL;
1123  if ( !newKin( pOldH, pOldL, mRHad, mNewL, pRHad, pNewL) ) {
1124  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1125  "failed to construct kinematics for two-hadron decay");
1126  return false;
1127  }
1128 
1129  // Insert intermediary or R-hadron and light hadron.
1130  iRNow = event.append( idRHad, statusRHad, iBeg, iOldL, 0, 0,
1131  colR, acolR, pRHad, mRHad, 0.);
1132  event.append( idNewL, 105, iBeg, iOldL, 0, 0, 0, 0,
1133  pNewL, mNewL, 0.);
1134 
1135  // Done for two-body case.
1136  nBody = 2;
1137  // For this case gluinoball should be handled as normal flavour.
1138  isGBall = false;
1139  }
1140  }
1141 
1142  // Final case: for very low mass collapse to one single R-hadron.
1143  if (nBody == 0 && (!isGBall || (iSide == 2 && idQLeap != 0) )) {
1144  if (isGBall) idSave = idQLeap;
1145  if (iSide == 1) idSave = idOldL;
1146  else idRHad = toIdWithGluino( idSave, idOldL);
1147  if (idRHad == 0) {
1148  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1149  "cannot form R-hadron code");
1150  return false;
1151  }
1152 
1153  // Insert R-hadron with new momentum.
1154  iRNow = event.append( idRHad, statusRHad, iBeg, iOldL, 0, 0,
1155  colR, acolR, pOldH + pOldL, (pOldH + pOldL).mCalc(), 0.);
1156 
1157  // Done with one-body case.
1158  // Even if hoped-for, it was not possible to create a gluinoball.
1159  isGBall = false;
1160  }
1161 
1162  // History bookkeeping: the processed partons.
1163  int iLast = event.size() - 1;
1164  for (int i = iBeg; i <= iOldL; ++i) {
1165  event[i].statusNeg();
1166  event[i].daughters( iRNow, iLast);
1167  }
1168 
1169  // End of loop over two sides of the gluino.
1170  iGlui = iRNow;
1171  }
1172 
1173  // History bookkeeping: insert R-hadron; delete old string system.
1174  if (iGlui == 0) {
1175  infoPtr->errorMsg("Error in RHadrons::produceGluino: "
1176  "could not handle gluinoball kinematics");
1177  return false;
1178  }
1179  iRHadron[iRHad] = iGlui;
1180  colConfig.erase(iSys);
1181 
1182  // Non-gluinoball: insert (up to) two new string systems.
1183  if (!isGBall) {
1184  if (iNewSys1.size() > 0) colConfig.insert( iNewSys1, event);
1185  if (iNewSys2.size() > 0) colConfig.insert( iNewSys2, event);
1186 
1187  // Gluinoball with enough energy in first string:
1188  // join two temporary gluons into one.
1189  } else if (idQLeap == 0) {
1190  int iG1 = iNewSys1[0];
1191  int iG2 = iNewSys2[0];
1192  int colG = event[iG1].col() + event[iG2].col();
1193  int acolG = event[iG1].acol() + event[iG2].acol();
1194  Vec4 pG = event[iG1].p() + event[iG2].p();
1195  int iG12 = event.append( 21, 107, iG1, iG2, 0, 0, colG, acolG,
1196  pG, pG.mCalc(), 0.);
1197 
1198  // Temporary gluons no longer needed, but new colour to avoid warnings.
1199  event[iG1].id( 21);
1200  event[iG2].id( 21);
1201  event[iG1].statusNeg();
1202  event[iG2].statusNeg();
1203  event[iG1].daughter1( iG12);
1204  event[iG2].daughter1( iG12);
1205  int colBridge = event.nextColTag();
1206  if (event[iG1].col() == 0) {
1207  event[iG1].col( colBridge);
1208  event[iG2].acol( colBridge);
1209  } else {
1210  event[iG1].acol( colBridge);
1211  event[iG2].col( colBridge);
1212  }
1213 
1214  // Form the remnant system from which the R-hadron has been split off.
1215  vector<int> iNewSys12;
1216  for (int i = int(iNewSys1.size()) - 1; i > 0; --i)
1217  iNewSys12.push_back( iNewSys1[i]);
1218  iNewSys12.push_back( iG12);
1219  for (int i = 1; i < int(iNewSys2.size()); ++i)
1220  iNewSys12.push_back( iNewSys2[i]);
1221  colConfig.insert( iNewSys12, event);
1222 
1223  // Gluinoball where side 1 was fully eaten, and its flavour content
1224  // should leap over to the other side, to a gluon there.
1225  } else {
1226  int iG2 = iNewSys2[0];
1227  event[iG2].id( idQLeap);
1228  colConfig.insert( iNewSys2, event);
1229  }
1230 
1231  // Copy lifetime and vertex from sparticle to R-hadron.
1232  event[iGlui].tau( event[iBef].tau() );
1233  if (event[iBef].hasVertex()) event[iGlui].vProd( event[iBef].vProd() );
1234 
1235  // Done with production of a R-hadron from a gluino.
1236  return true;
1237 
1238 }
1239 
1240 //--------------------------------------------------------------------------
1241 
1242 // Form a R-hadron code from a squark and a (di)quark code.
1243 // First argument is the (anti)squark, second the (anti)(di)quark.
1244 
1245 int RHadrons::toIdWithSquark( int id1, int id2) {
1246 
1247  // Check that physical combination; return 0 if not.
1248  int id1Abs = abs(id1);
1249  int id2Abs = abs(id2);
1250  if (id2Abs < 10 && id1 > 0 && id2 > 0) return 0;
1251  if (id2Abs < 10 && id1 < 0 && id2 < 0) return 0;
1252  if (id2Abs > 10 && id1 > 0 && id2 < 0) return 0;
1253  if (id2Abs > 10 && id1 < 0 && id2 > 0) return 0;
1254 
1255  // Form R-hadron code. Flip sign for antisquark.
1256  bool isSt = (id1Abs == idRSt);
1257  int idRHad = 1000000;
1258  if (id2Abs < 10) idRHad += ((isSt) ? 600 : 500) + 10 * id2Abs + 2;
1259  else idRHad += ((isSt) ? 6000 : 5000) + 10 * (id2Abs/100) + id2Abs%10;
1260  if (id1 < 0) idRHad = -idRHad;
1261 
1262  // Done.
1263  return idRHad;
1264 
1265 }
1266 
1267 //--------------------------------------------------------------------------
1268 
1269 // Resolve a R-hadron code into a squark and a (di)quark.
1270 // Return a pair, where first is the squark and the second the (di)quark.
1271 
1272 pair<int,int> RHadrons::fromIdWithSquark( int idRHad) {
1273 
1274  // Find squark flavour content.
1275  int idLight = (abs(idRHad) - 1000000) / 10;
1276  int idSq = (idLight < 100) ? idLight/10 : idLight/100;
1277  int id1 = (idSq == 6) ? idRSt : idRSb;
1278  if (idRHad < 0) id1 = -id1;
1279 
1280  // Find light (di)quark flavour content.
1281  int id2 = (idLight < 100) ? idLight%10 : idLight%100;
1282  if (id2 > 10) id2 = 100 * id2 + abs(idRHad)%10;
1283  if ((id2 < 10 && idRHad > 0) || (id2 > 10 && idRHad < 0)) id2 = -id2;
1284 
1285  // Done.
1286  return make_pair( id1, id2);
1287 
1288 }
1289 
1290 //--------------------------------------------------------------------------
1291 
1292 // Form a R-hadron code from two quark/diquark endpoints and a gluino.
1293 
1294 int RHadrons::toIdWithGluino( int id1, int id2) {
1295 
1296  // Check that physical combination; return 0 if not. Handle gluinoball.
1297  int id1Abs = abs(id1);
1298  int id2Abs = abs(id2);
1299  if (id1Abs == 21 && id2Abs == 21) return 1000993;
1300  int idMax = max( id1Abs, id2Abs);
1301  int idMin = min( id1Abs, id2Abs);
1302  if (idMin > 10) return 0;
1303  if (idMax > 10 && id1 > 0 && id2 < 0) return 0;
1304  if (idMax > 10 && id1 < 0 && id2 > 0) return 0;
1305  if (idMax < 10 && id1 > 0 && id2 > 0) return 0;
1306  if (idMax < 10 && id1 < 0 && id2 < 0) return 0;
1307 
1308  // Form R-meson code. Flip sign for antiparticle.
1309  int idRHad = 0;
1310  if (idMax < 10) {
1311  idRHad = 1009003 + 100 * idMax + 10 * idMin;
1312  if (idMin != idMax && idMax%2 == 1) {
1313  if (id1Abs == idMax && id1 > 0) idRHad = -idRHad;
1314  if (id2Abs == idMax && id2 > 0) idRHad = -idRHad;
1315  }
1316  if (idMin != idMax && idMax%2 == 0) {
1317  if (id1Abs == idMax && id1 < 0) idRHad = -idRHad;
1318  if (id2Abs == idMax && id2 < 0) idRHad = -idRHad;
1319  }
1320 
1321  // Form R-baryon code. Flip sign for antiparticle.
1322  } else {
1323  int idA = idMax/1000;
1324  int idB = (idMax/100)%10;
1325  int idC = idMin;
1326  if (idC > idB) swap( idB, idC);
1327  if (idB > idA) swap( idA, idB);
1328  if (idC > idB) swap( idB, idC);
1329  idRHad = 1090004 + 1000 * idA + 100 * idB + 10 * idC;
1330  if (id1 < 0) idRHad = -idRHad;
1331  }
1332 
1333  // Done.
1334  return idRHad;
1335 
1336 }
1337 
1338 //--------------------------------------------------------------------------
1339 
1340 // Resolve a R-hadron code into two quark/diquark endpoints (and a gluino).
1341 // Return a pair, where first carries colour and second anticolour.
1342 
1343 pair<int,int> RHadrons::fromIdWithGluino( int idRHad) {
1344 
1345  // Find light flavour content of R-hadron.
1346  int idLight = (abs(idRHad) - 1000000) / 10;
1347  int id1, id2, idTmp, idA, idB, idC;
1348 
1349  // Gluinoballs: split g into d dbar or u ubar.
1350  if (idLight < 100) {
1351  id1 = (rndmPtr->flat() < 0.5) ? 1 : 2;
1352  id2 = -id1;
1353 
1354  // Gluino-meson: split into q + qbar.
1355  } else if (idLight < 1000) {
1356  id1 = (idLight / 10) % 10;
1357  id2 = -(idLight % 10);
1358  // Flip signs when first quark of down-type.
1359  if (id1%2 == 1) {
1360  idTmp = id1;
1361  id1 = -id2;
1362  id2 = -idTmp;
1363  }
1364 
1365  // Gluino-baryon: split to q + qq (diquark).
1366  // Pick diquark at random, except if c or b involved.
1367  } else {
1368  idA = (idLight / 100) % 10;
1369  idB = (idLight / 10) % 10;
1370  idC = idLight % 10;
1371  double rndmQ = 3. * rndmPtr->flat();
1372  if (idA > 3) rndmQ = 0.5;
1373  if (rndmQ < 1.) {
1374  id1 = idA;
1375  id2 = 1000 * idB + 100 * idC + 3;
1376  if (idB != idC && rndmPtr->flat() > diquarkSpin1RH) id2 -= 2;
1377  } else if (rndmQ < 2.) {
1378  id1 = idB;
1379  id2 = 1000 * idA + 100 * idC + 3;
1380  if (idA != idC && rndmPtr->flat() > diquarkSpin1RH) id2 -= 2;
1381  } else {
1382  id1 = idC;
1383  id2 = 1000 * idA + 100 * idB +3;
1384  if (idA != idB && rndmPtr->flat() > diquarkSpin1RH) id2 -= 2;
1385  }
1386  }
1387 
1388  // Flip signs for anti-R-hadron.
1389  if (idRHad < 0) {
1390  idTmp = id1;
1391  id1 = -id2;
1392  id2 = -idTmp;
1393  }
1394 
1395  // Done.
1396  return make_pair( id1, id2);
1397 
1398 }
1399 
1400 //--------------------------------------------------------------------------
1401 
1402 // Construct modified four-vectors to match modified masses:
1403 // minimal reshuffling of momentum along common axis.
1404 // Note that last two arguments are used to provide output!
1405 
1406 bool RHadrons::newKin( Vec4 pOld1, Vec4 pOld2, double mNew1, double mNew2,
1407  Vec4& pNew1, Vec4& pNew2, bool checkMargin) {
1408 
1409  // Squared masses in initial and final kinematics.
1410  double sSum = (pOld1 + pOld2).m2Calc();
1411  double sOld1 = pOld1.m2Calc();
1412  double sOld2 = pOld2.m2Calc();
1413  double sNew1 = mNew1 * mNew1;
1414  double sNew2 = mNew2 * mNew2;
1415 
1416  // Check that kinematically possible.
1417  if (checkMargin && pow2(mNew1 + mNew2 + MSAFETY) > sSum) return false;
1418 
1419  // Transfer coefficients to give four-vectors with the new masses.
1420  double lamOld = sqrt( pow2(sSum - sOld1 - sOld2) - 4. * sOld1 * sOld2 );
1421  double lamNew = sqrt( pow2(sSum - sNew1 - sNew2) - 4. * sNew1 * sNew2 );
1422  double move1 = (lamNew * (sSum - sOld1 + sOld2)
1423  - lamOld * (sSum - sNew1 + sNew2)) / (2. * sSum * lamOld);
1424  double move2 = (lamNew * (sSum + sOld1 - sOld2)
1425  - lamOld * (sSum + sNew1 - sNew2)) / (2. * sSum * lamOld);
1426 
1427  // Construct final vectors. Done.
1428  pNew1 = (1. + move1) * pOld1 - move2 * pOld2;
1429  pNew2 = (1. + move2) * pOld2 - move1 * pOld1;
1430  return true;
1431 
1432 }
1433 
1434 //==========================================================================
1435 
1436 } // end namespace Pythia8
Definition: AgUStep.h:26