- Timestamp:
- Jun 18, 2010, 11:42:07 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/source/processes/electromagnetic/standard/src/G4WentzelVIModel.cc
r1228 r1315 24 24 // ******************************************************************** 25 25 // 26 // $Id: G4WentzelVIModel.cc,v 1. 37 2009/10/28 10:14:13vnivanch Exp $27 // GEANT4 tag $Name: geant4-09-0 3$26 // $Id: G4WentzelVIModel.cc,v 1.60 2010/06/01 11:13:31 vnivanch Exp $ 27 // GEANT4 tag $Name: geant4-09-04-beta-cand-01 $ 28 28 // 29 29 // ------------------------------------------------------------------- … … 39 39 // 40 40 // Modifications: 41 // 27-05-2010 V.Ivanchenko added G4WentzelOKandVIxSection class to 42 // compute cross sections and sample scattering angle 41 43 // 42 44 // … … 57 59 #include "G4WentzelVIModel.hh" 58 60 #include "Randomize.hh" 59 #include "G4LossTableManager.hh"60 61 #include "G4ParticleChangeForMSC.hh" 61 62 #include "G4PhysicsTableHelper.hh" 62 63 #include "G4ElementVector.hh" 63 64 #include "G4ProductionCutsTable.hh" 64 #include "G4PhysicsLogVector.hh" 65 #include "G4Electron.hh" 66 #include "G4Positron.hh" 67 #include "G4Proton.hh" 68 69 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 70 71 G4double G4WentzelVIModel::ScreenRSquare[] = {0.0}; 72 G4double G4WentzelVIModel::FormFactor[] = {0.0}; 65 #include "G4LossTableManager.hh" 66 #include "G4Pow.hh" 67 68 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 73 69 74 70 using namespace std; … … 77 73 G4VMscModel(nam), 78 74 theLambdaTable(0), 79 theLambda2Table(0), 80 numlimit(0.2), 81 nbins(60), 82 nwarnings(0), 83 nwarnlimit(50), 75 numlimit(0.1), 84 76 currentCouple(0), 85 77 cosThetaMin(1.0), 86 q2Limit(TeV*TeV),87 alpha2(fine_structure_const*fine_structure_const),88 78 isInitialized(false), 89 79 inside(false) … … 91 81 invsqrt12 = 1./sqrt(12.); 92 82 tlimitminfix = 1.e-6*mm; 93 theManager = G4LossTableManager::Instance(); 94 fNistManager = G4NistManager::Instance(); 95 theElectron = G4Electron::Electron(); 96 thePositron = G4Positron::Positron(); 97 theProton = G4Proton::Proton(); 98 lowEnergyLimit = 0.1*keV; 99 G4double p0 = electron_mass_c2*classic_electr_radius; 100 coeff = twopi*p0*p0; 101 tkin = targetZ = mom2 = DBL_MIN; 102 ecut = etag = DBL_MAX; 83 lowEnergyLimit = 1.0*eV; 103 84 particle = 0; 104 85 nelments = 5; 105 86 xsecn.resize(nelments); 106 87 prob.resize(nelments); 107 108 // Thomas-Fermi screening radii 109 // Formfactors from A.V. Butkevich et al., NIM A 488 (2002) 282 110 111 if(0.0 == ScreenRSquare[0]) { 112 G4double a0 = electron_mass_c2/0.88534; 113 G4double constn = 6.937e-6/(MeV*MeV); 114 115 ScreenRSquare[0] = alpha2*a0*a0; 116 for(G4int j=1; j<100; j++) { 117 G4double x = a0*fNistManager->GetZ13(j); 118 ScreenRSquare[j] = alpha2*x*x; 119 x = fNistManager->GetA27(j); 120 FormFactor[j] = constn*x*x; 121 } 122 } 88 theManager = G4LossTableManager::Instance(); 89 fG4pow = G4Pow::GetInstance(); 90 wokvi = new G4WentzelOKandVIxSection(); 123 91 } 124 92 … … 126 94 127 95 G4WentzelVIModel::~G4WentzelVIModel() 128 {} 96 { 97 delete wokvi; 98 } 129 99 130 100 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... … … 135 105 // reset parameters 136 106 SetupParticle(p); 137 tkin = targetZ = mom2 = 0.0;138 ecut = etag = DBL_MAX;139 107 currentRange = 0.0; 140 108 cosThetaMax = cos(PolarAngleLimit()); 109 wokvi->Initialise(p, cosThetaMax); 110 /* 111 G4cout << "G4WentzelVIModel: factorA2(GeV^2) = " << factorA2/(GeV*GeV) 112 << " 1-cos(ThetaLimit)= " << 1 - cosThetaMax 113 << G4endl; 114 */ 141 115 currentCuts = &cuts; 142 116 … … 157 131 G4double cutEnergy, G4double) 158 132 { 159 SetupParticle(p); 160 if(kinEnergy < lowEnergyLimit) return 0.0; 161 SetupKinematic(kinEnergy, cutEnergy); 162 SetupTarget(Z, kinEnergy); 163 G4double xsec = ComputeTransportXSectionPerAtom(); 164 /* 165 G4cout << "CS: e= " << tkin << " cosEl= " << cosTetMaxElec2 166 << " cosN= " << cosTetMaxNuc2 << " xsec(bn)= " << xsec/barn 167 << " " << particle->GetParticleName() << G4endl; 133 G4double xsec = 0.0; 134 if(p != particle) { SetupParticle(p); } 135 if(kinEnergy < lowEnergyLimit) { return xsec; } 136 DefineMaterial(CurrentCouple()); 137 cosTetMaxNuc = wokvi->SetupKinematic(kinEnergy, currentMaterial); 138 if(cosTetMaxNuc < 1.0) { 139 cosTetMaxNuc = wokvi->SetupTarget(G4int(Z), cutEnergy); 140 xsec = wokvi->ComputeTransportCrossSectionPerAtom(cosTetMaxNuc); 141 /* 142 G4cout << "G4WentzelVIModel::CS: Z= " << G4int(Z) << " e(MeV)= " << kinEnergy 143 << " 1-cosN= " << 1 - costm << " xsec(bn)= " << xsec/barn 144 << " " << particle->GetParticleName() << G4endl; 168 145 */ 146 } 169 147 return xsec; 170 }171 172 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......173 174 G4double G4WentzelVIModel::ComputeTransportXSectionPerAtom()175 {176 G4double xSection = 0.0;177 G4double x, y, x1, x2, x3, x4;178 179 // scattering off electrons180 if(cosTetMaxElec2 < 1.0) {181 x = (1.0 - cosTetMaxElec2)/screenZ;182 if(x < numlimit) y = 0.5*x*x*(1.0 - 1.3333333*x + 1.5*x*x);183 else y = log(1.0 + x) - x/(1.0 + x);184 if(y < 0.0) {185 nwarnings++;186 if(nwarnings < nwarnlimit /*&& y < -1.e-10*/) {187 G4cout << "Electron scattering <0 for L1 " << y188 << " e(MeV)= " << tkin << " p(MeV/c)= " << sqrt(mom2)189 << " Z= " << targetZ << " "190 << particle->GetParticleName() << G4endl;191 G4cout << " z= " << 1.0-cosTetMaxElec2 << " screenZ= " << screenZ192 << " x= " << x << G4endl;193 }194 y = 0.0;195 }196 xSection = y;197 }198 /*199 G4cout << "G4WentzelVI:XS per A " << " Z= " << targetZ200 << " e(MeV)= " << tkin/MeV << " XSel= " << xSection201 << " cut(MeV)= " << ecut/MeV202 << " zmaxE= " << (1.0 - cosTetMaxElec)/screenZ203 << " zmaxN= " << (1.0 - cosTetMaxNuc2)/screenZ204 << " costm= " << cosTetMaxNuc2 << G4endl;205 */206 // scattering off nucleus207 if(cosTetMaxNuc2 < 1.0) {208 x = 1.0 - cosTetMaxNuc2;209 x1 = screenZ*formfactA;210 x2 = 1.0 - x1;211 x3 = x/screenZ;212 x4 = formfactA*x;213 // low-energy limit214 if(x3 < numlimit && x1 < numlimit) {215 y = 0.5*x3*x3*(1.0 - 1.3333333*x3 + 1.5*x3*x3 - 1.5*x1216 + 3.0*x1*x1 + 2.666666*x3*x1)/(x2*x2*x2);217 // high energy limit218 } else if(x2 <= 0.0) {219 x4 = x1*(1.0 + x3);220 y = x3*(1.0 + 0.5*x3 - (2.0 - x1)*(1.0 + x3 + x3*x3/3.0)/x4)/(x4*x4);221 // middle energy222 } else {223 y = ((1.0 + x1)*x2*log((1. + x3)/(1. + x4))224 - x3/(1. + x3) - x4/(1. + x4))/(x2*x2);225 }226 //G4cout << "y= " << y << " x1= " <<x1<<" x2= " <<x2227 // <<" x3= "<<x3<<" x4= " << x4<<G4endl;228 if(y < 0.0) {229 nwarnings++;230 if(nwarnings < nwarnlimit /*&& y < -1.e-10*/) {231 G4cout << "Nuclear scattering <0 for L1 " << y232 << " e(MeV)= " << tkin << " Z= " << targetZ << " "233 << particle->GetParticleName() << G4endl;234 G4cout << " formfactA= " << formfactA << " screenZ= " << screenZ235 << " x= " << " x1= " << x1 << " x2= " << x2236 << " x3= " << x3 << " x4= " << x4 <<G4endl;237 }238 y = 0.0;239 }240 xSection += y*targetZ;241 }242 xSection *= kinFactor;243 /*244 G4cout << "Z= " << targetZ << " XStot= " << xSection/barn245 << " screenZ= " << screenZ << " formF= " << formfactA246 << " for " << particle->GetParticleName()247 << " m= " << mass << " 1/v= " << sqrt(invbeta2) << " p= " << sqrt(mom2)248 << " x= " << x249 << G4endl;250 */251 return xSection;252 148 } 253 149 … … 263 159 G4StepPoint* sp = track.GetStep()->GetPreStepPoint(); 264 160 G4StepStatus stepStatus = sp->GetStepStatus(); 161 //G4cout << "G4WentzelVIModel::ComputeTruePathLengthLimit stepStatus= " 162 // << stepStatus << G4endl; 265 163 266 164 // initialisation for 1st step … … 268 166 inside = false; 269 167 SetupParticle(dp->GetDefinition()); 270 theLambdaTable = theTable;271 168 } 272 169 … … 274 171 preKinEnergy = dp->GetKineticEnergy(); 275 172 DefineMaterial(track.GetMaterialCutsCouple()); 276 lambda0 = GetLambda(preKinEnergy); 173 theLambdaTable = theTable; 174 lambdaeff = GetLambda(preKinEnergy); 277 175 currentRange = 278 176 theManager->GetRangeFromRestricteDEDX(particle,preKinEnergy,currentCouple); 177 cosTetMaxNuc = wokvi->SetupKinematic(preKinEnergy, currentMaterial); 279 178 280 179 // extra check for abnormal situation 281 180 // this check needed to run MSC with eIoni and eBrem inactivated 282 if(tlimit > currentRange) tlimit = currentRange;181 if(tlimit > currentRange) { tlimit = currentRange; } 283 182 284 183 // stop here if small range particle 285 if(inside) return tlimit;184 if(inside) { return tlimit; } 286 185 287 186 // pre step … … 290 189 // compute presafety again if presafety <= 0 and no boundary 291 190 // i.e. when it is needed for optimization purposes 292 if(stepStatus != fGeomBoundary && presafety < tlimitminfix) 191 if(stepStatus != fGeomBoundary && presafety < tlimitminfix) { 293 192 presafety = ComputeSafety(sp->GetPosition(), tlimit); 193 } 294 194 /* 295 G4cout << "G4WentzelVIModel::ComputeTruePathLengthLimit tlimit= " 296 <<tlimit<<" safety= " << presafety 297 << " range= " <<currentRange<<G4endl; 195 G4cout << "e(MeV)= " << preKinEnergy/MeV 196 << " " << particle->GetParticleName() 197 << " CurLimit(mm)= " << tlimit/mm <<" safety(mm)= " << presafety/mm 198 << " R(mm)= " <<currentRange/mm 199 << " L0(mm^-1)= " << lambdaeff*mm 200 <<G4endl; 298 201 */ 299 202 // far from geometry boundary 300 203 if(currentRange < presafety) { 301 204 inside = true; 302 303 // limit mean scattering angle 304 } else { 305 G4double rlimit = facrange*lambda0; 306 G4double rcut = currentCouple->GetProductionCuts()->GetProductionCut(1); 307 if(rcut > rlimit) rlimit = std::pow(rcut*rcut*rlimit,0.33333333); 308 rlimit = std::min(rlimit, facgeom*currentMaterial->GetRadlen()); 309 if(rlimit < tlimit) tlimit = rlimit; 310 } 311 /* 205 return tlimit; 206 } 207 208 // natural limit for high energy 209 G4double rlimit = std::max(facrange*currentRange, 210 0.7*(1.0 - cosTetMaxNuc)*lambdaeff); 211 212 // low-energy e- 213 if(cosThetaMax > cosTetMaxNuc) { 214 rlimit = std::min(rlimit, facsafety*presafety); 215 } 216 217 // cut correction 218 G4double rcut = currentCouple->GetProductionCuts()->GetProductionCut(1); 219 //G4cout << "rcut= " << rcut << " rlimit= " << rlimit << " presafety= " << presafety 220 // << " 1-cosThetaMax= " <<1-cosThetaMax << " 1-cosTetMaxNuc= " << 1-cosTetMaxNuc 221 // << G4endl; 222 if(rcut > rlimit) { rlimit = std::min(rlimit, rcut*sqrt(rlimit/rcut)); } 223 224 if(rlimit < tlimit) { tlimit = rlimit; } 225 226 tlimit = std::max(tlimit, tlimitminfix); 227 228 // step limit in infinite media 229 tlimit = std::min(tlimit, 20*currentMaterial->GetRadlen()); 230 /* 312 231 G4cout << particle->GetParticleName() << " e= " << preKinEnergy 313 << " L0= " << lambda 0<< " R= " << currentRange232 << " L0= " << lambdaeff << " R= " << currentRange 314 233 << "tlimit= " << tlimit 315 234 << " currentMinimalStep= " << currentMinimalStep << G4endl; … … 324 243 tPathLength = truelength; 325 244 zPathLength = tPathLength; 326 lambdaeff = lambda0; 327 328 if(lambda0 > 0.0) { 329 G4double tau = tPathLength/lambda0; 245 246 if(lambdaeff > 0.0) { 247 G4double tau = tPathLength/lambdaeff; 330 248 //G4cout << "ComputeGeomPathLength: tLength= " << tPathLength 331 // << " lambda0= " << lambda0<< " tau= " << tau << G4endl;249 // << " Leff= " << lambdaeff << " tau= " << tau << G4endl; 332 250 // small step 333 251 if(tau < numlimit) { … … 336 254 // medium step 337 255 } else { 338 // zPathLength = lambda0*(1.0 - exp(-tPathLength/lambda0));339 256 G4double e1 = 0.0; 340 257 if(currentRange > tPathLength) { … … 343 260 currentCouple); 344 261 } 345 lambdaeff = GetLambda(0.5*(e1 + preKinEnergy)); 262 e1 = 0.5*(e1 + preKinEnergy); 263 cosTetMaxNuc = wokvi->SetupKinematic(e1, currentMaterial); 264 lambdaeff = GetLambda(e1); 346 265 zPathLength = lambdaeff*(1.0 - exp(-tPathLength/lambdaeff)); 347 266 } … … 355 274 G4double G4WentzelVIModel::ComputeTrueStepLength(G4double geomStepLength) 356 275 { 357 // step defined other than transportation 358 if(geomStepLength == zPathLength) return tPathLength; 276 // initialisation of single scattering x-section 277 xtsec = 0.0; 278 279 // pathalogical case 280 if(lambdaeff <= 0.0) { 281 zPathLength = geomStepLength; 282 tPathLength = geomStepLength; 283 return tPathLength; 284 } 285 286 G4double tau = geomStepLength/lambdaeff; 359 287 360 288 // step defined by transportation 361 tPathLength = geomStepLength; 362 zPathLength = geomStepLength; 363 G4double tau = zPathLength/lambdaeff; 364 tPathLength *= (1.0 + 0.5*tau + tau*tau/3.0); 365 366 if(tau > numlimit) { 367 G4double e1 = 0.0; 368 if(currentRange > tPathLength) { 369 e1 = theManager->GetEnergy(particle, 370 currentRange-tPathLength, 371 currentCouple); 372 } 373 lambdaeff = GetLambda(0.5*(e1 + preKinEnergy)); 374 tau = zPathLength/lambdaeff; 375 376 if(tau < 0.999999) tPathLength = -lambdaeff*log(1.0 - tau); 377 else tPathLength = currentRange; 378 379 if(tPathLength < zPathLength) tPathLength = zPathLength; 380 } 381 if(tPathLength > currentRange) tPathLength = currentRange; 382 //G4cout<<"Comp.true: zLength= "<<zPathLength<<" tLength= "<<tPathLength<<G4endl; 289 if(geomStepLength != zPathLength) { 290 291 // step defined by transportation 292 zPathLength = geomStepLength; 293 tPathLength = zPathLength*(1.0 + 0.5*tau + tau*tau/3.0); 294 295 // energy correction for a big step 296 if(tau > numlimit) { 297 G4double e1 = 0.0; 298 if(currentRange > tPathLength) { 299 e1 = theManager->GetEnergy(particle, 300 currentRange-tPathLength, 301 currentCouple); 302 } 303 e1 = 0.5*(e1 + preKinEnergy); 304 cosTetMaxNuc = wokvi->SetupKinematic(e1, currentMaterial); 305 lambdaeff = GetLambda(e1); 306 tau = zPathLength/lambdaeff; 307 308 if(tau < 0.999999) { tPathLength = -lambdaeff*log(1.0 - tau); } 309 else { tPathLength = currentRange; } 310 } 311 } 312 313 // check of step length 314 // define threshold angle between single and multiple scattering 315 cosThetaMin = 1.0 - 1.5*tPathLength/lambdaeff; 316 317 // recompute transport cross section - do not change energy 318 // anymore - cannot be applied for big steps 319 if(cosThetaMin > cosTetMaxNuc) { 320 321 // new computation 322 G4double xsec = ComputeXSectionPerVolume(); 323 //G4cout << "%%%% xsec= " << xsec << " xtsec= " << xtsec << G4endl; 324 if(xtsec > 0.0) { 325 if(xsec > 0.0) { lambdaeff = 1./xsec; } 326 else { lambdaeff = DBL_MAX; } 327 328 tau = zPathLength*xsec; 329 if(tau < numlimit) { tPathLength = zPathLength*(1.0 + 0.5*tau + tau*tau/3.0); } 330 else if(tau < 0.999999) { tPathLength = -lambdaeff*log(1.0 - tau); } 331 else { tPathLength = currentRange; } 332 } 333 } 334 335 if(tPathLength > currentRange) { tPathLength = currentRange; } 336 if(tPathLength < zPathLength) { tPathLength = zPathLength; } 337 /* 338 G4cout <<"Comp.true: zLength= "<<zPathLength<<" tLength= "<<tPathLength 339 <<" Leff(mm)= "<<lambdaeff/mm<<" sig0(1/mm)= " << xtsec <<G4endl; 340 G4cout << particle->GetParticleName() << " 1-cosThetaMin= " << 1-cosThetaMin 341 << " 1-cosTetMaxNuc= " << 1-cosTetMaxNuc 342 << " e(MeV)= " << preKinEnergy/MeV << G4endl; 343 */ 383 344 return tPathLength; 384 345 } … … 391 352 //G4cout << "!##! G4WentzelVIModel::SampleScattering for " 392 353 // << particle->GetParticleName() << G4endl; 393 G4double kinEnergy = dynParticle->GetKineticEnergy(); 394 395 // ignore scattering for zero step length and enegy below the limit 396 if(kinEnergy < lowEnergyLimit || tPathLength <= DBL_MIN) return; 397 398 G4double ekin = preKinEnergy; 399 if(ekin - kinEnergy > ekin*dtrl) { 400 ekin = 0.5*(preKinEnergy + kinEnergy); 401 lambdaeff = GetLambda(ekin); 402 } 354 355 // ignore scattering for zero step length and energy below the limit 356 if(dynParticle->GetKineticEnergy() < lowEnergyLimit || 357 tPathLength <= DBL_MIN || lambdaeff <= DBL_MIN) 358 { return; } 403 359 404 G4double x1 = 0.5*tPathLength/lambdaeff; 405 G4double cut= (*currentCuts)[currentMaterialIndex]; 406 /* 407 G4cout <<"SampleScat: E0(MeV)= "<< preKinEnergy<<" Eeff(MeV)= "<<ekin/MeV 408 << " L0= " << lambda0 << " Leff= " << lambdaeff 409 << " x1= " << x1 << " safety= " << safety << G4endl; 360 G4double invlambda = 0.0; 361 if(lambdaeff < DBL_MAX) { invlambda = 0.5/lambdaeff; } 362 363 // use average kinetic energy over the step 364 G4double cut = (*currentCuts)[currentMaterialIndex]; 365 /* 366 G4cout <<"SampleScat: E0(MeV)= "<< preKinEnergy/MeV 367 << " Leff= " << lambdaeff <<" sig0(1/mm)= " << xtsec 368 << " x1= " << tPathLength*invlambda << " safety= " << safety << G4endl; 410 369 */ 411 370 412 G4double xsec = 0.0; 413 G4bool largeAng = false; 414 415 // large scattering angle case 416 if(x1 > 0.5) { 417 x1 *= 0.5; 418 largeAng = true; 419 420 // normal case 421 } else { 422 423 // define threshold angle between single and multiple scattering 424 cosThetaMin = 1.0 - 3.0*x1; 425 426 // for low-energy e-,e+ no limit 427 SetupKinematic(ekin, cut); 428 429 // recompute transport cross section 430 if(cosThetaMin > cosTetMaxNuc) { 431 432 xsec = ComputeXSectionPerVolume(); 433 434 if(xtsec > 0.0) x1 = 0.5*tPathLength*xtsec; 435 else x1 = 0.0; 436 437 /* 438 G4cout << "cosTetMaxNuc= " << cosTetMaxNuc 439 << " cosThetaMin= " << cosThetaMin 440 << " cosThetaMax= " << cosThetaMax 441 << " cosTetMaxElec2= " << cosTetMaxElec2 << G4endl; 442 G4cout << "Recomputed xsec(1/mm)= " << xsec << " x1= " << x1 << G4endl; 443 */ 444 } 445 } 446 447 // result of central part sampling 448 G4double z; 371 G4double length = tPathLength; 372 G4double lengthlim = tPathLength*1.e-6; 373 374 // step limit due msc 375 G4double x0 = length; 376 // large scattering angle case - two step approach 377 if(tPathLength*invlambda > 0.5 && length > tlimitminfix) { x0 *= 0.5; } 378 379 // step limit due single scattering 380 G4double x1 = length; 381 if(xtsec > 0.0) { x1 = -log(G4UniformRand())/xtsec; } 382 383 const G4ElementVector* theElementVector = 384 currentMaterial->GetElementVector(); 385 G4int nelm = currentMaterial->GetNumberOfElements(); 386 387 // geometry 388 G4double sint, cost, phi; 389 G4ThreeVector oldDirection = dynParticle->GetMomentumDirection(); 390 G4ThreeVector temp(0.0,0.0,1.0); 391 392 // current position and direction relative to the end point 393 // because of magnetic field geometry is computed relatively to the 394 // end point of the step 395 G4ThreeVector dir(0.0,0.0,1.0); 396 G4ThreeVector pos(0.0,0.0,-zPathLength); 397 G4double mscfac = zPathLength/tPathLength; 398 399 // start a loop 449 400 do { 450 z = -x1*log(G4UniformRand()); 451 } while (z > 1.0); 452 453 // cost is sampled ------------------------------ 454 G4double cost = 1.0 - 2.0*z; 455 // if(cost < -1.0) cost = -1.0; 456 // else if(cost > 1.0) cost = 1.0; 457 G4double sint = sqrt((1.0 - cost)*(1.0 + cost)); 458 459 G4double phi = twopi*G4UniformRand(); 460 461 G4double dirx = sint*cos(phi); 462 G4double diry = sint*sin(phi); 463 464 //G4cout << "G4WentzelVIModel: step(mm)= " << tPathLength/mm 465 // << " sint= " << sint << " cost= " << cost<< G4endl; 466 467 G4ThreeVector oldDirection = dynParticle->GetMomentumDirection(); 468 G4ThreeVector newDirection(dirx,diry,cost); 469 G4ThreeVector temp(0.0,0.0,1.0); 470 G4ThreeVector pos(0.0,0.0,-zPathLength); 471 G4ThreeVector dir(0.0,0.0,1.0); 472 G4bool isscat = false; 473 474 // sample MSC scattering for large angle 475 // extra central scattering for half step 476 if(largeAng) { 477 isscat = true; 478 pos.setZ(-0.5*zPathLength); 479 do { 480 z = -x1*log(G4UniformRand()); 481 } while (z > 1.0); 401 G4double step = x0; 402 G4bool singleScat = false; 403 404 // single scattering case 405 if(x1 < x0) { 406 step = x1; 407 singleScat = true; 408 } 409 410 // new position 411 pos += step*mscfac*dir; 412 413 // added multiple scattering 414 G4double z; 415 G4double tet2 = step*invlambda; 416 do { z = -tet2*log(G4UniformRand()); } while (z >= 1.0); 417 482 418 cost = 1.0 - 2.0*z; 483 //if(std::fabs(cost) > 1.0) cost = 1.0;484 485 419 sint = sqrt((1.0 - cost)*(1.0 + cost)); 486 420 phi = twopi*G4UniformRand(); 487 488 // position and direction for secondary scattering 489 dir.set(sint*cos(phi),sint*sin(phi),cost); 490 pos += 0.5*dir*zPathLength; 491 x1 *= 2.0; 492 } 493 494 // sample Rutherford scattering for large angle 495 if(xsec > DBL_MIN) { 496 G4double t = tPathLength; 497 G4int nelm = currentMaterial->GetNumberOfElements(); 498 const G4ElementVector* theElementVector = 499 currentMaterial->GetElementVector(); 500 do{ 501 G4double x = -log(G4UniformRand())/xsec; 502 pos += dir*(zPathLength*std::min(x,t)/tPathLength); 503 t -= x; 504 if(t > 0.0) { 505 G4double zz1 = 1.0; 506 G4double qsec = G4UniformRand()*xsec; 507 508 // scattering off nucleus 509 G4int i = 0; 510 if(nelm > 1) { 511 for (; i<nelm; i++) {if(xsecn[i] >= qsec) break;} 512 if(i >= nelm) i = nelm - 1; 513 } 514 SetupTarget((*theElementVector)[i]->GetZ(), tkin); 515 G4double formf = formfactA; 516 G4double costm = cosTetMaxNuc2; 517 if(prob[i] > 0.0) { 518 if(G4UniformRand() <= prob[i]) { 519 formf = 0.0; 520 costm = cosTetMaxElec2; 521 } 522 } 523 if(cosThetaMin > costm) { 524 525 G4double w1 = 1. - cosThetaMin + screenZ; 526 G4double w2 = 1. - costm + screenZ; 527 G4double w3 = cosThetaMin - costm; 528 G4double grej, zz; 529 do { 530 zz = w1*w2/(w1 + G4UniformRand()*w3) - screenZ; 531 grej = 1.0/(1.0 + formf*zz); 532 } while ( G4UniformRand() > grej*grej ); 533 if(zz < 0.0) zz = 0.0; 534 else if(zz > 2.0) zz = 2.0; 535 zz1 = 1.0 - zz; 536 } 537 if(zz1 < 1.0) { 538 isscat = true; 539 //G4cout << "Rutherford zz1= " << zz1 << " t= " << t << G4endl; 540 sint = sqrt((1.0 - zz1)*(1.0 + zz1)); 541 //G4cout << "sint= " << sint << G4endl; 542 phi = twopi*G4UniformRand(); 543 G4double vx1 = sint*cos(phi); 544 G4double vy1 = sint*sin(phi); 545 temp.set(vx1,vy1,zz1); 546 temp.rotateUz(dir); 547 dir = temp; 548 } 421 G4double vx1 = sint*cos(phi); 422 G4double vy1 = sint*sin(phi); 423 424 // lateral displacement 425 if (latDisplasment && safety > tlimitminfix) { 426 G4double rms = invsqrt12*sqrt(2.0*tet2); 427 G4double dx = step*(0.5*vx1 + rms*G4RandGauss::shoot(0.0,1.0)); 428 G4double dy = step*(0.5*vy1 + rms*G4RandGauss::shoot(0.0,1.0)); 429 G4double dz; 430 G4double d = (dx*dx + dy*dy)/(step*step); 431 if(d < numlimit) { dz = -0.5*step*d*(1.0 + 0.25*d); } 432 else if(d < 1.0) { dz = -step*(1.0 - sqrt(1.0 - d));} 433 else { dx = dy = dz = 0.0; } 434 435 // change position 436 temp.set(dx,dy,dz); 437 temp.rotateUz(dir); 438 pos += temp; 439 } 440 441 // direction is changed 442 temp.set(vx1,vy1,cost); 443 temp.rotateUz(dir); 444 dir = temp; 445 446 if(singleScat) { 447 448 // select element 449 G4int i = 0; 450 if(nelm > 1) { 451 G4double qsec = G4UniformRand()*xtsec; 452 for (; i<nelm; ++i) { if(xsecn[i] >= qsec) { break; } } 453 if(i >= nelm) { i = nelm - 1; } 549 454 } 550 } while (t > 0.0); 551 } 552 if(isscat) newDirection.rotateUz(dir); 553 newDirection.rotateUz(oldDirection); 455 G4double cosTetM = 456 wokvi->SetupTarget(G4int((*theElementVector)[i]->GetZ()), cut); 457 temp = wokvi->SampleSingleScattering(cosThetaMin, cosTetM, prob[i]); 458 temp.rotateUz(dir); 459 460 // renew direction 461 dir = temp; 462 463 // new single scatetring 464 x1 = -log(G4UniformRand())/xtsec; 465 } 466 467 // update step 468 length -= step; 469 470 } while (length > lengthlim); 471 472 dir.rotateUz(oldDirection); 473 pos.rotateUz(oldDirection); 554 474 555 475 //G4cout << "G4WentzelVIModel sampling of scattering is done" << G4endl; 556 476 // end of sampling ------------------------------- 557 477 558 fParticleChange->ProposeMomentumDirection(newDirection); 559 560 if (latDisplasment && safety > tlimitminfix) { 561 G4double rms = invsqrt12*sqrt(2.0*x1); 562 G4double dx = zPathLength*(0.5*dirx + rms*G4RandGauss::shoot(0.0,1.0)); 563 G4double dy = zPathLength*(0.5*diry + rms*G4RandGauss::shoot(0.0,1.0)); 564 G4double dz; 565 G4double d = (dx*dx + dy*dy)/(zPathLength*zPathLength); 566 if(d < numlimit) dz = -0.5*zPathLength*d*(1.0 + 0.25*d); 567 else if(d < 1.0) dz = -zPathLength*(1.0 - sqrt(1.0 - d)); 568 else { 569 dx = dy = dz = 0.0; 570 } 571 572 temp.set(dx,dy,dz); 573 if(isscat) temp.rotateUz(dir); 574 pos += temp; 575 576 pos.rotateUz(oldDirection); 577 478 fParticleChange->ProposeMomentumDirection(dir); 479 480 // lateral displacement 481 if (latDisplasment) { 578 482 G4double r = pos.mag(); 579 483 … … 597 501 G4double G4WentzelVIModel::ComputeXSectionPerVolume() 598 502 { 599 const G4ElementVector* theElementVector =600 503 // prepare recomputation of x-sections 504 const G4ElementVector* theElementVector = currentMaterial->GetElementVector(); 601 505 const G4double* theAtomNumDensityVector = 602 506 currentMaterial->GetVecNbOfAtomsPerVolume(); … … 604 508 if(nelm > nelments) { 605 509 nelments = nelm; 606 xsecn.resize(nelments); 607 prob.resize(nelments); 608 } 609 510 xsecn.resize(nelm); 511 prob.resize(nelm); 512 } 513 G4double cut = (*currentCuts)[currentMaterialIndex]; 514 cosTetMaxNuc = wokvi->GetCosThetaNuc(); 515 516 // check consistency 610 517 xtsec = 0.0; 518 if(cosTetMaxNuc > cosThetaMin) { return 0.0; } 519 520 // loop over elements 611 521 G4double xs = 0.0; 612 613 for (G4int i=0; i<nelm; i++) {614 SetupTarget((*theElementVector)[i]->GetZ(), tkin);522 for (G4int i=0; i<nelm; ++i) { 523 G4double costm = 524 wokvi->SetupTarget(G4int((*theElementVector)[i]->GetZ()), cut); 615 525 G4double density = theAtomNumDensityVector[i]; 616 G4double cosnm = cosTetMaxNuc2;617 G4double cosem = cosTetMaxElec2;618 619 // recompute the angular limit620 cosTetMaxNuc2 = std::max(cosnm,cosThetaMin);621 cosTetMaxElec2 = std::max(cosem,cosThetaMin);622 xtsec += ComputeTransportXSectionPerAtom()*density;623 // return limit back624 cosTetMaxElec2 = cosem;625 cosTetMaxNuc2 = cosnm;626 526 627 527 G4double esec = 0.0; 628 G4double nsec = 0.0; 629 G4double x1 = 1.0 - cosThetaMin + screenZ; 630 G4double f = kinFactor*density; 631 632 // scattering off electrons 633 if(cosThetaMin > cosem) { 634 esec = f*(cosThetaMin - cosem)/(x1*(1.0 - cosem + screenZ)); 635 } 636 637 // scattering off nucleaus 638 if(cosThetaMin > cosnm) { 639 640 // Rutherford part 641 G4double s = screenZ*formfactA; 642 G4double z1 = 1.0 - cosnm + screenZ; 643 G4double s1 = 1.0 - s; 644 G4double d = s1/formfactA; 645 646 // check numerical limit 647 if(d < numlimit*x1) { 648 G4double x2 = x1*x1; 649 G4double z2 = z1*z1; 650 nsec = (1.0/(x1*x2) - 1.0/(z1*z2) - d*1.5*(1.0/(x2*x2) - 1.0/(z2*z2)))/ 651 (3.0*formfactA*formfactA); 652 } else { 653 G4double x2 = x1 + d; 654 G4double z2 = z1 + d; 655 nsec = (1.0/x1 - 1.0/z1 + 1.0/x2 - 1.0/z2 - 2.0*log(z1*x2/(z2*x1))/d)/(s1*s1); 656 } 657 nsec *= f*targetZ; 658 } 659 nsec += esec; 660 if(nsec > 0.0) esec /= nsec; 661 xs += nsec; 662 xsecn[i] = xs; 528 if(costm < cosThetaMin) { 529 530 // recompute the transport x-section 531 xs += density*wokvi->ComputeTransportCrossSectionPerAtom(cosThetaMin); 532 533 // recompute the total x-section 534 G4double nsec = wokvi->ComputeNuclearCrossSection(cosThetaMin, costm); 535 esec = wokvi->ComputeElectronCrossSection(cosThetaMin, costm); 536 nsec += esec; 537 if(nsec > 0.0) { esec /= nsec; } 538 xtsec += nsec*density; 539 } 540 xsecn[i] = xtsec; 663 541 prob[i] = esec; 664 //G4cout << i << " xs= " << xs << " cosThetaMin= " <<cosThetaMin665 // << " costm= " << costm<< G4endl;542 //G4cout << i << " xs= " << xs << " xtsec= " << xtsec << " 1-cosThetaMin= " << 1-cosThetaMin 543 // << " 1-cosTetMaxNuc2= " <<1-cosTetMaxNuc2<< G4endl; 666 544 } 667 545 668 546 //G4cout << "ComputeXS result: xsec(1/mm)= " << xs 669 // << " txsec(1/mm)= " << xtsec <<G4endl;547 // << " txsec(1/mm)= " << xtsec <<G4endl; 670 548 return xs; 671 549 } 672 550 673 551 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 674 675 /*676 G4double G4MuMscModel::ComputeXSectionPerVolume()677 {678 const G4ElementVector* theElementVector =679 currentMaterial->GetElementVector();680 const G4double* theAtomNumDensityVector =681 currentMaterial->GetVecNbOfAtomsPerVolume();682 size_t nelm = currentMaterial->GetNumberOfElements();683 684 xsece1 = 0.0;685 xsece2 = 0.0;686 xsecn2 = 0.0;687 zcorr = 0.0;688 689 G4double fac = coeff*chargeSquare*invbeta2/mom2;690 691 for (size_t i=0; i<nelm; i++) {692 const G4Element* elm = (*theElementVector)[i];693 G4double Z = elm->GetZ();694 SetupTarget(Z, tkin);695 G4double den = fac*theAtomNumDensityVector[i]*Z;696 697 G4double x = 1.0 - cosThetaMin;698 G4double x1 = x + screenZ;699 G4double x2 = 1.0/(x1*x1);700 G4double x3 = 1.0 + x*formfactA;701 702 //G4cout << "x= " << x << " den= " << den << " cosE= " << cosTetMaxElec << G4endl;703 //G4cout << "cosThtaMin= " << cosThetaMin << G4endl;704 //G4cout << "cosTetMaxNuc= " << cosTetMaxNuc << " q2Limit= " << q2Limit << G4endl;705 706 // scattering off electrons707 if(cosTetMaxElec < cosThetaMin) {708 709 // flat part710 G4double s = den*x2*x;711 xsece1 += s;712 zcorr += 0.5*x*s;713 714 // Rutherford part715 G4double z1 = 1.0 - cosTetMaxElec + screenZ;716 G4double z2 = (cosThetaMin - cosTetMaxElec)/x1;717 if(z2 < 0.2) s = z2*(x - 0.5*z2*(x - screenZ))/x1;718 else s = log(1.0 + z2) - screenZ*z2/z1;719 xsece2 += den*z2/z1;720 zcorr += den*s;721 }722 den *= Z;723 724 //G4cout << "Z= " << Z<< " cosL= " << cosTetMaxNuc << " cosMin= " << cosThetaMin << G4endl;725 // scattering off nucleaus726 if(cosTetMaxNuc < cosThetaMin) {727 728 // flat part729 G4double s = den*x2*x/(x3*x3);730 xsece1 += s;731 zcorr += 0.5*x*s;732 733 // Rutherford part734 s = screenZ*formfactA;735 G4double w = 1.0 + 2.0*s;736 G4double z1 = 1.0 - cosTetMaxNuc + screenZ;737 G4double d = (1.0 - s)/formfactA;738 G4double x4 = x1 + d;739 G4double z4 = z1 + d;740 G4double t1 = 1.0/(x1*z1);741 G4double t4 = 1.0/(x4*z4);742 G4double w1 = cosThetaMin - cosTetMaxNuc;743 G4double w2 = log(z1*x4/(x1*z4));744 745 den *= w;746 xsecn2 += den*(w1*(t1 + t4) - 2.0*w2/d);747 zcorr += den*(w*w2 - w1*(screenZ*t1 + t4/formfactA));748 }749 xsece[i] = xsece2;750 xsecn[i] = xsecn2;751 // G4cout << i << " xsece2= " << xsece2 << " xsecn2= " << xsecn2 << G4endl;752 }753 G4double xsec = xsece1 + xsece2 + xsecn2;754 755 //G4cout << "xsece1= " << xsece1 << " xsece2= " << xsece2756 //<< " xsecn2= " << xsecn2757 // << " zsec= " << zcorr*0.5*tPathLength << G4endl;758 zcorr *= 0.5*tPathLength;759 760 return xsec;761 }762 */763 764 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......765 766 void G4WentzelVIModel::ComputeMaxElectronScattering(G4double cutEnergy)767 {768 ecut = cutEnergy;769 G4double tmax = tkin;770 cosTetMaxElec = 1.0;771 if(mass > MeV) {772 G4double ratio = electron_mass_c2/mass;773 G4double tau = tkin/mass;774 tmax = 2.0*electron_mass_c2*tau*(tau + 2.)/775 (1.0 + 2.0*ratio*(tau + 1.0) + ratio*ratio);776 cosTetMaxElec = 1.0 - std::min(cutEnergy, tmax)*electron_mass_c2/mom2;777 } else {778 779 if(particle == theElectron) tmax *= 0.5;780 G4double t = std::min(cutEnergy, tmax);781 G4double mom21 = t*(t + 2.0*electron_mass_c2);782 G4double t1 = tkin - t;783 //G4cout <<"tkin=" <<tkin<<" tmax= "<<tmax<<" t= "784 //<<t<< " t1= "<<t1<<" cut= "<<ecut<<G4endl;785 if(t1 > 0.0) {786 G4double mom22 = t1*(t1 + 2.0*mass);787 G4double ctm = (mom2 + mom22 - mom21)*0.5/sqrt(mom2*mom22);788 if(ctm < 1.0) cosTetMaxElec = ctm;789 if(ctm < -1.0) cosTetMaxElec = -1.0;790 }791 }792 if(cosTetMaxElec < cosTetMaxNuc) cosTetMaxElec = cosTetMaxNuc;793 }794 795 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
Note: See TracChangeset
for help on using the changeset viewer.