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
G4LightTargetCollider.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// //
28// File: G4LightTargetCollider.cc //
29// Date: 30 September 2019 //
30// Author: Dennis Wright (SLAC) //
31// //
32// Description: model for collision of elementary particles with light //
33// targets (H, D, T, 3He) //
34// //
35////////////////////////////////////////////////////////////////////////////////
36
38#include "G4CascadeChannel.hh"
41#include "G4CollisionOutput.hh"
44#include "G4InuclNuclei.hh"
45#include "G4NucleiModel.hh"
46#include "G4LorentzConvertor.hh"
47#include "G4Deuteron.hh"
48#include "G4Gamma.hh"
49#include "G4PionZero.hh"
50#include "G4PionPlus.hh"
51#include "G4PionMinus.hh"
52#include "G4RandomDirection.hh"
53
54
56 : G4CascadeColliderBase("G4LightTargetCollider"),
57 theElementaryParticleCollider(new G4ElementaryParticleCollider)
58{
59 mP = G4Proton::Proton()->GetPDGMass()/CLHEP::GeV;
60 mN = G4Neutron::Neutron()->GetPDGMass()/CLHEP::GeV;
61 mD = G4Deuteron::Deuteron()->GetPDGMass()/CLHEP::GeV;
62 pFermiD = 0.045; // Fermi momentum of nucleon in deuteron Hulthen potential
63}
64
66 delete theElementaryParticleCollider;
67}
68
69
70// Set verbosity and pass on to member objects
73 theElementaryParticleCollider->setVerboseLevel(verboseLevel);
75}
76
77
79 G4InuclParticle* target,
80 G4CollisionOutput& globalOutput)
81{
82 if (verboseLevel) {
83 G4cout << " >>> G4LightTargetCollider::collide" << G4endl;
84 G4cout << " Projectile: " << bullet->getDefinition()->GetParticleName() << G4endl;
85 G4cout << " Target: " << target->getDefinition()->GetParticleName() << G4endl;
86 }
87
88 G4double ke = bullet->getKineticEnergy();
89
90 if (target->getDefinition() == G4Proton::Proton() ) {
91 if (ke < 0.1447) {
92 // Below threshold lab energy for pi0 creation
93 globalOutput.trivialise(bullet, target);
94 } else {
95 // Need inelastic cross section in this class if we want to replace ElementaryParticleCollider
96 // with SingleNucleonScattering
97 theElementaryParticleCollider->collide(bullet, target, globalOutput);
98 if (globalOutput.numberOfOutgoingParticles() == 0) globalOutput.trivialise(bullet, target);
99 }
100
101 } else if (target->getDefinition() == G4Deuteron::Deuteron() ) {
102
103 if (ke < mP + mN - mD) {
104 // Should not happen as long as inelastic cross section is zero
105 G4Exception("G4LightTargetCollider::collide()","HAD_BERT_201",
106 JustWarning, "Projectile energy below reaction threshold");
107 globalOutput.trivialise(bullet, target);
108
109 } else {
110 // Get p, n and deuteron cross sections; use lab energy to access
113 G4double gammaDXS = GammaDCrossSection(ke);
114
115 G4double probP = 0.0;
116 G4double probN = 0.0;
117 // Highest threshold is 0.152 (for gamma p -> n pi+)
118 // Because of Fermi momentum in deuteron, raise this to 0.159
119 if (ke > 0.159) {
120 G4double totalDXS = gammaPXS + gammaNXS + gammaDXS;
121 probP = gammaPXS/totalDXS;
122 probN = (gammaPXS+gammaNXS)/totalDXS;
123 }
124
125 G4double rndm = G4UniformRand();
126 if (rndm < probP) {
127 // Generate Fermi momenta of bullet and target
128 G4ThreeVector fermiMomentum = pFermiD*G4RandomDirection();
129 G4LorentzVector protonMomentum(fermiMomentum, std::sqrt(mP*mP + pFermiD*pFermiD) );
130 G4LorentzVector neutronMomentum(-fermiMomentum, std::sqrt(mN*mN + pFermiD*pFermiD) );
131
132 G4LorentzVector bulletMomentum = bullet->getMomentum();
133 G4ThreeVector betacm = bulletMomentum.findBoostToCM(protonMomentum);
134
135 // First boost bullet and target so that target is at rest
136 G4ThreeVector toProtonRest = -protonMomentum.boostVector();
137 protonMomentum.boost(toProtonRest);
138 bulletMomentum.boost(toProtonRest);
139
140 G4InuclElementaryParticle projectile(bulletMomentum, bullet->getDefinition() );
141 G4InuclElementaryParticle targetNucleon(protonMomentum, G4Proton::Proton() );
142 G4InuclElementaryParticle spectatorNucleon(neutronMomentum, G4Neutron::Neutron() );
143 ScatteringProducts products = SingleNucleonScattering(projectile, targetNucleon);
144
145 // Particles from SingleNucleonScattering are in CM frame of projectile
146 // and moving proton. Transform back to lab frame with -betacm, then
147 // add them to outgoing list.
148 globalOutput.reset();
149 G4LorentzVector temp;
150 for (G4int i = 0; i < G4int(products.size()); i++) {
151 temp = products[i].getMomentum();
152 temp.boost(-betacm);
153 products[i].setMomentum(temp);
154 globalOutput.addOutgoingParticle(products[i]);
155 }
156
157 // Add the recoil nucleon unmodified
158 globalOutput.addOutgoingParticle(spectatorNucleon);
159
160 } else if (rndm < probN) {
161 G4ThreeVector fermiMomentum = pFermiD*G4RandomDirection();
162 G4LorentzVector protonMomentum(fermiMomentum, std::sqrt(mP*mP + pFermiD*pFermiD) );
163 G4LorentzVector neutronMomentum(-fermiMomentum, std::sqrt(mN*mN + pFermiD*pFermiD) );
164
165 G4LorentzVector bulletMomentum = bullet->getMomentum();
166 G4ThreeVector betacm = bulletMomentum.findBoostToCM(neutronMomentum);
167
168 // First boost bullet and target so that target is at rest
169 G4ThreeVector toNeutronRest = -neutronMomentum.boostVector();
170 neutronMomentum.boost(toNeutronRest);
171 bulletMomentum.boost(toNeutronRest);
172
173 G4InuclElementaryParticle projectile(bulletMomentum, bullet->getDefinition() );
174 G4InuclElementaryParticle targetNucleon(neutronMomentum, G4Neutron::Neutron() );
175 G4InuclElementaryParticle spectatorNucleon(protonMomentum, G4Proton::Proton() );
176
177 ScatteringProducts products = SingleNucleonScattering(projectile, targetNucleon);
178
179 // Particles from SingleNucleonScattering are in CM frame of projectile
180 // and moving neutron. Transform back to lab frame with -betacm, then add
181 // them to outgoing list
182 globalOutput.reset();
183 G4LorentzVector temp;
184 for (G4int i = 0; i < G4int(products.size()); i++) {
185 temp = products[i].getMomentum();
186 temp.boost(-betacm);
187 products[i].setMomentum(temp);
188 globalOutput.addOutgoingParticle(products[i]);
189 }
190
191 // Add the recoil nucleon unmodified
192 globalOutput.addOutgoingParticle(spectatorNucleon);
193
194 } else {
195 NucleonPair products = AbsorptionOnDeuteron(bullet);
196 globalOutput.reset();
197 globalOutput.addOutgoingParticle(products.first);
198 globalOutput.addOutgoingParticle(products.second);
199 }
200 } // Energy above threshold ?
201
202 // Test code
203 // G4int numPart = globalOutput.numberOfOutgoingParticles();
204 // std::vector<G4InuclElementaryParticle> testList = globalOutput.getOutgoingParticles();
205 // G4LorentzVector sumP;
206 // G4cout << " Global output " << G4endl;
207 // for (G4int i = 0; i < numPart; i++) {
208 // sumP += testList[i].getMomentum();
209 // G4cout << testList[i] << G4endl;
210 // }
211 // G4cout << " Global 4-momentum sum = " << sumP << G4endl;
212 // G4cout << " Initial lab energy = " << mD + bullet->getEnergy() << G4endl;
213
214 } else {
215 G4Exception("G4LightTargetCollider::collide()","HAD_BERT_203",
216 FatalException, "Scattering from this target not implemented");
217 }
218
219 return;
220}
221
222
223G4double G4LightTargetCollider::GammaDCrossSection(G4double gammaEnergy)
224{
225 // Gamma deuteron cross section in mb parameterized from JLab data
226 // No parameterization needed below pi0 threshold where cross section
227 // is 100% disintegration
228 G4double sigma = 1000.0;
229 G4double term = 0.;
230 if (gammaEnergy > 0.144 && gammaEnergy < 0.42) {
231 term = (gammaEnergy - 0.24)/0.155;
232 sigma = 0.065*std::exp(-term*term);
233 } else if (gammaEnergy >= 0.42) {
234 sigma = 0.000526/gammaEnergy/gammaEnergy/gammaEnergy/gammaEnergy;
235 }
236
237 return sigma;
238}
239
240
241NucleonPair G4LightTargetCollider::AbsorptionOnDeuteron(G4InuclParticle* bullet)
242{
243 // Do break-up in center of mass, convert to lab frame before returning
244 // particles
245
246 G4double bulletMass = bullet->getMass();
247 G4double bulletE = bullet->getEnergy();
248
249 G4double S = bulletMass*bulletMass + mD*mD + 2.*mD*bulletE;
250
251 G4double qcm = 0.;
252 G4int outType1 = 0;
253 G4int outType2 = 0;
254 G4LorentzVector Mom1;
255 G4LorentzVector Mom2;
256
257 // Set up outgoing particle types
258 if (bullet->getDefinition() == G4Gamma::Gamma() ||
259 bullet->getDefinition() == G4PionZero::PionZero() ) {
260 qcm = std::sqrt( (S - (mP + mN)*(mP + mN)) * (S - (mP - mN)*(mP - mN))/S/4.);
261 Mom1.setE(std::sqrt(mP*mP + qcm*qcm) );
263 Mom2.setE(std::sqrt(mN*mN + qcm*qcm) );
265
266 } else if (bullet->getDefinition() == G4PionPlus::PionPlus() ) {
267 qcm = std::sqrt( (S - 4.*mP*mP)/4.);
268 Mom1.setE(std::sqrt(mP*mP + qcm*qcm) );
270 Mom2.setE(std::sqrt(mP*mP + qcm*qcm) );
272
273 } else if (bullet->getDefinition() == G4PionMinus::PionMinus() ) {
274 qcm = std::sqrt( (S - 4.*mN*mN)/4.);
275 Mom1.setE(std::sqrt(mN*mN + qcm*qcm) );
277 Mom2.setE(std::sqrt(mN*mN + qcm*qcm) );
279
280 } else {
281 G4Exception("G4LightTargetCollider::collide()","HAD_BERT_204",
282 FatalException, "Illegal bullet type");
283 }
284
285 // Sample angular distribution, assuming 100% S wave (no D-wave)
286 G4ThreeVector qVect = qcm*G4RandomDirection();
287 Mom1.setVect(qVect);
288 Mom2.setVect(-qVect);
289
290 // Boost to lab frame
291 G4ThreeVector betacm(0., 0., bullet->getMomModule()/(bulletE + mD) );
292 Mom1.boost(betacm);
293 Mom2.boost(betacm);
294
295 G4InuclElementaryParticle particle1(Mom1, outType1);
296 G4InuclElementaryParticle particle2(Mom2, outType2);
297 NucleonPair nucleon_pair(particle1, particle2);
298
299 // if pion, use parameterization of B.G. Ritchie, PRC 44, 533 (1991)
300 // Total cross section: 1/E + Lorentzian
301
302 return nucleon_pair;
303}
304
305
307G4LightTargetCollider::SingleNucleonScattering(const G4InuclElementaryParticle& projectile,
308 const G4InuclElementaryParticle& nucleon)
309{
310 // At this point projectile and nucleon momenta are in nucleon rest frame
311 G4int reactionIndex = G4InuclElementaryParticle::type(projectile.getDefinition() )
312 * G4InuclElementaryParticle::type(nucleon.getDefinition() );
313
314 const G4CascadeChannel* xsecTable = G4CascadeChannelTables::GetTable(reactionIndex);
315 G4double ke = projectile.getKineticEnergy();
316 G4int mult = xsecTable->getMultiplicity(ke);
317
318 std::vector<G4double> masses;
319 G4double mass = 0.0;
320 G4LorentzVector totalMom = projectile.getMomentum() + nucleon.getMomentum();
321 G4double Ecm = totalMom.mag();
322
323 std::vector<G4LorentzVector> cmMomenta;
324 std::vector<G4int> particle_kinds;
325 G4int itry = 0;
326 G4int itry_max = 200;
327 G4bool generate = true;
328
329 while (mult > 1) {
330 itry = 0;
331 generate = true;
332 while (generate && itry < itry_max) {
333 particle_kinds.clear();
334 xsecTable->getOutgoingParticleTypes(particle_kinds, mult, ke);
335 masses.clear();
336 for (G4int i = 0; i < mult; i++) {
337 mass = G4InuclElementaryParticle::getParticleMass(particle_kinds[i]);
338 masses.push_back(mass);
339 }
340
341 fsGen.Configure(const_cast<G4InuclElementaryParticle*>(&projectile),
342 const_cast<G4InuclElementaryParticle*>(&nucleon),
343 particle_kinds);
344 // Generate final state in CM of projectile and at-rest nucleon
345 cmMomenta.clear();
346 generate = !fsGen.Generate(Ecm, masses, cmMomenta);
347 itry++;
348 } // while
349
350 if (itry == itry_max) mult--;
351 else break;
352
353 } // while mult
354
355 ScatteringProducts finalState;
356 if (mult < 2) {
357 G4Exception("G4LightTargetCollider::SingleNucleonScattering()","HAD_BERT_202",
358 JustWarning, "Failed to generate final state");
359 // Final state particles not in CM - just using them as dummies
360 finalState.push_back(projectile);
361 finalState.push_back(nucleon);
362
363 } else {
364 for (G4int i = 0; i < mult; i++) {
365 G4InuclElementaryParticle fsPart(cmMomenta[i], particle_kinds[i]);
366 finalState.push_back(fsPart);
367 }
368 }
369
370 return finalState;
371}
G4double S(G4double temp)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::vector< G4InuclElementaryParticle > ScatteringProducts
std::pair< G4InuclElementaryParticle, G4InuclElementaryParticle > NucleonPair
G4ThreeVector G4RandomDirection()
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#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 setVect(const Hep3Vector &)
Hep3Vector findBoostToCM() const
static const G4CascadeChannel * GetTable(G4int initialState)
virtual G4int getMultiplicity(G4double ke) const =0
virtual G4double getCrossSection(double ke) const =0
virtual void getOutgoingParticleTypes(std::vector< G4int > &kinds, G4int mult, G4double ke) const =0
virtual void setVerboseLevel(G4int verbose=0)
void Configure(G4InuclElementaryParticle *bullet, G4InuclElementaryParticle *target, const std::vector< G4int > &particle_kinds)
G4int numberOfOutgoingParticles() const
void addOutgoingParticle(const G4InuclElementaryParticle &particle)
void setVerboseLevel(G4int verbose)
void trivialise(G4InuclParticle *bullet, G4InuclParticle *target)
static G4Deuteron * Deuteron()
Definition: G4Deuteron.cc:93
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
static G4Gamma * Gamma()
Definition: G4Gamma.cc:85
G4bool Generate(G4double initialMass, const std::vector< G4double > &masses, std::vector< G4LorentzVector > &finalState)
static G4double getParticleMass(G4int type)
const G4ParticleDefinition * getDefinition() const
G4double getKineticEnergy() const
G4double getMass() const
G4LorentzVector getMomentum() const
G4double getMomModule() const
G4double getEnergy() const
void setVerboseLevel(G4int verbose=0)
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &globalOutput)
static G4Neutron * Neutron()
Definition: G4Neutron.cc:103
const G4String & GetParticleName() const
static G4PionMinus * PionMinus()
Definition: G4PionMinus.cc:97
static G4PionPlus * PionPlus()
Definition: G4PionPlus.cc:97
static G4PionZero * PionZero()
Definition: G4PionZero.cc:107
static G4Proton * Proton()
Definition: G4Proton.cc:92
void generate(const G4double sqrtS, ParticleList &particles)
Generate an event in the CM system.
G4bool nucleon(G4int ityp)