Newer
Older
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#include <corsika/framework/process/ProcessSequence.hpp>
#include <corsika/framework/process/SwitchProcessSequence.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <catch2/catch.hpp>
#include <array>
#include <iomanip>
#include <iostream>
ralfulrich
committed
#include <typeinfo>
using namespace corsika;
ralfulrich
committed
int globalCount = 0; // simple counter
ralfulrich
committed
int checkInteract = 0; // use this as a bit field
int checkSec = 0; // use this as a bit field
int checkCont = 0; // use this as a bit field
class ContinuousProcess1 : public ContinuousProcess<ContinuousProcess1> {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
template <typename D, typename T>
cout << "ContinuousProcess1::DoContinuous" << endl;
ralfulrich
committed
checkCont |= 1;
for (int i = 0; i < nData; ++i) d.data_[i] += 0.933;
};
class ContinuousProcess2 : public ContinuousProcess<ContinuousProcess2> {
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
template <typename D, typename T>
cout << "ContinuousProcess2::DoContinuous" << endl;
ralfulrich
committed
checkCont |= 2;
ralfulrich
committed
}
ralfulrich
committed
};
class ContinuousProcess3 : public ContinuousProcess<ContinuousProcess3> {
public:
ContinuousProcess3(const int v)
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
ralfulrich
committed
globalCount++;
}
template <typename D, typename T>
ralfulrich
committed
cout << "ContinuousProcess3::DoContinuous" << endl;
checkCont |= 4;
class Process1 : public InteractionProcess<Process1> {
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 1;
for (int i = 0; i < nData; ++i) v.parent().data_[i] += 1 + i;
template <typename TParticle>
GrammageType getInteractionLength(TParticle&) const {
return 10_g / square(1_cm);
}
class Process2 : public InteractionProcess<Process2> {
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 2;
for (int i = 0; i < nData; ++i) v.parent().data_[i] /= 1.1;
template <typename Particle>
GrammageType getInteractionLength(Particle&) const {
ralfulrich
committed
return 20_g / (1_cm * 1_cm);
class Process3 : public InteractionProcess<Process3> {
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 4;
for (int i = 0; i < nData; ++i) v.parent().data_[i] *= 1.01;
template <typename Particle>
GrammageType getInteractionLength(Particle&) const {
ralfulrich
committed
return 30_g / (1_cm * 1_cm);
};
class Process4 : public BaseProcess<Process4> {
public:
: v_(v) {
cout << "globalCount: " << globalCount << ", v_: " << v_ << std::endl;
template <typename D, typename T>
ralfulrich
committed
checkCont |= 8;
for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; }
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 8;
};
class Decay1 : public DecayProcess<Decay1> {
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkDecay |= 1;
}
};
class Decay2 : public DecayProcess<Decay2> {
public:
Decay2(const int) {
cout << "Decay2()" << endl;
globalCount++;
}
template <typename Particle>
ralfulrich
committed
return 2_s;
}
template <typename TView>
ralfulrich
committed
checkDecay |= 2;
class Stack1 : public StackProcess<Stack1> {
public:
Stack1(const int n)
: StackProcess(n) {}
template <typename TStack>
ProcessReturn doStack(TStack&) {
count_++;
return ProcessReturn::Ok;
};
struct DummyStack {};
ralfulrich
committed
double data_[nData] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ralfulrich
committed
struct DummyView {
DummyView(DummyData& p)
: p_(p) {}
DummyData& p_;
DummyData& parent() { return p_; }
};
SECTION("Check construction") {
ralfulrich
committed
CHECK(is_process_sequence_v<decltype(sequence1)> == true);
ralfulrich
committed
CHECK(is_process_sequence_v<decltype(m2)> == false);
CHECK(is_switch_process_sequence_v<decltype(sequence1)> == false);
CHECK(is_switch_process_sequence_v<decltype(m2)> == false);
ralfulrich
committed
ralfulrich
committed
CHECK(is_process_sequence_v<decltype(sequence2)> == true);
ralfulrich
committed
CHECK(is_process_sequence_v<decltype(sequence3)> == true);
ContinuousProcess1 cp1(0);
Process2 m2(1);
Process3 m3(2);
auto sequence2 = make_sequence(cp1, m2, m3);
GrammageType const tot = sequence2.getInteractionLength(particle);
InverseGrammageType const tot_inv = sequence2.getInverseInteractionLength(particle);
cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl;
CHECK(tot / 1_g * square(1_cm) == 12);
CHECK(tot_inv * 1_g / square(1_cm) == 1. / 12);
ContinuousProcess1 cp1(0);
Process2 m2(1);
Process3 m3(2);
auto sequence2 = make_sequence(cp1, m2, m3, d3);
TimeType const tot = sequence2.getLifetime(particle);
InverseTimeType const tot_inv = sequence2.getInverseLifetime(particle);
cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl;
CHECK(tot / 1_s == 1);
CHECK(tot_inv * 1_s == 1.);
ContinuousProcess1 cp1(0); // += 0.933
ContinuousProcess2 cp2(1); // += 0.111
Process2 m2(2); // /= 1.1
Process3 m3(3); // *= 1.01
auto sequence2 = make_sequence(cp1, m2, m3, cp2);
DummyData particle;
DummyTrajectory track;
const int nLoop = 5;
cout << "Running loop with n=" << nLoop << endl;
for (int i = 0; i < nData; ++i) { test_data[i] += 0.933 + 0.111; }
for (int i = 0; i < nData; i++) {
ralfulrich
committed
cout << "data_[" << i << "]=" << particle.data_[i] << endl;
CHECK(particle.data_[i] == Approx(test_data[i]).margin(1e-9));
SECTION("StackProcess") {
Stack1 s1(1);
Stack1 s2(2);
DummyStack stack;
const int nLoop = 20;
for (int i = 0; i < nLoop; ++i) { sequence1.doStack(stack); }
CHECK(s1.getCount() == 20);
CHECK(s2.getCount() == 10);
ContinuousProcess2 cp2(1); // += 0.111
Process2 m2(2); // /= 1.1
auto sequence2 = make_sequence(cp2, m2);
auto sequence3 = make_sequence(cp2, m2, s1);
CHECK(is_process_sequence_v<decltype(sequence2)> == true);
CHECK(is_process_sequence_v<decltype(sequence3)> == true);
CHECK(contains_stack_process_v<decltype(sequence2)> == false);
CHECK(contains_stack_process_v<decltype(sequence3)> == true);
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
SECTION("Check construction") {
struct TestSelect {
SwitchResult operator()(const DummyData& p) const {
std::cout << "TestSelect data=" << p.data_[0] << std::endl;
if (p.data_[0] > 0) return SwitchResult::First;
return SwitchResult::Second;
}
};
TestSelect select1;
auto sequence1 = make_sequence(Process1(0), ContinuousProcess2(0), Decay1(0));
auto sequence2 = make_sequence(ContinuousProcess3(0), Process2(0), Decay2(0));
auto sequence3 = make_sequence(ContinuousProcess1(0), Process3(0),
SwitchProcessSequence(sequence1, sequence2, select1));
auto sequence_alt = make_sequence(
ContinuousProcess1(0), Process3(0),
make_select(make_sequence(Process1(0), ContinuousProcess2(0), Decay1(0)),
make_sequence(ContinuousProcess3(0), Process2(0), Decay2(0)),
select1));
// check that same process sequence can be build in different ways
CHECK(typeid(sequence3) == typeid(sequence_alt));
CHECK(is_process_sequence_v<decltype(sequence3)> == true);
CHECK(is_process_sequence_v<decltype(
SwitchProcessSequence(sequence1, sequence2, select1))> == true);
DummyData particle;
DummyTrajectory track;
DummyView view(particle);
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = 100; // data positive
sequence3.doContinuous(particle, track);
CHECK(checkInteract == 0);
CHECK(checkDecay == 0);
CHECK(checkCont == 0b011);
CHECK(checkSec == 0);
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = -100; // data negative
sequence_alt.doContinuous(particle, track);
CHECK(checkInteract == 0);
CHECK(checkDecay == 0);
CHECK(checkCont == 0b101);
CHECK(checkSec == 0);
// 1/(30g/cm2) is Process3
InverseGrammageType lambda_select = .9 / 30. * square(1_cm) / 1_g;
InverseTimeType time_select = 0.1 / second;
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = 100; // data positive
sequence3.selectInteraction(view, lambda_select);
sequence3.selectDecay(view, time_select);
CHECK(checkInteract == 0b100); // this is Process3
CHECK(checkDecay == 0b001); // this is Decay1
CHECK(checkCont == 0);
CHECK(checkSec == 0);
lambda_select = 1.01 / 30. * square(1_cm) / 1_g;
checkInteract = 0;
sequence3.selectInteraction(view, lambda_select);
CHECK(checkInteract == 0b001); // this is Process1
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = -100; // data negative
sequence3.selectInteraction(view, lambda_select);
sequence3.selectDecay(view, time_select);
CHECK(checkInteract == 0b010); // this is Process2
CHECK(checkDecay == 0b010); // this is Decay2
CHECK(checkCont == 0);
CHECK(checkSec == 0);
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = -100; // data negative
sequence3.doSecondaries(view);
Stack1 stack(0);
sequence3.doStack(stack);
CHECK(checkInteract == 0);
CHECK(checkDecay == 0);
CHECK(checkCont == 0);
CHECK(checkSec == 0);
}
}