File indexing completed on 2026-04-10 07:50:30
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 #include "G4ios.hh"
0065 #include "G4PhysicalConstants.hh"
0066 #include "G4SystemOfUnits.hh"
0067 #include "G4Poisson.hh"
0068 #include "G4EmProcessSubType.hh"
0069
0070 #include "G4LossTableManager.hh"
0071 #include "G4MaterialCutsCouple.hh"
0072 #include "G4ParticleDefinition.hh"
0073
0074 #include "G4Version.hh"
0075
0076 #include "Local_G4Cerenkov_modified.hh"
0077
0078 #ifdef INSTRUMENTED
0079 #include "OpticksDebug.hh"
0080 #include "OpticksRandom.hh"
0081 #endif
0082
0083 #ifdef STANDALONE
0084 #include "SLOG.hh"
0085 #include "U4.hh"
0086 #endif
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109 Local_G4Cerenkov_modified::Local_G4Cerenkov_modified(const G4String& processName, G4ProcessType type)
0110 : G4VProcess(processName, type),
0111 fTrackSecondariesFirst(false),
0112 fMaxBetaChange(0.0),
0113 fMaxPhotons(0),
0114 fStackingFlag(true),
0115 #ifdef INSTRUMENTED
0116 override_fNumPhotons(0),
0117 #endif
0118 fNumPhotons(0)
0119 {
0120 SetProcessSubType(fCerenkov);
0121
0122 thePhysicsTable = nullptr;
0123
0124 if (verboseLevel>0) {
0125 G4cout << GetProcessName() << " is created " << G4endl;
0126 }
0127 }
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 Local_G4Cerenkov_modified::~Local_G4Cerenkov_modified()
0138 {
0139 if (thePhysicsTable != nullptr) {
0140 thePhysicsTable->clearAndDestroy();
0141 delete thePhysicsTable;
0142 }
0143 }
0144
0145
0146
0147
0148
0149 G4bool Local_G4Cerenkov_modified::IsApplicable(const G4ParticleDefinition& aParticleType)
0150 {
0151 G4bool result = false;
0152
0153 if (aParticleType.GetPDGCharge() != 0.0 &&
0154 aParticleType.GetPDGMass() != 0.0 &&
0155 aParticleType.GetParticleName() != "chargedgeantino" &&
0156 !aParticleType.IsShortLived() ) { result = true; }
0157
0158 return result;
0159 }
0160
0161 void Local_G4Cerenkov_modified::SetTrackSecondariesFirst(const G4bool state)
0162 {
0163 fTrackSecondariesFirst = state;
0164 }
0165
0166 void Local_G4Cerenkov_modified::SetMaxBetaChangePerStep(const G4double value)
0167 {
0168 fMaxBetaChange = value*CLHEP::perCent;
0169 }
0170
0171 void Local_G4Cerenkov_modified::SetMaxNumPhotonsPerStep(const G4int NumPhotons)
0172 {
0173 fMaxPhotons = NumPhotons;
0174 }
0175
0176 void Local_G4Cerenkov_modified::BuildPhysicsTable(const G4ParticleDefinition&)
0177 {
0178 if (!thePhysicsTable) BuildThePhysicsTable();
0179 }
0180
0181
0182
0183
0184 G4VParticleChange* Local_G4Cerenkov_modified::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
0185
0186
0187
0188
0189
0190
0191
0192
0193 {
0194
0195
0196
0197
0198
0199 aParticleChange.Initialize(aTrack);
0200
0201 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
0202 const G4Material* aMaterial = aTrack.GetMaterial();
0203
0204 G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
0205 G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
0206
0207 G4ThreeVector x0 = pPreStepPoint->GetPosition();
0208 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
0209 G4double t0 = pPreStepPoint->GetGlobalTime();
0210
0211 G4MaterialPropertiesTable* aMaterialPropertiesTable =
0212 aMaterial->GetMaterialPropertiesTable();
0213 if (!aMaterialPropertiesTable) return pParticleChange;
0214
0215 G4MaterialPropertyVector* Rindex =
0216 aMaterialPropertiesTable->GetProperty(kRINDEX);
0217 if (!Rindex) return pParticleChange;
0218
0219
0220 G4double charge = aParticle->GetDefinition()->GetPDGCharge();
0221
0222
0223 G4double beta = (pPreStepPoint->GetBeta() + pPostStepPoint->GetBeta())*0.5;
0224
0225 fNumPhotons = 0;
0226
0227 G4double MeanNumberOfPhotons =
0228 GetAverageNumberOfPhotons(charge,beta,aMaterial,Rindex);
0229
0230 if (MeanNumberOfPhotons <= 0.0) {
0231
0232
0233
0234 aParticleChange.SetNumberOfSecondaries(0);
0235
0236 return pParticleChange;
0237
0238 }
0239
0240 G4double step_length = aStep.GetStepLength();
0241
0242 MeanNumberOfPhotons = MeanNumberOfPhotons * step_length;
0243
0244 fNumPhotons = (G4int) G4Poisson(MeanNumberOfPhotons);
0245
0246 #ifdef INSTRUMENTED
0247 if( override_fNumPhotons > 0 )
0248 {
0249 fNumPhotons = override_fNumPhotons ;
0250 }
0251 #endif
0252
0253
0254
0255
0256
0257
0258
0259
0260 if ( fNumPhotons <= 0 ) {
0261
0262
0263
0264 aParticleChange.SetNumberOfSecondaries(0);
0265
0266 fNumPhotons1 = 0;
0267 fNumPhotons2 = 0;
0268
0269 return pParticleChange;
0270
0271 }
0272
0273
0274 #if G4VERSION_NUMBER < 1100
0275 G4double Pmin = Rindex->GetMinLowEdgeEnergy();
0276 G4double Pmax = Rindex->GetMaxLowEdgeEnergy();
0277 #else
0278 G4double Pmin = Rindex->GetMinEnergy();
0279 G4double Pmax = Rindex->GetMaxEnergy();
0280 #endif
0281 G4double dp = Pmax - Pmin;
0282
0283
0284 #ifdef FLOAT_TEST
0285 float nMax = Rindex->GetMaxValue();
0286 #else
0287 G4double nMax = Rindex->GetMaxValue();
0288 #endif
0289 if (Rindex) {
0290
0291 size_t ri_sz = Rindex->GetVectorLength();
0292
0293 for (size_t i = 0; i < ri_sz; ++i) {
0294 if ((*Rindex)[i]>nMax) nMax = (*Rindex)[i];
0295 }
0296 }
0297
0298 G4double BetaInverse = 1./beta;
0299
0300 #ifdef FLOAT_TEST
0301 float maxCos = BetaInverse / nMax;
0302 float maxSin2 = (1.f - maxCos) * (1.f + maxCos);
0303 #else
0304 G4double maxCos = BetaInverse / nMax;
0305 G4double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
0306 #endif
0307
0308 G4double beta1 = pPreStepPoint ->GetBeta();
0309 G4double beta2 = pPostStepPoint->GetBeta();
0310
0311 G4double MeanNumberOfPhotons1 =
0312 GetAverageNumberOfPhotons(charge,beta1,aMaterial,Rindex);
0313 G4double MeanNumberOfPhotons2 =
0314 GetAverageNumberOfPhotons(charge,beta2,aMaterial,Rindex);
0315
0316 fNumPhotons1 = MeanNumberOfPhotons1;
0317 fNumPhotons2 = MeanNumberOfPhotons2;
0318
0319
0320 #ifdef INSTRUMENTED
0321 par->append( BetaInverse, "BetaInverse" );
0322 par->append( beta , "beta" );
0323 par->append( Pmin , "Pmin" );
0324 par->append( Pmax , "Pmax" );
0325
0326 par->append( nMax , "nMax" );
0327 par->append( maxCos , "maxCos" );
0328 par->append( maxSin2 , "maxSin2" );
0329 par->append( fNumPhotons, "fNumPhotons" );
0330 #endif
0331
0332
0333
0334 if (MeanNumberOfPhotons1 <= 0.0 or MeanNumberOfPhotons2<=0.0) {
0335
0336
0337
0338 aParticleChange.SetNumberOfSecondaries(0);
0339
0340
0341 fNumPhotons = 0;
0342 fNumPhotons1 = 0;
0343 fNumPhotons2 = 0;
0344
0345 return pParticleChange;
0346
0347 }
0348
0349
0350 if (!fStackingFlag) {
0351 aParticleChange.SetNumberOfSecondaries(0);
0352
0353 return pParticleChange;
0354 }
0355
0356
0357
0358 #ifdef STANDALONE
0359 fNumPhotons = std::min( fNumPhotons, 5 );
0360 #endif
0361
0362 aParticleChange.SetNumberOfSecondaries(fNumPhotons);
0363
0364 if (fTrackSecondariesFirst) {
0365 if (aTrack.GetTrackStatus() == fAlive )
0366 aParticleChange.ProposeTrackStatus(fSuspend);
0367 }
0368
0369
0370 #ifdef STANDALONE
0371 U4::CollectGenstep_G4Cerenkov_modified(
0372 &aTrack,
0373 &aStep,
0374 fNumPhotons,
0375 BetaInverse,
0376 Pmin,
0377 Pmax,
0378 maxCos,
0379 maxSin2,
0380 MeanNumberOfPhotons1,
0381 MeanNumberOfPhotons2
0382 );
0383 #endif
0384
0385 #ifdef STANDALONE
0386 U4::GenPhotonAncestor(&aTrack);
0387 #endif
0388
0389 for (G4int i = 0; i < fNumPhotons; i++) {
0390
0391
0392 #ifdef STANDALONE
0393 U4::GenPhotonBegin(i);
0394 #endif
0395
0396 #ifdef FLOAT_TEST
0397 float rand(0.f);
0398 float rand0(0.f);
0399 float rand1(0.f) ;
0400 float sampledEnergy(0.f);
0401 float sampledRI(0.f);
0402 float cosTheta(0.f) ;
0403 float sin2Theta(0.f) ;
0404 #else
0405 G4double rand(0.);
0406 G4double rand0(0.);
0407 G4double rand1(0.) ;
0408 G4double sampledEnergy(0.);
0409 G4double sampledRI(0.);
0410 G4double cosTheta(0.);
0411 G4double sin2Theta(0.);
0412 #endif
0413
0414 #ifdef INSTRUMENTED
0415 unsigned head_count = 0 ;
0416 unsigned tail_count = 0 ;
0417 unsigned continue_count = 0 ;
0418 unsigned condition_count = 0 ;
0419 int seqidx = -1 ;
0420 if(rnd)
0421 {
0422 rnd->setSequenceIndex(i);
0423 seqidx = rnd->getSequenceIndex();
0424
0425 if(i < 10) std::cout
0426 << " i " << std::setw(6) << i
0427 << " seqidx " << std::setw(7) << seqidx
0428 << " Pmin/eV " << std::fixed << std::setw(10) << std::setprecision(5) << Pmin/eV
0429 << " Pmax/eV " << std::fixed << std::setw(10) << std::setprecision(5) << Pmax/eV
0430 << " dp/eV " << std::fixed << std::setw(10) << std::setprecision(5) << dp/eV
0431 << " maxSin2 " << std::fixed << std::setw(10) << std::setprecision(5) << maxSin2
0432 << std::endl
0433 ;
0434
0435 }
0436 #endif
0437
0438
0439
0440 do {
0441 #ifdef INSTRUMENTED
0442 head_count += 1 ;
0443 #endif
0444 rand0 = G4UniformRand();
0445 sampledEnergy = Pmin + rand0 * dp;
0446 sampledRI = Rindex->Value(sampledEnergy);
0447
0448
0449 #ifdef SKIP_CONTINUE
0450 #else
0451
0452 if (sampledRI < BetaInverse) {
0453 #ifdef INSTRUMENTED
0454 continue_count += 1 ;
0455 #endif
0456 continue;
0457 }
0458
0459 #endif
0460
0461 #ifdef INSTRUMENTED
0462 tail_count += 1 ;
0463 #endif
0464
0465
0466 cosTheta = BetaInverse / sampledRI;
0467
0468
0469
0470
0471
0472
0473
0474 #ifdef FLOAT_TEST
0475 sin2Theta = (1.f - cosTheta)*(1.f + cosTheta);
0476 #else
0477 sin2Theta = (1.0 - cosTheta)*(1.0 + cosTheta);
0478 #endif
0479
0480 rand1 = G4UniformRand();
0481 #ifdef ONE_RAND
0482 rand1 = 1.0 ;
0483 #endif
0484
0485
0486 #ifdef INSTRUMENTED
0487
0488 if( i < 10 ) std::cout
0489 << " tc " << std::setw(6) << tail_count
0490 << " u0 " << std::fixed << std::setw(10) << std::setprecision(5) << rand0
0491 << " eV " << std::fixed << std::setw(10) << std::setprecision(5) << sampledEnergy/eV
0492 << " ri " << std::fixed << std::setw(10) << std::setprecision(5) << sampledRI
0493 << " ct " << std::fixed << std::setw(10) << std::setprecision(5) << cosTheta
0494 << " s2 " << std::fixed << std::setw(10) << std::setprecision(5) << sin2Theta
0495 << " rand1*maxSin2 " << std::fixed << std::setw(10) << std::setprecision(5) << rand1*maxSin2
0496 << " rand1*maxSin2 - sin2Theta " << std::fixed << std::setw(10) << std::setprecision(5) << rand1*maxSin2 - sin2Theta
0497 << " loop " << ( rand1*maxSin2 > sin2Theta ? "Y" : "N" )
0498 << std::endl
0499 ;
0500
0501
0502 } while ( looping_condition(condition_count) && rand1*maxSin2 > sin2Theta );
0503 #else
0504 } while (rand1*maxSin2 > sin2Theta);
0505 #endif
0506
0507 #ifdef INSTRUMENTED
0508 G4double sampledEnergy_eV = sampledEnergy/eV ;
0509 G4double sampledWavelength_nm = h_Planck*c_light/sampledEnergy/nm ;
0510
0511 gen->append( sampledEnergy_eV , "sampledEnergy" );
0512 gen->append( sampledWavelength_nm , "sampledWavelength" );
0513 gen->append( sampledRI , "sampledRI" );
0514 gen->append( cosTheta , "cosTheta" );
0515
0516 gen->append( sin2Theta , "sin2Theta" );
0517 gen->append( head_count , tail_count, "head_tail" );
0518 gen->append( continue_count , condition_count, "continue_condition" );
0519 gen->append( BetaInverse , "BetaInverse" );
0520
0521 if(rnd)
0522 {
0523 rnd->setSequenceIndex(-1);
0524 }
0525 #endif
0526
0527
0528
0529
0530
0531
0532
0533 rand = G4UniformRand();
0534
0535 G4double phi = twopi*rand;
0536 G4double sinPhi = std::sin(phi);
0537 G4double cosPhi = std::cos(phi);
0538
0539
0540
0541
0542
0543 G4double sinTheta = std::sqrt(sin2Theta);
0544 G4double px = sinTheta*cosPhi;
0545 G4double py = sinTheta*sinPhi;
0546 G4double pz = cosTheta;
0547
0548
0549
0550
0551
0552
0553 G4ParticleMomentum photonMomentum(px, py, pz);
0554
0555
0556
0557
0558 photonMomentum.rotateUz(p0);
0559
0560
0561
0562 G4double sx = cosTheta*cosPhi;
0563 G4double sy = cosTheta*sinPhi;
0564 G4double sz = -sinTheta;
0565
0566 G4ThreeVector photonPolarization(sx, sy, sz);
0567
0568
0569
0570 photonPolarization.rotateUz(p0);
0571
0572
0573
0574 G4DynamicParticle* aCerenkovPhoton =
0575 new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(),photonMomentum);
0576
0577 aCerenkovPhoton->SetPolarization(photonPolarization.x(),
0578 photonPolarization.y(),
0579 photonPolarization.z());
0580
0581 aCerenkovPhoton->SetKineticEnergy(sampledEnergy);
0582
0583
0584
0585 G4double NumberOfPhotons, N;
0586
0587 do {
0588 rand = G4UniformRand();
0589 NumberOfPhotons = MeanNumberOfPhotons1 - rand *
0590 (MeanNumberOfPhotons1-MeanNumberOfPhotons2);
0591 N = G4UniformRand() *
0592 std::max(MeanNumberOfPhotons1,MeanNumberOfPhotons2);
0593
0594 } while (N > NumberOfPhotons);
0595
0596 G4double delta = rand * aStep.GetStepLength();
0597
0598 G4double deltaTime = delta / (pPreStepPoint->GetVelocity()+
0599 rand*(pPostStepPoint->GetVelocity()-
0600 pPreStepPoint->GetVelocity())*0.5);
0601
0602 G4double aSecondaryTime = t0 + deltaTime;
0603
0604 G4ThreeVector aSecondaryPosition = x0 + rand * aStep.GetDeltaPosition();
0605
0606 G4Track* aSecondaryTrack =
0607 new G4Track(aCerenkovPhoton,aSecondaryTime,aSecondaryPosition);
0608
0609 aSecondaryTrack->SetTouchableHandle(
0610 aStep.GetPreStepPoint()->GetTouchableHandle());
0611
0612 aSecondaryTrack->SetParentID(aTrack.GetTrackID());
0613
0614 aParticleChange.AddSecondary(aSecondaryTrack);
0615
0616 #ifdef STANDALONE
0617 U4::GenPhotonEnd(i, aSecondaryTrack);
0618 #endif
0619
0620
0621
0622 }
0623
0624 if (verboseLevel>0) {
0625 G4cout <<"\n Exiting from Local_G4Cerenkov_modified::DoIt -- NumberOfSecondaries = "
0626 << aParticleChange.GetNumberOfSecondaries() << G4endl;
0627 }
0628
0629 return pParticleChange;
0630 }
0631
0632
0633 #ifdef INSTRUMENTED
0634 bool Local_G4Cerenkov_modified::looping_condition(unsigned& count)
0635 {
0636 count += 1 ;
0637 return true ;
0638 }
0639
0640
0641 #endif
0642
0643
0644
0645
0646
0647
0648 void Local_G4Cerenkov_modified::BuildThePhysicsTable()
0649 {
0650 if (thePhysicsTable) return;
0651
0652 const G4MaterialTable* theMaterialTable=
0653 G4Material::GetMaterialTable();
0654 G4int numOfMaterials = G4Material::GetNumberOfMaterials();
0655
0656
0657
0658 thePhysicsTable = new G4PhysicsTable(numOfMaterials);
0659
0660
0661
0662 for (G4int i=0 ; i < numOfMaterials; i++) {
0663
0664 G4PhysicsOrderedFreeVector* aPhysicsOrderedFreeVector = 0;
0665
0666
0667
0668
0669 G4Material* aMaterial = (*theMaterialTable)[i];
0670
0671 G4MaterialPropertiesTable* aMaterialPropertiesTable =
0672 aMaterial->GetMaterialPropertiesTable();
0673
0674 if (aMaterialPropertiesTable) {
0675 aPhysicsOrderedFreeVector = new G4PhysicsOrderedFreeVector();
0676 G4MaterialPropertyVector* theRefractionIndexVector =
0677 aMaterialPropertiesTable->GetProperty(kRINDEX);
0678
0679 if (theRefractionIndexVector) {
0680
0681
0682
0683
0684 G4double currentRI = (*theRefractionIndexVector)[0];
0685
0686 if (currentRI > 1.0) {
0687
0688
0689
0690
0691 G4double currentPM = theRefractionIndexVector->Energy(0);
0692 G4double currentCAI = 0.0;
0693
0694 aPhysicsOrderedFreeVector->InsertValues(currentPM , currentCAI);
0695
0696
0697
0698 G4double prevPM = currentPM;
0699 G4double prevCAI = currentCAI;
0700 G4double prevRI = currentRI;
0701
0702
0703
0704
0705 for (size_t ii = 1;
0706 ii < theRefractionIndexVector->GetVectorLength();
0707 ++ii) {
0708 currentRI = (*theRefractionIndexVector)[ii];
0709 currentPM = theRefractionIndexVector->Energy(ii);
0710
0711 currentCAI = 0.5*(1.0/(prevRI*prevRI) +
0712 1.0/(currentRI*currentRI));
0713
0714 currentCAI = prevCAI + (currentPM - prevPM) * currentCAI;
0715
0716 aPhysicsOrderedFreeVector->
0717 InsertValues(currentPM, currentCAI);
0718
0719 prevPM = currentPM;
0720 prevCAI = currentCAI;
0721 prevRI = currentRI;
0722 }
0723
0724 }
0725 }
0726 }
0727
0728
0729
0730
0731
0732
0733 thePhysicsTable->insertAt(i,aPhysicsOrderedFreeVector);
0734
0735 }
0736 }
0737
0738
0739
0740
0741
0742 G4double Local_G4Cerenkov_modified::GetMeanFreePath(const G4Track&,
0743 G4double,
0744 G4ForceCondition*)
0745 {
0746 return 1.;
0747 }
0748
0749 G4double Local_G4Cerenkov_modified::PostStepGetPhysicalInteractionLength(
0750 const G4Track& aTrack,
0751 G4double,
0752 G4ForceCondition* condition)
0753 {
0754 *condition = NotForced;
0755 G4double StepLimit = DBL_MAX;
0756
0757 const G4Material* aMaterial = aTrack.GetMaterial();
0758 G4int materialIndex = aMaterial->GetIndex();
0759
0760
0761
0762
0763 if(!(*thePhysicsTable)[materialIndex]) { return StepLimit; }
0764
0765 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
0766 const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
0767
0768 G4double kineticEnergy = aParticle->GetKineticEnergy();
0769 const G4ParticleDefinition* particleType = aParticle->GetDefinition();
0770 G4double mass = particleType->GetPDGMass();
0771
0772
0773 G4double beta = aParticle->GetTotalMomentum() /
0774 aParticle->GetTotalEnergy();
0775
0776 G4double gamma = aParticle->GetTotalEnergy()/mass;
0777
0778
0779 G4MaterialPropertiesTable* aMaterialPropertiesTable =
0780 aMaterial->GetMaterialPropertiesTable();
0781
0782 G4MaterialPropertyVector* Rindex = NULL;
0783
0784 if (aMaterialPropertiesTable)
0785 Rindex = aMaterialPropertiesTable->GetProperty(kRINDEX);
0786
0787 G4double nMax;
0788 if (Rindex) {
0789
0790 size_t ri_sz = Rindex->GetVectorLength();
0791 nMax = (*Rindex)[0];
0792 for (size_t i = 1; i < ri_sz; ++i) {
0793 if ((*Rindex)[i]>nMax) nMax = (*Rindex)[i];
0794 }
0795 } else {
0796 return StepLimit;
0797 }
0798
0799 G4double BetaMin = 1./nMax;
0800
0801 if ( BetaMin >= 1. ) return StepLimit;
0802
0803 G4double GammaMin = 1./std::sqrt(1.-BetaMin*BetaMin);
0804
0805 if (gamma < GammaMin ) return StepLimit;
0806
0807 G4double kinEmin = mass*(GammaMin-1.);
0808
0809 G4double RangeMin = G4LossTableManager::Instance()->GetRange(particleType,
0810 kinEmin,
0811 couple);
0812 G4double Range = G4LossTableManager::Instance()->GetRange(particleType,
0813 kineticEnergy,
0814 couple);
0815
0816 G4double Step = Range - RangeMin;
0817
0818
0819
0820 if (Step > 0. && Step < StepLimit) StepLimit = Step;
0821
0822
0823
0824
0825
0826 if (fMaxPhotons > 0) {
0827
0828 const G4double charge = aParticle->GetDefinition()->GetPDGCharge();
0829
0830 G4double MeanNumberOfPhotons =
0831 GetAverageNumberOfPhotons(charge,beta,aMaterial,Rindex);
0832
0833 Step = 0.;
0834 if (MeanNumberOfPhotons > 0.0) Step = fMaxPhotons / MeanNumberOfPhotons;
0835
0836 if (Step > 0. && Step < StepLimit) StepLimit = Step;
0837 }
0838
0839
0840 if (fMaxBetaChange > 0.) {
0841
0842 G4double dedx = G4LossTableManager::Instance()->GetDEDX(particleType,
0843 kineticEnergy,
0844 couple);
0845
0846 G4double deltaGamma = gamma - 1./std::sqrt(1.-beta*beta*
0847 (1.-fMaxBetaChange)*
0848 (1.-fMaxBetaChange));
0849
0850 Step = mass * deltaGamma / dedx;
0851
0852 if (Step > 0. && Step < StepLimit) StepLimit = Step;
0853
0854 }
0855
0856 *condition = StronglyForced;
0857 return StepLimit;
0858 }
0859
0860
0861
0862
0863
0864
0865
0866 G4double
0867 Local_G4Cerenkov_modified::GetAverageNumberOfPhotons(const G4double charge,
0868 const G4double beta,
0869 const G4Material* aMaterial,
0870 G4MaterialPropertyVector* Rindex)
0871 {
0872
0873 const G4double Rfact = 369.81/(eV * cm);
0874
0875 #ifdef X_INSTRUMENTED
0876 std::cout
0877 << "Local_G4Cerenkov_modified::GetAverageNumberOfPhotons"
0878 << " Rfact " << std::fixed << std::setw(10) << std::setprecision(5) << Rfact
0879 << " eV " << std::fixed << std::setw(10) << std::setprecision(7) << eV
0880 << " cm " << std::fixed << std::setw(10) << std::setprecision(5) << cm
0881 << " charge " << std::fixed << std::setw(10) << std::setprecision(5) << charge
0882 << std::endl
0883 ;
0884 #endif
0885
0886 if(beta <= 0.0)return 0.0;
0887
0888 G4double BetaInverse = 1./beta;
0889
0890
0891
0892
0893
0894 G4int materialIndex = aMaterial->GetIndex();
0895
0896
0897
0898 G4PhysicsOrderedFreeVector* CerenkovAngleIntegrals =
0899 (G4PhysicsOrderedFreeVector*)((*thePhysicsTable)(materialIndex));
0900 #if G4VERSION_NUMBER < 1100
0901 if(!(CerenkovAngleIntegrals->IsFilledVectorExist()))return 0.0;
0902 #else
0903 G4int length = CerenkovAngleIntegrals->GetVectorLength();
0904 if(0 == length) return 0.0;
0905 #endif
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961 G4int cross_num;
0962
0963
0964 std::vector<double> the_energies_threshold;
0965
0966
0967
0968 cross_num = 0;
0969 size_t vec_length = Rindex->GetVectorLength();
0970
0971 G4double maxRI=(*Rindex)[0]; G4double minRI=(*Rindex)[0];
0972 for (size_t ii = 1;
0973 ii < vec_length;
0974 ++ii) {
0975 G4double currentRI = (*Rindex)[ii];
0976 if (currentRI > maxRI) maxRI = currentRI;
0977 if (currentRI < minRI) minRI = currentRI;
0978 }
0979
0980
0981
0982 if (BetaInverse <= minRI) {
0983
0984
0985
0986 cross_num = 1;
0987
0988 the_energies_threshold.push_back(Rindex->Energy(0));
0989 the_energies_threshold.push_back(Rindex->Energy(vec_length-1));
0990
0991
0992
0993 } else if (BetaInverse >= maxRI) {
0994 cross_num = 0;
0995
0996 } else {
0997
0998
0999 double currentRI = (*Rindex)[0];
1000 double currentPM = Rindex->Energy(0);
1001
1002
1003 if (currentRI >= BetaInverse) {
1004 the_energies_threshold.push_back(currentPM);
1005 }
1006
1007
1008 if (vec_length>2) {
1009 for (size_t ii = 1; ii < vec_length-1; ++ii) {
1010 double prevRI = (*Rindex)[ii-1];
1011 double prevPM = Rindex->Energy(ii-1);
1012 double currentRI = (*Rindex)[ii];
1013 double currentPM = Rindex->Energy(ii);
1014
1015
1016 if ( (prevRI >= BetaInverse and currentRI < BetaInverse)
1017 or (prevRI < BetaInverse and currentRI >= BetaInverse) ) {
1018 double energy_threshold = (BetaInverse-prevRI)/(currentRI-prevRI)*(currentPM-prevPM) + prevPM;
1019 the_energies_threshold.push_back(energy_threshold);
1020 }
1021
1022 }
1023 }
1024
1025
1026 currentRI = (*Rindex)[vec_length-1];
1027 currentPM = Rindex->Energy(vec_length-1);
1028 if (currentRI >= BetaInverse) {
1029 the_energies_threshold.push_back(currentPM);
1030 }
1031
1032 if ((the_energies_threshold.size()%2) != 0) {
1033 G4cerr << "ERROR: missing endpoint for the_energies_threshold? "
1034 << "The size of the_energies_threshold is "
1035 << the_energies_threshold.size()
1036 << G4endl;
1037 }
1038
1039 cross_num = the_energies_threshold.size() / 2;
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121 }
1122 G4double dp1 = 0; G4double ge1 = 0;
1123 for (int i=0; i<cross_num; i++) {
1124 dp1 += the_energies_threshold[2*i+1] - the_energies_threshold[2*i];
1125 G4bool isOutRange;
1126 ge1 += CerenkovAngleIntegrals->GetValue(the_energies_threshold[2*i+1], isOutRange)
1127 - CerenkovAngleIntegrals->GetValue(the_energies_threshold[2*i], isOutRange);
1128 }
1129
1130
1131
1132
1133 G4double NumPhotons = Rfact * charge/eplus * charge/eplus *
1134 (dp1 - ge1 * BetaInverse*BetaInverse);
1135
1136
1137 #ifdef X_INSTRUMENTED
1138 std::cout
1139 << "Local_G4Cerenkov_modified::GetAverageNumberOfPhotons"
1140 << " BetaInverse " << std::fixed << std::setw(10) << std::setprecision(5) << BetaInverse
1141 << " maxRI " << std::fixed << std::setw(10) << std::setprecision(5) << maxRI
1142 << " minRI " << std::fixed << std::setw(10) << std::setprecision(5) << minRI
1143 << " cross_num " << cross_num
1144 << " dp1 " << std::fixed << std::setw(10) << std::setprecision(5) << dp1
1145 << " dp1/eV " << std::fixed << std::setw(10) << std::setprecision(5) << dp1/eV
1146 << " ge1 " << std::fixed << std::setw(10) << std::setprecision(5) << ge1
1147 << " NumPhotons " << std::fixed << std::setw(10) << std::setprecision(5) << NumPhotons
1148 << std::endl
1149 ;
1150
1151 for(int i=0 ; i < cross_num ; i++)
1152 {
1153
1154 G4bool isOutRange;
1155 G4double cai0 = CerenkovAngleIntegrals->GetValue(the_energies_threshold[2*i+0], isOutRange);
1156 G4double cai1 = CerenkovAngleIntegrals->GetValue(the_energies_threshold[2*i+1], isOutRange);
1157
1158 std::cout
1159 << "Local_G4Cerenkov_modified::GetAverageNumberOfPhotons"
1160 << " the_energies_threshold[2*i+0]/eV " << std::fixed << std::setw(10) << std::setprecision(5) << the_energies_threshold[2*i+0]/eV
1161 << " the_energies_threshold[2*i+1]/eV " << std::fixed << std::setw(10) << std::setprecision(5) << the_energies_threshold[2*i+1]/eV
1162 << " cai0 " << std::fixed << std::setw(20) << std::setprecision(10) << cai0
1163 << " cai1 " << std::fixed << std::setw(20) << std::setprecision(10) << cai1
1164 << std::endl
1165 ;
1166 }
1167 #endif
1168
1169
1170 return NumPhotons;
1171 }
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 G4double Local_G4Cerenkov_modified::GetAverageNumberOfPhotons_s2(const G4double charge, const G4double beta, const G4Material*, G4MaterialPropertyVector* Rindex) const
1227 {
1228 if(beta <= 0.0)return 0.0;
1229 G4double BetaInverse = 1./beta;
1230 G4double half(0.5) ;
1231 G4double s2integral(0.) ;
1232
1233 for(unsigned i=0 ; i < Rindex->GetVectorLength()-1 ; i++)
1234 {
1235 G4double en_0 = Rindex->Energy(i) ;
1236 G4double en_1 = Rindex->Energy(i+1) ;
1237
1238 G4double ri_0 = (*Rindex)[i] ;
1239 G4double ri_1 = (*Rindex)[i+1] ;
1240
1241 G4double ct_0 = BetaInverse/ri_0 ;
1242 G4double ct_1 = BetaInverse/ri_1 ;
1243
1244 G4double s2_0 = (1.-ct_0)*(1.+ct_0) ;
1245 G4double s2_1 = (1.-ct_1)*(1.+ct_1) ;
1246
1247 G4bool cross = s2_0*s2_1 < 0. ;
1248 G4double en_cross = cross ? en_0 + (BetaInverse - ri_0)*(en_1 - en_0)/(ri_1 - ri_0) : -1. ;
1249
1250 if( s2_0 <= 0. and s2_1 <= 0. )
1251 {
1252
1253 }
1254 else if( s2_0 < 0. and s2_1 > 0. )
1255 {
1256 s2integral += (en_1 - en_cross)*s2_1*half ;
1257 }
1258 else if( s2_0 >= 0. and s2_1 >= 0. )
1259 {
1260 s2integral += (en_1 - en_0)*(s2_0 + s2_1)*half ;
1261 }
1262 else if( s2_0 > 0. and s2_1 < 0. )
1263 {
1264 s2integral += (en_cross - en_0)*s2_0*half ;
1265 }
1266 else
1267 {
1268 std::cout
1269 << "Local_G4Cerenkov_modified::GetAverageNumberOfPhotons_s2"
1270 << " FATAL "
1271 << " s2_0 " << std::fixed << std::setw(10) << std::setprecision(5) << s2_0
1272 << " s2_1 " << std::fixed << std::setw(10) << std::setprecision(5) << s2_1
1273 << " en_0/eV " << std::fixed << std::setw(10) << std::setprecision(5) << en_0/eV
1274 << " en_1/eV " << std::fixed << std::setw(10) << std::setprecision(5) << en_1/eV
1275 << " ri_0 " << std::fixed << std::setw(10) << std::setprecision(5) << ri_0
1276 << " ri_1 " << std::fixed << std::setw(10) << std::setprecision(5) << ri_1
1277 << std::endl
1278 ;
1279 assert(0);
1280 }
1281 }
1282 const G4double Rfact = 369.81/(eV * cm);
1283 G4double NumPhotons = Rfact * charge/eplus * charge/eplus * s2integral ;
1284
1285 #ifdef X_INSTRUMENTED
1286 std::cout
1287 << "Local_G4Cerenkov_modified::GetAverageNumberOfPhotons_s2"
1288 << " Rfact " << std::fixed << std::setw(10) << std::setprecision(5) << Rfact
1289 << " eV " << std::fixed << std::setw(10) << std::setprecision(7) << eV
1290 << " cm " << std::fixed << std::setw(10) << std::setprecision(5) << cm
1291 << " mm " << std::fixed << std::setw(10) << std::setprecision(5) << mm
1292 << " charge " << std::fixed << std::setw(10) << std::setprecision(5) << charge
1293 << " s2integral " << std::fixed << std::setw(10) << std::setprecision(5) << s2integral
1294 << " NumPhotons " << std::fixed << std::setw(10) << std::setprecision(5) << NumPhotons
1295 << std::endl
1296 ;
1297 #endif
1298 return NumPhotons ;
1299 }
1300
1301
1302 void Local_G4Cerenkov_modified::DumpPhysicsTable() const
1303 {
1304 G4int PhysicsTableSize = thePhysicsTable->entries();
1305 G4PhysicsOrderedFreeVector *v;
1306
1307 for (G4int i = 0 ; i < PhysicsTableSize ; i++ ) {
1308 v = (G4PhysicsOrderedFreeVector*)(*thePhysicsTable)[i];
1309 v->DumpValues();
1310 }
1311 }
1312
1313