StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
BeamRemnants.cc
1 // BeamRemnants.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2018 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
7 // BeamRemnants class.
8 
9 #include "Pythia8/BeamRemnants.h"
10 
11 namespace Pythia8 {
12 
13 //==========================================================================
14 
15 // The BeamRemnants class.
16 
17 //--------------------------------------------------------------------------
18 
19 // Constants: could be changed here if desired, but normally should not.
20 // These are of technical nature, as described for each.
21 
22 // If same (anti)colour appears twice in final state, repair or reject.
23 const bool BeamRemnants::ALLOWCOLOURTWICE = true;
24 
25 // Maximum number of tries to match colours and kinematics in the event.
26 const int BeamRemnants::NTRYCOLMATCH = 10;
27 const int BeamRemnants::NTRYKINMATCH = 10;
28 
29 // Overall correction step for energy-momentum conservation; only
30 // becomes relevant in rescattering scenarios when FSR dipole emissions
31 // and primordial kT is added. Should hopefully not be needed.
32 const bool BeamRemnants::CORRECTMISMATCH = false;
33 
34 //--------------------------------------------------------------------------
35 
36 // Initialization.
37 
38 bool BeamRemnants::init( Info* infoPtrIn, Settings& settings, Rndm* rndmPtrIn,
39  BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn,
40  PartonSystems* partonSystemsPtrIn, PartonVertex* partonVertexPtrIn,
41  ParticleData* particleDataPtrIn,
42  ColourReconnection* colourReconnectionPtrIn) {
43 
44  // Save pointers.
45  infoPtr = infoPtrIn;
46  rndmPtr = rndmPtrIn;
47  beamAPtr = beamAPtrIn;
48  beamBPtr = beamBPtrIn;
49  partonSystemsPtr = partonSystemsPtrIn;
50  partonVertexPtr = partonVertexPtrIn;
51  colourReconnectionPtr = colourReconnectionPtrIn;
52  particleDataPtr = particleDataPtrIn;
53 
54  // Width of primordial kT distribution.
55  doPrimordialKT = settings.flag("BeamRemnants:primordialKT");
56  primordialKTsoft = settings.parm("BeamRemnants:primordialKTsoft");
57  primordialKThard = settings.parm("BeamRemnants:primordialKThard");
58  primordialKTremnant = settings.parm("BeamRemnants:primordialKTremnant");
59  halfScaleForKT = settings.parm("BeamRemnants:halfScaleForKT");
60  halfMassForKT = settings.parm("BeamRemnants:halfMassForKT");
61  reducedKTatHighY = settings.parm("BeamRemnants:reducedKTatHighY");
62 
63  // Handling of rescattering kinematics uncertainties from primodial kT.
64  allowRescatter = settings.flag("MultipartonInteractions:allowRescatter");
65  doRescatterRestoreY = settings.flag("BeamRemnants:rescatterRestoreY");
66 
67  // Choice of beam remnant and colour reconnection scenarios.
68  remnantMode = settings.mode("BeamRemnants:remnantMode");
69  doReconnect = settings.flag("ColourReconnection:reconnect");
70  reconnectMode = settings.mode("ColourReconnection:mode");
71 
72  // Do multiparton interactions.
73  doMPI = settings.flag("PartonLevel:MPI");
74 
75  // Check that remnant model and colour reconnection model work together.
76  if (remnantMode == 1 && reconnectMode == 0) {
77  infoPtr->errorMsg("Abort from BeamRemnants::init: The remnant model"
78  " and colour reconnection model does not work together");
79  return false;
80  }
81 
82  // Total and squared CM energy at nominal energy.
83  eCM = infoPtr->eCM();
84  sCM = eCM * eCM;
85 
86  // Initialize junction splitting class.
87  junctionSplitting.init(infoPtr, settings, rndmPtr, particleDataPtrIn);
88 
89  // Possibility to set parton vertex information.
90  doPartonVertex = settings.flag("PartonVertex:setVertex")
91  && (partonVertexPtr != 0);
92 
93  // Done.
94  return true;
95 
96 }
97 
98 //--------------------------------------------------------------------------
99 
100 // Select the flavours/kinematics/colours of the two beam remnants.
101 // Notation: iPar = all partons, iSys = matched systems of two beams,
102 // iRem = additional partons in remnants.
103 
104 bool BeamRemnants::add( Event& event, int iFirst, bool doDiffCR) {
105 
106  // Update to current CM energy.
107  eCM = infoPtr->eCM();
108  sCM = eCM * eCM;
109 
110  // Check that flavour bookkept in event and in beam particles agree.
111  for (int i = 0; i < beamAPtr->size(); ++i) {
112  int j = (*beamAPtr)[i].iPos();
113  if ((*beamAPtr)[i].id() != event[j].id()) {
114  infoPtr->errorMsg("Error in BeamRemnants::add: "
115  "event and beam flavours do not match");
116  return false;
117  }
118  }
119  for (int i = 0; i < beamBPtr->size(); ++i) {
120  int j = (*beamBPtr)[i].iPos();
121  if ((*beamBPtr)[i].id() != event[j].id()) {
122  infoPtr->errorMsg("Error in BeamRemnants::add: "
123  "event and beam flavours do not match");
124  return false;
125  }
126  }
127 
128  // Deeply inelastic scattering needs special remnant handling.
129  // Here getGammaMode separates from photoproduction.
130  isDIS = (beamAPtr->isLepton() && !beamBPtr->isLepton()
131  && beamAPtr->getGammaMode() == 0)
132  || (beamBPtr->isLepton() && !beamAPtr->isLepton()
133  && beamBPtr->getGammaMode() == 0);
134 
135  // Number of scattering subsystems. Size of event record before treatment.
136  nSys = partonSystemsPtr->sizeSys();
137  oldSize = event.size();
138 
139  // Store event as it was before adding anything.
140  Event eventSave = event;
141  BeamParticle beamAsave = (*beamAPtr);
142  BeamParticle beamBsave = (*beamBPtr);
143  PartonSystems partonSystemsSave = (*partonSystemsPtr);
144 
145  // Two different methods to add the beam remnants.
146  if (remnantMode == 0) {
147  if (!addOld(event)) return false;
148  } else
149  if (!addNew(event)) return false;
150 
151  if (isDIS) return true;
152 
153  // Store event before doing colour reconnections.
154  Event eventTmpSave = event;
155  bool colCorrect = false;
156  for (int i = 0; i < 10; ++i) {
157  if (doReconnect && doDiffCR
158  && (reconnectMode == 1 || reconnectMode == 2)) {
159  colourReconnectionPtr->next(event, iFirst);
160 
161  // Check that the new colour structure is physical.
162  if (!junctionSplitting.checkColours(event))
163  event = eventTmpSave;
164  else {
165  colCorrect = true;
166  break;
167  }
168  // If no colour reconnection, just check the colour configuration once.
169  } else {
170  if (junctionSplitting.checkColours(event))
171  colCorrect = true;
172  break;
173  }
174  }
175 
176  // Possibility to add vertex information to beam particles.
177  if (doPartonVertex) {
178  BeamParticle* beamPtr = beamAPtr;
179  // Add vertex information for both beams.
180  for (int beam = 0; beam < 2; ++beam) {
181  for (int i = 0; i < beamPtr->size(); ++i) {
182  int j = (*beamPtr)[i].iPos();
183  // We might have daughters.
184  vector<int> dList = event[j].daughterList();
185  // First the beam remnant particle itself.
186  partonVertexPtr->vertexBeam(j, beam, event);
187  // Then possible daughters.
188  for(int k = 0, N = dList.size(); k < N; ++k )
189  partonVertexPtr->vertexBeam(dList[k],beam,event);
190  }
191  // Switch beam.
192  beamPtr = beamBPtr;
193  }
194  }
195 
196  // Restore event and return false if colour reconnection failed.
197  if (!colCorrect) {
198  event = eventSave;
199  (*beamAPtr) = beamAsave;
200  (*beamBPtr) = beamBsave;
201  (*partonSystemsPtr) = partonSystemsSave;
202  infoPtr->errorMsg("Error in BeamRemnants::add: "
203  "failed to find physical colour state after colour reconnection");
204  return false;
205  }
206 
207  // Done.
208  return true;
209 }
210 
211 //--------------------------------------------------------------------------
212 
213 // Old function for adding beam remnant.
214 
215 bool BeamRemnants::addOld( Event& event) {
216 
217  // Add required extra remnant flavour content.
218  // Start all over if fails (in option where junctions not allowed).
219  if ( !beamAPtr->remnantFlavours(event, isDIS)
220  || !beamBPtr->remnantFlavours(event, isDIS) ) {
221  infoPtr->errorMsg("Error in BeamRemnants::add:"
222  " remnant flavour setup failed");
223  return false;
224  }
225 
226  // Do the kinematics of the collision subsystems and two beam remnants.
227  if (!setKinematics(event)) return false;
228 
229  // Allow colour reconnections.
230  if (doReconnect && reconnectMode == 0 && !isDIS)
231  colourReconnectionPtr->next(event, oldSize);
232 
233  // Save current modifiable colour configuration for fast restoration.
234  vector<int> colSave;
235  vector<int> acolSave;
236  for (int i = oldSize; i < event.size(); ++i) {
237  colSave.push_back( event[i].col() );
238  acolSave.push_back( event[i].acol() );
239  }
240  event.saveJunctionSize();
241 
242  // Allow several tries to match colours of initiators and remnants.
243  // Frequent "failures" since shortcutting colours separately on
244  // the two event sides may give "colour singlet gluons" etc.
245  bool physical = true;
246  for (int iTry = 0; iTry < NTRYCOLMATCH; ++iTry) {
247  physical = true;
248 
249  // Reset list of colour "collapses" (transformations).
250  colFrom.resize(0);
251  colTo.resize(0);
252 
253  // First process each set of beam colours on its own.
254  if (!beamAPtr->remnantColours(event, colFrom, colTo))
255  physical = false;
256  if (!beamBPtr->remnantColours(event, colFrom, colTo))
257  physical = false;
258 
259  // Then check that colours and anticolours are matched in whole event.
260  if ( physical && !checkColours(event) ) physical = false;
261 
262  // If no problems then done, else restore and loop.
263  if (physical) break;
264  for (int i = oldSize; i < event.size(); ++i)
265  event[i].cols( colSave[i - oldSize], acolSave[i - oldSize] );
266  event.restoreJunctionSize();
267  infoPtr->errorMsg("Warning in BeamRemnants::add:"
268  " colour tracing failed; will try again");
269  }
270 
271  // If no solution after several tries then failed.
272  if (!physical) {
273  infoPtr->errorMsg("Error in BeamRemnants::add:"
274  " colour tracing failed after several attempts");
275  return false;
276  }
277 
278  // Done.
279  return true;
280 }
281 
282 //--------------------------------------------------------------------------
283 
284 // New function for adding beam remnant.
285 
286 bool BeamRemnants::addNew( Event& event) {
287 
288  // Start by saving a copy of the event, if the beam remnant fails.
289  Event eventSave = event;
290  BeamParticle beamAsave = (*beamAPtr);
291  BeamParticle beamBsave = (*beamBPtr);
292  PartonSystems partonSystemsSave = (*partonSystemsPtr);
293 
294  // Do several tries in case an unphysical colour contruction is made.
295  bool beamRemnantFound = false;
296  int nMaxTries = 10;
297 
298  for (int iTries = 0;iTries < nMaxTries; ++iTries) {
299 
300  // Set the initial colours.
301  beamAPtr->setInitialCol(event);
302  beamBPtr->setInitialCol(event);
303 
304  // Find colour state of outgoing partons and reconnect colours to match it.
305  beamAPtr->findColSetup(event);
306  beamBPtr->updateCol(beamAPtr->getColUpdates());
307 
308  beamBPtr->findColSetup(event);
309  beamAPtr->updateCol(beamBPtr->getColUpdates());
310 
311  // Add beam remnants.
312  beamAPtr->remnantFlavoursNew(event);
313  beamBPtr->remnantFlavoursNew(event);
314 
315  // It is possible junctions were added, so update list.
316  event.saveJunctionSize();
317 
318  // Do the kinematics of the collision subsystems and two beam remnants.
319  if (!setKinematics(event)) {
320  // If it does not work, try parton level again.
321  event = eventSave;
322  (*beamAPtr) = beamAsave;
323  (*beamBPtr) = beamBsave;
324  (*partonSystemsPtr) = partonSystemsSave;
325  return false;
326  }
327 
328  // Update the colour changes for all final state particles.
329  updateColEvent(event, beamAPtr->getColUpdates());
330  updateColEvent(event, beamBPtr->getColUpdates());
331 
332  // Check whether the new colour structure can be accepted.
333  if (junctionSplitting.checkColours(event)) {
334  beamRemnantFound = true;
335  break;
336  }
337 
338  // If failed, restore earlier configuration and try to find new
339  // colour structure.
340  else {
341  event = eventSave;
342  (*beamAPtr) = beamAsave;
343  (*beamBPtr) = beamBsave;
344  (*partonSystemsPtr) = partonSystemsSave;
345  }
346  }
347 
348  // Return if it was not possible to find physical colour structure.
349  if (!beamRemnantFound) {
350  infoPtr->errorMsg("Error in BeamRemnants::add: "
351  "failed to find physical colour structure");
352  // Restore event to previous state.
353  event = eventSave;
354  (*beamAPtr) = beamAsave;
355  (*beamBPtr) = beamBsave;
356  (*partonSystemsPtr) = partonSystemsSave;
357  return false;
358  }
359 
360  // Done.
361  return true;
362 }
363 
364 //--------------------------------------------------------------------------
365 
366 // Set up trial transverse and longitudinal kinematics for each beam
367 // separately. Final decisions involve comparing the two beams.
368 
369 bool BeamRemnants::setKinematics( Event& event) {
370 
371  // References to beams to simplify indexing.
372  BeamParticle& beamA = *beamAPtr;
373  BeamParticle& beamB = *beamBPtr;
374 
375  // Nothing to do for lepton-lepton scattering with all energy already used.
376  if ( beamA.isUnresolvedLepton() && beamB.isUnresolvedLepton() )
377  return true;
378 
379  // Photon from photon beam is unresolved.
380  if ( beamA.isGamma() && beamA[0].id() == 22 ) {
381  beamA.resolvedGamma(false);
382  }
383  if ( beamB.isGamma() && beamB[0].id() == 22 ) {
384  beamB.resolvedGamma(false);
385  }
386 
387  // Check if photon beams need remnants.
388  bool beamAisGamma = beamA.isGamma();
389  bool beamBisGamma = beamB.isGamma();
390  bool gammaAResolved = beamA.resolvedGamma();
391  bool gammaBResolved = beamB.resolvedGamma();
392  bool gammaOneResolved = false;
393 
394  // Do nothing if ISR have found the original beam photons and only one MPI.
395  if ( ( beamAisGamma && !gammaAResolved && beamBisGamma && !gammaBResolved )
396  && infoPtr->nMPI() == 1 )
397  return true;
398 
399  // Check that has not already used up beams. Unless direct photon in photon.
400  if ( beamA.isGamma() && beamA[0].id() == 22 ) { }
401  else if ( beamB.isGamma() && beamB[0].id() == 22 ) { }
402  else if ( ( !(beamA.isLepton() || (beamAisGamma && !gammaAResolved) )
403  && beamA.xMax(-1) <= 0.) ||
404  ( !(beamB.isLepton() || (beamBisGamma && !gammaBResolved) )
405  && beamB.xMax(-1) <= 0.) ) {
406  infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
407  " no momentum left for beam remnants");
408  return false;
409  }
410 
411  // Check if exactly one remnant for photon-photon collisions.
412  if ( (beamAisGamma && beamBisGamma) &&
413  ( (gammaAResolved && !gammaBResolved) ||
414  (!gammaAResolved && gammaBResolved) ) )
415  gammaOneResolved = true;
416 
417  // Unresolved photon + hadron.
418  if ( ( (beamAisGamma && !gammaAResolved)
419  || (beamBisGamma && !gammaBResolved) )
420  && !(beamAisGamma && beamBisGamma) )
421  gammaOneResolved = true;
422 
423  // Unresolved photon from lepton + hadron.
424  if ( ( beamA.getGammaMode() == 2 && beamB.isHadron() )
425  || ( beamB.getGammaMode() == 2 && beamA.isHadron() ) )
426  gammaOneResolved = true;
427 
428  // Special kinematics setup for one-remnant systems (DIS).
429  if ( (gammaOneResolved && infoPtr->nMPI() == 1) || isDIS )
430  return setOneRemnKinematics(event, iDS);
431 
432  // Last beam-status particles. Offset relative to normal beam locations.
433  int nBeams = 3;
434  for (int i = 3; i < event.size(); ++i)
435  if (event[i].statusAbs() < 20) nBeams = i + 1;
436  int nOffset = nBeams - 3;
437 
438  // If extra photons in event fix the offset.
439  if ( !(beamA.isHadron() || beamB.isHadron()) ) {
440  if (beamA.hasResGamma()) --nOffset;
441  if (beamB.hasResGamma()) --nOffset;
442  }
443 
444  // Reserve space for extra information on the systems and beams.
445  int nMaxBeam = max( beamA.size(), beamB.size() );
446  vector<double> sHatSys(nMaxBeam);
447  vector<double> kTwidth(nMaxBeam);
448  vector<double> kTcomp(nMaxBeam);
449  vector<RotBstMatrix> Msys(nSys);
450 
451  // Loop over all subsystems. Default values. Find invariant mass.
452  double kTcompSumA = 0.;
453  double kTcompSumB = 0.;
454  for (int iSys = 0; iSys < nSys; ++iSys) {
455  double kTwidthNow = 0.;
456  double mHatDamp = 1.;
457  int iInA = partonSystemsPtr->getInA(iSys);
458  int iInB = partonSystemsPtr->getInB(iSys);
459  double sHatNow = (event[iInA].p() + event[iInB].p()).m2Calc();
460 
461  // Allow primordial kT reduction for small-mass and small-pT systems
462  // (for hardest interaction pT -> renormalization scale so also 2 -> 1).
463  if (doPrimordialKT) {
464  double mHat = sqrt(sHatNow);
465  double yDamp = pow( (event[iInA].e() + event[iInB].e()) / mHat,
466  reducedKTatHighY );
467  mHatDamp = mHat / (mHat + halfMassForKT * yDamp);
468  double scale = (iSys == 0) ? infoPtr->QRen(iDS)
469  : partonSystemsPtr->getPTHat(iSys);
470  kTwidthNow = ( (halfScaleForKT * primordialKTsoft
471  + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
472  }
473 
474  // Store properties of compensation systems and total compensation power.
475  // Rescattered partons do not compensate, but may be massive.
476  sHatSys[iSys] = sHatNow;
477  kTwidth[iSys] = kTwidthNow ;
478  kTcomp[iSys] = mHatDamp;
479  if (beamA[iSys].isFromBeam()) kTcompSumA += mHatDamp;
480  else beamA[iSys].m( event[iInA].m() );
481  if (beamB[iSys].isFromBeam()) kTcompSumB += mHatDamp;
482  else beamB[iSys].m( event[iInB].m() );
483  }
484 
485  // Primordial kT and compensation power among remnants.
486  double kTwidthNow = (doPrimordialKT) ? primordialKTremnant : 0.;
487  for (int iRem = nSys; iRem < nMaxBeam; ++iRem) {
488  sHatSys[iRem] = 0.;
489  kTwidth[iRem] = kTwidthNow ;
490  kTcomp[iRem] = 1.;
491  }
492  kTcompSumA += beamA.size() - nSys;
493  kTcompSumB += beamB.size() - nSys;
494 
495  // Allow ten tries to construct kinematics (but normally works first).
496  bool physical;
497  double xSum[2], xInvM[2], w2Beam[2], wPosRem, wNegRem, w2Rem;
498  for (int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
499  physical = true;
500 
501  // Loop over the two beams.
502  for (int iBeam = 0; iBeam < 2; ++iBeam) {
503  BeamParticle& beam = (iBeam == 0) ? beamA : beamB;
504  int nPar = beam.size();
505 
506  // Generate Gaussian pT for initiator partons inside hadrons.
507  // Store/restore rescattered parton momenta before primordial kT.
508  if ( (beam.isHadron() || beam.isGamma()) && doPrimordialKT ) {
509  double pxSum = 0.;
510  double pySum = 0.;
511  for (int iPar = 0; iPar < nPar; ++iPar) {
512  // Do nothing if initiator parton from gamma->qqbar
513  // where gamma is the original beam particle or for
514  // the other valence arising from the same splitting.
515  if ( iPar == beam.gamVal() || ( beam.gamVal() >= 0 &&
516  ( iPar != beam.gamVal() && beam[iPar].isValence()) ) ) ;
517  else if ( beam[iPar].isFromBeam() ) {
518  pair<double, double> gauss2 = rndmPtr->gauss2();
519  double px = kTwidth[iPar] * gauss2.first;
520  double py = kTwidth[iPar] * gauss2.second;
521  beam[iPar].px(px);
522  beam[iPar].py(py);
523  pxSum += px;
524  pySum += py;
525  } else {
526  int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
527  : partonSystemsPtr->getInB(iPar);
528  beam[iPar].p( event[iInAB].p() );
529  }
530  }
531 
532  // Share recoil between all initiator partons, rescatterers excluded.
533  double kTcompSum = (iBeam == 0) ? kTcompSumA : kTcompSumB;
534 
535  // If parton from gamma->qqbar in ISR, set pT accordingly.
536  if ( beam.gamVal() >= 0 ) {
537 
538  // Get the pT2 value for the given gamma->qqbar splitting.
539  double pT2corr = beam.pT2gamma2qqbar();
540 
541  // Sample the direction and set px and py.
542  double phi = 2*M_PI*rndmPtr->flat();
543  double px = cos(phi) * sqrt(pT2corr);
544  double py = sin(phi) * sqrt(pT2corr);
545  beam[beam.gamVal()].px(px);
546  beam[beam.gamVal()].py(py);
547  pxSum += px;
548  pySum += py;
549 
550  // Do not change the momentum of these partons when sharing recoil.
551  kTcompSum -= kTcomp[beam.gamVal()];
552 
553  // Other valence parton takes (most of) the recoil but this will
554  // still be part of pT balancing.
555  for (int iPar = 0; iPar < nPar; ++iPar)
556  if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
557  beam[iPar].px(-px);
558  beam[iPar].py(-py);
559  pxSum += -px;
560  pySum += -py;
561  break;
562  }
563  }
564 
565  for (int iPar = 0; iPar < nPar; ++iPar) {
566  if (beam[iPar].isFromBeam() && iPar != beam.gamVal() ) {
567  beam[iPar].px( beam[iPar].px() - pxSum * kTcomp[iPar] / kTcompSum);
568  beam[iPar].py( beam[iPar].py() - pySum * kTcomp[iPar] / kTcompSum);
569  }
570  }
571 
572  // Without primordial kT: still need to store rescattered partons.
573  } else if ( beam.isHadron() || beam.isGamma() ) {
574  for (int iPar = 0; iPar < nPar; ++iPar) {
575  if ( !beam[iPar].isFromBeam() ) {
576  int iInAB = (iBeam == 0) ? partonSystemsPtr->getInA(iPar)
577  : partonSystemsPtr->getInB(iPar);
578  beam[iPar].p( event[iInAB].p() );
579  }
580  }
581 
582  // And set the pT in case gamma->qqbar splitting with MPIs.
583  if ( beam.gamVal() >= 0 ) {
584  double phi = 2*M_PI*rndmPtr->flat();
585  double px = cos(phi) * sqrt(beam.pT2gamma2qqbar());
586  double py = sin(phi) * sqrt(beam.pT2gamma2qqbar());
587  beam[beam.gamVal()].px(px);
588  beam[beam.gamVal()].py(py);
589 
590  // Other valence parton takes the recoil but this will still be
591  // part of pT balancing.
592  for (int iPar = 0; iPar < nPar; ++iPar) {
593  if ( iPar != beam.gamVal() && beam[iPar].isValence() ) {
594  beam[iPar].px(-px);
595  beam[iPar].py(-py);
596  break;
597  }
598  }
599  }
600 
601  }
602 
603  // Pick unrescaled x values for remnants. Sum up (unscaled) p+ and p-.
604  xSum[iBeam] = 0.;
605  xInvM[iBeam] = 0.;
606  for (int iRem = nSys; iRem < nPar; ++iRem) {
607  double xPrel = beam.xRemnant( iRem);
608  beam[iRem].x(xPrel);
609  xSum[iBeam] += xPrel;
610  xInvM[iBeam] += beam[iRem].mT2()/xPrel;
611  }
612 
613  // Squared transverse mass for each beam, using lightcone x.
614  w2Beam[iBeam] = xSum[iBeam] * xInvM[iBeam];
615 
616  // End separate treatment of the two beams.
617  }
618 
619  // Recalculate kinematics of initiator systems with primordial kT.
620  wPosRem = eCM;
621  wNegRem = eCM;
622  for (int iSys = 0; iSys < nSys; ++iSys) {
623  int iA = beamA[iSys].iPos();
624  int iB = beamB[iSys].iPos();
625  double sHat = sHatSys[iSys];
626 
627  // Classify system: rescattering on either or both sides?
628  bool normalA = beamA[iSys].isFromBeam();
629  bool normalB = beamB[iSys].isFromBeam();
630  bool normalSys = normalA && normalB;
631  bool doubleRes = !normalA && !normalB;
632 
633  // Check whether final-state system momentum matches initial-state one.
634  if (allowRescatter && CORRECTMISMATCH) {
635  Vec4 pInitial = event[iA].p() + event[iB].p();
636  Vec4 pFinal;
637  for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
638  int iAB = partonSystemsPtr->getOut(iSys, iMem);
639  if (event[iAB].isFinal()) pFinal += event[iAB].p();
640  }
641 
642  // Scale down primordial kT from side A if p+ increased.
643  if (normalA && pFinal.pPos() > pInitial.pPos())
644  beamA[iSys].scalePT( pInitial.pPos() / pFinal.pPos() );
645 
646  // Scale down primordial kT from side B if p- increased.
647  if (normalB && pFinal.pNeg() > pInitial.pNeg())
648  beamB[iSys].scalePT( pInitial.pNeg() / pFinal.pNeg() );
649  }
650 
651  // Rescatter: possible change in sign of lightcone momentum of a
652  // rescattered parton. If this happens, try to pick
653  // new primordial kT values
654  if (allowRescatter
655  && (event[iA].pPos() / beamA[iSys].pPos() < 0
656  || event[iB].pNeg() / beamB[iSys].pNeg() < 0) ) {
657  infoPtr->errorMsg("Warning in BeamRemnants::setKinematics:"
658  " change in lightcone momentum sign; retrying kinematics");
659  physical = false;
660  break;
661  }
662 
663  // Begin kinematics of partons after primordial kT has been added.
664  double sHatTAft = sHat + pow2( beamA[iSys].px() + beamB[iSys].px())
665  + pow2( beamA[iSys].py() + beamB[iSys].py());
666  double w2A = beamA[iSys].mT2();
667  double w2B = beamB[iSys].mT2();
668  double w2Diff = sHatTAft - w2A - w2B;
669  double lambda = pow2(w2Diff) - 4. * w2A * w2B;
670 
671  // Too large transverse momenta means that kinematics will not work.
672  if (lambda <= 0.) {
673  physical = false;
674  break;
675  }
676  double lamRoot = sqrtpos( lambda );
677 
678  // Mirror solution if the two incoming have reverse rapidity ordering.
679  if (allowRescatter && doubleRes && (event[iA].pPos() * event[iB].pNeg()
680  < event[iA].pNeg() * event[iB].pPos()) ) lamRoot = -lamRoot;
681 
682  // Two procedures, which agree for normal scattering, separate here.
683  // First option keeps rapidity (and mass) of system unchanged by
684  // primordial kT, by modification of rescattered parton.
685  if (normalSys || doRescatterRestoreY || doubleRes) {
686 
687  // Find kinematics of initial system: transverse mass, and
688  // longitudinal momentum carried by all or rescattered partons.
689  double sHatTBef = sHat;
690  double wPosBef, wNegBef, wPosBefRes, wNegBefRes;
691  // Normal scattering.
692  if (normalSys) {
693  wPosBef = beamA[iSys].x() * eCM;
694  wNegBef = beamB[iSys].x() * eCM;
695  wPosBefRes = 0.;
696  wNegBefRes = 0.;
697  // Rescattering on side A.
698  } else if (normalB) {
699  sHatTBef += event[iA].pT2();
700  wPosBef = event[iA].pPos();
701  wNegBef = event[iA].pNeg() + beamB[iSys].x() * eCM;
702  wPosBefRes = beamA[iSys].pPos();
703  wNegBefRes = beamA[iSys].pNeg();
704  // Rescattering on side B.
705  } else if (normalA) {
706  sHatTBef += event[iB].pT2();
707  wPosBef = beamA[iSys].x() * eCM + event[iB].pPos();
708  wNegBef = event[iB].pNeg();
709  wPosBefRes = beamB[iSys].pPos();
710  wNegBefRes = beamB[iSys].pNeg();
711  // Rescattering on both sides.
712  } else {
713  sHatTBef += pow2( event[iA].px() + event[iB].px())
714  + pow2( event[iA].py() + event[iB].py());
715  wPosBef = event[iA].pPos() + event[iB].pPos();
716  wNegBef = event[iA].pNeg() + event[iB].pNeg();
717  wPosBefRes = beamA[iSys].pPos() + beamB[iSys].pPos();
718  wNegBefRes = beamA[iSys].pNeg() + beamB[iSys].pNeg();
719  }
720 
721  // Rescale outgoing momenta to keep same mass and rapidity of system
722  // as originally, and solve for kinematics.
723  double rescale = sqrt(sHatTAft / sHatTBef);
724  double wPosAft = rescale * wPosBef;
725  double wNegAft = rescale * wNegBef;
726  wPosRem -= wPosAft - wPosBefRes;
727  wNegRem -= wNegAft - wNegBefRes;
728  double wPosA = 0.5 * (sHatTAft + w2A - w2B + lamRoot) / wNegAft;
729  double wNegB = 0.5 * (sHatTAft + w2B - w2A + lamRoot) / wPosAft;
730 
731  // Store modified beam parton momenta.
732  beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
733  beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
734  beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
735  beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
736 
737  // Second option keeps rescattered parton (and system mass) unchanged
738  // by primordial kT, by modification of system rapidity.
739  } else {
740 
741  // Rescattering on side A: preserve already scattered parton.
742  if (normalB) {
743  double wPosA = beamA[iSys].pPos();
744  double wNegB = 0.5 * (w2Diff + lamRoot) / wPosA;
745  beamB[iSys].e( 0.5 * (w2B / wNegB + wNegB) );
746  beamB[iSys].pz( 0.5 * (w2B / wNegB - wNegB) );
747  wPosRem -= w2B / wNegB;
748  wNegRem -= wNegB;
749 
750 
751  // Rescattering on side B: preserve already scattered parton.
752  } else if (normalA) {
753  double wNegB = beamB[iSys].pNeg();
754  double wPosA = 0.5 * (w2Diff + lamRoot) / wNegB;
755  beamA[iSys].e( 0.5 * (wPosA + w2A / wPosA) );
756  beamA[iSys].pz( 0.5 * (wPosA - w2A / wPosA) );
757  wPosRem -= wPosA;
758  wNegRem -= w2A / wPosA;
759 
760  // Primordial kT in double rescattering does change the mass of
761  // the system without any possible fix in this framework, which
762  // leads to incorrect boosts. Current choice is therefore always
763  // to handle it with the first procedure, where mass is retained.
764  } else {
765  }
766  }
767 
768  // Construct system rotation and boost caused by primordial kT.
769  Msys[iSys].reset();
770  Msys[iSys].toCMframe( event[iA].p(), event[iB].p() );
771  Msys[iSys].fromCMframe( beamA[iSys].p(), beamB[iSys].p() );
772 
773  // Boost rescattered partons in subsequent beam A list.
774  for (int iSys2 = iSys + 1; iSys2 < nSys; ++iSys2) {
775  if (!beamA[iSys2].isFromBeam()) {
776  int iBefResc = event[ beamA[iSys2].iPos() ].mother1();
777  for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
778  if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
779  Vec4 pTemp = event[iBefResc].p();
780  pTemp.rotbst( Msys[iSys] );
781  beamA[iSys2].p( pTemp );
782  }
783  }
784 
785  // Boost rescattered partons in subsequent beam B list.
786  if (!beamB[iSys2].isFromBeam()) {
787  int iBefResc = event[ beamB[iSys2].iPos() ].mother1();
788  for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem)
789  if (partonSystemsPtr->getOut(iSys, iMem) == iBefResc) {
790  Vec4 pTemp = event[iBefResc].p();
791  pTemp.rotbst( Msys[iSys] );
792  beamB[iSys2].p( pTemp );
793  }
794  }
795  }
796  }
797 
798  // Check that remaining momentum is enough for remnants.
799  if (wPosRem < 0. || wNegRem < 0.) physical = false;
800  w2Rem = wPosRem * wNegRem;
801  if (sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1]))
802  physical = false;
803 
804  // End of loop over ten tries. Do not loop when solution found.
805  if (physical) break;
806  }
807 
808  // If no solution after ten tries then failed.
809  if (!physical) {
810  infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
811  " kinematics construction failed");
812  return false;
813  }
814 
815  // For successful initiator kinematics process whole systems.
816  Vec4 pSumOut;
817  for (int iSys = 0; iSys < nSys; ++iSys) {
818 
819  // Copy initiators and their systems and boost them accordingly.
820  // Update subsystem and beams info on new positions of partons.
821  // Update daughter info of mothers, i.e. of beams, for hardest interaction.
822  if (beamA[iSys].isFromBeam()) {
823  int iA = beamA[iSys].iPos();
824  int iAcopy = event.copy(iA, -61);
825  event[iAcopy].rotbst(Msys[iSys]);
826  partonSystemsPtr->setInA(iSys, iAcopy);
827  beamA[iSys].iPos( iAcopy);
828  if (iSys == 0) {
829  int mother = event[iAcopy].mother1();
830  event[mother].daughter1(iAcopy);
831  }
832  }
833  if (beamB[iSys].isFromBeam()) {
834  int iB = beamB[iSys].iPos();
835  int iBcopy = event.copy(iB, -61);
836  event[iBcopy].rotbst(Msys[iSys]);
837  partonSystemsPtr->setInB(iSys, iBcopy);
838  beamB[iSys].iPos( iBcopy);
839  if (iSys == 0) {
840  int mother = event[iBcopy].mother1();
841  event[mother].daughter1(iBcopy);
842  }
843  }
844 
845  for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
846  int iAB = partonSystemsPtr->getOut(iSys, iMem);
847  if (event[iAB].isFinal()) {
848  int iABcopy = event.copy(iAB, 62);
849  event[iABcopy].rotbst(Msys[iSys]);
850  partonSystemsPtr->setOut(iSys, iMem, iABcopy);
851  pSumOut += event[iABcopy].p();
852  }
853  }
854 
855  }
856 
857  // Colour dipoles spanning systems gives mismatch between FSR recoils
858  // and primordial kT boosts.
859  if (allowRescatter && CORRECTMISMATCH) {
860 
861  // Find summed pT of beam remnants = - wanted pT of systems.
862  double pxBeams = 0.;
863  double pyBeams = 0.;
864  for (int iRem = nSys; iRem < beamA.size(); ++iRem) {
865  pxBeams += beamA[iRem].px();
866  pyBeams += beamA[iRem].py();
867  }
868  for (int iRem = nSys; iRem < beamB.size(); ++iRem) {
869  pxBeams += beamB[iRem].px();
870  pyBeams += beamB[iRem].py();
871  }
872 
873  // Boost all final partons in systems transversely, and also their sum.
874  Vec4 pSumTo( -pxBeams, -pyBeams, pSumOut.pz(), sqrt( pow2(pxBeams)
875  + pow2(pyBeams) + pow2(pSumOut.pz()) + pSumOut.m2Calc() ) );
876  RotBstMatrix Mmismatch;
877  Mmismatch.bst( pSumOut, pSumTo);
878  for (int iSys = 0; iSys < nSys; ++iSys)
879  for (int iMem = 0; iMem < partonSystemsPtr->sizeOut(iSys); ++iMem) {
880  int iAB = partonSystemsPtr->getOut(iSys, iMem);
881  if (event[iAB].isFinal()) event[iAB].rotbst(Mmismatch);
882  }
883  pSumOut.rotbst(Mmismatch);
884 
885  // Reset energy and momentum sum, to be compensated by beam remnants.
886  wPosRem = eCM - (pSumOut.e() + pSumOut.pz());
887  wNegRem = eCM - (pSumOut.e() - pSumOut.pz());
888  w2Rem = wPosRem * wNegRem;
889  if ( wPosRem < 0. || wNegRem < 0.
890  || sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1])) {
891  infoPtr->errorMsg("Error in BeamRemnants::setKinematics:"
892  " kinematics construction failed owing to recoil mismatch");
893  return false;
894  }
895  }
896 
897  // Construct x rescaling factors for the two remants.
898  double lambdaRoot = sqrtpos( pow2(w2Rem - w2Beam[0] - w2Beam[1])
899  - 4. * w2Beam[0] * w2Beam[1] );
900  double rescaleA = (w2Rem + w2Beam[0] - w2Beam[1] + lambdaRoot)
901  / (2. * w2Rem * xSum[0]) ;
902  double rescaleB = (w2Rem + w2Beam[1] - w2Beam[0] + lambdaRoot)
903  / (2. * w2Rem * xSum[1]) ;
904 
905  // Construct energy and pz for remnants in first beam.
906  for (int iRem = nSys; iRem < beamA.size(); ++iRem) {
907  double pPos = rescaleA * beamA[iRem].x() * wPosRem;
908  double pNeg = beamA[iRem].mT2() / pPos;
909  beamA[iRem].e( 0.5 * (pPos + pNeg) );
910  beamA[iRem].pz( 0.5 * (pPos - pNeg) );
911 
912  // Add these partons to the normal event record.
913  int iNew = event.append( beamA[iRem].id(), 63, 1 + nOffset, 0, 0, 0,
914  beamA[iRem].col(), beamA[iRem].acol(), beamA[iRem].p(),
915  beamA[iRem].m() );
916  beamA[iRem].iPos( iNew);
917  }
918 
919  // Construct energy and pz for remnants in second beam.
920  for (int iRem = nSys; iRem < beamB.size(); ++iRem) {
921  double pNeg = rescaleB * beamB[iRem].x() * wNegRem;
922  double pPos = beamB[iRem].mT2() / pNeg;
923  beamB[iRem].e( 0.5 * (pPos + pNeg) );
924  beamB[iRem].pz( 0.5 * (pPos - pNeg) );
925 
926  // Add these partons to the normal event record.
927  int iNew = event.append( beamB[iRem].id(), 63, 2 + nOffset, 0, 0, 0,
928  beamB[iRem].col(), beamB[iRem].acol(), beamB[iRem].p(),
929  beamB[iRem].m() );
930  beamB[iRem].iPos( iNew);
931  }
932 
933  // Done.
934  return true;
935 
936 }
937 
938 //--------------------------------------------------------------------------
939 
940 // Special beam remnant kinematics for gamma-gamma collision with one
941 // remnant system, other created by ISR, and for Deeply Inelastic Scattering.
942 // Currently assumes unresolved lepton.
943 
944 bool BeamRemnants::setOneRemnKinematics( Event& event, int beamOffset) {
945 
946  // Identify beams with and without remnant.
947  int iBeamHad;
948  if ( beamAPtr->isGamma() && beamBPtr->isGamma() )
949  iBeamHad = beamAPtr->resolvedGamma() ? 1 : 2;
950  else iBeamHad = beamAPtr->isHadron() ? 1 : 2;
951  BeamParticle& beamHad = (iBeamHad == 1) ? *beamAPtr : *beamBPtr;
952  BeamParticle& beamOther = (iBeamHad == 2) ? *beamAPtr : *beamBPtr;
953 
954  // Beam offsets in case of gamma+gamma.
955  int iBeamA = 1 + beamOffset;
956  int iBeamB = 2 + beamOffset;
957 
958  // Identify remnant-side hadronic four-momentum and scattered lepton if DIS.
959  int iLepScat = isDIS ? (beamOther[0].iPos() + 2) : -1;
960  Vec4 pHadScat;
961  for (int i = 5 + beamOffset; i < event.size(); ++i)
962  if (event[i].isFinal() && i != iLepScat) pHadScat += event[i].p();
963 
964  // Set scattered lepton momentum if DIS and find the hadronic system.
965  Vec4 pLepScat = isDIS ? event[iLepScat].p() : Vec4();
966  Vec4 pHadTot = event[iBeamA].p() + event[iBeamB].p();
967  if ( isDIS ) pHadTot -= pLepScat;
968  Vec4 pRemnant = pHadTot - pHadScat;
969  double w2Tot = pHadTot.m2Calc();
970  double w2Scat = pHadScat.m2Calc();
971 
972  // Find a boost to the hadronic rest frame.
973  RotBstMatrix MtoHadRest;
974  RotBstMatrix MtoHadRest2;
975  MtoHadRest2.toCMframe( pHadScat, pRemnant);
976 
977  // Do not flip the direction with boosts.
978  if (iBeamHad == 1) MtoHadRest.toCMframe( pRemnant, pHadScat);
979  else MtoHadRest.toCMframe( pHadScat, pRemnant);
980 
981  // Boost the event to hadronic rest frame.
982  event.rotbst( MtoHadRest);
983  pHadScat.rotbst( MtoHadRest);
984 
985  // Set the variables for kT-generation.
986  int nBeam = beamHad.size();
987  vector<double> kTwidth(nBeam);
988  vector<double> kTcomp(nBeam);
989  // Currently no MPI's for one-remnant systems.
990  int iSys = 0;
991  double kTcompSum = 0;
992  if (doPrimordialKT) {
993 
994  // Calculate the kT width from hard process.
995  int iInA = partonSystemsPtr->getInA(iSys);
996  int iInB = partonSystemsPtr->getInB(iSys);
997  double sHatNow = (event[iInA].p() + event[iInB].p()).m2Calc();
998  double mHat = sqrt(sHatNow);
999  double mHatDamp = mHat / (mHat + halfMassForKT);
1000  double scale = (iSys == 0) ? infoPtr->QRen(iDS)
1001  : partonSystemsPtr->getPTHat(iSys);
1002  kTwidth[0] = ( (halfScaleForKT * primordialKTsoft
1003  + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp;
1004  kTcomp[0] = mHatDamp;
1005  kTcompSum = mHatDamp + nBeam - 1.;
1006 
1007  // Calculate the kT width for remnant partons.
1008  for ( int iRem = 1; iRem < nBeam; ++iRem) {
1009  kTwidth[iRem] = primordialKTremnant;
1010  kTcomp[iRem] = 1.;
1011  }
1012 
1013  }
1014 
1015  // Allow ten tries to construct kinematics (but normally works first).
1016  bool isPhysical = true;
1017  double xSum, xInvM, w2Remn, wDiff;
1018  for (int iTry = 0; iTry < NTRYKINMATCH; ++iTry) {
1019  isPhysical = true;
1020 
1021  // Add primordial kT for one-remnant system.
1022  if (doPrimordialKT) {
1023 
1024  // Generate Gaussian pT for initiator partons inside hadron.
1025  double pxSum = 0.;
1026  double pySum = 0.;
1027  for (int iPar = 0; iPar < nBeam; ++iPar) {
1028  pair<double, double> gauss2 = rndmPtr->gauss2();
1029  double px = kTwidth[iPar] * gauss2.first;
1030  double py = kTwidth[iPar] * gauss2.second;
1031  beamHad[iPar].px(px);
1032  beamHad[iPar].py(py);
1033  pxSum += px;
1034  pySum += py;
1035  }
1036 
1037  // Share recoil between all initiator partons.
1038  for (int iPar = 0; iPar < nBeam; ++iPar) {
1039  beamHad[iPar].px( beamHad[iPar].px() - pxSum*kTcomp[iPar]/kTcompSum );
1040  beamHad[iPar].py( beamHad[iPar].py() - pySum*kTcomp[iPar]/kTcompSum );
1041  }
1042  }
1043 
1044  // Pick unrescaled x values for remnants. Sum up (unscaled) p+ and p-.
1045  xSum = 0.;
1046  xInvM = 0.;
1047  for (int iRem = 1; iRem < beamHad.size(); ++iRem) {
1048  double xPrel = beamHad.xRemnant( iRem);
1049  beamHad[iRem].x(xPrel);
1050  xSum += xPrel;
1051  xInvM += beamHad[iRem].mT2() / xPrel;
1052  }
1053 
1054  // Include the primordial kT for scattered system if any.
1055  double mT2Scat = w2Scat;
1056  if (doPrimordialKT) mT2Scat += pow2( beamHad[0].pT());
1057 
1058  // Squared transverse mass for remnant, may give failure.
1059  w2Remn = xSum * xInvM;
1060  wDiff = sqrt(w2Tot) - sqrtpos(mT2Scat) - sqrtpos(w2Remn);
1061  if (wDiff < 0.) isPhysical = false;
1062  if (isPhysical) break;
1063  }
1064 
1065  if (!isPhysical) {
1066  // Boost back event.
1067  MtoHadRest.invert();
1068  event.rotbst( MtoHadRest);
1069  infoPtr->errorMsg("Error in BeamRemnants::setOneRemnKinematics:"
1070  " too big beam remnant invariant mass");
1071  return false;
1072  }
1073 
1074  // Calculate kinematics for the scattered and remnant system with kT.
1075  if (doPrimordialKT) {
1076 
1077  int iInA = partonSystemsPtr->getInA(iSys);
1078  int iInB = partonSystemsPtr->getInB(iSys);
1079  int iInit = (iBeamHad == 1) ? iInA : iInB;
1080 
1081  // Beam momentum for boosts.
1082  Vec4 pBeam = beamOther.p();
1083 
1084  // Calculate the energy and pz of initiator with added kT.
1085  double w2 = (beamOther.p() + event[iInit].p()).m2Calc();
1086  double m2 = pow2(beamHad.m());
1087  double mT2 = pow2(beamHad[iSys].pT()) + m2;
1088  double eInitNew = beamOther.e()*mT2/(w2-m2) + 0.25*(w2-m2)/beamOther.e();
1089  double pzInitNew = beamOther.e()*mT2/(w2-m2) - 0.25*(w2-m2)/beamOther.e();
1090  if(iBeamHad == 1) pzInitNew *= -1.0;
1091  beamHad[iSys].pz( pzInitNew);
1092  beamHad[iSys].e( eInitNew);
1093 
1094  // Define the boost from event rest frame to frame where initiator
1095  // has some kT.
1096  RotBstMatrix MtoInitWithkT;
1097 
1098  // Find the rest frame of beam particle and initiator.
1099  if (iBeamHad == 1) {
1100  MtoInitWithkT.toCMframe( beamHad[iSys].p(), beamOther.p());
1101  } else {
1102  MtoInitWithkT.toCMframe( beamOther.p(), beamHad[iSys].p());
1103  }
1104 
1105  // Boost to frame where beam particle has its original momentum.
1106  pBeam.rotbst(MtoInitWithkT);
1107  MtoInitWithkT.bst( pBeam, beamOther.p());
1108 
1109  // Invert the boost.
1110  MtoInitWithkT.invert();
1111 
1112  // Add the initiator with kT to the event record.
1113  int iBeam = beamHad[iSys].iPos();
1114  int iCopy = event.copy(iBeam, -61);
1115  event[iCopy].rotbst(MtoInitWithkT);
1116  if (iBeamHad == 1) partonSystemsPtr->setInA(iSys, iCopy);
1117  else partonSystemsPtr->setInB(iSys, iCopy);
1118  beamHad[iSys].iPos( iCopy);
1119  if (iSys == 0) {
1120  int mother = event[iCopy].mother1();
1121  event[mother].daughter1(iCopy);
1122  }
1123 
1124  // Calculate transverse mass for scattered system with kT.
1125  w2Scat += pow2( beamHad[iSys].pT());
1126  }
1127 
1128  // Boost of scattered system to compensate for remnant mass.
1129  double lambda = pow2( w2Tot - w2Scat - w2Remn) - 4. * w2Scat * w2Remn;
1130  double pzNew = 0.5 * sqrt( lambda / w2Tot);
1131  // Keep the direction of momentum to ensure stable boost.
1132  if(iBeamHad == 1) pzNew *= -1.0;
1133  double eNewScat = 0.5 * (w2Tot + w2Scat - w2Remn) / sqrt(w2Tot);
1134  Vec4 pNewScat( beamHad[iSys].px(), beamHad[iSys].py(), pzNew, eNewScat);
1135  RotBstMatrix MforScat;
1136  MforScat.bst( pHadScat, pNewScat);
1137  int sizeSave = event.size();
1138  for (int i = 5 + beamOffset; i < sizeSave; ++i)
1139  if ( i != iLepScat && event[i].isFinal() ) {
1140  int iNew = event.copy( i, 62);
1141  event[iNew].rotbst( MforScat);
1142  }
1143 
1144  // Calculate kinematics of remnants and insert into event record.
1145  double eNewRemn = 0.5 * (w2Tot + w2Remn - w2Scat) / sqrt(w2Tot);
1146  double wNewRemn = eNewRemn + pzNew;
1147  for (int iRem = 1; iRem < beamHad.size(); ++iRem) {
1148  double wNegNow = wNewRemn * beamHad[iRem].x() / xSum;
1149  double wPosNow = beamHad[iRem].mT2() / wNegNow;
1150  beamHad[iRem].pz(-0.5 * (wNegNow - wPosNow));
1151  beamHad[iRem].e ( 0.5 * (wPosNow + wNegNow));
1152  int iNew = event.append( beamHad[iRem].id(), 63, iBeamHad + beamOffset,
1153  0, 0, 0, beamHad[iRem].col(), beamHad[iRem].acol(), beamHad[iRem].p(),
1154  beamHad[iRem].m() );
1155  beamHad[iRem].iPos( iNew);
1156  }
1157 
1158  // Boost back event.
1159  MtoHadRest.invert();
1160  event.rotbst( MtoHadRest);
1161 
1162  // Done.
1163  return true;
1164 }
1165 
1166 //--------------------------------------------------------------------------
1167 
1168 // Collapse colours and check that they are consistent.
1169 
1170 bool BeamRemnants::checkColours( Event& event) {
1171 
1172  // No colours in lepton beams so no need to do anything.
1173  if (beamAPtr->isLepton() && beamBPtr->isLepton()) return true;
1174 
1175  // Remove ambiguities when one colour collapses two ways.
1176  // Resolve chains where one colour is mapped to another.
1177  for (int iCol = 1; iCol < int(colFrom.size()); ++iCol)
1178  for (int iColRef = 0; iColRef < iCol; ++iColRef) {
1179  if (colFrom[iCol] == colFrom[iColRef]) {
1180  colFrom[iCol] = colTo[iCol];
1181  colTo[iCol] = colTo[iColRef];
1182  }
1183  if (colTo[iCol] == colFrom[iColRef]) colTo[iCol] = colTo[iColRef];
1184  }
1185 
1186  // Transform event record colours from beam remnant colour collapses.
1187  for (int i = oldSize; i < event.size(); ++i) {
1188  int col = event[i].col();
1189  int acol = event[i].acol();
1190  for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1191  if (col == colFrom[iCol]) {col = colTo[iCol]; event[i].col(col);}
1192  if (acol == colFrom[iCol]) {acol = colTo[iCol]; event[i].acol(acol);}
1193  // Sextets have extra, negative, tags.
1194  if (col == -colFrom[iCol]) {col = -colTo[iCol]; event[i].col(col);}
1195  if (acol == -colFrom[iCol]) {acol = -colTo[iCol]; event[i].acol(acol);}
1196  }
1197  }
1198 
1199  // Transform junction colours from beam remnant colour collapses.
1200  for (int iJun = 0; iJun < event.sizeJunction(); ++iJun)
1201  for (int leg = 0; leg < 3; ++leg) {
1202  int col = event.colJunction(iJun, leg);
1203  for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) {
1204  if (col == colFrom[iCol]) {
1205  col = colTo[iCol];
1206  event.colJunction(iJun, leg, col);
1207  }
1208  }
1209  }
1210 
1211  // Arrays for current colours and anticolours, and for singlet gluons.
1212  vector<int> colList;
1213  vector<int> acolList;
1214  vector<int> iSingletGluon;
1215 
1216  // Find current colours and anticolours in the event record.
1217  for (int i = oldSize; i < event.size(); ++i)
1218  if (event[i].isFinal()) {
1219  int id = event[i].id();
1220  int col = event[i].col();
1221  int acol = event[i].acol();
1222  int colType = event[i].colType();
1223 
1224  // Quarks must have colour set, antiquarks anticolour, gluons both.
1225  if ( (id > 0 && id < 9 && (col <= 0 || acol != 0) )
1226  || (id < 0 && id > -9 && (col != 0 || acol <= 0) )
1227  || (id == 21 && (col <= 0 || acol <= 0) ) ) {
1228  infoPtr->errorMsg("Error in BeamRemnants::checkColours: "
1229  "q/qbar/g has wrong colour slots set");
1230  return false;
1231  }
1232 
1233  // Sextets must have one positive and one negative tag
1234  if ( (colType == 3 && (col <= 0 || acol >= 0))
1235  || (colType == -3 && (col >= 0 || acol <= 0)) ) {
1236  infoPtr->errorMsg("Error in BeamRemnants::checkColours: "
1237  "sextet has wrong colours");
1238  }
1239 
1240  // Save colours/anticolours, and position of colour singlet gluons.
1241  if ( col > 0) colList.push_back( col );
1242  if (acol > 0) acolList.push_back( acol );
1243  if (col > 0 && acol == col) iSingletGluon.push_back(i);
1244  // Colour sextets
1245  if ( col < 0) acolList.push_back( -col );
1246  if (acol < 0) colList.push_back( -acol );
1247  }
1248 
1249  // Run through list of singlet gluons and put them on final-state dipole
1250  // (i,j) that offers smallest (p_g p_i) * (p_g p_j) / (p_i p_j).
1251  for (int iS = 0; iS < int(iSingletGluon.size()); ++iS) {
1252  int iGlu = iSingletGluon[iS];
1253  int iAcolDip = -1;
1254  double pT2DipMin = sCM;
1255  for (int iC = oldSize; iC < event.size(); ++iC)
1256  if (iC != iGlu && event[iC].isFinal()) {
1257  int colDip = event[iC].col();
1258  if (colDip > 0 && event[iC].acol() !=colDip)
1259  for (int iA = oldSize; iA < event.size(); ++iA)
1260  if (iA != iGlu && iA != iC && event[iA].isFinal()
1261  && event[iA].acol() == colDip && event[iA].col() !=colDip) {
1262  double pT2Dip = (event[iGlu].p() * event[iC].p())
1263  * (event[iGlu].p() * event[iA].p())
1264  / (event[iC].p() * event[iA].p());
1265  if (pT2Dip < pT2DipMin) {
1266  iAcolDip = iA;
1267  pT2DipMin = pT2Dip;
1268  }
1269  }
1270  }
1271 
1272  // Fail if no dipole. Else insert singlet gluon onto relevant dipole.
1273  if (iAcolDip == -1) return false;
1274  event[iGlu].acol( event[iAcolDip].acol() );
1275  event[iAcolDip].acol( event[iGlu].col() );
1276 
1277  // Update any junction legs that match reconnected dipole.
1278  for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) {
1279 
1280  // Only junctions need to be updated, not antijunctions.
1281  if (event.kindJunction(iJun) % 2 == 0) continue;
1282  for (int leg = 0; leg < 3; ++leg) {
1283  int col = event.colJunction(iJun, leg);
1284  if (col == event[iGlu].acol())
1285  event.colJunction(iJun, leg, event[iGlu].col());
1286  }
1287  }
1288 
1289  }
1290 
1291  // Check that not the same colour or anticolour appears twice.
1292  for (int iCol = 0; iCol < int(colList.size()) - 1; ++iCol) {
1293  int col = colList[iCol];
1294  for (int iCol2 = iCol + 1; iCol2 < int(colList.size()); ++iCol2)
1295  if (colList[iCol2] == col) {
1296  infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
1297  " colour appears twice");
1298  if (!ALLOWCOLOURTWICE) return false;
1299  }
1300  }
1301  for (int iAcol = 0; iAcol < int(acolList.size()) - 1; ++iAcol) {
1302  int acol = acolList[iAcol];
1303  for (int iAcol2 = iAcol + 1; iAcol2 < int(acolList.size()); ++iAcol2)
1304  if (acolList[iAcol2] == acol) {
1305  infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
1306  " anticolour appears twice");
1307  if (!ALLOWCOLOURTWICE) return false;
1308  }
1309  }
1310 
1311  // Remove all matching colour-anticolour pairs.
1312  bool foundPair = true;
1313  while (foundPair && colList.size() > 0 && acolList.size() > 0) {
1314  foundPair = false;
1315  for (int iCol = 0; iCol < int(colList.size()); ++iCol) {
1316  for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) {
1317  if (acolList[iAcol] == colList[iCol]) {
1318  colList[iCol] = colList.back(); colList.pop_back();
1319  acolList[iAcol] = acolList.back(); acolList.pop_back();
1320  foundPair = true;
1321  break;
1322  }
1323  }
1324  if (foundPair) break;
1325  }
1326  }
1327 
1328  // Check that remaining (anti)colours are accounted for by junctions.
1329  for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) {
1330  int kindJun = event.kindJunction(iJun);
1331  for (int leg = 0; leg < 3; ++leg) {
1332  int colEnd = event.colJunction(iJun, leg);
1333 
1334  // Junction connected to three colours.
1335  if (kindJun == 1) {
1336  for (int iCol = 0; iCol < int(colList.size()); ++iCol)
1337  if (colList[iCol] == colEnd) {
1338  // Found colour match: remove and exit.
1339  colList[iCol] = colList.back();
1340  colList.pop_back();
1341  break;
1342  }
1343  }
1344 
1345  // Junction connected to three anticolours.
1346  else if (kindJun == 2) {
1347  for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1348  if (acolList[iAcol] == colEnd) {
1349  // Found colour match: remove and exit.
1350  acolList[iAcol] = acolList.back();
1351  acolList.pop_back();
1352  break;
1353  }
1354  }
1355 
1356  // Other junction types
1357  else if ( kindJun == 3 || kindJun == 5) {
1358  for (int iCol = 0; iCol < int(colList.size()); ++iCol)
1359  if (colList[iCol] == colEnd) {
1360  // Found colour match: remove and exit.
1361  colList[iCol] = colList.back();
1362  colList.pop_back();
1363  break;
1364  }
1365  }
1366 
1367  // Other antijunction types
1368  else if ( kindJun == 4 || kindJun == 6) {
1369  for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol)
1370  if (acolList[iAcol] == colEnd) {
1371  // Found colour match: remove and exit.
1372  acolList[iAcol] = acolList.back();
1373  acolList.pop_back();
1374  break;
1375  }
1376  }
1377 
1378  // End junction check.
1379  }
1380  }
1381 
1382 
1383  // Repair step - sometimes needed when rescattering allowed.
1384  if (colList.size() > 0 || acolList.size() > 0) {
1385  infoPtr->errorMsg("Warning in BeamRemnants::checkColours:"
1386  " need to repair unmatched colours");
1387  }
1388  while (colList.size() > 0 && acolList.size() > 0) {
1389 
1390  // Replace one colour and one anticolour index by a new common one.
1391  int colMatch = colList.back();
1392  int acolMatch = acolList.back();
1393  int colNew = event.nextColTag();
1394  colList.pop_back();
1395  acolList.pop_back();
1396  for (int i = oldSize; i < event.size(); ++i) {
1397  if (event[i].isFinal() && event[i].col() == colMatch) {
1398  event[i].col( colNew);
1399  break;
1400  }
1401  else if (event[i].isFinal() && event[i].acol() == -colMatch) {
1402  event[i].acol( -colNew);
1403  break;
1404  }
1405  }
1406  for (int i = oldSize; i < event.size(); ++i) {
1407  if (event[i].isFinal() && event[i].acol() == acolMatch) {
1408  event[i].acol( colNew);
1409  break;
1410  }
1411  if (event[i].isFinal() && event[i].col() == -acolMatch) {
1412  event[i].col( -colNew);
1413  break;
1414  }
1415  }
1416  }
1417 
1418  // Done.
1419  return (colList.size() == 0 && acolList.size() == 0);
1420 
1421 }
1422 
1423 //--------------------------------------------------------------------------
1424 
1425 // Update colours of outgoing particles in the event record.
1426 
1427 void BeamRemnants::updateColEvent( Event& event,
1428  vector<pair <int,int> > colChanges) {
1429 
1430  for (int iCol = 0; iCol < int(colChanges.size()); ++iCol) {
1431 
1432  int oldCol = colChanges[iCol].first;
1433  int newCol = colChanges[iCol].second;
1434  if (oldCol == newCol)
1435  continue;
1436 
1437  // Add a copy of final particles with old colour and change the colour.
1438  for (int j = 0; j < event.size(); ++j) {
1439  if (event[j].isFinal() && event[j].col() == oldCol)
1440  event[event.copy(j, 64)].col(newCol);
1441  if (event[j].isFinal() && event[j].acol() == -oldCol)
1442  event[event.copy(j, 64)].acol(-newCol);
1443 
1444  if (event[j].isFinal() && event[j].acol() == oldCol)
1445  event[event.copy(j,64)].acol(newCol);
1446  if (event[j].isFinal() && event[j].col() == -oldCol)
1447  event[event.copy(j,64)].col(-newCol);
1448  }
1449 
1450  // Update junction.
1451  for (int j = 0;j < event.sizeJunction(); ++j)
1452  for (int jCol = 0; jCol < 3; ++jCol)
1453  if (event.colJunction(j,jCol) == oldCol)
1454  event.colJunction(j,jCol,newCol);
1455  }
1456 
1457 }
1458 
1459 //==========================================================================
1460 
1461 } // end namespace Pythia8
Definition: beam.h:43
Definition: AgUStep.h:26