IAP GITLAB

Skip to content
Snippets Groups Projects
Commit 3ebf404d authored by ralfulrich's avatar ralfulrich
Browse files

migrated framework/process

parent 44d85880
No related branches found
No related tags found
1 merge request!280Refactory 2020
/*
* (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.
*/
#pragma once
#include <corsika/framework/process/BaseProcess.hpp>
#include <corsika/framework/process/ProcessTraits.hpp>
#include <corsika/framework/process/BoundaryCrossingProcess.hpp>
#include <corsika/framework/process/ContinuousProcess.hpp>
#include <corsika/framework/process/DecayProcess.hpp>
#include <corsika/framework/process/InteractionProcess.hpp>
#include <corsika/framework/process/ProcessReturn.hpp>
#include <corsika/framework/process/SecondariesProcess.hpp>
#include <corsika/framework/process/StackProcess.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <cmath>
#include <limits>
#include <type_traits>
namespace corsika {
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TParticle, typename TVTNType>
EProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doBoundaryCrossing(
TParticle& particle, TVTNType const& from, TVTNType const& to) {
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process1_type>,
process1_type> ||
t1ProcSeq) {
return A_.doBoundaryCrossing(particle, from, to);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process2_type>,
process2_type> ||
t2ProcSeq) {
return B_.doBoundaryCrossing(particle, from, to);
}
break;
}
}
return EProcessReturn::eOk;
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TParticle, typename TTrack>
inline EProcessReturn
SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doContinuous(TParticle& particle,
TTrack& vT) {
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>,
process1_type> ||
t1ProcSeq) {
return A_.doContinuous(particle, vT);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>,
process2_type> ||
t2ProcSeq) {
return B_.doContinuous(particle, vT);
}
break;
}
}
return EProcessReturn::eOk;
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TSecondaries>
inline void SwitchProcessSequence<TProcess1, TProcess2, TSelect>::doSecondaries(
TSecondaries& vS) {
const auto& particle = vS.parent();
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<SecondariesProcess<process1_type>,
process1_type> ||
t1ProcSeq) {
A_.doSecondaries(vS);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<SecondariesProcess<process2_type>,
process2_type> ||
t2ProcSeq) {
B_.doSecondaries(vS);
}
break;
}
}
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TParticle, typename TTrack>
inline LengthType SwitchProcessSequence<TProcess1, TProcess2, TSelect>::maxStepLength(
TParticle& particle, TTrack& vTrack) {
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>,
process1_type> ||
t1ProcSeq) {
return A_.maxStepLength(particle, vTrack);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>,
process2_type> ||
t2ProcSeq) {
return B_.maxStepLength(particle, vTrack);
}
break;
}
}
// if no other process in the sequence implements it
return std::numeric_limits<double>::infinity() * meter;
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TParticle>
inline InverseGrammageType
SwitchProcessSequence<TProcess1, TProcess2, TSelect>::getInverseInteractionLength(
TParticle&& particle) {
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<InteractionProcess<process1_type>,
process1_type> ||
t1ProcSeq) {
return A_.getInverseInteractionLength(particle);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<InteractionProcess<process2_type>,
process2_type> ||
t2ProcSeq) {
return B_.getInverseInteractionLength(particle);
}
break;
}
}
return 0 * meter * meter / gram; // default value
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TSecondaryView>
inline EProcessReturn
SwitchProcessSequence<TProcess1, TProcess2, TSelect>::selectInteraction(
TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
[[maybe_unused]] InverseGrammageType lambda_inv_sum) {
switch (select_(view.parent())) {
case SwitchResult::First: {
if constexpr (t1ProcSeq) {
// if A_ is a process sequence --> check inside
EProcessReturn const ret =
A_.selectInteraction(view, lambda_inv_select, lambda_inv_sum);
// if A_ did succeed, stop routine. Not checking other static branch B_.
if (ret != EProcessReturn::eOk) { return ret; }
} else if constexpr (std::is_base_of_v<InteractionProcess<process1_type>,
process1_type>) {
// if this is not a ContinuousProcess --> evaluate probability
lambda_inv_sum += A_.getInverseInteractionLength(view.parent());
// check if we should execute THIS process and then EXIT
if (lambda_inv_select < lambda_inv_sum) {
A_.doInteraction(view);
return EProcessReturn::eInteracted;
}
} // end branch A_
break;
}
case SwitchResult::Second: {
if constexpr (t2ProcSeq) {
// if B_ is a process sequence --> check inside
return B_.selectInteraction(view, lambda_inv_select, lambda_inv_sum);
} else if constexpr (std::is_base_of_v<InteractionProcess<process2_type>,
process2_type>) {
// if this is not a ContinuousProcess --> evaluate probability
lambda_inv_sum += B_.getInverseInteractionLength(view.parent());
// check if we should execute THIS process and then EXIT
if (lambda_inv_select < lambda_inv_sum) {
B_.doInteraction(view);
return EProcessReturn::eInteracted;
}
} // end branch B_
break;
}
}
return EProcessReturn::eOk;
}
template <typename TProcess1, typename TProcess2, typename TSelect>
template <typename TParticle>
inline InverseTimeType
SwitchProcessSequence<TProcess1, TProcess2, TSelect>::getInverseLifetime(
TParticle&& particle) {
switch (select_(particle)) {
case SwitchResult::First: {
if constexpr (std::is_base_of_v<DecayProcess<process1_type>, process1_type> ||
t1ProcSeq) {
return A_.getInverseLifetime(particle);
}
break;
}
case SwitchResult::Second: {
if constexpr (std::is_base_of_v<DecayProcess<process2_type>, process2_type> ||
t2ProcSeq) {
return B_.getInverseLifetime(particle);
}
break;
}
}
return 0 / second; // default value
}
template <typename TProcess1, typename TProcess2, typename TSelect>
// select decay process
template <typename TSecondaryView>
inline EProcessReturn SwitchProcessSequence<TProcess1, TProcess2, TSelect>::selectDecay(
TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
[[maybe_unused]] InverseTimeType decay_inv_sum) {
switch (select_(view.parent())) {
case SwitchResult::First: {
if constexpr (t1ProcSeq) {
// if A_ is a process sequence --> check inside
EProcessReturn const ret =
A_.selectDecay(view, decay_inv_select, decay_inv_sum);
// if A_ did succeed, stop routine here (not checking other static branch B_)
if (ret != EProcessReturn::eOk) { return ret; }
} else if constexpr (std::is_base_of_v<DecayProcess<process1_type>,
process1_type>) {
// if this is not a ContinuousProcess --> evaluate probability
decay_inv_sum += A_.getInverseLifetime(view.parent());
// check if we should execute THIS process and then EXIT
if (decay_inv_select < decay_inv_sum) {
// more pedagogical: rndm_select < decay_inv_sum / decay_inv_tot
A_.doDecay(view);
return EProcessReturn::eDecayed;
}
} // end branch A_
break;
}
case SwitchResult::Second: {
if constexpr (t2ProcSeq) {
// if B_ is a process sequence --> check inside
return B_.selectDecay(view, decay_inv_select, decay_inv_sum);
} else if constexpr (std::is_base_of_v<DecayProcess<process2_type>,
process2_type>) {
// if this is not a ContinuousProcess --> evaluate probability
decay_inv_sum += B_.getInverseLifetime(view.parent());
// check if we should execute THIS process and then EXIT
if (decay_inv_select < decay_inv_sum) {
B_.doDecay(view);
return EProcessReturn::eDecayed;
}
} // end branch B_
break;
}
}
return EProcessReturn::eOk;
}
/// traits marker to identify objectas ProcessSequence
template <typename TProcess1, typename TProcess2, typename TSelect>
struct is_process_sequence<SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
: std::true_type {};
/// traits marker to identify objectas SwitchProcessSequence
template <typename TProcess1, typename TProcess2, typename TSelect>
struct is_switch_process_sequence<SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
: std::true_type {};
} // namespace corsika
/*
* (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.
*/
#pragma once
#include <corsika/framework/process/BaseProcess.hpp>
namespace corsika {
class NullModel : public BaseProcess<NullModel> {
public:
NullModel() = default;
~NullModel() = default;
};
} // namespace corsika
/*
* (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.
*/
#pragma once
#include <type_traits>
namespace corsika {
/**
* A traits marker to track which BaseProcess is also a ProcessSequence
**/
template <typename TClass>
struct is_process_sequence : std::false_type {};
template <typename TClass>
bool constexpr is_process_sequence_v = is_process_sequence<TClass>::value;
/**
* A traits marker to identiy a BaseProcess that is also SwitchProcessesSequence
**/
template <typename TClass>
struct is_switch_process_sequence : std::false_type {};
template <typename TClass>
bool constexpr is_switch_process_sequence_v = is_switch_process_sequence<TClass>::value;
/**
* A traits marker to identify ProcessSequence that contain a StackProcess
**/
template <typename TClass>
struct contains_stack_process : std::false_type {};
template <typename TClass>
bool constexpr contains_stack_process_v = contains_stack_process<TClass>::value;
} // namespace corsika
/*
* (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.
*/
#pragma once
#include <corsika/framework/process/BaseProcess.hpp>
#include <corsika/framework/process/ProcessTraits.hpp>
#include <corsika/framework/process/BoundaryCrossingProcess.hpp>
#include <corsika/framework/process/ContinuousProcess.hpp>
#include <corsika/framework/process/DecayProcess.hpp>
#include <corsika/framework/process/InteractionProcess.hpp>
#include <corsika/framework/process/ProcessReturn.hpp>
#include <corsika/framework/process/SecondariesProcess.hpp>
#include <corsika/framework/process/StackProcess.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <cmath>
#include <limits>
#include <type_traits>
namespace corsika {
// enum for the process switch selection: identify if First or
// Second process branch should be used.
enum class SwitchResult { First, Second };
/**
\class SwitchProcessSequence
A compile time static list of processes that uses an internal
TSelect class to switch between different versions of processes
(or process sequence).
TProcess1 and TProcess2 must be derived from BaseProcess and are
both references if possible (lvalue), otherwise (rvalue) they are
just classes. This allows us to handle both, rvalue as well as
lvalue Processes in the SwitchProcessSequence.
TSelect has to implement a `operator()(const Particle&)` and has to
return either SwitchResult::First or SwitchResult::Second. Note:
TSelect may absolutely also use random numbers to sample between
its results. This can be used to achieve arbitrarily smooth
transition or mixtures of processes.
Warning: do not put StackProcess into a SwitchProcessSequence
since this makes no sense. The StackProcess acts on an entire
particle stack and not on indiviidual particles.
\comment See also class ProcessSequence
**/
template <typename TProcess1, typename TProcess2, typename TSelect>
class SwitchProcessSequence
: public BaseProcess<SwitchProcessSequence<TProcess1, TProcess2, TSelect>> {
using process1_type = typename std::decay_t<TProcess1>;
using process2_type = typename std::decay_t<TProcess2>;
static bool constexpr t1ProcSeq = is_process_sequence_v<process1_type>;
static bool constexpr t2ProcSeq = is_process_sequence_v<process2_type>;
// make sure only BaseProcess types TProcess1/2 are passed
static_assert(std::is_base_of_v<BaseProcess<process1_type>, process1_type>,
"can only use process derived from BaseProcess in "
"SwitchProcessSequence, for Process 1");
static_assert(std::is_base_of_v<BaseProcess<process2_type>, process2_type>,
"can only use process derived from BaseProcess in "
"SwitchProcessSequence, for Process 2");
// make sure none of TProcess1/2 is a StackProcess
static_assert(!std::is_base_of_v<StackProcess<process1_type>, process1_type>,
"cannot use StackProcess in SwitchProcessSequence, for Process 1");
static_assert(!std::is_base_of_v<StackProcess<process2_type>, process2_type>,
"cannot use StackProcess in SwitchProcessSequence, for Process 2");
// if TProcess1/2 are already ProcessSequences, make sure they do not contain
// any StackProcess
static_assert(!contains_stack_process_v<process1_type>,
"cannot use StackProcess in SwitchProcessSequence, remove from "
"ProcessSequence 1");
static_assert(!contains_stack_process_v<process2_type>,
"cannot use StackProcess in SwitchProcessSequence, remove from "
"ProcessSequence 2");
TSelect select_; // this is a reference, if possible
TProcess1 A_; // this is a reference, if possible
TProcess2 B_; // this is a reference, if possible
public:
SwitchProcessSequence(TProcess1 in_A, TProcess2 in_B, TSelect sel)
: select_(sel)
, A_(in_A)
, B_(in_B) {}
template <typename TParticle, typename TVTNType>
EProcessReturn doBoundaryCrossing(TParticle& particle, TVTNType const& from,
TVTNType const& to);
template <typename TParticle, typename TTrack>
inline EProcessReturn doContinuous(TParticle& particle, TTrack& vT);
template <typename TSecondaries>
inline void doSecondaries(TSecondaries& vS);
template <typename TParticle, typename TTrack>
inline LengthType maxStepLength(TParticle& particle, TTrack& vTrack);
template <typename TParticle>
inline GrammageType getInteractionLength(TParticle&& particle) {
return 1. / getInverseInteractionLength(particle);
}
template <typename TParticle>
inline InverseGrammageType getInverseInteractionLength(TParticle&& particle);
template <typename TSecondaryView>
inline EProcessReturn selectInteraction(
TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select,
[[maybe_unused]] InverseGrammageType lambda_inv_sum =
InverseGrammageType::zero());
template <typename TParticle>
inline TimeType getLifetime(TParticle&& particle) {
return 1. / getInverseLifetime(particle);
}
template <typename TParticle>
inline InverseTimeType getInverseLifetime(TParticle&& particle);
// select decay process
template <typename TSecondaryView>
inline EProcessReturn selectDecay(
TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select,
[[maybe_unused]] InverseTimeType decay_inv_sum = InverseTimeType::zero());
};
/**
* \function make_select
*
* the functin `make_select(proc1,proc1,selector)` assembles many
* BaseProcesses, and ProcessSequences into a SwitchProcessSequence,
* all combinatorics must be allowed, this is why we define a macro
* to define all combinations here:
*
*
* Both, Processes1 and Processes2, must derive from BaseProcesses
**/
template <typename TProcess1, typename TProcess2, typename TSelect>
inline typename std::enable_if_t<
std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>,
typename std::decay_t<TProcess1>> &&
std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>,
typename std::decay_t<TProcess2>>,
SwitchProcessSequence<TProcess1, TProcess2, TSelect>>
make_select(TProcess1&& vA, TProcess2&& vB, TSelect selector) {
return SwitchProcessSequence<TProcess1, TProcess2, TSelect>(vA, vB, selector);
}
} // namespace corsika
#include <corsika/detail/framework/process/SwitchProcessSequence.inl>
/*
* (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 <corsika/framework/process/NullModel.hpp>
#include <catch2/catch.hpp>
using namespace corsika;
/*
* The NullModel can do really nothing, so we can basically test
* nothing.
*/
TEST_CASE("NullModel", "[processes]") {
SECTION("interface") { [[maybe_unused]] NullModel model; }
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment