diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl index 8492f3d0d924f01e580084a52b234934d7a3f270..d6ad50a44a14372a105d8738cb5f603e785f8b82 100644 --- a/corsika/detail/framework/process/ProcessSequence.inl +++ b/corsika/detail/framework/process/ProcessSequence.inl @@ -26,233 +26,239 @@ namespace corsika { - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename Particle, typename VTNType> - EProcessReturn ProcessSequence<T1, T2>::DoBoundaryCrossing(Particle& p, + EProcessReturn ProcessSequence<TProcess1, TProcess2>::doBoundaryCrossing(Particle& particle, VTNType const& from, VTNType const& to) { EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of<BoundaryCrossingProcess<T1type>, T1type>::value || + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process1_type>, + process1_type> || t1ProcSeq) { - ret |= A.DoBoundaryCrossing(p, from, to); + ret |= A_.doBoundaryCrossing(particle, from, to); } - if constexpr (std::is_base_of<BoundaryCrossingProcess<T2type>, T2type>::value || + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<process2_type>, + process2_type> || t2ProcSeq) { - ret |= B.DoBoundaryCrossing(p, from, to); + ret |= B_.doBoundaryCrossing(particle, from, to); } return ret; } - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TParticle, typename TTrack> - EProcessReturn ProcessSequence<T1, T2>::DoContinuous(TParticle& vP, TTrack& vT) { + EProcessReturn ProcessSequence<TProcess1, TProcess2>::doContinuous(TParticle& particle, TTrack& vT) { EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value || + if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> || t1ProcSeq) { - - ret |= A.DoContinuous(vP, vT); + ret |= A_.doContinuous(particle, vT); } - if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value || + if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> || t2ProcSeq) { - ret |= B.DoContinuous(vP, vT); + if (!isAbsorbed(ret)) { ret |= B_.doContinuous(particle, vT); } } return ret; } - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TSecondaries> - EProcessReturn ProcessSequence<T1, T2>::DoSecondaries(TSecondaries& vS) { - EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of<SecondariesProcess<T1type>, T1type>::value || + void ProcessSequence<TProcess1, TProcess2>::doSecondaries(TSecondaries& vS) { + if constexpr (std::is_base_of_v<SecondariesProcess<process1_type>, process1_type> || t1ProcSeq) { - ret |= A.DoSecondaries(vS); + A_.doSecondaries(vS); } - if constexpr (std::is_base_of<SecondariesProcess<T2type>, T2type>::value || + if constexpr (std::is_base_of_v<SecondariesProcess<process2_type>, process2_type> || t2ProcSeq) { - ret |= B.DoSecondaries(vS); + B_.doSecondaries(vS); } - return ret; } - template <typename T1, typename T2> - bool ProcessSequence<T1, T2>::CheckStep() { + template <typename TProcess1, typename TProcess2> + bool ProcessSequence<TProcess1, TProcess2>::checkStep() { bool ret = false; - if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) { - ret |= A.CheckStep(); + if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> || + (t1ProcSeq && !t1SwitchProcSeq)) { + ret |= A_.checkStep(); } - if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) { - ret |= B.CheckStep(); + if constexpr (std::is_base_of_v<StackProcess<process2_type>, process2_type> || + (t2ProcSeq && !t2SwitchProcSeq)) { + ret |= B_.checkStep(); } return ret; } - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TStack> - EProcessReturn ProcessSequence<T1, T2>::DoStack(TStack& vS) { - EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of<StackProcess<T1type>, T1type>::value || t1ProcSeq) { - if (A.CheckStep()) { ret |= A.DoStack(vS); } + void ProcessSequence<TProcess1, TProcess2>::doStack(TStack& stack) { + if constexpr (std::is_base_of_v<StackProcess<process1_type>, process1_type> || + (t1ProcSeq && !t1SwitchProcSeq)) { + if (A_.checkStep()) { A_.doStack(stack); } } - if constexpr (std::is_base_of<StackProcess<T2type>, T2type>::value || t2ProcSeq) { - if (B.CheckStep()) { ret |= B.DoStack(vS); } + if constexpr (std::is_base_of_v<StackProcess<process2_type>, process2_type> || + (t2ProcSeq && !t2SwitchProcSeq)) { + if (B_.checkStep()) { B_.doStack(stack); } } - return ret; } - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TParticle, typename TTrack> - LengthType ProcessSequence<T1, T2>::MaxStepLength(TParticle& vP, TTrack& vTrack) { + LengthType ProcessSequence<TProcess1, TProcess2>::maxStepLength(TParticle& particle, TTrack& vTrack) { LengthType max_length = // if no other process in the sequence implements it std::numeric_limits<double>::infinity() * meter; - if constexpr (std::is_base_of<ContinuousProcess<T1type>, T1type>::value || + if constexpr (std::is_base_of_v<ContinuousProcess<process1_type>, process1_type> || t1ProcSeq) { - LengthType const len = A.MaxStepLength(vP, vTrack); + LengthType const len = A_.maxStepLength(particle, vTrack); max_length = std::min(max_length, len); } - if constexpr (std::is_base_of<ContinuousProcess<T2type>, T2type>::value || + if constexpr (std::is_base_of_v<ContinuousProcess<process2_type>, process2_type> || t2ProcSeq) { - LengthType const len = B.MaxStepLength(vP, vTrack); + LengthType const len = B_.maxStepLength(particle, vTrack); max_length = std::min(max_length, len); } return max_length; } - template <typename T1, typename T2> - template <typename TParticle> - GrammageType ProcessSequence<T1, T2>::GetTotalInteractionLength(TParticle& vP) { - return 1. / GetInverseInteractionLength(vP); - } - - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TParticle> - InverseGrammageType ProcessSequence<T1, T2>::GetTotalInverseInteractionLength( - TParticle& vP) { - return GetInverseInteractionLength(vP); - } + InverseGrammageType ProcessSequence<TProcess1, TProcess2>::getInverseInteractionLength( + TParticle&& particle) { - template <typename T1, typename T2> - template <typename TParticle> - InverseGrammageType ProcessSequence<T1, T2>::GetInverseInteractionLength( - TParticle& vP) { - InverseGrammageType tot = 0 * meter * meter / gram; + InverseGrammageType tot = 0 * meter * meter / gram; // default value - if constexpr (std::is_base_of<InteractionProcess<T1type>, T1type>::value || - t1ProcSeq || t1SwitchProc) { - tot += A.GetInverseInteractionLength(vP); + if constexpr (std::is_base_of_v<InteractionProcess<process1_type>, process1_type> || + t1ProcSeq) { + tot += A_.getInverseInteractionLength(particle); } - if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value || - t2ProcSeq || t2SwitchProc) { - tot += B.GetInverseInteractionLength(vP); + if constexpr (std::is_base_of_v<InteractionProcess<process2_type>, process2_type> || + t2ProcSeq) { + tot += B_.getInverseInteractionLength(particle); } return tot; } - template <typename T1, typename T2> - template <typename TParticle, typename TSecondaries> - EProcessReturn ProcessSequence<T1, T2>::SelectInteraction( - TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseGrammageType lambda_select, - InverseGrammageType& lambda_inv_count) { + template <typename TProcess1, typename TProcess2> + template <typename TSecondaryView> + inline EProcessReturn ProcessSequence<TProcess1, TProcess2>::selectInteraction( + TSecondaryView& view, [[maybe_unused]] InverseGrammageType lambda_inv_select, + [[maybe_unused]] InverseGrammageType lambda_inv_sum) { - if constexpr (t1ProcSeq || t1SwitchProc) { + // TODO: add check for lambda_inv_select>lambda_inv_tot + + if constexpr (t1ProcSeq) { // if A is a process sequence --> check inside - const EProcessReturn ret = - A.SelectInteraction(vP, vS, lambda_select, lambda_inv_count); - // if A did succeed, stop routine + 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<InteractionProcess<T1type>, T1type>::value) { + } else if constexpr (std::is_base_of_v<InteractionProcess<process1_type>, + process1_type>) { // if this is not a ContinuousProcess --> evaluate probability - lambda_inv_count += A.GetInverseInteractionLength(vP); + auto const particle = view.parent(); + lambda_inv_sum += A_.getInverseInteractionLength(particle); // check if we should execute THIS process and then EXIT - if (lambda_select < lambda_inv_count) { - A.DoInteraction(vS); + if (lambda_inv_select < lambda_inv_sum) { + A_.doInteraction(view); return EProcessReturn::eInteracted; } - } // end branch A + } // end branch A_ - if constexpr (t2ProcSeq || t2SwitchProc) { - // if A is a process sequence --> check inside - const EProcessReturn ret = - B.SelectInteraction(vP, vS, lambda_select, lambda_inv_count); - // if A did succeed, stop routine - if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of<InteractionProcess<T2type>, T2type>::value) { + 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_count += B.GetInverseInteractionLength(vP); + lambda_inv_sum += B_.getInverseInteractionLength(view.parent()); // check if we should execute THIS process and then EXIT - if (lambda_select < lambda_inv_count) { - B.DoInteraction(vS); + if (lambda_inv_select < lambda_inv_sum) { + B_.doInteraction(view); return EProcessReturn::eInteracted; } - } // end branch A + } // end branch B_ return EProcessReturn::eOk; } - template <typename T1, typename T2> - template <typename TParticle> - TimeType ProcessSequence<T1, T2>::GetTotalLifetime(TParticle& p) { - return 1. / GetInverseLifetime(p); - } - - template <typename T1, typename T2> + template <typename TProcess1, typename TProcess2> template <typename TParticle> - InverseTimeType ProcessSequence<T1, T2>::GetTotalInverseLifetime(TParticle& p) { - return GetInverseLifetime(p); - } + inline InverseTimeType ProcessSequence<TProcess1, TProcess2>::getInverseLifetime( + TParticle&& particle) { - template <typename T1, typename T2> - template <typename TParticle> - InverseTimeType ProcessSequence<T1, T2>::GetInverseLifetime(TParticle& p) { - InverseTimeType tot = 0 / second; + InverseTimeType tot = 0 / second; // default value - if constexpr (std::is_base_of<DecayProcess<T1type>, T1type>::value || t1ProcSeq) { - tot += A.GetInverseLifetime(p); + if constexpr (std::is_base_of_v<DecayProcess<process1_type>, process1_type> || + t1ProcSeq) { + tot += A_.getInverseLifetime(particle); } - if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value || t2ProcSeq) { - tot += B.GetInverseLifetime(p); + if constexpr (std::is_base_of_v<DecayProcess<process2_type>, process2_type> || + t2ProcSeq) { + tot += B_.getInverseLifetime(particle); } return tot; } - template <typename T1, typename T2> - template <typename TParticle, typename TSecondaries> - EProcessReturn ProcessSequence<T1, T2>::SelectDecay( - TParticle& vP, TSecondaries& vS, [[maybe_unused]] InverseTimeType decay_select, - InverseTimeType& decay_inv_count) { + template <typename TProcess1, typename TProcess2> + // select decay process + template <typename TSecondaryView> + inline EProcessReturn ProcessSequence<TProcess1, TProcess2>::selectDecay( + TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select, + [[maybe_unused]] InverseTimeType decay_inv_sum) { + + // TODO: add check for decay_inv_select>decay_inv_tot + if constexpr (t1ProcSeq) { - // if A is a process sequence --> check inside - const EProcessReturn ret = A.SelectDecay(vP, vS, decay_select, decay_inv_count); - // if A did succeed, stop routine + // 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<DecayProcess<T1type>, T1type>::value) { + } else if constexpr (std::is_base_of_v<DecayProcess<process1_type>, process1_type>) { // if this is not a ContinuousProcess --> evaluate probability - decay_inv_count += A.GetInverseLifetime(vP); + decay_inv_sum += A_.getInverseLifetime(view.parent()); // check if we should execute THIS process and then EXIT - if (decay_select < decay_inv_count) { // more pedagogical: rndm_select < - // decay_inv_count / decay_inv_tot - A.DoDecay(vS); + 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 + } // end branch A_ if constexpr (t2ProcSeq) { - // if A is a process sequence --> check inside - const EProcessReturn ret = B.SelectDecay(vP, vS, decay_select, decay_inv_count); - // if A did succeed, stop routine - if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of<DecayProcess<T2type>, T2type>::value) { + // 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_count += B.GetInverseLifetime(vP); + decay_inv_sum += B_.getInverseLifetime(view.parent()); // check if we should execute THIS process and then EXIT - if (decay_select < decay_inv_count) { - B.DoDecay(vS); + if (decay_inv_select < decay_inv_sum) { + B_.doDecay(view); return EProcessReturn::eDecayed; } - } // end branch B + } // end branch B_ return EProcessReturn::eOk; } + /** + * traits marker to identify objects containing any StackProcesses + **/ + namespace detail { + // need helper alias to achieve this: + template <typename TProcess1, typename TProcess2, + typename = typename std::enable_if_t< + contains_stack_process_v<TProcess1> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> || + contains_stack_process_v<TProcess2> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + int>> + using enable_if_stack = ProcessSequence<TProcess1, TProcess2>; + } // namespace detail + + template <typename TProcess1, typename TProcess2> + struct contains_stack_process<detail::enable_if_stack<TProcess1, TProcess2>> + : std::true_type {}; + } // namespace corsika diff --git a/corsika/framework/process/BaseProcess.hpp b/corsika/framework/process/BaseProcess.hpp index a8a353c581067467318c97a9747c3ab0e052d3ca..d5d939201812222528bbececf3cfecd6a0d7dc3e 100644 --- a/corsika/framework/process/BaseProcess.hpp +++ b/corsika/framework/process/BaseProcess.hpp @@ -8,9 +8,6 @@ n/* #pragma once -#include <corsika/framework/process/ProcessReturn.hpp> // for convenience -#include <type_traits> - namespace corsika { class TDerived; // fwd decl @@ -23,11 +20,14 @@ namespace corsika { are of type BaseProcess<T> \todo rename BaseProcess into just Process + \todo rename _BaseProcess, or find better alternative in + ./Processes/AnalyticProcessors/ExecTime.h, see e.g. how this is done in + ProcessSequence.hpp/make_sequence */ class _BaseProcess {}; template <typename TDerived> - class BaseProcess : _BaseProcess { + struct BaseProcess : _BaseProcess { protected: friend TDerived; @@ -35,16 +35,12 @@ namespace corsika { // derived classes to be created, not // BaseProcess itself - TDerived& GetRef() { return static_cast<TDerived&>(*this); } - const TDerived& GetRef() const { return static_cast<const TDerived&>(*this); } + TDerived& ref() { return static_cast<TDerived&>(*this); } + const TDerived& ref() const { return static_cast<const TDerived&>(*this); } public: // Base processor type for use in other template classes using TProcessType = TDerived; }; - // overwrite the default trait class, to mark BaseProcess<T> as useful process - template <class T> - std::true_type is_process_impl(const BaseProcess<T>* impl); - } // namespace corsika diff --git a/corsika/framework/process/BoundaryCrossingProcess.hpp b/corsika/framework/process/BoundaryCrossingProcess.hpp index 59d2fa043123b652ffba03f8237e0c1f966fde37..80d0246f17ce36f8e316dd9be56e48d4c97e27ca 100644 --- a/corsika/framework/process/BoundaryCrossingProcess.hpp +++ b/corsika/framework/process/BoundaryCrossingProcess.hpp @@ -13,15 +13,8 @@ n/* namespace corsika { - template <typename TDerived> - struct BoundaryCrossingProcess { - auto& GetRef() { return static_cast<TDerived&>(*this); } - auto const& GetRef() const { return static_cast<const TDerived&>(*this); } - template <typename TDerived> class BoundaryCrossingProcess : public BaseProcess<TDerived> { - private: - protected: public: /** * This method is called when a particle crosses the boundary between the nodes @@ -32,7 +25,4 @@ namespace corsika { TVolumeNode const& to); }; - template <class T> - std::true_type is_process_impl(BoundaryCrossingProcess<T> const* impl); - } // namespace corsika diff --git a/corsika/framework/process/ContinuousProcess.hpp b/corsika/framework/process/ContinuousProcess.hpp index b24bed9b1017adbbc0748d2688a91eb6fcb270ca..a397ef79e40db01b5717d4992525f83ef2fabda1 100644 --- a/corsika/framework/process/ContinuousProcess.hpp +++ b/corsika/framework/process/ContinuousProcess.hpp @@ -8,8 +8,8 @@ n/* #pragma once -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/process/ProcessReturn.hpp> // for convenience +#include <corsika/framework/process/BaseProcess.hpp> +#include <corsika/framework/process/ProcessReturn.hpp> namespace corsika { @@ -30,15 +30,11 @@ namespace corsika { // here starts the interface part // -> enforce TDerived to implement DoContinuous... template <typename TParticle, typename TTrack> - EProcessReturn DoContinuous(TParticle&, TTrack const&) const; + EProcessReturn doContinuous(TParticle&, TTrack const&) const; - // -> enforce derived to implement MaxStepLength... - template <typename Particle, typename Track> - LengthType MaxStepLength(Particle const& p, Track const& track) const; + // -> enforce TDerived to implement MaxStepLength... + template <typename TParticle, typename TTrack> + units::si::LengthType maxStepLength(TParticle const& p, TTrack const& track) const; }; - // overwrite the default trait class, to mark BaseProcess<T> as useful process - template <class T> - std::true_type is_process_impl(const ContinuousProcess<T>* impl); - } // namespace corsika diff --git a/corsika/framework/process/DecayProcess.hpp b/corsika/framework/process/DecayProcess.hpp index 84acb4d8c5abcb70287737abc0db1c2f4810a721..6794e8be372b48833553ea599f27bf5f1a897a29 100644 --- a/corsika/framework/process/DecayProcess.hpp +++ b/corsika/framework/process/DecayProcess.hpp @@ -8,10 +8,8 @@ n/* #pragma once -#include <type_traits> - +#include <corsika/framework/process/BaseProcess.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/process/ProcessReturn.hpp> namespace corsika { @@ -27,25 +25,19 @@ namespace corsika { template <typename TDerived> struct DecayProcess : BaseProcess<TDerived> { public: - using BaseProcess<TDerived>::GetRef; + using BaseProcess<TDerived>::ref; /// here starts the interface-definition part // -> enforce TDerived to implement DoDecay... template <typename TParticle> - EProcessReturn DoDecay(TParticle&); + EProcessReturn doDecay(TParticle&); - template <typename Particle> - TimeType GetLifetime(Particle& p); + template <typename TParticle> + TimeType getLifetime(TParticle const&); - template <typename Particle> - InverseTimeType GetInverseLifetime(Particle& vP) { - return 1. / GetRef().GetLifetime(vP); + template <typename TParticle> + InverseTimeType getInverseLifetime(TParticle const& particle) { + return 1. / ref().getLifetime(particle); } - /* template <typename TParticle> - corsika::units::si::InverseTimeType GetInverseInteractionLength(TParticle&& particle) - { auto p = std::move(particle); return 1. / GetRef().GetLifetime(p); - }*/ - }; - } // namespace corsika diff --git a/corsika/framework/process/InteractionProcess.hpp b/corsika/framework/process/InteractionProcess.hpp index 13a0dce1eb560ff0fc82e5fa1666e73abe6e5938..1b1c632edbeba9cbd3568cecc3b1833d905004a1 100644 --- a/corsika/framework/process/InteractionProcess.hpp +++ b/corsika/framework/process/InteractionProcess.hpp @@ -8,10 +8,8 @@ n/* #pragma once -#include <type_traits> - +#include <corsika/framework/process/BaseProcess.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/process/ProcessReturn.hpp> namespace corsika { @@ -27,24 +25,21 @@ namespace corsika { template <typename TDerived> class InteractionProcess : public BaseProcess<TDerived> { public: - using BaseProcess<TDerived>::GetRef; + using BaseProcess<TDerived>::ref; /// here starts the interface-definition part // -> enforce TDerived to implement DoInteraction... template <typename TParticle> - EProcessReturn DoInteraction(TParticle&); + EProcessReturn doInteraction(TParticle&); template <typename TParticle> - GrammageType GetInteractionLength(TParticle& p); + corsika::units::si::GrammageType getInteractionLength(TParticle const&); template <typename TParticle> - InverseGrammageType GetInverseInteractionLength(TParticle& p) { - return 1. / GetRef().GetInteractionLength(p); + corsika::units::si::InverseGrammageType getInverseInteractionLength( + TParticle const& particle) { + return 1. / ref().getInteractionLength(particle); } }; - // overwrite the default trait class, to mark BaseProcess<T> as useful process - template <class T> - std::true_type is_process_impl(const InteractionProcess<T>* impl); - } // namespace corsika diff --git a/corsika/framework/process/ProcessReturn.hpp b/corsika/framework/process/ProcessReturn.hpp index 72949ea01358bdc791e605cd8bb7c2f55d526932..c03721cd5ec453c15a772cab77c99ca86b91a5f4 100644 --- a/corsika/framework/process/ProcessReturn.hpp +++ b/corsika/framework/process/ProcessReturn.hpp @@ -39,4 +39,20 @@ namespace corsika { return (static_cast<int>(a) & static_cast<int>(b)) != 0; } + inline bool isOk(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eOk); + } + + inline bool isAbsorbed(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eParticleAbsorbed); + } + + inline bool isDecayed(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eDecayed); + } + + inline bool isInteracted(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eInteracted); + } + } // namespace corsika diff --git a/corsika/framework/process/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp index fdc8565e9a646c64aa6d2d7d8ad23d22bb01258f..be7a93f085534374a3cf791227dd8c7710fd23e0 100644 --- a/corsika/framework/process/ProcessSequence.hpp +++ b/corsika/framework/process/ProcessSequence.hpp @@ -8,9 +8,8 @@ n/* #pragma once -#include <corsika/framework/core/PhysicalUnits.hpp> - #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> @@ -18,15 +17,13 @@ n/* #include <corsika/framework/process/ProcessReturn.hpp> #include <corsika/framework/process/SecondariesProcess.hpp> #include <corsika/framework/process/StackProcess.hpp> - -#include <cmath> -#include <limits> -#include <type_traits> +#include <corsika/framework/process/NullModel.hpp> +#include <corsika/framework/core/PhysicalUnits.hpp> namespace corsika { /** - * FIXME + * \class ProcessSequence A compile time static list of processes. The compiler will @@ -38,26 +35,26 @@ namespace corsika { they are just classes. This allows us to handle both, rvalue as well as lvalue Processes in the ProcessSequence. - \comment Using CRTP pattern, - https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern + The sequence, and the processes use CRTP. */ + template <typename TProcess1, typename TProcess2 = NullModel> class ProcessSequence : public BaseProcess<ProcessSequence<TProcess1, TProcess2>> { - using TProcess1type = typename std::decay_t<TProcess1>; - using TProcess2type = typename std::decay_t<TProcess2>; + using process1_type = typename std::decay_t<TProcess1>; + using process2_type = typename std::decay_t<TProcess2>; - static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>; - static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>; + static bool constexpr t1ProcSeq = is_process_sequence_v<process1_type>; + static bool constexpr t2ProcSeq = is_process_sequence_v<process2_type>; - static bool constexpr t1SwitchProcSeq = is_switch_process_sequence_v<TProcess1type>; - static bool constexpr t2SwitchProcSeq = is_switch_process_sequence_v<TProcess2type>; + static bool constexpr t1SwitchProcSeq = is_switch_process_sequence_v<process1_type>; + static bool constexpr t2SwitchProcSeq = is_switch_process_sequence_v<process2_type>; // make sure only BaseProcess types TProcess1/2 are passed - static_assert(std::is_base_of_v<BaseProcess<TProcess1type>, TProcess1type>, + static_assert(std::is_base_of_v<BaseProcess<process1_type>, process1_type>, "can only use process derived from BaseProcess in " "ProcessSequence, for Process 1"); - static_assert(std::is_base_of_v<BaseProcess<TProcess2type>, TProcess2type>, + static_assert(std::is_base_of_v<BaseProcess<process2_type>, process2_type>, "can only use process derived from BaseProcess in " "ProcessSequence, for Process 2"); @@ -69,18 +66,15 @@ namespace corsika { : A_(in_A) , B_(in_B) {} - // example for a trait-based call: - // void Hello() const { detail::CallHello<T1,T2>::Call(A, B); } - - template <typename Particle, typename VTNType> - EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from, - VTNType const& to); + template <typename TParticle, typename TVTNType> + EProcessReturn doBoundaryCrossing(TParticle& particle, TVTNType const& from, + TVTNType const& to); template <typename TParticle, typename TTrack> - EProcessReturn DoContinuous(TParticle& vP, TTrack& vT); + inline EProcessReturn doContinuous(TParticle& particle, TTrack& vT); template <typename TSecondaries> - EProcessReturn DoSecondaries(TSecondaries& vS); + inline void doSecondaries(TSecondaries& vS); /** The processes of type StackProcess do have an internal counter, @@ -90,53 +84,48 @@ namespace corsika { tested if either A_ or B_ are StackProcess and if they are due for execution. */ - bool CheckStep(); + inline bool checkStep(); /** Execute the StackProcess-es in the ProcessSequence */ template <typename TStack> - EProcessReturn DoStack(TStack& vS); + inline void doStack(TStack& stack); template <typename TParticle, typename TTrack> - LengthType MaxStepLength(TParticle& vP, TTrack& vTrack); - template <typename TParticle> - GrammageType GetTotalInteractionLength(TParticle& vP); + inline LengthType maxStepLength(TParticle& particle, TTrack& vTrack); template <typename TParticle> - inline InverseGrammageType GetTotalInverseInteractionLength(TParticle& vP); + inline GrammageType getInteractionLength(TParticle&& particle) { + return 1. / getInverseInteractionLength(particle); + } template <typename TParticle> - inline InverseGrammageType GetInverseInteractionLength(TParticle& vP); + inline InverseGrammageType getInverseInteractionLength(TParticle&& particle); - template <typename TParticle, typename TSecondaries> - EProcessReturn SelectInteraction(TParticle& vP, TSecondaries& vS, - [[maybe_unused]] InverseGrammageType lambda_select, - InverseGrammageType& lambda_inv_count); - - template <typename TParticle> - TimeType GetTotalLifetime(TParticle& p); + 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> - InverseTimeType GetTotalInverseLifetime(TParticle& p); + inline TimeType getLifetime(TParticle& particle) { + return 1. / getInverseLifetime(particle); + } template <typename TParticle> - InverseTimeType GetInverseLifetime(TParticle& p); + inline InverseTimeType getInverseLifetime(TParticle&& particle); // select decay process - template <typename TParticle, typename TSecondaries> - EProcessReturn SelectDecay(TParticle& vP, TSecondaries& vS, - [[maybe_unused]] InverseTimeType decay_select, - InverseTimeType& decay_inv_count); - - void Init() { - A.Init(); - B.Init(); - } + template <typename TSecondaryView> + inline EProcessReturn selectDecay( + TSecondaryView& view, [[maybe_unused]] InverseTimeType decay_inv_select, + [[maybe_unused]] InverseTimeType decay_inv_sum = InverseTimeType::zero()); }; /** - * \function sequence + * \function make_sequence * * to construct ProcessSequences in a flexible and dynamic way the * `sequence` factory functions are provided @@ -159,15 +148,55 @@ namespace corsika { inline typename std::enable_if_t< std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, typename std::decay_t<TProcess1>>, - ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>> - sequence(TProcess1&& vA, TProcesses&&... vBs) { - return ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>( - vA, sequence(std::forward<TProcesses>(vBs)...)); + ProcessSequence<TProcess1, decltype(make_sequence(std::declval<TProcesses>()...))>> + make_sequence(TProcess1&& vA, TProcesses&&... vBs) { + return ProcessSequence<TProcess1, + decltype(make_sequence(std::declval<TProcesses>()...))>( + vA, make_sequence(std::forward<TProcesses>(vBs)...)); } - /// marker to identify objectas ProcessSequence - template <typename A, typename B> - struct is_process_sequence<corsika::ProcessSequence<A, B>> : std::true_type {}; + template <typename TProcess1, typename TProcess2> + 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>>, + ProcessSequence<TProcess1, TProcess2>> + make_sequence(TProcess1&& vA, TProcess2&& vB) { + return ProcessSequence<TProcess1, TProcess2>(vA, vB); + } + + /** + * \ function make_sequence + * + * also allow a single Process in ProcessSequence, accompany by + * `NullModel` + **/ + template <typename TProcess> + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess>>, + typename std::decay_t<TProcess>>, + ProcessSequence<TProcess, NullModel>> + make_sequence(TProcess&& vA) { + return ProcessSequence<TProcess, NullModel>(vA, NullModel()); + } + + /** + * \class is_process_sequence + * + * traits marker to identify objectas ProcessSequence + **/ + template <typename TProcess1, typename TProcess2> + struct is_process_sequence<ProcessSequence<TProcess1, TProcess2>> : std::true_type { + // only switch on for BaseProcesses + template <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>>, + int>> + is_process_sequence() {} + }; } // namespace corsika diff --git a/corsika/framework/process/ProcessSignature.hpp b/corsika/framework/process/ProcessSignature.hpp deleted file mode 100644 index a7cca793ea6171f9215a64516628ad40b8e0cc64..0000000000000000000000000000000000000000 --- a/corsika/framework/process/ProcessSignature.hpp +++ /dev/null @@ -1,26 +0,0 @@ -n/* - * (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. - */ - -#pragma once - -#define FORCE_SIGNATURE(nameTrait, nameMethod, signatureMethod) \ - template <typename U> \ - class nameTrait { \ - private: \ - template <typename T, T> \ - struct helper; \ - template <typename T> \ - static std::uint8_t check(helper<signatureMethod, &nameMethod>*); \ - template <typename T> \ - static std::uint16_t check(...); \ - \ - public: \ - static constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \ - } - -// FORCE_SIGNATURE(thisMustBeDefined, T::thisMustBeDefined, int(*)(void)); diff --git a/corsika/framework/process/SecondariesProcess.hpp b/corsika/framework/process/SecondariesProcess.hpp index 273d1a730fe2686ff8086f4ae2a0cdcddcd58c18..e7e80a8673a85a23c5bf1186b1f532f5e25ead3e 100644 --- a/corsika/framework/process/SecondariesProcess.hpp +++ b/corsika/framework/process/SecondariesProcess.hpp @@ -8,8 +8,8 @@ #pragma once +#include <corsika/framework/process/BaseProcess.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/process/ProcessReturn.hpp> namespace corsika { @@ -28,11 +28,7 @@ namespace corsika { /// here starts the interface-definition part // -> enforce TDerived to implement DoSecondaries... template <typename TSecondaries> - inline void DoSecondaries(TSecondaries&); + inline void doSecondaries(TSecondaries&); }; - // overwrite the default trait class, to mark BaseProcess<T> as useful process - template <class T> - std::true_type is_process_impl(const SecondariesProcess<T>* impl); - } // namespace corsika diff --git a/corsika/framework/process/StackProcess.hpp b/corsika/framework/process/StackProcess.hpp index 162bb789b0d4e8fbcee34f71cba6cc43b7438650..5eeb2bb4884cda3ab2602c419de0a3eae9d2e6b6 100644 --- a/corsika/framework/process/StackProcess.hpp +++ b/corsika/framework/process/StackProcess.hpp @@ -8,8 +8,8 @@ #pragma once +#include <corsika/framework/process/BaseProcess.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/process/ProcessReturn.hpp> // for convenience namespace corsika { @@ -29,15 +29,15 @@ namespace corsika { public: StackProcess() = delete; StackProcess(const unsigned int nStep) - : fNStep(nStep) {} + : nStep_(nStep) {} /// here starts the interface-definition part // -> enforce TDerived to implement DoStack... template <typename TStack> - inline void DoStack(TStack&); + inline void doStack(TStack&); - int GetStep() const { return fIStep; } - bool CheckStep() { return !((++fIStep) % fNStep); } + int getStep() const { return iStep_; } + bool checkStep() { return !((++iStep_) % nStep_); } private: /** @@ -46,13 +46,9 @@ namespace corsika { "fIStep modulo fNStep" @{ */ - unsigned int fNStep = 0; - unsigned long int fIStep = 0; + unsigned int nStep_ = 0; + unsigned long int iStep_ = 0; //! @} }; - // overwrite the default trait class, to mark BaseProcess<T> as useful process - template <class T> - std::true_type is_process_impl(const StackProcess<T>* impl); - } // namespace corsika diff --git a/tests/framework/CMakeLists.txt b/tests/framework/CMakeLists.txt index 3def966d1729e33ba9461ead21bb477f459be6d6..194438a92c399273dbe31bacbacdf0cede74f2d8 100644 --- a/tests/framework/CMakeLists.txt +++ b/tests/framework/CMakeLists.txt @@ -12,7 +12,8 @@ set (test_framework_sources testLogging.cpp TestMain.cpp testParticles.cpp - #testProcessSequence.cpp #FIXME: reenable this + testNullModel.cpp + testProcessSequence.cpp testRandom.cpp testSecondaryView.cpp testStackInterface.cpp diff --git a/tests/framework/testCascade.cpp b/tests/framework/testCascade.cpp index f8b0d8734bd377b6c72067d8e6672e2394332950..6fdbb86abacb8d35f6167970997727e73f5e5b9b 100644 --- a/tests/framework/testCascade.cpp +++ b/tests/framework/testCascade.cpp @@ -11,9 +11,9 @@ #include <corsika/framework/core/Cascade.hpp> #include <corsika/framework/sequence/ProcessSequence.hpp> -#include <corsika/process/NullModel.hpp> -#include <corsika/process/StackInspector.hpp> -#include <corsika/process/TrackingLine.hpp> +#include <corsika/framework/sequence/NullModel.hpp> +#include <corsika/modules/StackInspector.hpp> +#include <corsika/modules/TrackingLine.hpp> #include <corsika/framework/core/ParticleProperties.hpp> diff --git a/tests/framework/testProcessSequence.cpp b/tests/framework/testProcessSequence.cpp index 53ae9e26fb0a6f2e289652abf1a7f36e8641fc4f..c5f2668a86d3a24cbbe2a87d848b3b9c537e7caa 100644 --- a/tests/framework/testProcessSequence.cpp +++ b/tests/framework/testProcessSequence.cpp @@ -7,6 +7,8 @@ */ #include <corsika/framework/process/ProcessSequence.hpp> +#include <corsika/framework/process/SwitchProcessSequence.hpp> +#include <corsika/framework/core/PhysicalUnits.hpp> #include <catch2/catch.hpp> @@ -15,8 +17,6 @@ #include <iostream> #include <typeinfo> -using namespace corsika; -using namespace corsika::units::si; using namespace corsika; using namespace std; @@ -41,7 +41,7 @@ public: } template <typename D, typename T> - inline EProcessReturn DoContinuous(D& d, T&) const { + inline EProcessReturn doContinuous(D& d, T&) const { cout << "ContinuousProcess1::DoContinuous" << endl; checkCont |= 1; for (int i = 0; i < nData; ++i) d.data_[i] += 0.933; @@ -60,7 +60,7 @@ public: } template <typename D, typename T> - inline EProcessReturn DoContinuous(D& d, T&) const { + inline EProcessReturn doContinuous(D& d, T&) const { cout << "ContinuousProcess2::DoContinuous" << endl; checkCont |= 2; for (int i = 0; i < nData; ++i) d.data_[i] += 0.111; @@ -79,7 +79,7 @@ public: } template <typename D, typename T> - inline EProcessReturn DoContinuous(D& d, T&) const { + inline EProcessReturn doContinuous(D& d, T&) const { cout << "ContinuousProcess3::DoContinuous" << endl; checkCont |= 4; for (int i = 0; i < nData; ++i) d.data_[i] += 0.333; @@ -96,11 +96,17 @@ public: } template <typename TView> - inline EProcessReturn DoInteraction(TView& v) const { + inline EProcessReturn doInteraction(TView& v) const { checkInteract |= 1; for (int i = 0; i < nData; ++i) v.parent().data_[i] += 1 + i; return EProcessReturn::eOk; } + + template <typename TParticle> + GrammageType getInteractionLength(TParticle&) const { + return 10_g / square(1_cm); + } + private: [[maybe_unused]] int fV; }; @@ -116,14 +122,14 @@ public: } template <typename TView> - inline EProcessReturn DoInteraction(TView& v) const { + inline EProcessReturn doInteraction(TView& v) const { checkInteract |= 2; for (int i = 0; i < nData; ++i) v.parent().data_[i] /= 1.1; cout << "Process2::DoInteraction" << endl; return EProcessReturn::eOk; } template <typename Particle> - GrammageType GetInteractionLength(Particle&) const { + GrammageType getInteractionLength(Particle&) const { cout << "Process2::GetInteractionLength" << endl; return 20_g / (1_cm * 1_cm); } @@ -140,14 +146,14 @@ public: } template <typename TView> - inline EProcessReturn DoInteraction(TView& v) const { + inline EProcessReturn doInteraction(TView& v) const { checkInteract |= 4; for (int i = 0; i < nData; ++i) v.parent().data_[i] *= 1.01; cout << "Process3::DoInteraction" << endl; return EProcessReturn::eOk; } template <typename Particle> - GrammageType GetInteractionLength(Particle&) const { + GrammageType getInteractionLength(Particle&) const { cout << "Process3::GetInteractionLength" << endl; return 30_g / (1_cm * 1_cm); } @@ -164,34 +170,31 @@ public: } template <typename D, typename T> - inline EProcessReturn DoContinuous(D& d, T&) const { + inline EProcessReturn doContinuous(D& d, T&) const { std::cout << "Base::DoContinuous" << std::endl; checkCont |= 8; for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; } return EProcessReturn::eOk; } template <typename TView> - EProcessReturn DoInteraction(TView&) const { + EProcessReturn doInteraction(TView&) const { checkInteract |= 8; return EProcessReturn::eOk; } }; class Decay1 : public DecayProcess<Decay1> { - [[maybe_unused]] int fV = 0; - -public: Decay1(const int) { cout << "Decay1()" << endl; globalCount++; } template <typename Particle> - TimeType GetLifetime(Particle&) const { + TimeType getLifetime(Particle&) const { return 1_s; } template <typename TView> - EProcessReturn DoDecay(TView&) const { + EProcessReturn doDecay(TView&) const { checkDecay |= 1; return EProcessReturn::eOk; } @@ -206,11 +209,11 @@ public: } template <typename Particle> - TimeType GetLifetime(Particle&) const { + TimeType getLifetime(Particle&) const { return 2_s; } template <typename TView> - EProcessReturn DoDecay(TView&) const { + EProcessReturn doDecay(TView&) const { checkDecay |= 2; return EProcessReturn::eOk; } @@ -223,11 +226,11 @@ public: Stack1(const int n) : StackProcess(n) {} template <typename TStack> - EProcessReturn DoStack(TStack&) { + EProcessReturn doStack(TStack&) { fCount++; return EProcessReturn::eOk; } - int GetCount() const { return fCount; } + int getCount() const { return fCount; } }; struct DummyStack {}; @@ -256,16 +259,16 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { Process4 m4(3); CHECK(globalCount == 4); - auto sequence1 = process::sequence(m1, m2, m3, m4); + auto sequence1 = make_sequence(m1, m2, m3, m4); CHECK(is_process_sequence_v<decltype(sequence1)> == true); 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); - auto sequence2 = process::sequence(m1, m2, m3); + auto sequence2 = make_sequence(m1, m2, m3); CHECK(is_process_sequence_v<decltype(sequence2)> == true); - auto sequence3 = process::sequence(m4); + auto sequence3 = make_sequence(m4); CHECK(is_process_sequence_v<decltype(sequence3)> == true); } @@ -277,9 +280,9 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { DummyData particle; - auto sequence2 = sequence(cp1, m2, m3); - GrammageType const tot = sequence2.GetInteractionLength(particle); - InverseGrammageType const tot_inv = sequence2.GetInverseInteractionLength(particle); + 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); @@ -296,9 +299,9 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { DummyData particle; - auto sequence2 = sequence(cp1, m2, m3, d3); - TimeType const tot = sequence2.GetLifetime(particle); - InverseTimeType const tot_inv = sequence2.GetInverseLifetime(particle); + 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); @@ -313,7 +316,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { Process2 m2(2); // /= 1.1 Process3 m3(3); // *= 1.01 - auto sequence2 = sequence(cp1, m2, m3, cp2); + auto sequence2 = make_sequence(cp1, m2, m3, cp2); DummyData particle; DummyTrajectory track; @@ -329,7 +332,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { cout << "Running loop with n=" << nLoop << endl; for (int iLoop = 0; iLoop < nLoop; ++iLoop) { for (int i = 0; i < nData; ++i) { test_data[i] += 0.933 + 0.111; } - sequence2.DoContinuous(particle, track); + sequence2.doContinuous(particle, track); } for (int i = 0; i < nData; i++) { cout << "data_[" << i << "]=" << particle.data_[i] << endl; @@ -344,20 +347,20 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { Stack1 s1(1); Stack1 s2(2); - auto sequence = process::sequence(s1, s2); + auto sequence1 = make_sequence(s1, s2); DummyStack stack; const int nLoop = 20; - for (int i = 0; i < nLoop; ++i) { sequence.DoStack(stack); } + for (int i = 0; i < nLoop; ++i) { sequence1.doStack(stack); } - CHECK(s1.GetCount() == 20); - CHECK(s2.GetCount() == 10); + 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); + 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); @@ -366,14 +369,106 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { } } -/* - Note: there is a fine-grained dedicated test-suite for SwitchProcess - in Processes/SwitchProcess/testSwtichProcess - */ -/* -TEST_CASE("SwitchProcess") { - Process1 p1(0); - Process2 p2(0); - switch_process::SwitchProcess s(p1, p2, 10_GeV); - REQUIRE(is_switch_process_v<decltype(s)>); - }*/ +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); + } +}