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 // ------------------------------------------- 26 // ------------------------------------------------------------ 27 // GEANT 4 class implementation file 27 // GEANT 4 class implementation file 28 // 28 // 29 // ---------------- G4Fancy3DNucleus ---- 29 // ---------------- G4Fancy3DNucleus ---------------- 30 // by Gunter Folger, May 1998. 30 // by Gunter Folger, May 1998. 31 // class for a 3D nucleus, arranging nuc 31 // class for a 3D nucleus, arranging nucleons in space and momentum. 32 // ------------------------------------------- 32 // ------------------------------------------------------------ 33 // 20110805 M. Kelsey -- Remove C-style array 33 // 20110805 M. Kelsey -- Remove C-style array (pointer) of G4Nucleons, 34 // make vector a container of objects. Mov 34 // make vector a container of objects. Move Helper class 35 // to .hh. Move testSums, places, momentum 35 // to .hh. Move testSums, places, momentum and fermiM to 36 // class data members for reuse. 36 // class data members for reuse. 37 37 38 #include <algorithm> 38 #include <algorithm> 39 39 40 #include "G4Fancy3DNucleus.hh" 40 #include "G4Fancy3DNucleus.hh" 41 #include "G4Fancy3DNucleusHelper.hh" 41 #include "G4Fancy3DNucleusHelper.hh" 42 #include "G4NuclearFermiDensity.hh" 42 #include "G4NuclearFermiDensity.hh" 43 #include "G4NuclearShellModelDensity.hh" 43 #include "G4NuclearShellModelDensity.hh" 44 #include "G4NucleiProperties.hh" 44 #include "G4NucleiProperties.hh" 45 #include "G4HyperNucleiProperties.hh" 45 #include "G4HyperNucleiProperties.hh" 46 #include "G4Nucleon.hh" 46 #include "G4Nucleon.hh" 47 #include "G4SystemOfUnits.hh" 47 #include "G4SystemOfUnits.hh" 48 #include "Randomize.hh" 48 #include "Randomize.hh" 49 #include "G4ios.hh" 49 #include "G4ios.hh" 50 #include "G4Pow.hh" 50 #include "G4Pow.hh" 51 #include "G4HadronicException.hh" 51 #include "G4HadronicException.hh" 52 52 53 #include "Randomize.hh" 53 #include "Randomize.hh" 54 #include "G4ThreeVector.hh" 54 #include "G4ThreeVector.hh" 55 #include "G4RandomDirection.hh" 55 #include "G4RandomDirection.hh" 56 #include "G4LorentzRotation.hh" 56 #include "G4LorentzRotation.hh" 57 #include "G4RotationMatrix.hh" 57 #include "G4RotationMatrix.hh" 58 #include "G4PhysicalConstants.hh" 58 #include "G4PhysicalConstants.hh" 59 59 60 G4Fancy3DNucleus::G4Fancy3DNucleus() 60 G4Fancy3DNucleus::G4Fancy3DNucleus() 61 : myA(0), myZ(0), myL(0), theNucleons(250), 61 : myA(0), myZ(0), myL(0), theNucleons(250), currentNucleon(-1), theDensity(0), 62 nucleondistance(0.8*fermi),excitationEnerg 62 nucleondistance(0.8*fermi),excitationEnergy(0.), 63 places(250), momentum(250), fermiM(250), t 63 places(250), momentum(250), fermiM(250), testSums(250) 64 { 64 { 65 } 65 } 66 66 67 G4Fancy3DNucleus::~G4Fancy3DNucleus() 67 G4Fancy3DNucleus::~G4Fancy3DNucleus() 68 { 68 { 69 if(theDensity) delete theDensity; 69 if(theDensity) delete theDensity; 70 } 70 } 71 71 72 #if defined(NON_INTEGER_A_Z) 72 #if defined(NON_INTEGER_A_Z) 73 void G4Fancy3DNucleus::Init(G4double theA, G4d 73 void G4Fancy3DNucleus::Init(G4double theA, G4double theZ, G4int numberOfLambdas) 74 { 74 { 75 G4int intZ = G4int(theZ); 75 G4int intZ = G4int(theZ); 76 G4int intA= ( G4UniformRand()>theA-G4int(the 76 G4int intA= ( G4UniformRand()>theA-G4int(theA) ) ? G4int(theA) : G4int(theA)+1; 77 // forward to integer Init() 77 // forward to integer Init() 78 Init(intA, intZ, std::max(numberOfLambdas, 0 78 Init(intA, intZ, std::max(numberOfLambdas, 0)); 79 79 80 } 80 } 81 #endif 81 #endif 82 82 83 void G4Fancy3DNucleus::Init(G4int theA, G4int 83 void G4Fancy3DNucleus::Init(G4int theA, G4int theZ, G4int numberOfLambdas) 84 { 84 { 85 currentNucleon=-1; 85 currentNucleon=-1; 86 theNucleons.clear(); 86 theNucleons.clear(); 87 nucleondistance = 0.8*fermi; 87 nucleondistance = 0.8*fermi; 88 places.clear(); 88 places.clear(); 89 momentum.clear(); 89 momentum.clear(); 90 fermiM.clear(); 90 fermiM.clear(); 91 testSums.clear(); 91 testSums.clear(); 92 92 93 myZ = theZ; 93 myZ = theZ; 94 myA = theA; 94 myA = theA; 95 myL = std::max(numberOfLambdas, 0); // Cann 95 myL = std::max(numberOfLambdas, 0); // Cannot be negative 96 excitationEnergy=0; 96 excitationEnergy=0; 97 97 98 theNucleons.resize(myA); // Pre-loads vecto 98 theNucleons.resize(myA); // Pre-loads vector with empty elements 99 99 100 // For simplicity, we neglect eventual Lambd 100 // For simplicity, we neglect eventual Lambdas in the nucleus as far as the 101 // density of nucler levels and the Fermi le 101 // density of nucler levels and the Fermi level are concerned. 102 102 103 if(theDensity) delete theDensity; 103 if(theDensity) delete theDensity; 104 if ( myA < 17 ) { 104 if ( myA < 17 ) { 105 theDensity = new G4NuclearShellModelDensi 105 theDensity = new G4NuclearShellModelDensity(myA, myZ); 106 if( myA == 12 ) nucleondistance=0.9*fermi 106 if( myA == 12 ) nucleondistance=0.9*fermi; 107 } else { 107 } else { 108 theDensity = new G4NuclearFermiDensity(my 108 theDensity = new G4NuclearFermiDensity(myA, myZ); 109 } 109 } 110 110 111 theFermi.Init(myA, myZ); 111 theFermi.Init(myA, myZ); 112 112 113 ChooseNucleons(); 113 ChooseNucleons(); 114 114 115 ChoosePositions(); 115 ChoosePositions(); 116 116 117 if( myA == 12 ) CenterNucleons(); // This 117 if( myA == 12 ) CenterNucleons(); // This would introduce a bias 118 118 119 ChooseFermiMomenta(); 119 ChooseFermiMomenta(); 120 120 121 G4double Ebinding= BindingEnergy()/myA; 121 G4double Ebinding= BindingEnergy()/myA; 122 122 123 for (G4int aNucleon=0; aNucleon < myA; aNucl 123 for (G4int aNucleon=0; aNucleon < myA; aNucleon++) 124 { 124 { 125 theNucleons[aNucleon].SetBindingEnergy(Ebind 125 theNucleons[aNucleon].SetBindingEnergy(Ebinding); 126 } 126 } 127 127 128 return; 128 return; 129 } 129 } 130 130 131 G4bool G4Fancy3DNucleus::StartLoop() 131 G4bool G4Fancy3DNucleus::StartLoop() 132 { 132 { 133 currentNucleon=0; 133 currentNucleon=0; 134 return (theNucleons.size()>0); 134 return (theNucleons.size()>0); 135 } 135 } 136 136 137 // Returns by pointer; null pointer indicates 137 // Returns by pointer; null pointer indicates end of loop 138 G4Nucleon * G4Fancy3DNucleus::GetNextNucleon() 138 G4Nucleon * G4Fancy3DNucleus::GetNextNucleon() 139 { 139 { 140 return ( (currentNucleon>=0 && currentNucleo 140 return ( (currentNucleon>=0 && currentNucleon<myA) ? 141 &theNucleons[currentNucleon++] : 0 ); 141 &theNucleons[currentNucleon++] : 0 ); 142 } 142 } 143 143 144 const std::vector<G4Nucleon> & G4Fancy3DNucleu 144 const std::vector<G4Nucleon> & G4Fancy3DNucleus::GetNucleons() 145 { 145 { 146 return theNucleons; 146 return theNucleons; 147 } 147 } 148 148 149 149 150 // Class-scope function to sort nucleons by Z 150 // Class-scope function to sort nucleons by Z coordinate 151 bool G4Fancy3DNucleusHelperForSortInZ(const G4 151 bool G4Fancy3DNucleusHelperForSortInZ(const G4Nucleon& nuc1, const G4Nucleon& nuc2) 152 { 152 { 153 return nuc1.GetPosition().z() < nuc2.GetPosi 153 return nuc1.GetPosition().z() < nuc2.GetPosition().z(); 154 } 154 } 155 155 156 void G4Fancy3DNucleus::SortNucleonsIncZ() 156 void G4Fancy3DNucleus::SortNucleonsIncZ() 157 { 157 { 158 if (theNucleons.size() < 2 ) return; // A 158 if (theNucleons.size() < 2 ) return; // Avoid unnecesary work 159 159 160 std::sort(theNucleons.begin(), theNucleons.e 160 std::sort(theNucleons.begin(), theNucleons.end(), 161 G4Fancy3DNucleusHelperForSortInZ); 161 G4Fancy3DNucleusHelperForSortInZ); 162 } 162 } 163 163 164 void G4Fancy3DNucleus::SortNucleonsDecZ() 164 void G4Fancy3DNucleus::SortNucleonsDecZ() 165 { 165 { 166 if (theNucleons.size() < 2 ) return; // A 166 if (theNucleons.size() < 2 ) return; // Avoid unnecessary work 167 SortNucleonsIncZ(); 167 SortNucleonsIncZ(); 168 168 169 std::reverse(theNucleons.begin(), theNucleon 169 std::reverse(theNucleons.begin(), theNucleons.end()); 170 } 170 } 171 171 172 172 173 G4double G4Fancy3DNucleus::BindingEnergy() 173 G4double G4Fancy3DNucleus::BindingEnergy() 174 { 174 { 175 return G4NucleiProperties::GetBindingEnergy( 175 return G4NucleiProperties::GetBindingEnergy(myA,myZ); 176 } 176 } 177 177 178 178 179 G4double G4Fancy3DNucleus::GetNuclearRadius() 179 G4double G4Fancy3DNucleus::GetNuclearRadius() 180 { 180 { 181 return GetNuclearRadius(0.5); 181 return GetNuclearRadius(0.5); 182 } 182 } 183 183 184 G4double G4Fancy3DNucleus::GetNuclearRadius(co 184 G4double G4Fancy3DNucleus::GetNuclearRadius(const G4double maxRelativeDensity) 185 { 185 { 186 return theDensity->GetRadius(maxRelativeDens 186 return theDensity->GetRadius(maxRelativeDensity); 187 } 187 } 188 188 189 G4double G4Fancy3DNucleus::GetOuterRadius() 189 G4double G4Fancy3DNucleus::GetOuterRadius() 190 { 190 { 191 G4double maxradius2=0; 191 G4double maxradius2=0; 192 192 193 for (int i=0; i<myA; i++) 193 for (int i=0; i<myA; i++) 194 { 194 { 195 if ( theNucleons[i].GetPosition().mag2() 195 if ( theNucleons[i].GetPosition().mag2() > maxradius2 ) 196 { 196 { 197 maxradius2=theNucleons[i].GetPosition(). 197 maxradius2=theNucleons[i].GetPosition().mag2(); 198 } 198 } 199 } 199 } 200 return std::sqrt(maxradius2)+nucleondistance 200 return std::sqrt(maxradius2)+nucleondistance; 201 } 201 } 202 202 203 G4double G4Fancy3DNucleus::GetMass() 203 G4double G4Fancy3DNucleus::GetMass() 204 { 204 { 205 if ( myL <= 0 ) return myZ*G4Proton::Proton( 205 if ( myL <= 0 ) return myZ*G4Proton::Proton()->GetPDGMass() + 206 (myA-myZ)*G4Neutron:: 206 (myA-myZ)*G4Neutron::Neutron()->GetPDGMass() - 207 BindingEnergy(); 207 BindingEnergy(); 208 else return G4HyperNucleiProperti 208 else return G4HyperNucleiProperties::GetNuclearMass(myA, myZ, myL); 209 } 209 } 210 210 211 211 212 212 213 void G4Fancy3DNucleus::DoLorentzBoost(const G4 213 void G4Fancy3DNucleus::DoLorentzBoost(const G4LorentzVector & theBoost) 214 { 214 { 215 for (G4int i=0; i<myA; i++){ 215 for (G4int i=0; i<myA; i++){ 216 theNucleons[i].Boost(theBoost); 216 theNucleons[i].Boost(theBoost); 217 } 217 } 218 } 218 } 219 219 220 void G4Fancy3DNucleus::DoLorentzBoost(const G4 220 void G4Fancy3DNucleus::DoLorentzBoost(const G4ThreeVector & theBeta) 221 { 221 { 222 for (G4int i=0; i<myA; i++){ 222 for (G4int i=0; i<myA; i++){ 223 theNucleons[i].Boost(theBeta); 223 theNucleons[i].Boost(theBeta); 224 } 224 } 225 } 225 } 226 226 227 void G4Fancy3DNucleus::DoLorentzContraction(co 227 void G4Fancy3DNucleus::DoLorentzContraction(const G4ThreeVector & theBeta) 228 { 228 { 229 G4double beta2=theBeta.mag2(); 229 G4double beta2=theBeta.mag2(); 230 if (beta2 > 0) { 230 if (beta2 > 0) { 231 G4double factor=(1-std::sqrt(1-beta2))/be 231 G4double factor=(1-std::sqrt(1-beta2))/beta2; // (gamma-1)/gamma/beta**2 232 G4ThreeVector rprime; 232 G4ThreeVector rprime; 233 for (G4int i=0; i< myA; i++) { 233 for (G4int i=0; i< myA; i++) { 234 rprime = theNucleons[i].GetPosition() - 234 rprime = theNucleons[i].GetPosition() - 235 factor * (theBeta*theNucleons[i].GetP 235 factor * (theBeta*theNucleons[i].GetPosition()) * theBeta; 236 theNucleons[i].SetPosition(rprime); 236 theNucleons[i].SetPosition(rprime); 237 } 237 } 238 } 238 } 239 } 239 } 240 240 241 void G4Fancy3DNucleus::DoLorentzContraction(co 241 void G4Fancy3DNucleus::DoLorentzContraction(const G4LorentzVector & theBoost) 242 { 242 { 243 if (theBoost.e() !=0 ) { 243 if (theBoost.e() !=0 ) { 244 G4ThreeVector beta = theBoost.vect()/theB 244 G4ThreeVector beta = theBoost.vect()/theBoost.e(); 245 DoLorentzContraction(beta); 245 DoLorentzContraction(beta); 246 } 246 } 247 } 247 } 248 248 249 249 250 250 251 void G4Fancy3DNucleus::CenterNucleons() 251 void G4Fancy3DNucleus::CenterNucleons() 252 { 252 { 253 G4ThreeVector center; 253 G4ThreeVector center; 254 254 255 for (G4int i=0; i<myA; i++ ) 255 for (G4int i=0; i<myA; i++ ) 256 { 256 { 257 center+=theNucleons[i].GetPosition(); 257 center+=theNucleons[i].GetPosition(); 258 } 258 } 259 center /= -myA; 259 center /= -myA; 260 DoTranslation(center); 260 DoTranslation(center); 261 } 261 } 262 262 263 void G4Fancy3DNucleus::DoTranslation(const G4T 263 void G4Fancy3DNucleus::DoTranslation(const G4ThreeVector & theShift) 264 { 264 { 265 G4ThreeVector tempV; 265 G4ThreeVector tempV; 266 for (G4int i=0; i<myA; i++ ) 266 for (G4int i=0; i<myA; i++ ) 267 { 267 { 268 tempV = theNucleons[i].GetPosition() + t 268 tempV = theNucleons[i].GetPosition() + theShift; 269 theNucleons[i].SetPosition(tempV); 269 theNucleons[i].SetPosition(tempV); 270 } 270 } 271 } 271 } 272 272 273 const G4VNuclearDensity * G4Fancy3DNucleus::Ge 273 const G4VNuclearDensity * G4Fancy3DNucleus::GetNuclearDensity() const 274 { 274 { 275 return theDensity; 275 return theDensity; 276 } 276 } 277 277 278 //----------------------- private Implementati 278 //----------------------- private Implementation Methods------------- 279 279 280 void G4Fancy3DNucleus::ChooseNucleons() 280 void G4Fancy3DNucleus::ChooseNucleons() 281 { 281 { 282 G4int protons=0, nucleons=0, lambdas=0; 282 G4int protons=0, nucleons=0, lambdas=0; 283 G4double probProton = ( G4double(myZ) )/( G4 283 G4double probProton = ( G4double(myZ) )/( G4double(myA) ); 284 G4double probLambda = myL > 0 ? ( G4double(m 284 G4double probLambda = myL > 0 ? ( G4double(myL) )/( G4double(myA) ) : 0.0; 285 while ( nucleons < myA ) { /* Loop checking 285 while ( nucleons < myA ) { /* Loop checking, 30-Oct-2015, G.Folger */ 286 G4double rnd = G4UniformRand(); 286 G4double rnd = G4UniformRand(); 287 if ( rnd < probProton ) { 287 if ( rnd < probProton ) { 288 if ( protons < myZ ) { 288 if ( protons < myZ ) { 289 protons++; 289 protons++; 290 theNucleons[nucleons++].SetParticleType(G4Pr 290 theNucleons[nucleons++].SetParticleType(G4Proton::Proton()); 291 } 291 } 292 } else if ( rnd < probProton + probLambda 292 } else if ( rnd < probProton + probLambda ) { 293 if ( lambdas < myL ) { 293 if ( lambdas < myL ) { 294 lambdas++; 294 lambdas++; 295 theNucleons[nucleons++].SetParticleType(G4La 295 theNucleons[nucleons++].SetParticleType(G4Lambda::Lambda()); 296 } 296 } 297 } else { 297 } else { 298 if ( (nucleons - protons - lambdas) < (m 298 if ( (nucleons - protons - lambdas) < (myA - myZ - myL) ) { 299 theNucleons[nucleons++].SetParticleType(G4Ne 299 theNucleons[nucleons++].SetParticleType(G4Neutron::Neutron()); 300 } 300 } 301 } 301 } 302 } 302 } 303 return; 303 return; 304 } 304 } 305 305 306 void G4Fancy3DNucleus::ChoosePositions() 306 void G4Fancy3DNucleus::ChoosePositions() 307 { 307 { 308 if( myA != 12) { 308 if( myA != 12) { 309 309 310 G4int i=0; 310 G4int i=0; 311 G4ThreeVector aPos, delta; 311 G4ThreeVector aPos, delta; 312 G4bool freeplace; 312 G4bool freeplace; 313 const G4double nd2=sqr(nucleondistance); 313 const G4double nd2=sqr(nucleondistance); 314 G4double maxR=GetNuclearRadius(0.001); / 314 G4double maxR=GetNuclearRadius(0.001); // there are no nucleons at a 315 // rel 315 // relative Density of 0.01 316 G4int jr=0; 316 G4int jr=0; 317 G4int jx,jy; 317 G4int jx,jy; 318 G4double arand[600]; 318 G4double arand[600]; 319 G4double *prand=arand; 319 G4double *prand=arand; 320 places.clear(); // Reset data buffer 320 places.clear(); // Reset data buffer 321 G4int interationsLeft=1000*myA; 321 G4int interationsLeft=1000*myA; 322 while ( (i < myA) && (--interationsLeft>0) 322 while ( (i < myA) && (--interationsLeft>0)) /* Loop checking, 30-Oct-2015, G.Folger */ 323 { 323 { 324 do 324 do 325 { 325 { 326 if ( jr < 3 ) 326 if ( jr < 3 ) 327 { 327 { 328 jr=std::min(600,9*(myA - i)); 328 jr=std::min(600,9*(myA - i)); 329 G4RandFlat::shootArray(jr,prand); 329 G4RandFlat::shootArray(jr,prand); 330 //CLHEP::RandFlat::shootArray(jr, prand ); 330 //CLHEP::RandFlat::shootArray(jr, prand ); 331 } 331 } 332 jx=--jr; 332 jx=--jr; 333 jy=--jr; 333 jy=--jr; 334 aPos.set((2*arand[jx]-1.), (2*arand[jy]-1.), 334 aPos.set((2*arand[jx]-1.), (2*arand[jy]-1.), (2*arand[--jr]-1.)); 335 } while (aPos.mag2() > 1. ); /* Loop ch 335 } while (aPos.mag2() > 1. ); /* Loop checking, 30-Oct-2015, G.Folger */ 336 aPos *=maxR; 336 aPos *=maxR; 337 G4double density=theDensity->GetRelative 337 G4double density=theDensity->GetRelativeDensity(aPos); 338 if (G4UniformRand() < density) 338 if (G4UniformRand() < density) 339 { 339 { 340 freeplace= true; 340 freeplace= true; 341 std::vector<G4ThreeVector>::iterator iplace; 341 std::vector<G4ThreeVector>::iterator iplace; 342 for( iplace=places.begin(); iplace!=places.e 342 for( iplace=places.begin(); iplace!=places.end() && freeplace;++iplace) 343 { 343 { 344 delta = *iplace - aPos; 344 delta = *iplace - aPos; 345 freeplace= delta.mag2() > nd2; 345 freeplace= delta.mag2() > nd2; 346 } 346 } 347 if ( freeplace ) { 347 if ( freeplace ) { 348 G4double pFermi=theFermi.GetFermiMom 348 G4double pFermi=theFermi.GetFermiMomentum(theDensity->GetDensity(aPos)); 349 // protons must at least have bindin 349 // protons must at least have binding energy of CoulombBarrier, so 350 // assuming the Fermi energy corres 350 // assuming the Fermi energy corresponds to a potential, we must place these such 351 // that the Fermi Energy > CoulombB 351 // that the Fermi Energy > CoulombBarrier 352 if (theNucleons[i].GetDefinition() == G4Pr 352 if (theNucleons[i].GetDefinition() == G4Proton::Proton()) 353 { 353 { 354 G4double nucMass = theNucleons[i]. 354 G4double nucMass = theNucleons[i].GetDefinition()->GetPDGMass(); 355 G4double eFermi= std::sqrt( sqr(pF 355 G4double eFermi= std::sqrt( sqr(pFermi) + sqr(nucMass) ) - nucMass; 356 if (eFermi <= CoulombBarrier() ) freepla 356 if (eFermi <= CoulombBarrier() ) freeplace=false; 357 } 357 } 358 } 358 } 359 if ( freeplace ) { 359 if ( freeplace ) { 360 theNucleons[i].SetPosition(aPos); 360 theNucleons[i].SetPosition(aPos); 361 places.push_back(aPos); 361 places.push_back(aPos); 362 ++i; 362 ++i; 363 } 363 } 364 } 364 } 365 } 365 } 366 if (interationsLeft<=0) { 366 if (interationsLeft<=0) { 367 G4Exception("model/util/G4Fancy3DNucleus 367 G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util001", FatalException, 368 "Problem to place nucleons") 368 "Problem to place nucleons"); 369 } 369 } 370 370 371 } else { 371 } else { 372 // Start insertion 372 // Start insertion 373 // Alpha cluster structure of carbon nucle 373 // Alpha cluster structure of carbon nuclei, C-12, is implemented according to 374 // P. Bozek, W. Broniowski, E.R. Arr 374 // P. Bozek, W. Broniowski, E.R. Arriola and M. Rybczynski 375 // Phys. Rev. C90, 064902 ( 375 // Phys. Rev. C90, 064902 (2014) 376 const G4double Lbase=3.05*fermi; 376 const G4double Lbase=3.05*fermi; 377 const G4double Disp=0.552; // 0.91^ 377 const G4double Disp=0.552; // 0.91^2*2/3 fermi^2 378 const G4double nd2=sqr(nucleondistance); 378 const G4double nd2=sqr(nucleondistance); 379 const G4ThreeVector Corner1=G4ThreeVector( 379 const G4ThreeVector Corner1=G4ThreeVector( Lbase/2., 0., 0.); 380 const G4ThreeVector Corner2=G4ThreeVector( 380 const G4ThreeVector Corner2=G4ThreeVector(-Lbase/2., 0., 0.); 381 const G4ThreeVector Corner3=G4ThreeVector( 381 const G4ThreeVector Corner3=G4ThreeVector( 0.,Lbase*0.866, 0.); // 0.866=sqrt(3)/2 382 G4ThreeVector R1; 382 G4ThreeVector R1; 383 R1=G4ThreeVector(G4RandGauss::shoot(0.,Dis 383 R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner1; 384 theNucleons[0].SetPosition(R1); // First n 384 theNucleons[0].SetPosition(R1); // First nucleon of the first He-4 385 G4int loopCounterLeft = 10000; 385 G4int loopCounterLeft = 10000; 386 for(G4int ii=1; ii<4; ii++) // 2 - 4 n 386 for(G4int ii=1; ii<4; ii++) // 2 - 4 nucleons of the first He-4 387 { 387 { 388 G4bool Continue; 388 G4bool Continue; 389 do 389 do 390 { 390 { 391 R1=G4ThreeVector(G4RandGauss::shoot(0. 391 R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner1; 392 theNucleons[ii].SetPosition(R1); 392 theNucleons[ii].SetPosition(R1); 393 Continue=false; 393 Continue=false; 394 for(G4int jj=0; jj < ii; jj++) 394 for(G4int jj=0; jj < ii; jj++) 395 { 395 { 396 if( (theNucleons[ii].GetPosition() - 396 if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;} 397 } 397 } 398 } while( Continue && --loopCounterLeft > 398 } while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */ 399 } 399 } 400 if ( loopCounterLeft <= 0 ) { 400 if ( loopCounterLeft <= 0 ) { 401 G4Exception("model/util/G4Fancy3DNucleus 401 G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util002", FatalException, 402 "Unable to find a good posit 402 "Unable to find a good position for the first alpha cluster"); 403 } 403 } 404 loopCounterLeft = 10000; 404 loopCounterLeft = 10000; 405 for(G4int ii=4; ii<8; ii++) // 5 - 8 n 405 for(G4int ii=4; ii<8; ii++) // 5 - 8 nucleons of the second He-4 406 { 406 { 407 G4bool Continue; 407 G4bool Continue; 408 do 408 do 409 { 409 { 410 R1=G4ThreeVector(G4RandGauss::shoot(0. 410 R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner2; 411 theNucleons[ii].SetPosition(R1); 411 theNucleons[ii].SetPosition(R1); 412 Continue=false; 412 Continue=false; 413 for(G4int jj=0; jj < ii; jj++) 413 for(G4int jj=0; jj < ii; jj++) 414 { 414 { 415 if( (theNucleons[ii].GetPosition() - 415 if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;} 416 } 416 } 417 } while( Continue && --loopCounterLeft > 417 } while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */ 418 } 418 } 419 if ( loopCounterLeft <= 0 ) { 419 if ( loopCounterLeft <= 0 ) { 420 G4Exception("model/util/G4Fancy3DNucleus 420 G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util003", FatalException, 421 "Unable to find a good posit 421 "Unable to find a good position for the second alpha cluster"); 422 } 422 } 423 loopCounterLeft = 10000; 423 loopCounterLeft = 10000; 424 for(G4int ii=8; ii<12; ii++) // 9 - 12 424 for(G4int ii=8; ii<12; ii++) // 9 - 12 nucleons of the third He-4 425 { 425 { 426 G4bool Continue; 426 G4bool Continue; 427 do 427 do 428 { 428 { 429 R1=G4ThreeVector(G4RandGauss::shoot(0. 429 R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner3; 430 theNucleons[ii].SetPosition(R1); 430 theNucleons[ii].SetPosition(R1); 431 Continue=false; 431 Continue=false; 432 for(G4int jj=0; jj < ii; jj++) 432 for(G4int jj=0; jj < ii; jj++) 433 { 433 { 434 if( (theNucleons[ii].GetPosition() - 434 if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;} 435 } 435 } 436 } while( Continue && --loopCounterLeft > 436 } while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */ 437 } 437 } 438 if ( loopCounterLeft <= 0 ) { 438 if ( loopCounterLeft <= 0 ) { 439 G4Exception("model/util/G4Fancy3DNucleus 439 G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util004", FatalException, 440 "Unable to find a good posit 440 "Unable to find a good position for the third alpha cluster"); 441 } 441 } 442 G4LorentzRotation RandomRotation; 442 G4LorentzRotation RandomRotation; 443 RandomRotation.rotateZ(2.*pi*G4UniformRand 443 RandomRotation.rotateZ(2.*pi*G4UniformRand()); 444 RandomRotation.rotateY(std::acos(2.*G4Unif 444 RandomRotation.rotateY(std::acos(2.*G4UniformRand()-1.)); 445 // Randomly rotation of the created nucleu 445 // Randomly rotation of the created nucleus 446 G4LorentzVector Pos; 446 G4LorentzVector Pos; 447 for(G4int ii=0; ii<myA; ii++ ) 447 for(G4int ii=0; ii<myA; ii++ ) 448 { 448 { 449 Pos=G4LorentzVector(theNucleons[ii].GetP 449 Pos=G4LorentzVector(theNucleons[ii].GetPosition(),0.); Pos *=RandomRotation; 450 G4ThreeVector NewPos = Pos.vect(); 450 G4ThreeVector NewPos = Pos.vect(); 451 theNucleons[ii].SetPosition(NewPos); 451 theNucleons[ii].SetPosition(NewPos); 452 } 452 } 453 453 454 } 454 } 455 } 455 } 456 456 457 void G4Fancy3DNucleus::ChooseFermiMomenta() 457 void G4Fancy3DNucleus::ChooseFermiMomenta() 458 { 458 { 459 G4int i; 459 G4int i; 460 G4double density; 460 G4double density; 461 461 462 // Pre-allocate buffers for filling by ind 462 // Pre-allocate buffers for filling by index 463 momentum.resize(myA, G4ThreeVector(0.,0.,0 463 momentum.resize(myA, G4ThreeVector(0.,0.,0.)); 464 fermiM.resize(myA, 0.*GeV); 464 fermiM.resize(myA, 0.*GeV); 465 465 466 for (G4int ntry=0; ntry<1 ; ntry ++ ) 466 for (G4int ntry=0; ntry<1 ; ntry ++ ) 467 { 467 { 468 for (i=0; i < myA; i++ ) // momenta for a 468 for (i=0; i < myA; i++ ) // momenta for all, including last, in case we swap nucleons 469 { 469 { 470 density = theDensity->GetDensity(theNucle 470 density = theDensity->GetDensity(theNucleons[i].GetPosition()); 471 fermiM[i] = theFermi.GetFermiMomentum(den 471 fermiM[i] = theFermi.GetFermiMomentum(density); 472 G4ThreeVector mom=theFermi.GetMomentum(de 472 G4ThreeVector mom=theFermi.GetMomentum(density); 473 if (theNucleons[i].GetDefinition() == G4P 473 if (theNucleons[i].GetDefinition() == G4Proton::Proton()) 474 { 474 { 475 G4double eMax = std::sqrt(sqr(fermiM[i 475 G4double eMax = std::sqrt(sqr(fermiM[i]) +sqr(theNucleons[i].GetDefinition()->GetPDGMass()) ) 476 - CoulombBarrier(); 476 - CoulombBarrier(); 477 if ( eMax > theNucleons[i].GetDefiniti 477 if ( eMax > theNucleons[i].GetDefinition()->GetPDGMass() ) 478 { 478 { 479 G4double pmax2= sqr(eMax) - sqr(th 479 G4double pmax2= sqr(eMax) - sqr(theNucleons[i].GetDefinition()->GetPDGMass()); 480 fermiM[i] = std::sqrt(pmax2); 480 fermiM[i] = std::sqrt(pmax2); 481 while ( mom.mag2() > pmax2 ) /* Loop ch 481 while ( mom.mag2() > pmax2 ) /* Loop checking, 30-Oct-2015, G.Folger */ 482 { 482 { 483 mom=theFermi.GetMomentum(density, fe 483 mom=theFermi.GetMomentum(density, fermiM[i]); 484 } 484 } 485 } else 485 } else 486 { 486 { 487 //AR-21Dec2017 : emit a "Jus 487 //AR-21Dec2017 : emit a "JustWarning" exception instead of writing on the error stream. 488 //G4cerr << "G4Fancy3DNucleus: dif 488 //G4cerr << "G4Fancy3DNucleus: difficulty finding proton momentum" << G4endl; 489 G4ExceptionDescription ed; 489 G4ExceptionDescription ed; 490 ed << "Nucleus Z A " << my 490 ed << "Nucleus Z A " << myZ << " " << myA << G4endl; 491 ed << "proton with eMax=" << 491 ed << "proton with eMax=" << eMax << G4endl; 492 G4Exception( "G4Fancy3DNucle 492 G4Exception( "G4Fancy3DNucleus::ChooseFermiMomenta(): difficulty finding proton momentum, set it to (0,0,0)", 493 "HAD_FANCY3DNUC 493 "HAD_FANCY3DNUCLEUS_001", JustWarning, ed ); 494 mom=G4ThreeVector(0,0,0); 494 mom=G4ThreeVector(0,0,0); 495 } 495 } 496 496 497 } 497 } 498 momentum[i]= mom; 498 momentum[i]= mom; 499 } 499 } 500 500 501 if ( ReduceSum() ) break; 501 if ( ReduceSum() ) break; 502 // G4cout <<" G4FancyNucleus: iterating 502 // G4cout <<" G4FancyNucleus: iterating to find momenta: "<< ntry<< G4endl; 503 } 503 } 504 504 505 // G4ThreeVector sum; 505 // G4ThreeVector sum; 506 // for (G4int index=0; index<myA;sum+=mome 506 // for (G4int index=0; index<myA;sum+=momentum[index++]) 507 // ; 507 // ; 508 // G4cout << "final sum / mag() " << sum < 508 // G4cout << "final sum / mag() " << sum << " / " << sum.mag() << G4endl; 509 509 510 G4double energy; 510 G4double energy; 511 for ( i=0; i< myA ; i++ ) 511 for ( i=0; i< myA ; i++ ) 512 { 512 { 513 energy = theNucleons[i].GetParticleType 513 energy = theNucleons[i].GetParticleType()->GetPDGMass() 514 - BindingEnergy()/myA; 514 - BindingEnergy()/myA; 515 G4LorentzVector tempV(momentum[i],energ 515 G4LorentzVector tempV(momentum[i],energy); 516 theNucleons[i].SetMomentum(tempV); 516 theNucleons[i].SetMomentum(tempV); 517 // GF 11-05-2011: set BindingEnergy to 517 // GF 11-05-2011: set BindingEnergy to be T of Nucleon with p , ~ p**2/2m 518 //theNucleons[i].SetBindingEnergy( 518 //theNucleons[i].SetBindingEnergy( 519 // 0.5*sqr(fermiM[i])/theNucleons[i 519 // 0.5*sqr(fermiM[i])/theNucleons[i].GetParticleType()->GetPDGMass()); 520 } 520 } 521 } 521 } 522 522 523 523 524 G4bool G4Fancy3DNucleus::ReduceSum() 524 G4bool G4Fancy3DNucleus::ReduceSum() 525 { 525 { 526 G4ThreeVector sum; 526 G4ThreeVector sum; 527 G4double PFermi=fermiM[myA-1]; 527 G4double PFermi=fermiM[myA-1]; 528 528 529 for (G4int i=0; i < myA-1 ; i++ ) 529 for (G4int i=0; i < myA-1 ; i++ ) 530 { sum+=momentum[i]; } 530 { sum+=momentum[i]; } 531 531 532 // check if have to do anything at all.. 532 // check if have to do anything at all.. 533 if ( sum.mag() <= PFermi ) 533 if ( sum.mag() <= PFermi ) 534 { 534 { 535 momentum[myA-1]=-sum; 535 momentum[myA-1]=-sum; 536 return true; 536 return true; 537 } 537 } 538 538 539 // find all possible changes in momentum, chan 539 // find all possible changes in momentum, changing only the component parallel to sum 540 G4ThreeVector testDir=sum.unit(); 540 G4ThreeVector testDir=sum.unit(); 541 testSums.clear(); 541 testSums.clear(); 542 testSums.resize(myA-1); // Allocate block 542 testSums.resize(myA-1); // Allocate block for filling below 543 543 544 G4ThreeVector delta; 544 G4ThreeVector delta; 545 for (G4int aNucleon=0; aNucleon < myA-1; ++a << 545 for (G4int aNucleon=0; aNucleon < myA-1; aNucleon++) { 546 delta = 2.*((momentum[aNucleon]*testDir)*t 546 delta = 2.*((momentum[aNucleon]*testDir)*testDir); 547 547 548 testSums[aNucleon].Fill(delta, delta.mag() 548 testSums[aNucleon].Fill(delta, delta.mag(), aNucleon); 549 } 549 } 550 550 551 std::sort(testSums.begin(), testSums.end()); 551 std::sort(testSums.begin(), testSums.end()); 552 552 553 // reduce Momentum Sum until the next would 553 // reduce Momentum Sum until the next would be allowed. 554 G4int index=(G4int)testSums.size(); << 554 G4int index=testSums.size(); 555 while ( (sum-testSums[--index].Vector).mag() 555 while ( (sum-testSums[--index].Vector).mag()>PFermi && index>0) /* Loop checking, 30-Oct-2015, G.Folger */ 556 { 556 { 557 // Only take one which improve, ie. don't 557 // Only take one which improve, ie. don't change sign and overshoot... 558 if ( sum.mag() > (sum-testSums[index].Vect 558 if ( sum.mag() > (sum-testSums[index].Vector).mag() ) { 559 momentum[testSums[index].Index]-=testSum 559 momentum[testSums[index].Index]-=testSums[index].Vector; 560 sum-=testSums[index].Vector; 560 sum-=testSums[index].Vector; 561 } 561 } 562 } 562 } 563 563 564 if ( (sum-testSums[index].Vector).mag() <= P 564 if ( (sum-testSums[index].Vector).mag() <= PFermi ) 565 { 565 { 566 G4int best=-1; 566 G4int best=-1; 567 G4double pBest=2*PFermi; // anything large 567 G4double pBest=2*PFermi; // anything larger than PFermi 568 for ( G4int aNucleon=0; aNucleon<=index; a 568 for ( G4int aNucleon=0; aNucleon<=index; aNucleon++) 569 { 569 { 570 // find the momentum closest to choosen 570 // find the momentum closest to choosen momentum for last Nucleon. 571 G4double pTry=(testSums[aNucleon].Vector 571 G4double pTry=(testSums[aNucleon].Vector-sum).mag(); 572 if ( pTry < PFermi 572 if ( pTry < PFermi 573 && std::abs(momentum[myA-1].mag() - pT 573 && std::abs(momentum[myA-1].mag() - pTry ) < pBest ) 574 { 574 { 575 pBest=std::abs(momentum[myA-1].mag() 575 pBest=std::abs(momentum[myA-1].mag() - pTry ); 576 best=aNucleon; 576 best=aNucleon; 577 } 577 } 578 } 578 } 579 if ( best < 0 ) 579 if ( best < 0 ) 580 { 580 { 581 const G4String& text = "G4Fancy3DNucleus << 581 G4String text = "G4Fancy3DNucleus.cc: Logic error in ReduceSum()"; 582 throw G4HadronicException(__FILE 582 throw G4HadronicException(__FILE__, __LINE__, text); 583 } 583 } 584 momentum[testSums[best].Index]-=testSums[b 584 momentum[testSums[best].Index]-=testSums[best].Vector; 585 momentum[myA-1]=testSums[best].Vector-sum; 585 momentum[myA-1]=testSums[best].Vector-sum; 586 586 587 return true; 587 return true; 588 588 589 } 589 } 590 590 591 // try to compensate momentum using another 591 // try to compensate momentum using another Nucleon.... 592 G4int swapit=-1; 592 G4int swapit=-1; 593 while (swapit<myA-1) /* Loop checking, 30-O 593 while (swapit<myA-1) /* Loop checking, 30-Oct-2015, G.Folger */ 594 { 594 { 595 if ( fermiM[++swapit] > PFermi ) break; 595 if ( fermiM[++swapit] > PFermi ) break; 596 } 596 } 597 if (swapit == myA-1 ) return false; 597 if (swapit == myA-1 ) return false; 598 598 599 // Now we have a nucleon with a bigger Fermi 599 // Now we have a nucleon with a bigger Fermi Momentum. 600 // Exchange with last nucleon.. and iterate. 600 // Exchange with last nucleon.. and iterate. 601 std::swap(theNucleons[swapit], theNucleons[m 601 std::swap(theNucleons[swapit], theNucleons[myA-1]); 602 std::swap(momentum[swapit], momentum[myA-1]) 602 std::swap(momentum[swapit], momentum[myA-1]); 603 std::swap(fermiM[swapit], fermiM[myA-1]); 603 std::swap(fermiM[swapit], fermiM[myA-1]); 604 return ReduceSum(); 604 return ReduceSum(); 605 } 605 } 606 606 607 G4double G4Fancy3DNucleus::CoulombBarrier() 607 G4double G4Fancy3DNucleus::CoulombBarrier() 608 { 608 { 609 static const G4double cfactor = (1.44/1.14) 609 static const G4double cfactor = (1.44/1.14) * MeV; 610 return cfactor*myZ/(1.0 + G4Pow::GetInstance 610 return cfactor*myZ/(1.0 + G4Pow::GetInstance()->Z13(myA)); 611 } 611 } 612 612