Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4CRCoalescence.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//
29// ClassName: G4CRCoalescence ("CR" stands for "Cosmic Ray")
30//
31// Author: 2020 Alberto Ribon , based on code written by
32// Diego Mauricio Gomez Coral for the GAPS Collaboration
33//
34// Description: This class can be optionally used in the method:
35//
36// G4TheoFSGenerator::ApplyYourself
37//
38// to coalesce pairs of proton-neutron and antiproton-antineutron
39// into deuterons and antideuterons, respectively, from the list
40// of secondaries produced by a string model.
41// This class can be useful in particular for Cosmic Ray (CR)
42// applications.
43// By default, this class is not used.
44// However, it can be enabled via the UI command:
45//
46// /process/had/enableCRCoalescence true
47//
48// It is assumed that the candidate proton-neutron and
49// antiproton-antideuteron pairs originate from the same
50// spatial position, so the condition for coalescence takes
51// into account only their closeness in momentum space.
52//
53// This class is based entirely on code written by
54// Diego Mauricio Gomez Coral for the GAPS Collaboration.
55// The main application of this work is for cosmic ray physics.
56//
57// Notes:
58// - In its current version, coalescence can occur only for
59// proton projectile (because the coalescence parameters
60// for deuteron and antideuteron are set to non-null values
61// only for the case of proton projectile).
62// - This class is not meant be used for secondaries produces
63// by intranuclear cascade models - such as BERT, BIC and
64// INCL - which should have already a coalescence phase.
65//
66// Modified:
67//
68//----------------------------------------------------------------------------
69//
70#include "G4DynamicParticle.hh"
71#include "G4Proton.hh"
72#include "G4Neutron.hh"
73#include "G4Deuteron.hh"
74#include "G4AntiProton.hh"
75#include "G4AntiNeutron.hh"
76#include "G4CRCoalescence.hh"
77#include "G4ReactionProduct.hh"
78#include "G4IonTable.hh"
79
80
82 fP0_d( 0.0 ), fP0_dbar( 0.0 ) {}
83
84
86
87
88void G4CRCoalescence::SetP0Coalescence( const G4HadProjectile &thePrimary, G4String /* model */ ) {
89 // Note by A.R. : in the present version, the coalescence parameters are set only for
90 // proton projectile. If we want to extend this coalescence algorithm
91 // for other applications, besides cosmic rays, we need to set these
92 // coalescence parameters also for all projectiles.
93 // (Note that the method "GenerateDeuterons", instead, can be already used
94 // as it is for all projectiles.)
95 fP0_dbar = 0.0;
96 fP0_d = 0.0;
97 if ( thePrimary.GetDefinition()->GetPDGEncoding() == 2212 ) { // proton
98 G4double mproj = thePrimary.GetDefinition()->GetPDGMass();
99 G4double pz = thePrimary.Get4Momentum().z();
100 G4double ekin = std::sqrt( pz*pz + mproj*mproj ) - mproj;
101 if ( ekin > 10.0 ) {
102 fP0_dbar = 130.0 / ( 1.0 + std::exp( 21.6 - std::log( 0.001*ekin )/0.089 ) ); // set p0 for antideuteron
103 fP0_d = 118.1 * ( 1.0 + std::exp( 5.53 - std::log( 0.001*ekin )/0.43 ) ); // set p0 for deuteron
104 }
105 }
106 //G4cout << "Coalescence parameter p0 deuteron / antideuteron: " << fP0_d << " / " << fP0_dbar << G4endl;
107}
108
109
111 // Deuteron clusters are made with the first nucleon pair that fulfills
112 // the coalescence conditions, starting with the protons.
113 // A deuteron is a pair (i,j) where i is the proton and j the neutron in current event
114 // with the relative momentum less than p0 (i.e. within a sphere of radius p0).
115 // The same applies for antideuteron clusters, with antiprotons and antineutrons,
116 // instead of protons and neutrons, respectively.
117
118 // Vectors of index-position and 3-momentum pairs for, respectively:
119 // protons, neutrons, antiprotons and antineutrons
120 std::vector< std::pair< G4int, G4ThreeVector > > proton;
121 std::vector< std::pair< G4int, G4ThreeVector > > neutron;
122 std::vector< std::pair< G4int, G4ThreeVector > > antiproton;
123 std::vector< std::pair< G4int, G4ThreeVector > > antineutron;
124 for ( unsigned int i = 0; i < result->size(); ++i ) {
125 G4int pdgid = result->operator[](i)->GetDefinition()->GetPDGEncoding();
126 if ( pdgid == 2212 ) { // proton
127 proton.push_back( std::make_pair( i, result->operator[](i)->GetMomentum() ) );
128 result->erase( result->begin() + i );
129 }
130 }
131 for ( unsigned int i = 0; i < result->size(); ++i ) {
132 G4int pdgid = result->operator[](i)->GetDefinition()->GetPDGEncoding();
133 if ( pdgid == 2112 ) { // neutron
134 neutron.push_back( std::make_pair( i, result->operator[](i)->GetMomentum() ) );
135 result->erase( result->begin() + i );
136 }
137 }
138 for ( unsigned int i = 0; i < result->size(); ++i ) {
139 G4int pdgid = result->operator[](i)->GetDefinition()->GetPDGEncoding();
140 if ( pdgid == -2212 ) { // antiproton
141 antiproton.push_back( std::make_pair( i, result->operator[](i)->GetMomentum() ) );
142 result->erase( result->begin() + i );
143 }
144 }
145 for ( unsigned int i = 0; i < result->size(); ++i ) {
146 G4int pdgid = result->operator[](i)->GetDefinition()->GetPDGEncoding();
147 if ( pdgid == -2112 ) { // antineutron
148 antineutron.push_back( std::make_pair( i, result->operator[](i)->GetMomentum() ) );
149 result->erase( result->begin() + i );
150 }
151 }
152
153 for ( unsigned int i = 0; i < proton.size(); ++i ) { // loop over protons
154 if ( proton.at(i).first == -1 ) continue;
155 G4ThreeVector p1 = proton.at(i).second;
156 int partner1 = FindPartner( p1, G4Proton::Proton()->GetPDGMass(), neutron,
157 G4Neutron::Neutron()->GetPDGMass(), 1 );
158 if ( partner1 == -1 ) { // if no partner found, then the proton is a final-state secondary
161 finalp->SetDefinition( prt );
162 G4double massp = prt->GetPDGMass();
163 G4double totalEnergy = std::sqrt( p1.mag()*p1.mag() + massp*massp );
164 finalp->SetMomentum( p1 );
165 finalp->SetTotalEnergy( totalEnergy );
166 finalp->SetMass( massp );
167 result->push_back( finalp );
168 continue;
169 }
170 G4ThreeVector p2 = neutron.at(partner1).second;
171 PushDeuteron( p1, p2, 1, result );
172 neutron.at(partner1).first = -1; // tag the bound neutron
173 }
174
175 for ( unsigned int i = 0; i < neutron.size(); ++i ) { // loop over neutrons
176 if ( neutron.at(i).first == -1 ) continue; // Skip already bound neutron, else it is a final-state secondary
179 finaln->SetDefinition( nrt );
180 G4ThreeVector p2 = neutron.at(i).second;
181 G4double massn = nrt->GetPDGMass();
182 G4double totalEnergy = std::sqrt( p2.mag()*p2.mag() + massn*massn );
183 finaln->SetMomentum( p2 );
184 finaln->SetTotalEnergy( totalEnergy );
185 finaln->SetMass( massn );
186 result->push_back( finaln );
187 }
188
189 for ( unsigned int i = 0; i < antiproton.size(); ++i ) { // loop over antiprotons
190 if ( antiproton.at(i).first == -1 ) continue;
191 G4ThreeVector p1 = antiproton.at(i).second;
192 int partner1 = FindPartner( p1, G4Proton::Proton()->GetPDGMass(), antineutron,
193 G4Neutron::Neutron()->GetPDGMass(), -1 );
194 if ( partner1 == -1 ) { // if no partner found, then the antiproton is a final-state secondary
196 G4ReactionProduct* finalpbar = new G4ReactionProduct;
197 finalpbar->SetDefinition( pbar );
198 G4double massp = pbar->GetPDGMass();
199 G4double totalEnergy = std::sqrt( p1.mag()*p1.mag() + massp*massp );
200 finalpbar->SetMomentum( p1 );
201 finalpbar->SetTotalEnergy( totalEnergy );
202 finalpbar->SetMass( massp );
203 result->push_back( finalpbar );
204 continue;
205 }
206 G4ThreeVector p2 = antineutron.at(partner1).second;
207 PushDeuteron( p1, p2, -1, result );
208 antineutron.at(partner1).first = -1; // tag the bound antineutron
209 }
210
211 for ( unsigned int i = 0; i < antineutron.size(); ++i ) { // loop over antineutrons
212 if ( antineutron.at(i).first == -1 ) continue; // Skip already bound antineutron, else it is a final-state secondary
214 G4ReactionProduct* finalnbar = new G4ReactionProduct;
215 finalnbar->SetDefinition( nbar );
216 G4ThreeVector p2 = antineutron.at(i).second;
217 G4double massn = nbar->GetPDGMass();
218 G4double totalEnergy = std::sqrt( p2.mag()*p2.mag() + massn*massn );
219 finalnbar->SetMomentum( p2 );
220 finalnbar->SetTotalEnergy( totalEnergy );
221 finalnbar->SetMass( massn );
222 result->push_back( finalnbar );
223 }
224}
225
226
227void G4CRCoalescence::PushDeuteron( const G4ThreeVector &p1, const G4ThreeVector &p2, G4int charge, // input
228 G4ReactionProductVector* result ) { // output
229 // Create a deuteron or antideuteron (depending on "charge") object (of type G4ReactionProduct)
230 // from the two input momenta "p1" and "p2", and push it to the vector "result".
231 if ( charge > 0 ) {
233 G4ReactionProduct* finaldeut = new G4ReactionProduct;
234 finaldeut->SetDefinition( deuteron );
235 G4ThreeVector psum = p1 + p2;
236 G4double massd = deuteron->GetPDGMass();
237 G4double totalEnergy = std::sqrt( psum.mag()*psum.mag() + massd*massd );
238 finaldeut->SetMomentum( psum );
239 finaldeut->SetTotalEnergy( totalEnergy );
240 finaldeut->SetMass( massd );
241 result->push_back( finaldeut );
242 } else {
244 G4ReactionProduct* finalantideut = new G4ReactionProduct;
245 finalantideut->SetDefinition( antideuteron );
246 G4ThreeVector psum = p1 + p2;
247 G4double massd = antideuteron->GetPDGMass();
248 G4double totalEnergy = std::sqrt( psum.mag()*psum.mag() + massd*massd );
249 finalantideut->SetMomentum( psum );
250 finalantideut->SetTotalEnergy( totalEnergy );
251 finalantideut->SetMass( massd );
252 result->push_back( finalantideut );
253 }
254}
255
256
257G4int G4CRCoalescence::FindPartner( const G4ThreeVector &p1, G4double m1,
258 std::vector< std::pair< G4int, G4ThreeVector > > &neutron,
259 G4double m2, G4int charge ) {
260 // Find a nucleon/antinucleon (depending on "charge") partner, from the input list "neutron"
261 // (which is a vector of either neutron or antineutron particles depending on "charge")
262 // within a sphere of radius p0 centered at the input momentum "p1"; exclude already bound
263 // particles (neutrons or antineutrons depending on "charge") of "neutron".
264 for ( unsigned int j = 0; j < neutron.size(); ++j ) {
265 if ( neutron.at(j).first == -1 ) continue; // skip already bound particle
266 G4ThreeVector p2 = neutron.at(j).second;
267 if ( ! Coalescence( p1, m1, p2, m2, charge ) ) continue;
268 return j;
269 }
270 return -1; // no partner found
271}
272
273
274G4bool G4CRCoalescence::Coalescence( const G4ThreeVector &p1, G4double m1,
275 const G4ThreeVector &p2, G4double m2, G4int charge ) {
276 // Returns true if the momenta of the two nucleons/antinucleons (depending on "charge") are
277 // inside of an sphere of radius p0 (assuming that the two particles are in the same spatial place).
278 return Coalescence( p1.x(), p1.y(), p1.z(), m1, p2.x(), p2.y(), p2.z(), m2, charge );
279}
280
281
282G4bool G4CRCoalescence::Coalescence( G4double p1x, G4double p1y, G4double p1z, G4double m1,
283 G4double p2x, G4double p2y, G4double p2z, G4double m2,
284 G4int charge ) {
285 // Returns true if the momenta of the two nucleons/antinucleons (depending on "charge") are
286 // inside of a sphere of radius p0 (assuming that the two particles are in the same spatial place).
287 G4double deltaP = GetPcm( p1x, p1y, p1z, m1, p2x, p2y, p2z, m2 );
288 if ( charge > 0 ) return ( deltaP < fP0_d );
289 else return ( deltaP < fP0_dbar );
290}
291
292
293G4double G4CRCoalescence::GetPcm( const G4ThreeVector& p1, G4double m1,
294 const G4ThreeVector& p2, G4double m2 ) {
295 // Momentum in the center-of-mass frame of two particles from LAB values.
296 return GetPcm( p1.x(), p1.y(), p1.z(), m1, p2.x(), p2.y(), p2.z(), m2 );
297}
298
299
300G4double G4CRCoalescence::GetPcm( G4double p1x, G4double p1y, G4double p1z, G4double m1,
301 G4double p2x, G4double p2y, G4double p2z, G4double m2 ) {
302 // Momentum in the center-of-mass frame of two particles from LAB values.
303 G4double scm = GetS( p1x, p1y, p1z, m1, p2x, p2y, p2z, m2 );
304 return std::sqrt( (scm - (m1-m2)*(m1-m2))*(scm - (m1+m2)*(m1+m2)) ) / (2.0*std::sqrt( scm ));
305}
306
307
308G4double G4CRCoalescence::GetS( G4double p1x, G4double p1y, G4double p1z, G4double m1,
309 G4double p2x, G4double p2y, G4double p2z, G4double m2 ) {
310 // Square of center-of-mass energy of two particles from LAB values.
311 G4double E1 = std::sqrt( p1x*p1x + p1y*p1y + p1z*p1z + m1*m1 );
312 G4double E2 = std::sqrt( p2x*p2x + p2y*p2y + p2z*p2z + m2*m2 );
313 return (E1+E2)*(E1+E2) - (p1x+p2x)*(p1x+p2x) - (p1y+p2y)*(p1y+p2y) - (p1z+p2z)*(p1z+p2z);
314}
std::vector< G4ReactionProduct * > G4ReactionProductVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
double z() const
double x() const
double y() const
double mag() const
void GenerateDeuterons(G4ReactionProductVector *result)
~G4CRCoalescence() override
void SetP0Coalescence(const G4HadProjectile &thePrimary, G4String)
const G4ParticleDefinition * GetDefinition() const
const G4LorentzVector & Get4Momentum() const
static G4Neutron * Neutron()
Definition: G4Neutron.cc:103
G4ParticleDefinition * FindParticle(G4int PDGEncoding)
static G4ParticleTable * GetParticleTable()
G4ParticleDefinition * FindAntiParticle(G4int PDGEncoding)
static G4Proton * Proton()
Definition: G4Proton.cc:92
void SetMomentum(const G4double x, const G4double y, const G4double z)
void SetTotalEnergy(const G4double en)
void SetDefinition(const G4ParticleDefinition *aParticleDefinition)
void SetMass(const G4double mas)