Geant4 Cross Reference |
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 // 080721 Create adjust_final_state method by T. Koi 28 // 080801 Residual reconstruction with theNDLDataA,Z (A, Z, and momentum are adjusted) by T. Koi 29 // 101110 Set lower limit for gamma energy(1keV) by T. Koi 30 // P. Arce, June-2014 Conversion neutron_hp to particle_hp 31 // 32 33 #include "G4ParticleHPFinalState.hh" 34 35 #include "G4Alpha.hh" 36 #include "G4Deuteron.hh" 37 #include "G4Gamma.hh" 38 #include "G4He3.hh" 39 #include "G4IonTable.hh" 40 #include "G4Neutron.hh" 41 #include "G4PhysicalConstants.hh" 42 #include "G4Proton.hh" 43 #include "G4RandomDirection.hh" 44 #include "G4SystemOfUnits.hh" 45 #include "G4Triton.hh" 46 47 G4ParticleHPFinalState::G4ParticleHPFinalState() 48 { 49 theProjectile = G4Neutron::Neutron(); 50 theResult.Put(nullptr); 51 fManager = G4ParticleHPManager::GetInstance(); 52 ionTable = G4IonTable::GetIonTable(); 53 } 54 55 G4ParticleHPFinalState::~G4ParticleHPFinalState() 56 { 57 delete theResult.Get(); 58 } 59 60 void G4ParticleHPFinalState::adjust_final_state(G4LorentzVector init_4p_lab) 61 { 62 G4double minimum_energy = 1 * keV; 63 64 if (fManager->GetDoNotAdjustFinalState()) return; 65 66 auto nSecondaries = (G4int)theResult.Get()->GetNumberOfSecondaries(); 67 68 G4int sum_Z = 0; 69 G4int sum_A = 0; 70 G4int max_SecZ = 0; 71 G4int max_SecA = 0; 72 G4int imaxA = -1; 73 for (G4int i = 0; i < nSecondaries; ++i) { 74 auto ptr = theResult.Get()->GetSecondary(i)->GetParticle()->GetDefinition(); 75 sum_Z += ptr->GetAtomicNumber(); 76 max_SecZ = std::max(max_SecZ, ptr->GetAtomicNumber()); 77 sum_A += ptr->GetAtomicMass(); 78 max_SecA = std::max(max_SecA, ptr->GetAtomicMass()); 79 if (ptr->GetAtomicMass() == max_SecA) 80 imaxA = i; 81 #ifdef G4PHPDEBUG 82 if (fManager->GetDEBUG()) 83 G4cout << "G4ParticleHPFinalState::adjust_final_stat SECO " << i << " " 84 << ptr->GetParticleName() << G4endl; 85 #endif 86 } 87 88 G4ParticleDefinition* resi_pd = nullptr; 89 90 G4int baseZNew = theBaseZ; 91 G4int baseANew = theBaseA; 92 if (theProjectile == G4Neutron::Neutron()) { 93 baseANew++; 94 } 95 else if (theProjectile == G4Proton::Proton()) { 96 baseZNew++; 97 baseANew++; 98 } 99 else if (theProjectile == G4Deuteron::Deuteron()) { 100 baseZNew++; 101 baseANew += 2; 102 } 103 else if (theProjectile == G4Triton::Triton()) { 104 baseZNew++; 105 baseANew += 3; 106 } 107 else if (theProjectile == G4He3::He3()) { 108 baseZNew += 2; 109 baseANew += 3; 110 } 111 else if (theProjectile == G4Alpha::Alpha()) { 112 baseZNew += 2; 113 baseANew += 4; 114 } 115 116 #ifdef G4PHPDEBUG 117 if (fManager->GetDEBUG()) 118 G4cout << "G4ParticleHPFinalState::adjust_final_stat BaseZ " << baseZNew << " BaseA " 119 << baseANew << " sum_Z " << sum_Z << " sum_A " << sum_A << G4endl; 120 #endif 121 122 G4bool needOneMoreSec = false; 123 G4ParticleDefinition* oneMoreSec_pd = nullptr; 124 if (baseZNew == sum_Z && baseANew == sum_A) { 125 // All secondaries are already created; 126 resi_pd = theResult.Get()->GetSecondary(imaxA)->GetParticle()->GetDefinition(); 127 } 128 else { 129 if (max_SecA >= baseANew - sum_A) { 130 // Most heavy secondary is interpreted as residual 131 resi_pd = theResult.Get()->GetSecondary(imaxA)->GetParticle()->GetDefinition(); 132 needOneMoreSec = true; 133 } 134 else { 135 // creation of residual is required 136 resi_pd = ionTable->GetIon(baseZNew - sum_Z, baseANew - sum_A, 0.0); 137 } 138 139 if (needOneMoreSec) { 140 if (baseZNew == sum_Z && baseANew == sum_A) { 141 // In this case, one neutron is added to secondaries 142 if (baseANew - sum_A > 1) 143 G4cout << "More than one neutron is required for the balance of baryon number!" 144 << G4endl; 145 oneMoreSec_pd = G4Neutron::Neutron(); 146 } 147 else { 148 #ifdef G4PHPDEBUG 149 if (fManager->GetDEBUG()) 150 G4cout << this << "G4ParticleHPFinalState oneMoreSec_pd Z " 151 << baseZNew << " - " << sum_Z 152 << " A " << baseANew << " - " << sum_A << " projectile " 153 << theProjectile->GetParticleName() << G4endl; 154 #endif 155 oneMoreSec_pd = 156 G4IonTable::GetIonTable()->GetIon(baseZNew - sum_Z, baseANew - sum_A, 0.0); 157 if (oneMoreSec_pd == nullptr) { 158 G4ExceptionDescription ed; 159 ed << "G4ParticleHPFinalState oneMoreSec_pd Z=" << baseZNew << " - " << sum_Z 160 << " A=" << baseANew << " - " << sum_A << " projectile " 161 << theProjectile->GetParticleName(); 162 G4Exception("G4ParticleHPFinalState:adjust_final_state", "hadr01", JustWarning, 163 ed, "No adjustment will be done!"); 164 return; 165 } 166 } 167 } 168 169 if (resi_pd == nullptr) { 170 // theNDLDataZ,A has the Z and A of used NDL file 171 G4int ndlZNew = theNDLDataZ; 172 G4int ndlANew = theNDLDataA; 173 if (theProjectile == G4Neutron::Neutron()) { 174 ndlANew++; 175 } 176 else if (theProjectile == G4Proton::Proton()) { 177 ndlZNew++; 178 ndlANew++; 179 } 180 else if (theProjectile == G4Deuteron::Deuteron()) { 181 ndlZNew++; 182 ndlANew += 2; 183 } 184 else if (theProjectile == G4Triton::Triton()) { 185 ndlZNew++; 186 ndlANew += 3; 187 } 188 else if (theProjectile == G4He3::He3()) { 189 ndlZNew += 2; 190 ndlANew += 3; 191 } 192 else if (theProjectile == G4Alpha::Alpha()) { 193 ndlZNew += 2; 194 ndlANew += 4; 195 } 196 // theNDLDataZ,A has the Z and A of used NDL file 197 if (ndlZNew == sum_Z && ndlANew == sum_A) { 198 G4int dif_Z = theNDLDataZ - theBaseZ; 199 G4int dif_A = theNDLDataA - theBaseA; 200 resi_pd = ionTable->GetIon(max_SecZ - dif_Z, max_SecA - dif_A, 0.0); 201 if (resi_pd == nullptr) { 202 G4ExceptionDescription ed; 203 ed << "resi_pd Z=" << max_SecZ << " - " << dif_Z << " A=" 204 << max_SecA << " - " << dif_A << " projectile " 205 << theProjectile->GetParticleName(); 206 G4Exception("G4ParticleHPFinalState:adjust_final_state", "hadr02", JustWarning, 207 ed, "No adjustment will be done!"); 208 return; 209 } 210 211 for (G4int i = 0; i < nSecondaries; ++i) { 212 auto ptr = theResult.Get()->GetSecondary(i)->GetParticle(); 213 if (ptr->GetDefinition()->GetAtomicNumber() == max_SecZ && 214 ptr->GetDefinition()->GetAtomicMass() == max_SecA) 215 { 216 G4ThreeVector p = ptr->GetMomentum() * resi_pd->GetPDGMass() 217 / ionTable->GetIon(max_SecZ, max_SecA, 0.0)->GetPDGMass(); 218 ptr->SetDefinition(resi_pd); 219 ptr->SetMomentum(p); 220 } 221 } 222 } 223 } 224 } 225 226 G4LorentzVector secs_4p_lab(0.0); 227 228 auto n_sec = (G4int)theResult.Get()->GetNumberOfSecondaries(); 229 G4double fast = 0; 230 G4double slow = 1; 231 G4int ifast = 0; 232 G4int islow = 0; 233 G4int ires = -1; 234 235 for (G4int i = 0; i < n_sec; ++i) { 236 auto ptr = theResult.Get()->GetSecondary(i)->GetParticle(); 237 secs_4p_lab += ptr->Get4Momentum(); 238 239 G4double beta = 0; 240 if (ptr->GetDefinition() != G4Gamma::Gamma()) { 241 beta = ptr->Get4Momentum().beta(); 242 } 243 else { 244 beta = 1.0; 245 } 246 247 if (ptr->GetDefinition() == resi_pd) ires = i; 248 249 if (slow > beta && beta != 0) { 250 slow = beta; 251 islow = i; 252 } 253 254 if (fast <= beta) { 255 if (fast != 1) { 256 fast = beta; 257 ifast = i; 258 } 259 else { 260 // fast is already photon then check E 261 G4double e = ptr->Get4Momentum().e(); 262 if (e > theResult.Get()->GetSecondary(ifast)->GetParticle()->Get4Momentum().e()) { 263 // among photons, the highest E becomes the fastest 264 ifast = i; 265 } 266 } 267 } 268 } 269 270 G4LorentzVector dif_4p = init_4p_lab - secs_4p_lab; 271 272 G4LorentzVector p4(0); 273 if (ires == -1) { 274 // Create and Add Residual Nucleus 275 ires = nSecondaries; 276 nSecondaries += 1; 277 278 auto res = new G4DynamicParticle(resi_pd, dif_4p.v()); 279 theResult.Get()->AddSecondary(res, secID); 280 281 p4 = res->Get4Momentum(); 282 if (slow > p4.beta()) { 283 slow = p4.beta(); 284 islow = ires; 285 } 286 dif_4p = init_4p_lab - (secs_4p_lab + p4); 287 } 288 289 if (needOneMoreSec && oneMoreSec_pd != nullptr) 290 // 291 // fca: this is not a fix, this is a crash avoidance... 292 // fca: the baryon number is still wrong, most probably because it 293 // fca: should have been decreased, but since we could not create a particle 294 // fca: we just do not add it 295 // 296 { 297 nSecondaries += 1; 298 auto one = new G4DynamicParticle(oneMoreSec_pd, dif_4p.v()); 299 theResult.Get()->AddSecondary(one, secID); 300 p4 = one->Get4Momentum(); 301 if (slow > p4.beta()) { 302 slow = p4.beta(); 303 islow = nSecondaries - 1; // Because the first is 0th, so the last becomes "nSecondaries-1" 304 } 305 dif_4p = init_4p_lab - (secs_4p_lab + p4); 306 } 307 308 // Which is bigger dif_p or dif_e 309 310 if (dif_4p.v().mag() < std::abs(dif_4p.e())) { 311 // Adjust p 312 if (minimum_energy < dif_4p.v().mag() && dif_4p.v().mag() < 1 * MeV) { 313 nSecondaries += 1; 314 theResult.Get()->AddSecondary(new G4DynamicParticle(G4Gamma::Gamma(), dif_4p.v()), secID); 315 } 316 } 317 else { 318 // dif_p > dif_e 319 // at first momentum 320 // Move residual momentum 321 p4 = theResult.Get()->GetSecondary(ires)->GetParticle()->Get4Momentum(); 322 theResult.Get()->GetSecondary(ires)->GetParticle()->SetMomentum(p4.v() + dif_4p.v()); 323 dif_4p = init_4p_lab - 324 (secs_4p_lab - p4 + theResult.Get()->GetSecondary(ires)->GetParticle()->Get4Momentum()); 325 } 326 327 G4double dif_e = dif_4p.e() - (dif_4p.v()).mag(); 328 329 if (dif_e > 0) { 330 // create 2 gamma 331 332 nSecondaries += 2; 333 G4double e1 = (dif_4p.e() - dif_4p.v().mag()) / 2; 334 335 if (minimum_energy < e1) { 336 G4ThreeVector dir = G4RandomDirection(); 337 theResult.Get()->AddSecondary(new G4DynamicParticle(G4Gamma::Gamma(), e1 * dir), secID); 338 theResult.Get()->AddSecondary(new G4DynamicParticle(G4Gamma::Gamma(), -e1 * dir), secID); 339 } 340 } 341 else // dif_e < 0 342 { 343 // At first reduce KE of the fastest secondary; 344 auto ptr = theResult.Get()->GetSecondary(ifast)->GetParticle(); 345 G4double ke0 = ptr->GetKineticEnergy(); 346 G4ThreeVector p0 = ptr->GetMomentum(); 347 G4ThreeVector dir = p0.unit(); 348 349 if (ke0 + dif_e > 0) { 350 ptr->SetKineticEnergy(ke0 + dif_e); 351 G4ThreeVector dp = p0 - theResult.Get()->GetSecondary(ifast)->GetParticle()->GetMomentum(); 352 G4ThreeVector p = theResult.Get()->GetSecondary(islow)->GetParticle()->GetMomentum(); 353 theResult.Get()->GetSecondary(islow)->GetParticle()->SetMomentum(p + dp); 354 } 355 } 356 } 357