StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ProcessLevel.cc
1 // ProcessLevel.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2014 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL version 2, 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 ProcessLevel class.
7 
8 #include "Pythia8/ProcessLevel.h"
9 
10 namespace Pythia8 {
11 
12 //==========================================================================
13 
14 // The ProcessLevel 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 // Allow a few failures in final construction of events.
22 const int ProcessLevel::MAXLOOP = 5;
23 
24 //--------------------------------------------------------------------------
25 
26 // Destructor.
27 
28 ProcessLevel::~ProcessLevel() {
29 
30  // Run through list of first hard processes and delete them.
31  for (int i = 0; i < int(containerPtrs.size()); ++i)
32  delete containerPtrs[i];
33 
34  // Run through list of second hard processes and delete them.
35  for (int i = 0; i < int(container2Ptrs.size()); ++i)
36  delete container2Ptrs[i];
37 
38 }
39 
40 //--------------------------------------------------------------------------
41 
42 // Main routine to initialize generation process.
43 
44 bool ProcessLevel::init( Info* infoPtrIn, Settings& settings,
45  ParticleData* particleDataPtrIn, Rndm* rndmPtrIn,
46  BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn,
47  Couplings* couplingsPtrIn, SigmaTotal* sigmaTotPtrIn, bool doLHA,
48  SLHAinterface* slhaInterfacePtrIn, UserHooks* userHooksPtrIn,
49  vector<SigmaProcess*>& sigmaPtrs, ostream& os) {
50 
51  // Store input pointers for future use.
52  infoPtr = infoPtrIn;
53  particleDataPtr = particleDataPtrIn;
54  rndmPtr = rndmPtrIn;
55  beamAPtr = beamAPtrIn;
56  beamBPtr = beamBPtrIn;
57  couplingsPtr = couplingsPtrIn;
58  sigmaTotPtr = sigmaTotPtrIn;
59  userHooksPtr = userHooksPtrIn;
60  slhaInterfacePtr = slhaInterfacePtrIn;
61 
62  // Send on some input pointers.
63  resonanceDecays.init( infoPtr, particleDataPtr, rndmPtr);
64 
65  // Set up SigmaTotal. Store sigma_nondiffractive for future use.
66  sigmaTotPtr->init( infoPtr, settings, particleDataPtr);
67  int idA = infoPtr->idA();
68  int idB = infoPtr->idB();
69  double eCM = infoPtr->eCM();
70  sigmaTotPtr->calc( idA, idB, eCM);
71  sigmaND = sigmaTotPtr->sigmaND();
72 
73  // Options to allow second hard interaction and resonance decays.
74  doSecondHard = settings.flag("SecondHard:generate");
75  doSameCuts = settings.flag("PhaseSpace:sameForSecond");
76  doResDecays = settings.flag("ProcessLevel:resonanceDecays");
77  startColTag = settings.mode("Event:startColTag");
78 
79  // Second interaction not to be combined with biased phase space.
80  if (doSecondHard && userHooksPtr != 0
81  && userHooksPtr->canBiasSelection()) {
82  infoPtr->errorMsg("Error in ProcessLevel::init: "
83  "cannot combine second interaction with biased phase space");
84  return false;
85  }
86 
87  // Mass and pT cuts for two hard processes.
88  mHatMin1 = settings.parm("PhaseSpace:mHatMin");
89  mHatMax1 = settings.parm("PhaseSpace:mHatMax");
90  if (mHatMax1 < mHatMin1) mHatMax1 = eCM;
91  pTHatMin1 = settings.parm("PhaseSpace:pTHatMin");
92  pTHatMax1 = settings.parm("PhaseSpace:pTHatMax");
93  if (pTHatMax1 < pTHatMin1) pTHatMax1 = eCM;
94  mHatMin2 = settings.parm("PhaseSpace:mHatMinSecond");
95  mHatMax2 = settings.parm("PhaseSpace:mHatMaxSecond");
96  if (mHatMax2 < mHatMin2) mHatMax2 = eCM;
97  pTHatMin2 = settings.parm("PhaseSpace:pTHatMinSecond");
98  pTHatMax2 = settings.parm("PhaseSpace:pTHatMaxSecond");
99  if (pTHatMax2 < pTHatMin2) pTHatMax2 = eCM;
100 
101  // Check whether mass and pT ranges agree or overlap.
102  cutsAgree = doSameCuts;
103  if (mHatMin2 == mHatMin1 && mHatMax2 == mHatMax1 && pTHatMin2 == pTHatMin1
104  && pTHatMax2 == pTHatMax1) cutsAgree = true;
105  cutsOverlap = cutsAgree;
106  if (!cutsAgree) {
107  bool mHatOverlap = (max( mHatMin1, mHatMin2)
108  < min( mHatMax1, mHatMax2));
109  bool pTHatOverlap = (max( pTHatMin1, pTHatMin2)
110  < min( pTHatMax1, pTHatMax2));
111  if (mHatOverlap && pTHatOverlap) cutsOverlap = true;
112  }
113 
114  // Set up containers for all the internal hard processes.
115  SetupContainers setupContainers;
116  setupContainers.init(containerPtrs, infoPtr, settings, particleDataPtr,
117  couplingsPtr);
118 
119  // Append containers for external hard processes, if any.
120  if (sigmaPtrs.size() > 0) {
121  for (int iSig = 0; iSig < int(sigmaPtrs.size()); ++iSig)
122  containerPtrs.push_back( new ProcessContainer(sigmaPtrs[iSig],
123  true) );
124  }
125 
126  // Append single container for Les Houches processes, if any.
127  if (doLHA) {
128  SigmaProcess* sigmaPtr = new SigmaLHAProcess();
129  containerPtrs.push_back( new ProcessContainer(sigmaPtr) );
130 
131  // Store location of this container, and send in LHA pointer.
132  iLHACont = containerPtrs.size() - 1;
133  containerPtrs[iLHACont]->setLHAPtr(lhaUpPtr);
134  }
135 
136  // If no processes found then refuse to do anything.
137  if ( int(containerPtrs.size()) == 0) {
138  infoPtr->errorMsg("Error in ProcessLevel::init: "
139  "no process switched on");
140  return false;
141  }
142 
143  // Check whether pT-based weighting in 2 -> 2 is requested.
144  if (settings.flag("PhaseSpace:bias2Selection")) {
145  bool bias2Sel = false;
146  if (sigmaPtrs.size() == 0 && !doLHA && !doSecondHard) {
147  bias2Sel = true;
148  for (int i = 0; i < int(containerPtrs.size()); ++i) {
149  if (containerPtrs[i]->nFinal() != 2) bias2Sel = false;
150  int code = containerPtrs[i]->code();
151  if (code > 100 && code < 110) bias2Sel = false;
152  }
153  }
154  if (!bias2Sel) {
155  infoPtr->errorMsg("Error in ProcessLevel::init: "
156  "requested event weighting not possible");
157  return false;
158  }
159  }
160 
161  // Check that SUSY couplings were indeed initialized where necessary.
162  bool hasSUSY = false;
163  for (int i = 0; i < int(containerPtrs.size()); ++i)
164  if (containerPtrs[i]->isSUSY()) hasSUSY = true;
165 
166  // If SUSY processes requested but no SUSY couplings present
167  if(hasSUSY && !couplingsPtr->isSUSY) {
168  infoPtr->errorMsg("Error in ProcessLevel::init: "
169  "SUSY process switched on but no SUSY couplings found");
170  return false;
171  }
172 
173  // Fill SLHA blocks SMINPUTS and MASS from PYTHIA SM parameter values.
174  slhaInterfacePtr->pythia2slha(particleDataPtr);
175 
176  // Initialize each process.
177  int numberOn = 0;
178  for (int i = 0; i < int(containerPtrs.size()); ++i)
179  if (containerPtrs[i]->init(true, infoPtr, settings, particleDataPtr,
180  rndmPtr, beamAPtr, beamBPtr, couplingsPtr, sigmaTotPtr,
181  &resonanceDecays, slhaInterfacePtr, userHooksPtr)) ++numberOn;
182 
183  // Sum maxima for Monte Carlo choice.
184  sigmaMaxSum = 0.;
185  for (int i = 0; i < int(containerPtrs.size()); ++i)
186  sigmaMaxSum += containerPtrs[i]->sigmaMax();
187 
188  // Option to pick a second hard interaction: repeat as above.
189  int number2On = 0;
190  if (doSecondHard) {
191  setupContainers.init2(container2Ptrs, settings);
192  if ( int(container2Ptrs.size()) == 0) {
193  infoPtr->errorMsg("Error in ProcessLevel::init: "
194  "no second hard process switched on");
195  return false;
196  }
197  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
198  if (container2Ptrs[i2]->init(false, infoPtr, settings, particleDataPtr,
199  rndmPtr, beamAPtr, beamBPtr, couplingsPtr, sigmaTotPtr,
200  &resonanceDecays, slhaInterfacePtr, userHooksPtr)) ++number2On;
201  sigma2MaxSum = 0.;
202  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
203  sigma2MaxSum += container2Ptrs[i2]->sigmaMax();
204  }
205 
206  // Printout during initialization is optional.
207  if (settings.flag("Init:showProcesses")) {
208 
209  // Construct string with incoming beams and for cm energy.
210  string collision = "We collide " + particleDataPtr->name(idA)
211  + " with " + particleDataPtr->name(idB) + " at a CM energy of ";
212  string pad( 51 - collision.length(), ' ');
213 
214  // Print initialization information: header.
215  os << "\n *------- PYTHIA Process Initialization ---------"
216  << "-----------------*\n"
217  << " | "
218  << " |\n"
219  << " | " << collision << scientific << setprecision(3)
220  << setw(9) << eCM << " GeV" << pad << " |\n"
221  << " | "
222  << " |\n"
223  << " |---------------------------------------------------"
224  << "---------------|\n"
225  << " | "
226  << " | |\n"
227  << " | Subprocess Code"
228  << " | Estimated |\n"
229  << " | "
230  << " | max (mb) |\n"
231  << " | "
232  << " | |\n"
233  << " |---------------------------------------------------"
234  << "---------------|\n"
235  << " | "
236  << " | |\n";
237 
238  // Loop over existing processes: print individual process info.
239  map<int, double> sigmaMaxM;
240  map<int, string> nameM;
241  for (int i = 0; i < int(containerPtrs.size()); ++i) {
242  int code = containerPtrs[i]->code();
243  nameM[code] = containerPtrs[i]->name();
244  sigmaMaxM[code] = containerPtrs[i]->sigmaMax() > sigmaMaxM[code] ?
245  containerPtrs[i]->sigmaMax() : sigmaMaxM[code];
246  }
247  for (map<int, string>::iterator i = nameM.begin(); i != nameM.end(); ++i)
248  os << " | " << left << setw(45) << i->second
249  << right << setw(5) << i->first << " | "
250  << scientific << setprecision(3) << setw(11)
251  << sigmaMaxM[i->first] << " |\n";
252 
253  // Loop over second hard processes, if any, and repeat as above.
254  if (doSecondHard) {
255  os << " | "
256  << " | |\n"
257  << " |---------------------------------------------------"
258  <<"---------------|\n"
259  << " | "
260  <<" | |\n";
261  sigmaMaxM.clear();
262  nameM.clear();
263  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) {
264  int code = container2Ptrs[i2]->code();
265  nameM[code] = container2Ptrs[i2]->name();
266  sigmaMaxM[code] = container2Ptrs[i2]->sigmaMax() > sigmaMaxM[code] ?
267  container2Ptrs[i2]->sigmaMax() : sigmaMaxM[code];
268  }
269  for (map<int, string>::iterator i2 = nameM.begin(); i2 != nameM.end();
270  ++i2)
271  os << " | " << left << setw(45) << i2->second
272  << right << setw(5) << i2->first << " | "
273  << scientific << setprecision(3) << setw(11)
274  << sigmaMaxM[i2->first] << " |\n";
275  }
276 
277  // Listing finished.
278  os << " | "
279  << " |\n"
280  << " *------- End PYTHIA Process Initialization ----------"
281  <<"-------------*" << endl;
282  }
283 
284  // If sum of maxima vanishes then refuse to do anything.
285  if ( numberOn == 0 || sigmaMaxSum <= 0.) {
286  infoPtr->errorMsg("Error in ProcessLevel::init: "
287  "all processes have vanishing cross sections");
288  return false;
289  }
290  if ( doSecondHard && (number2On == 0 || sigma2MaxSum <= 0.) ) {
291  infoPtr->errorMsg("Error in ProcessLevel::init: "
292  "all second hard processes have vanishing cross sections");
293  return false;
294  }
295 
296  // If two hard processes then check whether some (but not all) agree.
297  allHardSame = true;
298  noneHardSame = true;
299  if (doSecondHard) {
300  bool foundMatch = false;
301 
302  // Check for each first process if matched in second.
303  for (int i = 0; i < int(containerPtrs.size()); ++i) {
304  foundMatch = false;
305  if (cutsOverlap)
306  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
307  if (container2Ptrs[i2]->code() == containerPtrs[i]->code())
308  foundMatch = true;
309  containerPtrs[i]->isSame( foundMatch );
310  if (!foundMatch) allHardSame = false;
311  if ( foundMatch) noneHardSame = false;
312  }
313 
314  // Check for each second process if matched in first.
315  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) {
316  foundMatch = false;
317  if (cutsOverlap)
318  for (int i = 0; i < int(containerPtrs.size()); ++i)
319  if (containerPtrs[i]->code() == container2Ptrs[i2]->code())
320  foundMatch = true;
321  container2Ptrs[i2]->isSame( foundMatch );
322  if (!foundMatch) allHardSame = false;
323  if ( foundMatch) noneHardSame = false;
324  }
325  }
326 
327  // Concluding classification, including cuts.
328  if (!cutsAgree) allHardSame = false;
329  someHardSame = !allHardSame && !noneHardSame;
330 
331  // Reset counters for average impact-parameter enhancement.
332  nImpact = 0;
333  sumImpactFac = 0.;
334  sum2ImpactFac = 0.;
335 
336  // Done.
337  return true;
338 }
339 
340 //--------------------------------------------------------------------------
341 
342 // Main routine to generate the hard process.
343 
344 bool ProcessLevel::next( Event& process) {
345 
346  // Generate the next event with two or one hard interactions.
347  bool physical = (doSecondHard) ? nextTwo( process) : nextOne( process);
348 
349  // Check that colour assignments make sense.
350  if (physical) physical = checkColours( process);
351 
352  // Done.
353  return physical;
354 }
355 
356 //--------------------------------------------------------------------------
357 
358 // Generate (= read in) LHA input of resonance decay only.
359 
360 bool ProcessLevel::nextLHAdec( Event& process) {
361 
362  // Read resonance decays from LHA interface.
363  infoPtr->setEndOfFile(false);
364  if (!lhaUpPtr->setEvent()) {
365  infoPtr->setEndOfFile(true);
366  return false;
367  }
368 
369  // Store LHA output in standard event record format.
370  containerLHAdec.constructDecays( process);
371 
372  // Done.
373  return true;
374 }
375 
376 //--------------------------------------------------------------------------
377 
378 // Accumulate and update statistics (after possible user veto).
379 
380 void ProcessLevel::accumulate() {
381 
382  // Increase number of accepted events.
383  containerPtrs[iContainer]->accumulate();
384 
385  // Provide current generated cross section estimate.
386  long nTrySum = 0;
387  long nSelSum = 0;
388  long nAccSum = 0;
389  double sigmaSum = 0.;
390  double delta2Sum = 0.;
391  double sigSelSum = 0.;
392  double weightSum = 0.;
393  int codeNow;
394  long nTryNow, nSelNow, nAccNow;
395  double sigmaNow, deltaNow, sigSelNow, weightNow;
396  map<int, bool> duplicate;
397  for (int i = 0; i < int(containerPtrs.size()); ++i)
398  if (containerPtrs[i]->sigmaMax() != 0.) {
399  codeNow = containerPtrs[i]->code();
400  nTryNow = containerPtrs[i]->nTried();
401  nSelNow = containerPtrs[i]->nSelected();
402  nAccNow = containerPtrs[i]->nAccepted();
403  sigmaNow = containerPtrs[i]->sigmaMC();
404  deltaNow = containerPtrs[i]->deltaMC();
405  sigSelNow = containerPtrs[i]->sigmaSelMC();
406  weightNow = containerPtrs[i]->weightSum();
407  nTrySum += nTryNow;
408  nSelSum += nSelNow;
409  nAccSum += nAccNow;
410  sigmaSum += sigmaNow;
411  delta2Sum += pow2(deltaNow);
412  sigSelSum += sigSelNow;
413  weightSum += weightNow;
414  if (!doSecondHard) {
415  if (!duplicate[codeNow])
416  infoPtr->setSigma( codeNow, containerPtrs[i]->name(),
417  nTryNow, nSelNow, nAccNow, sigmaNow, deltaNow, weightNow);
418  else
419  infoPtr->addSigma( codeNow, nTryNow, nSelNow, nAccNow, sigmaNow,
420  deltaNow);
421  duplicate[codeNow] = true;
422  }
423  }
424 
425  // Normally only one hard interaction. Then store info and done.
426  if (!doSecondHard) {
427  double deltaSum = sqrtpos(delta2Sum);
428  infoPtr->setSigma( 0, "sum", nTrySum, nSelSum, nAccSum, sigmaSum, deltaSum,
429  weightSum);
430  return;
431  }
432 
433  // Increase counter for a second hard interaction.
434  container2Ptrs[i2Container]->accumulate();
435 
436  // Update statistics on average impact factor.
437  ++nImpact;
438  sumImpactFac += infoPtr->enhanceMPI();
439  sum2ImpactFac += pow2(infoPtr->enhanceMPI());
440 
441  // Cross section estimate for second hard process.
442  double sigma2Sum = 0.;
443  double sig2SelSum = 0.;
444  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
445  if (container2Ptrs[i2]->sigmaMax() != 0.) {
446  nTrySum += container2Ptrs[i2]->nTried();
447  sigma2Sum += container2Ptrs[i2]->sigmaMC();
448  sig2SelSum += container2Ptrs[i2]->sigmaSelMC();
449  }
450 
451  // Average impact-parameter factor and error.
452  double invN = 1. / max(1, nImpact);
453  double impactFac = max( 1., sumImpactFac * invN);
454  double impactErr2 = ( sum2ImpactFac * invN / pow2(impactFac) - 1.) * invN;
455 
456  // Cross section estimate for combination of first and second process.
457  // Combine two possible ways and take average.
458  double sigmaComb = 0.5 * (sigmaSum * sig2SelSum + sigSelSum * sigma2Sum);
459  sigmaComb *= impactFac / sigmaND;
460  if (allHardSame) sigmaComb *= 0.5;
461  double deltaComb = sqrtpos(2. / nAccSum + impactErr2) * sigmaComb;
462 
463  // Store info and done.
464  infoPtr->setSigma( 0, "sum", nTrySum, nSelSum, nAccSum, sigmaComb, deltaComb,
465  weightSum);
466 
467 }
468 
469 //--------------------------------------------------------------------------
470 
471 // Print statistics on cross sections and number of events.
472 
473 void ProcessLevel::statistics(bool reset, ostream& os) {
474 
475  // Special processing if two hard interactions selected.
476  if (doSecondHard) {
477  statistics2(reset, os);
478  return;
479  }
480 
481  // Header.
482  os << "\n *------- PYTHIA Event and Cross Section Statistics ------"
483  << "-------------------------------------------------------*\n"
484  << " | "
485  << " |\n"
486  << " | Subprocess Code | "
487  << " Number of events | sigma +- delta |\n"
488  << " | | "
489  << "Tried Selected Accepted | (estimated) (mb) |\n"
490  << " | | "
491  << " | |\n"
492  << " |------------------------------------------------------------"
493  << "-----------------------------------------------------|\n"
494  << " | | "
495  << " | |\n";
496 
497  // Reset sum counters.
498  long nTrySum = 0;
499  long nSelSum = 0;
500  long nAccSum = 0;
501  double sigmaSum = 0.;
502  double delta2Sum = 0.;
503 
504  // Reset process maps.
505  map<int, string> nameM;
506  map<int, long> nTryM, nSelM, nAccM;
507  map<int, double> sigmaM, delta2M;
508  vector<ProcessContainer*> lheContainerPtrs;
509 
510  // Loop over existing processes.
511  for (int i = 0; i < int(containerPtrs.size()); ++i)
512  if (containerPtrs[i]->sigmaMax() != 0.) {
513 
514  // Read info for process. Sum counters.
515  nTrySum += containerPtrs[i]->nTried();
516  nSelSum += containerPtrs[i]->nSelected();
517  nAccSum += containerPtrs[i]->nAccepted();
518  sigmaSum += containerPtrs[i]->sigmaMC();
519  delta2Sum += pow2(containerPtrs[i]->deltaMC());
520 
521  // Skip Les Houches containers.
522  if (containerPtrs[i]->code() == 9999) {
523  lheContainerPtrs.push_back(containerPtrs[i]);
524  continue;
525  }
526 
527  // Internal process info.
528  int code = containerPtrs[i]->code();
529  nameM[code] = containerPtrs[i]->name();
530  nTryM[code] += containerPtrs[i]->nTried();
531  nSelM[code] += containerPtrs[i]->nSelected();
532  nAccM[code] += containerPtrs[i]->nAccepted();
533  sigmaM[code] += containerPtrs[i]->sigmaMC();
534  delta2M[code]+= pow2(containerPtrs[i]->deltaMC());
535  }
536 
537  // Print internal process info.
538  for (map<int, string>::iterator i = nameM.begin(); i != nameM.end(); ++i) {
539  int code = i->first;
540  os << " | " << left << setw(45) << i->second
541  << right << setw(5) << code << " | "
542  << setw(11) << nTryM[code] << " " << setw(10) << nSelM[code] << " "
543  << setw(10) << nAccM[code] << " | " << scientific << setprecision(3)
544  << setw(11) << sigmaM[code]
545  << setw(11) << sqrtpos(delta2M[code]) << " |\n";
546  }
547 
548  // Print Les Houches process info.
549  for (int i = 0; i < int(lheContainerPtrs.size()); ++i) {
550  ProcessContainer *ptr = lheContainerPtrs[i];
551  os << " | " << left << setw(45) << ptr->name()
552  << right << setw(5) << ptr->code() << " | "
553  << setw(11) << ptr->nTried() << " " << setw(10) << ptr->nSelected()
554  << " " << setw(10) << ptr->nAccepted() << " | " << scientific
555  << setprecision(3) << setw(11) << ptr->sigmaMC() << setw(11)
556  << ptr->deltaMC() << " |\n";
557 
558  // Print subdivision by user code for Les Houches process.
559  for (int j = 0; j < ptr->codeLHASize(); ++j)
560  os << " | ... whereof user classification code " << setw(10)
561  << ptr->subCodeLHA(j) << " | " << setw(11) << ptr->nTriedLHA(j)
562  << " " << setw(10) << ptr->nSelectedLHA(j) << " " << setw(10)
563  << ptr->nAcceptedLHA(j) << " | | \n";
564  }
565 
566  // Print summed process info.
567  os << " | | "
568  << " | |\n"
569  << " | " << left << setw(50) << "sum" << right << " | " << setw(11)
570  << nTrySum << " " << setw(10) << nSelSum << " " << setw(10)
571  << nAccSum << " | " << scientific << setprecision(3) << setw(11)
572  << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n";
573 
574  // Listing finished.
575  os << " | "
576  << " |\n"
577  << " *------- End PYTHIA Event and Cross Section Statistics -----"
578  << "-----------------------------------------------------*" << endl;
579 
580  // Optionally reset statistics contants.
581  if (reset) resetStatistics();
582 
583 }
584 
585 //--------------------------------------------------------------------------
586 
587 // Reset statistics on cross sections and number of events.
588 
589 void ProcessLevel::resetStatistics() {
590 
591  for (int i = 0; i < int(containerPtrs.size()); ++i)
592  containerPtrs[i]->reset();
593  if (doSecondHard)
594  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
595  container2Ptrs[i2]->reset();
596 
597 }
598 
599 //--------------------------------------------------------------------------
600 
601 // Generate the next event with one interaction.
602 
603 bool ProcessLevel::nextOne( Event& process) {
604 
605  // Update CM energy for phase space selection.
606  double eCM = infoPtr->eCM();
607  for (int i = 0; i < int(containerPtrs.size()); ++i)
608  containerPtrs[i]->newECM(eCM);
609 
610  // Outer loop in case of rare failures.
611  bool physical = true;
612  for (int loop = 0; loop < MAXLOOP; ++loop) {
613  if (!physical) process.clear();
614  physical = true;
615 
616  // Loop over tries until trial event succeeds.
617  for ( ; ; ) {
618 
619  // Pick one of the subprocesses.
620  double sigmaMaxNow = sigmaMaxSum * rndmPtr->flat();
621  int iMax = containerPtrs.size() - 1;
622  iContainer = -1;
623  do sigmaMaxNow -= containerPtrs[++iContainer]->sigmaMax();
624  while (sigmaMaxNow > 0. && iContainer < iMax);
625 
626  // Do a trial event of this subprocess; accept or not.
627  if (containerPtrs[iContainer]->trialProcess()) break;
628 
629  // Check for end-of-file condition for Les Houches events.
630  if (infoPtr->atEndOfFile()) return false;
631  }
632 
633  // Update sum of maxima if current maximum violated.
634  if (containerPtrs[iContainer]->newSigmaMax()) {
635  sigmaMaxSum = 0.;
636  for (int i = 0; i < int(containerPtrs.size()); ++i)
637  sigmaMaxSum += containerPtrs[i]->sigmaMax();
638  }
639 
640  // Construct kinematics of acceptable process.
641  containerPtrs[iContainer]->constructState();
642  if ( !containerPtrs[iContainer]->constructProcess( process) )
643  physical = false;
644 
645  // Do all resonance decays.
646  if ( physical && doResDecays
647  && !containerPtrs[iContainer]->decayResonances( process) )
648  physical = false;
649 
650  // Add any junctions to the process event record list.
651  if (physical) findJunctions( process);
652 
653  // Outer loop should normally work first time around.
654  if (physical) break;
655  }
656 
657  // Done.
658  return physical;
659 }
660 
661 //--------------------------------------------------------------------------
662 
663 // Generate the next event with two hard interactions.
664 
665 bool ProcessLevel::nextTwo( Event& process) {
666 
667  // Update CM energy for phase space selection.
668  double eCM = infoPtr->eCM();
669  for (int i = 0; i < int(containerPtrs.size()); ++i)
670  containerPtrs[i]->newECM(eCM);
671  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
672  container2Ptrs[i2]->newECM(eCM);
673 
674  // Outer loop in case of rare failures.
675  bool physical = true;
676  for (int loop = 0; loop < MAXLOOP; ++loop) {
677  if (!physical) process.clear();
678  physical = true;
679 
680  // Loop over both hard processes to find consistent common kinematics.
681  for ( ; ; ) {
682 
683  // Loop internally over tries for hardest process until succeeds.
684  for ( ; ; ) {
685 
686  // Pick one of the subprocesses.
687  double sigmaMaxNow = sigmaMaxSum * rndmPtr->flat();
688  int iMax = containerPtrs.size() - 1;
689  iContainer = -1;
690  do sigmaMaxNow -= containerPtrs[++iContainer]->sigmaMax();
691  while (sigmaMaxNow > 0. && iContainer < iMax);
692 
693  // Do a trial event of this subprocess; accept or not.
694  if (containerPtrs[iContainer]->trialProcess()) break;
695 
696  // Check for end-of-file condition for Les Houches events.
697  if (infoPtr->atEndOfFile()) return false;
698  }
699 
700  // Update sum of maxima if current maximum violated.
701  if (containerPtrs[iContainer]->newSigmaMax()) {
702  sigmaMaxSum = 0.;
703  for (int i = 0; i < int(containerPtrs.size()); ++i)
704  sigmaMaxSum += containerPtrs[i]->sigmaMax();
705  }
706 
707  // Loop internally over tries for second hardest process until succeeds.
708  for ( ; ; ) {
709 
710  // Pick one of the subprocesses.
711  double sigma2MaxNow = sigma2MaxSum * rndmPtr->flat();
712  int i2Max = container2Ptrs.size() - 1;
713  i2Container = -1;
714  do sigma2MaxNow -= container2Ptrs[++i2Container]->sigmaMax();
715  while (sigma2MaxNow > 0. && i2Container < i2Max);
716 
717  // Do a trial event of this subprocess; accept or not.
718  if (container2Ptrs[i2Container]->trialProcess()) break;
719  }
720 
721  // Update sum of maxima if current maximum violated.
722  if (container2Ptrs[i2Container]->newSigmaMax()) {
723  sigma2MaxSum = 0.;
724  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
725  sigma2MaxSum += container2Ptrs[i2]->sigmaMax();
726  }
727 
728  // Pick incoming flavours (etc), needed for PDF reweighting.
729  containerPtrs[iContainer]->constructState();
730  container2Ptrs[i2Container]->constructState();
731 
732  // Check whether common set of x values is kinematically possible.
733  double xA1 = containerPtrs[iContainer]->x1();
734  double xB1 = containerPtrs[iContainer]->x2();
735  double xA2 = container2Ptrs[i2Container]->x1();
736  double xB2 = container2Ptrs[i2Container]->x2();
737  if (xA1 + xA2 >= 1. || xB1 + xB2 >= 1.) continue;
738 
739  // Reset beam contents. Naive parton densities for second interaction.
740  // (Subsequent procedure could be symmetrized, but would be overkill.)
741  beamAPtr->clear();
742  beamBPtr->clear();
743  int idA1 = containerPtrs[iContainer]->id1();
744  int idB1 = containerPtrs[iContainer]->id2();
745  int idA2 = container2Ptrs[i2Container]->id1();
746  int idB2 = container2Ptrs[i2Container]->id2();
747  double Q2Fac1 = containerPtrs[iContainer]->Q2Fac();
748  double Q2Fac2 = container2Ptrs[i2Container]->Q2Fac();
749  double pdfA2Raw = beamAPtr->xf( idA2, xA2,Q2Fac2);
750  double pdfB2Raw = beamBPtr->xf( idB2, xB2,Q2Fac2);
751 
752  // Remove partons in first interaction from beams.
753  beamAPtr->append( 3, idA1, xA1);
754  beamAPtr->xfISR( 0, idA1, xA1, Q2Fac1);
755  beamAPtr->pickValSeaComp();
756  beamBPtr->append( 4, idB1, xB1);
757  beamBPtr->xfISR( 0, idB1, xB1, Q2Fac1);
758  beamBPtr->pickValSeaComp();
759 
760  // Reevaluate pdf's for second interaction and weight by reduction.
761  double pdfA2Mod = beamAPtr->xfMPI( idA2, xA2,Q2Fac2);
762  double pdfB2Mod = beamBPtr->xfMPI( idB2, xB2,Q2Fac2);
763  double wtPdfMod = (pdfA2Mod * pdfB2Mod) / (pdfA2Raw * pdfB2Raw);
764  if (wtPdfMod < rndmPtr->flat()) continue;
765 
766  // Reduce by a factor of 2 for identical processes when others not,
767  // and when in same phase space region.
768  bool toLoop = false;
769  if ( someHardSame && containerPtrs[iContainer]->isSame()
770  && container2Ptrs[i2Container]->isSame()) {
771  if (cutsAgree) {
772  if (rndmPtr->flat() > 0.5) toLoop = true;
773  } else {
774  double mHat1 = containerPtrs[iContainer]->mHat();
775  double pTHat1 = containerPtrs[iContainer]->pTHat();
776  double mHat2 = container2Ptrs[i2Container]->mHat();
777  double pTHat2 = container2Ptrs[i2Container]->pTHat();
778  if (mHat1 > mHatMin2 && mHat1 < mHatMax2
779  && pTHat1 > pTHatMin2 && pTHat1 < pTHatMax2
780  && mHat2 > mHatMin1 && mHat2 < mHatMax1
781  && pTHat2 > pTHatMin1 && pTHat2 < pTHatMax1
782  && rndmPtr->flat() > 0.5) toLoop = true;
783  }
784  }
785  if (toLoop) continue;
786 
787  // If come this far then acceptable event.
788  break;
789  }
790 
791  // Construct kinematics of acceptable processes.
792  Event process2;
793  process2.init( "(second hard)", particleDataPtr, startColTag);
794  process2.initColTag();
795  if ( !containerPtrs[iContainer]->constructProcess( process) )
796  physical = false;
797  if (physical && !container2Ptrs[i2Container]->constructProcess( process2,
798  false) ) physical = false;
799 
800  // Do all resonance decays.
801  if ( physical && doResDecays
802  && !containerPtrs[iContainer]->decayResonances( process) )
803  physical = false;
804  if ( physical && doResDecays
805  && !container2Ptrs[i2Container]->decayResonances( process2) )
806  physical = false;
807 
808  // Append second hard interaction to normal process object.
809  if (physical) combineProcessRecords( process, process2);
810 
811  // Add any junctions to the process event record list.
812  if (physical) findJunctions( process);
813 
814  // Outer loop should normally work first time around.
815  if (physical) break;
816  }
817 
818  // Done.
819  return physical;
820 }
821 
822 //--------------------------------------------------------------------------
823 
824 // Append second hard interaction to normal process object.
825 // Complication: all resonance decay chains must be put at the end.
826 
827 void ProcessLevel::combineProcessRecords( Event& process, Event& process2) {
828 
829  // Find first event record size, excluding resonances.
830  int nSize = process.size();
831  int nHard = 5;
832  while (nHard < nSize && process[nHard].mother1() == 3) ++nHard;
833 
834  // Save resonance products temporarily elsewhere.
835  vector<Particle> resProd;
836  if (nSize > nHard) {
837  for (int i = nHard; i < nSize; ++i) resProd.push_back( process[i] );
838  process.popBack(nSize - nHard);
839  }
840 
841  // Find second event record size, excluding resonances.
842  int nSize2 = process2.size();
843  int nHard2 = 5;
844  while (nHard2 < nSize2 && process2[nHard2].mother1() == 3) ++nHard2;
845 
846  // Find amount of necessary position and colour offset for second process.
847  int addPos = nHard - 3;
848  int addCol = process.lastColTag() - startColTag;
849 
850  // Loop over all particles (except beams) from second process.
851  for (int i = 3; i < nSize2; ++i) {
852 
853  // Offset mother and daughter pointers and colour tags of particle.
854  process2[i].offsetHistory( 2, addPos, 2, addPos);
855  process2[i].offsetCol( addCol);
856 
857  // Append hard-process particles from process2 to process.
858  if (i < nHard2) process.append( process2[i] );
859  }
860 
861  // Reinsert resonance decay chains of first hard process.
862  int addPos2 = nHard2 - 3;
863  if (nHard < nSize) {
864 
865  // Offset daughter pointers of unmoved mothers.
866  for (int i = 5; i < nHard; ++i)
867  process[i].offsetHistory( 0, 0, nHard - 1, addPos2);
868 
869  // Modify history of resonance products when restoring.
870  for (int i = 0; i < int(resProd.size()); ++i) {
871  resProd[i].offsetHistory( nHard - 1, addPos2, nHard - 1, addPos2);
872  process.append( resProd[i] );
873  }
874  }
875 
876  // Insert resonance decay chains of second hard process.
877  if (nHard2 < nSize2) {
878  int nHard3 = nHard + nHard2 - 3;
879  int addPos3 = nSize - nHard;
880 
881  // Offset daughter pointers of second-process mothers.
882  for (int i = nHard + 2; i < nHard3; ++i)
883  process[i].offsetHistory( 0, 0, nHard3 - 1, addPos3);
884 
885  // Modify history of second-process resonance products and insert.
886  for (int i = nHard2; i < nSize2; ++i) {
887  process2[i].offsetHistory( nHard3 - 1, addPos3, nHard3 - 1, addPos3);
888  process.append( process2[i] );
889  }
890  }
891 
892  // Store PDF scale for second interaction.
893  process.scaleSecond( process2.scale() );
894 
895 }
896 
897 //--------------------------------------------------------------------------
898 
899 // Add any junctions to the process event record list.
900 // Also check that do not doublebook if called repeatedly.
901 
902 void ProcessLevel::findJunctions( Event& junEvent) {
903 
904  // Check all hard vertices for BNV
905  for (int i = 1; i<junEvent.size(); i++) {
906 
907  // Ignore colorless particles and stages before hard-scattering
908  // final state.
909  if (abs(junEvent[i].status()) <= 21 || junEvent[i].colType() == 0)
910  continue;
911  vector<int> motherList = junEvent.motherList(i);
912  int iMot1 = motherList[0];
913  vector<int> sisterList = junEvent.daughterList(iMot1);
914 
915  // Check baryon number of vertex.
916  int barSum = 0;
917  map<int,int> colVertex, acolVertex;
918 
919  // Loop over mothers (enter with crossed colors and negative sign).
920  for (unsigned int indx = 0; indx < motherList.size(); indx++) {
921  int iMot = motherList[indx];
922  if ( abs(junEvent[iMot].colType()) == 1 )
923  barSum -= junEvent[iMot].colType();
924  else if ( abs(junEvent[iMot].colType()) == 3)
925  barSum -= 2*junEvent[iMot].colType()/3;
926  int col = junEvent[iMot].acol();
927  int acol = junEvent[iMot].col();
928 
929  // If unmatched (so far), add end. Else erase matching parton.
930  if (col > 0) {
931  if (acolVertex.find(col) == acolVertex.end() ) colVertex[col] = iMot;
932  else acolVertex.erase(col);
933  } else if (col < 0) {
934  if (colVertex.find(-col) == colVertex.end() ) acolVertex[-col] = iMot;
935  else colVertex.erase(-col);
936  }
937  if (acol > 0) {
938  if (colVertex.find(acol) == colVertex.end()) acolVertex[acol] = iMot;
939  else colVertex.erase(acol);
940  } else if (acol < 0) {
941  if (acolVertex.find(-acol) == acolVertex.end())
942  colVertex[-acol] = iMot;
943  else acolVertex.erase(-acol);
944  }
945  }
946 
947  // Loop over sisters.
948  for (unsigned int indx = 0; indx < sisterList.size(); indx++) {
949  int iDau = sisterList[indx];
950  if ( abs(junEvent[iDau].colType()) == 1 )
951  barSum += junEvent[iDau].colType();
952  else if ( abs(junEvent[iDau].colType()) == 3)
953  barSum += 2*junEvent[iDau].colType()/3;
954  int col = junEvent[iDau].col();
955  int acol = junEvent[iDau].acol();
956 
957  // If unmatched (so far), add end. Else erase matching parton.
958  if (col > 0) {
959  if (acolVertex.find(col) == acolVertex.end() ) colVertex[col] = iDau;
960  else acolVertex.erase(col);
961  } else if (col < 0) {
962  if (colVertex.find(-col) == colVertex.end() ) acolVertex[-col] = iDau;
963  else colVertex.erase(-col);
964  }
965  if (acol > 0) {
966  if (colVertex.find(acol) == colVertex.end()) acolVertex[acol] = iDau;
967  else colVertex.erase(acol);
968  } else if (acol < 0) {
969  if (acolVertex.find(-acol) == acolVertex.end())
970  colVertex[-acol] = iDau;
971  else acolVertex.erase(-acol);
972  }
973 
974  }
975 
976  // Skip if baryon number conserved in this vertex.
977  if (barSum == 0) continue;
978 
979  // Check and skip any junctions that have already been added.
980  for (int iJun = 0; iJun < junEvent.sizeJunction(); ++iJun) {
981  // Remove the tags corresponding to each of the 3 existing junction legs.
982  for (int j = 0; j < 3; ++j) {
983  int colNow = junEvent.colJunction(iJun, j);
984  if (junEvent.kindJunction(iJun) % 2 == 1) colVertex.erase(colNow);
985  else acolVertex.erase(colNow);
986  }
987  }
988 
989  // Skip if no junction colors remain.
990  if (colVertex.size() == 0 && acolVertex.size() == 0) continue;
991 
992  // If baryon number violated, is B = +1 or -1 (larger values not handled).
993  int kindJun = 0;
994  if (colVertex.size() == 3 && acolVertex.size() == 0) kindJun = 1;
995  else if (colVertex.size() == 0 && acolVertex.size() == 3) kindJun = 2;
996  else {
997  infoPtr->errorMsg("Error in ProcessLevel::findJunctions: "
998  "N(unmatched (anti)colour tags) != 3");
999  return;
1000  }
1001 
1002  // From now on, use colJun as shorthand for colVertex or acolVertex.
1003  map<int,int> colJun = (kindJun == 1) ? colVertex : acolVertex;
1004 
1005  // Order so incoming tags appear first in colVec, outgoing tags last.
1006  vector<int> colVec;
1007  for (map<int,int>::iterator it = colJun.begin();
1008  it != colJun.end(); it++) {
1009  int col = it->first;
1010  int iCol = it->second;
1011  for (unsigned int indx = 0; indx < motherList.size(); indx++) {
1012  if (iCol == motherList[indx]) {
1013  kindJun += 2;
1014  colVec.insert(colVec.begin(),col);
1015  }
1016  }
1017  if (colVec.size() == 0 || colVec[0] != col) colVec.push_back(col);
1018  }
1019 
1020  // Add junction with these tags.
1021  junEvent.appendJunction( kindJun, colVec[0], colVec[1], colVec[2]);
1022 
1023  }
1024 
1025 }
1026 //--------------------------------------------------------------------------
1027 
1028 // Check that colours match up.
1029 
1030 bool ProcessLevel::checkColours( Event& process) {
1031 
1032  // Variables and arrays for common usage.
1033  bool physical = true;
1034  bool match;
1035  int colType, col, acol, iPos, iNow, iNowA;
1036  vector<int> colTags, colPos, acolPos;
1037 
1038  // Check that each particle has the kind of colours expected of it.
1039  for (int i = 0; i < process.size(); ++i) {
1040  colType = process[i].colType();
1041  col = process[i].col();
1042  acol = process[i].acol();
1043  if (colType == 0 && (col != 0 || acol != 0)) physical = false;
1044  else if (colType == 1 && (col <= 0 || acol != 0)) physical = false;
1045  else if (colType == -1 && (col != 0 || acol <= 0)) physical = false;
1046  else if (colType == 2 && (col <= 0 || acol <= 0)) physical = false;
1047  // Preparations for colour-sextet assignments
1048  // (colour,colour) = (colour,negative anticolour)
1049  else if (colType == 3 && (col <= 0 || acol >= 0)) physical = false;
1050  else if (colType == -3 && (col >= 0 || acol <= 0)) physical = false;
1051  // All other cases
1052  else if (colType < -1 || colType > 3) physical = false;
1053 
1054  // Add to the list of colour tags.
1055  if (col > 0) {
1056  match = false;
1057  for (int ic = 0; ic < int(colTags.size()) ; ++ic)
1058  if (col == colTags[ic]) match = true;
1059  if (!match) colTags.push_back(col);
1060  } else if (acol > 0) {
1061  match = false;
1062  for (int ic = 0; ic < int(colTags.size()) ; ++ic)
1063  if (acol == colTags[ic]) match = true;
1064  if (!match) colTags.push_back(acol);
1065  }
1066  // Colour sextets : map negative colour -> anticolour and vice versa
1067  else if (col < 0) {
1068  match = false;
1069  for (int ic = 0; ic < int(colTags.size()) ; ++ic)
1070  if (-col == colTags[ic]) match = true;
1071  if (!match) colTags.push_back(-col);
1072  } else if (acol < 0) {
1073  match = false;
1074  for (int ic = 0; ic < int(colTags.size()) ; ++ic)
1075  if (-acol == colTags[ic]) match = true;
1076  if (!match) colTags.push_back(-acol);
1077  }
1078  }
1079 
1080  // Warn and give up if particles did not have the expected colours.
1081  if (!physical) {
1082  infoPtr->errorMsg("Error in ProcessLevel::checkColours: "
1083  "incorrect colour assignment");
1084  return false;
1085  }
1086 
1087  // Remove (anti)colours coming from an (anti)junction.
1088  for (int iJun = 0; iJun < process.sizeJunction(); ++iJun) {
1089  for (int j = 0; j < 3; ++j) {
1090  int colJun = process.colJunction(iJun, j);
1091  for (int ic = 0; ic < int(colTags.size()) ; ++ic)
1092  if (colJun == colTags[ic]) {
1093  colTags[ic] = colTags[colTags.size() - 1];
1094  colTags.pop_back();
1095  break;
1096  }
1097  }
1098  }
1099 
1100  // Loop through all colour tags and find their positions (by sign).
1101  for (int ic = 0; ic < int(colTags.size()); ++ic) {
1102  col = colTags[ic];
1103  colPos.resize(0);
1104  acolPos.resize(0);
1105  for (int i = 0; i < process.size(); ++i) {
1106  if (process[i].col() == col || process[i].acol() == -col)
1107  colPos.push_back(i);
1108  if (process[i].acol() == col || process[i].col() == -col)
1109  acolPos.push_back(i);
1110  }
1111 
1112  // Trace colours back through decays; remove daughters.
1113  while (colPos.size() > 1) {
1114  iPos = colPos.size() - 1;
1115  iNow = colPos[iPos];
1116  if ( process[iNow].mother1() == colPos[iPos - 1]
1117  && process[iNow].mother2() == 0) colPos.pop_back();
1118  else break;
1119  }
1120  while (acolPos.size() > 1) {
1121  iPos = acolPos.size() - 1;
1122  iNow = acolPos[iPos];
1123  if ( process[iNow].mother1() == acolPos[iPos - 1]
1124  && process[iNow].mother2() == 0) acolPos.pop_back();
1125  else break;
1126  }
1127 
1128  // Now colour should exist in only 2 copies.
1129  if (colPos.size() + acolPos.size() != 2) physical = false;
1130 
1131  // If both colours or both anticolours then one mother of the other.
1132  else if (colPos.size() == 2) {
1133  iNow = colPos[1];
1134  if ( process[iNow].mother1() != colPos[0]
1135  && process[iNow].mother2() != colPos[0] ) physical = false;
1136  }
1137  else if (acolPos.size() == 2) {
1138  iNowA = acolPos[1];
1139  if ( process[iNowA].mother1() != acolPos[0]
1140  && process[iNowA].mother2() != acolPos[0] ) physical = false;
1141  }
1142 
1143  // If one of each then should have same mother(s), or point to beams.
1144  else {
1145  iNow = colPos[0];
1146  iNowA = acolPos[0];
1147  if ( process[iNow].status() == -21 && process[iNowA].status() == -21 );
1148  else if ( (process[iNow].mother1() != process[iNowA].mother1())
1149  || (process[iNow].mother2() != process[iNowA].mother2()) )
1150  physical = false;
1151  }
1152 
1153  }
1154 
1155  // Error message if problem found. Done.
1156  if (!physical) infoPtr->errorMsg("Error in ProcessLevel::checkColours: "
1157  "unphysical colour flow");
1158  return physical;
1159 
1160 }
1161 
1162 //--------------------------------------------------------------------------
1163 
1164 // Print statistics when two hard processes allowed.
1165 
1166 void ProcessLevel::statistics2(bool reset, ostream& os) {
1167 
1168  // Average impact-parameter factor and error.
1169  double invN = 1. / max(1, nImpact);
1170  double impactFac = max( 1., sumImpactFac * invN);
1171  double impactErr2 = ( sum2ImpactFac * invN / pow2(impactFac) - 1.) * invN;
1172 
1173  // Derive scaling factor to be applied to first set of processes.
1174  double sigma2SelSum = 0.;
1175  int n2SelSum = 0;
1176  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) {
1177  sigma2SelSum += container2Ptrs[i2]->sigmaSelMC();
1178  n2SelSum += container2Ptrs[i2]->nSelected();
1179  }
1180  double factor1 = impactFac * sigma2SelSum / sigmaND;
1181  double rel1Err = sqrt(1. / max(1, n2SelSum) + impactErr2);
1182  if (allHardSame) factor1 *= 0.5;
1183 
1184  // Derive scaling factor to be applied to second set of processes.
1185  double sigma1SelSum = 0.;
1186  int n1SelSum = 0;
1187  for (int i = 0; i < int(containerPtrs.size()); ++i) {
1188  sigma1SelSum += containerPtrs[i]->sigmaSelMC();
1189  n1SelSum += containerPtrs[i]->nSelected();
1190  }
1191  double factor2 = impactFac * sigma1SelSum / sigmaND;
1192  if (allHardSame) factor2 *= 0.5;
1193  double rel2Err = sqrt(1. / max(1, n1SelSum) + impactErr2);
1194 
1195  // Header.
1196  os << "\n *------- PYTHIA Event and Cross Section Statistics ------"
1197  << "--------------------------------------------------*\n"
1198  << " | "
1199  << " |\n"
1200  << " | Subprocess Code | "
1201  << "Number of events | sigma +- delta |\n"
1202  << " | | Tried"
1203  << " Selected Accepted | (estimated) (mb) |\n"
1204  << " | | "
1205  << " | |\n"
1206  << " |------------------------------------------------------------"
1207  << "------------------------------------------------|\n"
1208  << " | | "
1209  << " | |\n"
1210  << " | First hard process: | "
1211  << " | |\n"
1212  << " | | "
1213  << " | |\n";
1214 
1215  // Reset sum counters.
1216  long nTrySum = 0;
1217  long nSelSum = 0;
1218  long nAccSum = 0;
1219  double sigmaSum = 0.;
1220  double delta2Sum = 0.;
1221 
1222  // Reset process maps.
1223  map<int, string> nameM;
1224  map<int, long> nTryM, nSelM, nAccM;
1225  map<int, double> sigmaM, delta2M;
1226 
1227  // Loop over existing first processes.
1228  for (int i = 0; i < int(containerPtrs.size()); ++i)
1229  if (containerPtrs[i]->sigmaMax() != 0.) {
1230 
1231  // Read info for process. Sum counters.
1232  int code = containerPtrs[i]->code();
1233  nTrySum += containerPtrs[i]->nTried();
1234  nSelSum += containerPtrs[i]->nSelected();
1235  nAccSum += containerPtrs[i]->nAccepted();
1236  sigmaSum += containerPtrs[i]->sigmaMC() * factor1;
1237  delta2Sum += pow2(containerPtrs[i]->deltaMC() * factor1);
1238  nameM[code] = containerPtrs[i]->name();
1239  nTryM[code] += containerPtrs[i]->nTried();
1240  nSelM[code] += containerPtrs[i]->nSelected();
1241  nAccM[code] += containerPtrs[i]->nAccepted();
1242  sigmaM[code] += containerPtrs[i]->sigmaMC() * factor1;
1243  delta2M[code] += pow2(containerPtrs[i]->deltaMC() * factor1);
1244  delta2M[code] += pow2(containerPtrs[i]->sigmaMC() * factor1 * rel1Err);
1245  }
1246 
1247  // Print first process info.
1248  for (map<int, string>::iterator i = nameM.begin(); i != nameM.end(); ++i) {
1249  int code = i->first;
1250  os << " | " << left << setw(40) << i->second
1251  << right << setw(5) << code << " | "
1252  << setw(11) << nTryM[code] << " " << setw(10) << nSelM[code] << " "
1253  << setw(10) << nAccM[code] << " | " << scientific << setprecision(3)
1254  << setw(11) << sigmaM[code]
1255  << setw(11) << sqrtpos(delta2M[code]) << " |\n";
1256  }
1257 
1258  // Print summed info for first processes.
1259  delta2Sum += pow2( sigmaSum * rel1Err );
1260  os << " | | "
1261  << " | |\n"
1262  << " | " << left << setw(45) << "sum" << right << " | " << setw(11)
1263  << nTrySum << " " << setw(10) << nSelSum << " " << setw(10)
1264  << nAccSum << " | " << scientific << setprecision(3) << setw(11)
1265  << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n";
1266 
1267  // Separation lines to second hard processes.
1268  os << " | | "
1269  << " | |\n"
1270  << " |------------------------------------------------------------"
1271  << "------------------------------------------------|\n"
1272  << " | | "
1273  << " | |\n"
1274  << " | Second hard process: | "
1275  << " | |\n"
1276  << " | | "
1277  << " | |\n";
1278 
1279  // Reset sum counters.
1280  nTrySum = 0;
1281  nSelSum = 0;
1282  nAccSum = 0;
1283  sigmaSum = 0.;
1284  delta2Sum = 0.;
1285 
1286  // Reset process maps.
1287  nameM.clear();
1288  nTryM.clear();
1289  nSelM.clear();
1290  nAccM.clear();
1291  sigmaM.clear();
1292  delta2M.clear();
1293 
1294  // Loop over existing second processes.
1295  for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2)
1296  if (container2Ptrs[i2]->sigmaMax() != 0.) {
1297 
1298  // Read info for process. Sum counters.
1299  int code = container2Ptrs[i2]->code();
1300  nTrySum += container2Ptrs[i2]->nTried();
1301  nSelSum += container2Ptrs[i2]->nSelected();
1302  nAccSum += container2Ptrs[i2]->nAccepted();
1303  sigmaSum += container2Ptrs[i2]->sigmaMC() * factor2;
1304  delta2Sum += pow2(container2Ptrs[i2]->deltaMC() * factor2);
1305  nameM[code] = container2Ptrs[i2]->name();
1306  nTryM[code] += container2Ptrs[i2]->nTried();
1307  nSelM[code] += container2Ptrs[i2]->nSelected();
1308  nAccM[code] += container2Ptrs[i2]->nAccepted();
1309  sigmaM[code] += container2Ptrs[i2]->sigmaMC() * factor2;
1310  delta2M[code] += pow2(container2Ptrs[i2]->deltaMC() * factor2);
1311  delta2M[code] += pow2(container2Ptrs[i2]->sigmaMC() * factor2 * rel2Err);
1312  }
1313 
1314  // Print second process info.
1315  for (map<int, string>::iterator i2 = nameM.begin(); i2 != nameM.end(); ++i2) {
1316  int code = i2->first;
1317  os << " | " << left << setw(40) << i2->second
1318  << right << setw(5) << code << " | "
1319  << setw(11) << nTryM[code] << " " << setw(10) << nSelM[code] << " "
1320  << setw(10) << nAccM[code] << " | " << scientific << setprecision(3)
1321  << setw(11) << sigmaM[code]
1322  << setw(11) << sqrtpos(delta2M[code]) << " |\n";
1323  }
1324 
1325  // Print summed info for second processes.
1326  delta2Sum += pow2( sigmaSum * rel2Err );
1327  os << " | | "
1328  << " | |\n"
1329  << " | " << left << setw(45) << "sum" << right << " | " << setw(11)
1330  << nTrySum << " " << setw(10) << nSelSum << " " << setw(10)
1331  << nAccSum << " | " << scientific << setprecision(3) << setw(11)
1332  << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n";
1333 
1334  // Print information on how the two processes were combined.
1335  os << " | | "
1336  << " | |\n"
1337  << " |------------------------------------------------------------"
1338  << "------------------------------------------------|\n"
1339  << " | "
1340  << " |\n"
1341  << " | Uncombined cross sections for the two event sets were "
1342  << setw(10) << sigma1SelSum << " and " << sigma2SelSum << " mb, "
1343  << "respectively, combined |\n"
1344  << " | using a sigma(nonDiffractive) of " << setw(10) << sigmaND
1345  << " mb and an impact-parameter enhancement factor of "
1346  << setw(10) << impactFac << ". |\n";
1347 
1348  // Listing finished.
1349  os << " | "
1350  << " |\n"
1351  << " *------- End PYTHIA Event and Cross Section Statistics -----"
1352  << "------------------------------------------------*" << endl;
1353 
1354  // Optionally reset statistics contants.
1355  if (reset) resetStatistics();
1356 
1357 }
1358 
1359 //==========================================================================
1360 
1361 } // end namespace Pythia8
1362 
Definition: AgUStep.h:26