00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include "G4WentzelVIRelModel.hh"
00056 #include "G4PhysicalConstants.hh"
00057 #include "G4SystemOfUnits.hh"
00058 #include "Randomize.hh"
00059 #include "G4ParticleChangeForMSC.hh"
00060 #include "G4PhysicsTableHelper.hh"
00061 #include "G4ElementVector.hh"
00062 #include "G4ProductionCutsTable.hh"
00063 #include "G4LossTableManager.hh"
00064 #include "G4Pow.hh"
00065 #include "G4NistManager.hh"
00066
00067
00068
00069 using namespace std;
00070
00071 G4WentzelVIRelModel::G4WentzelVIRelModel(const G4String& nam) :
00072 G4VMscModel(nam),
00073 numlimit(0.1),
00074 currentCouple(0),
00075 cosThetaMin(1.0),
00076 inside(false),
00077 singleScatteringMode(false)
00078 {
00079 invsqrt12 = 1./sqrt(12.);
00080 tlimitminfix = 1.e-6*mm;
00081 lowEnergyLimit = 1.0*eV;
00082 particle = 0;
00083 nelments = 5;
00084 xsecn.resize(nelments);
00085 prob.resize(nelments);
00086 theManager = G4LossTableManager::Instance();
00087 fNistManager = G4NistManager::Instance();
00088 fG4pow = G4Pow::GetInstance();
00089 wokvi = new G4WentzelVIRelXSection();
00090
00091 preKinEnergy = tPathLength = zPathLength = lambdaeff = currentRange = xtsec = 0;
00092 currentMaterialIndex = 0;
00093 cosThetaMax = cosTetMaxNuc = 1.0;
00094
00095 fParticleChange = 0;
00096 currentCuts = 0;
00097 currentMaterial = 0;
00098 }
00099
00100
00101
00102 G4WentzelVIRelModel::~G4WentzelVIRelModel()
00103 {
00104 delete wokvi;
00105 }
00106
00107
00108
00109 void G4WentzelVIRelModel::Initialise(const G4ParticleDefinition* p,
00110 const G4DataVector& cuts)
00111 {
00112
00113 SetupParticle(p);
00114 currentRange = 0.0;
00115
00116 cosThetaMax = cos(PolarAngleLimit());
00117 wokvi->Initialise(p, cosThetaMax);
00118
00119
00120
00121
00122
00123 currentCuts = &cuts;
00124
00125
00126 fParticleChange = GetParticleChangeForMSC(p);
00127 }
00128
00129
00130
00131 G4double G4WentzelVIRelModel::ComputeCrossSectionPerAtom(
00132 const G4ParticleDefinition* p,
00133 G4double kinEnergy,
00134 G4double Z, G4double,
00135 G4double cutEnergy, G4double)
00136 {
00137 G4double cross = 0.0;
00138 if(p != particle) { SetupParticle(p); }
00139 if(kinEnergy < lowEnergyLimit) { return cross; }
00140 if(!CurrentCouple()) {
00141 G4Exception("G4WentzelVIRelModel::ComputeCrossSectionPerAtom", "em0011",
00142 FatalException, " G4MaterialCutsCouple is not defined");
00143 return 0.0;
00144 }
00145 DefineMaterial(CurrentCouple());
00146 cosTetMaxNuc = wokvi->SetupKinematic(kinEnergy, currentMaterial);
00147 if(cosTetMaxNuc < 1.0) {
00148 cosTetMaxNuc = wokvi->SetupTarget(G4lrint(Z), cutEnergy);
00149 cross = wokvi->ComputeTransportCrossSectionPerAtom(cosTetMaxNuc);
00150
00151
00152
00153
00154
00155
00156 }
00157 return cross;
00158 }
00159
00160
00161
00162 void G4WentzelVIRelModel::StartTracking(G4Track* track)
00163 {
00164 SetupParticle(track->GetDynamicParticle()->GetDefinition());
00165 inside = false;
00166 }
00167
00168
00169
00170 G4double G4WentzelVIRelModel::ComputeTruePathLengthLimit(
00171 const G4Track& track,
00172 G4double& currentMinimalStep)
00173 {
00174 G4double tlimit = currentMinimalStep;
00175 const G4DynamicParticle* dp = track.GetDynamicParticle();
00176 G4StepPoint* sp = track.GetStep()->GetPreStepPoint();
00177 G4StepStatus stepStatus = sp->GetStepStatus();
00178 singleScatteringMode = false;
00179
00180
00181
00182
00183
00184 preKinEnergy = dp->GetKineticEnergy();
00185 DefineMaterial(track.GetMaterialCutsCouple());
00186 lambdaeff = GetTransportMeanFreePath(particle,preKinEnergy);
00187 currentRange = GetRange(particle,preKinEnergy,currentCouple);
00188 cosTetMaxNuc = wokvi->SetupKinematic(preKinEnergy, currentMaterial);
00189
00190
00191
00192 if(tlimit > currentRange) { tlimit = currentRange; }
00193
00194
00195 if(inside || tlimit < tlimitminfix) {
00196 return ConvertTrueToGeom(tlimit, currentMinimalStep);
00197 }
00198
00199
00200 G4double presafety = sp->GetSafety();
00201
00202 if(currentRange < presafety) {
00203 inside = true;
00204 return ConvertTrueToGeom(tlimit, currentMinimalStep);
00205 }
00206
00207
00208
00209 if(stepStatus != fGeomBoundary && presafety < tlimitminfix) {
00210 presafety = ComputeSafety(sp->GetPosition(), tlimit);
00211 if(currentRange < presafety) {
00212 inside = true;
00213 return ConvertTrueToGeom(tlimit, currentMinimalStep);
00214 }
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 G4double rlimit = std::max(facrange*currentRange,
00227 0.7*(1.0 - cosTetMaxNuc)*lambdaeff);
00228
00229
00230 if(cosThetaMax > cosTetMaxNuc) {
00231 rlimit = std::min(rlimit, facsafety*presafety);
00232 }
00233
00234
00235 G4double rcut = currentCouple->GetProductionCuts()->GetProductionCut(1);
00236
00237
00238
00239 if(rcut > rlimit) { rlimit = std::min(rlimit, rcut*sqrt(rlimit/rcut)); }
00240
00241 if(rlimit < tlimit) { tlimit = rlimit; }
00242
00243 tlimit = std::max(tlimit, tlimitminfix);
00244
00245
00246 tlimit = std::min(tlimit, 50*currentMaterial->GetRadlen()/facgeom);
00247
00248
00249 if (steppingAlgorithm == fUseDistanceToBoundary && stepStatus == fGeomBoundary)
00250 {
00251 G4double geomlimit = ComputeGeomLimit(track, presafety, currentRange);
00252 tlimit = std::min(tlimit, geomlimit/facgeom);
00253 }
00254
00255
00256
00257
00258
00259
00260
00261 return ConvertTrueToGeom(tlimit, currentMinimalStep);
00262 }
00263
00264
00265
00266 G4double G4WentzelVIRelModel::ComputeGeomPathLength(G4double truelength)
00267 {
00268 tPathLength = truelength;
00269 zPathLength = tPathLength;
00270
00271 if(lambdaeff > 0.0 && lambdaeff != DBL_MAX) {
00272 G4double tau = tPathLength/lambdaeff;
00273
00274
00275
00276 if(tau < numlimit) {
00277 zPathLength *= (1.0 - 0.5*tau + tau*tau/6.0);
00278
00279
00280 } else {
00281 G4double e1 = 0.0;
00282 if(currentRange > tPathLength) {
00283 e1 = GetEnergy(particle,currentRange-tPathLength,currentCouple);
00284 }
00285 e1 = 0.5*(e1 + preKinEnergy);
00286 cosTetMaxNuc = wokvi->SetupKinematic(e1, currentMaterial);
00287 lambdaeff = GetTransportMeanFreePath(particle,e1);
00288 zPathLength = lambdaeff*(1.0 - exp(-tPathLength/lambdaeff));
00289 }
00290 } else { lambdaeff = DBL_MAX; }
00291
00292 return zPathLength;
00293 }
00294
00295
00296
00297 G4double G4WentzelVIRelModel::ComputeTrueStepLength(G4double geomStepLength)
00298 {
00299
00300 xtsec = 0.0;
00301 cosThetaMin = cosTetMaxNuc;
00302
00303
00304
00305
00306 if(lambdaeff == DBL_MAX) {
00307 singleScatteringMode = true;
00308 zPathLength = geomStepLength;
00309 tPathLength = geomStepLength;
00310 cosThetaMin = 1.0;
00311
00312
00313 } else {
00314
00315
00316 const G4double singleScatLimit = 1.0e-7;
00317 if(geomStepLength < lambdaeff*singleScatLimit*(1.0 - cosTetMaxNuc)) {
00318 singleScatteringMode = true;
00319 cosThetaMin = 1.0;
00320 zPathLength = geomStepLength;
00321 tPathLength = geomStepLength;
00322
00323
00324 } else if(geomStepLength != zPathLength) {
00325
00326
00327 zPathLength = geomStepLength;
00328 G4double tau = geomStepLength/lambdaeff;
00329 tPathLength = zPathLength*(1.0 + 0.5*tau + tau*tau/3.0);
00330
00331
00332 if(tau > numlimit) {
00333 G4double e1 = 0.0;
00334 if(currentRange > tPathLength) {
00335 e1 = GetEnergy(particle,currentRange-tPathLength,currentCouple);
00336 }
00337 e1 = 0.5*(e1 + preKinEnergy);
00338 cosTetMaxNuc = wokvi->SetupKinematic(e1, currentMaterial);
00339 lambdaeff = GetTransportMeanFreePath(particle,e1);
00340 tau = zPathLength/lambdaeff;
00341
00342 if(tau < 0.999999) { tPathLength = -lambdaeff*log(1.0 - tau); }
00343 else { tPathLength = currentRange; }
00344 }
00345 }
00346 }
00347
00348
00349
00350 if(!singleScatteringMode) { cosThetaMin = 1.0 - 1.5*tPathLength/lambdaeff; }
00351
00352
00353
00354 if(cosThetaMin > cosTetMaxNuc) {
00355
00356
00357 G4double cross = ComputeXSectionPerVolume();
00358
00359 if(cross <= 0.0) {
00360 singleScatteringMode = true;
00361 tPathLength = zPathLength;
00362 lambdaeff = DBL_MAX;
00363 } else if(xtsec > 0.0) {
00364
00365 lambdaeff = 1./cross;
00366 G4double tau = zPathLength*cross;
00367 if(tau < numlimit) { tPathLength = zPathLength*(1.0 + 0.5*tau + tau*tau/3.0); }
00368 else if(tau < 0.999999) { tPathLength = -lambdaeff*log(1.0 - tau); }
00369 else { tPathLength = currentRange; }
00370
00371 if(tPathLength > currentRange) { tPathLength = currentRange; }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382 return tPathLength;
00383 }
00384
00385
00386
00387 G4ThreeVector&
00388 G4WentzelVIRelModel::SampleScattering(const G4ThreeVector& oldDirection,
00389 G4double safety)
00390 {
00391 fDisplacement.set(0.0,0.0,0.0);
00392
00393
00394
00395
00396 if(preKinEnergy < lowEnergyLimit || tPathLength <= 0.0)
00397 { return fDisplacement; }
00398
00399 G4double invlambda = 0.0;
00400 if(lambdaeff < DBL_MAX) { invlambda = 0.5/lambdaeff; }
00401
00402
00403 G4double cut = (*currentCuts)[currentMaterialIndex];
00404
00405
00406
00407
00408
00409
00410
00411 G4double x0 = tPathLength;
00412
00413 const G4double thinlimit = 0.1;
00414 G4int nMscSteps = 1;
00415
00416 if(tPathLength*invlambda > thinlimit && safety > tlimitminfix) {
00417 x0 *= 0.5;
00418 nMscSteps = 2;
00419 }
00420
00421
00422 G4double x1 = 2*tPathLength;
00423 if(0.0 < xtsec) { x1 = -log(G4UniformRand())/xtsec; }
00424
00425 const G4ElementVector* theElementVector =
00426 currentMaterial->GetElementVector();
00427 G4int nelm = currentMaterial->GetNumberOfElements();
00428
00429
00430 G4double sint, cost, phi;
00431 G4ThreeVector temp(0.0,0.0,1.0);
00432
00433
00434
00435
00436 G4ThreeVector dir(0.0,0.0,1.0);
00437 fDisplacement.set(0.0,0.0,-zPathLength);
00438 G4double mscfac = zPathLength/tPathLength;
00439
00440
00441 G4double x2 = x0;
00442 G4double step, z;
00443 G4bool singleScat;
00444
00445
00446
00447
00448
00449 do {
00450
00451
00452 if(x1 < x2) {
00453 step = x1;
00454 singleScat = true;
00455 } else {
00456 step = x2;
00457 singleScat = false;
00458 }
00459
00460
00461 fDisplacement += step*mscfac*dir;
00462
00463 if(singleScat) {
00464
00465
00466 G4int i = 0;
00467 if(nelm > 1) {
00468 G4double qsec = G4UniformRand()*xtsec;
00469 for (; i<nelm; ++i) { if(xsecn[i] >= qsec) { break; } }
00470 }
00471 G4double cosTetM =
00472 wokvi->SetupTarget(G4lrint((*theElementVector)[i]->GetZ()), cut);
00473
00474 temp = wokvi->SampleSingleScattering(cosThetaMin, cosTetM, prob[i]);
00475
00476
00477 temp.rotateUz(dir);
00478 dir = temp;
00479
00480
00481 x1 = -log(G4UniformRand())/xtsec;
00482 x2 -= step;
00483 if(x2 <= 0.0) { --nMscSteps; }
00484
00485
00486 } else {
00487 --nMscSteps;
00488 x1 -= step;
00489 x2 = x0;
00490
00491
00492 if(!singleScatteringMode) {
00493 G4double z0 = x0*invlambda;
00494
00495
00496
00497
00498 if(z0 > 5.0) { z = G4UniformRand(); }
00499 else {
00500 G4double zzz = 0.0;
00501 if(z0 > 0.01) { zzz = exp(-1.0/z0); }
00502 z = -z0*log(1.0 - (1.0 - zzz)*G4UniformRand());
00503
00504 }
00505
00506 cost = 1.0 - 2.0*z;
00507 if(cost > 1.0) { cost = 1.0; }
00508 else if(cost < -1.0) { cost =-1.0; }
00509 sint = sqrt((1.0 - cost)*(1.0 + cost));
00510 phi = twopi*G4UniformRand();
00511 G4double vx1 = sint*cos(phi);
00512 G4double vy1 = sint*sin(phi);
00513
00514
00515 temp.set(vx1,vy1,cost);
00516 temp.rotateUz(dir);
00517 dir = temp;
00518
00519
00520 if (latDisplasment && x0 > tlimitminfix) {
00521 G4double rms = invsqrt12*sqrt(2*z0);
00522 G4double r = x0*mscfac;
00523 G4double dx = r*(0.5*vx1 + rms*G4RandGauss::shoot(0.0,1.0));
00524 G4double dy = r*(0.5*vy1 + rms*G4RandGauss::shoot(0.0,1.0));
00525 G4double dz;
00526 G4double d = r*r - dx*dx - dy*dy;
00527 if(d >= 0.0) { dz = sqrt(d) - r; }
00528 else { dx = dy = dz = 0.0; }
00529
00530
00531 temp.set(dx,dy,dz);
00532 temp.rotateUz(dir);
00533 fDisplacement += temp;
00534 }
00535 }
00536 }
00537 } while (0 < nMscSteps);
00538
00539 dir.rotateUz(oldDirection);
00540
00541
00542
00543
00544 fParticleChange->ProposeMomentumDirection(dir);
00545
00546
00547 fDisplacement.rotateUz(oldDirection);
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561 return fDisplacement;
00562 }
00563
00564
00565
00566 G4double G4WentzelVIRelModel::ComputeXSectionPerVolume()
00567 {
00568
00569 const G4ElementVector* theElementVector = currentMaterial->GetElementVector();
00570 const G4double* theAtomNumDensityVector =
00571 currentMaterial->GetVecNbOfAtomsPerVolume();
00572 G4int nelm = currentMaterial->GetNumberOfElements();
00573 if(nelm > nelments) {
00574 nelments = nelm;
00575 xsecn.resize(nelm);
00576 prob.resize(nelm);
00577 }
00578 G4double cut = (*currentCuts)[currentMaterialIndex];
00579
00580
00581
00582 xtsec = 0.0;
00583 if(cosTetMaxNuc > cosThetaMin) { return 0.0; }
00584
00585
00586 G4double xs = 0.0;
00587 for (G4int i=0; i<nelm; ++i) {
00588 G4double costm =
00589 wokvi->SetupTarget(G4lrint((*theElementVector)[i]->GetZ()), cut);
00590 G4double density = theAtomNumDensityVector[i];
00591
00592 G4double esec = 0.0;
00593 if(costm < cosThetaMin) {
00594
00595
00596 if(1.0 > cosThetaMin) {
00597 xs += density*wokvi->ComputeTransportCrossSectionPerAtom(cosThetaMin);
00598 }
00599
00600 G4double nucsec = wokvi->ComputeNuclearCrossSection(cosThetaMin, costm);
00601 esec = wokvi->ComputeElectronCrossSection(cosThetaMin, costm);
00602 nucsec += esec;
00603 if(nucsec > 0.0) { esec /= nucsec; }
00604 xtsec += nucsec*density;
00605 }
00606 xsecn[i] = xtsec;
00607 prob[i] = esec;
00608
00609
00610
00611 }
00612
00613
00614
00615 return xs;
00616 }
00617
00618