Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 ////////////////////////////////////////////// << 27 // << 28 // File: G4LENDInelastic.cc << 29 // Date: 24 March 2020 << 30 // Author: Dennis Wright << 31 // << 32 // Description: model for inelastic scatterin << 33 // gammas at energies of order 2 << 34 // This model uses GIDI particle << 35 // in spectrum mode. In this mo << 36 // for each possible particle ty << 37 // given interaction. Unlike Ge << 38 // consideration of event-by-eve << 39 // Indeed, forcing such conserva << 40 // introduces correlations and d << 41 // spectra which are not present << 42 // << 43 // In order to use GIDI data wit << 44 // minimal event-by-event baryon << 45 // enforced which allows deviati << 46 // giving warnings. Neither cha << 47 // conservation is enforced. Un << 48 // fragment (n, p, d, t, alpha) << 49 // after a large number of event << 50 // conservation also approach th << 51 // this limit. The mass, charge << 52 // large fragments, however, are << 53 // data very well. This is a re << 54 // baryon number conservation an << 55 // fragment spectra are correct. << 56 // << 57 ////////////////////////////////////////////// << 58 << 59 #include "G4LENDInelastic.hh" 26 #include "G4LENDInelastic.hh" >> 27 60 #include "G4SystemOfUnits.hh" 28 #include "G4SystemOfUnits.hh" 61 #include "G4Nucleus.hh" 29 #include "G4Nucleus.hh" 62 #include "G4IonTable.hh" 30 #include "G4IonTable.hh" 63 #include <algorithm> << 64 #include <random> << 65 31 66 G4HadFinalState* G4LENDInelastic::ApplyYoursel << 32 G4HadFinalState * G4LENDInelastic::ApplyYourself(const G4HadProjectile& aTrack, G4Nucleus& aTarg ) 67 << 68 { 33 { 69 G4ThreeVector projMom = aTrack.Get4Momentum( << 34 //return preco->ApplyYourself( aTrack, aTarg ); 70 G4double temp = aTrack.GetMaterial()->GetTem << 71 35 72 G4int iZ = aTarg.GetZ_asInt(); << 36 G4ThreeVector proj_p = aTrack.Get4Momentum().vect(); 73 G4int iA = aTarg.GetA_asInt(); << 74 G4int iM = 0; << 75 if (aTarg.GetIsotope() != nullptr) iM = aTar << 76 << 77 G4double ke = aTrack.GetKineticEnergy(); << 78 << 79 G4HadFinalState* theResult = &theParticleCha << 80 theResult->Clear(); << 81 << 82 G4GIDI_target* aGIDITarget = << 83 get_target_from_map(lend_manager->GetNucle << 84 if (aGIDITarget == nullptr) { << 85 // G4cout << " No target found " << G4endl; << 86 theParticleChange.Clear(); << 87 theParticleChange.SetStatusChange(isAlive) << 88 theParticleChange.SetEnergyChange(aTrack.G << 89 theParticleChange.SetMomentumChange(aTrack << 90 return &theParticleChange; << 91 } << 92 // return returnUnchanged(aTrack, theResult); << 93 << 94 // Get GIDI final state products for givern << 95 G4int loop(0); << 96 G4int loopMax = 1000; << 97 std::vector<G4GIDI_Product>* products; << 98 do { << 99 products = aGIDITarget->getOthersFinalStat << 100 loop++; << 101 } while (products == nullptr && loop < loopM << 102 << 103 // G4LENDInelastic accepts all light fragmen << 104 // and removes any heavy fragments which cau << 105 // Charge and energy non-conservation still << 106 // of events, this improves on average. << 107 << 108 if (loop > loopMax - 1) { << 109 // G4cout << " too many loops, return initi << 110 << 111 theParticleChange.Clear(); << 112 theParticleChange.SetStatusChange(isAlive) << 113 theParticleChange.SetEnergyChange(aTrack.G << 114 theParticleChange.SetMomentumChange(aTrack << 115 return &theParticleChange; << 116 << 117 // if (aTrack.GetDefinition() == G4Proton:: << 118 // aTrack.GetDefinition() == G4Neutron: << 119 // theResult = preco->ApplyYourself(aTra << 120 // } else { << 121 // theResult = returnUnchanged(aTrack, t << 122 // } << 123 << 124 } else { << 125 G4int iTotZ = iZ + aTrack.GetDefinition()- << 126 G4int iTotA = iA + aTrack.GetDefinition()- << 127 << 128 // Loop over GIDI products and separate li << 129 G4int GZtot(0); << 130 G4int GAtot(0); << 131 G4int productA(0); << 132 G4int productZ(0); << 133 std::vector<G4int> lightProductIndex; << 134 std::vector<G4int> heavyProductIndex; << 135 for (G4int i = 0; i < int( products->size( << 136 productA = (*products)[i].A; << 137 if (productA < 5) { << 138 lightProductIndex.push_back(i); << 139 GZtot += (*products)[i].Z; << 140 GAtot += productA; << 141 } else { << 142 heavyProductIndex.push_back(i); << 143 } << 144 } << 145 37 146 // Randomize order of heavies to correct s << 38 G4double temp = aTrack.GetMaterial()->GetTemperature(); 147 // std::random_shuffle(heavyProductIndex.b << 39 148 // std::cout << " Heavy product index befo << 40 //G4int iZ = int ( aTarg.GetZ() ); 149 // for (G4int i = 0; i < int(heavyProductI << 41 //G4int iA = int ( aTarg.GetN() ); 150 // std::cout << std::endl; << 42 //migrate to integer A and Z (GetN_asInt returns number of neutrons in the nucleus since this) 151 << 43 G4int iZ = aTarg.GetZ_asInt(); 152 auto rng = std::default_random_engine {}; << 44 G4int iA = aTarg.GetA_asInt(); 153 std::shuffle(heavyProductIndex.begin(), he << 45 //G4int iM = aTarg.GetM_asInt(); 154 << 46 G4int iM = 0; 155 // std::cout << " Heavy product index afte << 47 if ( aTarg.GetIsotope() != NULL ) { 156 // for (G4int i = 0; i < int(heavyProductI << 48 iM = aTarg.GetIsotope()->Getm(); 157 // std::cout << std::endl; << 49 } 158 << 50 //G4cout << "target: Z = " << iZ << " N = " << iA << G4endl; 159 std::vector<G4int> savedHeavyIndex; << 51 160 G4int itest(0); << 52 G4double ke = aTrack.GetKineticEnergy(); 161 for (G4int i = 0; i < int(heavyProductInde << 53 //G4cout << "projectile: KE = " << ke/MeV << " [MeV]" << G4endl; 162 itest = heavyProductIndex[i]; << 54 163 productA = (*products)[itest].A; << 55 G4HadFinalState* theResult = &theParticleChange; 164 productZ = (*products)[itest].Z; << 56 theResult->Clear(); 165 if ((GAtot + productA <= iTotA) && (GZto << 57 166 savedHeavyIndex.push_back(itest); << 58 G4GIDI_target* aTarget = get_target_from_map( lend_manager->GetNucleusEncoding( iZ , iA , iM ) ); 167 GZtot += productZ; << 59 if ( aTarget == NULL ) return returnUnchanged( aTrack , theResult ); 168 GAtot += productA; << 60 169 } << 61 std::vector<G4GIDI_Product>* products; 170 } << 62 for ( G4int i = 0 ; i != 1024 ; i++ ) { >> 63 products = aTarget->getOthersFinalState( ke*MeV, temp, MyRNG, NULL ); >> 64 if ( products != NULL ) break; >> 65 } >> 66 //return preco->ApplyYourself( aTrack, aTarg ); >> 67 >> 68 G4int iTotZ = iZ + aTrack.GetDefinition()->GetAtomicNumber(); >> 69 G4int iTotA = iA + aTrack.GetDefinition()->GetAtomicMass(); >> 70 >> 71 if ( products != NULL ) >> 72 { >> 73 //G4cout << "Using LENDModel" << G4endl; >> 74 >> 75 G4ThreeVector psum(0); >> 76 G4bool needResidual = true; >> 77 int totN = 0; >> 78 int totZ = 0; >> 79 for ( G4int j = 0; j < int( products->size() ); j++ ) >> 80 { >> 81 >> 82 G4int jZ = (*products)[j].Z; >> 83 G4int jA = (*products)[j].A; >> 84 G4int jm = (*products)[j].m; >> 85 //TK >> 86 //We need coordination LEND *products)[j].m and G4IonTable(Z,A,m) >> 87 //Excitation energy of isomer level is might (probably) different each other. >> 88 // >> 89 >> 90 //G4cout << "ZA = " << 1000 * (*products)[j].Z + (*products)[j].A << " EK = " >> 91 // << (*products)[j].kineticEnergy >> 92 // << " px " << (*products)[j].px >> 93 // << " py " << (*products)[j].py >> 94 // << " pz " << (*products)[j].pz >> 95 // << G4endl; >> 96 >> 97 iTotZ -= jZ; >> 98 iTotA -= jA; >> 99 >> 100 G4DynamicParticle* theSec = new G4DynamicParticle; >> 101 >> 102 if ( jA == 1 && jZ == 1 ) >> 103 { >> 104 theSec->SetDefinition( G4Proton::Proton() ); >> 105 totN += 1; >> 106 totZ += 1; >> 107 } >> 108 else if ( jA == 1 && jZ == 0 ) >> 109 { >> 110 theSec->SetDefinition( G4Neutron::Neutron() ); >> 111 totN += 1; >> 112 } >> 113 else if ( jZ > 0 ) >> 114 { >> 115 if ( jA != 0 ) >> 116 { >> 117 theSec->SetDefinition( G4IonTable::GetIonTable()->GetIon( jZ , jA , jm ) ); >> 118 totN += jA; >> 119 totZ += jZ; >> 120 } >> 121 else >> 122 { >> 123 theSec->SetDefinition( G4IonTable::GetIonTable()->GetIon( jZ , iA+aTrack.GetDefinition()->GetAtomicMass()-totN , jm ) ); >> 124 iTotZ -= jZ; >> 125 iTotA -= iA+aTrack.GetDefinition()->GetAtomicMass()-totN; >> 126 needResidual=false; >> 127 } >> 128 } >> 129 else >> 130 { >> 131 theSec->SetDefinition( G4Gamma::Gamma() ); >> 132 } >> 133 >> 134 G4ThreeVector p( (*products)[j].px*MeV , (*products)[j].py*MeV , (*products)[j].pz*MeV ); >> 135 psum += p; >> 136 if ( p.mag() == 0 ) p = proj_p - psum; >> 137 >> 138 theSec->SetMomentum( p ); >> 139 >> 140 theResult->AddSecondary( theSec ); >> 141 } >> 142 >> 143 if ( !( iTotZ == 0 && iTotA == 0 ) ) { >> 144 >> 145 if ( iTotZ >= 0 && iTotA > 0 ) { >> 146 if ( needResidual ) { >> 147 G4DynamicParticle* residual = new G4DynamicParticle; >> 148 if ( iTotZ > 0 ) { >> 149 residual->SetDefinition( G4IonTable::GetIonTable()->GetIon( iTotZ , iTotA ) ); >> 150 } else if ( iTotA == 1 ) { >> 151 residual->SetDefinition( G4Neutron::Neutron() ); >> 152 } else { >> 153 //G4cout << "Charge or Baryon Number Error #3 iTotZ = " << iTotZ << ", iTotA = " << iTotA << G4endl; >> 154 ; >> 155 } >> 156 residual->SetMomentum( proj_p - psum ); >> 157 theResult->AddSecondary( residual ); >> 158 } else { >> 159 //G4cout << "Charge or Baryon Number Error #1 iTotZ = " << iTotZ << ", iTotA = " << iTotA << G4endl; >> 160 ; >> 161 } >> 162 } else { >> 163 >> 164 if ( needResidual ) { >> 165 //G4cout << "Charge or Baryon Number Error #2 iTotZ = " << iTotZ << ", iTotA = " << iTotA << G4endl; >> 166 ; >> 167 } >> 168 } 171 169 172 /* << 173 G4cout << " saved light products = "; << 174 for (G4int k = 0; k < int(lightProductInde << 175 itest = lightProductIndex[k]; << 176 G4cout << "(" << (*products)[itest].Z << << 177 } << 178 G4cout << G4endl; << 179 << 180 G4cout << " saved heavy products = "; << 181 for (G4int k = 0; k < int(savedHeavyIndex. << 182 itest = savedHeavyIndex[k]; << 183 G4cout << "(" << (*products)[itest].Z << << 184 } << 185 G4cout << G4endl; << 186 */ << 187 // Now convert saved products to Geant4 pa << 188 // Note that, at least for heavy fragments << 189 // have slightly different values. << 190 << 191 G4DynamicParticle* theSec = nullptr; << 192 G4ThreeVector Psum; << 193 for (G4int i = 0; i < int(lightProductInde << 194 itest = lightProductIndex[i]; << 195 productZ = (*products)[itest].Z; << 196 productA = (*products)[itest].A; << 197 theSec = new G4DynamicParticle(); << 198 if (productA == 1 && productZ == 0) { << 199 theSec->SetDefinition(G4Neutron::Neutr << 200 } else if (productA == 1 && productZ == << 201 theSec->SetDefinition(G4Proton::Proton << 202 } else if (productA == 2 && productZ == << 203 theSec->SetDefinition(G4Deuteron::Deut << 204 } else if (productA == 3 && productZ == << 205 theSec->SetDefinition(G4Triton::Triton << 206 } else if (productA == 4 && productZ == << 207 theSec->SetDefinition(G4Alpha::Alpha() << 208 } else { << 209 theSec->SetDefinition(G4Gamma::Gamma() << 210 } 170 } 211 171 212 G4ThreeVector momentum((*products)[itest << 172 } 213 (*products)[itest << 173 else { 214 (*products)[itest << 174 //G4cout << "Using PreCompoundModel" << G4endl; 215 Psum += momentum; << 175 if ( aTrack.GetDefinition() == G4Proton::Proton() || 216 theSec->SetMomentum(momentum); << 176 aTrack.GetDefinition() == G4Neutron::Neutron() ) { 217 // theResult->AddSecondary(theSec); << 177 theResult = preco->ApplyYourself( aTrack, aTarg ); 218 theParticleChange.AddSecondary(theSec, s << 219 } << 220 << 221 G4int productM(0); << 222 for (G4int i = 0; i < int(savedHeavyIndex. << 223 itest = savedHeavyIndex[i]; << 224 productZ = (*products)[itest].Z; << 225 productA = (*products)[itest].A; << 226 productM = (*products)[itest].m; << 227 theSec = new G4DynamicParticle(); << 228 theSec->SetDefinition(G4IonTable::GetIon << 229 << 230 << 231 G4ThreeVector momentum((*products)[itest << 232 (*products)[itest << 233 (*products)[itest << 234 Psum += momentum; << 235 theSec->SetMomentum(momentum); << 236 // theResult->AddSecondary(theSec); << 237 theParticleChange.AddSecondary(theSec, s << 238 } << 239 << 240 // Create heavy fragment if necessary to t << 241 // Note: this step is only required to pre << 242 // where "catastrophic" non-conserva << 243 // The residual generated will not n << 244 // occur in the actual reaction. << 245 if (iTotA - GAtot > 1) { << 246 theSec = new G4DynamicParticle(); << 247 if (iTotZ == GZtot) { << 248 // Special case when a nucleus of only << 249 // Violate charge conservation and set << 250 // G4cout << " Z = 1, A = "<< iTotA - << 251 theSec->SetDefinition(G4IonTable::GetI << 252 } else { 178 } else { 253 theSec->SetDefinition(G4IonTable::GetI << 179 return theResult; 254 } 180 } 255 theSec->SetMomentum(projMom - Psum); << 181 } 256 // theResult->AddSecondary(theSec); << 182 delete products; 257 theParticleChange.AddSecondary(theSec, s << 183 258 } << 184 theResult->SetStatusChange( stopAndKill ); 259 } // loop OK << 185 260 << 186 return theResult; 261 delete products; << 187 262 // theResult->SetStatusChange( stopAndKill ); << 263 theParticleChange.SetStatusChange( stopAndKi << 264 // return theResult; << 265 return &theParticleChange; << 266 } 188 } 267 189