00001
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
00052
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00085
00086 #include "G4ios.hh"
00087 #include "G4Poisson.hh"
00088 #include "G4EmProcessSubType.hh"
00089
00090 #include "G4LossTableManager.hh"
00091 #include "G4MaterialCutsCouple.hh"
00092 #include "G4ParticleDefinition.hh"
00093
00094 #include "DsG4Cerenkov.h"
00095
00096 using namespace std;
00097
00099
00101
00103
00105
00106
00107
00108
00109
00111
00113
00114 DsG4Cerenkov::DsG4Cerenkov(const G4String& processName, G4ProcessType type)
00115 : G4VProcess(processName, type)
00116 , fApplyPreQE(false)
00117 , fPreQE(1.)
00118 {
00119 G4cout << "DsG4Cerenkov::DsG4Cerenkov constructor" << G4endl;
00120 G4cout << "NOTE: this is now a G4VProcess!" << G4endl;
00121 G4cout << "Required change in UserPhysicsList: " << G4endl;
00122 G4cout << "change: pmanager->AddContinuousProcess(theCerenkovProcess);" << G4endl;
00123 G4cout << "to: pmanager->AddProcess(theCerenkovProcess);" << G4endl;
00124 G4cout << " pmanager->SetProcessOrdering(theCerenkovProcess,idxPostStep);" << G4endl;
00125
00126 SetProcessSubType(fCerenkov);
00127
00128 fTrackSecondariesFirst = false;
00129 fMaxBetaChange = 0.;
00130 fMaxPhotons = 0;
00131 fPhotonWeight = 1.0;
00132
00133 thePhysicsTable = NULL;
00134
00135 if (verboseLevel>0) {
00136 G4cout << GetProcessName() << " is created " << G4endl;
00137 }
00138
00139 BuildThePhysicsTable();
00140 }
00141
00142
00143
00144
00145
00147
00149
00150 DsG4Cerenkov::~DsG4Cerenkov()
00151 {
00152 if (thePhysicsTable != NULL) {
00153 thePhysicsTable->clearAndDestroy();
00154 delete thePhysicsTable;
00155 }
00156 }
00157
00159
00161
00162
00163
00164
00165 G4VParticleChange*
00166 DsG4Cerenkov::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
00167
00168
00169
00170
00171
00172
00173
00174
00175 {
00177
00179
00180 aParticleChange.Initialize(aTrack);
00181
00182 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
00183 const G4Material* aMaterial = aTrack.GetMaterial();
00184
00185 G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
00186 G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
00187
00188 G4ThreeVector x0 = pPreStepPoint->GetPosition();
00189 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
00190 G4double t0 = pPreStepPoint->GetGlobalTime();
00191
00192 G4MaterialPropertiesTable* aMaterialPropertiesTable =
00193 aMaterial->GetMaterialPropertiesTable();
00194 if (!aMaterialPropertiesTable) return pParticleChange;
00195
00196 const G4MaterialPropertyVector* Rindex =
00197 aMaterialPropertiesTable->GetProperty("RINDEX");
00198 if (!Rindex) return pParticleChange;
00199
00200
00201 const G4double charge = aParticle->GetDefinition()->GetPDGCharge();
00202
00203
00204 const G4double beta = (pPreStepPoint ->GetBeta() +
00205 pPostStepPoint->GetBeta())/2.;
00206
00207 G4double MeanNumberOfPhotons =
00208 GetAverageNumberOfPhotons(charge,beta,aMaterial,Rindex);
00209
00210 if (MeanNumberOfPhotons <= 0.0) {
00211
00212
00213
00214 aParticleChange.SetNumberOfSecondaries(0);
00215
00216 return pParticleChange;
00217
00218 }
00219
00220 G4double step_length;
00221 step_length = aStep.GetStepLength();
00222
00223 MeanNumberOfPhotons = MeanNumberOfPhotons * step_length;
00224
00225
00226 MeanNumberOfPhotons/=fPhotonWeight;
00227 if ( fApplyPreQE ) MeanNumberOfPhotons *= fPreQE;
00228 G4int NumPhotons = (G4int) G4Poisson(MeanNumberOfPhotons);
00229
00230 if (NumPhotons <= 0) {
00231
00232 aParticleChange.SetNumberOfSecondaries(0);
00233 return pParticleChange;
00234 }
00235
00237
00238 aParticleChange.SetNumberOfSecondaries(NumPhotons);
00239
00240 if (fTrackSecondariesFirst) {
00241 if (aTrack.GetTrackStatus() == fAlive )
00242 aParticleChange.ProposeTrackStatus(fSuspend);
00243 }
00244
00246
00247 G4double Pmin = Rindex->GetMinPhotonEnergy();
00248 G4double Pmax = Rindex->GetMaxPhotonEnergy();
00249 G4double dp = Pmax - Pmin;
00250
00251 G4double nMax = Rindex->GetMaxProperty();
00252
00253 G4double BetaInverse = 1./beta;
00254
00255 G4double maxCos = BetaInverse / nMax;
00256 G4double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
00257
00258 const G4double beta1 = pPreStepPoint ->GetBeta();
00259 const G4double beta2 = pPostStepPoint->GetBeta();
00260
00261 G4double MeanNumberOfPhotons1 =
00262 GetAverageNumberOfPhotons(charge,beta1,aMaterial,Rindex);
00263 G4double MeanNumberOfPhotons2 =
00264 GetAverageNumberOfPhotons(charge,beta2,aMaterial,Rindex);
00265
00266 for (G4int i = 0; i < NumPhotons; i++) {
00267
00268 G4double rand=0;
00269 G4double sampledEnergy=0, sampledRI=0;
00270 G4double cosTheta=0, sin2Theta=0;
00271
00272
00273 do {
00274 rand = G4UniformRand();
00275 sampledEnergy = Pmin + rand * dp;
00276 sampledRI = Rindex->GetProperty(sampledEnergy);
00277 cosTheta = BetaInverse / sampledRI;
00278
00279 sin2Theta = (1.0 - cosTheta)*(1.0 + cosTheta);
00280 rand = G4UniformRand();
00281
00282 } while (rand*maxSin2 > sin2Theta);
00283
00284
00285
00286 rand = G4UniformRand();
00287
00288 G4double phi = twopi*rand;
00289 G4double sinPhi = sin(phi);
00290 G4double cosPhi = cos(phi);
00291
00292
00293
00294
00295
00296 G4double sinTheta = sqrt(sin2Theta);
00297 G4double px = sinTheta*cosPhi;
00298 G4double py = sinTheta*sinPhi;
00299 G4double pz = cosTheta;
00300
00301
00302
00303
00304
00305
00306 G4ParticleMomentum photonMomentum(px, py, pz);
00307
00308
00309
00310
00311 photonMomentum.rotateUz(p0);
00312
00313
00314
00315 G4double sx = cosTheta*cosPhi;
00316 G4double sy = cosTheta*sinPhi;
00317 G4double sz = -sinTheta;
00318
00319 G4ThreeVector photonPolarization(sx, sy, sz);
00320
00321
00322
00323 photonPolarization.rotateUz(p0);
00324
00325
00326
00327 G4DynamicParticle* aCerenkovPhoton =
00328 new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(),
00329 photonMomentum);
00330 aCerenkovPhoton->SetPolarization
00331 (photonPolarization.x(),
00332 photonPolarization.y(),
00333 photonPolarization.z());
00334
00335 aCerenkovPhoton->SetKineticEnergy(sampledEnergy);
00336
00337
00338
00339 G4double delta, NumberOfPhotons, N;
00340
00341 do {
00342 rand = G4UniformRand();
00343 delta = rand * aStep.GetStepLength();
00344 NumberOfPhotons = MeanNumberOfPhotons1 - delta *
00345 (MeanNumberOfPhotons1-MeanNumberOfPhotons2)/
00346 aStep.GetStepLength();
00347 N = G4UniformRand() *
00348 std::max(MeanNumberOfPhotons1,MeanNumberOfPhotons2);
00349 } while (N > NumberOfPhotons);
00350
00351 G4double deltaTime = delta /
00352 ((pPreStepPoint->GetVelocity()+
00353 pPostStepPoint->GetVelocity())/2.);
00354
00355 G4double aSecondaryTime = t0 + deltaTime;
00356
00357 G4ThreeVector aSecondaryPosition =
00358 x0 + rand * aStep.GetDeltaPosition();
00359
00360 G4Track* aSecondaryTrack =
00361 new G4Track(aCerenkovPhoton,aSecondaryTime,aSecondaryPosition);
00362
00363 aSecondaryTrack->SetTouchableHandle(
00364 aStep.GetPreStepPoint()->GetTouchableHandle());
00365
00366 aSecondaryTrack->SetParentID(aTrack.GetTrackID());
00367
00368 aParticleChange.AddSecondary(aSecondaryTrack);
00369
00370
00371 aSecondaryTrack->SetWeight(fPhotonWeight*aTrack.GetWeight());
00372 aParticleChange.SetSecondaryWeightByProcess(true);
00373 }
00374
00375 if (verboseLevel>0) {
00376 G4cout << "\n Exiting from DsG4Cerenkov::DoIt -- NumberOfSecondaries = "
00377 << aParticleChange.GetNumberOfSecondaries() << G4endl;
00378 }
00379
00380 return pParticleChange;
00381 }
00382
00383
00384
00385
00386
00387 void DsG4Cerenkov::BuildThePhysicsTable()
00388 {
00389 if (thePhysicsTable) return;
00390
00391 const G4MaterialTable* theMaterialTable=
00392 G4Material::GetMaterialTable();
00393 G4int numOfMaterials = G4Material::GetNumberOfMaterials();
00394
00395
00396
00397 thePhysicsTable = new G4PhysicsTable(numOfMaterials);
00398
00399
00400
00401
00402
00403 for (G4int i=0 ; i < numOfMaterials; i++)
00404 {
00405 G4PhysicsOrderedFreeVector* aPhysicsOrderedFreeVector =
00406 new G4PhysicsOrderedFreeVector();
00407
00408
00409
00410
00411 G4Material* aMaterial = (*theMaterialTable)[i];
00412
00413 G4MaterialPropertiesTable* aMaterialPropertiesTable =
00414 aMaterial->GetMaterialPropertiesTable();
00415
00416 if (aMaterialPropertiesTable) {
00417
00418 G4MaterialPropertyVector* theRefractionIndexVector =
00419 aMaterialPropertiesTable->GetProperty("RINDEX");
00420
00421 if (theRefractionIndexVector) {
00422
00423
00424
00425
00426 theRefractionIndexVector->ResetIterator();
00427 ++(*theRefractionIndexVector);
00428
00429 G4double currentRI = theRefractionIndexVector->
00430 GetProperty();
00431
00432 if (currentRI > 1.0) {
00433
00434
00435
00436
00437 G4double currentPM = theRefractionIndexVector->
00438 GetPhotonEnergy();
00439 G4double currentCAI = 0.0;
00440
00441 aPhysicsOrderedFreeVector->
00442 InsertValues(currentPM , currentCAI);
00443
00444
00445
00446 G4double prevPM = currentPM;
00447 G4double prevCAI = currentCAI;
00448 G4double prevRI = currentRI;
00449
00450
00451
00452
00453 while(++(*theRefractionIndexVector))
00454 {
00455 currentRI=theRefractionIndexVector->
00456 GetProperty();
00457
00458 currentPM = theRefractionIndexVector->
00459 GetPhotonEnergy();
00460
00461 currentCAI = 0.5*(1.0/(prevRI*prevRI) +
00462 1.0/(currentRI*currentRI));
00463
00464 currentCAI = prevCAI +
00465 (currentPM - prevPM) * currentCAI;
00466
00467 aPhysicsOrderedFreeVector->
00468 InsertValues(currentPM, currentCAI);
00469
00470 prevPM = currentPM;
00471 prevCAI = currentCAI;
00472 prevRI = currentRI;
00473 }
00474
00475 }
00476 }
00477 }
00478
00479
00480
00481
00482
00483
00484 thePhysicsTable->insertAt(i,aPhysicsOrderedFreeVector);
00485
00486 }
00487 }
00488
00489
00490
00491
00492
00493 G4double DsG4Cerenkov::GetMeanFreePath(const G4Track&,
00494 G4double,
00495 G4ForceCondition*)
00496 {
00497 return 1.;
00498 }
00499
00500 G4double DsG4Cerenkov::PostStepGetPhysicalInteractionLength(
00501 const G4Track& aTrack,
00502 G4double,
00503 G4ForceCondition* condition)
00504 {
00505 *condition = NotForced;
00506 G4double StepLimit = DBL_MAX;
00507
00508 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
00509 const G4Material* aMaterial = aTrack.GetMaterial();
00510 const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
00511
00512 const G4double kineticEnergy = aParticle->GetKineticEnergy();
00513 const G4ParticleDefinition* particleType = aParticle->GetDefinition();
00514 const G4double mass = particleType->GetPDGMass();
00515
00516
00517 const G4double beta = aParticle->GetTotalMomentum() /
00518 aParticle->GetTotalEnergy();
00519
00520 const G4double gamma = 1./std::sqrt(1.-beta*beta);
00521
00522 G4MaterialPropertiesTable* aMaterialPropertiesTable =
00523 aMaterial->GetMaterialPropertiesTable();
00524
00525 const G4MaterialPropertyVector* Rindex = NULL;
00526
00527 if (aMaterialPropertiesTable)
00528 Rindex = aMaterialPropertiesTable->GetProperty("RINDEX");
00529
00530 G4double nMax;
00531 if (Rindex) {
00532 nMax = Rindex->GetMaxProperty();
00533 } else {
00534 return StepLimit;
00535 }
00536
00537 G4double BetaMin = 1./nMax;
00538 if ( BetaMin >= 1. ) return StepLimit;
00539
00540 G4double GammaMin = 1./std::sqrt(1.-BetaMin*BetaMin);
00541
00542 if (gamma < GammaMin ) return StepLimit;
00543
00544 G4double kinEmin = mass*(GammaMin-1.);
00545
00546 G4double RangeMin = G4LossTableManager::Instance()->
00547 GetRange(particleType,
00548 kinEmin,
00549 couple);
00550 G4double Range = G4LossTableManager::Instance()->
00551 GetRange(particleType,
00552 kineticEnergy,
00553 couple);
00554
00555 G4double Step = Range - RangeMin;
00556 if (Step < 1.*um ) return StepLimit;
00557
00558 if (Step > 0. && Step < StepLimit) StepLimit = Step;
00559
00560
00561
00562
00563
00564 if (fMaxPhotons > 0) {
00565
00566
00567 const G4double charge = aParticle->
00568 GetDefinition()->GetPDGCharge();
00569
00570 G4double MeanNumberOfPhotons =
00571 GetAverageNumberOfPhotons(charge,beta,aMaterial,Rindex);
00572
00573 G4double Step = 0.;
00574 if (MeanNumberOfPhotons > 0.0) Step = fMaxPhotons /
00575 MeanNumberOfPhotons;
00576
00577 if (Step > 0. && Step < StepLimit) StepLimit = Step;
00578 }
00579
00580
00581 if (fMaxBetaChange > 0.) {
00582
00583 G4double dedx = G4LossTableManager::Instance()->
00584 GetDEDX(particleType,
00585 kineticEnergy,
00586 couple);
00587
00588 G4double deltaGamma = gamma -
00589 1./std::sqrt(1.-beta*beta*
00590 (1.-fMaxBetaChange)*
00591 (1.-fMaxBetaChange));
00592
00593 G4double Step = mass * deltaGamma / dedx;
00594
00595 if (Step > 0. && Step < StepLimit) StepLimit = Step;
00596
00597 }
00598
00599 *condition = StronglyForced;
00600 return StepLimit;
00601 }
00602
00603
00604
00605
00606
00607
00608
00609 G4double
00610 DsG4Cerenkov::GetAverageNumberOfPhotons(const G4double charge,
00611 const G4double beta,
00612 const G4Material* aMaterial,
00613 const G4MaterialPropertyVector* Rindex) const
00614 {
00615 const G4double Rfact = 369.81/(eV * cm);
00616
00617 if(beta <= 0.0)return 0.0;
00618
00619 G4double BetaInverse = 1./beta;
00620
00621
00622
00623
00624
00625
00626 G4int materialIndex = aMaterial->GetIndex();
00627
00628
00629
00630
00631 G4PhysicsOrderedFreeVector* CerenkovAngleIntegrals =
00632 (G4PhysicsOrderedFreeVector*)((*thePhysicsTable)(materialIndex));
00633
00634 if(!(CerenkovAngleIntegrals->IsFilledVectorExist()))return 0.0;
00635
00636
00637 G4double Pmin = Rindex->GetMinPhotonEnergy();
00638 G4double Pmax = Rindex->GetMaxPhotonEnergy();
00639
00640
00641 G4double nMin = Rindex->GetMinProperty();
00642 G4double nMax = Rindex->GetMaxProperty();
00643
00644
00645 G4double CAImax = CerenkovAngleIntegrals->GetMaxValue();
00646
00647 G4double dp=0, ge=0;
00648
00649
00650
00651 if (nMax < BetaInverse) {
00652 dp = 0;
00653 ge = 0;
00654 }
00655
00656
00657
00658 else if (nMin > BetaInverse) {
00659 dp = Pmax - Pmin;
00660 ge = CAImax;
00661 }
00662
00663
00664
00665
00666
00667
00668
00669 else {
00670 Pmin = Rindex->GetPhotonEnergy(BetaInverse);
00671 dp = Pmax - Pmin;
00672
00673
00674
00675 G4bool isOutRange;
00676 G4double CAImin = CerenkovAngleIntegrals->
00677 GetValue(Pmin, isOutRange);
00678 ge = CAImax - CAImin;
00679
00680 if (verboseLevel>0) {
00681 G4cout << "CAImin = " << CAImin << G4endl;
00682 G4cout << "ge = " << ge << G4endl;
00683 }
00684 }
00685
00686
00687 G4double NumPhotons = Rfact * charge/eplus * charge/eplus *
00688 (dp - ge * BetaInverse*BetaInverse);
00689
00690 return NumPhotons;
00691 }
00692