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 | // MODULE: G4SPSEneDistribution.cc |
---|
29 | // |
---|
30 | // Version: 1.0 |
---|
31 | // Date: 5/02/04 |
---|
32 | // Author: Fan Lei |
---|
33 | // Organisation: QinetiQ ltd. |
---|
34 | // Customer: ESA/ESTEC |
---|
35 | // |
---|
36 | /////////////////////////////////////////////////////////////////////////////// |
---|
37 | // |
---|
38 | // CHANGE HISTORY |
---|
39 | // -------------- |
---|
40 | // |
---|
41 | // |
---|
42 | // Version 1.0, 05/02/2004, Fan Lei, Created. |
---|
43 | // Based on the G4GeneralParticleSource class in Geant4 v6.0 |
---|
44 | // |
---|
45 | /////////////////////////////////////////////////////////////////////////////// |
---|
46 | // |
---|
47 | #include "Randomize.hh" |
---|
48 | //#include <cmath> |
---|
49 | |
---|
50 | #include "G4SPSEneDistribution.hh" |
---|
51 | |
---|
52 | G4SPSEneDistribution::G4SPSEneDistribution() { |
---|
53 | // |
---|
54 | // Initialise all variables |
---|
55 | particle_energy = 1.0 * MeV; |
---|
56 | |
---|
57 | EnergyDisType = "Mono"; |
---|
58 | weight = 1.; |
---|
59 | MonoEnergy = 1 * MeV; |
---|
60 | Emin = 0.; |
---|
61 | Emax = 1.e30; |
---|
62 | alpha = 0.; |
---|
63 | biasalpha = 0.; |
---|
64 | prob_norm = 1.0; |
---|
65 | Ezero = 0.; |
---|
66 | SE = 0.; |
---|
67 | Temp = 0.; |
---|
68 | grad = 0.; |
---|
69 | cept = 0.; |
---|
70 | Biased = false; // not biased |
---|
71 | EnergySpec = true; // true - energy spectra, false - momentum spectra |
---|
72 | DiffSpec = true; // true - differential spec, false integral spec |
---|
73 | IntType = "NULL"; // Interpolation type |
---|
74 | IPDFEnergyExist = false; |
---|
75 | IPDFArbExist = false; |
---|
76 | |
---|
77 | ArbEmin = 0.; |
---|
78 | ArbEmax = 1.e30; |
---|
79 | |
---|
80 | verbosityLevel = 0; |
---|
81 | |
---|
82 | } |
---|
83 | |
---|
84 | G4SPSEneDistribution::~G4SPSEneDistribution() { |
---|
85 | } |
---|
86 | |
---|
87 | void G4SPSEneDistribution::SetEnergyDisType(G4String DisType) { |
---|
88 | EnergyDisType = DisType; |
---|
89 | if (EnergyDisType == "User") { |
---|
90 | UDefEnergyH = IPDFEnergyH = ZeroPhysVector; |
---|
91 | IPDFEnergyExist = false; |
---|
92 | } else if (EnergyDisType == "Arb") { |
---|
93 | ArbEnergyH = IPDFArbEnergyH = ZeroPhysVector; |
---|
94 | IPDFArbExist = false; |
---|
95 | } else if (EnergyDisType == "Epn") { |
---|
96 | UDefEnergyH = IPDFEnergyH = ZeroPhysVector; |
---|
97 | IPDFEnergyExist = false; |
---|
98 | EpnEnergyH = ZeroPhysVector; |
---|
99 | } |
---|
100 | } |
---|
101 | |
---|
102 | void G4SPSEneDistribution::SetEmin(G4double emi) { |
---|
103 | Emin = emi; |
---|
104 | } |
---|
105 | |
---|
106 | void G4SPSEneDistribution::SetEmax(G4double ema) { |
---|
107 | Emax = ema; |
---|
108 | } |
---|
109 | |
---|
110 | void G4SPSEneDistribution::SetMonoEnergy(G4double menergy) { |
---|
111 | MonoEnergy = menergy; |
---|
112 | } |
---|
113 | |
---|
114 | void G4SPSEneDistribution::SetBeamSigmaInE(G4double e) { |
---|
115 | SE = e; |
---|
116 | } |
---|
117 | void G4SPSEneDistribution::SetAlpha(G4double alp) { |
---|
118 | alpha = alp; |
---|
119 | } |
---|
120 | |
---|
121 | void G4SPSEneDistribution::SetBiasAlpha(G4double alp) { |
---|
122 | biasalpha = alp; |
---|
123 | Biased = true; |
---|
124 | } |
---|
125 | |
---|
126 | void G4SPSEneDistribution::SetTemp(G4double tem) { |
---|
127 | Temp = tem; |
---|
128 | } |
---|
129 | |
---|
130 | void G4SPSEneDistribution::SetEzero(G4double eze) { |
---|
131 | Ezero = eze; |
---|
132 | } |
---|
133 | |
---|
134 | void G4SPSEneDistribution::SetGradient(G4double gr) { |
---|
135 | grad = gr; |
---|
136 | } |
---|
137 | |
---|
138 | void G4SPSEneDistribution::SetInterCept(G4double c) { |
---|
139 | cept = c; |
---|
140 | } |
---|
141 | |
---|
142 | void G4SPSEneDistribution::UserEnergyHisto(G4ThreeVector input) { |
---|
143 | G4double ehi, val; |
---|
144 | ehi = input.x(); |
---|
145 | val = input.y(); |
---|
146 | if (verbosityLevel > 1) { |
---|
147 | G4cout << "In UserEnergyHisto" << G4endl; |
---|
148 | G4cout << " " << ehi << " " << val << G4endl; |
---|
149 | } |
---|
150 | UDefEnergyH.InsertValues(ehi, val); |
---|
151 | Emax = ehi; |
---|
152 | } |
---|
153 | |
---|
154 | void G4SPSEneDistribution::ArbEnergyHisto(G4ThreeVector input) { |
---|
155 | G4double ehi, val; |
---|
156 | ehi = input.x(); |
---|
157 | val = input.y(); |
---|
158 | if (verbosityLevel > 1) { |
---|
159 | G4cout << "In ArbEnergyHisto" << G4endl; |
---|
160 | G4cout << " " << ehi << " " << val << G4endl; |
---|
161 | } |
---|
162 | ArbEnergyH.InsertValues(ehi, val); |
---|
163 | } |
---|
164 | |
---|
165 | void G4SPSEneDistribution::ArbEnergyHistoFile(G4String filename) { |
---|
166 | std::ifstream infile(filename, std::ios::in); |
---|
167 | if (!infile) |
---|
168 | G4Exception("Unable to open the histo ASCII file"); |
---|
169 | G4double ehi, val; |
---|
170 | while (infile >> ehi >> val) { |
---|
171 | ArbEnergyH.InsertValues(ehi, val); |
---|
172 | } |
---|
173 | } |
---|
174 | |
---|
175 | void G4SPSEneDistribution::EpnEnergyHisto(G4ThreeVector input) { |
---|
176 | G4double ehi, val; |
---|
177 | ehi = input.x(); |
---|
178 | val = input.y(); |
---|
179 | if (verbosityLevel > 1) { |
---|
180 | G4cout << "In EpnEnergyHisto" << G4endl; |
---|
181 | G4cout << " " << ehi << " " << val << G4endl; |
---|
182 | } |
---|
183 | EpnEnergyH.InsertValues(ehi, val); |
---|
184 | Emax = ehi; |
---|
185 | Epnflag = true; |
---|
186 | } |
---|
187 | |
---|
188 | void G4SPSEneDistribution::Calculate() { |
---|
189 | if (EnergyDisType == "Cdg") |
---|
190 | CalculateCdgSpectrum(); |
---|
191 | else if (EnergyDisType == "Bbody") |
---|
192 | CalculateBbodySpectrum(); |
---|
193 | } |
---|
194 | |
---|
195 | void G4SPSEneDistribution::CalculateCdgSpectrum() { |
---|
196 | // This uses the spectrum from The INTEGRAL Mass Model (TIMM) |
---|
197 | // to generate a Cosmic Diffuse X/gamma ray spectrum. |
---|
198 | G4double pfact[2] = { 8.5, 112 }; |
---|
199 | G4double spind[2] = { 1.4, 2.3 }; |
---|
200 | G4double ene_line[3] = { 1. * keV, 18. * keV, 1E6 * keV }; |
---|
201 | G4int n_par; |
---|
202 | |
---|
203 | ene_line[0] = Emin; |
---|
204 | if (Emin < 18 * keV) { |
---|
205 | n_par = 2; |
---|
206 | ene_line[2] = Emax; |
---|
207 | if (Emax < 18 * keV) { |
---|
208 | n_par = 1; |
---|
209 | ene_line[1] = Emax; |
---|
210 | } |
---|
211 | } else { |
---|
212 | n_par = 1; |
---|
213 | pfact[0] = 112.; |
---|
214 | spind[0] = 2.3; |
---|
215 | ene_line[1] = Emax; |
---|
216 | } |
---|
217 | |
---|
218 | // Create a cumulative histogram. |
---|
219 | CDGhist[0] = 0.; |
---|
220 | G4double omalpha; |
---|
221 | G4int i = 0; |
---|
222 | |
---|
223 | while (i < n_par) { |
---|
224 | omalpha = 1. - spind[i]; |
---|
225 | CDGhist[i + 1] = CDGhist[i] + (pfact[i] / omalpha) * (std::pow( |
---|
226 | ene_line[i + 1] / keV, omalpha) - std::pow(ene_line[i] / keV, |
---|
227 | omalpha)); |
---|
228 | i++; |
---|
229 | } |
---|
230 | |
---|
231 | // Normalise histo and divide by 1000 to make MeV. |
---|
232 | i = 0; |
---|
233 | while (i < n_par) { |
---|
234 | CDGhist[i + 1] = CDGhist[i + 1] / CDGhist[n_par]; |
---|
235 | // G4cout << CDGhist[i] << CDGhist[n_par] << G4endl; |
---|
236 | i++; |
---|
237 | } |
---|
238 | } |
---|
239 | |
---|
240 | void G4SPSEneDistribution::CalculateBbodySpectrum() { |
---|
241 | // create bbody spectrum |
---|
242 | // Proved very hard to integrate indefinitely, so different |
---|
243 | // method. User inputs emin, emax and T. These are used to |
---|
244 | // create a 10,000 bin histogram. |
---|
245 | // Use photon density spectrum = 2 nu**2/c**2 * (std::exp(h nu/kT)-1) |
---|
246 | // = 2 E**2/h**2c**2 times the exponential |
---|
247 | G4double erange = Emax - Emin; |
---|
248 | G4double steps = erange / 10000.; |
---|
249 | G4double Bbody_y[10000]; |
---|
250 | G4double k = 8.6181e-11; //Boltzmann const in MeV/K |
---|
251 | G4double h = 4.1362e-21; // Plancks const in MeV s |
---|
252 | G4double c = 3e8; // Speed of light |
---|
253 | G4double h2 = h * h; |
---|
254 | G4double c2 = c * c; |
---|
255 | G4int count = 0; |
---|
256 | G4double sum = 0.; |
---|
257 | BBHist[0] = 0.; |
---|
258 | while (count < 10000) { |
---|
259 | Bbody_x[count] = Emin + G4double(count * steps); |
---|
260 | Bbody_y[count] = (2. * std::pow(Bbody_x[count], 2.)) / (h2 * c2 |
---|
261 | * (std::exp(Bbody_x[count] / (k * Temp)) - 1.)); |
---|
262 | sum = sum + Bbody_y[count]; |
---|
263 | BBHist[count + 1] = BBHist[count] + Bbody_y[count]; |
---|
264 | count++; |
---|
265 | } |
---|
266 | |
---|
267 | Bbody_x[10000] = Emax; |
---|
268 | // Normalise cumulative histo. |
---|
269 | count = 0; |
---|
270 | while (count < 10001) { |
---|
271 | BBHist[count] = BBHist[count] / sum; |
---|
272 | count++; |
---|
273 | } |
---|
274 | } |
---|
275 | |
---|
276 | void G4SPSEneDistribution::InputEnergySpectra(G4bool value) { |
---|
277 | // Allows user to specifiy spectrum is momentum |
---|
278 | EnergySpec = value; // false if momentum |
---|
279 | if (verbosityLevel > 1) |
---|
280 | G4cout << "EnergySpec has value " << EnergySpec << G4endl; |
---|
281 | } |
---|
282 | |
---|
283 | void G4SPSEneDistribution::InputDifferentialSpectra(G4bool value) { |
---|
284 | // Allows user to specify integral or differential spectra |
---|
285 | DiffSpec = value; // true = differential, false = integral |
---|
286 | if (verbosityLevel > 1) |
---|
287 | G4cout << "Diffspec has value " << DiffSpec << G4endl; |
---|
288 | } |
---|
289 | |
---|
290 | void G4SPSEneDistribution::ArbInterpolate(G4String IType) { |
---|
291 | if (EnergyDisType != "Arb") |
---|
292 | G4cout << "Error: this is for arbitrary distributions" << G4endl; |
---|
293 | IntType = IType; |
---|
294 | ArbEmax = ArbEnergyH.GetMaxLowEdgeEnergy(); |
---|
295 | ArbEmin = ArbEnergyH.GetMinLowEdgeEnergy(); |
---|
296 | |
---|
297 | // Now interpolate points |
---|
298 | if (IntType == "Lin") |
---|
299 | LinearInterpolation(); |
---|
300 | if (IntType == "Log") |
---|
301 | LogInterpolation(); |
---|
302 | if (IntType == "Exp") |
---|
303 | ExpInterpolation(); |
---|
304 | if (IntType == "Spline") |
---|
305 | SplineInterpolation(); |
---|
306 | } |
---|
307 | |
---|
308 | void G4SPSEneDistribution::LinearInterpolation() { |
---|
309 | // Method to do linear interpolation on the Arb points |
---|
310 | // Calculate equation of each line segment, max 1024. |
---|
311 | // Calculate Area under each segment |
---|
312 | // Create a cumulative array which is then normalised Arb_Cum_Area |
---|
313 | |
---|
314 | G4double Area_seg[1024]; // Stores area under each segment |
---|
315 | G4double sum = 0., Arb_x[1024], Arb_y[1024], Arb_Cum_Area[1024]; |
---|
316 | G4int i, count; |
---|
317 | G4int maxi = ArbEnergyH.GetVectorLength(); |
---|
318 | for (i = 0; i < maxi; i++) { |
---|
319 | Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(size_t(i)); |
---|
320 | Arb_y[i] = ArbEnergyH(size_t(i)); |
---|
321 | } |
---|
322 | // Points are now in x,y arrays. If the spectrum is integral it has to be |
---|
323 | // made differential and if momentum it has to be made energy. |
---|
324 | if (DiffSpec == false) { |
---|
325 | // Converts integral point-wise spectra to Differential |
---|
326 | for (count = 0; count < maxi - 1; count++) { |
---|
327 | Arb_y[count] = (Arb_y[count] - Arb_y[count + 1]) |
---|
328 | / (Arb_x[count + 1] - Arb_x[count]); |
---|
329 | } |
---|
330 | maxi--; |
---|
331 | } |
---|
332 | // |
---|
333 | if (EnergySpec == false) { |
---|
334 | // change currently stored values (emin etc) which are actually momenta |
---|
335 | // to energies. |
---|
336 | if (particle_definition == NULL) |
---|
337 | G4cout << "Error: particle not defined" << G4endl; |
---|
338 | else { |
---|
339 | // Apply Energy**2 = p**2c**2 + m0**2c**4 |
---|
340 | // p should be entered as E/c i.e. without the division by c |
---|
341 | // being done - energy equivalent. |
---|
342 | G4double mass = particle_definition->GetPDGMass(); |
---|
343 | // convert point to energy unit and its value to per energy unit |
---|
344 | G4double total_energy; |
---|
345 | for (count = 0; count < maxi; count++) { |
---|
346 | total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass |
---|
347 | * mass)); // total energy |
---|
348 | |
---|
349 | Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy; |
---|
350 | Arb_x[count] = total_energy - mass; // kinetic energy |
---|
351 | } |
---|
352 | } |
---|
353 | } |
---|
354 | // |
---|
355 | i = 1; |
---|
356 | Arb_grad[0] = 0.; |
---|
357 | Arb_cept[0] = 0.; |
---|
358 | Area_seg[0] = 0.; |
---|
359 | Arb_Cum_Area[0] = 0.; |
---|
360 | while (i < maxi) { |
---|
361 | // calc gradient and intercept for each segment |
---|
362 | Arb_grad[i] = (Arb_y[i] - Arb_y[i - 1]) / (Arb_x[i] - Arb_x[i - 1]); |
---|
363 | if (verbosityLevel == 2) |
---|
364 | G4cout << Arb_grad[i] << G4endl; |
---|
365 | if (Arb_grad[i] > 0.) { |
---|
366 | if (verbosityLevel == 2) |
---|
367 | G4cout << "Arb_grad is positive" << G4endl; |
---|
368 | Arb_cept[i] = Arb_y[i] - (Arb_grad[i] * Arb_x[i]); |
---|
369 | } else if (Arb_grad[i] < 0.) { |
---|
370 | if (verbosityLevel == 2) |
---|
371 | G4cout << "Arb_grad is negative" << G4endl; |
---|
372 | Arb_cept[i] = Arb_y[i] + (-Arb_grad[i] * Arb_x[i]); |
---|
373 | } else { |
---|
374 | if (verbosityLevel == 2) |
---|
375 | G4cout << "Arb_grad is 0." << G4endl; |
---|
376 | Arb_cept[i] = Arb_y[i]; |
---|
377 | } |
---|
378 | |
---|
379 | Area_seg[i] = ((Arb_grad[i] / 2) * (Arb_x[i] * Arb_x[i] - Arb_x[i - 1] |
---|
380 | * Arb_x[i - 1]) + Arb_cept[i] * (Arb_x[i] - Arb_x[i - 1])); |
---|
381 | Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i]; |
---|
382 | sum = sum + Area_seg[i]; |
---|
383 | if (verbosityLevel == 2) |
---|
384 | G4cout << Arb_x[i] << Arb_y[i] << Area_seg[i] << sum << Arb_grad[i] |
---|
385 | << G4endl; |
---|
386 | i++; |
---|
387 | } |
---|
388 | |
---|
389 | i = 0; |
---|
390 | while (i < maxi) { |
---|
391 | Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; // normalisation |
---|
392 | IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]); |
---|
393 | i++; |
---|
394 | } |
---|
395 | |
---|
396 | // now scale the ArbEnergyH, needed by Probability() |
---|
397 | ArbEnergyH.ScaleVector(1., 1./sum); |
---|
398 | |
---|
399 | if (verbosityLevel >= 1) { |
---|
400 | G4cout << "Leaving LinearInterpolation" << G4endl; |
---|
401 | ArbEnergyH.DumpValues(); |
---|
402 | IPDFArbEnergyH.DumpValues(); |
---|
403 | } |
---|
404 | } |
---|
405 | |
---|
406 | void G4SPSEneDistribution::LogInterpolation() { |
---|
407 | // Interpolation based on Logarithmic equations |
---|
408 | // Generate equations of line segments |
---|
409 | // y = Ax**alpha => log y = alpha*logx + logA |
---|
410 | // Find area under line segments |
---|
411 | // create normalised, cumulative array Arb_Cum_Area |
---|
412 | G4double Area_seg[1024]; // Stores area under each segment |
---|
413 | G4double sum = 0., Arb_x[1024], Arb_y[1024], Arb_Cum_Area[1024]; |
---|
414 | G4int i, count; |
---|
415 | G4int maxi = ArbEnergyH.GetVectorLength(); |
---|
416 | for (i = 0; i < maxi; i++) { |
---|
417 | Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(size_t(i)); |
---|
418 | Arb_y[i] = ArbEnergyH(size_t(i)); |
---|
419 | } |
---|
420 | // Points are now in x,y arrays. If the spectrum is integral it has to be |
---|
421 | // made differential and if momentum it has to be made energy. |
---|
422 | if (DiffSpec == false) { |
---|
423 | // Converts integral point-wise spectra to Differential |
---|
424 | for (count = 0; count < maxi - 1; count++) { |
---|
425 | Arb_y[count] = (Arb_y[count] - Arb_y[count + 1]) |
---|
426 | / (Arb_x[count + 1] - Arb_x[count]); |
---|
427 | } |
---|
428 | maxi--; |
---|
429 | } |
---|
430 | // |
---|
431 | if (EnergySpec == false) { |
---|
432 | // change currently stored values (emin etc) which are actually momenta |
---|
433 | // to energies. |
---|
434 | if (particle_definition == NULL) |
---|
435 | G4cout << "Error: particle not defined" << G4endl; |
---|
436 | else { |
---|
437 | // Apply Energy**2 = p**2c**2 + m0**2c**4 |
---|
438 | // p should be entered as E/c i.e. without the division by c |
---|
439 | // being done - energy equivalent. |
---|
440 | G4double mass = particle_definition->GetPDGMass(); |
---|
441 | // convert point to energy unit and its value to per energy unit |
---|
442 | G4double total_energy; |
---|
443 | for (count = 0; count < maxi; count++) { |
---|
444 | total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass |
---|
445 | * mass)); // total energy |
---|
446 | |
---|
447 | Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy; |
---|
448 | Arb_x[count] = total_energy - mass; // kinetic energy |
---|
449 | } |
---|
450 | } |
---|
451 | } |
---|
452 | // |
---|
453 | i = 1; |
---|
454 | Arb_alpha[0] = 0.; |
---|
455 | Arb_Const[0] = 0.; |
---|
456 | Area_seg[0] = 0.; |
---|
457 | Arb_Cum_Area[0] = 0.; |
---|
458 | if (Arb_x[0] <= 0. || Arb_y[0] <= 0.) { |
---|
459 | G4cout << "You should not use log interpolation with points <= 0." |
---|
460 | << G4endl; |
---|
461 | G4cout << "These will be changed to 1e-20, which may cause problems" |
---|
462 | << G4endl; |
---|
463 | if (Arb_x[0] <= 0.) |
---|
464 | Arb_x[0] = 1e-20; |
---|
465 | if (Arb_y[0] <= 0.) |
---|
466 | Arb_y[0] = 1e-20; |
---|
467 | } |
---|
468 | |
---|
469 | G4double alp; |
---|
470 | while (i < maxi) { |
---|
471 | // Incase points are negative or zero |
---|
472 | if (Arb_x[i] <= 0. || Arb_y[i] <= 0.) { |
---|
473 | G4cout << "You should not use log interpolation with points <= 0." |
---|
474 | << G4endl; |
---|
475 | G4cout |
---|
476 | << "These will be changed to 1e-20, which may cause problems" |
---|
477 | << G4endl; |
---|
478 | if (Arb_x[i] <= 0.) |
---|
479 | Arb_x[i] = 1e-20; |
---|
480 | if (Arb_y[i] <= 0.) |
---|
481 | Arb_y[i] = 1e-20; |
---|
482 | } |
---|
483 | |
---|
484 | Arb_alpha[i] = (std::log10(Arb_y[i]) - std::log10(Arb_y[i - 1])) |
---|
485 | / (std::log10(Arb_x[i]) - std::log10(Arb_x[i - 1])); |
---|
486 | Arb_Const[i] = Arb_y[i] / (std::pow(Arb_x[i], Arb_alpha[i])); |
---|
487 | alp = Arb_alpha[i] + 1; |
---|
488 | if (alp == 0.) { |
---|
489 | Area_seg[i] = Arb_Const[i] * (std::log(Arb_x[i]) - std::log(Arb_x[i - 1])); |
---|
490 | } else { |
---|
491 | Area_seg[i] = (Arb_Const[i] / alp) * (std::pow(Arb_x[i], alp) |
---|
492 | - std::pow(Arb_x[i - 1], alp)); |
---|
493 | } |
---|
494 | sum = sum + Area_seg[i]; |
---|
495 | Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i]; |
---|
496 | if (verbosityLevel == 2) |
---|
497 | G4cout << Arb_alpha[i] << Arb_Const[i] << Area_seg[i] << G4endl; |
---|
498 | i++; |
---|
499 | } |
---|
500 | |
---|
501 | i = 0; |
---|
502 | while (i < maxi) { |
---|
503 | Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; |
---|
504 | IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]); |
---|
505 | i++; |
---|
506 | } |
---|
507 | |
---|
508 | // now scale the ArbEnergyH, needed by Probability() |
---|
509 | ArbEnergyH.ScaleVector(1., 1./sum); |
---|
510 | |
---|
511 | if (verbosityLevel >= 1) |
---|
512 | G4cout << "Leaving LogInterpolation " << G4endl; |
---|
513 | } |
---|
514 | |
---|
515 | void G4SPSEneDistribution::ExpInterpolation() { |
---|
516 | // Interpolation based on Exponential equations |
---|
517 | // Generate equations of line segments |
---|
518 | // y = Ae**-(x/e0) => ln y = -x/e0 + lnA |
---|
519 | // Find area under line segments |
---|
520 | // create normalised, cumulative array Arb_Cum_Area |
---|
521 | G4double Area_seg[1024]; // Stores area under each segment |
---|
522 | G4double sum = 0., Arb_x[1024], Arb_y[1024], Arb_Cum_Area[1024]; |
---|
523 | G4int i, count; |
---|
524 | G4int maxi = ArbEnergyH.GetVectorLength(); |
---|
525 | for (i = 0; i < maxi; i++) { |
---|
526 | Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(size_t(i)); |
---|
527 | Arb_y[i] = ArbEnergyH(size_t(i)); |
---|
528 | } |
---|
529 | // Points are now in x,y arrays. If the spectrum is integral it has to be |
---|
530 | // made differential and if momentum it has to be made energy. |
---|
531 | if (DiffSpec == false) { |
---|
532 | // Converts integral point-wise spectra to Differential |
---|
533 | for (count = 0; count < maxi - 1; count++) { |
---|
534 | Arb_y[count] = (Arb_y[count] - Arb_y[count + 1]) |
---|
535 | / (Arb_x[count + 1] - Arb_x[count]); |
---|
536 | } |
---|
537 | maxi--; |
---|
538 | } |
---|
539 | // |
---|
540 | if (EnergySpec == false) { |
---|
541 | // change currently stored values (emin etc) which are actually momenta |
---|
542 | // to energies. |
---|
543 | if (particle_definition == NULL) |
---|
544 | G4cout << "Error: particle not defined" << G4endl; |
---|
545 | else { |
---|
546 | // Apply Energy**2 = p**2c**2 + m0**2c**4 |
---|
547 | // p should be entered as E/c i.e. without the division by c |
---|
548 | // being done - energy equivalent. |
---|
549 | G4double mass = particle_definition->GetPDGMass(); |
---|
550 | // convert point to energy unit and its value to per energy unit |
---|
551 | G4double total_energy; |
---|
552 | for (count = 0; count < maxi; count++) { |
---|
553 | total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass |
---|
554 | * mass)); // total energy |
---|
555 | |
---|
556 | Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy; |
---|
557 | Arb_x[count] = total_energy - mass; // kinetic energy |
---|
558 | } |
---|
559 | } |
---|
560 | } |
---|
561 | // |
---|
562 | i = 1; |
---|
563 | Arb_ezero[0] = 0.; |
---|
564 | Arb_Const[0] = 0.; |
---|
565 | Area_seg[0] = 0.; |
---|
566 | Arb_Cum_Area[0] = 0.; |
---|
567 | while (i < maxi) { |
---|
568 | G4double test = std::log(Arb_y[i]) - std::log(Arb_y[i - 1]); |
---|
569 | if (test > 0. || test < 0.) { |
---|
570 | Arb_ezero[i] = -(Arb_x[i] - Arb_x[i - 1]) / (std::log(Arb_y[i]) |
---|
571 | - std::log(Arb_y[i - 1])); |
---|
572 | Arb_Const[i] = Arb_y[i] / (std::exp(-Arb_x[i] / Arb_ezero[i])); |
---|
573 | Area_seg[i] = -(Arb_Const[i] * Arb_ezero[i]) * (std::exp(-Arb_x[i] |
---|
574 | / Arb_ezero[i]) - std::exp(-Arb_x[i - 1] / Arb_ezero[i])); |
---|
575 | } else { |
---|
576 | G4cout << "Flat line segment: problem" << G4endl; |
---|
577 | Arb_ezero[i] = 0.; |
---|
578 | Arb_Const[i] = 0.; |
---|
579 | Area_seg[i] = 0.; |
---|
580 | } |
---|
581 | sum = sum + Area_seg[i]; |
---|
582 | Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i]; |
---|
583 | if (verbosityLevel == 2) |
---|
584 | G4cout << Arb_ezero[i] << Arb_Const[i] << Area_seg[i] << G4endl; |
---|
585 | i++; |
---|
586 | } |
---|
587 | |
---|
588 | i = 0; |
---|
589 | while (i < maxi) { |
---|
590 | Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; |
---|
591 | IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]); |
---|
592 | i++; |
---|
593 | } |
---|
594 | |
---|
595 | // now scale the ArbEnergyH, needed by Probability() |
---|
596 | ArbEnergyH.ScaleVector(1., 1./sum); |
---|
597 | |
---|
598 | if (verbosityLevel >= 1) |
---|
599 | G4cout << "Leaving ExpInterpolation " << G4endl; |
---|
600 | } |
---|
601 | |
---|
602 | void G4SPSEneDistribution::SplineInterpolation() { |
---|
603 | // Interpolation using Splines. |
---|
604 | // Create Normalised arrays, make x 0->1 and y hold |
---|
605 | // the function (Energy) |
---|
606 | // |
---|
607 | // Current method based on the above will not work in all cases. |
---|
608 | // new method is implemented below. |
---|
609 | |
---|
610 | G4double sum, Arb_x[1024], Arb_y[1024], Arb_Cum_Area[1024]; |
---|
611 | G4int i, count; |
---|
612 | |
---|
613 | G4int maxi = ArbEnergyH.GetVectorLength(); |
---|
614 | for (i = 0; i < maxi; i++) { |
---|
615 | Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(size_t(i)); |
---|
616 | Arb_y[i] = ArbEnergyH(size_t(i)); |
---|
617 | } |
---|
618 | // Points are now in x,y arrays. If the spectrum is integral it has to be |
---|
619 | // made differential and if momentum it has to be made energy. |
---|
620 | if (DiffSpec == false) { |
---|
621 | // Converts integral point-wise spectra to Differential |
---|
622 | for (count = 0; count < maxi - 1; count++) { |
---|
623 | Arb_y[count] = (Arb_y[count] - Arb_y[count + 1]) |
---|
624 | / (Arb_x[count + 1] - Arb_x[count]); |
---|
625 | } |
---|
626 | maxi--; |
---|
627 | } |
---|
628 | // |
---|
629 | if (EnergySpec == false) { |
---|
630 | // change currently stored values (emin etc) which are actually momenta |
---|
631 | // to energies. |
---|
632 | if (particle_definition == NULL) |
---|
633 | G4cout << "Error: particle not defined" << G4endl; |
---|
634 | else { |
---|
635 | // Apply Energy**2 = p**2c**2 + m0**2c**4 |
---|
636 | // p should be entered as E/c i.e. without the division by c |
---|
637 | // being done - energy equivalent. |
---|
638 | G4double mass = particle_definition->GetPDGMass(); |
---|
639 | // convert point to energy unit and its value to per energy unit |
---|
640 | G4double total_energy; |
---|
641 | for (count = 0; count < maxi; count++) { |
---|
642 | total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass |
---|
643 | * mass)); // total energy |
---|
644 | |
---|
645 | Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy; |
---|
646 | Arb_x[count] = total_energy - mass; // kinetic energy |
---|
647 | } |
---|
648 | } |
---|
649 | } |
---|
650 | |
---|
651 | // |
---|
652 | i = 1; |
---|
653 | Arb_Cum_Area[0] = 0.; |
---|
654 | sum = 0.; |
---|
655 | Splinetemp = new G4DataInterpolation(Arb_x, Arb_y, maxi, 0., 0.); |
---|
656 | G4double ei[101],prob[101]; |
---|
657 | while (i < maxi) { |
---|
658 | // 100 step per segment for the integration of area |
---|
659 | G4double de = (Arb_x[i] - Arb_x[i - 1])/100.; |
---|
660 | G4double area = 0.; |
---|
661 | |
---|
662 | for (count = 0; count < 101; count++) { |
---|
663 | ei[count] = Arb_x[i - 1] + de*count ; |
---|
664 | prob[count] = Splinetemp->CubicSplineInterpolation(ei[count]); |
---|
665 | if (prob[count] < 0.) { |
---|
666 | G4cout << "Warning: G4DataInterpolation returns value < 0 " << prob[count] <<" "<<ei[count]<< G4endl; |
---|
667 | G4Exception(" Please use an alternative method, e.g. Lin, for interpolation"); |
---|
668 | } |
---|
669 | area += prob[count]*de; |
---|
670 | } |
---|
671 | Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + area; |
---|
672 | sum += area; |
---|
673 | |
---|
674 | prob[0] = prob[0]/(area/de); |
---|
675 | for (count = 1; count < 100; count++) |
---|
676 | prob[count] = prob[count-1] + prob[count]/(area/de); |
---|
677 | |
---|
678 | SplineInt[i] = new G4DataInterpolation(prob, ei, 101, 0., 0.); |
---|
679 | // note i start from 1! |
---|
680 | i++; |
---|
681 | } |
---|
682 | i = 0; |
---|
683 | while (i < maxi) { |
---|
684 | Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; // normalisation |
---|
685 | IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]); |
---|
686 | i++; |
---|
687 | } |
---|
688 | // now scale the ArbEnergyH, needed by Probability() |
---|
689 | ArbEnergyH.ScaleVector(1., 1./sum); |
---|
690 | |
---|
691 | if (verbosityLevel > 0) |
---|
692 | G4cout << "Leaving SplineInterpolation " << G4endl; |
---|
693 | } |
---|
694 | |
---|
695 | void G4SPSEneDistribution::GenerateMonoEnergetic() { |
---|
696 | // Method to generate MonoEnergetic particles. |
---|
697 | particle_energy = MonoEnergy; |
---|
698 | } |
---|
699 | |
---|
700 | void G4SPSEneDistribution::GenerateGaussEnergies() { |
---|
701 | // Method to generate Gaussian particles. |
---|
702 | particle_energy = G4RandGauss::shoot(MonoEnergy,SE); |
---|
703 | if (particle_energy < 0) particle_energy = 0.; |
---|
704 | } |
---|
705 | |
---|
706 | void G4SPSEneDistribution::GenerateLinearEnergies(G4bool bArb = false) { |
---|
707 | G4double rndm; |
---|
708 | G4double emaxsq = std::pow(Emax, 2.); //Emax squared |
---|
709 | G4double eminsq = std::pow(Emin, 2.); //Emin squared |
---|
710 | G4double intersq = std::pow(cept, 2.); //cept squared |
---|
711 | |
---|
712 | if (bArb) |
---|
713 | rndm = G4UniformRand(); |
---|
714 | else |
---|
715 | rndm = eneRndm->GenRandEnergy(); |
---|
716 | |
---|
717 | G4double bracket = ((grad / 2.) * (emaxsq - eminsq) + cept * (Emax - Emin)); |
---|
718 | bracket = bracket * rndm; |
---|
719 | bracket = bracket + (grad / 2.) * eminsq + cept * Emin; |
---|
720 | // Now have a quad of form m/2 E**2 + cE - bracket = 0 |
---|
721 | bracket = -bracket; |
---|
722 | // G4cout << "BRACKET" << bracket << G4endl; |
---|
723 | if (grad != 0.) { |
---|
724 | G4double sqbrack = (intersq - 4 * (grad / 2.) * (bracket)); |
---|
725 | // G4cout << "SQBRACK" << sqbrack << G4endl; |
---|
726 | sqbrack = std::sqrt(sqbrack); |
---|
727 | G4double root1 = -cept + sqbrack; |
---|
728 | root1 = root1 / (2. * (grad / 2.)); |
---|
729 | |
---|
730 | G4double root2 = -cept - sqbrack; |
---|
731 | root2 = root2 / (2. * (grad / 2.)); |
---|
732 | |
---|
733 | // G4cout << root1 << " roots " << root2 << G4endl; |
---|
734 | |
---|
735 | if (root1 > Emin && root1 < Emax) |
---|
736 | particle_energy = root1; |
---|
737 | if (root2 > Emin && root2 < Emax) |
---|
738 | particle_energy = root2; |
---|
739 | } else if (grad == 0.) |
---|
740 | // have equation of form cE - bracket =0 |
---|
741 | particle_energy = bracket / cept; |
---|
742 | |
---|
743 | if (particle_energy < 0.) |
---|
744 | particle_energy = -particle_energy; |
---|
745 | |
---|
746 | if (verbosityLevel >= 1) |
---|
747 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
748 | } |
---|
749 | |
---|
750 | void G4SPSEneDistribution::GeneratePowEnergies(G4bool bArb = false) { |
---|
751 | // Method to generate particle energies distributed as |
---|
752 | // a power-law |
---|
753 | |
---|
754 | G4double rndm; |
---|
755 | G4double emina, emaxa; |
---|
756 | |
---|
757 | emina = std::pow(Emin, alpha + 1); |
---|
758 | emaxa = std::pow(Emax, alpha + 1); |
---|
759 | |
---|
760 | if (bArb) |
---|
761 | rndm = G4UniformRand(); |
---|
762 | else |
---|
763 | rndm = eneRndm->GenRandEnergy(); |
---|
764 | |
---|
765 | if (alpha != -1.) { |
---|
766 | particle_energy = ((rndm * (emaxa - emina)) + emina); |
---|
767 | particle_energy = std::pow(particle_energy, (1. / (alpha + 1.))); |
---|
768 | } else { |
---|
769 | particle_energy = (std::log(Emin) + rndm * (std::log(Emax) - std::log( |
---|
770 | Emin))); |
---|
771 | particle_energy = std::exp(particle_energy); |
---|
772 | } |
---|
773 | if (verbosityLevel >= 1) |
---|
774 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
775 | } |
---|
776 | |
---|
777 | void G4SPSEneDistribution::GenerateBiasPowEnergies() { |
---|
778 | // Method to generate particle energies distributed as |
---|
779 | // in biased power-law and calculate its weight |
---|
780 | |
---|
781 | G4double rndm; |
---|
782 | G4double emina, emaxa, emin, emax; |
---|
783 | |
---|
784 | G4double normal = 1. ; |
---|
785 | |
---|
786 | emin = Emin; |
---|
787 | emax = Emax; |
---|
788 | // if (EnergyDisType == "Arb") { |
---|
789 | // emin = ArbEmin; |
---|
790 | // emax = ArbEmax; |
---|
791 | //} |
---|
792 | |
---|
793 | rndm = eneRndm->GenRandEnergy(); |
---|
794 | |
---|
795 | if (biasalpha != -1.) { |
---|
796 | emina = std::pow(emin, biasalpha + 1); |
---|
797 | emaxa = std::pow(emax, biasalpha + 1); |
---|
798 | particle_energy = ((rndm * (emaxa - emina)) + emina); |
---|
799 | particle_energy = std::pow(particle_energy, (1. / (biasalpha + 1.))); |
---|
800 | normal = 1./(1+biasalpha) * (emaxa - emina); |
---|
801 | } else { |
---|
802 | particle_energy = (std::log(emin) + rndm * (std::log(emax) - std::log( |
---|
803 | emin))); |
---|
804 | particle_energy = std::exp(particle_energy); |
---|
805 | normal = std::log(emax) - std::log(emin) ; |
---|
806 | } |
---|
807 | weight = GetProbability(particle_energy) / (std::pow(particle_energy,biasalpha)/normal); |
---|
808 | |
---|
809 | if (verbosityLevel >= 1) |
---|
810 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
811 | } |
---|
812 | |
---|
813 | void G4SPSEneDistribution::GenerateExpEnergies(G4bool bArb = false) { |
---|
814 | // Method to generate particle energies distributed according |
---|
815 | // to an exponential curve. |
---|
816 | G4double rndm; |
---|
817 | |
---|
818 | if (bArb) |
---|
819 | rndm = G4UniformRand(); |
---|
820 | else |
---|
821 | rndm = eneRndm->GenRandEnergy(); |
---|
822 | |
---|
823 | particle_energy = -Ezero * (std::log(rndm * (std::exp(-Emax / Ezero) |
---|
824 | - std::exp(-Emin / Ezero)) + std::exp(-Emin / Ezero))); |
---|
825 | if (verbosityLevel >= 1) |
---|
826 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
827 | } |
---|
828 | |
---|
829 | void G4SPSEneDistribution::GenerateBremEnergies() { |
---|
830 | // Method to generate particle energies distributed according |
---|
831 | // to a Bremstrahlung equation of |
---|
832 | // form I = const*((kT)**1/2)*E*(e**(-E/kT)) |
---|
833 | |
---|
834 | G4double rndm; |
---|
835 | rndm = eneRndm->GenRandEnergy(); |
---|
836 | G4double expmax, expmin, k; |
---|
837 | |
---|
838 | k = 8.6181e-11; // Boltzmann's const in MeV/K |
---|
839 | G4double ksq = std::pow(k, 2.); // k squared |
---|
840 | G4double Tsq = std::pow(Temp, 2.); // Temp squared |
---|
841 | |
---|
842 | expmax = std::exp(-Emax / (k * Temp)); |
---|
843 | expmin = std::exp(-Emin / (k * Temp)); |
---|
844 | |
---|
845 | // If either expmax or expmin are zero then this will cause problems |
---|
846 | // Most probably this will be because T is too low or E is too high |
---|
847 | |
---|
848 | if (expmax == 0.) |
---|
849 | G4cout << "*****EXPMAX=0. Choose different E's or Temp" << G4endl; |
---|
850 | if (expmin == 0.) |
---|
851 | G4cout << "*****EXPMIN=0. Choose different E's or Temp" << G4endl; |
---|
852 | |
---|
853 | G4double tempvar = rndm * ((-k) * Temp * (Emax * expmax - Emin * expmin) |
---|
854 | - (ksq * Tsq * (expmax - expmin))); |
---|
855 | |
---|
856 | G4double bigc = (tempvar - k * Temp * Emin * expmin - ksq * Tsq * expmin) |
---|
857 | / (-k * Temp); |
---|
858 | |
---|
859 | // This gives an equation of form: Ee(-E/kT) + kTe(-E/kT) - C =0 |
---|
860 | // Solve this iteratively, step from Emin to Emax in 1000 steps |
---|
861 | // and take the best solution. |
---|
862 | |
---|
863 | G4double erange = Emax - Emin; |
---|
864 | G4double steps = erange / 1000.; |
---|
865 | G4int i; |
---|
866 | G4double etest, diff, err; |
---|
867 | |
---|
868 | err = 100000.; |
---|
869 | |
---|
870 | for (i = 1; i < 1000; i++) { |
---|
871 | etest = Emin + (i - 1) * steps; |
---|
872 | |
---|
873 | diff = etest * (std::exp(-etest / (k * Temp))) + k * Temp * (std::exp( |
---|
874 | -etest / (k * Temp))) - bigc; |
---|
875 | |
---|
876 | if (diff < 0.) |
---|
877 | diff = -diff; |
---|
878 | |
---|
879 | if (diff < err) { |
---|
880 | err = diff; |
---|
881 | particle_energy = etest; |
---|
882 | } |
---|
883 | } |
---|
884 | if (verbosityLevel >= 1) |
---|
885 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
886 | } |
---|
887 | |
---|
888 | void G4SPSEneDistribution::GenerateBbodyEnergies() { |
---|
889 | // BBody_x holds Energies, and BBHist holds the cumulative histo. |
---|
890 | // binary search to find correct bin then lin interpolation. |
---|
891 | // Use the earlier defined histogram + RandGeneral method to generate |
---|
892 | // random numbers following the histos distribution. |
---|
893 | G4double rndm; |
---|
894 | G4int nabove, nbelow = 0, middle; |
---|
895 | nabove = 10001; |
---|
896 | rndm = eneRndm->GenRandEnergy(); |
---|
897 | |
---|
898 | // Binary search to find bin that rndm is in |
---|
899 | while (nabove - nbelow > 1) { |
---|
900 | middle = (nabove + nbelow) / 2; |
---|
901 | if (rndm == BBHist[middle]) |
---|
902 | break; |
---|
903 | if (rndm < BBHist[middle]) |
---|
904 | nabove = middle; |
---|
905 | else |
---|
906 | nbelow = middle; |
---|
907 | } |
---|
908 | |
---|
909 | // Now interpolate in that bin to find the correct output value. |
---|
910 | G4double x1, x2, y1, y2, m, q; |
---|
911 | x1 = Bbody_x[nbelow]; |
---|
912 | x2 = Bbody_x[nbelow + 1]; |
---|
913 | y1 = BBHist[nbelow]; |
---|
914 | y2 = BBHist[nbelow + 1]; |
---|
915 | m = (y2 - y1) / (x2 - x1); |
---|
916 | q = y1 - m * x1; |
---|
917 | |
---|
918 | particle_energy = (rndm - q) / m; |
---|
919 | |
---|
920 | if (verbosityLevel >= 1) { |
---|
921 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
922 | } |
---|
923 | } |
---|
924 | |
---|
925 | void G4SPSEneDistribution::GenerateCdgEnergies() { |
---|
926 | // Gen random numbers, compare with values in cumhist |
---|
927 | // to find appropriate part of spectrum and then |
---|
928 | // generate energy in the usual inversion way. |
---|
929 | // G4double pfact[2] = {8.5, 112}; |
---|
930 | // G4double spind[2] = {1.4, 2.3}; |
---|
931 | // G4double ene_line[3] = {1., 18., 1E6}; |
---|
932 | G4double rndm, rndm2; |
---|
933 | G4double ene_line[3]; |
---|
934 | G4double omalpha[2]; |
---|
935 | if (Emin < 18 * keV && Emax < 18 * keV) { |
---|
936 | omalpha[0] = 1. - 1.4; |
---|
937 | ene_line[0] = Emin; |
---|
938 | ene_line[1] = Emax; |
---|
939 | } |
---|
940 | if (Emin < 18 * keV && Emax > 18 * keV) { |
---|
941 | omalpha[0] = 1. - 1.4; |
---|
942 | omalpha[1] = 1. - 2.3; |
---|
943 | ene_line[0] = Emin; |
---|
944 | ene_line[1] = 18. * keV; |
---|
945 | ene_line[2] = Emax; |
---|
946 | } |
---|
947 | if (Emin > 18 * keV) { |
---|
948 | omalpha[0] = 1. - 2.3; |
---|
949 | ene_line[0] = Emin; |
---|
950 | ene_line[1] = Emax; |
---|
951 | } |
---|
952 | rndm = eneRndm->GenRandEnergy(); |
---|
953 | rndm2 = eneRndm->GenRandEnergy(); |
---|
954 | |
---|
955 | G4int i = 0; |
---|
956 | while (rndm >= CDGhist[i]) { |
---|
957 | i++; |
---|
958 | } |
---|
959 | // Generate final energy. |
---|
960 | particle_energy = (std::pow(ene_line[i - 1], omalpha[i - 1]) + (std::pow( |
---|
961 | ene_line[i], omalpha[i - 1]) - std::pow(ene_line[i - 1], omalpha[i |
---|
962 | - 1])) * rndm2); |
---|
963 | particle_energy = std::pow(particle_energy, (1. / omalpha[i - 1])); |
---|
964 | |
---|
965 | if (verbosityLevel >= 1) |
---|
966 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
967 | } |
---|
968 | |
---|
969 | void G4SPSEneDistribution::GenUserHistEnergies() { |
---|
970 | // Histograms are DIFFERENTIAL. |
---|
971 | // G4cout << "In GenUserHistEnergies " << G4endl; |
---|
972 | if (IPDFEnergyExist == false) { |
---|
973 | G4int ii; |
---|
974 | G4int maxbin = G4int(UDefEnergyH.GetVectorLength()); |
---|
975 | G4double bins[1024], vals[1024], sum; |
---|
976 | sum = 0.; |
---|
977 | |
---|
978 | if ((EnergySpec == false) && (particle_definition == NULL)) |
---|
979 | G4cout << "Error: particle definition is NULL" << G4endl; |
---|
980 | |
---|
981 | if (maxbin > 1024) { |
---|
982 | G4cout << "Maxbin > 1024" << G4endl; |
---|
983 | G4cout << "Setting maxbin to 1024, other bins are lost" << G4endl; |
---|
984 | } |
---|
985 | |
---|
986 | if (DiffSpec == false) |
---|
987 | G4cout << "Histograms are Differential!!! " << G4endl; |
---|
988 | else { |
---|
989 | bins[0] = UDefEnergyH.GetLowEdgeEnergy(size_t(0)); |
---|
990 | vals[0] = UDefEnergyH(size_t(0)); |
---|
991 | sum = vals[0]; |
---|
992 | for (ii = 1; ii < maxbin; ii++) { |
---|
993 | bins[ii] = UDefEnergyH.GetLowEdgeEnergy(size_t(ii)); |
---|
994 | vals[ii] = UDefEnergyH(size_t(ii)) + vals[ii - 1]; |
---|
995 | sum = sum + UDefEnergyH(size_t(ii)); |
---|
996 | } |
---|
997 | } |
---|
998 | |
---|
999 | if (EnergySpec == false) { |
---|
1000 | G4double mass = particle_definition->GetPDGMass(); |
---|
1001 | // multiply the function (vals) up by the bin width |
---|
1002 | // to make the function counts/s (i.e. get rid of momentum |
---|
1003 | // dependence). |
---|
1004 | for (ii = 1; ii < maxbin; ii++) { |
---|
1005 | vals[ii] = vals[ii] * (bins[ii] - bins[ii - 1]); |
---|
1006 | } |
---|
1007 | // Put energy bins into new histo, plus divide by energy bin width |
---|
1008 | // to make evals counts/s/energy |
---|
1009 | for (ii = 0; ii < maxbin; ii++) { |
---|
1010 | bins[ii] = std::sqrt((bins[ii] * bins[ii]) + (mass * mass)) |
---|
1011 | - mass; //kinetic energy |
---|
1012 | } |
---|
1013 | for (ii = 1; ii < maxbin; ii++) { |
---|
1014 | vals[ii] = vals[ii] / (bins[ii] - bins[ii - 1]); |
---|
1015 | } |
---|
1016 | sum = vals[maxbin - 1]; |
---|
1017 | vals[0] = 0.; |
---|
1018 | } |
---|
1019 | for (ii = 0; ii < maxbin; ii++) { |
---|
1020 | vals[ii] = vals[ii] / sum; |
---|
1021 | IPDFEnergyH.InsertValues(bins[ii], vals[ii]); |
---|
1022 | } |
---|
1023 | |
---|
1024 | // Make IPDFEnergyExist = true |
---|
1025 | IPDFEnergyExist = true; |
---|
1026 | if (verbosityLevel > 1) |
---|
1027 | IPDFEnergyH.DumpValues(); |
---|
1028 | } |
---|
1029 | |
---|
1030 | // IPDF has been create so carry on |
---|
1031 | G4double rndm = eneRndm->GenRandEnergy(); |
---|
1032 | particle_energy = IPDFEnergyH.GetEnergy(rndm); |
---|
1033 | |
---|
1034 | if (verbosityLevel >= 1) |
---|
1035 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
1036 | } |
---|
1037 | |
---|
1038 | void G4SPSEneDistribution::GenArbPointEnergies() { |
---|
1039 | if (verbosityLevel > 0) |
---|
1040 | G4cout << "In GenArbPointEnergies" << G4endl; |
---|
1041 | G4double rndm; |
---|
1042 | rndm = eneRndm->GenRandEnergy(); |
---|
1043 | // IPDFArbEnergyH.DumpValues(); |
---|
1044 | // Find the Bin |
---|
1045 | // have x, y, no of points, and cumulative area distribution |
---|
1046 | G4int nabove, nbelow = 0, middle; |
---|
1047 | nabove = IPDFArbEnergyH.GetVectorLength(); |
---|
1048 | // G4cout << nabove << G4endl; |
---|
1049 | // Binary search to find bin that rndm is in |
---|
1050 | while (nabove - nbelow > 1) { |
---|
1051 | middle = (nabove + nbelow) / 2; |
---|
1052 | if (rndm == IPDFArbEnergyH(size_t(middle))) |
---|
1053 | break; |
---|
1054 | if (rndm < IPDFArbEnergyH(size_t(middle))) |
---|
1055 | nabove = middle; |
---|
1056 | else |
---|
1057 | nbelow = middle; |
---|
1058 | } |
---|
1059 | if (IntType == "Lin") { |
---|
1060 | Emax = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow + 1)); |
---|
1061 | Emin = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow)); |
---|
1062 | grad = Arb_grad[nbelow + 1]; |
---|
1063 | cept = Arb_cept[nbelow + 1]; |
---|
1064 | // G4cout << rndm << " " << Emax << " " << Emin << " " << grad << " " << cept << G4endl; |
---|
1065 | GenerateLinearEnergies(true); |
---|
1066 | } else if (IntType == "Log") { |
---|
1067 | Emax = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow + 1)); |
---|
1068 | Emin = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow)); |
---|
1069 | alpha = Arb_alpha[nbelow + 1]; |
---|
1070 | // G4cout << rndm << " " << Emax << " " << Emin << " " << alpha << G4endl; |
---|
1071 | GeneratePowEnergies(true); |
---|
1072 | } else if (IntType == "Exp") { |
---|
1073 | Emax = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow + 1)); |
---|
1074 | Emin = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow)); |
---|
1075 | Ezero = Arb_ezero[nbelow + 1]; |
---|
1076 | // G4cout << rndm << " " << Emax << " " << Emin << " " << Ezero << G4endl; |
---|
1077 | GenerateExpEnergies(true); |
---|
1078 | } else if (IntType == "Spline") { |
---|
1079 | Emax = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow + 1)); |
---|
1080 | Emin = IPDFArbEnergyH.GetLowEdgeEnergy(size_t(nbelow)); |
---|
1081 | particle_energy = -1e100; |
---|
1082 | rndm = eneRndm->GenRandEnergy(); |
---|
1083 | while (particle_energy < Emin || particle_energy > Emax) { |
---|
1084 | particle_energy = SplineInt[nbelow+1]->CubicSplineInterpolation(rndm); |
---|
1085 | rndm = eneRndm->GenRandEnergy(); |
---|
1086 | } |
---|
1087 | if (verbosityLevel >= 1) |
---|
1088 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
1089 | } else |
---|
1090 | G4cout << "Error: IntType unknown type" << G4endl; |
---|
1091 | } |
---|
1092 | |
---|
1093 | void G4SPSEneDistribution::GenEpnHistEnergies() { |
---|
1094 | // G4cout << "In GenEpnHistEnergies " << Epnflag << G4endl; |
---|
1095 | |
---|
1096 | // Firstly convert to energy if not already done. |
---|
1097 | if (Epnflag == true) |
---|
1098 | // epnflag = true means spectrum is epn, false means e. |
---|
1099 | { |
---|
1100 | // convert to energy by multiplying by A number |
---|
1101 | ConvertEPNToEnergy(); |
---|
1102 | // EpnEnergyH will be replace by UDefEnergyH. |
---|
1103 | // UDefEnergyH.DumpValues(); |
---|
1104 | } |
---|
1105 | |
---|
1106 | // G4cout << "Creating IPDFEnergy if not already done so" << G4endl; |
---|
1107 | if (IPDFEnergyExist == false) { |
---|
1108 | // IPDF has not been created, so create it |
---|
1109 | G4double bins[1024], vals[1024], sum; |
---|
1110 | G4int ii; |
---|
1111 | G4int maxbin = G4int(UDefEnergyH.GetVectorLength()); |
---|
1112 | bins[0] = UDefEnergyH.GetLowEdgeEnergy(size_t(0)); |
---|
1113 | vals[0] = UDefEnergyH(size_t(0)); |
---|
1114 | sum = vals[0]; |
---|
1115 | for (ii = 1; ii < maxbin; ii++) { |
---|
1116 | bins[ii] = UDefEnergyH.GetLowEdgeEnergy(size_t(ii)); |
---|
1117 | vals[ii] = UDefEnergyH(size_t(ii)) + vals[ii - 1]; |
---|
1118 | sum = sum + UDefEnergyH(size_t(ii)); |
---|
1119 | } |
---|
1120 | |
---|
1121 | for (ii = 0; ii < maxbin; ii++) { |
---|
1122 | vals[ii] = vals[ii] / sum; |
---|
1123 | IPDFEnergyH.InsertValues(bins[ii], vals[ii]); |
---|
1124 | } |
---|
1125 | // Make IPDFEpnExist = true |
---|
1126 | IPDFEnergyExist = true; |
---|
1127 | } |
---|
1128 | // IPDFEnergyH.DumpValues(); |
---|
1129 | // IPDF has been create so carry on |
---|
1130 | G4double rndm = eneRndm->GenRandEnergy(); |
---|
1131 | particle_energy = IPDFEnergyH.GetEnergy(rndm); |
---|
1132 | |
---|
1133 | if (verbosityLevel >= 1) |
---|
1134 | G4cout << "Energy is " << particle_energy << G4endl; |
---|
1135 | } |
---|
1136 | |
---|
1137 | void G4SPSEneDistribution::ConvertEPNToEnergy() { |
---|
1138 | // Use this before particle generation to convert the |
---|
1139 | // currently stored histogram from energy/nucleon |
---|
1140 | // to energy. |
---|
1141 | // G4cout << "In ConvertEpntoEnergy " << G4endl; |
---|
1142 | if (particle_definition == NULL) |
---|
1143 | G4cout << "Error: particle not defined" << G4endl; |
---|
1144 | else { |
---|
1145 | // Need to multiply histogram by the number of nucleons. |
---|
1146 | // Baryon Number looks to hold the no. of nucleons. |
---|
1147 | G4int Bary = particle_definition->GetBaryonNumber(); |
---|
1148 | // G4cout << "Baryon No. " << Bary << G4endl; |
---|
1149 | // Change values in histogram, Read it out, delete it, re-create it |
---|
1150 | G4int count, maxcount; |
---|
1151 | maxcount = G4int(EpnEnergyH.GetVectorLength()); |
---|
1152 | // G4cout << maxcount << G4endl; |
---|
1153 | G4double ebins[1024], evals[1024]; |
---|
1154 | if (maxcount > 1024) { |
---|
1155 | G4cout << "Histogram contains more than 1024 bins!" << G4endl; |
---|
1156 | G4cout << "Those above 1024 will be ignored" << G4endl; |
---|
1157 | maxcount = 1024; |
---|
1158 | } |
---|
1159 | if (maxcount < 1) { |
---|
1160 | G4cout << "Histogram contains less than 1 bin!" << G4endl; |
---|
1161 | G4cout << "Redefine the histogram" << G4endl; |
---|
1162 | return; |
---|
1163 | } |
---|
1164 | for (count = 0; count < maxcount; count++) { |
---|
1165 | // Read out |
---|
1166 | ebins[count] = EpnEnergyH.GetLowEdgeEnergy(size_t(count)); |
---|
1167 | evals[count] = EpnEnergyH(size_t(count)); |
---|
1168 | } |
---|
1169 | |
---|
1170 | // Multiply the channels by the nucleon number to give energies |
---|
1171 | for (count = 0; count < maxcount; count++) { |
---|
1172 | ebins[count] = ebins[count] * Bary; |
---|
1173 | } |
---|
1174 | |
---|
1175 | // Set Emin and Emax |
---|
1176 | Emin = ebins[0]; |
---|
1177 | if (maxcount > 1) |
---|
1178 | Emax = ebins[maxcount - 1]; |
---|
1179 | else |
---|
1180 | Emax = ebins[0]; |
---|
1181 | // Put energy bins into new histogram - UDefEnergyH. |
---|
1182 | for (count = 0; count < maxcount; count++) { |
---|
1183 | UDefEnergyH.InsertValues(ebins[count], evals[count]); |
---|
1184 | } |
---|
1185 | Epnflag = false; //so that you dont repeat this method. |
---|
1186 | } |
---|
1187 | } |
---|
1188 | |
---|
1189 | // |
---|
1190 | void G4SPSEneDistribution::ReSetHist(G4String atype) { |
---|
1191 | if (atype == "energy") { |
---|
1192 | UDefEnergyH = IPDFEnergyH = ZeroPhysVector; |
---|
1193 | IPDFEnergyExist = false; |
---|
1194 | Emin = 0.; |
---|
1195 | Emax = 1e30; |
---|
1196 | } else if (atype == "arb") { |
---|
1197 | ArbEnergyH = IPDFArbEnergyH = ZeroPhysVector; |
---|
1198 | IPDFArbExist = false; |
---|
1199 | } else if (atype == "epn") { |
---|
1200 | UDefEnergyH = IPDFEnergyH = ZeroPhysVector; |
---|
1201 | IPDFEnergyExist = false; |
---|
1202 | EpnEnergyH = ZeroPhysVector; |
---|
1203 | } else { |
---|
1204 | G4cout << "Error, histtype not accepted " << G4endl; |
---|
1205 | } |
---|
1206 | } |
---|
1207 | |
---|
1208 | G4double G4SPSEneDistribution::GenerateOne(G4ParticleDefinition* a) { |
---|
1209 | particle_definition = a; |
---|
1210 | particle_energy = -1.; |
---|
1211 | |
---|
1212 | while ((EnergyDisType == "Arb") ? (particle_energy < ArbEmin |
---|
1213 | || particle_energy > ArbEmax) : (particle_energy < Emin |
---|
1214 | || particle_energy > Emax)) { |
---|
1215 | if (Biased) { |
---|
1216 | GenerateBiasPowEnergies(); |
---|
1217 | } else { |
---|
1218 | if (EnergyDisType == "Mono") |
---|
1219 | GenerateMonoEnergetic(); |
---|
1220 | else if (EnergyDisType == "Lin") |
---|
1221 | GenerateLinearEnergies(); |
---|
1222 | else if (EnergyDisType == "Pow") |
---|
1223 | GeneratePowEnergies(); |
---|
1224 | else if (EnergyDisType == "Exp") |
---|
1225 | GenerateExpEnergies(); |
---|
1226 | else if (EnergyDisType == "Gauss") |
---|
1227 | GenerateGaussEnergies(); |
---|
1228 | else if (EnergyDisType == "Brem") |
---|
1229 | GenerateBremEnergies(); |
---|
1230 | else if (EnergyDisType == "Bbody") |
---|
1231 | GenerateBbodyEnergies(); |
---|
1232 | else if (EnergyDisType == "Cdg") |
---|
1233 | GenerateCdgEnergies(); |
---|
1234 | else if (EnergyDisType == "User") |
---|
1235 | GenUserHistEnergies(); |
---|
1236 | else if (EnergyDisType == "Arb") |
---|
1237 | GenArbPointEnergies(); |
---|
1238 | else if (EnergyDisType == "Epn") |
---|
1239 | GenEpnHistEnergies(); |
---|
1240 | else |
---|
1241 | G4cout << "Error: EnergyDisType has unusual value" << G4endl; |
---|
1242 | } |
---|
1243 | } |
---|
1244 | return particle_energy; |
---|
1245 | } |
---|
1246 | |
---|
1247 | G4double G4SPSEneDistribution::GetProbability(G4double ene) { |
---|
1248 | G4double prob = 1.; |
---|
1249 | |
---|
1250 | if (EnergyDisType == "Lin") { |
---|
1251 | if (prob_norm == 1.) { |
---|
1252 | prob_norm = 0.5*grad*Emax*Emax + cept*Emax - 0.5*grad*Emin*Emin - cept*Emin; |
---|
1253 | } |
---|
1254 | prob = cept + grad * ene; |
---|
1255 | prob /= prob_norm; |
---|
1256 | } |
---|
1257 | else if (EnergyDisType == "Pow") { |
---|
1258 | if (prob_norm == 1.) { |
---|
1259 | if (alpha != -1.) { |
---|
1260 | G4double emina = std::pow(Emin, alpha + 1); |
---|
1261 | G4double emaxa = std::pow(Emax, alpha + 1); |
---|
1262 | prob_norm = 1./(1.+alpha) * (emaxa - emina); |
---|
1263 | } else { |
---|
1264 | prob_norm = std::log(Emax) - std::log(Emin) ; |
---|
1265 | } |
---|
1266 | } |
---|
1267 | prob = std::pow(ene, alpha)/prob_norm; |
---|
1268 | } |
---|
1269 | else if (EnergyDisType == "Exp"){ |
---|
1270 | if (prob_norm == 1.) { |
---|
1271 | prob_norm = -Ezero*(std::exp(-Emax/Ezero) - std::exp(Emin/Ezero)); |
---|
1272 | } |
---|
1273 | prob = std::exp(-ene / Ezero); |
---|
1274 | prob /= prob_norm; |
---|
1275 | } |
---|
1276 | else if (EnergyDisType == "Arb") { |
---|
1277 | prob = ArbEnergyH.Value(ene); |
---|
1278 | // prob = ArbEInt->CubicSplineInterpolation(ene); |
---|
1279 | //G4double deltaY; |
---|
1280 | //prob = ArbEInt->PolynomInterpolation(ene, deltaY); |
---|
1281 | if (prob <= 0.) { |
---|
1282 | //G4cout << " Warning:G4SPSEneDistribution::GetProbability: prob<= 0. "<<prob <<" "<<ene << " " <<deltaY<< G4endl; |
---|
1283 | G4cout << " Warning:G4SPSEneDistribution::GetProbability: prob<= 0. "<<prob <<" "<<ene << G4endl; |
---|
1284 | prob = 1e-30; |
---|
1285 | } |
---|
1286 | // already normalised |
---|
1287 | } |
---|
1288 | else |
---|
1289 | G4cout << "Error: EnergyDisType not supported" << G4endl; |
---|
1290 | |
---|
1291 | return prob; |
---|
1292 | } |
---|