diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h index 03204dde72a73c0fed4733e968b89266b6f76a6f..c55ac0b43b86e1956750618ec65e868a0d1334e0 100644 --- a/Framework/Cascade/Cascade.h +++ b/Framework/Cascade/Cascade.h @@ -201,7 +201,7 @@ namespace corsika::cascade { actual_inv_length); const auto sample_process = uniDist(fRNG); InverseGrammageType inv_lambda_count = 0. * meter * meter / gram; - fProcessSequence.SelectInteraction(particle, fStack, sample_process, + fProcessSequence.SelectInteraction(particle, step, fStack, sample_process, inv_lambda_count); } else { std::cout << "decay" << std::endl; diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h index 4d4d3fbfdaff3d075f6cc613da78ece584ed7142..1056ccd9e4cdb4ec80fca29b7c08857de1e28fc9 100644 --- a/Framework/ProcessSequence/ProcessSequence.h +++ b/Framework/ProcessSequence/ProcessSequence.h @@ -132,24 +132,24 @@ namespace corsika::process { return tot; } - template <typename Particle, typename Stack> + template <typename Particle, typename Track, typename Stack> EProcessReturn SelectInteraction( - Particle& p, Stack& s, + Particle& vP, Track& vT, Stack& vS, [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_select, corsika::units::si::InverseGrammageType& lambda_inv_count) { if constexpr (is_process_sequence<T1type>::value) { // if A is a process sequence --> check inside const EProcessReturn ret = - A.SelectInteraction(p, s, lambda_select, lambda_inv_count); + A.SelectInteraction(vP, vT, 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<T1type>, T1type>::value) { // if this is not a ContinuousProcess --> evaluate probability - lambda_inv_count += A.GetInverseInteractionLength(p, s); + lambda_inv_count += A.GetInverseInteractionLength(vP, vT); // check if we should execute THIS process and then EXIT if (lambda_select < lambda_inv_count) { - A.DoInteraction(p, s); + A.DoInteraction(vP, vS); return EProcessReturn::eInteracted; } } // end branch A @@ -157,15 +157,15 @@ namespace corsika::process { if constexpr (is_process_sequence<T2>::value) { // if A is a process sequence --> check inside const EProcessReturn ret = - B.SelectInteraction(p, s, lambda_select, lambda_inv_count); + B.SelectInteraction(vP, vT, 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 this is not a ContinuousProcess --> evaluate probability - lambda_inv_count += B.GetInverseInteractionLength(p, s); + lambda_inv_count += B.GetInverseInteractionLength(vP, vT); // check if we should execute THIS process and then EXIT if (lambda_select < lambda_inv_count) { - B.DoInteraction(p, s); + B.DoInteraction(vP, vS); return EProcessReturn::eInteracted; } } // end branch A diff --git a/Framework/StackInterface/ParticleBase.h b/Framework/StackInterface/ParticleBase.h index e2f277e379c7ac0b393fb898ec7e6fd896dfaaf0..ef85de7af7f61c829e66f04058b89d48706ddc03 100644 --- a/Framework/StackInterface/ParticleBase.h +++ b/Framework/StackInterface/ParticleBase.h @@ -48,6 +48,7 @@ namespace corsika::stack { class ParticleBase { public: + using StackIteratorType = StackIterator; ParticleBase() = default; private: diff --git a/Framework/StackInterface/Stack.h b/Framework/StackInterface/Stack.h index bfb5acfbd10f5910ede79649df123bdc8aa296c5..e917f0a721913666da4eea3df37e5c3162c9ec7d 100644 --- a/Framework/StackInterface/Stack.h +++ b/Framework/StackInterface/Stack.h @@ -19,22 +19,6 @@ #include <corsika/stack/SecondaryView.h> -// SFINAE test -template <typename T> -class HasGetIndexFromIterator { -private: - typedef char YesType[1]; - typedef char NoType[2]; - - template <typename C> - static YesType& test(decltype(&C::GetIndexFromIterator)); - template <typename C> - static NoType& test(...); - -public: - enum { value = sizeof(test<T>(0)) == sizeof(YesType) }; -}; - /** All classes around management of particles on a stack. */ @@ -123,9 +107,14 @@ namespace corsika::stack { ParticleInterface, StackType>; /** - * this is the full type of the declared ParticleInterface: typedef typename + * this is the full type of the user-declared ParticleInterface + */ + using ParticleInterfaceType = typename StackIterator::ParticleInterfaceType; + /** + * In all programming context, the object to access, copy, and + * transport particle data is via the StackIterator */ - typedef typename StackIterator::ParticleInterfaceType ParticleType; + using ParticleType = StackIterator; // friends are needed since they need access to protected members friend class StackIteratorInterface< @@ -216,7 +205,7 @@ namespace corsika::stack { /** * delete this particle */ - void Delete(ParticleType p) { Delete(p.GetIterator()); } + void Delete(ParticleInterfaceType p) { Delete(p.GetIterator()); } /** * delete last particle on stack by decrementing stack size diff --git a/Framework/StackInterface/testCombinedStack.cc b/Framework/StackInterface/testCombinedStack.cc index 63e984b1b95a9583156df1ce0bad72e5f85573fc..11a3314a2e60a517b9c1b197f913ffec1e7cc421 100644 --- a/Framework/StackInterface/testCombinedStack.cc +++ b/Framework/StackInterface/testCombinedStack.cc @@ -89,7 +89,6 @@ using CombinedTestInterfaceType = TestParticleInterface2, StackIter>; using StackTest = CombinedStack<TestStackData, TestStackData2, CombinedTestInterfaceType>; -typedef StackTest::ParticleType Particle; TEST_CASE("Combined Stack", "[stack]") { @@ -161,10 +160,9 @@ TEST_CASE("Combined Stack", "[stack]") { StackTest s; REQUIRE(s.GetSize() == 0); auto iter = s.AddParticle(std::tuple{9.9}); - Particle& p = *iter; // also this is valid to access particle data - p.SetData2(2); + iter.SetData2(2); REQUIRE(s.GetSize() == 1); - p.AddSecondary(std::tuple{4.4}); + iter.AddSecondary(std::tuple{4.4}); REQUIRE(s.GetSize() == 2); // p.AddSecondary(3.3, 2.2, 1.); // REQUIRE(s.GetSize() == 3); @@ -259,7 +257,6 @@ using CombinedTestInterfaceType2 = using StackTest2 = CombinedStack<typename StackTest::StackImpl, TestStackData3, CombinedTestInterfaceType2>; -typedef StackTest2::ParticleType Particle2; TEST_CASE("Combined Stack - multi", "[stack]") { diff --git a/Framework/StackInterface/testSecondaryView.cc b/Framework/StackInterface/testSecondaryView.cc index df8521386b3b4f49214ad92f2a69906b1c804b55..08d27c169bfa6144abd203603eae74dc1e134c98 100644 --- a/Framework/StackInterface/testSecondaryView.cc +++ b/Framework/StackInterface/testSecondaryView.cc @@ -32,7 +32,6 @@ using namespace corsika::stack; using namespace std; typedef Stack<TestStackData, TestParticleInterface> StackTest; -typedef StackTest::ParticleType Particle; TEST_CASE("SecondaryStack", "[stack]") { diff --git a/Framework/StackInterface/testStackInterface.cc b/Framework/StackInterface/testStackInterface.cc index 448aab92731f41c7722aaff369b1517ab76c7c25..5d4de9dae7b1cb49e6d4915eb565e2a9bf1c8416 100644 --- a/Framework/StackInterface/testStackInterface.cc +++ b/Framework/StackInterface/testStackInterface.cc @@ -33,7 +33,7 @@ using namespace corsika::stack; using namespace std; typedef Stack<TestStackData, TestParticleInterface> StackTest; -typedef StackTest::ParticleType Particle; +typedef StackTest::ParticleInterfaceType Particle; TEST_CASE("Stack", "[Stack]") { diff --git a/Processes/Sibyll/CMakeLists.txt b/Processes/Sibyll/CMakeLists.txt index 880496a219b8674a2cca984c6ab3e8615ecd1470..357964b39c77d5d1ddcdaa9d3ae290debd61d911 100644 --- a/Processes/Sibyll/CMakeLists.txt +++ b/Processes/Sibyll/CMakeLists.txt @@ -18,6 +18,9 @@ add_custom_command ( set ( MODEL_SOURCES ParticleConversion.cc + Interaction.cc + Decay.cc + NuclearInteraction.cc sibyll2.3c.f nuclib.f signuc.f diff --git a/Processes/Sibyll/Decay.cc b/Processes/Sibyll/Decay.cc new file mode 100644 index 0000000000000000000000000000000000000000..1e0d1ca2b64be8db9444c94894fc6983a01e62ba --- /dev/null +++ b/Processes/Sibyll/Decay.cc @@ -0,0 +1,189 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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/process/sibyll/Decay.h> + +#include <corsika/process/sibyll/ParticleConversion.h> +#include <corsika/process/sibyll/SibStack.h> + +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> + +using std::cout; +using std::endl; +using std::tuple; +using std::vector; + +using namespace corsika; +using namespace corsika::setup; +using Particle = Stack::StackIterator; // ParticleType; +using Track = Trajectory; + +namespace corsika::process::sibyll { + + Decay::Decay() {} + Decay::~Decay() { cout << "Sibyll::Decay n=" << fCount << endl; } + void Decay::Init() { + setHadronsUnstable(); + setTrackedParticlesStable(); + } + + void Decay::setTrackedParticlesStable() { + /* + Sibyll is hadronic generator + only hadrons decay + */ + // set particles unstable + setHadronsUnstable(); + // make tracked particles stable + cout << "Interaction: setting tracked hadrons stable.." << endl; + const vector<particles::Code> particleList = { + particles::Code::PiPlus, particles::Code::PiMinus, particles::Code::KPlus, + particles::Code::KMinus, particles::Code::K0Long, particles::Code::K0Short}; + + for (auto p : particleList) { + // set particle stable by setting table value negative + const int sibid = process::sibyll::ConvertToSibyllRaw(p); + s_csydec_.idb[sibid - 1] = (-1) * abs(s_csydec_.idb[sibid - 1]); + } + } + + void Decay::setUnstable(const particles::Code pCode) { + int s_id = process::sibyll::ConvertToSibyllRaw(pCode); + s_csydec_.idb[s_id - 1] = abs(s_csydec_.idb[s_id - 1]); + } + + void Decay::setStable(const particles::Code pCode) { + int s_id = process::sibyll::ConvertToSibyllRaw(pCode); + s_csydec_.idb[s_id - 1] = (-1) * abs(s_csydec_.idb[s_id - 1]); + } + + void Decay::setAllStable() { + // name? also makes EM particles stable + + cout << "Decay: setting all particles stable.." << endl; + + // loop over all particles in sibyll + // should be changed to loop over human readable list + // i.e. particles::ListOfParticles() + for (auto& p : corsika2sibyll) { + // cout << (int)p << endl; + const int sibCode = static_cast<int>(p); + // skip unknown and antiparticles + if (sibCode < 1) continue; + s_csydec_.idb[sibCode - 1] = -1 * abs(s_csydec_.idb[sibCode - 1]); + } + } + + void Decay::setHadronsUnstable() { + + // name? also makes EM particles stable + + // loop over all particles in sibyll + // should be changed to loop over human readable list + // i.e. particles::ListOfParticles() + cout << "Sibyll: setting hadrons unstable.." << endl; + // make ALL particles unstable, then set EM stable + for (int sibCode : corsika2sibyll) { + if (sibCode < 1) continue; + s_csydec_.idb[sibCode - 1] = abs(s_csydec_.idb[sibCode - 1]); + } + // set Leptons and Proton and Neutron stable + // use stack to loop over particles + constexpr particles::Code particleList[] = { + particles::Code::Proton, particles::Code::Neutron, particles::Code::Electron, + particles::Code::Positron, particles::Code::NuE, particles::Code::NuEBar, + particles::Code::MuMinus, particles::Code::MuPlus, particles::Code::NuMu, + particles::Code::NuMuBar}; + + for (auto p : particleList) { + const int sibid = process::sibyll::ConvertToSibyllRaw(p); + s_csydec_.idb[sibid - 1] = (-1) * abs(s_csydec_.idb[sibid - 1]); + } + } + + template <> + units::si::TimeType Decay::GetLifetime(Particle const& p) { + using namespace units::si; + + HEPEnergyType E = p.GetEnergy(); + HEPMassType m = particles::GetMass(p.GetPID()); + + const double gamma = E / m; + + const TimeType t0 = particles::GetLifetime(p.GetPID()); + auto const lifetime = gamma * t0; + + const auto mkin = + (E * E - p.GetMomentum().squaredNorm()); // delta_mass(p.GetMomentum(), E, m); + cout << "Decay: code: " << p.GetPID() << endl; + cout << "Decay: MinStep: t0: " << t0 << endl; + cout << "Decay: MinStep: energy: " << E / 1_GeV << " GeV" << endl; + cout << "Decay: momentum: " << p.GetMomentum().GetComponents() / 1_GeV << " GeV" + << endl; + cout << "Decay: momentum: shell mass-kin. inv. mass " << mkin / 1_GeV / 1_GeV << " " + << m / 1_GeV * m / 1_GeV << endl; + auto sib_id = process::sibyll::ConvertToSibyllRaw(p.GetPID()); + cout << "Decay: sib mass: " << get_sibyll_mass2(sib_id) << endl; + cout << "Decay: MinStep: gamma: " << gamma << endl; + cout << "Decay: MinStep: tau: " << lifetime << endl; + + return lifetime; + } + + template <> + void Decay::DoDecay(Particle& p, Stack&) { + using geometry::Point; + using namespace units::si; + + fCount++; + SibStack ss; + ss.Clear(); + const particles::Code pCode = p.GetPID(); + // copy particle to sibyll stack + ss.AddParticle(process::sibyll::ConvertToSibyllRaw(pCode), p.GetEnergy(), + p.GetMomentum(), + // setting particle mass with Corsika values, may be inconsistent + // with sibyll internal values + particles::GetMass(pCode)); + // remember position + Point const decayPoint = p.GetPosition(); + TimeType const t0 = p.GetTime(); + // remove original particle from corsika stack + p.Delete(); + // set all particles/hadrons unstable + // setHadronsUnstable(); + setUnstable(pCode); + // call sibyll decay + cout << "Decay: calling Sibyll decay routine.." << endl; + decsib_(); + // reset to stable + setStable(pCode); + // print output + int print_unit = 6; + sib_list_(print_unit); + + // copy particles from sibyll stack to corsika + for (auto& psib : ss) { + // FOR NOW: skip particles that have decayed in Sibyll, move to iterator? + if (psib.HasDecayed()) continue; + // add to corsika stack + p.AddSecondary( + tuple<particles::Code, units::si::HEPEnergyType, corsika::stack::MomentumVector, + geometry::Point, units::si::TimeType>{ + process::sibyll::ConvertFromSibyll(psib.GetPID()), psib.GetEnergy(), + psib.GetMomentum(), decayPoint, t0}); + } + // empty sibyll stack + ss.Clear(); + } + +} // namespace corsika::process::sibyll diff --git a/Processes/Sibyll/Decay.h b/Processes/Sibyll/Decay.h index 24ccffcb8766824fd7f5da6050096d6da897ead6..c078af7b8763c4d6df9015177ed764f6a663b460 100644 --- a/Processes/Sibyll/Decay.h +++ b/Processes/Sibyll/Decay.h @@ -12,14 +12,8 @@ #ifndef _include_corsika_process_sibyll_decay_h_ #define _include_corsika_process_sibyll_decay_h_ -#include <corsika/process/DecayProcess.h> -#include <corsika/process/sibyll/ParticleConversion.h> -#include <corsika/process/sibyll/SibStack.h> - -#include <corsika/setup/SetupStack.h> -#include <corsika/setup/SetupTrajectory.h> - #include <corsika/particles/ParticleProperties.h> +#include <corsika/process/DecayProcess.h> namespace corsika::process { @@ -29,191 +23,21 @@ namespace corsika::process { int fCount = 0; public: - Decay() {} - ~Decay() { std::cout << "Sibyll::Decay n=" << fCount << std::endl; } - void Init() { - setHadronsUnstable(); - setTrackedParticlesStable(); - } - - void setTrackedParticlesStable() { - /* - Sibyll is hadronic generator - only hadrons decay - */ - // set particles unstable - setHadronsUnstable(); - // make tracked particles stable - std::cout << "Interaction: setting tracked hadrons stable.." << std::endl; - const std::vector<corsika::particles::Code> particleList = { - particles::Code::PiPlus, particles::Code::PiMinus, particles::Code::KPlus, - particles::Code::KMinus, particles::Code::K0Long, particles::Code::K0Short}; - - for (auto p : particleList) { - // set particle stable by setting table value negative - const int sibid = process::sibyll::ConvertToSibyllRaw(p); - s_csydec_.idb[sibid - 1] = (-1) * abs(s_csydec_.idb[sibid - 1]); - } - } - - void setUnstable(const corsika::particles::Code pCode) { - int s_id = process::sibyll::ConvertToSibyllRaw(pCode); - s_csydec_.idb[s_id - 1] = abs(s_csydec_.idb[s_id - 1]); - } - - void setStable(const corsika::particles::Code pCode) { - int s_id = process::sibyll::ConvertToSibyllRaw(pCode); - s_csydec_.idb[s_id - 1] = (-1) * abs(s_csydec_.idb[s_id - 1]); - } - - void setAllStable() { - // name? also makes EM particles stable - - using std::cout; - using std::endl; - - std::cout << "Decay: setting all particles stable.." << std::endl; - - // loop over all particles in sibyll - // should be changed to loop over human readable list - // i.e. corsika::particles::ListOfParticles() - for (auto& p : corsika2sibyll) { - // std::cout << (int)p << std::endl; - const int sibCode = static_cast<int>(p); - // skip unknown and antiparticles - if (sibCode < 1) continue; - s_csydec_.idb[sibCode - 1] = -1 * abs(s_csydec_.idb[sibCode - 1]); - } - } + Decay(); + ~Decay(); + void Init(); - void setHadronsUnstable() { - - using std::cout; - using std::endl; - using namespace corsika::units::si; - - // name? also makes EM particles stable - - // loop over all particles in sibyll - // should be changed to loop over human readable list - // i.e. corsika::particles::ListOfParticles() - std::cout << "Sibyll: setting hadrons unstable.." << std::endl; - // make ALL particles unstable, then set EM stable - for (int sibCode : corsika2sibyll) { - // std::cout << (int)p << std::endl; - // skip unknown and antiparticles - if (sibCode < 1) continue; - // std::cout << "Sibyll: Decay: setting " << ConvertFromSibyll( - // static_cast<SibyllCode> ( sibCode ) ) << " unstable" << std::endl; - s_csydec_.idb[sibCode - 1] = abs(s_csydec_.idb[sibCode - 1]); - // std::cout << "decay table value: " << s_csydec_.idb[ sibCode - 1 ] << - // std::endl; - } - // set Leptons and Proton and Neutron stable - // use stack to loop over particles - constexpr corsika::particles::Code particleList[] = { - corsika::particles::Code::Proton, corsika::particles::Code::Neutron, - corsika::particles::Code::Electron, corsika::particles::Code::Positron, - corsika::particles::Code::NuE, corsika::particles::Code::NuEBar, - corsika::particles::Code::MuMinus, corsika::particles::Code::MuPlus, - corsika::particles::Code::NuMu, corsika::particles::Code::NuMuBar}; - - for (auto p : particleList) { - // set particle stable by setting table value negative - // cout << "Sibyll: setting " << p.GetPID() << "(" << s_id << ")" - // << " stable in Sibyll .." << endl; - const int sibid = process::sibyll::ConvertToSibyllRaw(p); - s_csydec_.idb[sibid - 1] = (-1) * abs(s_csydec_.idb[sibid - 1]); - } - } + void setTrackedParticlesStable(); + void setUnstable(const corsika::particles::Code pCode); + void setStable(const corsika::particles::Code pCode); + void setAllStable(); + void setHadronsUnstable(); template <typename Particle> - corsika::units::si::TimeType GetLifetime(Particle const& p) { - using std::cout; - using std::endl; - using namespace corsika::units::si; - - corsika::units::si::HEPEnergyType E = p.GetEnergy(); - corsika::units::si::HEPMassType m = corsika::particles::GetMass(p.GetPID()); - - const double gamma = E / m; - - const corsika::units::si::TimeType t0 = - corsika::particles::GetLifetime(p.GetPID()); - auto const lifetime = gamma * t0; - - const auto mkin = - (E * E - p.GetMomentum().squaredNorm()); // delta_mass(p.GetMomentum(), E, m); - cout << "Decay: code: " << p.GetPID() << endl; - cout << "Decay: MinStep: t0: " << t0 << endl; - cout << "Decay: MinStep: energy: " << E / 1_GeV << " GeV" << endl; - cout << "Decay: momentum: " << p.GetMomentum().GetComponents() / 1_GeV << " GeV" - << endl; - cout << "Decay: momentum: shell mass-kin. inv. mass " << mkin / 1_GeV / 1_GeV - << " " << m / 1_GeV * m / 1_GeV << endl; - // cout << "Decay: sib mass: " << s_mass1_.am2[ - // process::sibyll::ConvertToSibyllRaw(p.GetPID()) ] << endl; - auto sib_id = process::sibyll::ConvertToSibyllRaw(p.GetPID()); - cout << "Decay: sib mass: " << get_sibyll_mass2(sib_id) << endl; - cout << "Decay: MinStep: gamma: " << gamma << endl; - cout << "Decay: MinStep: tau: " << lifetime << endl; - - return lifetime; - } + corsika::units::si::TimeType GetLifetime(Particle const& p); template <typename Particle, typename Stack> - void DoDecay(Particle& p, Stack&) { - using corsika::geometry::Point; - using namespace corsika::units::si; - - fCount++; - SibStack ss; - ss.Clear(); - const corsika::particles::Code pCode = p.GetPID(); - // copy particle to sibyll stack - ss.AddParticle( - // std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - // corsika::stack::MomentumVector, corsika::geometry::Point, - // corsika::units::si::TimeType>{ - corsika::process::sibyll::ConvertToSibyllRaw(pCode), p.GetEnergy(), - p.GetMomentum(), - // setting particle mass with Corsika values, may be inconsistent - // with sibyll internal values - // TODO: #warning setting particle mass with Corsika values, may be - // inconsistent with sibyll internal values - corsika::particles::GetMass(pCode)); - // remember position - Point const decayPoint = p.GetPosition(); - TimeType const t0 = p.GetTime(); - // remove original particle from corsika stack - p.Delete(); - // set all particles/hadrons unstable - // setHadronsUnstable(); - setUnstable(pCode); - // call sibyll decay - std::cout << "Decay: calling Sibyll decay routine.." << std::endl; - decsib_(); - // reset to stable - setStable(pCode); - // print output - int print_unit = 6; - sib_list_(print_unit); - - // copy particles from sibyll stack to corsika - for (auto& psib : ss) { - // FOR NOW: skip particles that have decayed in Sibyll, move to iterator? - if (psib.HasDecayed()) continue; - // add to corsika stack - p.AddSecondary( - std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - corsika::stack::MomentumVector, corsika::geometry::Point, - corsika::units::si::TimeType>{ - corsika::process::sibyll::ConvertFromSibyll(psib.GetPID()), - psib.GetEnergy(), psib.GetMomentum(), decayPoint, t0}); - } - // empty sibyll stack - ss.Clear(); - } + void DoDecay(Particle& p, Stack&); }; } // namespace sibyll } // namespace corsika::process diff --git a/Processes/Sibyll/Interaction.cc b/Processes/Sibyll/Interaction.cc new file mode 100644 index 0000000000000000000000000000000000000000..893de4f51263b21b374d4292c9c6c18f58cbb879 --- /dev/null +++ b/Processes/Sibyll/Interaction.cc @@ -0,0 +1,362 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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/process/sibyll/Interaction.h> + +#include <corsika/environment/Environment.h> +#include <corsika/environment/NuclearComposition.h> +#include <corsika/geometry/FourVector.h> +#include <corsika/process/sibyll/ParticleConversion.h> +#include <corsika/process/sibyll/SibStack.h> +#include <corsika/process/sibyll/sibyll2.3c.h> +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> +#include <corsika/utl/COMBoost.h> + +#include <tuple> + +using std::cout; +using std::endl; +using std::tuple; + +using namespace corsika; +using namespace corsika::setup; +using Particle = Stack::StackIterator; // ParticleType; +using Track = Trajectory; + +namespace corsika::process::sibyll { + + Interaction::Interaction(environment::Environment const& env) + : fEnvironment(env) {} + + Interaction::~Interaction() { + cout << "Sibyll::Interaction n=" << fCount << " Nnuc=" << fNucCount << endl; + } + + void Interaction::Init() { + + using random::RNGManager; + + // initialize Sibyll + if (!fInitialized) { + sibyll_ini_(); + + fInitialized = true; + } + } + + tuple<units::si::CrossSectionType, units::si::CrossSectionType, int> + Interaction::GetCrossSection(const particles::Code BeamId, + const particles::Code TargetId, + const units::si::HEPEnergyType CoMenergy) { + using namespace units::si; + double sigProd, sigEla, dummy, dum1, dum3, dum4; + double dumdif[3]; + const int iBeam = process::sibyll::GetSibyllXSCode(BeamId); + const double dEcm = CoMenergy / 1_GeV; + int iTarget = -1; + if (particles::IsNucleus(TargetId)) { + iTarget = particles::GetNucleusA(TargetId); + if (iTarget > 18 || iTarget == 0) + throw std::runtime_error( + "Sibyll target outside range. Only nuclei with A<18 are allowed."); + sib_sigma_hnuc_(iBeam, iTarget, dEcm, sigProd, dummy, sigEla); + } else if (TargetId == particles::Proton::GetCode()) { + sib_sigma_hp_(iBeam, dEcm, dum1, sigEla, sigProd, dumdif, dum3, dum4); + iTarget = 1; + } else { + // no interaction in sibyll possible, return infinite cross section? or throw? + sigProd = std::numeric_limits<double>::infinity(); + sigEla = std::numeric_limits<double>::infinity(); + } + return std::make_tuple(sigProd * 1_mbarn, sigEla * 1_mbarn, iTarget); + } + + template <> + units::si::GrammageType Interaction::GetInteractionLength(Particle& p, Track&) { + + using namespace units; + using namespace units::si; + using namespace geometry; + + // coordinate system, get global frame of reference + CoordinateSystem& rootCS = + RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); + + const particles::Code corsikaBeamId = p.GetPID(); + + // beam particles for sibyll : 1, 2, 3 for p, pi, k + // read from cross section code table + const bool kInteraction = process::sibyll::CanInteract(corsikaBeamId); + + const HEPMassType nucleon_mass = + 0.5 * (particles::Proton::GetMass() + particles::Neutron::GetMass()); + + // FOR NOW: assume target is at rest + MomentumVector pTarget(rootCS, {0_GeV, 0_GeV, 0_GeV}); + + // total momentum and energy + HEPEnergyType Elab = p.GetEnergy() + nucleon_mass; + MomentumVector pTotLab(rootCS, {0_GeV, 0_GeV, 0_GeV}); + pTotLab += p.GetMomentum(); + pTotLab += pTarget; + auto const pTotLabNorm = pTotLab.norm(); + // calculate cm. energy + const HEPEnergyType ECoM = sqrt( + (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy + + cout << "Interaction: LambdaInt: \n" + << " input energy: " << p.GetEnergy() / 1_GeV << endl + << " beam can interact:" << kInteraction << endl + << " beam pid:" << p.GetPID() << endl; + + // TODO: move limits into variables + if (kInteraction && Elab >= 8.5_GeV && ECoM >= 10_GeV) { + + // get target from environment + /* + the target should be defined by the Environment, + ideally as full particle object so that the four momenta + and the boosts can be defined.. + */ + const auto currentNode = + fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); + const auto mediumComposition = + currentNode->GetModelProperties().GetNuclearComposition(); + // determine average interaction length + // weighted sum + int i = -1; + double avgTargetMassNumber = 0.; + si::CrossSectionType weightedProdCrossSection = 0_mbarn; + // get weights of components from environment/medium + const auto w = mediumComposition.GetFractions(); + // loop over components in medium + for (auto const targetId : mediumComposition.GetComponents()) { + i++; + cout << "Interaction: get interaction length for target: " << targetId << endl; + + auto const [productionCrossSection, elaCrossSection, numberOfNucleons] = + GetCrossSection(corsikaBeamId, targetId, ECoM); + [[maybe_unused]] auto elaCrossSectionCopy = + elaCrossSection; // ONLY TO AVOID COMPILER WARNING + + cout << "Interaction: " + << " IntLength: sibyll return (mb): " << productionCrossSection / 1_mbarn + << endl; + weightedProdCrossSection += w[i] * productionCrossSection; + avgTargetMassNumber += w[i] * numberOfNucleons; + } + cout << "Interaction: " + << "IntLength: weighted CrossSection (mb): " + << weightedProdCrossSection / 1_mbarn << endl; + + // calculate interaction length in medium + //#warning check interaction length units + GrammageType const int_length = + avgTargetMassNumber * units::constants::u / weightedProdCrossSection; + cout << "Interaction: " + << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm + << endl; + + return int_length; + } + + return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); + } + + /** + In this function SIBYLL is called to produce one event. The + event is copied (and boosted) into the shower lab frame. + */ + + template <> + process::EProcessReturn Interaction::DoInteraction(Particle& p, Stack&) { + + using namespace units; + using namespace utl; + using namespace units::si; + using namespace geometry; + + const auto corsikaBeamId = p.GetPID(); + cout << "ProcessSibyll: " + << "DoInteraction: " << corsikaBeamId << " interaction? " + << process::sibyll::CanInteract(corsikaBeamId) << endl; + + if (particles::IsNucleus(corsikaBeamId)) { + // nuclei handled by different process, this should not happen + throw std::runtime_error("Nuclear projectile are not handled by SIBYLL!"); + } + + if (process::sibyll::CanInteract(corsikaBeamId)) { + const CoordinateSystem& rootCS = + RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); + + // position and time of interaction, not used in Sibyll + Point pOrig = p.GetPosition(); + TimeType tOrig = p.GetTime(); + + // define target + // for Sibyll is always a single nucleon + auto constexpr nucleon_mass = + 0.5 * (particles::Proton::GetMass() + particles::Neutron::GetMass()); + // FOR NOW: target is always at rest + const auto eTargetLab = 0_GeV + nucleon_mass; + const auto pTargetLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV); + const FourVector PtargLab(eTargetLab, pTargetLab); + + // define projectile + HEPEnergyType const eProjectileLab = p.GetEnergy(); + auto const pProjectileLab = p.GetMomentum(); + + cout << "Interaction: ebeam lab: " << eProjectileLab / 1_GeV << endl + << "Interaction: pbeam lab: " << pProjectileLab.GetComponents() / 1_GeV + << endl; + cout << "Interaction: etarget lab: " << eTargetLab / 1_GeV << endl + << "Interaction: ptarget lab: " << pTargetLab.GetComponents() / 1_GeV << endl; + + const FourVector PprojLab(eProjectileLab, pProjectileLab); + + // define target kinematics in lab frame + // define boost to and from CoM frame + // CoM frame definition in Sibyll projectile: +z + COMBoost const boost(PprojLab, nucleon_mass); + + // just for show: + // boost projecticle + auto const PprojCoM = boost.toCoM(PprojLab); + + // boost target + auto const PtargCoM = boost.toCoM(PtargLab); + + cout << "Interaction: ebeam CoM: " << PprojCoM.GetTimeLikeComponent() / 1_GeV + << endl + << "Interaction: pbeam CoM: " + << PprojCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; + cout << "Interaction: etarget CoM: " << PtargCoM.GetTimeLikeComponent() / 1_GeV + << endl + << "Interaction: ptarget CoM: " + << PtargCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; + + cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() << endl; + cout << "Interaction: time: " << tOrig << endl; + + HEPEnergyType Etot = eProjectileLab + eTargetLab; + MomentumVector Ptot = p.GetMomentum(); + // invariant mass, i.e. cm. energy + HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.squaredNorm()); + + // sample target mass number + const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(pOrig); + const auto& mediumComposition = + currentNode->GetModelProperties().GetNuclearComposition(); + // get cross sections for target materials + /* + Here we read the cross section from the interaction model again, + should be passed from GetInteractionLength if possible + */ + //#warning reading interaction cross section again, should not be necessary + auto const& compVec = mediumComposition.GetComponents(); + std::vector<si::CrossSectionType> cross_section_of_components(compVec.size()); + + for (size_t i = 0; i < compVec.size(); ++i) { + auto const targetId = compVec[i]; + const auto [sigProd, sigEla, nNuc] = + GetCrossSection(corsikaBeamId, targetId, Ecm); + cross_section_of_components[i] = sigProd; + [[maybe_unused]] int ideleteme = + nNuc; // to avoid not used warning in array binding + [[maybe_unused]] auto sigElaCopy = + sigEla; // to avoid not used warning in array binding + } + + const auto targetCode = currentNode->GetModelProperties().SampleTarget( + cross_section_of_components, fRNG); + cout << "Interaction: target selected: " << targetCode << endl; + /* + FOR NOW: allow nuclei with A<18 or protons only. + when medium composition becomes more complex, approximations will have to be + allowed air in atmosphere also contains some Argon. + */ + int targetSibCode = -1; + if (IsNucleus(targetCode)) targetSibCode = GetNucleusA(targetCode); + if (targetCode == particles::Proton::GetCode()) targetSibCode = 1; + cout << "Interaction: sibyll code: " << targetSibCode << endl; + if (targetSibCode > 18 || targetSibCode < 1) + throw std::runtime_error( + "Sibyll target outside range. Only nuclei with A<18 or protons are " + "allowed."); + + // beam id for sibyll + const int kBeam = process::sibyll::ConvertToSibyllRaw(corsikaBeamId); + + cout << "Interaction: " + << " DoInteraction: E(GeV):" << eProjectileLab / 1_GeV + << " Ecm(GeV): " << Ecm / 1_GeV << endl; + if (eProjectileLab < 8.5_GeV || Ecm < 10_GeV) { + cout << "Interaction: " + << " DoInteraction: should have dropped particle.. " + << "THIS IS AN ERROR" << endl; + throw std::runtime_error("energy too low for SIBYLL"); + // p.Delete(); delete later... different process + } else { + fCount++; + // Sibyll does not know about units.. + const double sqs = Ecm / 1_GeV; + // running sibyll, filling stack + sibyll_(kBeam, targetSibCode, sqs); + // running decays + // setTrackedParticlesStable(); + decsib_(); + // print final state + int print_unit = 6; + sib_list_(print_unit); + fNucCount += get_nwounded() - 1; + + // delete current particle + p.Delete(); + + // add particles from sibyll to stack + // link to sibyll stack + SibStack ss; + + MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); + HEPEnergyType Elab_final = 0_GeV, Ecm_final = 0_GeV; + for (auto& psib : ss) { + + // skip particles that have decayed in Sibyll + if (psib.HasDecayed()) continue; + + // transform energy to lab. frame + auto const pCoM = psib.GetMomentum(); + HEPEnergyType const eCoM = psib.GetEnergy(); + auto const Plab = boost.fromCoM(FourVector(eCoM, pCoM)); + + // add to corsika stack + auto pnew = p.AddSecondary( + tuple<particles::Code, units::si::HEPEnergyType, stack::MomentumVector, + geometry::Point, units::si::TimeType>{ + process::sibyll::ConvertFromSibyll(psib.GetPID()), + Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig, + tOrig}); + + Plab_final += pnew.GetMomentum(); + Elab_final += pnew.GetEnergy(); + Ecm_final += psib.GetEnergy(); + } + cout << "conservation (all GeV): Ecm_final=" << Ecm_final / 1_GeV << endl + << "Elab_final=" << Elab_final / 1_GeV + << ", Plab_final=" << (Plab_final / 1_GeV).GetComponents() << endl; + } + } + return process::EProcessReturn::eOk; + } + +} // namespace corsika::process::sibyll diff --git a/Processes/Sibyll/Interaction.h b/Processes/Sibyll/Interaction.h index 6a85592fe5af8b62d7e75f34db80abe60e247c16..40463f6657c2b6e877be5a018b7cfcf67ae6f884 100644 --- a/Processes/Sibyll/Interaction.h +++ b/Processes/Sibyll/Interaction.h @@ -12,18 +12,15 @@ #ifndef _corsika_process_sibyll_interaction_h_ #define _corsika_process_sibyll_interaction_h_ -#include <corsika/process/InteractionProcess.h> - -#include <corsika/environment/Environment.h> -#include <corsika/environment/NuclearComposition.h> -#include <corsika/geometry/FourVector.h> #include <corsika/particles/ParticleProperties.h> -#include <corsika/process/sibyll/ParticleConversion.h> -#include <corsika/process/sibyll/SibStack.h> -#include <corsika/process/sibyll/sibyll2.3c.h> +#include <corsika/process/InteractionProcess.h> #include <corsika/random/RNGManager.h> #include <corsika/units/PhysicalUnits.h> -#include <corsika/utl/COMBoost.h> +#include <tuple> + +namespace corsika::environment { + class Environment; +} namespace corsika::process::sibyll { @@ -34,28 +31,12 @@ namespace corsika::process::sibyll { bool fInitialized = false; public: - Interaction(corsika::environment::Environment const& env) - : fEnvironment(env) {} - ~Interaction() { - std::cout << "Sibyll::Interaction n=" << fCount << " Nnuc=" << fNucCount - << std::endl; - } - - void Init() { + Interaction(corsika::environment::Environment const& env); + ~Interaction(); - using corsika::random::RNGManager; - using std::cout; - using std::endl; - - // initialize Sibyll - if (!fInitialized) { - sibyll_ini_(); - fInitialized = true; - } - } + void Init(); bool WasInitialized() { return fInitialized; } - bool ValidCoMEnergy(corsika::units::si::HEPEnergyType ecm) { using namespace corsika::units::si; return (10_GeV < ecm) && (ecm < 1_PeV); @@ -65,123 +46,10 @@ namespace corsika::process::sibyll { int> GetCrossSection(const corsika::particles::Code BeamId, const corsika::particles::Code TargetId, - const corsika::units::si::HEPEnergyType CoMenergy) { - using namespace corsika::units::si; - double sigProd, sigEla, dummy, dum1, dum3, dum4; - double dumdif[3]; - const int iBeam = process::sibyll::GetSibyllXSCode(BeamId); - const double dEcm = CoMenergy / 1_GeV; - int iTarget = -1; - if (corsika::particles::IsNucleus(TargetId)) { - iTarget = corsika::particles::GetNucleusA(TargetId); - if (iTarget > 18 || iTarget == 0) - throw std::runtime_error( - "Sibyll target outside range. Only nuclei with A<18 are allowed."); - sib_sigma_hnuc_(iBeam, iTarget, dEcm, sigProd, dummy, sigEla); - } else if (TargetId == corsika::particles::Proton::GetCode()) { - sib_sigma_hp_(iBeam, dEcm, dum1, sigEla, sigProd, dumdif, dum3, dum4); - iTarget = 1; - } else { - // no interaction in sibyll possible, return infinite cross section? or throw? - sigProd = std::numeric_limits<double>::infinity(); - sigEla = std::numeric_limits<double>::infinity(); - } - return std::make_tuple(sigProd * 1_mbarn, sigEla * 1_mbarn, iTarget); - } + const corsika::units::si::HEPEnergyType CoMenergy); template <typename Particle, typename Track> - corsika::units::si::GrammageType GetInteractionLength(Particle const& p, Track&) { - - using namespace corsika::units; - using namespace corsika::units::si; - using namespace corsika::geometry; - using std::cout; - using std::endl; - - // coordinate system, get global frame of reference - CoordinateSystem& rootCS = - RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); - - const particles::Code corsikaBeamId = p.GetPID(); - - // beam particles for sibyll : 1, 2, 3 for p, pi, k - // read from cross section code table - const bool kInteraction = process::sibyll::CanInteract(corsikaBeamId); - - const HEPMassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() + - corsika::particles::Neutron::GetMass()); - - // FOR NOW: assume target is at rest - MomentumVector pTarget(rootCS, {0_GeV, 0_GeV, 0_GeV}); - - // total momentum and energy - HEPEnergyType Elab = p.GetEnergy() + nucleon_mass; - MomentumVector pTotLab(rootCS, {0_GeV, 0_GeV, 0_GeV}); - pTotLab += p.GetMomentum(); - pTotLab += pTarget; - auto const pTotLabNorm = pTotLab.norm(); - // calculate cm. energy - const HEPEnergyType ECoM = sqrt( - (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy - - std::cout << "Interaction: LambdaInt: \n" - << " input energy: " << p.GetEnergy() / 1_GeV << endl - << " beam can interact:" << kInteraction << endl - << " beam pid:" << p.GetPID() << endl; - - // TODO: move limits into variables - if (kInteraction && Elab >= 8.5_GeV && ECoM >= 10_GeV) { - - // get target from environment - /* - the target should be defined by the Environment, - ideally as full particle object so that the four momenta - and the boosts can be defined.. - */ - const auto currentNode = - fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); - const auto mediumComposition = - currentNode->GetModelProperties().GetNuclearComposition(); - // determine average interaction length - // weighted sum - int i = -1; - double avgTargetMassNumber = 0.; - si::CrossSectionType weightedProdCrossSection = 0_mbarn; - // get weights of components from environment/medium - const auto w = mediumComposition.GetFractions(); - // loop over components in medium - for (auto const targetId : mediumComposition.GetComponents()) { - i++; - cout << "Interaction: get interaction length for target: " << targetId << endl; - - auto const [productionCrossSection, elaCrossSection, numberOfNucleons] = - GetCrossSection(corsikaBeamId, targetId, ECoM); - [[maybe_unused]] auto elaCrossSectionCopy = - elaCrossSection; // ONLY TO AVOID COMPILER WARNING - - std::cout << "Interaction: " - << " IntLength: sibyll return (mb): " - << productionCrossSection / 1_mbarn << std::endl; - weightedProdCrossSection += w[i] * productionCrossSection; - avgTargetMassNumber += w[i] * numberOfNucleons; - } - cout << "Interaction: " - << "IntLength: weighted CrossSection (mb): " - << weightedProdCrossSection / 1_mbarn << endl; - - // calculate interaction length in medium - //#warning check interaction length units - GrammageType const int_length = - avgTargetMassNumber * corsika::units::constants::u / weightedProdCrossSection; - std::cout << "Interaction: " - << "interaction length (g/cm2): " - << int_length / (0.001_kg) * 1_cm * 1_cm << std::endl; - - return int_length; - } - - return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); - } + corsika::units::si::GrammageType GetInteractionLength(Particle&, Track&); /** In this function SIBYLL is called to produce one event. The @@ -189,193 +57,7 @@ namespace corsika::process::sibyll { */ template <typename Particle, typename Stack> - corsika::process::EProcessReturn DoInteraction(Particle& p, Stack&) { - - using namespace corsika::units; - using namespace corsika::utl; - using namespace corsika::units::si; - using namespace corsika::geometry; - using std::cout; - using std::endl; - - const auto corsikaBeamId = p.GetPID(); - cout << "ProcessSibyll: " - << "DoInteraction: " << corsikaBeamId << " interaction? " - << process::sibyll::CanInteract(corsikaBeamId) << endl; - - if (corsika::particles::IsNucleus(corsikaBeamId)) { - // nuclei handled by different process, this should not happen - throw std::runtime_error("Nuclear projectile are not handled by SIBYLL!"); - } - - if (process::sibyll::CanInteract(corsikaBeamId)) { - const CoordinateSystem& rootCS = - RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); - - // position and time of interaction, not used in Sibyll - Point pOrig = p.GetPosition(); - TimeType tOrig = p.GetTime(); - - // define target - // for Sibyll is always a single nucleon - auto constexpr nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() + - corsika::particles::Neutron::GetMass()); - // FOR NOW: target is always at rest - const auto eTargetLab = 0_GeV + nucleon_mass; - const auto pTargetLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV); - const FourVector PtargLab(eTargetLab, pTargetLab); - - // define projectile - HEPEnergyType const eProjectileLab = p.GetEnergy(); - auto const pProjectileLab = p.GetMomentum(); - - cout << "Interaction: ebeam lab: " << eProjectileLab / 1_GeV << endl - << "Interaction: pbeam lab: " << pProjectileLab.GetComponents() / 1_GeV - << endl; - cout << "Interaction: etarget lab: " << eTargetLab / 1_GeV << endl - << "Interaction: ptarget lab: " << pTargetLab.GetComponents() / 1_GeV - << endl; - - const FourVector PprojLab(eProjectileLab, pProjectileLab); - - // define target kinematics in lab frame - // define boost to and from CoM frame - // CoM frame definition in Sibyll projectile: +z - COMBoost const boost(PprojLab, nucleon_mass); - - // just for show: - // boost projecticle - auto const PprojCoM = boost.toCoM(PprojLab); - - // boost target - auto const PtargCoM = boost.toCoM(PtargLab); - - cout << "Interaction: ebeam CoM: " << PprojCoM.GetTimeLikeComponent() / 1_GeV - << endl - << "Interaction: pbeam CoM: " - << PprojCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; - cout << "Interaction: etarget CoM: " << PtargCoM.GetTimeLikeComponent() / 1_GeV - << endl - << "Interaction: ptarget CoM: " - << PtargCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; - - cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() - << endl; - cout << "Interaction: time: " << tOrig << endl; - - HEPEnergyType Etot = eProjectileLab + eTargetLab; - MomentumVector Ptot = p.GetMomentum(); - // invariant mass, i.e. cm. energy - HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.squaredNorm()); - - // sample target mass number - const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(pOrig); - const auto& mediumComposition = - currentNode->GetModelProperties().GetNuclearComposition(); - // get cross sections for target materials - /* - Here we read the cross section from the interaction model again, - should be passed from GetInteractionLength if possible - */ - //#warning reading interaction cross section again, should not be necessary - auto const& compVec = mediumComposition.GetComponents(); - std::vector<si::CrossSectionType> cross_section_of_components(compVec.size()); - - for (size_t i = 0; i < compVec.size(); ++i) { - auto const targetId = compVec[i]; - const auto [sigProd, sigEla, nNuc] = - GetCrossSection(corsikaBeamId, targetId, Ecm); - cross_section_of_components[i] = sigProd; - [[maybe_unused]] int ideleteme = - nNuc; // to avoid not used warning in array binding - [[maybe_unused]] auto sigElaCopy = - sigEla; // to avoid not used warning in array binding - } - - const auto targetCode = currentNode->GetModelProperties().SampleTarget( - cross_section_of_components, fRNG); - cout << "Interaction: target selected: " << targetCode << endl; - /* - FOR NOW: allow nuclei with A<18 or protons only. - when medium composition becomes more complex, approximations will have to be - allowed air in atmosphere also contains some Argon. - */ - int targetSibCode = -1; - if (IsNucleus(targetCode)) targetSibCode = GetNucleusA(targetCode); - if (targetCode == corsika::particles::Proton::GetCode()) targetSibCode = 1; - cout << "Interaction: sibyll code: " << targetSibCode << endl; - if (targetSibCode > 18 || targetSibCode < 1) - throw std::runtime_error( - "Sibyll target outside range. Only nuclei with A<18 or protons are " - "allowed."); - - // beam id for sibyll - const int kBeam = process::sibyll::ConvertToSibyllRaw(corsikaBeamId); - - std::cout << "Interaction: " - << " DoInteraction: E(GeV):" << eProjectileLab / 1_GeV - << " Ecm(GeV): " << Ecm / 1_GeV << std::endl; - if (eProjectileLab < 8.5_GeV || Ecm < 10_GeV) { - std::cout << "Interaction: " - << " DoInteraction: should have dropped particle.. " - << "THIS IS AN ERROR" << std::endl; - throw std::runtime_error("energy too low for SIBYLL"); - // p.Delete(); delete later... different process - } else { - fCount++; - // Sibyll does not know about units.. - const double sqs = Ecm / 1_GeV; - // running sibyll, filling stack - sibyll_(kBeam, targetSibCode, sqs); - // running decays - // setTrackedParticlesStable(); - decsib_(); - // print final state - int print_unit = 6; - sib_list_(print_unit); - fNucCount += get_nwounded() - 1; - - // delete current particle - p.Delete(); - - // add particles from sibyll to stack - // link to sibyll stack - SibStack ss; - - MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); - HEPEnergyType Elab_final = 0_GeV, Ecm_final = 0_GeV; - for (auto& psib : ss) { - - // skip particles that have decayed in Sibyll - if (psib.HasDecayed()) continue; - - // transform energy to lab. frame - auto const pCoM = psib.GetMomentum(); - HEPEnergyType const eCoM = psib.GetEnergy(); - auto const Plab = boost.fromCoM(FourVector(eCoM, pCoM)); - - // add to corsika stack - auto pnew = - p.AddSecondary(std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, - units::si::TimeType>{ - process::sibyll::ConvertFromSibyll(psib.GetPID()), - Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig, - tOrig}); - - Plab_final += pnew.GetMomentum(); - Elab_final += pnew.GetEnergy(); - Ecm_final += psib.GetEnergy(); - } - std::cout << "conservation (all GeV): Ecm_final=" << Ecm_final / 1_GeV - << std::endl - << "Elab_final=" << Elab_final / 1_GeV - << ", Plab_final=" << (Plab_final / 1_GeV).GetComponents() - << std::endl; - } - } - return process::EProcessReturn::eOk; - } + corsika::process::EProcessReturn DoInteraction(Particle&, Stack&); private: corsika::environment::Environment const& fEnvironment; diff --git a/Processes/Sibyll/NuclearInteraction.cc b/Processes/Sibyll/NuclearInteraction.cc new file mode 100644 index 0000000000000000000000000000000000000000..b3602cb57198aeb57619c37476ef3050594431da --- /dev/null +++ b/Processes/Sibyll/NuclearInteraction.cc @@ -0,0 +1,523 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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/process/sibyll/Interaction.h> +#include <corsika/process/sibyll/NuclearInteraction.h> + +#include <corsika/environment/Environment.h> +#include <corsika/environment/NuclearComposition.h> +#include <corsika/geometry/FourVector.h> +#include <corsika/process/sibyll/nuclib.h> +#include <corsika/units/PhysicalUnits.h> +#include <corsika/utl/COMBoost.h> + +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> + +using std::cout; +using std::endl; +using std::tuple; +using std::vector; + +using namespace corsika; +using namespace corsika::setup; +using Particle = Stack::StackIterator; // ParticleType; +using Track = Trajectory; + +namespace corsika::process::sibyll { + + NuclearInteraction::NuclearInteraction(environment::Environment const& env, + process::sibyll::Interaction& hadint) + : fEnvironment(env) + , fHadronicInteraction(hadint) {} + + NuclearInteraction::~NuclearInteraction() { + cout << "Nuclib::NuclearInteraction n=" << fCount << " Nnuc=" << fNucCount << endl; + } + + void NuclearInteraction::Init() { + + using random::RNGManager; + + // initialize hadronic interaction module + // TODO: safe to run multiple initializations? + if (!fHadronicInteraction.WasInitialized()) fHadronicInteraction.Init(); + + // initialize nuclib + // TODO: make sure this does not overlap with sibyll + nuc_nuc_ini_(); + } + + // TODO: remove number of nucleons, avg target mass is available in environment + template <> + tuple<units::si::CrossSectionType, units::si::CrossSectionType> + NuclearInteraction::GetCrossSection(Particle& p, const particles::Code TargetId) { + using namespace units::si; + double sigProd; + auto const pCode = p.GetPID(); + if (pCode != particles::Code::Nucleus) + throw std::runtime_error( + "NuclearInteraction: GetCrossSection: particle not a nucleus!"); + + auto const iBeam = p.GetNuclearA(); + HEPEnergyType LabEnergyPerNuc = p.GetEnergy() / iBeam; + cout << "NuclearInteraction: GetCrossSection: called with: beamNuclA= " << iBeam + << " TargetId= " << TargetId << " LabEnergyPerNuc= " << LabEnergyPerNuc / 1_GeV + << endl; + + // use nuclib to calc. nuclear cross sections + // TODO: for now assumes air with hard coded composition + // extend to arbitrary mixtures, requires smarter initialization + // get nuclib projectile code: nucleon number + if (iBeam > 56 || iBeam < 2) { + cout << "NuclearInteraction: beam nucleus outside allowed range for NUCLIB!" << endl + << "A=" << iBeam << endl; + throw std::runtime_error( + "NuclearInteraction: GetCrossSection: beam nucleus outside allowed range for " + "NUCLIB!"); + } + + const double dElabNuc = LabEnergyPerNuc / 1_GeV; + // TODO: these limitations are still sibyll specific. + // available target nuclei depends on the hadronic interaction model and the + // initialization + if (dElabNuc < 10.) + throw std::runtime_error("NuclearInteraction: GetCrossSection: energy too low!"); + + // TODO: these limitations are still sibyll specific. + // available target nuclei depends on the hadronic interaction model and the + // initialization + if (particles::IsNucleus(TargetId)) { + const int iTarget = particles::GetNucleusA(TargetId); + if (iTarget > 18 || iTarget == 0) + throw std::runtime_error( + "Sibyll target outside range. Only nuclei with A<18 are allowed."); + cout << "NuclearInteraction: calling signuc.." << endl; + cout << "WARNING: using hard coded cross section for Nucleus-Air with " + "SIBYLL! (fix me!)" + << endl; + // TODO: target id is not used because cross section is still hard coded and fixed + // to air. + signuc_(iBeam, dElabNuc, sigProd); + cout << "cross section: " << sigProd << endl; + return std::make_tuple(sigProd * 1_mbarn, 0_mbarn); + } + return std::make_tuple(std::numeric_limits<double>::infinity() * 1_mbarn, + std::numeric_limits<double>::infinity() * 1_mbarn); + } + + template <> + units::si::GrammageType NuclearInteraction::GetInteractionLength(Particle& p, Track&) { + + using namespace units; + using namespace units::si; + using namespace geometry; + + // coordinate system, get global frame of reference + CoordinateSystem& rootCS = + RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); + + const particles::Code corsikaBeamId = p.GetPID(); + if (!particles::IsNucleus(corsikaBeamId)) { + // no nuclear interaction + return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); + } + // check if target-style nucleus (enum) + if (corsikaBeamId != particles::Code::Nucleus) + throw std::runtime_error( + "NuclearInteraction: GetInteractionLength: Wrong nucleus type. Nuclear " + "projectiles should use NuclearStackExtension!"); + + // read from cross section code table + const HEPMassType nucleon_mass = + 0.5 * (particles::Proton::GetMass() + particles::Neutron::GetMass()); + + // FOR NOW: assume target is at rest + corsika::stack::MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); + + // total momentum and energy + HEPEnergyType Elab = p.GetEnergy() + nucleon_mass; + int const nuclA = p.GetNuclearA(); + auto const ElabNuc = p.GetEnergy() / nuclA; + + corsika::stack::MomentumVector pTotLab(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); + pTotLab += p.GetMomentum(); + pTotLab += pTarget; + auto const pTotLabNorm = pTotLab.norm(); + // calculate cm. energy + const HEPEnergyType ECoM = sqrt( + (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy + auto const ECoMNN = sqrt(2. * ElabNuc * nucleon_mass); + cout << "NuclearInteraction: LambdaInt: \n" + << " input energy: " << Elab / 1_GeV << endl + << " input energy CoM: " << ECoM / 1_GeV << endl + << " beam pid:" << corsikaBeamId << endl + << " beam A: " << nuclA << endl + << " input energy per nucleon: " << ElabNuc / 1_GeV << endl + << " input energy CoM per nucleon: " << ECoMNN / 1_GeV << endl; + // throw std::runtime_error("stop here"); + + // energy limits + // TODO: values depend on hadronic interaction model !! this is sibyll specific + if (ElabNuc >= 8.5_GeV && ECoMNN >= 10_GeV) { + + // get target from environment + /* + the target should be defined by the Environment, + ideally as full particle object so that the four momenta + and the boosts can be defined.. + */ + const auto currentNode = + fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); + const auto mediumComposition = + currentNode->GetModelProperties().GetNuclearComposition(); + // determine average interaction length + // weighted sum + int i = -1; + si::CrossSectionType weightedProdCrossSection = 0_mbarn; + // get weights of components from environment/medium + const auto w = mediumComposition.GetFractions(); + // loop over components in medium + for (auto const targetId : mediumComposition.GetComponents()) { + i++; + cout << "NuclearInteraction: get interaction length for target: " << targetId + << endl; + auto const [productionCrossSection, elaCrossSection] = + GetCrossSection(p, targetId); + [[maybe_unused]] auto elaCrossSectionCopy = elaCrossSection; + + cout << "NuclearInteraction: " + << "IntLength: nuclib return (mb): " << productionCrossSection / 1_mbarn + << endl; + weightedProdCrossSection += w[i] * productionCrossSection; + } + cout << "NuclearInteraction: " + << "IntLength: weighted CrossSection (mb): " + << weightedProdCrossSection / 1_mbarn << endl; + + // calculate interaction length in medium + GrammageType const int_length = mediumComposition.GetAverageMassNumber() * + units::constants::u / weightedProdCrossSection; + cout << "NuclearInteraction: " + << "interaction length (g/cm2): " << int_length / (0.001_kg) * 1_cm * 1_cm + << endl; + + return int_length; + } else { + return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); + } + } + + template <> + process::EProcessReturn NuclearInteraction::DoInteraction(Particle& p, Stack& s) { + + // this routine superimposes different nucleon-nucleon interactions + // in a nucleus-nucleus interaction, based the SIBYLL routine SIBNUC + + using namespace units; + using namespace utl; + using namespace units::si; + using namespace geometry; + + const auto ProjId = p.GetPID(); + // TODO: calculate projectile mass in nuclearStackExtension + // const auto ProjMass = p.GetMass(); + cout << "NuclearInteraction: DoInteraction: called with:" << ProjId << endl; + + if (!IsNucleus(ProjId)) { + cout << "WARNING: non nuclear projectile in NUCLIB!" << endl; + // this should not happen + // throw std::runtime_error("Non nuclear projectile in NUCLIB!"); + return process::EProcessReturn::eOk; + } + + // check if target-style nucleus (enum) + if (ProjId != particles::Code::Nucleus) + throw std::runtime_error( + "NuclearInteraction: DoInteraction: Wrong nucleus type. Nuclear projectiles " + "should use NuclearStackExtension!"); + + auto const ProjMass = + p.GetNuclearZ() * particles::Proton::GetMass() + + (p.GetNuclearA() - p.GetNuclearZ()) * particles::Neutron::GetMass(); + cout << "NuclearInteraction: projectile mass: " << ProjMass / 1_GeV << endl; + + fCount++; + + const CoordinateSystem& rootCS = + RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); + + // position and time of interaction, not used in NUCLIB + Point pOrig = p.GetPosition(); + TimeType tOrig = p.GetTime(); + + cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() << endl; + cout << "Interaction: time: " << tOrig << endl; + + // projectile nucleon number + const int kAProj = p.GetNuclearA(); // GetNucleusA(ProjId); + if (kAProj > 56) throw std::runtime_error("Projectile nucleus too large for NUCLIB!"); + + // kinematics + // define projectile nucleus + HEPEnergyType const eProjectileLab = p.GetEnergy(); + auto const pProjectileLab = p.GetMomentum(); + const FourVector PprojLab(eProjectileLab, pProjectileLab); + + cout << "NuclearInteraction: eProj lab: " << eProjectileLab / 1_GeV << endl + << "NuclearInteraction: pProj lab: " << pProjectileLab.GetComponents() / 1_GeV + << endl; + + // define projectile nucleon + HEPEnergyType const eProjectileNucLab = p.GetEnergy() / kAProj; + auto const pProjectileNucLab = p.GetMomentum() / kAProj; + const FourVector PprojNucLab(eProjectileNucLab, pProjectileNucLab); + + cout << "NuclearInteraction: eProjNucleon lab: " << eProjectileNucLab / 1_GeV << endl + << "NuclearInteraction: pProjNucleon lab: " + << pProjectileNucLab.GetComponents() / 1_GeV << endl; + + // define target + // always a nucleon + auto constexpr nucleon_mass = + 0.5 * (particles::Proton::GetMass() + particles::Neutron::GetMass()); + // target is always at rest + const auto eTargetNucLab = 0_GeV + nucleon_mass; + const auto pTargetNucLab = + corsika::stack::MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV); + const FourVector PtargNucLab(eTargetNucLab, pTargetNucLab); + + cout << "NuclearInteraction: etarget lab: " << eTargetNucLab / 1_GeV << endl + << "NuclearInteraction: ptarget lab: " << pTargetNucLab.GetComponents() / 1_GeV + << endl; + + // center-of-mass energy in nucleon-nucleon frame + auto const PtotNN4 = PtargNucLab + PprojNucLab; + HEPEnergyType EcmNN = PtotNN4.GetNorm(); + cout << "NuclearInteraction: nuc-nuc cm energy: " << EcmNN / 1_GeV << endl; + + if (!fHadronicInteraction.ValidCoMEnergy(EcmNN)) { + cout << "NuclearInteraction: nuc-nuc. CoM energy too low for hadronic " + "interaction model!" + << endl; + throw std::runtime_error("NuclearInteraction: DoInteraction: energy too low!"); + } + + // define boost to NUCLEON-NUCLEON frame + COMBoost const boost(PprojNucLab, nucleon_mass); + // boost projecticle + auto const PprojNucCoM = boost.toCoM(PprojNucLab); + + // boost target + auto const PtargNucCoM = boost.toCoM(PtargNucLab); + + cout << "Interaction: ebeam CoM: " << PprojNucCoM.GetTimeLikeComponent() / 1_GeV + << endl + << "Interaction: pbeam CoM: " + << PprojNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; + cout << "Interaction: etarget CoM: " << PtargNucCoM.GetTimeLikeComponent() / 1_GeV + << endl + << "Interaction: ptarget CoM: " + << PtargNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; + + // sample target nucleon number + // + // proton stand-in for nucleon + const auto beamId = particles::Proton::GetCode(); + const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(pOrig); + const auto& mediumComposition = + currentNode->GetModelProperties().GetNuclearComposition(); + cout << "get nucleon-nucleus cross sections for target materials.." << endl; + // get cross sections for target materials + // using nucleon-target-nucleus cross section!!! + /* + Here we read the cross section from the interaction model again, + should be passed from GetInteractionLength if possible + */ + auto const& compVec = mediumComposition.GetComponents(); + vector<si::CrossSectionType> cross_section_of_components(compVec.size()); + + for (size_t i = 0; i < compVec.size(); ++i) { + auto const targetId = compVec[i]; + cout << "target component: " << targetId << endl; + cout << "beam id: " << beamId << endl; + const auto [sigProd, sigEla, nNuc] = + fHadronicInteraction.GetCrossSection(beamId, targetId, EcmNN); + cross_section_of_components[i] = sigProd; + [[maybe_unused]] auto sigElaCopy = sigEla; // ONLY TO AVOID COMPILER WARNINGS + [[maybe_unused]] auto sigNucCopy = nNuc; // ONLY TO AVOID COMPILER WARNINGS + } + + const auto targetCode = + currentNode->GetModelProperties().SampleTarget(cross_section_of_components, fRNG); + cout << "Interaction: target selected: " << targetCode << endl; + /* + FOR NOW: allow nuclei with A<18 or protons only. + when medium composition becomes more complex, approximations will have to be + allowed air in atmosphere also contains some Argon. + */ + int kATarget = -1; + if (IsNucleus(targetCode)) kATarget = GetNucleusA(targetCode); + if (targetCode == particles::Proton::GetCode()) kATarget = 1; + cout << "NuclearInteraction: nuclib target code: " << kATarget << endl; + if (kATarget > 18 || kATarget < 1) + throw std::runtime_error( + "Sibyll target outside range. Only nuclei with A<18 or protons are " + "allowed."); + // end of target sampling + + // superposition + cout << "NuclearInteraction: sampling nuc. multiple interaction structure.. " << endl; + // get nucleon-nucleon cross section + // (needed to determine number of nucleon-nucleon scatterings) + const auto protonId = particles::Proton::GetCode(); + const auto [prodCrossSection, elaCrossSection, dum] = + fHadronicInteraction.GetCrossSection(protonId, protonId, EcmNN); + [[maybe_unused]] auto dumCopy = dum; // ONLY TO AVOID COMPILER WARNING + const double sigProd = prodCrossSection / 1_mbarn; + const double sigEla = elaCrossSection / 1_mbarn; + // sample number of interactions (only input variables, output in common cnucms) + // nuclear multiple scattering according to glauber (r.i.p.) + int_nuc_(kATarget, kAProj, sigProd, sigEla); + + cout << "number of nucleons in target : " << kATarget << endl + << "number of wounded nucleons in target : " << cnucms_.na << endl + << "number of nucleons in projectile : " << kAProj << endl + << "number of wounded nucleons in project. : " << cnucms_.nb << endl + << "number of inel. nuc.-nuc. interactions : " << cnucms_.ni << endl + << "number of elastic nucleons in target : " << cnucms_.nael << endl + << "number of elastic nucleons in project. : " << cnucms_.nbel << endl + << "impact parameter: " << cnucms_.b << endl; + + // calculate fragmentation + cout << "calculating nuclear fragments.." << endl; + // number of interactions + // include elastic + const int nElasticNucleons = cnucms_.nbel; + const int nInelNucleons = cnucms_.nb; + const int nIntProj = nInelNucleons + nElasticNucleons; + const double impactPar = cnucms_.b; // only needed to avoid passing common var. + int nFragments; + // number of fragments is limited to 60 + int AFragments[60]; + // call fragmentation routine + // input: target A, projectile A, number of int. nucleons in projectile, impact + // parameter (fm) output: nFragments, AFragments in addition the momenta ar stored + // in pf in common fragments, neglected + fragm_(kATarget, kAProj, nIntProj, impactPar, nFragments, AFragments); + + // this should not occur but well :) + if (nFragments > 60) + throw std::runtime_error("Number of nuclear fragments in NUCLIB exceeded!"); + + cout << "number of fragments: " << nFragments << endl; + for (int j = 0; j < nFragments; ++j) + cout << "fragment: " << j << " A=" << AFragments[j] + << " px=" << fragments_.ppp[j][0] << " py=" << fragments_.ppp[j][1] + << " pz=" << fragments_.ppp[j][2] << endl; + + cout << "adding nuclear fragments to particle stack.." << endl; + // put nuclear fragments on corsika stack + for (int j = 0; j < nFragments; ++j) { + particles::Code specCode; + const auto nuclA = AFragments[j]; + // get Z from stability line + const auto nuclZ = int(nuclA / 2.15 + 0.7); + + // TODO: do we need to catch single nucleons?? + if (nuclA == 1) + // TODO: sample neutron or proton + specCode = particles::Code::Proton; + else + specCode = particles::Code::Nucleus; + + // TODO: mass of nuclei? + const HEPMassType mass = + particles::Proton::GetMass() * nuclZ + + (nuclA - nuclZ) * particles::Neutron::GetMass(); // this neglects binding energy + + cout << "NuclearInteraction: adding fragment: " << specCode << endl; + cout << "NuclearInteraction: A,Z: " << nuclA << "," << nuclZ << endl; + cout << "NuclearInteraction: mass: " << mass / 1_GeV << endl; + + // CORSIKA 7 way + // spectators inherit momentum from original projectile + const double mass_ratio = mass / ProjMass; + + cout << "NuclearInteraction: mass ratio " << mass_ratio << endl; + + auto const Plab = PprojLab * mass_ratio; + + cout << "NuclearInteraction: fragment momentum: " + << Plab.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; + + if (nuclA == 1) + // add nucleon + p.AddSecondary(tuple<particles::Code, units::si::HEPEnergyType, + stack::MomentumVector, geometry::Point, units::si::TimeType>{ + specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig, + tOrig}); + else + // add nucleus + p.AddSecondary(tuple<particles::Code, units::si::HEPEnergyType, + corsika::stack::MomentumVector, geometry::Point, + units::si::TimeType, unsigned short, unsigned short>{ + specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), pOrig, + tOrig, nuclA, nuclZ}); + } + + // add elastic nucleons to corsika stack + // TODO: the elastic interaction could be external like the inelastic interaction, + // e.g. use existing ElasticModel + cout << "adding elastically scattered nucleons to particle stack.." << endl; + for (int j = 0; j < nElasticNucleons; ++j) { + // TODO: sample proton or neutron + auto const elaNucCode = particles::Code::Proton; + + // CORSIKA 7 way + // elastic nucleons inherit momentum from original projectile + // neglecting momentum transfer in interaction + const double mass_ratio = particles::GetMass(elaNucCode) / ProjMass; + auto const Plab = PprojLab * mass_ratio; + + p.AddSecondary( + tuple<particles::Code, units::si::HEPEnergyType, corsika::stack::MomentumVector, + geometry::Point, units::si::TimeType>{ + elaNucCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), + pOrig, tOrig}); + } + + // add inelastic interactions + cout << "calculate inelastic nucleon-nucleon interactions.." << endl; + for (int j = 0; j < nInelNucleons; ++j) { + // TODO: sample neutron or proton + auto pCode = particles::Proton::GetCode(); + // temporarily add to stack, will be removed after interaction in DoInteraction + cout << "inelastic interaction no. " << j << endl; + auto inelasticNucleon = p.AddSecondary( + tuple<particles::Code, units::si::HEPEnergyType, corsika::stack::MomentumVector, + geometry::Point, units::si::TimeType>{ + pCode, PprojNucLab.GetTimeLikeComponent(), + PprojNucLab.GetSpaceLikeComponents(), pOrig, tOrig}); + // create inelastic interaction + cout << "calling HadronicInteraction..." << endl; + fHadronicInteraction.DoInteraction(inelasticNucleon, s); + } + + // delete parent particle + p.Delete(); + + cout << "NuclearInteraction: DoInteraction: done" << endl; + + return process::EProcessReturn::eOk; + } + +} // namespace corsika::process::sibyll diff --git a/Processes/Sibyll/NuclearInteraction.h b/Processes/Sibyll/NuclearInteraction.h index cd2735029bd739405cce4b7ad52680e0f2016141..cf1f6593330fddc72e867dd7d40387747d6ee9be 100644 --- a/Processes/Sibyll/NuclearInteraction.h +++ b/Processes/Sibyll/NuclearInteraction.h @@ -12,18 +12,23 @@ #ifndef _corsika_process_sibyll_nuclearinteraction_h_ #define _corsika_process_sibyll_nuclearinteraction_h_ -#include <corsika/process/InteractionProcess.h> - -#include <corsika/environment/Environment.h> -#include <corsika/environment/NuclearComposition.h> #include <corsika/particles/ParticleProperties.h> -#include <corsika/process/sibyll/nuclib.h> +#include <corsika/process/InteractionProcess.h> #include <corsika/random/RNGManager.h> -#include <corsika/units/PhysicalUnits.h> -#include <corsika/utl/COMBoost.h> + +namespace corsika::environment { + class Environment; +} namespace corsika::process::sibyll { + class Interaction; // fwd-decl + + /** + * + * + **/ + class NuclearInteraction : public corsika::process::InteractionProcess<NuclearInteraction> { @@ -32,506 +37,19 @@ namespace corsika::process::sibyll { public: NuclearInteraction(corsika::environment::Environment const& env, - corsika::process::sibyll::Interaction& hadint) - : fEnvironment(env) - , fHadronicInteraction(hadint) {} - ~NuclearInteraction() { - std::cout << "Nuclib::NuclearInteraction n=" << fCount << " Nnuc=" << fNucCount - << std::endl; - } - - void Init() { - - using corsika::random::RNGManager; - using std::cout; - using std::endl; - - // initialize hadronic interaction module - // TODO: safe to run multiple initializations? - if (!fHadronicInteraction.WasInitialized()) fHadronicInteraction.Init(); + corsika::process::sibyll::Interaction& hadint); + ~NuclearInteraction(); + void Init(); - // initialize nuclib - // TODO: make sure this does not overlap with sibyll - nuc_nuc_ini_(); - } - - // TODO: remove number of nucleons, avg target mass is available in environment template <typename Particle> std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType> - GetCrossSection(Particle const& p, const corsika::particles::Code TargetId) { - using namespace corsika::units::si; - double sigProd; - auto const pCode = p.GetPID(); - if (pCode != corsika::particles::Code::Nucleus) - throw std::runtime_error( - "NuclearInteraction: GetCrossSection: particle not a nucleus!"); - - auto const iBeam = p.GetNuclearA(); - HEPEnergyType LabEnergyPerNuc = p.GetEnergy() / iBeam; - std::cout << "NuclearInteraction: GetCrossSection: called with: beamNuclA= " - << iBeam << " TargetId= " << TargetId - << " LabEnergyPerNuc= " << LabEnergyPerNuc / 1_GeV << std::endl; - - // use nuclib to calc. nuclear cross sections - // TODO: for now assumes air with hard coded composition - // extend to arbitrary mixtures, requires smarter initialization - // get nuclib projectile code: nucleon number - if (iBeam > 56 || iBeam < 2) { - std::cout << "NuclearInteraction: beam nucleus outside allowed range for NUCLIB!" - << std::endl - << "A=" << iBeam << std::endl; - throw std::runtime_error( - "NuclearInteraction: GetCrossSection: beam nucleus outside allowed range for " - "NUCLIB!"); - } - - const double dElabNuc = LabEnergyPerNuc / 1_GeV; - // TODO: these limitations are still sibyll specific. - // available target nuclei depends on the hadronic interaction model and the - // initialization - if (dElabNuc < 10.) - throw std::runtime_error("NuclearInteraction: GetCrossSection: energy too low!"); - - // TODO: these limitations are still sibyll specific. - // available target nuclei depends on the hadronic interaction model and the - // initialization - if (corsika::particles::IsNucleus(TargetId)) { - const int iTarget = corsika::particles::GetNucleusA(TargetId); - if (iTarget > 18 || iTarget == 0) - throw std::runtime_error( - "Sibyll target outside range. Only nuclei with A<18 are allowed."); - std::cout << "NuclearInteraction: calling signuc.." << std::endl; - std::cout << "WARNING: using hard coded cross section for Nucleus-Air with " - "SIBYLL! (fix me!)" - << std::endl; - // TODO: target id is not used because cross section is still hard coded and fixed - // to air. - signuc_(iBeam, dElabNuc, sigProd); - std::cout << "cross section: " << sigProd << std::endl; - return std::make_tuple(sigProd * 1_mbarn, 0_mbarn); - } - return std::make_tuple(std::numeric_limits<double>::infinity() * 1_mbarn, - std::numeric_limits<double>::infinity() * 1_mbarn); - } + GetCrossSection(Particle& p, const corsika::particles::Code TargetId); template <typename Particle, typename Track> - corsika::units::si::GrammageType GetInteractionLength(Particle const& p, Track&) { - - using namespace corsika::units; - using namespace corsika::units::si; - using namespace corsika::geometry; - using std::cout; - using std::endl; - - // coordinate system, get global frame of reference - CoordinateSystem& rootCS = - RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); - - const particles::Code corsikaBeamId = p.GetPID(); - if (!corsika::particles::IsNucleus(corsikaBeamId)) { - // no nuclear interaction - return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); - } - // check if target-style nucleus (enum) - if (corsikaBeamId != corsika::particles::Code::Nucleus) - throw std::runtime_error( - "NuclearInteraction: GetInteractionLength: Wrong nucleus type. Nuclear " - "projectiles should use NuclearStackExtension!"); - - // read from cross section code table - const HEPMassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() + - corsika::particles::Neutron::GetMass()); - - // FOR NOW: assume target is at rest - MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); - - // total momentum and energy - HEPEnergyType Elab = p.GetEnergy() + nucleon_mass; - int const nuclA = p.GetNuclearA(); - auto const ElabNuc = p.GetEnergy() / nuclA; - - MomentumVector pTotLab(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); - pTotLab += p.GetMomentum(); - pTotLab += pTarget; - auto const pTotLabNorm = pTotLab.norm(); - // calculate cm. energy - const HEPEnergyType ECoM = sqrt( - (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy - auto const ECoMNN = sqrt(2. * ElabNuc * nucleon_mass); - std::cout << "NuclearInteraction: LambdaInt: \n" - << " input energy: " << Elab / 1_GeV << endl - << " input energy CoM: " << ECoM / 1_GeV << endl - << " beam pid:" << corsikaBeamId << endl - << " beam A: " << nuclA << endl - << " input energy per nucleon: " << ElabNuc / 1_GeV << endl - << " input energy CoM per nucleon: " << ECoMNN / 1_GeV << endl; - // throw std::runtime_error("stop here"); - - // energy limits - // TODO: values depend on hadronic interaction model !! this is sibyll specific - if (ElabNuc >= 8.5_GeV && ECoMNN >= 10_GeV) { - - // get target from environment - /* - the target should be defined by the Environment, - ideally as full particle object so that the four momenta - and the boosts can be defined.. - */ - const auto currentNode = - fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); - const auto mediumComposition = - currentNode->GetModelProperties().GetNuclearComposition(); - // determine average interaction length - // weighted sum - int i = -1; - si::CrossSectionType weightedProdCrossSection = 0_mbarn; - // get weights of components from environment/medium - const auto w = mediumComposition.GetFractions(); - // loop over components in medium - for (auto const targetId : mediumComposition.GetComponents()) { - i++; - cout << "NuclearInteraction: get interaction length for target: " << targetId - << endl; - auto const [productionCrossSection, elaCrossSection] = - GetCrossSection(p, targetId); - [[maybe_unused]] auto elaCrossSectionCopy = elaCrossSection; - - std::cout << "NuclearInteraction: " - << "IntLength: nuclib return (mb): " - << productionCrossSection / 1_mbarn << std::endl; - weightedProdCrossSection += w[i] * productionCrossSection; - } - cout << "NuclearInteraction: " - << "IntLength: weighted CrossSection (mb): " - << weightedProdCrossSection / 1_mbarn << endl; - - // calculate interaction length in medium - GrammageType const int_length = mediumComposition.GetAverageMassNumber() * - corsika::units::constants::u / - weightedProdCrossSection; - std::cout << "NuclearInteraction: " - << "interaction length (g/cm2): " - << int_length / (0.001_kg) * 1_cm * 1_cm << std::endl; - - return int_length; - } else { - return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); - } - } + corsika::units::si::GrammageType GetInteractionLength(Particle& p, Track&); template <typename Particle, typename Stack> - corsika::process::EProcessReturn DoInteraction(Particle& p, Stack& s) { - - // this routine superimposes different nucleon-nucleon interactions - // in a nucleus-nucleus interaction, based the SIBYLL routine SIBNUC - - using namespace corsika::units; - using namespace corsika::utl; - using namespace corsika::units::si; - using namespace corsika::geometry; - using std::cout; - using std::endl; - - const auto ProjId = p.GetPID(); - // TODO: calculate projectile mass in nuclearStackExtension - // const auto ProjMass = p.GetMass(); - cout << "NuclearInteraction: DoInteraction: called with:" << ProjId << endl; - - if (!IsNucleus(ProjId)) { - cout << "WARNING: non nuclear projectile in NUCLIB!" << endl; - // this should not happen - // throw std::runtime_error("Non nuclear projectile in NUCLIB!"); - return process::EProcessReturn::eOk; - } - - // check if target-style nucleus (enum) - if (ProjId != corsika::particles::Code::Nucleus) - throw std::runtime_error( - "NuclearInteraction: DoInteraction: Wrong nucleus type. Nuclear projectiles " - "should use NuclearStackExtension!"); - - auto const ProjMass = - p.GetNuclearZ() * corsika::particles::Proton::GetMass() + - (p.GetNuclearA() - p.GetNuclearZ()) * corsika::particles::Neutron::GetMass(); - cout << "NuclearInteraction: projectile mass: " << ProjMass / 1_GeV << endl; - - fCount++; - - const CoordinateSystem& rootCS = - RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); - - // position and time of interaction, not used in NUCLIB - Point pOrig = p.GetPosition(); - TimeType tOrig = p.GetTime(); - - cout << "Interaction: position of interaction: " << pOrig.GetCoordinates() << endl; - cout << "Interaction: time: " << tOrig << endl; - - // projectile nucleon number - const int kAProj = p.GetNuclearA(); // GetNucleusA(ProjId); - if (kAProj > 56) - throw std::runtime_error("Projectile nucleus too large for NUCLIB!"); - - // kinematics - // define projectile nucleus - HEPEnergyType const eProjectileLab = p.GetEnergy(); - auto const pProjectileLab = p.GetMomentum(); - const FourVector PprojLab(eProjectileLab, pProjectileLab); - - cout << "NuclearInteraction: eProj lab: " << eProjectileLab / 1_GeV << endl - << "NuclearInteraction: pProj lab: " << pProjectileLab.GetComponents() / 1_GeV - << endl; - - // define projectile nucleon - HEPEnergyType const eProjectileNucLab = p.GetEnergy() / kAProj; - auto const pProjectileNucLab = p.GetMomentum() / kAProj; - const FourVector PprojNucLab(eProjectileNucLab, pProjectileNucLab); - - cout << "NuclearInteraction: eProjNucleon lab: " << eProjectileNucLab / 1_GeV - << endl - << "NuclearInteraction: pProjNucleon lab: " - << pProjectileNucLab.GetComponents() / 1_GeV << endl; - - // define target - // always a nucleon - auto constexpr nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() + - corsika::particles::Neutron::GetMass()); - // target is always at rest - const auto eTargetNucLab = 0_GeV + nucleon_mass; - const auto pTargetNucLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV); - const FourVector PtargNucLab(eTargetNucLab, pTargetNucLab); - - cout << "NuclearInteraction: etarget lab: " << eTargetNucLab / 1_GeV << endl - << "NuclearInteraction: ptarget lab: " << pTargetNucLab.GetComponents() / 1_GeV - << endl; - - // center-of-mass energy in nucleon-nucleon frame - auto const PtotNN4 = PtargNucLab + PprojNucLab; - HEPEnergyType EcmNN = PtotNN4.GetNorm(); - cout << "NuclearInteraction: nuc-nuc cm energy: " << EcmNN / 1_GeV << endl; - - if (!fHadronicInteraction.ValidCoMEnergy(EcmNN)) { - cout << "NuclearInteraction: nuc-nuc. CoM energy too low for hadronic " - "interaction model!" - << endl; - throw std::runtime_error("NuclearInteraction: DoInteraction: energy too low!"); - } - - // define boost to NUCLEON-NUCLEON frame - COMBoost const boost(PprojNucLab, nucleon_mass); - // boost projecticle - auto const PprojNucCoM = boost.toCoM(PprojNucLab); - - // boost target - auto const PtargNucCoM = boost.toCoM(PtargNucLab); - - cout << "Interaction: ebeam CoM: " << PprojNucCoM.GetTimeLikeComponent() / 1_GeV - << endl - << "Interaction: pbeam CoM: " - << PprojNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; - cout << "Interaction: etarget CoM: " << PtargNucCoM.GetTimeLikeComponent() / 1_GeV - << endl - << "Interaction: ptarget CoM: " - << PtargNucCoM.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; - - // sample target nucleon number - // - // proton stand-in for nucleon - const auto beamId = corsika::particles::Proton::GetCode(); - const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(pOrig); - const auto& mediumComposition = - currentNode->GetModelProperties().GetNuclearComposition(); - cout << "get nucleon-nucleus cross sections for target materials.." << endl; - // get cross sections for target materials - // using nucleon-target-nucleus cross section!!! - /* - Here we read the cross section from the interaction model again, - should be passed from GetInteractionLength if possible - */ - auto const& compVec = mediumComposition.GetComponents(); - std::vector<si::CrossSectionType> cross_section_of_components(compVec.size()); - - for (size_t i = 0; i < compVec.size(); ++i) { - auto const targetId = compVec[i]; - cout << "target component: " << targetId << endl; - cout << "beam id: " << beamId << endl; - const auto [sigProd, sigEla, nNuc] = - fHadronicInteraction.GetCrossSection(beamId, targetId, EcmNN); - cross_section_of_components[i] = sigProd; - [[maybe_unused]] auto sigElaCopy = sigEla; // ONLY TO AVOID COMPILER WARNINGS - [[maybe_unused]] auto sigNucCopy = nNuc; // ONLY TO AVOID COMPILER WARNINGS - } - - const auto targetCode = currentNode->GetModelProperties().SampleTarget( - cross_section_of_components, fRNG); - cout << "Interaction: target selected: " << targetCode << endl; - /* - FOR NOW: allow nuclei with A<18 or protons only. - when medium composition becomes more complex, approximations will have to be - allowed air in atmosphere also contains some Argon. - */ - int kATarget = -1; - if (IsNucleus(targetCode)) kATarget = GetNucleusA(targetCode); - if (targetCode == corsika::particles::Proton::GetCode()) kATarget = 1; - cout << "NuclearInteraction: nuclib target code: " << kATarget << endl; - if (kATarget > 18 || kATarget < 1) - throw std::runtime_error( - "Sibyll target outside range. Only nuclei with A<18 or protons are " - "allowed."); - // end of target sampling - - // superposition - cout << "NuclearInteraction: sampling nuc. multiple interaction structure.. " - << endl; - // get nucleon-nucleon cross section - // (needed to determine number of nucleon-nucleon scatterings) - const auto protonId = corsika::particles::Proton::GetCode(); - const auto [prodCrossSection, elaCrossSection, dum] = - fHadronicInteraction.GetCrossSection(protonId, protonId, EcmNN); - [[maybe_unused]] auto dumCopy = dum; // ONLY TO AVOID COMPILER WARNING - const double sigProd = prodCrossSection / 1_mbarn; - const double sigEla = elaCrossSection / 1_mbarn; - // sample number of interactions (only input variables, output in common cnucms) - // nuclear multiple scattering according to glauber (r.i.p.) - int_nuc_(kATarget, kAProj, sigProd, sigEla); - - cout << "number of nucleons in target : " << kATarget << endl - << "number of wounded nucleons in target : " << cnucms_.na << endl - << "number of nucleons in projectile : " << kAProj << endl - << "number of wounded nucleons in project. : " << cnucms_.nb << endl - << "number of inel. nuc.-nuc. interactions : " << cnucms_.ni << endl - << "number of elastic nucleons in target : " << cnucms_.nael << endl - << "number of elastic nucleons in project. : " << cnucms_.nbel << endl - << "impact parameter: " << cnucms_.b << endl; - - // calculate fragmentation - cout << "calculating nuclear fragments.." << endl; - // number of interactions - // include elastic - const int nElasticNucleons = cnucms_.nbel; - const int nInelNucleons = cnucms_.nb; - const int nIntProj = nInelNucleons + nElasticNucleons; - const double impactPar = cnucms_.b; // only needed to avoid passing common var. - int nFragments; - // number of fragments is limited to 60 - int AFragments[60]; - // call fragmentation routine - // input: target A, projectile A, number of int. nucleons in projectile, impact - // parameter (fm) output: nFragments, AFragments in addition the momenta ar stored - // in pf in common fragments, neglected - fragm_(kATarget, kAProj, nIntProj, impactPar, nFragments, AFragments); - - // this should not occur but well :) - if (nFragments > 60) - throw std::runtime_error("Number of nuclear fragments in NUCLIB exceeded!"); - - cout << "number of fragments: " << nFragments << endl; - for (int j = 0; j < nFragments; ++j) - cout << "fragment: " << j << " A=" << AFragments[j] - << " px=" << fragments_.ppp[j][0] << " py=" << fragments_.ppp[j][1] - << " pz=" << fragments_.ppp[j][2] << endl; - - cout << "adding nuclear fragments to particle stack.." << endl; - // put nuclear fragments on corsika stack - for (int j = 0; j < nFragments; ++j) { - corsika::particles::Code specCode; - const auto nuclA = AFragments[j]; - // get Z from stability line - const auto nuclZ = int(nuclA / 2.15 + 0.7); - - // TODO: do we need to catch single nucleons?? - if (nuclA == 1) - // TODO: sample neutron or proton - specCode = corsika::particles::Code::Proton; - else - specCode = corsika::particles::Code::Nucleus; - - // TODO: mass of nuclei? - const HEPMassType mass = - corsika::particles::Proton::GetMass() * nuclZ + - (nuclA - nuclZ) * - corsika::particles::Neutron::GetMass(); // this neglects binding energy - - cout << "NuclearInteraction: adding fragment: " << specCode << endl; - cout << "NuclearInteraction: A,Z: " << nuclA << "," << nuclZ << endl; - cout << "NuclearInteraction: mass: " << mass / 1_GeV << endl; - - // CORSIKA 7 way - // spectators inherit momentum from original projectile - const double mass_ratio = mass / ProjMass; - - cout << "NuclearInteraction: mass ratio " << mass_ratio << endl; - - auto const Plab = PprojLab * mass_ratio; - - cout << "NuclearInteraction: fragment momentum: " - << Plab.GetSpaceLikeComponents().GetComponents() / 1_GeV << endl; - - if (nuclA == 1) - // add nucleon - p.AddSecondary( - std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - corsika::stack::MomentumVector, corsika::geometry::Point, - corsika::units::si::TimeType>{ - specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), - pOrig, tOrig}); - else - // add nucleus - p.AddSecondary( - std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - corsika::stack::MomentumVector, corsika::geometry::Point, - corsika::units::si::TimeType, unsigned short, unsigned short>{ - specCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), - pOrig, tOrig, nuclA, nuclZ}); - } - - // add elastic nucleons to corsika stack - // TODO: the elastic interaction could be external like the inelastic interaction, - // e.g. use existing ElasticModel - cout << "adding elastically scattered nucleons to particle stack.." << endl; - for (int j = 0; j < nElasticNucleons; ++j) { - // TODO: sample proton or neutron - auto const elaNucCode = corsika::particles::Code::Proton; - - // CORSIKA 7 way - // elastic nucleons inherit momentum from original projectile - // neglecting momentum transfer in interaction - const double mass_ratio = corsika::particles::GetMass(elaNucCode) / ProjMass; - auto const Plab = PprojLab * mass_ratio; - - p.AddSecondary( - std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - corsika::stack::MomentumVector, corsika::geometry::Point, - corsika::units::si::TimeType>{ - elaNucCode, Plab.GetTimeLikeComponent(), Plab.GetSpaceLikeComponents(), - pOrig, tOrig}); - } - - // add inelastic interactions - cout << "calculate inelastic nucleon-nucleon interactions.." << endl; - for (int j = 0; j < nInelNucleons; ++j) { - // TODO: sample neutron or proton - auto pCode = corsika::particles::Proton::GetCode(); - // temporarily add to stack, will be removed after interaction in DoInteraction - cout << "inelastic interaction no. " << j << endl; - auto inelasticNucleon = p.AddSecondary( - std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType, - corsika::stack::MomentumVector, corsika::geometry::Point, - corsika::units::si::TimeType>{ - pCode, PprojNucLab.GetTimeLikeComponent(), - PprojNucLab.GetSpaceLikeComponents(), pOrig, tOrig}); - // create inelastic interaction - cout << "calling HadronicInteraction..." << endl; - fHadronicInteraction.DoInteraction(inelasticNucleon, s); - } - - // delete parent particle - p.Delete(); - - cout << "NuclearInteraction: DoInteraction: done" << endl; - - return process::EProcessReturn::eOk; - } + corsika::process::EProcessReturn DoInteraction(Particle& p, Stack& s); private: corsika::environment::Environment const& fEnvironment; diff --git a/Processes/TrackingLine/TrackingLine.cc b/Processes/TrackingLine/TrackingLine.cc index 4af036ccd7d48f84da06c731937b2275c25f6ef7..9021bf2796ce50768ca8f7c9c13a7d971f193c9c 100644 --- a/Processes/TrackingLine/TrackingLine.cc +++ b/Processes/TrackingLine/TrackingLine.cc @@ -1,3 +1,14 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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/process/tracking_line/TrackingLine.h> #include <corsika/environment/Environment.h> @@ -126,8 +137,6 @@ namespace corsika::process::tracking_line { #include <corsika/setup/SetupStack.h> #include <corsika/setup/SetupTrajectory.h> using namespace corsika::setup; -using Particle = Stack::ParticleType; -// using Track = Trajectory; template class corsika::process::tracking_line::TrackingLine<setup::Stack, setup::Trajectory>; diff --git a/Processes/TrackingLine/TrackingLine.h b/Processes/TrackingLine/TrackingLine.h index b5e715cd21dba7814ca4143e3e59b6f199d03d04..cfc3568079bf7ad6433f2f28aee416230d9d5866 100644 --- a/Processes/TrackingLine/TrackingLine.h +++ b/Processes/TrackingLine/TrackingLine.h @@ -31,7 +31,7 @@ namespace corsika::process { template <typename Stack, typename Trajectory> class TrackingLine { // - using Particle = typename Stack::ParticleType; + using Particle = typename Stack::StackIterator; corsika::environment::Environment const& fEnvironment; diff --git a/Processes/TrackingLine/testTrackingLineStack.cc b/Processes/TrackingLine/testTrackingLineStack.cc index 0a718634a7f15cb9ca5a53c6675ecda9fb94c4e3..4c21923884ff69a76ec9acdc7428a313b1559734 100644 --- a/Processes/TrackingLine/testTrackingLineStack.cc +++ b/Processes/TrackingLine/testTrackingLineStack.cc @@ -1,3 +1,14 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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. + */ + #ifndef _include_process_trackinling_teststack_h_ #define _include_process_trackinling_teststack_h_ diff --git a/Processes/TrackingLine/testTrackingLineStack.h b/Processes/TrackingLine/testTrackingLineStack.h index 6d8a46c1a4ca6ac5bcec0bca04a5a767b7f7fbc5..b825bc2f17b684e5fd753557296015d748181e57 100644 --- a/Processes/TrackingLine/testTrackingLineStack.h +++ b/Processes/TrackingLine/testTrackingLineStack.h @@ -1,3 +1,14 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * 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. + */ + #ifndef _include_process_trackinling_teststack_h_ #define _include_process_trackinling_teststack_h_ @@ -28,6 +39,7 @@ struct DummyParticle { struct DummyStack { using ParticleType = DummyParticle; + using StackIterator = DummyParticle; }; #endif