Newer
Older
* (c) Copyright 2018 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 <catch2/catch.hpp>
#include <array>
#include <iomanip>
#include <iostream>
ralfulrich
committed
#include <typeinfo>
#include <corsika/process/ProcessSequence.h>
ralfulrich
committed
#include <corsika/process/SwitchProcessSequence.h>
#include <corsika/units/PhysicalUnits.h>
using namespace corsika::process;
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> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
template <typename D, typename T>
inline EProcessReturn DoContinuous(D& d, T&) const {
cout << "ContinuousProcess1::DoContinuous" << endl;
ralfulrich
committed
checkCont |= 1;
for (int i = 0; i < nData; ++i) d.data_[i] += 0.933;
return EProcessReturn::eOk;
}
};
class ContinuousProcess2 : public ContinuousProcess<ContinuousProcess2> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
template <typename D, typename T>
inline EProcessReturn DoContinuous(D& d, T&) const {
cout << "ContinuousProcess2::DoContinuous" << endl;
ralfulrich
committed
checkCont |= 2;
ralfulrich
committed
return EProcessReturn::eOk;
}
};
class ContinuousProcess3 : public ContinuousProcess<ContinuousProcess3> {
int fV = 0;
public:
ContinuousProcess3(const int v)
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
globalCount++;
}
template <typename D, typename T>
inline EProcessReturn DoContinuous(D& d, T&) const {
cout << "ContinuousProcess3::DoContinuous" << endl;
checkCont |= 4;
return EProcessReturn::eOk;
}
};
class Process1 : public InteractionProcess<Process1> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
ralfulrich
committed
template <typename TView>
inline EProcessReturn DoInteraction(TView& v) const {
checkInteract |= 1;
for (int i = 0; i < nData; ++i) v.parent().data_[i] += 1 + i;
ralfulrich
committed
template <typename TParticle>
corsika::units::si::GrammageType GetInteractionLength(TParticle&) const {
return 10_g / square(1_cm);
}
class Process2 : public InteractionProcess<Process2> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 2;
for (int i = 0; i < nData; ++i) v.parent().data_[i] /= 1.1;
cout << "Process2::DoInteraction" << endl;
template <typename Particle>
GrammageType GetInteractionLength(Particle&) const {
ralfulrich
committed
return 20_g / (1_cm * 1_cm);
class Process3 : public InteractionProcess<Process3> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
ralfulrich
committed
template <typename TView>
ralfulrich
committed
checkInteract |= 4;
for (int i = 0; i < nData; ++i) v.parent().data_[i] *= 1.01;
cout << "Process3::DoInteraction" << endl;
template <typename Particle>
GrammageType GetInteractionLength(Particle&) const {
ralfulrich
committed
return 30_g / (1_cm * 1_cm);
};
class Process4 : public BaseProcess<Process4> {
: fV(v) {
cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl;
template <typename D, typename T>
inline EProcessReturn DoContinuous(D& d, T&) const {
ralfulrich
committed
std::cout << "Base::DoContinuous" << std::endl;
checkCont |= 8;
for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; }
ralfulrich
committed
template <typename TView>
EProcessReturn DoInteraction(TView&) const {
checkInteract |= 8;
return EProcessReturn::eOk;
}
};
class Decay1 : public DecayProcess<Decay1> {
public:
ralfulrich
committed
template <typename TView>
EProcessReturn DoDecay(TView&) const {
checkDecay |= 1;
return EProcessReturn::eOk;
}
};
class Decay2 : public DecayProcess<Decay2> {
public:
Decay2(const int) {
cout << "Decay2()" << endl;
globalCount++;
}
template <typename Particle>
ralfulrich
committed
TimeType GetLifetime(Particle&) const {
return 2_s;
}
template <typename TView>
EProcessReturn DoDecay(TView&) const {
checkDecay |= 2;
class Stack1 : public StackProcess<Stack1> {
int fCount = 0;
public:
Stack1(const int n)
: StackProcess(n) {}
template <typename TStack>
EProcessReturn DoStack(TStack&) {
fCount++;
return EProcessReturn::eOk;
}
};
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
auto sequence1 = process::sequence(m1, m2, m3, m4);
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
auto sequence2 = process::sequence(m1, m2, m3);
CHECK(is_process_sequence_v<decltype(sequence2)> == true);
auto sequence3 = process::sequence(m4);
CHECK(is_process_sequence_v<decltype(sequence3)> == true);
ContinuousProcess1 cp1(0);
Process2 m2(1);
Process3 m3(2);
ralfulrich
committed
auto sequence2 = sequence(cp1, m2, m3);
ralfulrich
committed
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);
ralfulrich
committed
auto sequence2 = sequence(cp1, m2, m3, d3);
ralfulrich
committed
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
ralfulrich
committed
auto sequence2 = 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);
ralfulrich
committed
auto sequence = process::sequence(s1, s2);
DummyStack stack;
const int nLoop = 20;
for (int i = 0; i < nLoop; ++i) { sequence.DoStack(stack); }
CHECK(s1.GetCount() == 20);
CHECK(s2.GetCount() == 10);
ContinuousProcess2 cp2(1); // += 0.111
Process2 m2(2); // /= 1.1
auto sequence2 = process::sequence(cp2, m2);
auto sequence3 = process::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);
ralfulrich
committed
TEST_CASE("Switch Process Sequence", "[Process Sequence]") {
SECTION("Check construction") {
struct TestSelect {
ralfulrich
committed
corsika::process::SwitchResult operator()(const DummyData& p) const {
ralfulrich
committed
std::cout << "TestSelect data=" << p.data_[0] << std::endl;
if (p.data_[0] > 0) return corsika::process::SwitchResult::First;
return corsika::process::SwitchResult::Second;
}
};
TestSelect select;
ralfulrich
committed
auto sequence1 = process::sequence(Process1(0), ContinuousProcess2(0), Decay1(0));
auto sequence2 = process::sequence(ContinuousProcess3(0), Process2(0), Decay2(0));
ralfulrich
committed
ralfulrich
committed
auto sequence =
process::sequence(ContinuousProcess1(0), Process3(0),
SwitchProcessSequence(sequence1, sequence2, select));
ralfulrich
committed
ralfulrich
committed
auto sequence_alt = process::sequence(
ContinuousProcess1(0), Process3(0),
process::select(process::sequence(Process1(0), ContinuousProcess2(0), Decay1(0)),
process::sequence(ContinuousProcess3(0), Process2(0), Decay2(0)),
select));
ralfulrich
committed
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
// check that same process sequence can be build in different ways
CHECK(typeid(sequence) == typeid(sequence_alt));
CHECK(is_process_sequence_v<decltype(sequence)> == true);
CHECK(is_process_sequence_v<decltype(
SwitchProcessSequence(sequence1, sequence2, select))> == true);
DummyData particle;
DummyTrajectory track;
DummyView view(particle);
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = 100; // data positive
sequence.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
corsika::units::si::InverseGrammageType lambda_select = .9 / 30. * square(1_cm) / 1_g;
ralfulrich
committed
corsika::units::si::InverseTimeType time_select = 0.1 / second;
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = 100; // data positive
sequence.SelectInteraction(view, lambda_select);
sequence.SelectDecay(view, time_select);
CHECK(checkInteract == 0b100); // this is Process3
ralfulrich
committed
CHECK(checkCont == 0);
CHECK(checkSec == 0);
lambda_select = 1.01 / 30. * square(1_cm) / 1_g;
ralfulrich
committed
checkInteract = 0;
sequence.SelectInteraction(view, lambda_select);
CHECK(checkInteract == 0b001); // this is Process1
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = -100; // data negative
sequence.SelectInteraction(view, lambda_select);
sequence.SelectDecay(view, time_select);
CHECK(checkInteract == 0b010); // this is Process2
ralfulrich
committed
CHECK(checkCont == 0);
CHECK(checkSec == 0);
checkDecay = 0;
checkInteract = 0;
checkSec = 0;
checkCont = 0;
particle.data_[0] = -100; // data negative
sequence.DoSecondaries(view);
Stack1 stack(0);
sequence.DoStack(stack);
CHECK(checkInteract == 0);
CHECK(checkDecay == 0);
CHECK(checkCont == 0);
CHECK(checkSec == 0);
}