diff --git a/Processes/Proposal/ContinuousProcess.cc b/Processes/Proposal/ContinuousProcess.cc index 81ba9825eb4243efa06be491db552546aceee7fe..1977467c2f91ab5513c2d491e2f468ec4ff67330 100644 --- a/Processes/Proposal/ContinuousProcess.cc +++ b/Processes/Proposal/ContinuousProcess.cc @@ -8,7 +8,6 @@ #include <PROPOSAL/PROPOSAL.h> #include <corsika/environment/IMediumModel.h> -#include <corsika/environment/NuclearComposition.h> #include <corsika/process/particle_cut/ParticleCut.h> #include <corsika/process/proposal/ContinuousProcess.h> #include <corsika/process/proposal/Interaction.h> @@ -18,60 +17,38 @@ #include <corsika/units/PhysicalUnits.h> #include <corsika/utl/COMBoost.h> -using SetupParticle = corsika::setup::Stack::ParticleType; -using SetupTrack = corsika::setup::Trajectory; - namespace corsika::process::proposal { - using namespace corsika::setup; - using namespace corsika::environment; + using namespace corsika::units::si; - bool ContinuousProcess::CanInteract(particles::Code pcode) const noexcept { - if (std::find(tracked_particles.begin(), tracked_particles.end(), pcode) != - tracked_particles.end()) - return true; - return false; + void ContinuousProcess::BuildCalculator(particles::Code code, + environment::NuclearComposition const& comp) { + auto c = cross[code](media.at(&comp), cut); + auto disp = PROPOSAL::make_displacement(c, true); + auto scatter = PROPOSAL::make_scattering("highland", particle[code], media.at(&comp)); + calc[std::make_pair(&comp, code)] = + std::make_tuple(std::move(disp), std::move(scatter)); } template <> - ContinuousProcess::ContinuousProcess(SetupEnvironment const& _env, - CORSIKA_ParticleCut& _cut) - : cut(_cut) - , fRNG(corsika::random::RNGManager::GetInstance().GetRandomStream("proposal")) { - auto all_compositions = std::vector<const NuclearComposition*>(); - _env.GetUniverse()->walk([&](auto& vtn) { - if (vtn.HasModelProperties()) - all_compositions.push_back(&vtn.GetModelProperties().GetNuclearComposition()); - }); - for (auto& ncarg : all_compositions) { - auto comp_vec = std::vector<PROPOSAL::Components::Component>(); - auto frac_iter = ncarg->GetFractions().cbegin(); - for (auto& pcode : ncarg->GetComponents()) { - comp_vec.emplace_back(GetName(pcode), GetNucleusZ(pcode), GetNucleusA(pcode), - *frac_iter); - ++frac_iter; - } - media[ncarg] = PROPOSAL::Medium( - "Modified Air", PROPOSAL::Air().GetI(), PROPOSAL::Air().GetC(), - PROPOSAL::Air().GetA(), PROPOSAL::Air().GetM(), PROPOSAL::Air().GetX0(), - PROPOSAL::Air().GetX1(), PROPOSAL::Air().GetD0(), 1.0, comp_vec); - } - } + ContinuousProcess::ContinuousProcess(setup::SetupEnvironment const& _env, + particle_cut::ParticleCut& _cut) + : ProposalProcessBase(_env, _cut) {} template <> - HEPEnergyType ContinuousProcess::TotalEnergyLoss(SetupParticle const& vP, + HEPEnergyType ContinuousProcess::TotalEnergyLoss(setup::Stack::ParticleType const& vP, GrammageType const& vDX) { - auto calc = GetCalculator(vP); - return vP.GetEnergy() - get<DISPLACEMENT>(calc->second) - ->UpperLimitTrackIntegral(vP.GetEnergy() / 1_MeV, - vDX / 1_g * 1_cm * 1_cm) * + auto c = GetCalculator(vP, calc); + return vP.GetEnergy() - get<DISPLACEMENT>(c->second)->UpperLimitTrackIntegral( + vP.GetEnergy() / 1_MeV, vDX / 1_g * 1_cm * 1_cm) * 1_MeV; } template <> - void ContinuousProcess::Scatter(SetupParticle& vP, HEPEnergyType const& loss, + void ContinuousProcess::Scatter(setup::Stack::ParticleType& vP, + HEPEnergyType const& loss, GrammageType const& grammage) { - auto calc = GetCalculator(vP); + auto c = GetCalculator(vP, calc); auto d = vP.GetDirection().GetComponents(); auto direction = PROPOSAL::Vector3D(d.GetX().magnitude(), d.GetY().magnitude(), d.GetZ().magnitude()); @@ -79,10 +56,10 @@ namespace corsika::process::proposal { std::uniform_real_distribution<double> distr(0., 1.); auto rnd = array<double, 4>(); for (auto& it : rnd) it = distr(fRNG); - auto [mean_dir, final_dir] = - get<SCATTERING>(calc->second) - ->Scatter(grammage / 1_g * square(1_cm), vP.GetEnergy() / 1_MeV, E_f / 1_MeV, - direction, rnd); + auto [mean_dir, final_dir] = get<SCATTERING>(c->second)->Scatter( + grammage / 1_g * square(1_cm), vP.GetEnergy() / 1_MeV, E_f / 1_MeV, direction, + rnd); + (void)mean_dir; auto vec = corsika::geometry::QuantityVector( final_dir.GetX() * E_f, final_dir.GetY() * E_f, final_dir.GetZ() * E_f); vP.SetMomentum(corsika::stack::MomentumVector( @@ -91,8 +68,8 @@ namespace corsika::process::proposal { } template <> - EProcessReturn ContinuousProcess::DoContinuous(SetupParticle& vP, - SetupTrack const& vT) { + EProcessReturn ContinuousProcess::DoContinuous(setup::Stack::ParticleType& vP, + setup::Trajectory const& vT) { if (!CanInteract(vP.GetPID())) return process::EProcessReturn::eOk; auto dX = vP.GetNode()->GetModelProperties().IntegratedGrammage(vT, vT.GetLength()); auto energy_loss = TotalEnergyLoss(vP, dX); @@ -104,15 +81,15 @@ namespace corsika::process::proposal { } template <> - units::si::LengthType ContinuousProcess::MaxStepLength(SetupParticle const& vP, - SetupTrack const& vT) { - auto energy_lim = 0.9 * vP.GetEnergy() / 1_MeV; - auto calc = GetCalculator(vP); - auto grammage = get<DISPLACEMENT>(calc->second) - ->SolveTrackIntegral(vP.GetEnergy() / 1_MeV, energy_lim) * + units::si::LengthType ContinuousProcess::MaxStepLength( + setup::Stack::ParticleType const& vP, setup::Trajectory const& vT) { + auto energy_lim = 0.9 * vP.GetEnergy(); + if (cut.GetECut() > energy_lim) energy_lim = cut.GetECut(); + auto c = GetCalculator(vP, calc); + auto grammage = get<DISPLACEMENT>(c->second)->SolveTrackIntegral( + vP.GetEnergy() / 1_MeV, energy_lim / 1_MeV) * 1_g / square(1_cm); - return vP.GetNode()->GetModelProperties().ArclengthFromGrammage(vT, grammage) * - 1.0001; + return vP.GetNode()->GetModelProperties().ArclengthFromGrammage(vT, grammage) * 1.0001; } } // namespace corsika::process::proposal diff --git a/Processes/Proposal/ContinuousProcess.h b/Processes/Proposal/ContinuousProcess.h index cbb5a337c74c727fc9fc1574f4f666a6f3e4ed4a..c50ac8d541bb4e3073dec4476e8a27cbd2abeb3a 100644 --- a/Processes/Proposal/ContinuousProcess.h +++ b/Processes/Proposal/ContinuousProcess.h @@ -13,102 +13,70 @@ #include <corsika/particles/ParticleProperties.h> #include <corsika/process/ContinuousProcess.h> #include <corsika/process/particle_cut/ParticleCut.h> +#include <corsika/process/proposal/ProposalProcessBase.h> #include <corsika/random/RNGManager.h> #include <corsika/random/UniformRealDistribution.h> #include <unordered_map> -using std::unordered_map; - -using namespace corsika::environment; -using namespace corsika::units::si; - -using CORSIKA_ParticleCut = corsika::process::particle_cut::ParticleCut; - namespace corsika::process::proposal { - class ContinuousProcess - : public corsika::process::ContinuousProcess<ContinuousProcess> { - CORSIKA_ParticleCut& cut; - corsika::random::RNG& fRNG; - static constexpr std::array<particles::Code, 7> tracked_particles{ - particles::Code::Gamma, particles::Code::Electron, particles::Code::Positron, - particles::Code::MuMinus, particles::Code::MuPlus, particles::Code::TauPlus, - particles::Code::TauMinus, - }; - unordered_map<const NuclearComposition*, PROPOSAL::Medium> media; - - bool CanInteract(particles::Code pcode) const noexcept; + using namespace corsika::units::si; - using calc_key_t = std::pair<const NuclearComposition*, particles::Code>; - using calc_t = - tuple<unique_ptr<PROPOSAL::Displacement>, unique_ptr<PROPOSAL::Scattering>>; - - struct disp_hash { - size_t operator()(const calc_key_t& p) const { - return std::hash<const NuclearComposition*>{}(p.first) ^ - std::hash<particles::Code>{}(p.second); - } - }; + //! + //! Electro-magnetic and gamma continous losses produced by proposal. It makes + //! use of interpolation tables which are runtime intensive calculation, but can be + //! reused by setting the \param PROPOSAL::InterpolationDef::path_to_tables variable. + //! + class ContinuousProcess : public process::ContinuousProcess<ContinuousProcess>, + ProposalProcessBase { enum { DISPLACEMENT, SCATTERING }; - unordered_map<calc_key_t, calc_t, disp_hash> calc; - - template <typename Particle> - auto BuildCalculator(particles::Code code, Particle p_def, - NuclearComposition const& comp) { - auto cross = GetStdCrossSections( - p_def, media.at(&comp), - make_shared<const PROPOSAL::EnergyCutSettings>(cut.GetECut() / 1_MeV, 1, false), - true); - auto [insert_it, success] = - calc.insert({std::make_pair(&comp, code), - std::make_tuple(PROPOSAL::make_displacement(cross, true), - PROPOSAL::make_scattering("highland", p_def, - media.at(&comp)))}); - return insert_it; - } + using calc_t = std::tuple<std::unique_ptr<PROPOSAL::Displacement>, + std::unique_ptr<PROPOSAL::Scattering>>; - auto BuildCalculator(particles::Code corsika_code, NuclearComposition const& comp) { - if (corsika_code == particles::Code::Gamma) - return BuildCalculator(particles::Code::Gamma, PROPOSAL::GammaDef(), comp); - if (corsika_code == particles::Code::Electron) - return BuildCalculator(particles::Code::Electron, PROPOSAL::EMinusDef(), comp); - if (corsika_code == particles::Code::Positron) - return BuildCalculator(particles::Code::Positron, PROPOSAL::EPlusDef(), comp); - if (corsika_code == particles::Code::MuMinus) - return BuildCalculator(particles::Code::MuMinus, PROPOSAL::MuMinusDef(), comp); - if (corsika_code == particles::Code::MuPlus) - return BuildCalculator(particles::Code::MuPlus, PROPOSAL::MuPlusDef(), comp); - if (corsika_code == particles::Code::TauMinus) - return BuildCalculator(particles::Code::TauMinus, PROPOSAL::TauMinusDef(), comp); - if (corsika_code == particles::Code::TauPlus) - return BuildCalculator(particles::Code::TauPlus, PROPOSAL::TauPlusDef(), comp); - throw std::runtime_error("PROPOSAL could not find corresponding builder"); - } + std::unordered_map<calc_key_t, calc_t, hash> + calc; //!< Stores the displacement and scattering calculators. - template <typename Particle> - auto GetCalculator(Particle& vP) { - auto& comp = vP.GetNode()->GetModelProperties().GetNuclearComposition(); - auto calc_it = calc.find(std::make_pair(&comp, vP.GetPID())); - if (calc_it != calc.end()) return calc_it; - return BuildCalculator(vP.GetPID(), comp); - } + //! + //! Build the displacement and scattering calculators and add it to calc. + //! + void BuildCalculator(particles::Code, environment::NuclearComposition const&) final; public: + //! Produces the continuous loss calculator for leptons based on nuclear + //! compositions and stochastic description limited by the particle cut. + //! template <typename TEnvironment> - ContinuousProcess(TEnvironment const&, CORSIKA_ParticleCut&); + ContinuousProcess(TEnvironment const&, particle_cut::ParticleCut&); + //! + //! Calculates the energy of the particle which has passed the given + //! grammage. + //! template <typename Particle> corsika::units::si::HEPEnergyType TotalEnergyLoss( Particle const&, corsika::units::si::GrammageType const&); + //! + //! Multiple Scattering of the lepton. Stochastic deflection is not yet taken into + //! account. Displacment of the track due to multiple scattering is not possible + //! because of the constant referernce. The final direction will be updated anyway. + //! template <typename Particle> void Scatter(Particle&, corsika::units::si::HEPEnergyType const&, corsika::units::si::GrammageType const&); + //! + //! Produces the loss and deflection after given distance for the particle. + //! If the particle if below the given energy threshold where it will be + //! considered stochastically, it will be absorbed. + //! template <typename Particle, typename Track> EProcessReturn DoContinuous(Particle&, Track const&); + //! + //! Calculates maximal step length of process. + //! template <typename Particle, typename Track> corsika::units::si::LengthType MaxStepLength(Particle const&, Track const&); }; diff --git a/Processes/Proposal/Interaction.cc b/Processes/Proposal/Interaction.cc index 71ddfcfee72e230b2a1343338e03d8a9b2884480..219712d65c6f950be8d616de50e4270ae9255e03 100644 --- a/Processes/Proposal/Interaction.cc +++ b/Processes/Proposal/Interaction.cc @@ -8,6 +8,7 @@ #include <corsika/environment/IMediumModel.h> #include <corsika/environment/NuclearComposition.h> +#include <corsika/process/particle_cut/ParticleCut.h> #include <corsika/process/proposal/Interaction.h> #include <corsika/setup/SetupEnvironment.h> #include <corsika/setup/SetupStack.h> @@ -19,55 +20,34 @@ #include <random> #include <tuple> -using Component_PROPOSAL = PROPOSAL::Components::Component; - namespace corsika::process::proposal { - using namespace corsika::setup; using namespace corsika::environment; using namespace corsika::units::si; - bool Interaction::CanInteract(particles::Code pcode) const noexcept { - if (std::find(tracked_particles.begin(), tracked_particles.end(), pcode) != - tracked_particles.end()) - return true; - return false; - } - template <> - Interaction::Interaction(SetupEnvironment const& _env, CORSIKA_ParticleCut& _cut) - : cut(_cut) - , fRNG(corsika::random::RNGManager::GetInstance().GetRandomStream("proposal")) { - auto all_compositions = std::vector<const NuclearComposition*>(); - _env.GetUniverse()->walk([&](auto& vtn) { - if (vtn.HasModelProperties()) - all_compositions.push_back(&vtn.GetModelProperties().GetNuclearComposition()); - }); - for (auto& ncarg : all_compositions) { - auto comp_vec = std::vector<Component_PROPOSAL>(); - auto frac_iter = ncarg->GetFractions().cbegin(); - for (auto& pcode : ncarg->GetComponents()) { - comp_vec.emplace_back(GetName(pcode), GetNucleusZ(pcode), GetNucleusA(pcode), - *frac_iter); - ++frac_iter; - } - media[ncarg] = PROPOSAL::Medium( - "Modified Air", PROPOSAL::Air().GetI(), PROPOSAL::Air().GetC(), - PROPOSAL::Air().GetA(), PROPOSAL::Air().GetM(), PROPOSAL::Air().GetX0(), - PROPOSAL::Air().GetX1(), PROPOSAL::Air().GetD0(), 1.0, comp_vec); - } + Interaction::Interaction(setup::SetupEnvironment const& _env, + particle_cut::ParticleCut& _cut) + : ProposalProcessBase(_env, _cut) {} + + void Interaction::BuildCalculator(particles::Code code, + environment::NuclearComposition const& comp) { + auto c = cross[code](media.at(&comp), cut); + auto inter_types = PROPOSAL::CrossSectionVector::GetInteractionTypes(c); + calc[std::make_pair(&comp, code)] = std::make_tuple( + PROPOSAL::make_secondaries(inter_types, particle[code], media.at(&comp)), + PROPOSAL::make_interaction(c, true)); } template <> corsika::process::EProcessReturn Interaction::DoInteraction( setup::StackView::StackIterator& vP) { if (CanInteract(vP.GetPID())) { - auto calc = GetCalculator(vP); // [CrossSections] + auto c = GetCalculator(vP, calc); // [CrossSections] std::uniform_real_distribution<double> distr(0., 1.); - auto [type, comp_ptr, v] = - get<INTERACTION>(calc->second) - ->TypeInteraction(vP.GetEnergy() / 1_MeV, distr(fRNG)); - auto rnd = - vector<double>(get<SECONDARIES>(calc->second)->RequiredRandomNumbers(type)); + auto rates = get<INTERACTION>(c->second)->Rates(vP.GetEnergy() / 1_MeV); + auto [type, comp_ptr, v] = get<INTERACTION>(c->second)->SampleLoss( + vP.GetEnergy() / 1_MeV, rates, distr(fRNG)); + auto rnd = vector<double>(get<SECONDARIES>(c->second)->RequiredRandomNumbers(type)); for (auto& it : rnd) it = distr(fRNG); auto point = PROPOSAL::Vector3D(vP.GetPosition().GetX() / 1_cm, vP.GetPosition().GetY() / 1_cm, @@ -77,8 +57,8 @@ namespace corsika::process::proposal { d.GetZ().magnitude()); auto loss = make_tuple(static_cast<int>(type), point, direction, v * vP.GetEnergy() / 1_MeV, 0.); - auto sec = get<SECONDARIES>(calc->second) - ->CalculateSecondaries(vP.GetEnergy() / 1_MeV, loss, *comp_ptr, rnd); + auto sec = get<SECONDARIES>(c->second)->CalculateSecondaries(vP.GetEnergy() / 1_MeV, + loss, *comp_ptr, rnd); for (auto& s : sec) { auto E = get<PROPOSAL::Loss::ENERGY>(s) * 1_MeV; auto vec = corsika::geometry::QuantityVector( @@ -101,8 +81,8 @@ namespace corsika::process::proposal { corsika::units::si::GrammageType Interaction::GetInteractionLength( setup::Stack::StackIterator const& vP) { if (CanInteract(vP.GetPID())) { - auto calc = GetCalculator(vP); - return get<INTERACTION>(calc->second)->MeanFreePath(vP.GetEnergy() / 1_MeV) * 1_g / + auto c = GetCalculator(vP, calc); + return get<INTERACTION>(c->second)->MeanFreePath(vP.GetEnergy() / 1_MeV) * 1_g / (1_cm * 1_cm); } return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); diff --git a/Processes/Proposal/Interaction.h b/Processes/Proposal/Interaction.h index 6e1b2d57941c204a1a5a1b210c0e62f54a7295c8..990cf11156cf107acd91ff8c4f1c57871f6b8943 100644 --- a/Processes/Proposal/Interaction.h +++ b/Processes/Proposal/Interaction.h @@ -14,89 +14,29 @@ #include <corsika/particles/ParticleProperties.h> #include <corsika/process/InteractionProcess.h> #include <corsika/process/particle_cut/ParticleCut.h> +#include <corsika/process/proposal/ProposalProcessBase.h> #include <corsika/random/RNGManager.h> #include <corsika/random/UniformRealDistribution.h> #include <array> -using namespace corsika::environment; -using namespace corsika::units::si; - -using CORSIKA_ParticleCut = corsika::process::particle_cut::ParticleCut; -using std::make_pair; -using std::make_tuple; - namespace corsika::process::proposal { - class Interaction : public corsika::process::InteractionProcess<Interaction> { - CORSIKA_ParticleCut& cut; - corsika::random::RNG& fRNG; - static constexpr std::array<particles::Code, 7> tracked_particles{ - particles::Code::Gamma, particles::Code::Electron, particles::Code::Positron, - particles::Code::MuMinus, particles::Code::MuPlus, particles::Code::TauPlus, - particles::Code::TauMinus, - }; - std::unordered_map<const NuclearComposition*, PROPOSAL::Medium> media; + using namespace corsika::units::si; - bool CanInteract(particles::Code pcode) const noexcept; + class Interaction : public InteractionProcess<Interaction>, ProposalProcessBase { using calculator_t = tuple<unique_ptr<PROPOSAL::SecondariesCalculator>, unique_ptr<PROPOSAL::Interaction>>; - using calc_key_t = std::pair<const NuclearComposition*, particles::Code>; - - struct interaction_hash { - size_t operator()(const calc_key_t& p) const { - return std::hash<const NuclearComposition*>{}(p.first) ^ - std::hash<particles::Code>{}(p.second); - } - }; - std::unordered_map<calc_key_t, calculator_t, interaction_hash> calculators; + std::unordered_map<calc_key_t, calculator_t, hash> calc; - template <typename Particle> - auto BuildCalculator(particles::Code code, Particle p_def, - NuclearComposition const& comp) { - auto cross = GetStdCrossSections( - p_def, media.at(&comp), - make_shared<const PROPOSAL::EnergyCutSettings>(cut.GetECut() / 1_MeV, 1, false), - true); - auto inter_types = PROPOSAL::CrossSectionVector::GetInteractionTypes(cross); - auto [insert_it, success] = calculators.insert( - {make_pair(&comp, code), - make_tuple(PROPOSAL::make_secondaries(inter_types, p_def, media.at(&comp)), - PROPOSAL::make_interaction(cross, true))}); - return insert_it; - } - - auto BuildCalculator(particles::Code corsika_code, NuclearComposition const& comp) { - if (corsika_code == particles::Code::Gamma) - return BuildCalculator(particles::Code::Gamma, PROPOSAL::GammaDef(), comp); - if (corsika_code == particles::Code::Electron) - return BuildCalculator(particles::Code::Electron, PROPOSAL::EMinusDef(), comp); - if (corsika_code == particles::Code::Positron) - return BuildCalculator(particles::Code::Positron, PROPOSAL::EPlusDef(), comp); - if (corsika_code == particles::Code::MuMinus) - return BuildCalculator(particles::Code::MuMinus, PROPOSAL::MuMinusDef(), comp); - if (corsika_code == particles::Code::MuPlus) - return BuildCalculator(particles::Code::MuPlus, PROPOSAL::MuPlusDef(), comp); - if (corsika_code == particles::Code::TauMinus) - return BuildCalculator(particles::Code::TauMinus, PROPOSAL::TauMinusDef(), comp); - if (corsika_code == particles::Code::TauPlus) - return BuildCalculator(particles::Code::TauPlus, PROPOSAL::TauPlusDef(), comp); - throw std::runtime_error("PROPOSAL could not find corresponding builder"); - } + void BuildCalculator(particles::Code, environment::NuclearComposition const&) final; enum { SECONDARIES, INTERACTION }; - template <typename Particle> - auto GetCalculator(Particle& vP) { - auto& comp = vP.GetNode()->GetModelProperties().GetNuclearComposition(); - auto calc_it = calculators.find(make_pair(&comp, vP.GetPID())); - if (calc_it != calculators.end()) return calc_it; - return BuildCalculator(vP.GetPID(), comp); - } public: template <typename TEnvironment> - Interaction(TEnvironment const& env, CORSIKA_ParticleCut& cut); + Interaction(TEnvironment const& env, particle_cut::ParticleCut& cut); template <typename Particle> corsika::process::EProcessReturn DoInteraction(Particle&); diff --git a/Processes/Proposal/PROPOSAL b/Processes/Proposal/PROPOSAL index 17bc2e3a6fb777c51993dca12831c45a8eb40ff8..92b9b9ca20826725cb805d135a1a5d5b29a7e06a 160000 --- a/Processes/Proposal/PROPOSAL +++ b/Processes/Proposal/PROPOSAL @@ -1 +1 @@ -Subproject commit 17bc2e3a6fb777c51993dca12831c45a8eb40ff8 +Subproject commit 92b9b9ca20826725cb805d135a1a5d5b29a7e06a diff --git a/Processes/Proposal/ProposalProcessBase.cc b/Processes/Proposal/ProposalProcessBase.cc new file mode 100644 index 0000000000000000000000000000000000000000..335cf41860160dbbd73df8e79dcd94535a306eef --- /dev/null +++ b/Processes/Proposal/ProposalProcessBase.cc @@ -0,0 +1,60 @@ +/* + * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#include <corsika/environment/IMediumModel.h> +#include <corsika/environment/NuclearComposition.h> +#include <corsika/process/proposal/ProposalProcessBase.h> +#include <corsika/setup/SetupEnvironment.h> +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> +#include <corsika/units/PhysicalUnits.h> +#include <corsika/utl/COMBoost.h> +#include <limits> +#include <memory> +#include <random> +#include <tuple> + +namespace corsika::process::proposal { + bool ProposalProcessBase::CanInteract(particles::Code pcode) const { + if (std::find(begin(tracked), end(tracked), pcode) != end(tracked)) return true; + return false; + } + + ProposalProcessBase::ProposalProcessBase(setup::SetupEnvironment const& _env, + particle_cut::ParticleCut& _cut) + : cut(_cut) + , fRNG(corsika::random::RNGManager::GetInstance().GetRandomStream("proposal")) { + auto all_compositions = std::vector<const environment::NuclearComposition*>(); + _env.GetUniverse()->walk([&](auto& vtn) { + if (vtn.HasModelProperties()) + all_compositions.push_back(&vtn.GetModelProperties().GetNuclearComposition()); + }); + for (auto& ncarg : all_compositions) { + auto comp_vec = std::vector<PROPOSAL::Components::Component>(); + auto frac_iter = ncarg->GetFractions().cbegin(); + for (auto& pcode : ncarg->GetComponents()) { + comp_vec.emplace_back(GetName(pcode), GetNucleusZ(pcode), GetNucleusA(pcode), + *frac_iter); + ++frac_iter; + } + media[ncarg] = PROPOSAL::Medium( + "Modified Air", PROPOSAL::Air().GetI(), PROPOSAL::Air().GetC(), + PROPOSAL::Air().GetA(), PROPOSAL::Air().GetM(), PROPOSAL::Air().GetX0(), + PROPOSAL::Air().GetX1(), PROPOSAL::Air().GetD0(), 1.0, comp_vec); + } + PROPOSAL::InterpolationDef::order_of_interpolation = 2; + PROPOSAL::InterpolationDef::nodes_cross_section = 100; + PROPOSAL::InterpolationDef::nodes_propagate = 100; + } + + size_t ProposalProcessBase::hash::operator()(const calc_key_t& p) const noexcept { + return std::hash<const environment::NuclearComposition*>{}(p.first) ^ + std::hash<particles::Code>{}(p.second); + } + +} // namespace corsika::process::proposal diff --git a/Processes/Proposal/ProposalProcessBase.h b/Processes/Proposal/ProposalProcessBase.h new file mode 100644 index 0000000000000000000000000000000000000000..b2f503e775f4584d0a1809ee0c8b3d6bc57eed5a --- /dev/null +++ b/Processes/Proposal/ProposalProcessBase.h @@ -0,0 +1,122 @@ +#pragma once + +#include <PROPOSAL/PROPOSAL.h> + +#include <corsika/environment/Environment.h> +#include <corsika/particles/ParticleProperties.h> +#include <corsika/process/particle_cut/ParticleCut.h> +#include <corsika/random/RNGManager.h> +#include <array> + +namespace corsika::process::proposal { + + using namespace corsika::units::si; + using namespace std::placeholders; + + //! + //! Particles which can be handled by proposal. That means they can be + //! propagated and decayed if they decays. + //! + static constexpr std::array<particles::Code, 7> tracked{ + particles::Code::Gamma, particles::Code::Electron, particles::Code::Positron, + particles::Code::MuMinus, particles::Code::MuPlus, particles::Code::TauPlus, + particles::Code::TauMinus, + }; + + //! + //! Internal map from particle codes to particle properties required for + //! crosssections, decay and scattering algorithms. In the future the + //! particles may be created by reading out the Corsica constants. + //! + static std::map<particles::Code, PROPOSAL::ParticleDef> particle = { + {particles::Code::Gamma, PROPOSAL::GammaDef()}, + {particles::Code::Electron, PROPOSAL::EMinusDef()}, + {particles::Code::Positron, PROPOSAL::EPlusDef()}, + {particles::Code::MuMinus, PROPOSAL::MuMinusDef()}, + {particles::Code::MuPlus, PROPOSAL::MuPlusDef()}, + {particles::Code::TauMinus, PROPOSAL::TauMinusDef()}, + {particles::Code::TauPlus, PROPOSAL::TauPlusDef()}}; + + //! + //! Crosssection factories for different particle types. + //! + template <typename T> + static auto cross_builder = [](PROPOSAL::Medium& m, particle_cut::ParticleCut& cut) { + auto p_cut = std::make_shared<const PROPOSAL::EnergyCutSettings>( + cut.GetECut() / 1_MeV, 1, true); + return PROPOSAL::DefaultCrossSections<T>::template Get<std::false_type>(T(), m, p_cut, + true); + }; + + //! + //! PROPOSAL default crosssections are maped to corresponding corsika particle + //! code. + //! + static std::map<particles::Code, std::function<PROPOSAL::crosssection_list_t< + PROPOSAL::ParticleDef, PROPOSAL::Medium>( + PROPOSAL::Medium&, particle_cut::ParticleCut&)>> + cross = {{particles::Code::Gamma, cross_builder<PROPOSAL::GammaDef>}, + {particles::Code::Electron, cross_builder<PROPOSAL::EMinusDef>}, + {particles::Code::Positron, cross_builder<PROPOSAL::EPlusDef>}, + {particles::Code::MuMinus, cross_builder<PROPOSAL::MuMinusDef>}, + {particles::Code::MuPlus, cross_builder<PROPOSAL::MuPlusDef>}, + {particles::Code::TauMinus, cross_builder<PROPOSAL::TauMinusDef>}, + {particles::Code::TauPlus, cross_builder<PROPOSAL::TauPlusDef>}}; + + //! + //! PROPOSAL base process which handels mapping of particle codes to + //! stored interpolation tables. + //! + class ProposalProcessBase { + protected: + particle_cut::ParticleCut& cut; //!< Stochastic losses smaller than the given cut + //!< will be handeled continuously. + corsika::random::RNG& fRNG; //!< random number generator used by proposal + + std::unordered_map<const environment::NuclearComposition*, PROPOSAL::Medium> + media; //!< maps nuclear composition from univers to media to produce + //!< crosssections, which requires further ionization constants. + + //! + //! Store cut and nuclear composition of the whole universe in media which are + //! required for creating crosssections by proposal. + //! + ProposalProcessBase(setup::SetupEnvironment const& _env, + particle_cut::ParticleCut& _cut); + + //! + //! Checks if a particle can be processed by proposal + //! + bool CanInteract(particles::Code pcode) const; + + using calc_key_t = std::pair<const environment::NuclearComposition*, particles::Code>; + + //! + //! Hash to store interpolation tables related to a pair of particle and nuclear + //! composition. + //! + struct hash { + size_t operator()(const calc_key_t& p) const noexcept; + }; + + //! + //! Builds the calculator to the corresponding class + //! + virtual void BuildCalculator(particles::Code, + environment::NuclearComposition const&) = 0; + + //! + //! Searches the particle dependet calculator dependent of actuall medium composition + //! and particle type. If no calculator is found, the corresponding new calculator is + //! built and then returned. + //! + template <typename Particle, typename Calculators> + auto GetCalculator(Particle& vP, Calculators& calc) { + auto& comp = vP.GetNode()->GetModelProperties().GetNuclearComposition(); + auto calc_it = calc.find(std::make_pair(&comp, vP.GetPID())); + if (calc_it != calc.end()) return calc_it; + BuildCalculator(vP.GetPID(), comp); + return GetCalculator(vP, calc); + } + }; +} // namespace corsika::process::proposal