Line data Source code
1 : #include "crpropa/Candidate.h"
2 : #include "crpropa/Units.h"
3 : #include "crpropa/ParticleID.h"
4 : #include "crpropa/PhotonBackground.h"
5 : #include "crpropa/module/ElectronPairProduction.h"
6 : #include "crpropa/module/NuclearDecay.h"
7 : #include "crpropa/module/PhotoDisintegration.h"
8 : #include "crpropa/module/ElasticScattering.h"
9 : #include "crpropa/module/PhotoPionProduction.h"
10 : #include "crpropa/module/Redshift.h"
11 : #include "crpropa/module/EMPairProduction.h"
12 : #include "crpropa/module/EMDoublePairProduction.h"
13 : #include "crpropa/module/EMTripletPairProduction.h"
14 : #include "crpropa/module/EMInverseComptonScattering.h"
15 : #include "crpropa/module/SynchrotronRadiation.h"
16 : #include "gtest/gtest.h"
17 :
18 : #include <fstream>
19 :
20 : namespace crpropa {
21 :
22 : // ElectronPairProduction -----------------------------------------------------
23 1 : TEST(ElectronPairProduction, allBackgrounds) {
24 : // Test if interaction data files are loaded.
25 1 : ref_ptr<PhotonField> cmb = new CMB();
26 1 : ElectronPairProduction epp(cmb);
27 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
28 1 : epp.setPhotonField(irb);
29 2 : irb = new IRB_Stecker05();
30 1 : epp.setPhotonField(irb);
31 2 : irb = new IRB_Franceschini08();
32 1 : epp.setPhotonField(irb);
33 2 : irb = new IRB_Finke10();
34 1 : epp.setPhotonField(irb);
35 2 : irb = new IRB_Dominguez11();
36 1 : epp.setPhotonField(irb);
37 2 : irb = new IRB_Gilmore12();
38 1 : epp.setPhotonField(irb);
39 2 : irb = new IRB_Stecker16_upper();
40 1 : epp.setPhotonField(irb);
41 2 : irb = new IRB_Stecker16_lower();
42 1 : epp.setPhotonField(irb);
43 2 : irb = new IRB_Finke22();
44 2 : epp.setPhotonField(irb);
45 2 : }
46 :
47 1 : TEST(ElectronPairProduction, energyDecreasing) {
48 : // Test if energy loss occurs for protons with energies from 1e15 - 1e23 eV.
49 1 : Candidate c;
50 1 : c.setCurrentStep(2 * Mpc);
51 1 : c.current.setId(nucleusId(1, 1)); // proton
52 :
53 1 : ref_ptr<PhotonField> cmb = new CMB();
54 1 : ElectronPairProduction epp1(cmb);
55 81 : for (int i = 0; i < 80; i++) {
56 80 : double E = pow(10, 15 + i * 0.1) * eV;
57 80 : c.current.setEnergy(E);
58 80 : epp1.process(&c);
59 80 : EXPECT_LE(c.current.getEnergy(), E);
60 : }
61 :
62 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
63 2 : ElectronPairProduction epp2(irb);
64 81 : for (int i = 0; i < 80; i++) {
65 80 : double E = pow(10, 15 + i * 0.1) * eV;
66 80 : c.current.setEnergy(E);
67 80 : epp2.process(&c);
68 80 : EXPECT_LE(c.current.getEnergy(), E);
69 : }
70 2 : }
71 :
72 1 : TEST(ElectronPairProduction, belowEnergyTreshold) {
73 : // Test if nothing happens below 1e15 eV.
74 1 : ref_ptr<PhotonField> cmb = new CMB();
75 1 : ElectronPairProduction epp(cmb);
76 1 : Candidate c(nucleusId(1, 1), 1E14 * eV);
77 1 : epp.process(&c);
78 1 : EXPECT_DOUBLE_EQ(1E14 * eV, c.current.getEnergy());
79 2 : }
80 :
81 1 : TEST(ElectronPairProduction, thisIsNotNucleonic) {
82 : // Test if non-nuclei are skipped.
83 1 : ref_ptr<PhotonField> cmb = new CMB();
84 1 : ElectronPairProduction epp(cmb);
85 1 : Candidate c(11, 1E20 * eV); // electron
86 1 : epp.process(&c);
87 1 : EXPECT_DOUBLE_EQ(1E20 * eV, c.current.getEnergy());
88 2 : }
89 :
90 2 : TEST(ElectronPairProduction, valuesCMB) {
91 : // Test if energy loss corresponds to the data table.
92 : std::vector<double> x;
93 : std::vector<double> y;
94 2 : std::ifstream infile(getDataPath("pair_CMB.txt").c_str());
95 1 : while (infile.good()) {
96 0 : if (infile.peek() != '#') {
97 : double a, b;
98 : infile >> a >> b;
99 0 : if (infile) {
100 0 : x.push_back(a * eV);
101 0 : y.push_back(b * eV / Mpc);
102 : }
103 : }
104 0 : infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
105 : }
106 1 : infile.close();
107 :
108 1 : Candidate c;
109 1 : c.setCurrentStep(1 * Mpc);
110 1 : c.current.setId(nucleusId(1, 1)); // proton
111 1 : ref_ptr<PhotonField> cmb = new CMB();
112 :
113 1 : ElectronPairProduction epp(cmb);
114 1 : for (int i = 0; i < x.size(); i++) {
115 0 : c.current.setEnergy(x[i]);
116 0 : epp.process(&c);
117 0 : double dE = x[i] - c.current.getEnergy();
118 0 : double dE_table = y[i] * 1 * Mpc;
119 0 : EXPECT_NEAR(dE_table, dE, 1e-12);
120 : }
121 3 : }
122 :
123 1 : TEST(ElectronPairProduction, interactionTag) {
124 :
125 1 : ref_ptr<PhotonField> cmb = new CMB();
126 0 : ElectronPairProduction epp(cmb);
127 :
128 : // test the default interaction tag
129 2 : EXPECT_TRUE(epp.getInteractionTag() == "EPP");
130 :
131 : // test changing the interaction tag
132 1 : epp.setInteractionTag("myTag");
133 2 : EXPECT_TRUE(epp.getInteractionTag() == "myTag");
134 :
135 : // test the tag of produced secondaries
136 2 : Candidate c;
137 1 : c.setCurrentStep(1 * Gpc);
138 1 : c.current.setId(nucleusId(1,1));
139 1 : c.current.setEnergy(100 * EeV);
140 1 : epp.setHaveElectrons(true);
141 1 : epp.process(&c);
142 :
143 1 : std::string secondaryTag = c.secondaries[0] -> getTagOrigin();
144 1 : EXPECT_TRUE(secondaryTag == "myTag");
145 2 : }
146 :
147 2 : TEST(ElectronPairProduction, valuesIRB) {
148 : // Test if energy loss corresponds to the data table.
149 : std::vector<double> x;
150 : std::vector<double> y;
151 2 : std::ifstream infile(getDataPath("pairIRB.txt").c_str());
152 1 : while (infile.good()) {
153 0 : if (infile.peek() != '#') {
154 : double a, b;
155 : infile >> a >> b;
156 0 : if (infile) {
157 0 : x.push_back(a * eV);
158 0 : y.push_back(b * eV / Mpc);
159 : }
160 : }
161 0 : infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
162 : }
163 1 : infile.close();
164 :
165 1 : Candidate c;
166 1 : c.setCurrentStep(1 * Mpc);
167 1 : c.current.setId(nucleusId(1, 1)); // proton
168 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
169 :
170 1 : ElectronPairProduction epp(irb);
171 1 : for (int i = 0; i < x.size(); i++) {
172 0 : c.current.setEnergy(x[i]);
173 0 : epp.process(&c);
174 0 : double dE = x[i] - c.current.getEnergy();
175 0 : double dE_table = y[i] * 1 * Mpc;
176 0 : EXPECT_NEAR(dE, dE_table, 1e-12);
177 : }
178 3 : }
179 :
180 : // NuclearDecay ---------------------------------------------------------------
181 1 : TEST(NuclearDecay, scandium44) {
182 : // Test beta+ decay of 44Sc to 44Ca.
183 : // This test can stochastically fail.
184 1 : NuclearDecay d(true, true);
185 1 : Candidate c(nucleusId(44, 21), 1E18 * eV);
186 1 : c.setCurrentStep(100 * Mpc);
187 1 : double gamma = c.current.getLorentzFactor();
188 1 : d.process(&c);
189 :
190 : // expected decay product: 44Ca
191 1 : EXPECT_EQ(nucleusId(44, 20), c.current.getId());
192 :
193 : // expect Lorentz factor to be conserved
194 1 : EXPECT_DOUBLE_EQ(gamma, c.current.getLorentzFactor());
195 :
196 : // expect at least two secondaries: positron + electron neutrino
197 1 : EXPECT_GE(c.secondaries.size(), 2);
198 1 : }
199 :
200 1 : TEST(NuclearDecay, lithium4) {
201 : // Test proton dripping of Li-4 to He-3
202 : // This test can stochastically fail
203 1 : NuclearDecay d;
204 1 : Candidate c(nucleusId(4, 3), 4 * EeV);
205 1 : c.setCurrentStep(100 * Mpc);
206 1 : d.process(&c);
207 :
208 : // expected decay product: He-3
209 1 : EXPECT_EQ(nucleusId(3, 2), c.current.getId());
210 :
211 : // expected secondary: proton
212 1 : EXPECT_EQ(1, c.secondaries.size());
213 2 : Candidate c1 = *c.secondaries[0];
214 1 : EXPECT_EQ(nucleusId(1, 1), c1.current.getId());
215 1 : EXPECT_EQ(1 * EeV, c1.current.getEnergy());
216 1 : }
217 :
218 1 : TEST(NuclearDecay, helium5) {
219 : // Test neutron dripping of He-5 to He-4.
220 : // This test can stochastically fail.
221 1 : NuclearDecay d;
222 1 : Candidate c(nucleusId(5, 2), 5 * EeV);
223 1 : c.setCurrentStep(100 * Mpc);
224 1 : d.process(&c);
225 :
226 : // expected primary: He-4
227 1 : EXPECT_EQ(nucleusId(4, 2), c.current.getId());
228 1 : EXPECT_EQ(4, c.current.getEnergy() / EeV);
229 :
230 : // expected secondary: neutron
231 2 : Candidate c2 = *c.secondaries[0];
232 1 : EXPECT_EQ(nucleusId(1, 0), c2.current.getId());
233 1 : EXPECT_EQ(1, c2.current.getEnergy() / EeV);
234 1 : }
235 :
236 1 : TEST(NuclearDecay, limitNextStep) {
237 : // Test if next step is limited in case of a neutron.
238 1 : NuclearDecay decay;
239 1 : Candidate c(nucleusId(1, 0), 10 * EeV);
240 1 : c.setNextStep(std::numeric_limits<double>::max());
241 1 : decay.process(&c);
242 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
243 1 : }
244 :
245 1 : TEST(NuclearDecay, allChannelsWorking) {
246 : // Test if all nuclear decays are working.
247 1 : NuclearDecay d;
248 1 : Candidate c;
249 :
250 2 : std::ifstream infile(getDataPath("nuclear_decay.txt").c_str());
251 951 : while (infile.good()) {
252 950 : if (infile.peek() != '#') {
253 : int Z, N, channel, foo;
254 948 : infile >> Z >> N >> channel >> foo;
255 948 : c.current.setId(nucleusId(Z + N, Z));
256 948 : c.current.setEnergy(80 * EeV);
257 948 : d.performInteraction(&c, channel);
258 : }
259 950 : infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
260 : }
261 1 : infile.close();
262 1 : }
263 :
264 1 : TEST(NuclearDecay, secondaries) {
265 : // Test if all types of secondaries are produced.
266 1 : NuclearDecay d;
267 1 : d.setHaveElectrons(true);
268 1 : d.setHaveNeutrinos(true);
269 1 : d.setHavePhotons(true);
270 1 : Candidate c;
271 :
272 : // He-8 --> Li-8 + e- + neutrino
273 : // additional photon emitted with 84% probability
274 : // --> expect at least 1 photon out of 10 decays
275 11 : for (int i = 0; i < 10; ++i) {
276 10 : c.current.setId(nucleusId(8, 2));
277 10 : c.current.setEnergy(5 * EeV);
278 10 : d.performInteraction(&c, 10000);
279 : }
280 :
281 : // count number of secondaries
282 1 : size_t nElectrons = 0;
283 1 : size_t nNeutrinos = 0;
284 1 : size_t nPhotons = 0;
285 :
286 28 : for(size_t i = 0; i < c.secondaries.size(); ++i) {
287 27 : int id = (*c.secondaries[i]).current.getId();
288 27 : if (id == 22) nPhotons++;
289 27 : if (id == 11) nElectrons++;
290 27 : if (id == -12) nNeutrinos++;
291 : }
292 :
293 1 : EXPECT_EQ(nElectrons, 10);
294 1 : EXPECT_EQ(nNeutrinos, 10);
295 1 : EXPECT_GE(nPhotons, 1);
296 1 : }
297 :
298 1 : TEST(NuclearDecay, thisIsNotNucleonic) {
299 : // Test if nothing happens to an electron
300 1 : NuclearDecay decay;
301 1 : Candidate c(11, 10 * EeV);
302 1 : c.setNextStep(std::numeric_limits<double>::max());
303 1 : decay.process(&c);
304 1 : EXPECT_EQ(11, c.current.getId());
305 1 : EXPECT_EQ(10 * EeV, c.current.getEnergy());
306 1 : }
307 :
308 1 : TEST(NuclearDecay, interactionTag) {
309 : // test default interaction tag
310 1 : NuclearDecay decay;
311 2 : EXPECT_TRUE(decay.getInteractionTag() == "ND");
312 :
313 : // test secondary tag
314 1 : decay.setHaveElectrons(true);
315 2 : Candidate c(nucleusId(8,2), 5 * EeV);
316 1 : decay.performInteraction(&c, 10000);
317 3 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "ND");
318 :
319 : // test custom tags
320 1 : decay.setInteractionTag("myTag");
321 2 : EXPECT_TRUE(decay.getInteractionTag() == "myTag");
322 1 : }
323 :
324 : // PhotoDisintegration --------------------------------------------------------
325 1 : TEST(PhotoDisintegration, allBackgrounds) {
326 : // Test if interaction data files are loaded.
327 1 : ref_ptr<PhotonField> cmb = new CMB();
328 1 : PhotoDisintegration pd(cmb);
329 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
330 1 : pd.setPhotonField(irb);
331 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
332 1 : pd.setPhotonField(urb);
333 2 : irb = new IRB_Stecker05();
334 1 : pd.setPhotonField(irb);
335 2 : irb = new IRB_Franceschini08();
336 1 : pd.setPhotonField(irb);
337 2 : irb = new IRB_Finke10();
338 1 : pd.setPhotonField(irb);
339 2 : irb = new IRB_Dominguez11();
340 1 : pd.setPhotonField(irb);
341 2 : irb = new IRB_Gilmore12();
342 1 : pd.setPhotonField(irb);
343 2 : irb = new IRB_Stecker16_upper();
344 1 : pd.setPhotonField(irb);
345 2 : irb = new IRB_Stecker16_lower();
346 1 : pd.setPhotonField(irb);
347 2 : irb = new IRB_Finke22();
348 1 : pd.setPhotonField(irb);
349 2 : urb = new URB_Nitu21();
350 2 : pd.setPhotonField(urb);
351 2 : }
352 :
353 1 : TEST(PhotoDisintegration, carbon) {
354 : // Test if a 100 EeV C-12 nucleus photo-disintegrates (at least once) over a distance of 1 Gpc.
355 : // This test can stochastically fail.
356 1 : ref_ptr<PhotonField> cmb = new CMB();
357 1 : PhotoDisintegration pd(cmb);
358 1 : Candidate c;
359 1 : int id = nucleusId(12, 6);
360 1 : c.current.setId(id);
361 1 : c.current.setEnergy(100 * EeV);
362 1 : c.setCurrentStep(1000 * Mpc);
363 1 : pd.process(&c);
364 :
365 1 : EXPECT_TRUE(c.current.getEnergy() < 100 * EeV);
366 : // energy loss
367 1 : EXPECT_TRUE(c.secondaries.size() > 0);
368 : // secondaries produced
369 :
370 1 : double E = c.current.getEnergy();
371 1 : id = c.current.getId();
372 1 : int A = massNumber(id);
373 1 : int Z = chargeNumber(id);
374 :
375 9 : for (int i = 0; i < c.secondaries.size(); i++) {
376 8 : E += (*c.secondaries[i]).current.getEnergy();
377 8 : id = (*c.secondaries[i]).current.getId();
378 8 : A += massNumber(id);
379 8 : Z += chargeNumber(id);
380 : }
381 1 : EXPECT_EQ(12, A);
382 : // nucleon number conserved
383 1 : EXPECT_EQ(6, Z);
384 : // proton number conserved
385 1 : EXPECT_DOUBLE_EQ(100 * EeV, E);
386 : // energy conserved
387 2 : }
388 :
389 1 : TEST(PhotoDisintegration, iron) {
390 : // Test if a 200 EeV Fe-56 nucleus photo-disintegrates (at least once) over a distance of 1 Gpc.
391 : // This test can stochastically fail.
392 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
393 1 : PhotoDisintegration pd(irb);
394 1 : Candidate c;
395 1 : int id = nucleusId(56, 26);
396 1 : c.current.setId(id);
397 1 : c.current.setEnergy(200 * EeV);
398 1 : c.setCurrentStep(1000 * Mpc);
399 1 : pd.process(&c);
400 :
401 : // expect energy loss
402 1 : EXPECT_TRUE(c.current.getEnergy() < 200 * EeV);
403 :
404 : // expect secondaries produced
405 1 : EXPECT_TRUE(c.secondaries.size() > 0);
406 :
407 1 : double E = c.current.getEnergy();
408 1 : id = c.current.getId();
409 1 : int A = massNumber(id);
410 1 : int Z = chargeNumber(id);
411 :
412 40 : for (int i = 0; i < c.secondaries.size(); i++) {
413 39 : E += (*c.secondaries[i]).current.getEnergy();
414 39 : id = (*c.secondaries[i]).current.getId();
415 39 : A += massNumber(id);
416 39 : Z += chargeNumber(id);
417 : }
418 :
419 : // nucleon number conserved
420 1 : EXPECT_EQ(56, A);
421 :
422 : // proton number conserved (no decay active)
423 1 : EXPECT_EQ(26, Z);
424 :
425 : // energy conserved
426 1 : EXPECT_DOUBLE_EQ(200 * EeV, E);
427 2 : }
428 :
429 1 : TEST(PhotoDisintegration, thisIsNotNucleonic) {
430 : // Test that nothing happens to an electron.
431 1 : ref_ptr<PhotonField> cmb = new CMB();
432 1 : PhotoDisintegration pd(cmb);
433 1 : Candidate c;
434 1 : c.setCurrentStep(1 * Mpc);
435 1 : c.current.setId(11); // electron
436 1 : c.current.setEnergy(10 * EeV);
437 1 : pd.process(&c);
438 1 : EXPECT_EQ(11, c.current.getId());
439 1 : EXPECT_EQ(10 * EeV, c.current.getEnergy());
440 2 : }
441 :
442 1 : TEST(PhotoDisintegration, limitNextStep) {
443 : // Test if the interaction limits the next propagation step.
444 1 : ref_ptr<PhotonField> cmb = new CMB();
445 1 : PhotoDisintegration pd(cmb);
446 1 : Candidate c;
447 1 : c.setNextStep(std::numeric_limits<double>::max());
448 1 : c.current.setId(nucleusId(4, 2));
449 1 : c.current.setEnergy(200 * EeV);
450 1 : pd.process(&c);
451 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
452 2 : }
453 :
454 1 : TEST(PhotoDisintegration, allIsotopes) {
455 : // Test if all isotopes are handled.
456 1 : ref_ptr<PhotonField> cmb = new CMB();
457 1 : PhotoDisintegration pd1(cmb);
458 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
459 1 : PhotoDisintegration pd2(irb);
460 1 : Candidate c;
461 1 : c.setCurrentStep(10 * Mpc);
462 :
463 27 : for (int Z = 1; Z <= 26; Z++) {
464 806 : for (int N = 1; N <= 30; N++) {
465 :
466 780 : c.current.setId(nucleusId(Z + N, Z));
467 780 : c.current.setEnergy(80 * EeV);
468 780 : pd1.process(&c);
469 :
470 780 : c.current.setId(nucleusId(Z + N, Z));
471 780 : c.current.setEnergy(80 * EeV);
472 780 : pd2.process(&c);
473 : }
474 : }
475 3 : }
476 :
477 1 : TEST(Photodisintegration, updateParticleParentProperties) { // Issue: #204
478 1 : ref_ptr<PhotonField> cmb = new CMB();
479 1 : PhotoDisintegration pd(cmb);
480 :
481 1 : Candidate c(nucleusId(56,26), 500 * EeV, Vector3d(1 * Mpc, 0, 0));
482 :
483 1 : pd.performInteraction(&c, 1);
484 : // the candidates parent is the original particle
485 1 : EXPECT_EQ(c.created.getId(), nucleusId(56,26));
486 :
487 1 : pd.performInteraction(&c, 1);
488 : // now it has to be changed
489 1 : EXPECT_NE(c.created.getId(), nucleusId(56,26));
490 2 : }
491 :
492 1 : TEST(PhotoDisintegration, interactionTag) {
493 2 : PhotoDisintegration pd(new CMB());
494 :
495 : // test default interactionTag
496 2 : EXPECT_TRUE(pd.getInteractionTag() == "PD");
497 :
498 : // test secondary tag
499 1 : pd.setHavePhotons(true);
500 2 : Candidate c(nucleusId(56,26), 500 * EeV);
501 1 : c.setCurrentStep(1 * Gpc);
502 1 : pd.process(&c);
503 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "PD");
504 :
505 : // test custom tag
506 1 : pd.setInteractionTag("myTag");
507 2 : EXPECT_TRUE(pd.getInteractionTag() == "myTag");
508 1 : }
509 :
510 : // ElasticScattering ----------------------------------------------------------
511 1 : TEST(ElasticScattering, allBackgrounds) {
512 : // Test if interaction data files are loaded.
513 1 : ref_ptr<PhotonField> cmb = new CMB();
514 1 : ElasticScattering scattering(cmb);
515 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
516 1 : scattering.setPhotonField(irb);
517 1 : ref_ptr<PhotonField> urb = new URB_Nitu21();
518 2 : scattering.setPhotonField(urb);
519 2 : }
520 :
521 1 : TEST(ElasticScattering, secondaries) {
522 : // Test the creation of cosmic ray photons.
523 : // This test can stochastically fail.
524 1 : ref_ptr<PhotonField> cmb = new CMB();
525 1 : ElasticScattering scattering(cmb);
526 1 : Candidate c;
527 1 : int id = nucleusId(12, 6);
528 1 : c.current.setId(id);
529 1 : c.current.setEnergy(200 * EeV);
530 1 : c.setCurrentStep(400 * Mpc);
531 1 : scattering.process(&c);
532 :
533 1 : EXPECT_GT(c.secondaries.size(), 0);
534 :
535 7 : for (int i = 0; i < c.secondaries.size(); i++) {
536 6 : int id = (*c.secondaries[i]).current.getId();
537 6 : EXPECT_EQ(id, 22);
538 6 : double energy = (*c.secondaries[i]).current.getEnergy();
539 6 : EXPECT_GT(energy, 0);
540 6 : EXPECT_LT(energy, 200 * EeV);
541 : }
542 2 : }
543 :
544 : // PhotoPionProduction --------------------------------------------------------
545 1 : TEST(PhotoPionProduction, allBackgrounds) {
546 : // Test if all interaction data files can be loaded.
547 1 : ref_ptr<PhotonField> cmb = new CMB();
548 1 : PhotoPionProduction ppp(cmb);
549 1 : ref_ptr<PhotonField> irb = new IRB_Kneiske04();
550 1 : ppp.setPhotonField(irb);
551 2 : irb = new IRB_Stecker05();
552 1 : ppp.setPhotonField(irb);
553 2 : irb = new IRB_Franceschini08();
554 1 : ppp.setPhotonField(irb);
555 2 : irb = new IRB_Finke10();
556 1 : ppp.setPhotonField(irb);
557 2 : irb = new IRB_Dominguez11();
558 1 : ppp.setPhotonField(irb);
559 2 : irb = new IRB_Gilmore12();
560 1 : ppp.setPhotonField(irb);
561 2 : irb = new IRB_Stecker16_upper();
562 1 : ppp.setPhotonField(irb);
563 2 : irb = new IRB_Stecker16_lower();
564 1 : ppp.setPhotonField(irb);
565 2 : irb = new IRB_Finke22();
566 1 : ppp.setPhotonField(irb);
567 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
568 1 : ppp.setPhotonField(urb);
569 2 : urb = new URB_Nitu21();
570 2 : ppp.setPhotonField(urb);
571 2 : }
572 :
573 1 : TEST(PhotoPionProduction, proton) {
574 : // Test photopion interaction for 100 EeV proton.
575 : // This test can stochastically fail.
576 1 : ref_ptr<PhotonField> cmb = new CMB();
577 1 : PhotoPionProduction ppp(cmb);
578 1 : Candidate c(nucleusId(1, 1), 100 * EeV);
579 1 : c.setCurrentStep(1000 * Mpc);
580 1 : ppp.process(&c);
581 :
582 : // expect energy loss
583 1 : EXPECT_LT(c.current.getEnergy(), 100. * EeV);
584 :
585 : // expect nucleon number conservation
586 1 : EXPECT_EQ(1, massNumber(c.current.getId()));
587 :
588 : // expect no (nucleonic) secondaries
589 1 : EXPECT_EQ(0, c.secondaries.size());
590 2 : }
591 :
592 1 : TEST(PhotoPionProduction, helium) {
593 : // Test photo-pion interaction for 400 EeV He nucleus.
594 : // This test can stochastically fail.
595 1 : ref_ptr<PhotonField> cmb = new CMB();
596 1 : PhotoPionProduction ppp(cmb);
597 1 : Candidate c;
598 1 : c.current.setId(nucleusId(4, 2));
599 1 : c.current.setEnergy(400. * EeV);
600 1 : c.setCurrentStep(1000 * Mpc);
601 1 : ppp.process(&c);
602 1 : EXPECT_LT(c.current.getEnergy(), 400. * EeV);
603 1 : int id = c.current.getId();
604 1 : EXPECT_TRUE(massNumber(id) < 4);
605 1 : EXPECT_TRUE(c.secondaries.size() > 0);
606 2 : }
607 :
608 1 : TEST(PhotoPionProduction, thisIsNotNucleonic) {
609 : // Test if nothing happens to an electron.
610 1 : ref_ptr<PhotonField> cmb = new CMB();
611 1 : PhotoPionProduction ppp(cmb);
612 1 : Candidate c;
613 1 : c.current.setId(11); // electron
614 1 : c.current.setEnergy(10 * EeV);
615 1 : c.setCurrentStep(100 * Mpc);
616 1 : ppp.process(&c);
617 1 : EXPECT_EQ(11, c.current.getId());
618 1 : EXPECT_EQ(10 * EeV, c.current.getEnergy());
619 2 : }
620 :
621 1 : TEST(PhotoPionProduction, limitNextStep) {
622 : // Test if the interaction limits the next propagation step.
623 1 : ref_ptr<PhotonField> cmb = new CMB();
624 1 : PhotoPionProduction ppp(cmb);
625 1 : Candidate c(nucleusId(1, 1), 200 * EeV);
626 1 : c.setNextStep(std::numeric_limits<double>::max());
627 1 : ppp.process(&c);
628 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
629 2 : }
630 :
631 1 : TEST(PhotoPionProduction, secondaries) {
632 : // Test photo-pion interaction for 100 EeV proton.
633 : // This test can stochastically fail.
634 1 : ref_ptr<PhotonField> cmb = new CMB();
635 1 : PhotoPionProduction ppp(cmb, true, true, true);
636 1 : Candidate c(nucleusId(1, 1), 100 * EeV);
637 1 : c.setCurrentStep(1000 * Mpc);
638 1 : ppp.process(&c);
639 : // there should be secondaries
640 1 : EXPECT_GT(c.secondaries.size(), 1);
641 2 : }
642 :
643 1 : TEST(PhotoPionProduction, sampling) {
644 : // Specific test of photon sampling of photo-pion production
645 : // by testing the calculated pEpsMax for CMB(), also indirectly
646 : // testing epsMinInteraction and logSampling (default).
647 1 : ref_ptr<PhotonField> cmb = new CMB(); //create CMB instance
648 : double energy = 1.e10; //1e10 GeV
649 : bool onProton = true; //proton
650 : double z = 0; //no redshift
651 1 : PhotoPionProduction ppp(cmb, true, true, true);
652 1 : double correctionFactor = ppp.getCorrectionFactor(); //get current correctionFactor
653 1 : double epsMin = std::max(cmb -> getMinimumPhotonEnergy(z) / eV, 0.00710614); // 0.00710614 = epsMinInteraction(onProton,energy)
654 1 : double epsMax = cmb -> getMaximumPhotonEnergy(z) / eV;
655 1 : double pEpsMax = ppp.probEpsMax(onProton, energy, z, epsMin, epsMax) / correctionFactor;
656 1 : EXPECT_DOUBLE_EQ(pEpsMax,132673934934.922);
657 2 : }
658 :
659 1 : TEST(PhotoPionProduction, interactionTag) {
660 2 : PhotoPionProduction ppp(new CMB());
661 :
662 : // test default interactionTag
663 2 : EXPECT_TRUE(ppp.getInteractionTag() == "PPP");
664 :
665 : // test secondary tag
666 1 : ppp.setHavePhotons(true);
667 2 : Candidate c(nucleusId(1,1), 100 * EeV);
668 11 : for(int i = 0; i <10; i++)
669 10 : ppp.performInteraction(&c, true);
670 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "PPP");
671 :
672 : // test custom interactionTag
673 1 : ppp.setInteractionTag("myTag");
674 2 : EXPECT_TRUE(ppp.getInteractionTag() == "myTag");
675 1 : }
676 :
677 : // Redshift -------------------------------------------------------------------
678 2 : TEST(Redshift, simpleTest) {
679 : // Test if redshift is decreased and adiabatic energy loss is applied.
680 : Redshift redshift;
681 :
682 1 : Candidate c;
683 1 : c.setRedshift(0.024);
684 1 : c.current.setEnergy(100 * EeV);
685 1 : c.setCurrentStep(1 * Mpc);
686 :
687 1 : redshift.process(&c);
688 1 : EXPECT_GT(0.024, c.getRedshift()); // expect redshift decrease
689 1 : EXPECT_GT(100, c.current.getEnergy() / EeV); // expect energy loss
690 2 : }
691 :
692 2 : TEST(Redshift, limitRedshiftDecrease) {
693 : // Test if the redshift decrease is limited to z_updated >= 0.
694 : Redshift redshift;
695 :
696 1 : Candidate c;
697 1 : c.setRedshift(0.024); // roughly corresponds to 100 Mpc
698 1 : c.setCurrentStep(150 * Mpc);
699 :
700 1 : redshift.process(&c);
701 1 : EXPECT_DOUBLE_EQ(0, c.getRedshift());
702 2 : }
703 :
704 : // EMPairProduction -----------------------------------------------------------
705 1 : TEST(EMPairProduction, allBackgrounds) {
706 : // Test if interaction data files are loaded.
707 1 : ref_ptr<PhotonField> cmb = new CMB();
708 1 : EMPairProduction em(cmb);
709 1 : ref_ptr<PhotonField> ebl = new IRB_Kneiske04();
710 1 : em.setPhotonField(ebl);
711 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
712 1 : em.setPhotonField(urb);
713 2 : ebl = new IRB_Stecker05();
714 1 : em.setPhotonField(ebl);
715 2 : ebl = new IRB_Franceschini08();
716 1 : em.setPhotonField(ebl);
717 2 : ebl = new IRB_Finke10();
718 1 : em.setPhotonField(ebl);
719 2 : ebl = new IRB_Dominguez11();
720 1 : em.setPhotonField(ebl);
721 2 : ebl = new IRB_Gilmore12();
722 1 : em.setPhotonField(ebl);
723 2 : ebl = new IRB_Stecker16_upper();
724 1 : em.setPhotonField(ebl);
725 2 : ebl = new IRB_Stecker16_lower();
726 1 : em.setPhotonField(ebl);
727 2 : ebl = new IRB_Finke22();
728 1 : em.setPhotonField(ebl);
729 2 : urb = new URB_Fixsen11();
730 1 : em.setPhotonField(urb);
731 2 : urb = new URB_Nitu21();
732 2 : em.setPhotonField(urb);
733 2 : }
734 :
735 1 : TEST(EMPairProduction, limitNextStep) {
736 : // Test if the interaction limits the next propagation step.
737 1 : ref_ptr<PhotonField> cmb = new CMB();
738 1 : EMPairProduction m(cmb);
739 1 : Candidate c(22, 1E17 * eV);
740 1 : c.setNextStep(std::numeric_limits<double>::max());
741 1 : m.process(&c);
742 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
743 2 : }
744 :
745 1 : TEST(EMPairProduction, secondaries) {
746 : // Test if secondaries are correctly produced.
747 1 : ref_ptr<PhotonField> cmb = new CMB();
748 1 : ref_ptr<PhotonField> irb = new IRB_Saldana21();
749 1 : ref_ptr<PhotonField> urb = new URB_Nitu21();
750 1 : EMPairProduction m(cmb);
751 1 : m.setHaveElectrons(true);
752 1 : m.setThinning(0.);
753 :
754 : std::vector<ref_ptr<PhotonField>> fields;
755 1 : fields.push_back(cmb);
756 1 : fields.push_back(irb);
757 1 : fields.push_back(urb);
758 :
759 : // loop over photon backgrounds
760 4 : for (int f = 0; f < fields.size(); f++) {
761 3 : m.setPhotonField(fields[f]);
762 423 : for (int i = 0; i < 140; i++) { // loop over energies Ep = (1e10 - 1e23) eV
763 420 : double Ep = pow(10, 9.05 + 0.1 * i) * eV;
764 420 : Candidate c(22, Ep);
765 420 : c.setCurrentStep(1e10 * Mpc);
766 :
767 420 : m.process(&c);
768 :
769 : // pass if no interaction has ocurred (no tabulated rates)
770 420 : if (c.isActive())
771 : continue;
772 :
773 : // expect 2 secondaries
774 310 : EXPECT_EQ(c.secondaries.size(), 2);
775 :
776 : // expect electron / positron with energies 0 < E < Ephoton
777 : double Etot = 0;
778 930 : for (int j = 0; j < c.secondaries.size(); j++) {
779 620 : Candidate s = *c.secondaries[j];
780 620 : EXPECT_EQ(abs(s.current.getId()), 11);
781 620 : EXPECT_GT(s.current.getEnergy(), 0);
782 620 : EXPECT_LT(s.current.getEnergy(), Ep);
783 620 : Etot += s.current.getEnergy();
784 620 : }
785 :
786 : // test energy conservation
787 310 : EXPECT_DOUBLE_EQ(Ep, Etot);
788 420 : }
789 : }
790 2 : }
791 :
792 1 : TEST(EMPairProduction, interactionTag) {
793 2 : EMPairProduction m(new CMB());
794 :
795 : // test default interactionTag
796 2 : EXPECT_TRUE(m.getInteractionTag() == "EMPP");
797 :
798 : // test secondary tag
799 1 : m.setHaveElectrons(true);
800 2 : Candidate c(22, 1 * EeV);
801 1 : m.performInteraction(&c);
802 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "EMPP");
803 :
804 : // test custom tag
805 1 : m.setInteractionTag("myTag");
806 2 : EXPECT_TRUE(m.getInteractionTag() == "myTag");
807 1 : }
808 :
809 : // EMDoublePairProduction -----------------------------------------------------
810 1 : TEST(EMDoublePairProduction, allBackgrounds) {
811 : // Test if interaction data files are loaded.
812 1 : ref_ptr<PhotonField> cmb = new CMB();
813 1 : EMDoublePairProduction em(cmb);
814 1 : ref_ptr<PhotonField> ebl = new IRB_Kneiske04();
815 1 : em.setPhotonField(ebl);
816 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
817 1 : em.setPhotonField(urb);
818 2 : ebl = new IRB_Stecker05();
819 1 : em.setPhotonField(ebl);
820 2 : ebl = new IRB_Franceschini08();
821 1 : em.setPhotonField(ebl);
822 2 : ebl = new IRB_Finke10();
823 1 : em.setPhotonField(ebl);
824 2 : ebl = new IRB_Dominguez11();
825 1 : em.setPhotonField(ebl);
826 2 : ebl = new IRB_Gilmore12();
827 1 : em.setPhotonField(ebl);
828 2 : ebl = new IRB_Stecker16_upper();
829 1 : em.setPhotonField(ebl);
830 2 : ebl = new IRB_Stecker16_lower();
831 1 : em.setPhotonField(ebl);
832 2 : ebl = new IRB_Finke22();
833 1 : em.setPhotonField(ebl);
834 2 : urb = new URB_Fixsen11();
835 1 : em.setPhotonField(urb);
836 2 : urb = new URB_Nitu21();
837 2 : em.setPhotonField(urb);
838 2 : }
839 :
840 1 : TEST(EMDoublePairProduction, limitNextStep) {
841 : // Test if the interaction limits the next propagation step.
842 1 : ref_ptr<PhotonField> cmb = new CMB();
843 1 : EMDoublePairProduction m(cmb);
844 1 : Candidate c(22, 1E17 * eV);
845 1 : c.setNextStep(std::numeric_limits<double>::max());
846 1 : m.process(&c);
847 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
848 2 : }
849 :
850 1 : TEST(EMDoublePairProduction, secondaries) {
851 : // Test if secondaries are correctly produced.
852 1 : ref_ptr<PhotonField> cmb = new CMB();
853 1 : ref_ptr<PhotonField> irb = new IRB_Saldana21();
854 1 : ref_ptr<PhotonField> urb = new URB_Nitu21();
855 1 : EMPairProduction m(cmb);
856 1 : m.setHaveElectrons(true);
857 1 : m.setThinning(0.);
858 :
859 : std::vector<ref_ptr<PhotonField>> fields;
860 1 : fields.push_back(cmb);
861 1 : fields.push_back(irb);
862 1 : fields.push_back(urb);
863 :
864 : // loop over photon backgrounds
865 4 : for (int f = 0; f < fields.size(); f++) {
866 3 : m.setPhotonField(fields[f]);
867 :
868 : // loop over energies Ep = (1e9 - 1e23) eV
869 423 : for (int i = 0; i < 140; i++) {
870 420 : double Ep = pow(10, 9.05 + 0.1 * i) * eV;
871 420 : Candidate c(22, Ep);
872 420 : c.setCurrentStep(1e4 * Mpc); // use lower value so that the test can run faster
873 420 : m.process(&c);
874 :
875 : // pass if no interaction has occured (no tabulated rates)
876 420 : if (c.isActive())
877 : continue;
878 :
879 : // expect 2 secondaries (only one pair is considered)
880 248 : EXPECT_EQ(c.secondaries.size(), 2);
881 :
882 : // expect electron / positron with energies 0 < E < Ephoton
883 : double Etot = 0;
884 744 : for (int j = 0; j < c.secondaries.size(); j++) {
885 496 : Candidate s = *c.secondaries[j];
886 496 : EXPECT_EQ(abs(s.current.getId()), 11);
887 496 : EXPECT_GT(s.current.getEnergy(), 0);
888 496 : EXPECT_LT(s.current.getEnergy(), Ep);
889 496 : Etot += s.current.getEnergy();
890 496 : }
891 :
892 : // test energy conservation
893 248 : EXPECT_NEAR(Ep, Etot, 1E-9);
894 420 : }
895 : }
896 2 : }
897 :
898 1 : TEST(EMDoublePairProduction, interactionTag) {
899 2 : EMDoublePairProduction m(new CMB());
900 :
901 : // test default interactionTag
902 2 : EXPECT_TRUE(m.getInteractionTag() == "EMDP");
903 :
904 : // test secondary tag
905 1 : m.setHaveElectrons(true);
906 2 : Candidate c(22, 1 * EeV);
907 1 : m.performInteraction(&c);
908 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "EMDP");
909 :
910 : // test custom tag
911 1 : m.setInteractionTag("myTag");
912 2 : EXPECT_TRUE(m.getInteractionTag() == "myTag");
913 1 : }
914 :
915 : // EMTripletPairProduction ----------------------------------------------------
916 1 : TEST(EMTripletPairProduction, allBackgrounds) {
917 : // Test if interaction data files are loaded.
918 1 : ref_ptr<PhotonField> cmb = new CMB();
919 1 : EMTripletPairProduction em(cmb);
920 1 : ref_ptr<PhotonField> ebl = new IRB_Kneiske04();
921 1 : em.setPhotonField(ebl);
922 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
923 1 : em.setPhotonField(urb);
924 2 : ebl = new IRB_Stecker05();
925 1 : em.setPhotonField(ebl);
926 2 : ebl = new IRB_Franceschini08();
927 1 : em.setPhotonField(ebl);
928 2 : ebl = new IRB_Finke10();
929 1 : em.setPhotonField(ebl);
930 2 : ebl = new IRB_Dominguez11();
931 1 : em.setPhotonField(ebl);
932 2 : ebl = new IRB_Gilmore12();
933 1 : em.setPhotonField(ebl);
934 2 : ebl = new IRB_Stecker16_upper();
935 1 : em.setPhotonField(ebl);
936 2 : ebl = new IRB_Stecker16_lower();
937 1 : em.setPhotonField(ebl);
938 2 : ebl = new IRB_Finke22();
939 1 : em.setPhotonField(ebl);
940 2 : urb = new URB_Fixsen11();
941 1 : em.setPhotonField(urb);
942 2 : urb = new URB_Nitu21();
943 2 : em.setPhotonField(urb);
944 2 : }
945 :
946 1 : TEST(EMTripletPairProduction, limitNextStep) {
947 : // Test if the interaction limits the next propagation step.
948 1 : ref_ptr<PhotonField> cmb = new CMB();
949 1 : EMTripletPairProduction m(cmb);
950 1 : Candidate c(11, 1E17 * eV);
951 1 : c.setNextStep(std::numeric_limits<double>::max());
952 1 : m.process(&c);
953 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
954 2 : }
955 :
956 1 : TEST(EMTripletPairProduction, secondaries) {
957 : // Test if secondaries are correctly produced.
958 1 : ref_ptr<PhotonField> cmb = new CMB();
959 1 : ref_ptr<PhotonField> irb = new IRB_Saldana21();
960 1 : ref_ptr<PhotonField> urb = new URB_Nitu21();
961 1 : EMPairProduction m(cmb);
962 1 : m.setHaveElectrons(true);
963 1 : m.setThinning(0.);
964 :
965 : std::vector<ref_ptr<PhotonField>> fields;
966 1 : fields.push_back(cmb);
967 1 : fields.push_back(irb);
968 1 : fields.push_back(urb);
969 :
970 : // loop over photon backgrounds
971 4 : for (int f = 0; f < fields.size(); f++) {
972 3 : m.setPhotonField(fields[f]);
973 :
974 : // loop over energies Ep = (1e9 - 1e23) eV
975 423 : for (int i = 0; i < 140; i++) {
976 :
977 420 : double Ep = pow(10, 9.05 + 0.1 * i) * eV;
978 420 : Candidate c(11, Ep);
979 420 : c.setCurrentStep(1e4 * Mpc); // use lower value so that the test can run faster
980 420 : m.process(&c);
981 :
982 : // pass if no interaction has occured (no tabulated rates)
983 420 : if (c.current.getEnergy() == Ep)
984 : continue;
985 :
986 : // expect positive energy of primary electron
987 0 : EXPECT_GT(c.current.getEnergy(), 0);
988 0 : double Etot = c.current.getEnergy();
989 :
990 : // expect electron / positron with energies 0 < E < Ephoton
991 0 : for (int j = 0; j < c.secondaries.size(); j++) {
992 0 : Candidate s = *c.secondaries[j];
993 0 : EXPECT_EQ(abs(s.current.getId()), 11);
994 0 : EXPECT_GT(s.current.getEnergy(), 0);
995 0 : EXPECT_LT(s.current.getEnergy(), Ep);
996 0 : Etot += s.current.getEnergy();
997 0 : }
998 :
999 : // test energy conservation
1000 0 : EXPECT_NEAR(Ep, Etot, 1e-9);
1001 420 : }
1002 : }
1003 2 : }
1004 :
1005 1 : TEST(EMTripletPairProduction, interactionTag) {
1006 2 : EMTripletPairProduction m(new CMB());
1007 :
1008 : // test default interactionTag
1009 2 : EXPECT_TRUE(m.getInteractionTag() == "EMTP");
1010 :
1011 : // test secondary tag
1012 1 : m.setHaveElectrons(true);
1013 2 : Candidate c(11, 1 * EeV);
1014 1 : m.performInteraction(&c);
1015 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "EMTP");
1016 :
1017 : // test custom tag
1018 1 : m.setInteractionTag("myTag");
1019 2 : EXPECT_TRUE(m.getInteractionTag() == "myTag");
1020 1 : }
1021 :
1022 : // EMInverseComptonScattering -------------------------------------------------
1023 1 : TEST(EMInverseComptonScattering, allBackgrounds) {
1024 : // Test if interaction data files are loaded.
1025 1 : ref_ptr<PhotonField> cmb = new CMB();
1026 1 : EMInverseComptonScattering em(cmb);
1027 1 : ref_ptr<PhotonField> ebl = new IRB_Kneiske04();
1028 1 : em.setPhotonField(ebl);
1029 1 : ref_ptr<PhotonField> urb = new URB_Protheroe96();
1030 1 : em.setPhotonField(urb);
1031 2 : ebl = new IRB_Stecker05();
1032 1 : em.setPhotonField(ebl);
1033 2 : ebl = new IRB_Franceschini08();
1034 1 : em.setPhotonField(ebl);
1035 2 : ebl = new IRB_Finke10();
1036 1 : em.setPhotonField(ebl);
1037 2 : ebl = new IRB_Dominguez11();
1038 1 : em.setPhotonField(ebl);
1039 2 : ebl = new IRB_Gilmore12();
1040 1 : em.setPhotonField(ebl);
1041 2 : ebl = new IRB_Stecker16_upper();
1042 1 : em.setPhotonField(ebl);
1043 2 : ebl = new IRB_Stecker16_lower();
1044 1 : em.setPhotonField(ebl);
1045 2 : ebl = new IRB_Finke22();
1046 1 : em.setPhotonField(ebl);
1047 2 : urb = new URB_Fixsen11();
1048 1 : em.setPhotonField(urb);
1049 2 : urb = new URB_Nitu21();
1050 2 : em.setPhotonField(urb);
1051 2 : }
1052 :
1053 1 : TEST(EMInverseComptonScattering, limitNextStep) {
1054 : // Test if the interaction limits the next propagation step.
1055 1 : ref_ptr<PhotonField> cmb = new CMB();
1056 1 : EMInverseComptonScattering m(cmb);
1057 1 : Candidate c(11, 1E17 * eV);
1058 1 : c.setNextStep(std::numeric_limits<double>::max());
1059 1 : m.process(&c);
1060 1 : EXPECT_LT(c.getNextStep(), std::numeric_limits<double>::max());
1061 2 : }
1062 :
1063 1 : TEST(EMInverseComptonScattering, secondaries) {
1064 : // Test if secondaries are correctly produced.
1065 1 : ref_ptr<PhotonField> cmb = new CMB();
1066 1 : ref_ptr<PhotonField> irb = new IRB_Saldana21();
1067 1 : ref_ptr<PhotonField> urb = new URB_Nitu21();
1068 1 : EMPairProduction m(cmb);
1069 1 : m.setHaveElectrons(true);
1070 1 : m.setThinning(0.);
1071 :
1072 : std::vector<ref_ptr<PhotonField>> fields;
1073 1 : fields.push_back(cmb);
1074 1 : fields.push_back(irb);
1075 1 : fields.push_back(urb);
1076 :
1077 : // loop over photon backgrounds
1078 4 : for (int f = 0; f < fields.size(); f++) {
1079 3 : m.setPhotonField(fields[f]);
1080 :
1081 : // loop over energies Ep = (1e9 - 1e23) eV
1082 423 : for (int i = 0; i < 140; i++) {
1083 420 : double Ep = pow(10, 9.05 + 0.1 * i) * eV;
1084 420 : Candidate c(11, Ep);
1085 420 : c.setCurrentStep(1e3 * Mpc); // use lower value so that the test can run faster
1086 420 : m.process(&c);
1087 :
1088 : // pass if no interaction has occured (no tabulated rates)
1089 420 : if (c.current.getEnergy() == Ep)
1090 : continue;
1091 :
1092 : // expect positive energy of primary electron
1093 0 : EXPECT_GT(c.current.getEnergy(), 0);
1094 :
1095 : // expect photon with energy 0 < E < Ephoton
1096 0 : Candidate s = *c.secondaries[0];
1097 0 : EXPECT_EQ(abs(s.current.getId()), 22);
1098 0 : EXPECT_TRUE(s.current.getEnergy() >= 0.);
1099 0 : EXPECT_TRUE(s.current.getEnergy() < Ep);
1100 :
1101 :
1102 0 : double Etot = c.current.getEnergy();
1103 0 : for (int j = 0; j < c.secondaries.size(); j++) {
1104 0 : s = *c.secondaries[j];
1105 0 : Etot += s.current.getEnergy();
1106 : }
1107 0 : EXPECT_NEAR(Ep, Etot, 1e-9);
1108 420 : }
1109 : }
1110 2 : }
1111 :
1112 1 : TEST(EMInverseComptonScattering, interactionTag) {
1113 2 : EMInverseComptonScattering m(new CMB());
1114 :
1115 : // test default interactionTag
1116 2 : EXPECT_TRUE(m.getInteractionTag() == "EMIC");
1117 :
1118 : // test secondary tag
1119 1 : m.setHavePhotons(true);
1120 2 : Candidate c(11, 1 * PeV);
1121 1 : m.performInteraction(&c);
1122 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "EMIC");
1123 :
1124 : // test custom tag
1125 1 : m.setInteractionTag("myTag");
1126 2 : EXPECT_TRUE(m.getInteractionTag() == "myTag");
1127 1 : }
1128 :
1129 : // SynchrotronRadiation -------------------------------------------------
1130 1 : TEST(SynchrotronRadiation, interactionTag) {
1131 1 : SynchrotronRadiation s(1 * muG, true);
1132 :
1133 : // test default interactionTag
1134 2 : EXPECT_TRUE(s.getInteractionTag() == "SYN");
1135 :
1136 : // test secondary tag
1137 2 : Candidate c(11, 10 * PeV);
1138 1 : c.setCurrentStep(1 * pc);
1139 1 : s.process(&c);
1140 2 : EXPECT_TRUE(c.secondaries[0] -> getTagOrigin() == "SYN");
1141 :
1142 : // test custom tag
1143 1 : s.setInteractionTag("myTag");
1144 2 : EXPECT_TRUE(s.getInteractionTag() == "myTag");
1145 1 : }
1146 :
1147 :
1148 0 : int main(int argc, char **argv) {
1149 0 : ::testing::InitGoogleTest(&argc, argv);
1150 0 : return RUN_ALL_TESTS();
1151 : }
1152 :
1153 : } // namespace crpropa
|