Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4StandardCerenkovModel.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// G4StandardCerenkovModel
28//
29// Created 25.05.2025 V.Ivanchenko
30//
31// --------------------------------------------------------------------
32
34
35#include "G4ios.hh"
36#include "G4LossTableManager.hh"
37#include "G4Material.hh"
42#include "G4ParticleMomentum.hh"
45#include "G4Poisson.hh"
46#include "G4SystemOfUnits.hh"
47#include "G4ThreeVector.hh"
48#include "Randomize.hh"
49#include "G4OpticalPhoton.hh"
50
51namespace
52{
53 constexpr G4double minAllowedStep = 0.001*CLHEP::mm;
54 constexpr G4int nvec = 10; // number of slices in beta of projectile
55}
56
57std::vector<G4double>* G4StandardCerenkovModel::fBetaLim = nullptr;
58std::vector<G4MaterialPropertyVector*>* G4StandardCerenkovModel::fRindex = nullptr;
59std::vector<std::vector<G4double>* >* G4StandardCerenkovModel::fMeanNumberOfPhotons = nullptr;
60std::vector<std::vector<std::vector<G4double>* >* >* G4StandardCerenkovModel::fIntegral = nullptr;
61
62//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
64 : G4VXRayModel("theCerenkov")
65{
66 if (nullptr == fBetaLim) {
67 isInitializer = true;
68 fBetaLim = new std::vector<G4double>;
69 fMeanNumberOfPhotons = new std::vector<std::vector<G4double>* >;
70 fIntegral = new std::vector<std::vector<std::vector<G4double>* >* >;
71 fRindex = new std::vector<G4MaterialPropertyVector*>;
72 }
74 fRfact = 369.81 / (CLHEP::eV * CLHEP::cm); // number of photons per mm
75}
76
77//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
79{
80 if (isInitializer && isInitialized) {
81 delete fBetaLim;
82 for (auto const & ptr : *fRindex) {
83 delete ptr;
84 }
85 delete fRindex;
86 for (auto const & ptr : *fMeanNumberOfPhotons) {
87 delete ptr;
88 }
89 delete fMeanNumberOfPhotons;
90 for (auto const & ptr : *fIntegral) {
91 for (auto const & p : *ptr) {
92 delete p;
93 }
94 delete ptr;
95 }
96 delete fIntegral;
97 fIntegral = nullptr;
98 fBetaLim = nullptr;
99 fRindex = nullptr;
100 fMeanNumberOfPhotons = nullptr;
101 }
102}
103
104//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
106{
107 G4double beta = 1.0;
108 if (0 == nVolumes) { return; }
109 if (isInitializer && !isInitialized) {
110 isInitialized = true;
111 fBetaLim->resize(nVolumes, 1.0);
112 fRindex->resize(nVolumes, nullptr);
113 fMeanNumberOfPhotons->resize(nVolumes, new std::vector<G4double>(nvec, 0.0));
114 fIntegral->resize(nVolumes, nullptr);
115
116 for (std::size_t i = 0; i < nVolumes; ++i) {
117 auto mat = ((*pLogicalVolumes)[i])->GetMaterial();
118 auto MPT = mat->GetMaterialPropertiesTable();
119
120 if (nullptr == MPT) { continue; }
121 G4MaterialPropertyVector* rindex = MPT->GetProperty(kRINDEX);
122 if (nullptr == rindex) { continue; }
123 (*fRindex)[i] = rindex;
124
125 G4double nMax = rindex->GetMaxValue();
126 if (nMax <= 1.0) { continue; }
127 G4double b = 1.0/nMax;
128 (*fBetaLim)[i] = b;
129 beta = std::min(beta, b);
130 G4double dbeta = (1.0 - b)/(G4double)(nvec - 1);
131 G4double b0 = b;
132 std::size_t nn = rindex->GetVectorLength();
133 if (0 == nn) { continue; }
134
135 auto iptr = new std::vector<std::vector<G4double>* >((std::size_t)nvec, nullptr);
136 (*fIntegral)[i] = iptr;
137 for (auto & ptr : *iptr) {
138 ptr = new std::vector<G4double>(nn, 0.0);
139 }
140
141 // Initialisation for charge = 1.0
142 G4double y0 = AverageNumberOfPhotons(1.0, b0, (*rindex)[0]);
143 (*(*fMeanNumberOfPhotons)[i])[0] = y0;
144 if (1 == nn) { continue; }
145
146 // Initialisation for charge = 1.0
147 for (G4int k = 0; k < nvec; ++k) {
148 (*((*fIntegral)[i]))[k]->resize(nn, 0.0);
149 G4double sum = 0.0;
150 G4double e0 = rindex->GetMinEnergy();
151 G4double deltae = rindex->GetMaxEnergy() - e0;
152 for (std::size_t j = 1; j < nn; ++j) {
153 G4double e = rindex->Energy(j);
154 G4double y = AverageNumberOfPhotons(1.0, beta, (*rindex)[j]);
155 sum += 0.5*(y - y0)*(e - e0);
156 y0 = y;
157 e0 = e;
158 (*(*((*fIntegral)[i]))[k])[j] = sum;
159 }
160 if (deltae > 0.0) { (*(*fMeanNumberOfPhotons)[i])[k] = sum/deltae; }
161 if (sum > 0.0) { sum = 1.0/sum; }
162 for (std::size_t j = 1; j < nn; ++j) {
163 G4double y = (*(*((*fIntegral)[i]))[k])[j]/sum;
164 (*(*((*fIntegral)[i]))[k])[j] = y;
165 }
166 beta += dbeta;
167 beta = std::min(beta, 1.0);
168 }
169 }
170 } else {
171 for (std::size_t i = 0; i < nVolumes; ++i) {
172 beta = std::min(beta, (*fBetaLim)[i]);
173 }
174 }
175 pBetaMin = beta;
176}
177
178//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
180{
181 G4double betaMin = (*fBetaLim)[pIndex];
182 if (pPreStepBeta <= betaMin) { return false; }
183
184 // step limitation
185 betaMin = std::max(betaMin, pPreStepBeta*pMaxBetaChange);
186
187 auto const dynPart = pCurrentTrack->GetDynamicParticle();
188 fParticle = dynPart->GetDefinition();
189 fPreStepKinE = dynPart->GetKineticEnergy();
190 fCharge = fParticle->GetPDGCharge()/CLHEP::eplus;
191 fMass = fParticle->GetPDGMass();
192 G4double x = limit;
193
194 // If the step is smaller than G4ThreeVector::getTolerance(), it may happen
195 // that the particle does not move. See bug 1992.
196 if (x < minAllowedStep) { return false; }
197
198 // If user has defined an average maximum number of photons to be generated in
199 // a Step, then calculate the Step length for that number of photons using preStep beta.
200 G4double nmax = (*fRindex)[pIndex]->GetMaxValue();
201 fMeanNPhotons = x * AverageNumberOfPhotons(fCharge, pPreStepBeta, nmax);
202 if (pMaxPhotons < fMeanNPhotons) {
203 x *= pMaxPhotons/fMeanNPhotons;
204 x = std::max(x, minAllowedStep);
205 }
206 limit = x;
207 return true;
208}
209
210//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
211void G4StandardCerenkovModel::SampleXRays(std::vector<G4Track*>& out,
212 const G4Step& step)
213{
214 auto const preStep = step.GetPreStepPoint();
215 auto const postStep = step.GetPostStepPoint();
216 G4double kinE = postStep->GetKineticEnergy();
217 G4double beta = pPreStepBeta;
218 G4double b = (*fBetaLim)[pIndex];
219 G4double dbeta = (1.0 - b)/(G4double)(nvec - 1);
220 G4int idx = std::max(G4int((beta - b)/dbeta), 0);
221 idx = std::min(idx, nvec - 1);
222 std::vector<G4double>* v = (*((*fIntegral)[pIndex]))[idx];
223
224 G4ThreeVector pos = preStep->GetPosition();
225 G4ThreeVector dpos = postStep->GetPosition() - pos;
226 G4ThreeVector dir = dpos.unit();
227 G4double time = preStep->GetGlobalTime();
228 G4double dt = postStep->GetGlobalTime() - time;
229 G4double de = fPreStepKinE - kinE;
230
231 // define sub-steps inside the current step
232 G4double x = (1.0 + fPreStepKinE/fMass);
233 G4double delim = fMass*pMaxBetaChange*x*x*x;
234 G4int nn = (G4int)(de/delim) + 1;
235 x = 1.0/(G4double)nn;
236 dpos *= x;
237 dt *= x;
238 de *= x;
239 G4double delta = dpos.mag();
240 fMeanNPhotons *= x;
241
242 // produce Cerenkov gamma - loop over sub-steps
243 G4double ekin = fPreStepKinE;
244 auto const rindex = (*fRindex)[pIndex];
245 std::size_t ni = rindex->GetVectorLength();
246 if (0 == ni) { return; }
247 G4double emin = rindex->Energy(0);
248 G4double mean = delta*fCharge*fCharge*(*(*fMeanNumberOfPhotons)[pIndex])[idx];
249
250 for (G4int i=0; i<nn; ++i) {
251 G4int ngamma = (G4int)G4Poisson(mean);
252 for (G4int j = 0; j < ngamma; ++j) {
254 G4double e = emin;
255 G4double n = (*rindex)[0];
256 if (ni > 1) {
257 for (std::size_t k = 1; k < ni; ++k) {
258 if ((*v)[k] <= q) {
259 e = rindex->Energy(k - 1);
260 e += (rindex->Energy(k) - e)*(q - (*v)[k - 1])/((*v)[k] - (*v)[k - 1]);
261 n = (*rindex)[k - 1];
262 n += ((*rindex)[k] - n)*(q - (*v)[k - 1])/((*v)[k] - (*v)[k - 1]);
263 }
264 }
265 }
266 q = G4UniformRand();
267 G4double t = time + q*dt;
268 G4ThreeVector posnew = pos + q*dpos;
269 G4double minCos = 1.0/(n*beta);
270 G4double maxSin2 = (1.0 - minCos)*(1.0 + minCos);
271 G4double cost, sint2;
272 do {
273 cost = 1.0 - G4UniformRand()*(1.0 - minCos);
274 sint2 = (1.0 - cost)*(1.0 + cost);
275 q = G4UniformRand();
276 } while(q * maxSin2 > sint2);
277
278 G4double sint = std::sqrt(sint2);
279 G4double phi = G4UniformRand()*CLHEP::twopi;
280 G4double cosPhi = std::cos(phi);
281 G4double sinPhi = std::sin(phi);
282 G4ThreeVector dirnew(sint*cosPhi, sint*sinPhi, cost);
283 dirnew.rotateUz(dir);
284
285 // Determine polarization of new photon
286 G4ThreeVector photonPolarization(cost*cosPhi, cost*sinPhi, -sint);
287
288 // Rotate back to original coord system
289 photonPolarization.rotateUz(dir);
290
291 auto dp = new G4DynamicParticle(fPhoton, dirnew, e);
292 dp->SetPolarization(photonPolarization);
293 auto track = new G4Track(dp, t, posnew);
294 out.push_back(track);
295 }
296 pos += dpos;
297 time += dt;
298 ekin -= de;
299 beta = std::sqrt(ekin * (ekin + 2*fMass))/(fMass + ekin);
300 }
301}
302
303//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
304void G4StandardCerenkovModel::ModelDescription(std::ostream& out) const
305{
306 out << "The Cerenkov effect simulates optical photons created by the\n";
307 out << "passage of charged particles through matter. Materials need\n";
308 out << "to have the property RINDEX (refractive index) defined." << G4endl;
309}
310
311
312
313
G4PhysicsFreeVector G4MaterialPropertyVector
G4long G4Poisson(G4double mean)
Definition G4Poisson.hh:50
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
#define G4UniformRand()
Definition Randomize.hh:52
Hep3Vector unit() const
double mag() const
Hep3Vector & rotateUz(const Hep3Vector &)
static G4OpticalPhoton * OpticalPhoton()
G4double GetMaxEnergy() const
G4double GetMaxValue() const
G4double Energy(const std::size_t index) const
G4double GetMinEnergy() const
std::size_t GetVectorLength() const
void SampleXRays(std::vector< G4Track * > &out, const G4Step &) override
G4bool StepLimitForVolume(G4double &limit) override
void ModelDescription(std::ostream &outFile) const override
G4StepPoint * GetPreStepPoint() const
G4StepPoint * GetPostStepPoint() const
G4double pMaxBetaChange
G4VXRayModel(const G4String &nam)
std::size_t pIndex
G4double pBetaMin
const G4Track * pCurrentTrack
std::size_t nVolumes
G4double pPreStepBeta