Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4ElementaryParticleCollider.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// 20100114 M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
28// 20100316 D. Wright (restored by M. Kelsey) -- Replace original (incorrect)
29// pp, pn, nn 2-body to 2-body scattering angular distributions
30// with a new parametrization of elastic scattering data using
31// the sum of two exponentials.
32// 20100319 M. Kelsey -- Use new generateWithRandomAngles for theta,phi stuff;
33// eliminate some unnecessary std::pow()
34// 20100407 M. Kelsey -- Replace std::vector<>::resize(0) with ::clear()
35// Eliminate return-by-value std::vector<> by creating buffers
36// buffers for particles, momenta, and particle types.
37// The following functions now return void and are non-const:
38// ::generateSCMfinalState()
39// ::generateMomModules()
40// ::generateStrangeChannelPartTypes()
41// ::generateSCMpionAbsorption()
42// 20100408 M. Kelsey -- Follow changes to G4*Sampler to pass particle_kinds
43// as input buffer.
44// 20100413 M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
45// 20100428 M. Kelsey -- Use G4InuclParticleNames enum
46// 20100429 M. Kelsey -- Change "photon()" to "isPhoton()"
47// 20100507 M. Kelsey -- Rationalize multiplicity returns to be actual value
48// 20100511 M. Kelsey -- Replace G4PionSampler and G4NucleonSampler with new
49// pi-N and N-N classes, reorganize if-cascades
50// 20100511 M. Kelsey -- Eliminate three residual random-angles blocks.
51// 20100511 M. Kelsey -- Bug fix: pi-N two-body final states not correctly
52// tested for charge-exchange case.
53// 20100512 M. Kelsey -- Rationalize multiplicity returns to be actual value
54// 20100512 M. Kelsey -- Add some additional debugging messages for 2-to-2
55// 20100512 M. Kelsey -- Replace "if (is==)" cascades with switch blocks.
56// Use G4CascadeInterpolator for angular distributions.
57// 20100517 M. Kelsey -- Inherit from common base class, make arrays static
58// 20100519 M. Kelsey -- Use G4InteractionCase to compute "is" values.
59// 20100625 M. Kelsey -- Two bugs in n-body momentum, last particle recoil
60// 20100713 M. Kelsey -- Bump collide start message up to verbose > 1
61// 20100714 M. Kelsey -- Move conservation checking to base class
62// 20100714 M. Kelsey -- Add sanity check for two-body final state, to ensure
63// that final state total mass is below etot_scm; also compute
64// kinematics without "rescaling" (which led to non-conservation)
65// 20100726 M. Kelsey -- Move remaining std::vector<> buffers to .hh file
66// 20100804 M. Kelsey -- Add printing of final-state tables, protected by
67// G4CASCADE_DEBUG_SAMPLER preprocessor flag
68// 20101019 M. Kelsey -- CoVerity report: check dynamic_cast<> for null
69// 20110214 M. Kelsey -- Follow G4InuclParticle::Model enumerator migration
70// 20110718 V. Uzhinskiy -- Drop IL,IM reset for multiplicity-three collisions
71// 20110718 M. Kelsey -- Use enum names in switch blocks (c.f. G4NucleiModel)
72// 20110720 M. Kelsey -- Follow interface change for cross-section tables,
73// eliminating switch blocks.
74// 20110806 M. Kelsey -- Pre-allocate buffers to avoid memory churn
75// 20110922 M. Kelsey -- Follow G4InuclParticle::print(ostream&) migration
76// 20110926 M. Kelsey -- Protect sampleCMcosFor2to2 from unphysical arguments
77// 20111003 M. Kelsey -- Prepare for gamma-N interactions by checking for
78// final-state tables instead of particle "isPhoton()"
79// 20111007 M. Kelsey -- Add gamma-N final-state tables to printFinalState
80// 20111107 M. Kelsey -- In sampleCMmomentumFor2to2(), hide message about
81// unrecognized gamma-N initial state behind verbosity.
82// 20111216 M. Kelsey -- Add diagnostics to generateMomModulesFor2toMany(),
83// defer allocation of buffer in generateSCMfinalState() so that
84// multiplicity failures return zero output, and can be trapped.
85// 20120308 M. Kelsey -- Allow photons to interact with dibaryons (see
86// changes in G4NucleiModel).
87// 20120608 M. Kelsey -- Fix variable-name "shadowing" compiler warnings.
88// 20121206 M. Kelsey -- Add Omega to printFinalStateTables(), remove line
89// about "preliminary" gamma-N.
90// 20130129 M. Kelsey -- Add static arrays and interpolators for two-body
91// angular distributions (addresses MT thread-local issue)
92// 20130221 M. Kelsey -- Move two-body angular dist classes to factory
93// 20130306 M. Kelsey -- Use particle-name enums in if-blocks; add comments
94// to sections of momentum-coefficient matrix; move final state
95// table printing to G4CascadeChannelTables.
96// 20130307 M. Kelsey -- Reverse order of dimensions for rmn array
97// 20130307 M. Kelsey -- Use new momentum generator factory instead of rmn
98// 20130308 M. Kelsey -- Move 3-body angle calc to G4InuclSpecialFunctions.
99// 20130422 M. Kelsey -- Move kinematics to G4CascadeFinalStateAlgorithm;
100// reduce nesting and replicated code in collide().
101// 20130508 D. Wright -- Implement muon capture
102// 20130511 M. Kelsey -- Check for neutrinos and skip them in ::collide()
103// 20141009 M. Kelsey -- Add pion absorption by single nucleons, with
104// nuclear recoil. Improves pi- capture performance.
105// 20141030 M. Kelsey -- Check flag for whether to do pi-N absorption
106// 20141201 M. Kelsey -- Check for null vector return from G4GDecay3
107// 20141211 M. Kelsey -- Change PIN_ABSORPTION flag to double, probability;
108// fix handling of boosts for pi-N absorption.
109// 20150608 M. Kelsey -- Label all while loops as terminating.
110
112#include "G4CascadeChannel.hh"
114#include "G4CascadeParameters.hh"
115#include "G4CollisionOutput.hh"
116#include "G4GDecay3.hh"
119#include "G4LorentzConvertor.hh"
121#include "G4NucleiModel.hh"
124#include "G4VMultiBodyMomDst.hh"
125#include "G4VTwoBodyAngDst.hh"
126#include "Randomize.hh"
127#include <algorithm>
128#include <cfloat>
129#include <vector>
130
131using namespace G4InuclParticleNames;
132using namespace G4InuclSpecialFunctions;
133
134typedef std::vector<G4InuclElementaryParticle>::iterator particleIterator;
135
136
138 : G4CascadeColliderBase("G4ElementaryParticleCollider"),
139 nucleusA(0), nucleusZ(0) {;}
140
141
142void
144 G4InuclParticle* target,
145 G4CollisionOutput& output)
146{
147 if (verboseLevel > 1)
148 G4cout << " >>> G4ElementaryParticleCollider::collide" << G4endl;
149
150 if (!useEPCollider(bullet,target)) { // Sanity check
151 G4cerr << " ElementaryParticleCollider -> can collide only particle with particle "
152 << G4endl;
153 return;
154 }
155
156#ifdef G4CASCADE_DEBUG_SAMPLER
157 static G4bool doPrintTables = true; // Once and only once per job
158 if (doPrintTables) {
160 doPrintTables = false;
161 }
162#endif
163
164 interCase.set(bullet, target); // To identify kind of collision
165
166 if (verboseLevel > 1) G4cout << *bullet << G4endl << *target << G4endl;
167
168 G4InuclElementaryParticle* particle1 =
169 dynamic_cast<G4InuclElementaryParticle*>(bullet);
170 G4InuclElementaryParticle* particle2 =
171 dynamic_cast<G4InuclElementaryParticle*>(target);
172
173 if (!particle1 || !particle2) { // Redundant with useEPCollider()
174 G4cerr << " ElementaryParticleCollider -> can only collide hadrons"
175 << G4endl;
176 return;
177 }
178
179 if (particle1->isNeutrino() || particle2->isNeutrino()) return;
180
181 // Check for available interaction, or pion+dibaryon special case
183 !particle1->quasi_deutron() && !particle2->quasi_deutron()) {
184 G4cerr << " ElementaryParticleCollider -> cannot collide "
185 << particle1->getDefinition()->GetParticleName() << " with "
186 << particle2->getDefinition()->GetParticleName() << G4endl;
187 return;
188 }
189
190 G4LorentzConvertor convertToSCM; // Utility to handle frame manipulation
191 if (particle2->nucleon() || particle2->quasi_deutron()) {
192 convertToSCM.setBullet(particle1);
193 convertToSCM.setTarget(particle2);
194 } else {
195 convertToSCM.setBullet(particle2);
196 convertToSCM.setTarget(particle1);
197 }
198
199 convertToSCM.setVerbose(verboseLevel);
200 convertToSCM.toTheCenterOfMass();
201
202 G4double etot_scm = convertToSCM.getTotalSCMEnergy();
203
204 // Generate any particle collision with nucleon
205 if (particle1->nucleon() || particle2->nucleon()) {
206 G4double ekin = convertToSCM.getKinEnergyInTheTRS();
207
208 // SPECIAL: Very low energy pions may be absorbed by a nucleon
209 if (pionNucleonAbsorption(ekin)) {
210 generateSCMpionNAbsorption(etot_scm, particle1, particle2);
211 } else {
212 generateSCMfinalState(ekin, etot_scm, particle1, particle2);
213 }
214 }
215
216 // Generate pion or photon collision with quasi-deuteron
217 if (particle1->quasi_deutron() || particle2->quasi_deutron()) {
218 if (!G4NucleiModel::useQuasiDeuteron(particle1->type(),particle2->type()) &&
219 !G4NucleiModel::useQuasiDeuteron(particle2->type(),particle1->type())) {
220 G4cerr << " ElementaryParticleCollider -> can only collide pi,mu,gamma with"
221 << " dibaryons " << G4endl;
222 return;
223 }
224
225 if (particle1->isMuon() || particle2->isMuon()) {
226 generateSCMmuonAbsorption(etot_scm, particle1, particle2);
227 } else { // Currently, pion absoprtion also handles gammas
228 generateSCMpionAbsorption(etot_scm, particle1, particle2);
229 }
230 }
231
232 if (particles.empty()) { // No final state possible, pass bullet through
233 if (verboseLevel) {
234 G4cerr << " ElementaryParticleCollider -> failed to collide "
235 << particle1->getMomModule() << " GeV/c "
236 << particle1->getDefinition()->GetParticleName() << " with "
237 << particle2->getDefinition()->GetParticleName() << G4endl;
238 }
239 return;
240 }
241
242 // Convert final state back to lab frame
243 G4LorentzVector mom; // Buffer to avoid memory churn
244 particleIterator ipart;
245 for(ipart = particles.begin(); ipart != particles.end(); ipart++) {
246 mom = convertToSCM.backToTheLab(ipart->getMomentum());
247 ipart->setMomentum(mom);
248 };
249
250 if (verboseLevel) {
251 // Check conservation in multibody final state
252 const G4ParticleDefinition* bDef = bullet->getDefinition();
253 const G4ParticleDefinition* tDef = target->getDefinition();
254
255 G4int initBaryonNumber = bDef->GetBaryonNumber() + tDef->GetBaryonNumber();
256 G4int initCharge = bullet->getCharge() + target->getCharge();
257 G4int initStrangeness = bDef->GetQuarkContent(3) - bDef->GetAntiQuarkContent(3) +
258 tDef->GetQuarkContent(3) - tDef->GetAntiQuarkContent(3);
259
260 G4int finalBaryonNumber = 0;
261 G4int finalCharge = 0;
262 G4int finalStrangeness = 0;
263
264 for (ipart = particles.begin(); ipart != particles.end(); ipart++) {
265 finalBaryonNumber += ipart->baryon();
266 finalCharge += ipart->getCharge();
267 finalStrangeness += ipart->getStrangeness();
268 }
269
270 G4int bnc = finalBaryonNumber - initBaryonNumber;
271 G4int cnc = finalCharge - initCharge;
272 G4int snc = finalStrangeness - initStrangeness;
273
274 if (bnc != 0 || cnc != 0 || snc != 0) {
275 G4cout << " G4ElementaryParticleCollider: quantum number non-conservation " << G4endl;
276 G4cout << " Baryon number: initial = " << initBaryonNumber << ", final = "
277 << finalBaryonNumber << G4endl;
278 G4cout << " Charge: initial = " << initCharge << ", final = "
279 << finalCharge << G4endl;
280 G4cout << " Strangeness: initial = " << initStrangeness << ", final = "
281 << finalStrangeness << G4endl;
282
283 G4cout << " bullet = " << bDef->GetParticleName() << G4endl;
284 G4cout << " target = " << tDef->GetParticleName() << G4endl;
285 G4cout << " secondaries = " ;
286 for (ipart = particles.begin(); ipart != particles.end(); ipart++) {
287 G4cout << ipart->getDefinition()->GetParticleName() << " " ;
288 }
289 G4cout << G4endl;
290 }
291 }
292
293 if (verboseLevel && !validateOutput(bullet, target, particles)) {
294 G4cout << " incoming particles: \n" << *particle1 << G4endl
295 << *particle2 << G4endl
296 << " outgoing particles: " << G4endl;
297 for(ipart = particles.begin(); ipart != particles.end(); ipart++)
298 G4cout << *ipart << G4endl;
299
300 G4cout << " <<< Non-conservation in G4ElementaryParticleCollider"
301 << G4endl;
302 }
303
304 std::sort(particles.begin(), particles.end(), G4ParticleLargerEkin());
305 output.addOutgoingParticles(particles);
306}
307
308
309G4int
310G4ElementaryParticleCollider::generateMultiplicity(G4int is,
311 G4double ekin) const
312{
313 G4int mul = 0;
314
316
317 if (xsecTable) mul = xsecTable->getMultiplicity(ekin);
318 else {
319 G4cerr << " G4ElementaryParticleCollider: Unknown interaction channel "
320 << is << " - multiplicity not generated " << G4endl;
321 }
322
323 if(verboseLevel > 3){
324 G4cout << " G4ElementaryParticleCollider::generateMultiplicity: "
325 << " multiplicity = " << mul << G4endl;
326 }
327
328 return mul;
329}
330
331
332void
333G4ElementaryParticleCollider::generateOutgoingPartTypes(G4int is, G4int mult,
334 G4double ekin)
335{
336 particle_kinds.clear(); // Initialize buffer for generation
337
339
340 if (xsecTable)
341 xsecTable->getOutgoingParticleTypes(particle_kinds, mult, ekin);
342 else {
343 G4cerr << " G4ElementaryParticleCollider: Unknown interaction channel "
344 << is << " - outgoing kinds not generated " << G4endl;
345 }
346
347 return;
348}
349
350
351void
352G4ElementaryParticleCollider::generateSCMfinalState(G4double ekin,
353 G4double etot_scm,
354 G4InuclElementaryParticle* particle1,
355 G4InuclElementaryParticle* particle2) {
356 if (verboseLevel > 2) {
357 G4cout << " >>> G4ElementaryParticleCollider::generateSCMfinalState"
358 << G4endl;
359 }
360
361 fsGenerator.SetVerboseLevel(verboseLevel);
362
363 const G4int itry_max = 10;
364
365 G4int type1 = particle1->type();
366 G4int type2 = particle2->type();
367
368 G4int is = type1 * type2;
369
370 if (verboseLevel > 3) G4cout << " is " << is << G4endl;
371
372 G4int multiplicity = 0;
373 G4bool generate = true;
374
375 G4int itry = 0;
376 while (generate && itry++ < itry_max) { /* Loop checking 08.06.2015 MHK */
377 particles.clear(); // Initialize buffers for this event
378 particle_kinds.clear();
379
380 // Generate list of final-state particles
381 multiplicity = generateMultiplicity(is, ekin);
382
383 generateOutgoingPartTypes(is, multiplicity, ekin);
384 if (particle_kinds.empty()) {
385 if (verboseLevel > 3) {
386 G4cout << " generateOutgoingPartTypes failed mult " << multiplicity
387 << G4endl;
388 }
389 continue;
390 }
391
392 fillOutgoingMasses(); // Fill mass buffer from particle types
393
394 // Attempt to produce final state kinematics
395 fsGenerator.Configure(particle1, particle2, particle_kinds);
396 generate = !fsGenerator.Generate(etot_scm, masses, scm_momentums);
397 } // while (generate)
398
399 if (itry >= itry_max) { // Unable to generate valid final state
400 if (verboseLevel > 2)
401 G4cout << " generateSCMfinalState failed " << itry << " attempts"
402 << G4endl;
403 return;
404 }
405
406 // Store generated momenta into outgoing particles
407
408 particles.resize(multiplicity); // Preallocate buffer
409 for (G4int i=0; i<multiplicity; i++) {
410 particles[i].fill(scm_momentums[i], particle_kinds[i],
412 }
413
414 if (verboseLevel > 3) {
415 G4cout << " <<< G4ElementaryParticleCollider::generateSCMfinalState"
416 << G4endl;
417 }
418
419 return; // Particles buffer filled
420}
421
422
423// Use generated list of final states to fill mass buffers
424
425void G4ElementaryParticleCollider::fillOutgoingMasses() {
426 std::size_t mult = particle_kinds.size();
427
428 masses.resize(mult,0.);
429 masses2.resize(mult,0.); // Allows direct [i] setting
430
431 for (std::size_t i = 0; i < mult; ++i) {
432 masses[i] = G4InuclElementaryParticle::getParticleMass(particle_kinds[i]);
433 masses2[i] = masses[i] * masses[i];
434 }
435}
436
437
438// Generate nucleon momenta for pion or photon absorption by dibaryon
439// The nucleon distribution is assumed to be isotropic in SCM
440
441void
442G4ElementaryParticleCollider::generateSCMpionAbsorption(G4double etot_scm,
443 G4InuclElementaryParticle* particle1,
444 G4InuclElementaryParticle* particle2)
445{
446 if (verboseLevel > 3)
447 G4cout << " >>> G4ElementaryParticleCollider::generateSCMpionAbsorption"
448 << G4endl;
449
450 particles.clear(); // Initialize buffers for this event
451 particles.resize(2);
452
453 particle_kinds.clear();
454
455 G4int typeProduct = particle1->type() * particle2->type();
456
457 if (typeProduct == G4int(pi0)*G4int(diproton) || typeProduct == G4int(pip)*G4int(unboundPN) ||
458 typeProduct == G4int(gam)*G4int(diproton)) {
459 particle_kinds.push_back(pro);
460 particle_kinds.push_back(pro);
461
462 } else if (typeProduct == G4int(pim)*G4int(diproton) || typeProduct == G4int(pip)*G4int(dineutron) ||
463 typeProduct == G4int(pi0)*G4int(unboundPN) || typeProduct == G4int(gam)*G4int(unboundPN)) {
464 particle_kinds.push_back(pro);
465 particle_kinds.push_back(neu);
466
467 } else if (typeProduct == G4int(pi0)*G4int(dineutron) || typeProduct == G4int(pim)*G4int(unboundPN) ||
468 typeProduct == G4int(gam)*G4int(dineutron)) {
469 particle_kinds.push_back(neu);
470 particle_kinds.push_back(neu);
471
472 } else {
473 G4cerr << " Illegal absorption: "
474 << particle1->getDefinition()->GetParticleName() << " + "
475 << particle2->getDefinition()->GetParticleName() << " -> ?"
476 << G4endl;
477 return;
478 }
479
480 fillOutgoingMasses();
481
482 G4double a = 0.5 * (etot_scm * etot_scm - masses2[0] - masses2[1]);
483
484 G4double pmod = std::sqrt((a*a - masses2[0]*masses2[1])
485 / (etot_scm*etot_scm) );
486 G4LorentzVector mom1 = generateWithRandomAngles(pmod, masses[0]);
487 G4LorentzVector mom2;
488 mom2.setVectM(-mom1.vect(), masses[1]);
489
490 particles[0].fill(mom1, particle_kinds[0], G4InuclParticle::EPCollider);
491 particles[1].fill(mom2, particle_kinds[1], G4InuclParticle::EPCollider);
492}
493
494
495// Generate nucleon momenta for muon absorption by dibaryon
496// The nucleon distribution is assumed to be isotropic in SCM
497
498void
499G4ElementaryParticleCollider::generateSCMmuonAbsorption(G4double etot_scm,
500 G4InuclElementaryParticle* particle1,
501 G4InuclElementaryParticle* particle2)
502{
503 if (verboseLevel > 3)
504 G4cout << " >>> G4ElementaryParticleCollider::generateSCMmuonAbsorption"
505 << G4endl;
506
507 particles.clear(); // Initialize buffers for this event
508 particles.resize(3);
509
510 scm_momentums.clear();
511 scm_momentums.resize(3);
512
513 particle_kinds.clear();
514
515 G4int typeProduct = particle1->type() * particle2->type();
516
517 if (typeProduct == G4int(mum)*G4int(diproton)) {
518 particle_kinds.push_back(pro);
519 particle_kinds.push_back(neu);
520 } else if (typeProduct == G4int(mum)*G4int(unboundPN)) {
521 particle_kinds.push_back(neu);
522 particle_kinds.push_back(neu);
523 } else {
524 G4cerr << " Illegal absorption: "
525 << particle1->getDefinition()->GetParticleName() << " + "
526 << particle2->getDefinition()->GetParticleName() << " -> ?"
527 << G4endl;
528 return;
529 }
530 particle_kinds.push_back(mnu);
531
532 fillOutgoingMasses();
533
534 // Phase space generator required for the 3-body final state
535 G4GDecay3 breakup(etot_scm, masses[0], masses[1], masses[2]);
536 std::vector<G4ThreeVector> theMomenta = breakup.GetThreeBodyMomenta();
537
538 if (theMomenta.empty()) {
539 G4cerr << " generateSCMmuonAbsorption: GetThreeBodyMomenta() failed"
540 << " for " << particle2->type() << " dibaryon" << G4endl;
541 particle_kinds.clear();
542 masses.clear();
543 particles.clear();
544 return;
545 }
546
547 for (std::size_t i=0; i<3; ++i) {
548 scm_momentums[i].setVectM(theMomenta[i], masses[i]);
549 particles[i].fill(scm_momentums[i], particle_kinds[i], G4InuclParticle::EPCollider);
550 }
551}
552
553
554// generate nucleons momenta for pion absorption by single nucleon
555
556void
557G4ElementaryParticleCollider::generateSCMpionNAbsorption(G4double /*etot_scm*/,
558 G4InuclElementaryParticle* particle1,
559 G4InuclElementaryParticle* particle2) {
560 if (verboseLevel > 3)
561 G4cout << " >>> G4ElementaryParticleCollider::generateSCMpionNAbsorption"
562 << G4endl;
563
564 particles.clear(); // Initialize buffers for this event
565 particles.resize(1);
566
567 particle_kinds.clear();
568
569 G4int type1 = particle1->type();
570 G4int type2 = particle2->type();
571
572 // Ensure that single-nucleon absportion is valid (charge exchangeable)
573 if ((type1*type2 != pim*pro && type1*type2 != pip*neu)) {
574 G4cerr << " pion-nucleon absorption: "
575 << particle1->getDefinition()->GetParticleName() << " + "
576 << particle2->getDefinition()->GetParticleName() << " -> ?"
577 << G4endl;
578 return;
579 }
580
581 // Get outgoing nucleon type using charge exchange
582 // Proton code is 1, neutron code is 2, so 3-# swaps them
583 G4int ntype = (particle2->nucleon() ? type2 : type1);
584 G4int outType = 3 - ntype;
585 particle_kinds.push_back(outType);
586
587 fillOutgoingMasses();
588
589 // Get mass of residual nucleus (2-ntype = 1 for proton, 0 for neutron)
590 G4double mRecoil =
591 G4InuclNuclei::getNucleiMass(nucleusA-1, nucleusZ-(2-ntype));
592 G4double mRecoil2 = mRecoil*mRecoil;
593
594 // Recompute Ecm to include nucleus (for recoil kinematics)
595 G4LorentzVector piN4 = particle1->getMomentum() + particle2->getMomentum();
596 G4LorentzVector vsum(0.,0.,0.,mRecoil);
597 vsum += piN4;
598
599 // Two-body kinematics (nucleon against nucleus) in overall CM system
600 G4double esq_scm = vsum.m2();
601 G4double a = 0.5 * (esq_scm - masses2[0] - mRecoil2);
602
603 G4double pmod = std::sqrt((a*a - masses2[0]*mRecoil2) / esq_scm );
604 G4LorentzVector mom1 = generateWithRandomAngles(pmod, masses[0]);
605
606 if (verboseLevel > 3) {
607 G4cout << " outgoing type " << outType << " recoiling on nuclear mass "
608 << mRecoil << "\n a " << a << " p " << pmod << " Ekin "
609 << mom1.e()-masses[0] << G4endl;
610 }
611
612 mom1.boost(-piN4.boostVector()); // Boost into CM of pi-N collision
613
614 if (verboseLevel > 3) {
615 G4cout << " in original pi-N frame p(SCM) " << mom1.rho() << " Ekin "
616 << mom1.e()-masses[0] << G4endl;
617 }
618
619 // Fill only the ejected nucleon
620 particles[0].fill(mom1, particle_kinds[0], G4InuclParticle::EPCollider);
621}
622
623
624// Evaluate whether interaction is candidate for absorption on nucleon
625G4bool
626G4ElementaryParticleCollider::pionNucleonAbsorption(G4double ekin) const {
627 if (verboseLevel > 3)
628 G4cout << " >>> G4ElementaryParticleCollider::pionNucleonAbsorption ?"
629 << " ekin " << ekin << " is " << interCase.hadrons() << G4endl;
630
631 // Absorption occurs with specified probability
633
634 // Absorption occurs only for pi- p -> n, or pi+ n -> p
635 // Restrict to "very slow" pions, to allow for some normal scattering
636 return ((interCase.hadrons() == pim*pro ||
638 && (ekin < 0.05) // 50 MeV kinetic energy or less
639 && (G4UniformRand() < absProb)
640 );
641}
642
std::vector< G4InuclElementaryParticle >::iterator particleIterator
Definition: G4BigBanger.cc:64
std::vector< G4InuclElementaryParticle >::iterator particleIterator
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector boostVector() const
HepLorentzVector & boost(double, double, double)
void setVectM(const Hep3Vector &spatial, double mass)
Hep3Vector vect() const
static void Print(std::ostream &os=G4cout)
static const G4CascadeChannel * GetTable(G4int initialState)
virtual G4int getMultiplicity(G4double ke) const =0
virtual void getOutgoingParticleTypes(std::vector< G4int > &kinds, G4int mult, G4double ke) const =0
virtual G4bool useEPCollider(G4InuclParticle *bullet, G4InuclParticle *target) const
virtual G4bool validateOutput(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
void Configure(G4InuclElementaryParticle *bullet, G4InuclElementaryParticle *target, const std::vector< G4int > &particle_kinds)
static G4double piNAbsorption()
void addOutgoingParticles(const std::vector< G4InuclElementaryParticle > &particles)
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
void SetVerboseLevel(G4int verbose)
G4bool Generate(G4double initialMass, const std::vector< G4double > &masses, std::vector< G4LorentzVector > &finalState)
G4int hadrons() const
void set(G4InuclParticle *part1, G4InuclParticle *part2)
static G4double getParticleMass(G4int type)
G4double getNucleiMass() const
const G4ParticleDefinition * getDefinition() const
G4LorentzVector getMomentum() const
G4double getMomModule() const
G4double getCharge() const
G4double getTotalSCMEnergy() const
void setVerbose(G4int vb=0)
void setBullet(const G4InuclParticle *bullet)
G4LorentzVector backToTheLab(const G4LorentzVector &mom) const
G4double getKinEnergyInTheTRS() const
void setTarget(const G4InuclParticle *target)
static G4bool useQuasiDeuteron(G4int ptype, G4int qdtype=0)
G4int GetQuarkContent(G4int flavor) const
const G4String & GetParticleName() const
G4int GetAntiQuarkContent(G4int flavor) const
void generate(const G4double sqrtS, ParticleList &particles)
Generate an event in the CM system.
G4LorentzVector generateWithRandomAngles(G4double p, G4double mass=0.)