Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4eDPWAElasticDCS.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// -------------------------------------------------------------------
28//
29// GEANT4 Class header file
30//
31//
32// File name: G4eDPWAElasticDCS
33//
34// Author: Mihaly Novak
35//
36// Creation date: 02.07.2020
37//
38// Modifications:
39//
40//
41// -------------------------------------------------------------------
42
43#include "G4eDPWAElasticDCS.hh"
44#include "G4EmParameters.hh"
45#include "G4Physics2DVector.hh"
46
47#include "zlib.h"
48
49//
50// Global variables:
51//
52G4bool G4eDPWAElasticDCS::gIsGridLoaded = false;
53G4String G4eDPWAElasticDCS::gDataDirectory = "";
54// final values of these variables will be set in LoadGrid() called by master
55std::size_t G4eDPWAElasticDCS::gNumEnergies = 106;
56std::size_t G4eDPWAElasticDCS::gIndxEnergyLim = 35;
57std::size_t G4eDPWAElasticDCS::gNumThetas1 = 247;
58std::size_t G4eDPWAElasticDCS::gNumThetas2 = 128;
59G4double G4eDPWAElasticDCS::gLogMinEkin = 1.0;
60G4double G4eDPWAElasticDCS::gInvDelLogEkin = 1.0;
61// containers for grids: Ekin, mu(t)=0.5[1-cos(t)] and u(mu,A)=(A+1)mu/(mu+A)
62std::vector<G4double> G4eDPWAElasticDCS::gTheEnergies(G4eDPWAElasticDCS::gNumEnergies);
63std::vector<G4double> G4eDPWAElasticDCS::gTheMus1(G4eDPWAElasticDCS::gNumThetas1);
64std::vector<G4double> G4eDPWAElasticDCS::gTheMus2(G4eDPWAElasticDCS::gNumThetas2);
65std::vector<G4double> G4eDPWAElasticDCS::gTheU1(G4eDPWAElasticDCS::gNumThetas1);
66std::vector<G4double> G4eDPWAElasticDCS::gTheU2(G4eDPWAElasticDCS::gNumThetas2);
67// abscissas and weights of an 8 point Gauss-Legendre quadrature
68// for numerical integration on [0,1]
69const G4double G4eDPWAElasticDCS::gXGL[] = {
70 1.98550718E-02, 1.01666761E-01, 2.37233795E-01, 4.08282679E-01,
71 5.91717321E-01, 7.62766205E-01, 8.98333239E-01, 9.80144928E-01
72};
73const G4double G4eDPWAElasticDCS::gWGL[] = {
74 5.06142681E-02, 1.11190517E-01, 1.56853323E-01, 1.81341892E-01,
75 1.81341892E-01, 1.56853323E-01, 1.11190517E-01, 5.06142681E-02
76};
77
78
79// - iselectron : data for e- (for e+ otherwise)
80// - isrestricted : sampling of angular deflection on restricted interavl is
81// required (i.e. in case of mixed-simulation models)
83: fIsRestrictedSamplingRequired(isrestricted), fIsElectron(iselectron) {
84 fDCS.resize(gMaxZ+1, nullptr);
85 fDCSLow.resize(gMaxZ+1, nullptr);
86 fSamplingTables.resize(gMaxZ+1, nullptr);
87}
88
89
90 // DTR
92 for (std::size_t i=0; i<fDCS.size(); ++i) {
93 if (fDCS[i]) delete fDCS[i];
94 }
95 for (std::size_t i=0; i<fDCSLow.size(); ++i) {
96 if (fDCSLow[i]) delete fDCSLow[i];
97 }
98 for (std::size_t i=0; i<fSamplingTables.size(); ++i) {
99 if (fSamplingTables[i]) delete fSamplingTables[i];
100 }
101 // clear scp correction data
102 for (std::size_t imc=0; imc<fSCPCPerMatCuts.size(); ++imc) {
103 if (fSCPCPerMatCuts[imc]) {
104 fSCPCPerMatCuts[imc]->fVSCPC.clear();
105 delete fSCPCPerMatCuts[imc];
106 }
107 }
108 fSCPCPerMatCuts.clear();
109}
110
111
112// initialise for a given 'iz' atomic number:
113// - nothing happens if it has already been initialised for that Z.
115 if (!gIsGridLoaded) {
116 LoadGrid();
117 }
118 LoadDCSForZ((G4int)iz);
119 BuildSmplingTableForZ((G4int)iz);
120}
121
122
123// loads the kinetic energy and theta grids for the DCS data (first init step)
124// should be called only by the master
125void G4eDPWAElasticDCS::LoadGrid() {
126 G4String fname = FindDirectoryPath() + "grid.dat";
127 std::ifstream infile(fname.c_str());
128 if (!infile.is_open()) {
129 G4String msg =
130 " Problem while trying to read " + fname + " file.\n"+
131 " G4LEDATA version should be G4EMLOW7.12 or later.\n";
132 G4Exception("G4eDPWAElasticDCS::ReadCompressedFile","em0006",
133 FatalException,msg.c_str());
134 return;
135 }
136 // read size
137 infile >> gNumEnergies;
138 infile >> gNumThetas1;
139 infile >> gNumThetas2;
140 // read the grids
141 // - energy in [MeV]
142 G4double dum = 0.0;
143 gTheEnergies.resize(gNumEnergies);
144 for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
145 infile >> dum;
146 gTheEnergies[ie] = G4Log(dum*CLHEP::MeV);
147 if (gTheEnergies[ie]<G4Log(2.0*CLHEP::keV)) gIndxEnergyLim = ie; // only for e-
148 }
149 ++gIndxEnergyLim;
150 // store/set usefull logarithms of the kinetic energy grid
151 gLogMinEkin = gTheEnergies[0];
152 gInvDelLogEkin = (gNumEnergies-1)/(gTheEnergies[gNumEnergies-1]-gTheEnergies[0]);
153 // - theta1 in [deg.] (247): we store mu(theta) = 0.5[1-cos(theta)]
154 gTheMus1.resize(gNumThetas1);
155 gTheU1.resize(gNumThetas1);
156 const double theA = 0.01;
157 for (std::size_t it=0; it<gNumThetas1; ++it) {
158 infile >> dum;
159 gTheMus1[it] = 0.5*(1.0-std::cos(dum*CLHEP::degree));
160 gTheU1[it] = (theA+1.0)*gTheMus1[it]/(theA+gTheMus1[it]);
161 }
162 // - theta2 in [deg.] (128): we store mu(theta) = 0.5[1-cos(theta)]
163 gTheMus2.resize(gNumThetas2);
164 gTheU2.resize(gNumThetas2);
165 for (std::size_t it=0; it<gNumThetas2; ++it) {
166 infile >> dum;
167 gTheMus2[it] = 0.5*(1.0-std::cos(dum*CLHEP::degree));
168 gTheU2[it] = (theA+1.0)*gTheMus2[it]/(theA+gTheMus2[it]);
169
170 }
171 infile.close();
172 gIsGridLoaded = true;
173}
174
175
176// load DCS data for a given Z
177void G4eDPWAElasticDCS::LoadDCSForZ(G4int iz) {
178 // Check if it has already been done:
179 if (fDCS[iz]) return;
180 // Do it otherwise
181 if (fIsElectron) {
182 // e-
183 // load the high energy part firt:
184 // - with gNumThetas2 theta and gNumEnergies-gIndxEnergyLim energy values
185 const std::size_t hNumEnergries = gNumEnergies-gIndxEnergyLim;
186 auto v2DHigh = new G4Physics2DVector(gNumThetas2, hNumEnergries);
187 v2DHigh->SetBicubicInterpolation(true);
188 for (std::size_t it=0; it<gNumThetas2; ++it) {
189 v2DHigh->PutX(it, gTheMus2[it]);
190 }
191 for (std::size_t ie=0; ie<hNumEnergries; ++ie) {
192 v2DHigh->PutY(ie, gTheEnergies[gIndxEnergyLim+ie]);
193 }
194 std::ostringstream ossh;
195 ossh << FindDirectoryPath() << "dcss/el/dcs_"<< iz<<"_h";
196 std::istringstream finh(std::ios::in);
197 ReadCompressedFile(ossh.str(), finh);
198 G4double dum = 0.0;
199 for (std::size_t it=0; it<gNumThetas2; ++it) {
200 finh >> dum;
201 for (std::size_t ie=0; ie<hNumEnergries; ++ie) {
202 finh >> dum;
203 v2DHigh->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
204 }
205 }
206 // load the low energy part:
207 // - with gNumThetas1 theta and gIndxEnergyLim+1 energy values (the +1 is
208 // for including the firts DCS from the higher part above for being
209 // able to perform interpolation between the high and low energy DCS set)
210 auto v2DLow = new G4Physics2DVector(gNumThetas1, gIndxEnergyLim+1);
211 v2DLow->SetBicubicInterpolation(true);
212 for (std::size_t it=0; it<gNumThetas1; ++it) {
213 v2DLow->PutX(it, gTheMus1[it]);
214 }
215 for (std::size_t ie=0; ie<gIndxEnergyLim+1; ++ie) {
216 v2DLow->PutY(ie, gTheEnergies[ie]);
217 }
218 std::ostringstream ossl;
219 ossl << FindDirectoryPath() << "dcss/el/dcs_"<< iz<<"_l";
220 std::istringstream finl(std::ios::in);
221 ReadCompressedFile(ossl.str(), finl);
222 for (std::size_t it=0; it<gNumThetas1; ++it) {
223 finl >> dum;
224 for (std::size_t ie=0; ie<gIndxEnergyLim; ++ie) {
225 finl >> dum;
226 v2DLow->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
227 }
228 }
229 // add the +1 part: interpolate the firts DCS from the high energy
230 std::size_t ix = 0;
231 std::size_t iy = 0;
232 for (std::size_t it=0; it<gNumThetas1; ++it) {
233 const G4double val = v2DHigh->Value(gTheMus1[it], gTheEnergies[gIndxEnergyLim], ix, iy);
234 v2DLow->PutValue(it, gIndxEnergyLim, val);
235 }
236 // store
237 fDCSLow[iz] = v2DLow;
238 fDCS[iz] = v2DHigh;
239 } else {
240 // e+
241 auto v2D= new G4Physics2DVector(gNumThetas2, gNumEnergies);
242 v2D->SetBicubicInterpolation(true);
243 for (std::size_t it=0; it<gNumThetas2; ++it) {
244 v2D->PutX(it, gTheMus2[it]);
245 }
246 for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
247 v2D->PutY(ie, gTheEnergies[ie]);
248 }
249 std::ostringstream oss;
250 oss << FindDirectoryPath() << "dcss/pos/dcs_"<< iz;
251 std::istringstream fin(std::ios::in);
252 ReadCompressedFile(oss.str(), fin);
253 G4double dum = 0.0;
254 for (std::size_t it=0; it<gNumThetas2; ++it) {
255 fin >> dum;
256 for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
257 fin >> dum;
258 v2D->PutValue(it, ie, G4Log(dum*CLHEP::cm2/CLHEP::sr));
259 }
260 }
261 fDCS[iz]= v2D;
262 }
263}
264
265
266
267// Computes the elastic, first and second cross sections for the given kinetic
268// energy and target atom.
269// Cross sections are zero ff ekin is below/above the kinetic energy grid
271 G4double& tr1cs, G4double& tr2cs,
272 G4double mumin, G4double mumax) {
273 // init all cross section values to zero;
274 elcs = 0.0;
275 tr1cs = 0.0;
276 tr2cs = 0.0;
277 // make sure that mu(theta) = 0.5[1-cos(theta)] limits have appropriate vals
278 mumin = std::max(0.0, std::min(1.0, mumin));
279 mumax = std::max(0.0, std::min(1.0, mumax));
280 if (mumin>=mumax) return;
281 // make sure that kin. energy is within the available range (10 eV-100MeV)
282 const G4double lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], G4Log(ekin)));
283 // if the lower, denser in theta, DCS set should be used
284 const G4bool isLowerGrid = (fIsElectron && lekin<gTheEnergies[gIndxEnergyLim]);
285 const std::vector<G4double>& theMuVector = (isLowerGrid) ? gTheMus1 : gTheMus2;
286 const G4Physics2DVector* the2DDCS = (isLowerGrid) ? fDCSLow[iz] : fDCS[iz];
287 // find lower/upper mu bin of integration:
288 // 0.0 <= mumin < 1.0 for sure here
289 const std::size_t iMuStart = (mumin == 0.0) ? 0 : std::distance( theMuVector.begin(), std::upper_bound(theMuVector.begin(), theMuVector.end(), mumin) )-1 ;
290 // 0.0 < mumax <= 1.0 for sure here
291 const std::size_t iMuEnd = (mumax == 1.0) ? theMuVector.size()-2 : std::distance( theMuVector.begin(), std::upper_bound(theMuVector.begin(), theMuVector.end(), mumax) )-1 ;
292 // perform numerical integration of the DCS over the given [mumin, mumax]
293 // interval (where mu(theta) = 0.5[1-cos(theta)]) to get the elastic, first
294 std::size_t ix = 0;
295 std::size_t iy = 0;
296 for (std::size_t imu=iMuStart; imu<=iMuEnd; ++imu) {
297 G4double elcsPar = 0.0;
298 G4double tr1csPar = 0.0;
299 G4double tr2csPar = 0.0;
300 const G4double low = (imu==iMuStart) ? mumin : theMuVector[imu];
301 const G4double del = (imu==iMuEnd) ? mumax-low : theMuVector[imu+1]-low;
302 ix = imu;
303 for (std::size_t igl=0; igl<8; ++igl) {
304 const double mu = low + del*gXGL[igl];
305 const double dcs = G4Exp(the2DDCS->Value(mu, lekin, ix, iy));
306 elcsPar += gWGL[igl]*dcs; // elastic
307 tr1csPar += gWGL[igl]*dcs*mu; // first transport
308 tr2csPar += gWGL[igl]*dcs*mu*(1.0-mu); // second transport
309 }
310 elcs += del*elcsPar;
311 tr1cs += del*tr1csPar;
312 tr2cs += del*tr2csPar;
313 }
314 elcs *= 2.0*CLHEP::twopi;
315 tr1cs *= 4.0*CLHEP::twopi;
316 tr2cs *= 12.0*CLHEP::twopi;
317}
318
319
320// data structure to store one sampling table: combined Alias + RatIn
321// NOTE: when Alias is used, sampling on a resctricted interval is not possible
322// However, Alias makes possible faster sampling. Alias is used in case
323// of single scattering model while it's not used in case of mixed-model
324// when restricted interval sampling is needed. This is controlled by
325// the fIsRestrictedSamplingRequired flag (false by default).
327 OneSamplingTable () = default;
328 void SetSize(std::size_t nx, G4bool useAlias) {
329 fN = nx;
330 // Alias
331 if (useAlias) {
332 fW.resize(nx);
333 fI.resize(nx);
334 }
335 // Ratin
336 fCum.resize(nx);
337 fA.resize(nx);
338 fB.resize(nx);
339 }
340
341 // members
342 std::size_t fN; // # data points
343 G4double fScreenParA; // the screening parameter
344 std::vector<G4double> fW;
345 std::vector<G4double> fCum;
346 std::vector<G4double> fA;
347 std::vector<G4double> fB;
348 std::vector<G4int> fI;
349};
350
351
352// loads sampling table for the given Z over the enrgy grid
353void G4eDPWAElasticDCS::BuildSmplingTableForZ(G4int iz) {
354 // Check if it has already been done:
355 if (fSamplingTables[iz]) return;
356 // Do it otherwise:
357 // allocate space
358 auto sTables = new std::vector<OneSamplingTable>(gNumEnergies);
359 // read compressed sampling table data
360 std::ostringstream oss;
361 const G4String fname = fIsElectron ? "stables/el/" : "stables/pos/";
362 oss << FindDirectoryPath() << fname << "stable_" << iz;
363 std::istringstream fin(std::ios::in);
364 ReadCompressedFile(oss.str(), fin);
365 std::size_t ndata = 0;
366 for (std::size_t ie=0; ie<gNumEnergies; ++ie) {
367 OneSamplingTable& aTable = (*sTables)[ie];
368 // #data in this table
369 fin >> ndata;
370 aTable.SetSize(ndata, !fIsRestrictedSamplingRequired);
371 // the A screening parameter value used for transformation of mu to u
372 fin >> aTable.fScreenParA;
373 // load data: Alias(W,I) + RatIn(Cum, A, B)
374 if (!fIsRestrictedSamplingRequired) {
375 for (std::size_t id=0; id<ndata; ++id) {
376 fin >> aTable.fW[id];
377 }
378 for (std::size_t id=0; id<ndata; ++id) {
379 fin >> aTable.fI[id];
380 }
381 }
382 for (std::size_t id=0; id<ndata; ++id) {
383 fin >> aTable.fCum[id];
384 }
385 for (std::size_t id=0; id<ndata; ++id) {
386 fin >> aTable.fA[id];
387 }
388 for (std::size_t id=0; id<ndata; ++id) {
389 fin >> aTable.fB[id];
390 }
391 }
392 fSamplingTables[iz] = sTables;
393}
394
395
396
397
398
399// samples cos(theta) i.e. cosine of the polar angle of scattering in elastic
400// interaction (Coulomb scattering) of the projectile (e- or e+ depending on
401// fIsElectron) with kinetic energy of exp('lekin'), target atom with atomic
402// muber of 'iz'. See the 'SampleCosineThetaRestricted' for obtain samples on
403// a restricted inteval.
406 G4double r2, G4double r3) {
407 lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], lekin));
408 // determine the discrete ekin sampling table to be used:
409 // - statistical interpolation (i.e. linear) on log energy scale
410 const G4double rem = (lekin-gLogMinEkin)*gInvDelLogEkin;
411 const auto k = (std::size_t)rem;
412 const std::size_t iekin = (r1 < rem-k) ? k+1 : k;
413 // sample the mu(t)=0.5(1-cos(t))
414 const double mu = SampleMu(iz, iekin, r2, r3);
415 return std::max(-1.0, std::min(1.0, 1.0-2.0*mu));
416}
417
418
419// samples cos(theta) i.e. cosine of the polar angle of scattering in elastic
420// interaction (Coulomb scattering) of the projectile (e- or e+ depending on
421// fIsElectron) with kinetic energy of exp('lekin'), target atom with atomic
422// muber of 'iz'.
423// The cosine theta will be in the [costMin, costMax] interval where costMin
424// corresponds to a maximum allowed polar scattering angle thetaMax while
425// costMin corresponds to minimum allowed polar scatterin angle thetaMin.
426// See the 'SampleCosineTheta' for obtain samples on the entire [-1,1] range.
429 G4double r1, G4double r2,
430 G4double costMax, G4double costMin) {
431 // costMin corresponds to mu-max while costMax to mu-min: mu(t)=0.5[1-cos(t)]
432 lekin = std::max(gTheEnergies[0], std::min(gTheEnergies[gNumEnergies-1], lekin));
433 // determine the discrete ekin sampling table to be used:
434 // - statistical interpolation (i.e. linear) on log energy scale
435 const G4double rem = (lekin-gLogMinEkin)*gInvDelLogEkin;
436 const auto k = (size_t)rem;
437 const std::size_t iekin = (r1 < rem-k) ? k : k+1;
438 // sample the mu(t)=0.5(1-cos(t))
439 const G4double mu = SampleMu(iz, iekin, r2, 0.5*(1.0-costMax), 0.5*(1.0-costMin));
440 return std::max(-1.0, std::min(1.0, 1.0-2.0*mu));
441}
442
443
444
446G4eDPWAElasticDCS::SampleMu(std::size_t izet, std::size_t ie, G4double r1, G4double r2) {
447 OneSamplingTable& rtn = (*fSamplingTables[izet])[ie];
448 // get the lower index of the bin by using the alias part
449 const G4double rest = r1 * (rtn.fN - 1);
450 auto indxl = (std::size_t)rest;
451 const G4double dum0 = rest - indxl;
452 if (rtn.fW[indxl] < dum0) indxl = rtn.fI[indxl];
453 // sample value within the selected bin by using ratin based numerical inversion
454 const G4double delta = rtn.fCum[indxl + 1] - rtn.fCum[indxl];
455 const G4double aval = r2 * delta;
456
457 const G4double dum1 = (1.0 + rtn.fA[indxl] + rtn.fB[indxl]) * delta * aval;
458 const G4double dum2 = delta * delta + rtn.fA[indxl] * delta * aval + rtn.fB[indxl] * aval * aval;
459 const std::vector<G4double>& theUVect = (fIsElectron && ie<gIndxEnergyLim) ? gTheU1 : gTheU2;
460 const G4double u = theUVect[indxl] + dum1 / dum2 * (theUVect[indxl + 1] - theUVect[indxl]);
461 // transform back u to mu
462 return rtn.fScreenParA*u/(rtn.fScreenParA+1.0-u);
463}
464
465
466
468G4eDPWAElasticDCS::FindCumValue(G4double u, const OneSamplingTable& stable,
469 const std::vector<G4double>& uvect) {
470 const std::size_t iLow = std::distance( uvect.begin(), std::upper_bound(uvect.begin(), uvect.end(), u) )-1;
471 const G4double tau = (u-uvect[iLow])/(uvect[iLow+1]-uvect[iLow]); // Note: I could store 1/(fX[iLow+1]-fX[iLow])
472 const G4double dum0 = (1.0+stable.fA[iLow]*(1.0-tau)+stable.fB[iLow]);
473 const G4double dum1 = 2.0*stable.fB[iLow]*tau;
474 const G4double dum2 = 1.0 - std::sqrt(std::max(0.0, 1.0-2.0*dum1*tau/(dum0*dum0)));
475 return std::min(stable.fCum[iLow+1], std::max(stable.fCum[iLow], stable.fCum[iLow]+dum0*dum2*(stable.fCum[iLow+1]-stable.fCum[iLow])/dum1 ));
476}
477
478// muMin and muMax : no checks on these
479G4double G4eDPWAElasticDCS::SampleMu(std::size_t izet, std::size_t ie, G4double r1,
480 G4double muMin, G4double muMax) {
481 const OneSamplingTable& rtn = (*fSamplingTables[izet])[ie];
482 const G4double theA = rtn.fScreenParA;
483 //
484 const std::vector<G4double>& theUVect = (fIsElectron && ie<gIndxEnergyLim) ? gTheU1 : gTheU2;
485 const G4double xiMin = (muMin > 0.0) ? FindCumValue((theA+1.0)*muMin/(theA+muMin), rtn, theUVect) : 0.0;
486 const G4double xiMax = (muMax < 1.0) ? FindCumValue((theA+1.0)*muMax/(theA+muMax), rtn, theUVect) : 1.0;
487 //
488 const G4double xi = xiMin+r1*(xiMax-xiMin); // a smaple within the range
489 const std::size_t iLow = std::distance( rtn.fCum.begin(), std::upper_bound(rtn.fCum.begin(), rtn.fCum.end(), xi) )-1;
490 const G4double delta = rtn.fCum[iLow + 1] - rtn.fCum[iLow];
491 const G4double aval = xi - rtn.fCum[iLow];
492
493 const G4double dum1 = (1.0 + rtn.fA[iLow] + rtn.fB[iLow]) * delta * aval;
494 const G4double dum2 = delta * delta + rtn.fA[iLow] * delta * aval + rtn.fB[iLow] * aval * aval;
495 const G4double u = theUVect[iLow] + dum1 / dum2 * (theUVect[iLow + 1] - theUVect[iLow]);
496 return theA*u/(theA+1.0-u);
497}
498
499
500
501// set the DCS data directory path
502const G4String& G4eDPWAElasticDCS::FindDirectoryPath() {
503 // check environment variable
504 if (gDataDirectory.empty()) {
505 std::ostringstream ost;
506 ost << G4EmParameters::Instance()->GetDirLEDATA() << "/dpwa/";
507 gDataDirectory = ost.str();
508 }
509 return gDataDirectory;
510}
511
512
513
514// uncompress one data file into the input string stream
515void
516G4eDPWAElasticDCS::ReadCompressedFile(G4String fname, std::istringstream &iss) {
517 G4String *dataString = nullptr;
518 G4String compfilename(fname+".z");
519 // create input stream with binary mode operation and positioning at the end of the file
520 std::ifstream in(compfilename, std::ios::binary | std::ios::ate);
521 if (in.good()) {
522 // get current position in the stream (was set to the end)
523 std::size_t fileSize = in.tellg();
524 // set current position being the beginning of the stream
525 in.seekg(0,std::ios::beg);
526 // create (zlib) byte buffer for the data
527 Bytef *compdata = new Bytef[fileSize];
528 while(in) {
529 in.read((char*)compdata, fileSize);
530 }
531 // create (zlib) byte buffer for the uncompressed data
532 uLongf complen = (uLongf)(fileSize*4);
533 Bytef *uncompdata = new Bytef[complen];
534 while (Z_OK!=uncompress(uncompdata, &complen, compdata, fileSize)) {
535 // increase uncompressed byte buffer
536 delete[] uncompdata;
537 complen *= 2;
538 uncompdata = new Bytef[complen];
539 }
540 // delete the compressed data buffer
541 delete [] compdata;
542 // create a string from the uncompressed data (will be deallocated by the caller)
543 dataString = new G4String((char*)uncompdata, (long)complen);
544 // delete the uncompressed data buffer
545 delete [] uncompdata;
546 } else {
547 G4String msg =
548 " Problem while trying to read " + fname + " data file.\n"+
549 " G4LEDATA version should be G4EMLOW7.12 or later.\n";
550 G4Exception("G4eDPWAElasticDCS::ReadCompressedFile","em0006",
551 FatalException,msg.c_str());
552 return;
553 }
554 // create the input string stream from the data string
555 if (dataString) {
556 iss.str(*dataString);
557 in.close();
558 delete dataString;
559 }
560}
561
562
563
564
567 G4double ekin) {
568 const G4int imc = matcut->GetIndex();
569 G4double corFactor = 1.0;
570 if (!(fSCPCPerMatCuts[imc]->fIsUse) || ekin<=fSCPCPerMatCuts[imc]->fPrCut) {
571 return corFactor;
572 }
573 // get the scattering power correction factor
574 const G4double lekin = G4Log(ekin);
575 G4double remaining = (lekin-fSCPCPerMatCuts[imc]->fLEmin)*fSCPCPerMatCuts[imc]->fILDel;
576 std::size_t lindx = (G4int)remaining;
577 remaining -= lindx;
578 std::size_t imax = fSCPCPerMatCuts[imc]->fVSCPC.size()-1;
579 if (lindx>=imax) {
580 corFactor = fSCPCPerMatCuts[imc]->fVSCPC[imax];
581 } else {
582 corFactor = fSCPCPerMatCuts[imc]->fVSCPC[lindx] + remaining*(fSCPCPerMatCuts[imc]->fVSCPC[lindx+1]-fSCPCPerMatCuts[imc]->fVSCPC[lindx]);
583 }
584 return corFactor;
585}
586
587
589 G4double highEnergyLimit) {
590 // get the material-cuts table
592 std::size_t numMatCuts = thePCTable->GetTableSize();
593 // clear container if any
594 for (std::size_t imc=0; imc<fSCPCPerMatCuts.size(); ++imc) {
595 if (fSCPCPerMatCuts[imc]) {
596 fSCPCPerMatCuts[imc]->fVSCPC.clear();
597 delete fSCPCPerMatCuts[imc];
598 fSCPCPerMatCuts[imc] = nullptr;
599 }
600 }
601 //
602 // set size of the container and create the corresponding data structures
603 fSCPCPerMatCuts.resize(numMatCuts,nullptr);
604 // loop over the material-cuts and create scattering power correction data structure for each
605 for (G4int imc=0; imc<(G4int)numMatCuts; ++imc) {
606 const G4MaterialCutsCouple *matCut = thePCTable->GetMaterialCutsCouple(imc);
607 const G4Material* mat = matCut->GetMaterial();
608 // get e- production cut in the current material-cuts in energy
609 const G4double ecut = (*(thePCTable->GetEnergyCutsVector(idxG4ElectronCut)))[matCut->GetIndex()];
610 const G4double limit = fIsElectron ? 2.0*ecut : ecut;
611 const G4double min = std::max(limit,lowEnergyLimit);
612 const G4double max = highEnergyLimit;
613 if (min>=max) {
614 fSCPCPerMatCuts[imc] = new SCPCorrection();
615 fSCPCPerMatCuts[imc]->fIsUse = false;
616 fSCPCPerMatCuts[imc]->fPrCut = min;
617 continue;
618 }
619 G4int numEbins = fNumSPCEbinPerDec*G4lrint(std::log10(max/min));
620 numEbins = std::max(numEbins,3);
621 const G4double lmin = G4Log(min);
622 const G4double ldel = G4Log(max/min)/(numEbins-1.0);
623 fSCPCPerMatCuts[imc] = new SCPCorrection();
624 fSCPCPerMatCuts[imc]->fVSCPC.resize(numEbins,1.0);
625 fSCPCPerMatCuts[imc]->fIsUse = true;
626 fSCPCPerMatCuts[imc]->fPrCut = min;
627 fSCPCPerMatCuts[imc]->fLEmin = lmin;
628 fSCPCPerMatCuts[imc]->fILDel = 1./ldel;
629 // compute Moliere material dependet parameetrs
630 G4double moliereBc = 0.0;
631 G4double moliereXc2 = 0.0;
632 ComputeMParams(mat, moliereBc, moliereXc2);
633 // compute scattering power correction over the enrgy grid
634 for (G4int ie=0; ie<numEbins; ++ie) {
635 const G4double ekin = G4Exp(lmin+ie*ldel);
636 G4double scpCorr = 1.0;
637 // compute correction factor: I.Kawrakow, Med.Phys.24,505-517(1997)(Eqs(32-37)
638 if (ie>0) {
639 const G4double tau = ekin/CLHEP::electron_mass_c2;
640 const G4double tauCut = ecut/CLHEP::electron_mass_c2;
641 // Moliere's screening parameter
642 const G4double A = moliereXc2/(4.0*tau*(tau+2.)*moliereBc);
643 const G4double gr = (1.+2.*A)*G4Log(1.+1./A)-2.;
644 const G4double dum0 = (tau+2.)/(tau+1.);
645 const G4double dum1 = tau+1.;
646 G4double gm = G4Log(0.5*tau/tauCut) + (1.+dum0*dum0)*G4Log(2.*(tau-tauCut+2.)/(tau+4.))
647 - 0.25*(tau+2.)*( tau+2.+2.*(2.*tau+1.)/(dum1*dum1))*
648 G4Log((tau+4.)*(tau-tauCut)/tau/(tau-tauCut+2.))
649 + 0.5*(tau-2*tauCut)*(tau+2.)*(1./(tau-tauCut)-1./(dum1*dum1));
650 if (gm<gr) {
651 gm = gm/gr;
652 } else {
653 gm = 1.;
654 }
655 const G4double z0 = matCut->GetMaterial()->GetIonisation()->GetZeffective();
656 scpCorr = 1.-gm*z0/(z0*(z0+1.));
657 }
658 fSCPCPerMatCuts[imc]->fVSCPC[ie] = scpCorr;
659 }
660 }
661}
662
663
664// compute material dependent Moliere MSC parameters at initialisation
665void G4eDPWAElasticDCS::ComputeMParams(const G4Material* mat, G4double& theBc,
666 G4double& theXc2) {
667 const G4double const1 = 7821.6; // [cm2/g]
668 const G4double const2 = 0.1569; // [cm2 MeV2 / g]
669 const G4double finstrc2 = 5.325135453E-5; // fine-structure const. square
670 // G4double xi = 1.0;
671 const G4ElementVector* theElemVect = mat->GetElementVector();
672 const std::size_t numelems = mat->GetNumberOfElements();
673 //
674 const G4double* theNbAtomsPerVolVect = mat->GetVecNbOfAtomsPerVolume();
675 G4double theTotNbAtomsPerVol = mat->GetTotNbOfAtomsPerVolume();
676 //
677 G4double zs = 0.0;
678 G4double zx = 0.0;
679 G4double ze = 0.0;
680 G4double sa = 0.0;
681 //
682 for(std::size_t ielem = 0; ielem < numelems; ++ielem) {
683 const G4double zet = (*theElemVect)[ielem]->GetZ();
684 const G4double iwa = (*theElemVect)[ielem]->GetN();
685 const G4double ipz = theNbAtomsPerVolVect[ielem]/theTotNbAtomsPerVol;
686 const G4double dum = ipz*zet*(zet+1.0);
687 zs += dum;
688 ze += dum*(-2.0/3.0)*G4Log(zet);
689 zx += dum*G4Log(1.0+3.34*finstrc2*zet*zet);
690 sa += ipz*iwa;
691 }
692 const G4double density = mat->GetDensity()*CLHEP::cm3/CLHEP::g; // [g/cm3]
693 //
694 theBc = const1*density*zs/sa*G4Exp(ze/zs)/G4Exp(zx/zs); //[1/cm]
695 theXc2 = const2*density*zs/sa; // [MeV2/cm]
696 // change to Geant4 internal units of 1/length and energ2/length
697 theBc *= 1.0/CLHEP::cm;
698 theXc2 *= CLHEP::MeV*CLHEP::MeV/CLHEP::cm;
699}
700
std::vector< const G4Element * > G4ElementVector
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:180
G4double G4Log(G4double x)
Definition G4Log.hh:227
@ idxG4ElectronCut
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
const G4double A[17]
static G4EmParameters * Instance()
const G4String & GetDirLEDATA() const
G4double GetZeffective() const
const G4Material * GetMaterial() const
G4double GetDensity() const
const G4ElementVector * GetElementVector() const
G4double GetTotNbOfAtomsPerVolume() const
G4IonisParamMat * GetIonisation() const
const G4double * GetVecNbOfAtomsPerVolume() const
std::size_t GetNumberOfElements() const
G4double Value(G4double x, G4double y, std::size_t &lastidx, std::size_t &lastidy) const
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
std::size_t GetTableSize() const
const std::vector< G4double > * GetEnergyCutsVector(std::size_t pcIdx) const
static G4ProductionCutsTable * GetProductionCutsTable()
void ComputeCSPerAtom(G4int iz, G4double ekin, G4double &elcs, G4double &tr1cs, G4double &tr2cs, G4double mumin=0.0, G4double mumax=1.0)
void InitialiseForZ(std::size_t iz)
void InitSCPCorrection(G4double lowEnergyLimit, G4double highEnergyLimit)
G4double ComputeScatteringPowerCorrection(const G4MaterialCutsCouple *matcut, G4double ekin)
G4double SampleCosineTheta(std::size_t iz, G4double lekin, G4double r1, G4double r2, G4double r3)
G4double SampleCosineThetaRestricted(std::size_t iz, G4double lekin, G4double r1, G4double r2, G4double costMax, G4double costMin)
G4eDPWAElasticDCS(G4bool iselectron=true, G4bool isrestricted=false)
std::vector< G4double > fB
std::vector< G4double > fA
std::vector< G4int > fI
void SetSize(std::size_t nx, G4bool useAlias)
OneSamplingTable()=default
std::vector< G4double > fW
std::vector< G4double > fCum
int G4lrint(double ad)
Definition templates.hh:134
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition uncompr.c:86
#define Z_OK
Definition zlib.h:177