diff --git a/corsika/detail/framework/core/ParticleProperties.inl b/corsika/detail/framework/core/ParticleProperties.inl index 6fc0bea950f383c6e12e537eabcd95cf66cbe4ca..b478b1e17f3f12f850482c6c652c8c884f104656 100644 --- a/corsika/detail/framework/core/ParticleProperties.inl +++ b/corsika/detail/framework/core/ParticleProperties.inl @@ -13,6 +13,14 @@ namespace corsika { + HEPEnergyType constexpr get_energy_threshold(Code const p) { + return particle::detail::thresholds[static_cast<CodeIntType>(p)]; + } + + void constexpr set_energy_threshold(Code const p, HEPEnergyType const val) { + particle::detail::thresholds[static_cast<CodeIntType>(p)] = val; + } + HEPMassType constexpr get_mass(Code const p) { if (p == Code::Nucleus) throw std::runtime_error("Cannot GetMass() of particle::Nucleus -> unspecified"); diff --git a/corsika/detail/framework/geometry/FourVector.inl b/corsika/detail/framework/geometry/FourVector.inl index 6c0a039e5466ef46d2d3014b7e91a6f0621c922c..135790bfcfa83efaf1a78f218228d0c2557f5853 100644 --- a/corsika/detail/framework/geometry/FourVector.inl +++ b/corsika/detail/framework/geometry/FourVector.inl @@ -95,7 +95,7 @@ namespace corsika { template <typename TTimeType, typename TSpaceVecType> typename FourVector<TTimeType, TSpaceVecType>::norm_type - FourVector<TTimeType, TSpaceVecType>::operator*(FourVector const& b) { + FourVector<TTimeType, TSpaceVecType>::operator*(FourVector const& b) { if constexpr (std::is_same<time_type, decltype(std::declval<space_type>() / meter * second)>::value) return timeLike_ * b.timeLike_ * constants::cSquared - spaceLike_.norm(); diff --git a/corsika/detail/framework/geometry/QuantityVector.inl b/corsika/detail/framework/geometry/QuantityVector.inl index 151b35daec64d4909ef3492e80ee3c0c57a64429..994f70689a97d2cc6f183f7d6e03e9558f08b7ba 100644 --- a/corsika/detail/framework/geometry/QuantityVector.inl +++ b/corsika/detail/framework/geometry/QuantityVector.inl @@ -17,8 +17,8 @@ namespace corsika { template <typename TDimension> - inline typename QuantityVector<TDimension>::quantity_type QuantityVector<TDimension>:: - operator[](size_t const index) const { + inline typename QuantityVector<TDimension>::quantity_type + QuantityVector<TDimension>::operator[](size_t const index) const { return quantity_type(phys::units::detail::magnitude_tag, eigenVector_[index]); } diff --git a/corsika/detail/media/WeightProvider.inl b/corsika/detail/media/WeightProvider.inl index af9849aa3ca75b9bdaeefc661d56232f1ab895f4..c075b236350127c9978fb7c08d87ed035292e5a8 100644 --- a/corsika/detail/media/WeightProvider.inl +++ b/corsika/detail/media/WeightProvider.inl @@ -20,7 +20,7 @@ namespace corsika { template <class AConstIterator, class BConstIterator> typename WeightProviderIterator<AConstIterator, BConstIterator>::value_type - WeightProviderIterator<AConstIterator, BConstIterator>::operator*() const { + WeightProviderIterator<AConstIterator, BConstIterator>::operator*() const { return ((*aIter_) * (*bIter_)).magnitude(); } diff --git a/corsika/detail/modules/ParticleCut.inl b/corsika/detail/modules/ParticleCut.inl index da19bce2727550a09a3ccede6b08a8ead7ca51ec..7a22b4d719beddef778acab9861b65ba7578217f 100644 --- a/corsika/detail/modules/ParticleCut.inl +++ b/corsika/detail/modules/ParticleCut.inl @@ -12,68 +12,114 @@ namespace corsika { - ParticleCut::ParticleCut(const HEPEnergyType eCut, bool em, bool inv) - : energy_cut_(eCut) - , doCutEm_(em) + ParticleCut::ParticleCut(HEPEnergyType const eEleCut, HEPEnergyType const ePhoCut, + HEPEnergyType const eHadCut, HEPEnergyType const eMuCut, + bool const inv) + : doCutEm_(false) , doCutInv_(inv) , energy_(0_GeV) , em_energy_(0_GeV) , em_count_(0) , inv_energy_(0_GeV) - , inv_count_(0) {} + , inv_count_(0) { + for (auto p : get_all_particles()) + if (is_hadron(p)) + set_energy_threshold(p, eHadCut); + else if (is_muon(p)) + set_energy_threshold(p, eMuCut); + else if (p == Code::Electron || p == Code::Positron) + set_energy_threshold(p, eEleCut); + else if (p == Code::Gamma) + set_energy_threshold(p, ePhoCut); + else if (p == Code::Nucleus) + // nuclei have same threshold as hadrons on the nucleon level. + set_energy_threshold(p, eHadCut); + CORSIKA_LOG_DEBUG( + "setting thresholds: electrons = {} GeV, photons = {} GeV, hadrons = {} GeV, " + "muons = {} GeV", + eEleCut / 1_GeV, ePhoCut / 1_GeV, eHadCut / 1_GeV, eMuCut / 1_GeV); + printThresholds(); + } + + ParticleCut::ParticleCut(HEPEnergyType const eHadCut, HEPEnergyType const eMuCut, + bool const inv) + : doCutEm_(true) + , doCutInv_(inv) + , energy_(0_GeV) + , em_energy_(0_GeV) + , em_count_(0) + , inv_energy_(0_GeV) + , inv_count_(0) { + + for (auto p : get_all_particles()) + if (is_hadron(p)) + set_energy_threshold(p, eHadCut); + else if (is_muon(p)) + set_energy_threshold(p, eMuCut); + CORSIKA_LOG_DEBUG( + "setting thresholds: hadrons = {} GeV, " + "muons = {} GeV", + eHadCut / 1_GeV, eMuCut / 1_GeV); + printThresholds(); + } + + ParticleCut::ParticleCut(HEPEnergyType const eCut, bool const em, bool const inv) + : doCutEm_(em) + , doCutInv_(inv) + , energy_(0_GeV) + , em_energy_(0_GeV) + , em_count_(0) + , inv_energy_(0_GeV) + , inv_count_(0) { + for (auto p : get_all_particles()) set_energy_threshold(p, eCut); + CORSIKA_LOG_DEBUG("setting threshold for all particles to {} GeV", eCut / 1_GeV); + printThresholds(); + } + + ParticleCut::ParticleCut( + std::unordered_map<Code const, HEPEnergyType const> const& eCuts, bool const em, + bool const inv) + : doCutEm_(em) + , doCutInv_(inv) + , energy_(0_GeV) + , em_energy_(0_GeV) + , em_count_(0) + , inv_energy_(0_GeV) + , inv_count_(0) { + set_energy_thresholds(eCuts); + CORSIKA_LOG_DEBUG("setting threshold particles individually"); + printThresholds(); + } template <typename TParticle> bool ParticleCut::isBelowEnergyCut(TParticle const& vP) const { auto const energyLab = vP.getEnergy(); + auto const pid = vP.getPID(); // nuclei - if (vP.getPID() == Code::Nucleus) { + if (pid == Code::Nucleus) { // calculate energy per nucleon auto const ElabNuc = energyLab / vP.getNuclearA(); - return (ElabNuc < energy_cut_); + return (ElabNuc < get_energy_threshold(pid)); } else { - return (energyLab < energy_cut_); - } - } - - bool ParticleCut::isEmParticle(Code vCode) const { - // FOR NOW: switch - switch (vCode) { - case Code::Gamma: - case Code::Electron: - case Code::Positron: - return true; - default: - return false; + return (energyLab < get_energy_threshold(pid)); } } - bool ParticleCut::isInvisible(Code vCode) const { - switch (vCode) { - case Code::NuE: - case Code::NuEBar: - case Code::NuMu: - case Code::NuMuBar: - return true; - - default: - return false; - } - } + bool ParticleCut::isInvisible(Code const& vCode) const { return is_neutrino(vCode); } template <typename TParticle> - bool ParticleCut::checkCutParticle(const TParticle& particle) { + bool ParticleCut::checkCutParticle(TParticle const& particle) { - const Code pid = particle.getPID(); + Code const pid = particle.getPID(); HEPEnergyType energy = particle.getEnergy(); - CORSIKA_LOG_DEBUG(fmt::format("ParticleCut: checking {}, E= {} GeV, EcutTot={} GeV", - pid, energy / 1_GeV, - (em_energy_ + inv_energy_ + energy_) / 1_GeV)); - if (doCutEm_ && isEmParticle(pid)) { + CORSIKA_LOG_DEBUG("ParticleCut: checking {}, E= {} GeV, EcutTot={} GeV", pid, + energy / 1_GeV, (em_energy_ + inv_energy_ + energy_) / 1_GeV); + if (doCutEm_ && is_em(pid)) { CORSIKA_LOG_DEBUG("removing em. particle..."); em_energy_ += energy; em_count_ += 1; return true; - } else if (doCutInv_ && isInvisible(pid)) { + } else if (doCutInv_ && is_neutrino(pid)) { CORSIKA_LOG_DEBUG("removing inv. particle..."); inv_energy_ += energy; inv_count_ += 1; @@ -110,6 +156,13 @@ namespace corsika { return ProcessReturn::Ok; } + void ParticleCut::printThresholds() { + for (auto p : get_all_particles()) { + auto const Eth = get_energy_threshold(p); + CORSIKA_LOG_INFO("energy threshold for particle {} is {} GeV", p, Eth / 1_GeV); + } + } + void ParticleCut::showResults() { CORSIKA_LOG_INFO( " ******************************\n" diff --git a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl index 776531540cce808be3fb017c40865d6d1bddc373..1f3d0e9303cb60f40fb588ecad70034c634dd1c8 100644 --- a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl +++ b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl @@ -26,11 +26,10 @@ namespace corsika { return sqrt((Elab - m) * (Elab + m)); }; - BetheBlochPDG::BetheBlochPDG(ShowerAxis const& shower_axis, HEPEnergyType emCut) + BetheBlochPDG::BetheBlochPDG(ShowerAxis const& shower_axis) : dX_(10_g / square(1_cm)) // profile binning , dX_threshold_(0.0001_g / square(1_cm)) , shower_axis_(shower_axis) - , emCut_(emCut) , profile_(int(shower_axis.getMaximumX() / dX_) + 1) {} HEPEnergyType BetheBlochPDG::getBetheBloch(setup::Stack::particle_type const& p, @@ -170,8 +169,9 @@ namespace corsika { auto const dEdX = -getTotalEnergyLoss(vParticle, dX) / dX; // dE > 0 //~ auto const Ekin = vParticle.getEnergy() - vParticle.getMass(); - // in any case: never go below 0.99*emCut_ This needs to be - // slightly smaller than emCut_ since, either this Step is limited + auto const emCut = get_energy_threshold(vParticle.getPID()); + // in any case: never go below 0.99*emCut This needs to be + // slightly smaller than emCut since, either this Step is limited // by energy_lim, then the particle is stopped in a very short // range (before doing anythin else) and is then removed // instantly. The exact position where it reaches emCut is not @@ -179,7 +179,7 @@ namespace corsika { // afterwards. // const auto energy = vParticle.getEnergy(); - auto energy_lim = std::max(0.9 * energy, 0.99 * emCut_); + auto energy_lim = std::max(0.9 * energy, 0.99 * emCut); auto const maxGrammage = (energy - energy_lim) / dEdX; diff --git a/corsika/detail/modules/proposal/ContinuousProcess.inl b/corsika/detail/modules/proposal/ContinuousProcess.inl index 16d419b0be200bb0d65b8748770818491d5e53b2..8bfbd705b8bb0dfc19d1e7efe79252aa5a6a69be 100644 --- a/corsika/detail/modules/proposal/ContinuousProcess.inl +++ b/corsika/detail/modules/proposal/ContinuousProcess.inl @@ -32,7 +32,9 @@ namespace corsika::proposal { // interpolate the crosssection for given media and energy cut. These may // take some minutes if you have to build the tables and cannot read the // from disk - auto c = p_cross->second(media.at(comp.getHash()), emCut_); + auto const emCut = get_energy_threshold( + code); //! energy thresholds globally defined for individual particles + auto c = p_cross->second(media.at(comp.getHash()), emCut); // Build displacement integral and scattering object and interpolate them too and // saved in the calc map by a key build out of a hash of composed of the component and @@ -45,9 +47,8 @@ namespace corsika::proposal { } template <> - ContinuousProcess::ContinuousProcess(setup::Environment const& _env, - HEPEnergyType _emCut) - : ProposalProcessBase(_env, _emCut) {} + ContinuousProcess::ContinuousProcess(setup::Environment const& _env) + : ProposalProcessBase(_env) {} template <> void ContinuousProcess::scatter(setup::Stack::particle_type& vP, @@ -115,21 +116,24 @@ namespace corsika::proposal { template <> LengthType ContinuousProcess::getMaxStepLength(setup::Stack::particle_type const& vP, setup::Trajectory const& vT) { - - if (!canInteract(vP.getPID())) return meter * std::numeric_limits<double>::infinity(); + auto const code = vP.getPID(); + if (!canInteract(code)) return meter * std::numeric_limits<double>::infinity(); // Limit the step size of a conitnuous loss. The maximal continuous loss seems to be a // hyper parameter which must be adjusted. // - // in any case: never go below 0.99*emCut_ This needs to be - // slightly smaller than emCut_ since, either this Step is limited + auto const emCut = get_energy_threshold( + code); //! energy thresholds globally defined for individual particles + + // in any case: never go below 0.99*emCut This needs to be + // slightly smaller than emCut since, either this Step is limited // by energy_lim, then the particle is stopped in a very short // range (before doing anythin else) and is then removed // instantly. The exact position where it reaches emCut is not // important, the important fact is that its E_kin is zero // afterwards. // - auto energy_lim = std::max(0.9 * vP.getEnergy(), 0.99 * emCut_); + auto energy_lim = std::max(0.9 * vP.getEnergy(), 0.99 * emCut); // solving the track integral for giving energy lim auto c = getCalculator(vP, calc); diff --git a/corsika/detail/modules/proposal/Interaction.inl b/corsika/detail/modules/proposal/Interaction.inl index 853302967fcc0bd460f6181f593254c9335b10bb..4874bda1f7fb7f6ca89d898cf7f1e01e8a51b791 100644 --- a/corsika/detail/modules/proposal/Interaction.inl +++ b/corsika/detail/modules/proposal/Interaction.inl @@ -24,8 +24,8 @@ namespace corsika::proposal { template <> - Interaction::Interaction(setup::Environment const& _env, HEPEnergyType _emCut) - : ProposalProcessBase(_env, _emCut) {} + Interaction::Interaction(setup::Environment const& _env) + : ProposalProcessBase(_env) {} void Interaction::buildCalculator(Code code, NuclearComposition const& comp) { // search crosssection builder for given particle @@ -36,7 +36,10 @@ namespace corsika::proposal { // interpolate the crosssection for given media and energy cut. These may // take some minutes if you have to build the tables and cannot read the // from disk - auto c = p_cross->second(media.at(comp.getHash()), emCut_); + auto const emCut = get_energy_threshold( + code); //! energy thresholds globally defined for individual particles + + auto c = p_cross->second(media.at(comp.getHash()), emCut); // Look which interactions take place and build the corresponding // interaction and secondarie builder. The interaction integral will diff --git a/corsika/detail/modules/proposal/ProposalProcessBase.inl b/corsika/detail/modules/proposal/ProposalProcessBase.inl index b71b0fa9b1f9aff2784796588fb4ea7017a17d1f..21d0cce576f306055d745a8d50a6a2baa3f21466 100644 --- a/corsika/detail/modules/proposal/ProposalProcessBase.inl +++ b/corsika/detail/modules/proposal/ProposalProcessBase.inl @@ -30,10 +30,8 @@ namespace corsika::proposal { return false; } - ProposalProcessBase::ProposalProcessBase(setup::Environment const& _env, - HEPEnergyType _emCut) - : emCut_(_emCut) - , RNG_(RNGManager::getInstance().getRandomStream("proposal")) { + ProposalProcessBase::ProposalProcessBase(setup::Environment const& _env) + : RNG_(RNGManager::getInstance().getRandomStream("proposal")) { _env.getUniverse()->walk([&](auto& vtn) { if (vtn.hasModelProperties()) { const auto& prop = vtn.getModelProperties(); diff --git a/corsika/framework/core/ParticleProperties.hpp b/corsika/framework/core/ParticleProperties.hpp index 2deb03a865c6d32e37f4c274c83a604f72fecb04..85227425c42bf584ffcde2cea20c75d11570709e 100644 --- a/corsika/framework/core/ParticleProperties.hpp +++ b/corsika/framework/core/ParticleProperties.hpp @@ -25,6 +25,7 @@ #include <iosfwd> #include <string_view> #include <type_traits> +#include <unordered_map> #include <corsika/framework/core/PhysicalUnits.hpp> @@ -50,6 +51,20 @@ namespace corsika { int16_t constexpr get_charge_number(Code); //!< electric charge in units of e ElectricChargeType constexpr get_charge(Code); //!< electric charge HEPMassType constexpr get_mass(Code); //!< mass + HEPEnergyType constexpr get_energy_threshold( + Code const); //!< get energy threshold below which the particle is discarded, by + //!< default set to particle mass + void constexpr set_energy_threshold( + Code const, HEPEnergyType const); //!< set energy threshold below which the particle + //!< is discarded + + inline void set_energy_threshold(std::pair<Code const, HEPEnergyType const> p) { + set_energy_threshold(p.first, p.second); + } + inline void set_energy_thresholds( + std::unordered_map<Code const, HEPEnergyType const> const& eCuts) { + for (auto v : eCuts) set_energy_threshold(v); + } //! Particle code according to PDG, "Monte Carlo Particle Numbering Scheme" PDGCode constexpr get_PDG(Code); diff --git a/corsika/modules/ParticleCut.hpp b/corsika/modules/ParticleCut.hpp index 7abc7d6be02517cf78c8bc19749387cbf7055a23..ca7f87013d59cf2cbab4194c7e0fa02b31101c42 100644 --- a/corsika/modules/ParticleCut.hpp +++ b/corsika/modules/ParticleCut.hpp @@ -8,6 +8,8 @@ #pragma once +#include <unordered_map> + #include <corsika/framework/core/ParticleProperties.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> #include <corsika/framework/process/SecondariesProcess.hpp> @@ -17,12 +19,35 @@ #include <corsika/setup/SetupTrajectory.hpp> namespace corsika { - + /** + simple ParticleCut process. Goes through the secondaries of an interaction and + removes particles according to their energy. Particles with a time delay of more than + 10ms are removed as well. Invisible particles (neutrinos) can be removed if selected. + **/ class ParticleCut : public SecondariesProcess<ParticleCut>, public ContinuousProcess<ParticleCut> { public: - ParticleCut(const HEPEnergyType eCut, bool em, bool inv); + /** + * particle cut with energy thresholds for electrons, photons, + * hadrons (including nuclei with energy per nucleon) and muons + * invisible particles (neutrinos) can be cut or not + **/ + ParticleCut(HEPEnergyType const eEleCut, HEPEnergyType const ePhoCut, + HEPEnergyType const eHadCut, HEPEnergyType const eMuCut, bool const inv); + + //! simple cut. hadrons and muons are cut by threshold. EM particles are all + //! discarded. + ParticleCut(HEPEnergyType const eHadCut, HEPEnergyType const euCut, bool const inv); + + //! simplest cut. all particles have same threshold. EM particles can be set to be + //! discarded altogether. + ParticleCut(HEPEnergyType const eCut, bool const em, bool const inv); + + //! threshold for specific particles redefined. EM and invisible particles can be set + //! to be discarded altogether. + ParticleCut(std::unordered_map<Code const, HEPEnergyType const> const& eCuts, + bool const em, bool const inv); void doSecondaries(corsika::setup::StackView&); ProcessReturn doContinuous(corsika::setup::Stack::particle_type& vParticle, @@ -32,10 +57,14 @@ namespace corsika { return meter * std::numeric_limits<double>::infinity(); } + void printThresholds(); void showResults(); void reset(); - HEPEnergyType getECut() const { return energy_cut_; } + HEPEnergyType getElectronECut() const { return get_energy_threshold(Code::Electron); } + HEPEnergyType getPhotonECut() const { return get_energy_threshold(Code::Gamma); } + HEPEnergyType getMuonECut() const { return get_energy_threshold(Code::MuPlus); } + HEPEnergyType getHadronECut() const { return get_energy_threshold(Code::Proton); } HEPEnergyType getInvEnergy() const { return inv_energy_; } HEPEnergyType getCutEnergy() const { return energy_; } HEPEnergyType getEmEnergy() const { return em_energy_; } @@ -44,15 +73,15 @@ namespace corsika { private: template <typename TParticle> - bool checkCutParticle(const TParticle& p); + bool checkCutParticle(TParticle const& p); template <typename TParticle> bool isBelowEnergyCut(TParticle const&) const; - bool isEmParticle(Code) const; - bool isInvisible(Code) const; + + //! defines which particles are invisible, by default only neutrinos + bool isInvisible(Code const&) const; private: - HEPEnergyType energy_cut_; bool doCutEm_; bool doCutInv_; HEPEnergyType energy_ = 0 * electronvolt; diff --git a/corsika/modules/energy_loss/BetheBlochPDG.hpp b/corsika/modules/energy_loss/BetheBlochPDG.hpp index 3e64567b974c9dfdb71b6f67c99e7877dbd6d39d..f8e8759376a3833bd3f7df438b2dbe4132c5e3c8 100644 --- a/corsika/modules/energy_loss/BetheBlochPDG.hpp +++ b/corsika/modules/energy_loss/BetheBlochPDG.hpp @@ -41,11 +41,13 @@ namespace corsika { using MeVgcm2 = decltype(1e6 * electronvolt / gram * square(1e-2 * meter)); public: - BetheBlochPDG(ShowerAxis const& showerAxis, HEPEnergyType emCut); + BetheBlochPDG(ShowerAxis const& showerAxis); ProcessReturn doContinuous(setup::Stack::particle_type&, setup::Trajectory const&); LengthType getMaxStepLength(setup::Stack::particle_type const&, - setup::Trajectory const&) const; + setup::Trajectory const&) + const; //! limited by the energy threshold! By default the limit is the particle + //! rest mass, i.e. kinetic energy is zero static HEPEnergyType getBetheBloch(setup::Stack::particle_type const&, const GrammageType); static HEPEnergyType getRadiationLosses(setup::Stack::particle_type const&, @@ -66,7 +68,6 @@ namespace corsika { GrammageType const dX_ = 10_g / square(1_cm); // profile binning GrammageType const dX_threshold_ = 0.0001_g / square(1_cm); ShowerAxis const& shower_axis_; - HEPEnergyType emCut_; HEPEnergyType energy_lost_ = HEPEnergyType::zero(); std::vector<HEPEnergyType> profile_; // longitudinal profile }; diff --git a/corsika/modules/proposal/ContinuousProcess.hpp b/corsika/modules/proposal/ContinuousProcess.hpp index 3bf53b145246392848f6ba09cbd293ac722c0a80..3b8976f3ac6bfe7a6d5251740782e4ca8fec89bc 100644 --- a/corsika/modules/proposal/ContinuousProcess.hpp +++ b/corsika/modules/proposal/ContinuousProcess.hpp @@ -52,7 +52,7 @@ namespace corsika::proposal { //! compositions and stochastic description limited by the particle cut. //! template <typename TEnvironment> - ContinuousProcess(TEnvironment const&, HEPEnergyType _emCut); + ContinuousProcess(TEnvironment const&); //! //! Multiple Scattering of the lepton. Stochastic deflection is not yet taken into diff --git a/corsika/modules/proposal/Interaction.hpp b/corsika/modules/proposal/Interaction.hpp index 69f27cca42b728cd52a77883cd377c6c3ccafc36..c6a389b1e2dcfcbb5308dcd53b9dd7b33589ef00 100644 --- a/corsika/modules/proposal/Interaction.hpp +++ b/corsika/modules/proposal/Interaction.hpp @@ -48,7 +48,7 @@ namespace corsika::proposal { //! compositions and stochastic description limited by the particle cut. //! template <typename TEnvironment> - Interaction(TEnvironment const& env, HEPEnergyType emCut); + Interaction(TEnvironment const& env); //! //! Calculate the rates for the different targets and interactions. Sample a diff --git a/corsika/modules/proposal/ProposalProcessBase.hpp b/corsika/modules/proposal/ProposalProcessBase.hpp index 89037f9fead31d255b76e40180a265aaa00d3cb7..cedad07efa87d7266764ebd61d9b808983e68de5 100644 --- a/corsika/modules/proposal/ProposalProcessBase.hpp +++ b/corsika/modules/proposal/ProposalProcessBase.hpp @@ -44,7 +44,10 @@ namespace corsika::proposal { //! template <typename T> static auto cross_builder = - [](PROPOSAL::Medium& m, corsika::units::si::HEPEnergyType emCut) { + [](PROPOSAL::Medium& m, + corsika::units::si::HEPEnergyType + emCut) { //!< Stochastic losses smaller than the given cut + //!< will be handeled continuously. using namespace corsika::units::si; auto p_cut = std::make_shared<const PROPOSAL::EnergyCutSettings>(emCut / 1_MeV, 1, true); @@ -73,8 +76,6 @@ namespace corsika::proposal { //! class ProposalProcessBase { protected: - HEPEnergyType emCut_; //!< Stochastic losses smaller than the given cut - //!< will be handeled continuously. RNGManager::prng_type RNG_; //!< random number generator used by proposal std::unordered_map<std::size_t, PROPOSAL::Medium> @@ -85,7 +86,7 @@ namespace corsika::proposal { //! Store cut and nuclear composition of the whole universe in media which are //! required for creating crosssections by proposal. //! - ProposalProcessBase(corsika::setup::Environment const& _env, HEPEnergyType _emCut); + ProposalProcessBase(corsika::setup::Environment const& _env); //! //! Checks if a particle can be processed by proposal diff --git a/examples/cascade_example.cpp b/examples/cascade_example.cpp index d14843c51730d8c05dd2e8d46c7374ba5e4224b7..91bc3f7cc99640a10e067da3360eee6e50911020 100644 --- a/examples/cascade_example.cpp +++ b/examples/cascade_example.cpp @@ -142,7 +142,7 @@ int main() { ParticleCut cut(80_GeV, true, true); TrackWriter trackWriter("tracks.dat"); - BetheBlochPDG eLoss{showerAxis, cut.getECut()}; + BetheBlochPDG eLoss{showerAxis}; // assemble all processes into an ordered process list auto sequence = diff --git a/examples/cascade_proton_example.cpp b/examples/cascade_proton_example.cpp index 003dc85584ebbe6911348b74109471fda5b3c096..24ed9e77d3be401229568a818511c9b2f2735563 100644 --- a/examples/cascade_proton_example.cpp +++ b/examples/cascade_proton_example.cpp @@ -132,7 +132,7 @@ int main() { TrackWriter trackWriter("tracks.dat"); ShowerAxis const showerAxis{injectionPos, Vector{rootCS, 0_m, 0_m, -100_km}, env}; - BetheBlochPDG eLoss{showerAxis, cut.getECut()}; + BetheBlochPDG eLoss{showerAxis}; // assemble all processes into an ordered process list // auto sequence = sibyll << decay << hadronicElastic << cut << trackWriter; diff --git a/examples/em_shower.cpp b/examples/em_shower.cpp index edb377953427cb89120828193319b41ce152d8b4..2afddc84ee9744909d4378eb3cf2456267655308 100644 --- a/examples/em_shower.cpp +++ b/examples/em_shower.cpp @@ -142,9 +142,9 @@ int main(int argc, char** argv) { // setup processes, decays and interactions // PROPOSAL processs proposal{...}; - ParticleCut cut(10_GeV, false, true); - corsika::proposal::Interaction proposal(env, cut.getECut()); - corsika::proposal::ContinuousProcess em_continuous(env, cut.getECut()); + ParticleCut cut(10_GeV, 10_GeV, 100_PeV, 100_PeV, true); + corsika::proposal::Interaction proposal(env); + corsika::proposal::ContinuousProcess em_continuous(env); InteractionCounter proposalCounted(proposal); TrackWriter trackWriter("tracks.dat"); diff --git a/examples/hybrid_MC.cpp b/examples/hybrid_MC.cpp index 71d8cf82875f39c85a7f6b11dd39f7ce2faac5bf..83ca7bd57098a6af751f430077dffc7414fa31e1 100644 --- a/examples/hybrid_MC.cpp +++ b/examples/hybrid_MC.cpp @@ -207,7 +207,7 @@ int main(int argc, char** argv) { decaySibyll.printDecayConfig(); ParticleCut cut{60_GeV, false, true}; - BetheBlochPDG eLoss{showerAxis, cut.getECut()}; + BetheBlochPDG eLoss{showerAxis}; CONEXhybrid conex_model(center, showerAxis, t, injectionHeight, E0, get_PDG(Code::Proton)); diff --git a/examples/stopping_power.cpp b/examples/stopping_power.cpp index ef8252501703205734ed361e4667df9fabdcbbed..d419efbb86b9cbfb3bc5a2b8db3cc8adb3a6e2bb 100644 --- a/examples/stopping_power.cpp +++ b/examples/stopping_power.cpp @@ -49,7 +49,7 @@ int main() { 112.8_km); // this is the CORSIKA 7 start of atmosphere/universe ShowerAxis showerAxis{injectionPos, Vector<length_d>{rootCS, 0_m, 0_m, 1_m}, env}; - BetheBlochPDG eLoss{showerAxis, 300_MeV}; + BetheBlochPDG eLoss{showerAxis}; setup::Stack stack; diff --git a/examples/vertical_EAS.cpp b/examples/vertical_EAS.cpp index 28488a1bdb53a8cc9a6b8f234152acf289919dfa..f012440e82deb19c3ab2b5220622c0255da9dbc5 100644 --- a/examples/vertical_EAS.cpp +++ b/examples/vertical_EAS.cpp @@ -221,9 +221,9 @@ int main(int argc, char** argv) { decaySibyll.printDecayConfig(); - ParticleCut cut{60_GeV, false, true}; - corsika::proposal::Interaction proposal(env, cut.getECut()); - corsika::proposal::ContinuousProcess em_continuous(env, cut.getECut()); + ParticleCut cut{60_GeV, 60_GeV, 60_GeV, 60_GeV, true}; + corsika::proposal::Interaction proposal(env); + corsika::proposal::ContinuousProcess em_continuous(env); InteractionCounter proposalCounted(proposal); OnShellCheck reset_particle_mass(1.e-3, 1.e-1, false); diff --git a/modules/conex b/modules/conex index 73e3d1fa850d2d3602a15b3b948ac1789fbc968d..820f042b6a055276d465437c74160ef7c199b646 160000 --- a/modules/conex +++ b/modules/conex @@ -1 +1 @@ -Subproject commit 73e3d1fa850d2d3602a15b3b948ac1789fbc968d +Subproject commit 820f042b6a055276d465437c74160ef7c199b646 diff --git a/modules/data b/modules/data index afe83dc19c1464deb176f38c3ddab80a64e081f4..8b76a9ca2599cd0ce1f204b17362eb06bbcf5277 160000 --- a/modules/data +++ b/modules/data @@ -1 +1 @@ -Subproject commit afe83dc19c1464deb176f38c3ddab80a64e081f4 +Subproject commit 8b76a9ca2599cd0ce1f204b17362eb06bbcf5277 diff --git a/src/framework/core/pdxml_reader.py b/src/framework/core/pdxml_reader.py index fcd0b134187647d81bf747c3634e4dce2eb76a57..2520cdfe4adb3f75bf316043425ca47e3e3742d7 100755 --- a/src/framework/core/pdxml_reader.py +++ b/src/framework/core/pdxml_reader.py @@ -330,7 +330,13 @@ def gen_properties(particle_db): for p in particle_db.values(): string += " {mass:e} * 1e9 * corsika::units::si::electronvolt, // {name:s}\n".format(mass = p['mass'], name = p['name']) string += "};\n\n" - + + # particle threshold table, initially set to the particle mass + string += "static std::array<corsika::units::si::HEPEnergyType, size> thresholds = {\n" + for p in particle_db.values(): + string += " {mass:e} * 1e9 * corsika::units::si::electronvolt, // {name:s}\n".format(mass = p['mass'], name = p['name']) + string += "};\n\n" + # PDG code table string += "static constexpr std::array<PDGCode, size> pdg_codes = {\n" for p in particle_db.keys(): diff --git a/tests/framework/testParticles.cpp b/tests/framework/testParticles.cpp index dd999ecf8c6be288546fd7b32ec5770b414c39b4..b74d836bc47d5715ec4f2504b30fb056af545af4 100644 --- a/tests/framework/testParticles.cpp +++ b/tests/framework/testParticles.cpp @@ -80,6 +80,15 @@ TEST_CASE("ParticleProperties", "[Particles]") { (Approx(2.1970332555864364e-06).epsilon(1e-5))); } + SECTION("Energy threshold") { + //! by default energy thresholds are set to particle mass + CHECK(get_energy_threshold(Electron::code) / Electron::mass == Approx(1)); + + set_energy_threshold(Electron::code, 10_GeV); + CHECK_FALSE(get_energy_threshold(Code::Electron) == 1_GeV); + CHECK(get_energy_threshold(Code::Electron) == 10_GeV); + } + SECTION("Particle groups: electromagnetic") { CHECK(is_em(Code::Gamma)); CHECK(is_em(Code::Electron)); diff --git a/tests/modules/testParticleCut.cpp b/tests/modules/testParticleCut.cpp index a8894230196e5041482cd53d267d1786a5a05a21..0dede160e563c6abab6a9a3fb2b1f0318f3dc1c7 100644 --- a/tests/modules/testParticleCut.cpp +++ b/tests/modules/testParticleCut.cpp @@ -25,7 +25,7 @@ using namespace corsika; TEST_CASE("ParticleCut", "[processes]") { logging::set_level(logging::level::info); - corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v"); + corsika_logger->set_pattern("[%n:%^%-8l%$] %v"); feenableexcept(FE_INVALID); using EnvType = setup::Environment; @@ -51,7 +51,7 @@ TEST_CASE("ParticleCut", "[processes]") { SECTION("cut on particle type: inv") { ParticleCut cut(20_GeV, false, true); - CHECK(cut.getECut() == 20_GeV); + CHECK(cut.getHadronECut() == 20_GeV); // add primary particle to stack auto particle = stack.addParticle(std::make_tuple( @@ -135,6 +135,50 @@ TEST_CASE("ParticleCut", "[processes]") { CHECK(view.getSize() == 13); } + SECTION("cut low energy: electrons, photons, hadrons and muons") { + ParticleCut cut(5_MeV, 5_MeV, 5_GeV, 5_GeV, true); + + // add primary particle to stack + auto particle = stack.addParticle( + std::make_tuple(Code::Proton, Eabove, + MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), point0, 0_ns)); + // view on secondary particles + setup::StackView view(particle); + // ref. to primary particle through the secondary view. + // only this way the secondary view is populated + auto projectile = view.getProjectile(); + // add secondaries + projectile.addSecondary(std::make_tuple( + Code::Gamma, 3_MeV, MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), point0, 0_ns)); + projectile.addSecondary(std::make_tuple(Code::Electron, 3_MeV, + MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + point0, 0_ns)); + projectile.addSecondary(std::make_tuple(Code::PiPlus, 4_GeV, + MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + point0, 0_ns)); + unsigned short A = 18; + unsigned short Z = 8; + projectile.addSecondary(std::make_tuple(Code::Nucleus, 4_GeV * A, + MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + point0, 0_ns, A, Z)); + projectile.addSecondary(std::make_tuple(Code::Nucleus, 6_GeV * A, + MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + point0, 0_ns, A, Z)); + + cut.doSecondaries(view); + + CHECK(view.getEntries() == 1); + CHECK(view.getSize() == 5); + } + + SECTION("cut low energy: reset thresholds of arbitrary set of particles") { + ParticleCut cut({{Code::Electron, 5_MeV}, {Code::Positron, 50_MeV}}, false, true); + CHECK(get_energy_threshold(Code::Electron) != get_energy_threshold(Code::Positron)); + CHECK_FALSE(get_energy_threshold(Code::Electron) == Electron::mass); + // test default values still correct + CHECK(get_energy_threshold(Code::Proton) == 5_GeV); + } + SECTION("cut on time") { ParticleCut cut(20_GeV, false, false); const TimeType too_late = 1_s; @@ -170,7 +214,7 @@ TEST_CASE("ParticleCut", "[processes]") { SECTION("cut on DoContinous, just invisibles") { ParticleCut cut(20_GeV, false, true); - CHECK(cut.getECut() == 20_GeV); + CHECK(cut.getHadronECut() == 20_GeV); // add particles, all with energies above the threshold // only cut is by species