diff --git a/corsika/detail/framework/core/Cascade.inl b/corsika/detail/framework/core/Cascade.inl index f11427148c96e927176168f6d9d8c1ee3dc9fc15..82b6887a3edcf18ff4f2044adc0c1d33efb9f9fe 100644 --- a/corsika/detail/framework/core/Cascade.inl +++ b/corsika/detail/framework/core/Cascade.inl @@ -211,7 +211,7 @@ namespace corsika { } particle.setTime(particle.getTime() + step.getDuration()); particle.setPosition(step.getPosition(1)); - particle.setMomentum(step.getDirection(1) * particle.getMomentum().getNorm()); + particle.setDirection(step.getDirection(1)); if (isContinuous) { return; // there is nothing further, step is finished diff --git a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl index c840de798880c3c94a939aff13ffc7b02a32f28a..066997364c8d7843cdf912e893294b3eada2a825 100644 --- a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl +++ b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl @@ -163,8 +163,7 @@ namespace corsika { auto Enew = E + dE; CORSIKA_LOG_TRACE("EnergyLoss dE={} MeV, E={} GeV, Ekin={} GeV, Enew={} GeV", dE / 1_MeV, E / 1_GeV, Ekin / 1_GeV, Enew / 1_GeV); - p.setEnergy(Enew); - updateMomentum(p, Enew); + p.setEnergy(Enew); // kinetic energy on stack fillProfile(t, dE); return ProcessReturn::Ok; } @@ -194,13 +193,6 @@ namespace corsika { vTrack, maxGrammage); } - template <typename TParticle> - inline void BetheBlochPDG::updateMomentum(TParticle& vP, HEPEnergyType Enew) { - HEPMomentumType Pnew = elab2plab(Enew, vP.getMass()); - auto pnew = vP.getMomentum(); - vP.setMomentum(pnew * Pnew / pnew.getNorm()); - } - template <typename TTrajectory> inline void BetheBlochPDG::fillProfile(TTrajectory const& vTrack, const HEPEnergyType dE) { diff --git a/corsika/detail/modules/proposal/ContinuousProcess.inl b/corsika/detail/modules/proposal/ContinuousProcess.inl index 818398ef889402c84f1b065686a0c2bea07870e4..89f571b69d620a3e893e6b14ebe6b48913f02bd5 100644 --- a/corsika/detail/modules/proposal/ContinuousProcess.inl +++ b/corsika/detail/modules/proposal/ContinuousProcess.inl @@ -81,18 +81,15 @@ namespace corsika::proposal { // update particle direction after continuous loss caused by multiple // scattering - auto particle_momentum = vP.getMomentum().getNorm(); - auto vec = QuantityVector(final_direction.GetX() * particle_momentum, - final_direction.GetY() * particle_momentum, - final_direction.GetZ() * particle_momentum); - vP.setMomentum(MomentumVector(vP_dir.getCoordinateSystem(), vec)); + vP.setDirection( + {vP_dir.getCoordinateSystem(), + {final_direction.GetX(), final_direction.GetY(), final_direction.GetZ()}}); } template <typename TParticle, typename TTrajectory> inline ProcessReturn ContinuousProcess::doContinuous(TParticle& vP, TTrajectory const& vT, bool const) { - if (!canInteract(vP.getPID())) return ProcessReturn::Ok; if (vT.getLength() == 0_m) return ProcessReturn::Ok; @@ -110,10 +107,7 @@ namespace corsika::proposal { // if the particle has a charge take multiple scattering into account if (vP.getChargeNumber() != 0) scatter(vP, dE, dX); - vP.setEnergy(final_energy); - auto new_momentum = - sqrt(vP.getEnergy() * vP.getEnergy() - vP.getMass() * vP.getMass()); - vP.setMomentum(vP.getMomentum() * new_momentum / vP.getMomentum().getNorm()); + vP.setEnergy(final_energy); // on the stack, this is just kinetic energy, E-m return ProcessReturn::Ok; } @@ -123,8 +117,8 @@ namespace corsika::proposal { auto const code = vP.getPID(); if (!canInteract(code)) return meter * std::numeric_limits<double>::infinity(); - // Limit the step size of a conitnuous loss. The maximal continuous loss seems to be a - // hyper parameter which must be adjusted. + // Limit the step size of a conitnuous loss. The maximal continuous loss seems to be + // a hyper parameter which must be adjusted. // auto const energy = vP.getEnergy(); auto const energy_lim = diff --git a/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl b/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl index 675636a173490fa57c064ea3c7d893c2d4207f42..a39e8f59cf911755d7a9ed1bf64c2018061f872e 100644 --- a/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl +++ b/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl @@ -100,9 +100,7 @@ namespace corsika { CORSIKA_LOG_DEBUG("gyroradius {}, Steplimit: {}", gyroradius, steplimit); // calculate first halve step for "steplimit" - auto const initialMomentum = particle.getMomentum(); - auto const absMomentum = initialMomentum.getNorm(); - DirectionVector const direction = initialVelocity.normalized(); + DirectionVector const initialDirection = particle.getDirection(); // avoid any intersections within first halve steplength // aim for intersection in second halve step @@ -112,26 +110,28 @@ namespace corsika { CORSIKA_LOG_DEBUG("first halve step length {}, steplimit={}, initialTrackLength={}", firstHalveSteplength, steplimit, initialTrackLength); // perform the first halve-step - Point const position_mid = initialPosition + direction * firstHalveSteplength; + Point const position_mid = + initialPosition + initialDirection * firstHalveSteplength; auto const k = charge / (constants::c * convert_HEP_to_SI<MassType::dimension_type>( particle.getMomentum().getNorm())); DirectionVector const new_direction = - direction + direction.cross(magneticfield) * firstHalveSteplength * 2 * k; + initialDirection + + initialDirection.cross(magneticfield) * firstHalveSteplength * 2 * k; auto const new_direction_norm = new_direction.getNorm(); // by design this is >1 CORSIKA_LOG_DEBUG( "position_mid={}, new_direction={}, (new_direction_norm)={}, deflection={}", position_mid.getCoordinates(), new_direction.getComponents(), new_direction_norm, - acos(std::min(1.0, direction.dot(new_direction) / new_direction_norm)) * 180 / - M_PI); + acos(std::min(1.0, initialDirection.dot(new_direction) / new_direction_norm)) * + 180 / M_PI); // check, where the second halve-step direction has geometric intersections particle.setPosition(position_mid); - particle.setMomentum(new_direction * absMomentum); + particle.setDirection(new_direction); auto const [finalTrack, finalTrackNextVolume] = tracking_line::Tracking::getTrack(particle); - particle.setPosition(initialPosition); // this is not nice... - particle.setMomentum(initialMomentum); // this is not nice... + particle.setPosition(initialPosition); // this is not nice... + particle.setDirection(initialDirection); // this is not nice... LengthType const finalTrackLength = finalTrack.getLength(1); LengthType const secondLeapFrogLength = firstHalveSteplength * new_direction_norm; diff --git a/corsika/detail/stack/NuclearStackExtension.inl b/corsika/detail/stack/NuclearStackExtension.inl deleted file mode 100644 index cdd377d12ca9452e601847f9ad151e43c05fb4ad..0000000000000000000000000000000000000000 --- a/corsika/detail/stack/NuclearStackExtension.inl +++ /dev/null @@ -1,384 +0,0 @@ -/* - * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu - * - * This software is distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3). See file LICENSE for a full version of - * the license. - */ - -#pragma once - -#include <corsika/framework/core/ParticleProperties.hpp> -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/stack/Stack.hpp> -#include <corsika/framework/geometry/Point.hpp> -#include <corsika/framework/geometry/Vector.hpp> -#include <corsika/stack/VectorStack.hpp> - -#include <algorithm> -#include <tuple> -#include <vector> - -namespace corsika::nuclear_stack { - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(typename super_type::particle_data_type const& v) { - - if (std::get<0>(v) == Code::Nucleus) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - super_type::setParticleData(v); - setNucleusRef(-1); // this is not a nucleus - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(nuclear_particle_data_type const& v) { - unsigned short const A = std::get<5>(v); - unsigned short const Z = std::get<6>(v); - Code const PID = std::get<0>(v); - if (PID != Code::Nucleus || A == 0 || Z == 0) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - setNucleusRef( - super_type::getStackData().getNucleusNextRef()); // store this nucleus data ref - setNuclearA(A); - setNuclearZ(Z); - super_type::setParticleData(typename super_type::particle_data_type{ - PID, std::get<1>(v), std::get<2>(v), std::get<3>(v), std::get<4>(v)}); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(super_type& p, typename super_type::particle_data_type const& v) { - if (std::get<0>(v) == Code::Nucleus) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - super_type::setParticleData(p, v); - setNucleusRef(-1); // this is not a nucleus - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(super_type& p, nuclear_particle_data_type const& v) { - - unsigned short const A = std::get<5>(v); - unsigned short const Z = std::get<6>(v); - - if (std::get<0>(v) != Code::Nucleus || A == 0 || Z == 0) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - setNucleusRef( - super_type::getStackData().getNucleusNextRef()); // store this nucleus data ref - setNuclearA(A); - setNuclearZ(Z); - super_type::setParticleData(p, typename super_type::particle_data_type{ - std::get<0>(v), std::get<1>(v), std::get<2>(v), - std::get<3>(v), std::get<4>(v)}); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(typename super_type::particle_data_momentum_type const& v) { - - if (std::get<0>(v) == Code::Nucleus) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - super_type::setParticleData(v); - setNucleusRef(-1); // this is not a nucleus - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(nuclear_particle_data_momentum_type const& v) { - unsigned short const A = std::get<4>(v); - unsigned short const Z = std::get<5>(v); - Code const PID = std::get<0>(v); - if (PID != Code::Nucleus || A == 0 || Z == 0) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - setNucleusRef( - super_type::getStackData().getNucleusNextRef()); // store this nucleus data ref - setNuclearA(A); - setNuclearZ(Z); - HEPMassType m = 0_GeV; - if (PID == Code::Nucleus) { - m = get_nucleus_mass(get_nucleus_code(A, Z)); - } else { - m = get_mass(PID); - } - MomentumVector const& p = std::get<1>(v); - auto const P2 = p.getSquaredNorm(); - HEPEnergyType Ekin = sqrt(P2 + square(m)) - m; - super_type::setParticleData(typename super_type::particle_data_type{ - PID, Ekin, p / sqrt(P2), std::get<2>(v), std::get<3>(v)}); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(super_type& p, - typename super_type::particle_data_momentum_type const& v) { - if (std::get<0>(v) == Code::Nucleus) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - super_type::setParticleData(p, v); - setNucleusRef(-1); // this is not a nucleus - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>:: - setParticleData(super_type& parent, nuclear_particle_data_momentum_type const& v) { - - unsigned short const A = std::get<4>(v); - unsigned short const Z = std::get<5>(v); - Code const PID = std::get<0>(v); - if (PID != Code::Nucleus || A == 0 || Z == 0) { - std::ostringstream err; - err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; - throw std::runtime_error(err.str()); - } - - setNucleusRef( - super_type::getStackData().getNucleusNextRef()); // store this nucleus data ref - setNuclearA(A); - setNuclearZ(Z); - HEPMassType m = 0_GeV; - if (PID == Code::Nucleus) { - m = get_nucleus_mass(get_nucleus_code(A, Z)); - } else { - m = get_mass(PID); - } - MomentumVector const& p = std::get<1>(v); - auto const P2 = p.getSquaredNorm(); - HEPEnergyType Ekin = sqrt(P2 + square(m)) - m; - super_type::setParticleData( - parent, typename super_type::particle_data_type{PID, Ekin, p / sqrt(P2), - std::get<2>(v), std::get<3>(v)}); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline std::string NuclearParticleInterface<InnerParticleInterface, - StackIteratorInterface>::asString() const { - return fmt::format( - "{}, nuc({})", super_type::asString(), - (isNucleus() ? fmt::format("A={}, Z={}", getNuclearA(), getNuclearZ()) : "n/a")); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline PDGCode NuclearParticleInterface<InnerParticleInterface, - StackIteratorInterface>::getPDG() const { - return (isNucleus() ? PDGCode(1000000000 + getNuclearZ() * 10000 + getNuclearA() * 10) - : super_type::getPDG()); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void - NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>::setMomentum( - MomentumVector const& v) { - HEPMomentumType const P = v.getNorm(); - if (P == 0_eV) { - super_type::getStackData().setKineticEnergy(super_type::getIndex(), 0_eV); - super_type::getStackData().setDirection( - super_type::getIndex(), DirectionVector(v.getCoordinateSystem(), {0, 0, 0})); - } else { - super_type::getStackData().setKineticEnergy( - super_type::getIndex(), - sqrt(square(this->getMass()) + square(P)) - this->getMass()); - super_type::getStackData().setDirection(super_type::getIndex(), v / P); - } - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline MomentumVector NuclearParticleInterface< - InnerParticleInterface, StackIteratorInterface>::getMomentum() const { - auto const P = sqrt(square(this->getKineticEnergy() + this->getMass()) - - square(this->getMass())); - return super_type::getStackData().getDirection(super_type::getIndex()) * P; - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline VelocityVector NuclearParticleInterface< - InnerParticleInterface, StackIteratorInterface>::getVelocity() const { - return this->getMomentum() / this->getEnergy() * constants::c; - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline HEPMassType NuclearParticleInterface<InnerParticleInterface, - StackIteratorInterface>::getMass() const { - if (super_type::getPID() == Code::Nucleus) - return get_nucleus_mass(get_nucleus_code(getNuclearA(), getNuclearZ())); - return super_type::getMass(); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline ElectricChargeType NuclearParticleInterface< - InnerParticleInterface, StackIteratorInterface>::getCharge() const { - if (super_type::getPID() == Code::Nucleus) return getNuclearZ() * constants::e; - return super_type::getCharge(); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline HEPEnergyType NuclearParticleInterface< - InnerParticleInterface, StackIteratorInterface>::getEnergy() const { - return this->getKineticEnergy() + this->getMass(); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline void - NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>::setEnergy( - HEPEnergyType const& e) { - super_type::getStackData().setKineticEnergy(super_type::getIndex(), - e - this->getMass()); - } - - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - inline int16_t NuclearParticleInterface< - InnerParticleInterface, StackIteratorInterface>::getChargeNumber() const { - if (super_type::getPID() == Code::Nucleus) return getNuclearZ(); - return super_type::getChargeNumber(); - } - - template <typename InnerStackImpl> - inline int NuclearStackExtensionImpl<InnerStackImpl>::getNucleusNextRef() { - nuclearA_.push_back(0); - nuclearZ_.push_back(0); - return nuclearA_.size() - 1; - } - - template <typename InnerStackImpl> - inline int NuclearStackExtensionImpl<InnerStackImpl>::getNucleusRef( - const unsigned int i) const { - if (nucleusRef_[i] >= 0) return nucleusRef_[i]; - std::ostringstream err; - err << "NuclearStackExtension: no nucleus at ref=" << i; - throw std::runtime_error(err.str()); - } - - template <typename InnerStackImpl> - inline void NuclearStackExtensionImpl<InnerStackImpl>::copy(const unsigned int i1, - const unsigned int i2) { - // index range check - if (i1 >= getSize() || i2 >= getSize()) { - std::ostringstream err; - err << "NuclearStackExtension: trying to access data beyond size of stack!"; - throw std::runtime_error(err.str()); - } - // copy internal particle data p[i2] = p[i1] - super_type::copy(i1, i2); - // check if any of p[i1] or p[i2] was a Code::Nucleus - const int ref1 = nucleusRef_[i1]; - const int ref2 = nucleusRef_[i2]; - if (ref2 < 0) { - if (ref1 >= 0) { - // i1 is nucleus, i2 is not - nucleusRef_[i2] = getNucleusNextRef(); - nuclearA_[nucleusRef_[i2]] = nuclearA_[ref1]; - nuclearZ_[nucleusRef_[i2]] = nuclearZ_[ref1]; - } else { - // neither i1 nor i2 are nuclei - } - } else { - if (ref1 >= 0) { - // both are nuclei, i2 is overwritten with nucleus i1 - // fNucleusRef stays the same, but A and Z data is overwritten - nuclearA_[ref2] = nuclearA_[ref1]; - nuclearZ_[ref2] = nuclearZ_[ref1]; - } else { - // i2 is overwritten with non-nucleus i1 - nucleusRef_[i2] = -1; // flag as non-nucleus - nuclearA_.erase(nuclearA_.cbegin() + ref2); // remove data for i2 - nuclearZ_.erase(nuclearZ_.cbegin() + ref2); // remove data for i2 - const int n = nucleusRef_.size(); // update fNucleusRef: indices above ref2 - // must be decremented by 1 - for (int i = 0; i < n; ++i) { - if (nucleusRef_[i] > ref2) { nucleusRef_[i] -= 1; } - } - } - } - } - - template <typename InnerStackImpl> - inline void NuclearStackExtensionImpl<InnerStackImpl>::clear() { - super_type::clear(); - nucleusRef_.clear(); - nuclearA_.clear(); - nuclearZ_.clear(); - } - - template <typename InnerStackImpl> - inline void NuclearStackExtensionImpl<InnerStackImpl>::swap(const unsigned int i1, - const unsigned int i2) { - // index range check - if (i1 >= getSize() || i2 >= getSize()) { - std::ostringstream err; - err << "NuclearStackExtension: trying to access data beyond size of stack!"; - throw std::runtime_error(err.str()); - } - // swap original particle data - super_type::swap(i1, i2); - // swap corresponding nuclear reference data - std::swap(nucleusRef_[i2], nucleusRef_[i1]); - } - - template <typename InnerStackImpl> - inline void NuclearStackExtensionImpl<InnerStackImpl>::incrementSize() { - super_type::incrementSize(); - nucleusRef_.push_back(-1); - } - - template <typename InnerStackImpl> - inline void NuclearStackExtensionImpl<InnerStackImpl>::decrementSize() { - super_type::decrementSize(); - if (nucleusRef_.size() > 0) { - const int ref = nucleusRef_.back(); - nucleusRef_.pop_back(); - if (ref >= 0) { - nuclearA_.erase(nuclearA_.begin() + ref); - nuclearZ_.erase(nuclearZ_.begin() + ref); - const int n = nucleusRef_.size(); - for (int i = 0; i < n; ++i) { - if (nucleusRef_[i] >= ref) { nucleusRef_[i] -= 1; } - } - } - } - } - -} // namespace corsika::nuclear_stack diff --git a/corsika/stack/DummyStack.hpp b/corsika/stack/DummyStack.hpp index bcba30f1d55d2ca5197ca804d22ff672096c9d16..a37fe53d7f5161ee9ad289fa8c6a1f1733121b1a 100644 --- a/corsika/stack/DummyStack.hpp +++ b/corsika/stack/DummyStack.hpp @@ -10,6 +10,7 @@ #include <corsika/framework/core/ParticleProperties.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> +#include <corsika/framework/geometry/PhysicalGeometry.hpp> #include <corsika/framework/stack/Stack.hpp> #include <string> @@ -22,8 +23,8 @@ namespace corsika::dummy_stack { */ /** - however, conceptually we need to provide fake data. A stack without data does not - work... + * However, conceptually we need to provide fake data. A stack without data does not + * work... */ struct NoData { /* nothing */ @@ -40,6 +41,14 @@ namespace corsika::dummy_stack { void setParticleData(super_type& /*parent*/, const std::tuple<NoData>& /*v*/) {} std::string asString() const { return "dummy-data"; } + + // unfortunately we need those dummy getter + // for some more complex tests with "history" + HEPEnergyType getEnergy() const { return 0_GeV; } + MomentumVector getMomentum() const { + return MomentumVector(get_root_CoordinateSystem(), {0_GeV, 0_GeV, 0_GeV}); + } + Code getPID() const { return Code::Unknown; } }; /** @@ -67,7 +76,7 @@ namespace corsika::dummy_stack { int getCapacity() const { return entries_; } /** - * Function to copy particle at location i2 in stack to i1 + * Function to copy particle at location i2 in stack to i1. */ void copy(const int /*i1*/, const int /*i2*/) {} diff --git a/corsika/stack/NuclearStackExtension.hpp b/corsika/stack/NuclearStackExtension.hpp deleted file mode 100644 index 03870ccf5de4b0225be86add758eaec8ef0c8a15..0000000000000000000000000000000000000000 --- a/corsika/stack/NuclearStackExtension.hpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu - * - * This software is distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3). See file LICENSE for a full version of - * the license. - */ - -#pragma once - -#include <corsika/framework/core/ParticleProperties.hpp> -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/stack/Stack.hpp> -#include <corsika/framework/geometry/Point.hpp> -#include <corsika/framework/geometry/Vector.hpp> -#include <corsika/framework/geometry/PhysicalGeometry.hpp> -#include <corsika/stack/VectorStack.hpp> - -#include <algorithm> -#include <tuple> -#include <vector> - -namespace corsika::nuclear_stack { - - /** - * - * Define ParticleInterface for NuclearStackExtension Stack derived from - * ParticleInterface of Inner stack class - * - * Add A and Z data to existing stack (currently VectorStack) of particle - * properties. This is done via inheritance, not via CombinedStack since the nuclear - * data is stored ONLY when needed (for nuclei) and not for all particles. Thus, this is - * a new, derived Stack object. - * - * Only for Code::Nucleus particles A and Z are stored, not for all - * normal elementary particles. - * - * Thus in your code, make sure to always check <code> - * particle.getPID()==Code::Nucleus </code> before attempting to - * read any nuclear information. - */ - template <template <typename> class InnerParticleInterface, - typename StackIteratorInterface> - struct NuclearParticleInterface - : public InnerParticleInterface<StackIteratorInterface> { - - typedef InnerParticleInterface<StackIteratorInterface> super_type; - - public: - typedef std::tuple<Code, HEPEnergyType, DirectionVector, Point, TimeType, - unsigned short, unsigned short> - nuclear_particle_data_type; - - typedef std::tuple<Code, MomentumVector, Point, TimeType, unsigned short, - unsigned short> - nuclear_particle_data_momentum_type; - - /** - * - * @param v which is a tuple containing: PID, kinetic Energy, DirectionVector, - * Position, Time - */ - void setParticleData(typename super_type::particle_data_type const& v); - - /** - * - * @param v which is a tuple containing: PID, kinetic Energy, DirectionVector, - * Position, Time, A, Z - */ - void setParticleData(nuclear_particle_data_type const& v); - - /** - * - * @param p the parent particle - * @param v which is a tuple containing: PID, Momentum Vector, Position, - * Time - */ - void setParticleData(super_type& p, typename super_type::particle_data_type const& v); - - /** - * - * @param p the parent particle - * @param v which is a tuple containing: PID, Momentum Vector, Position, - * Time, A, Z - */ - void setParticleData(super_type& p, nuclear_particle_data_type const& v); - - /** - * - * @param v which is a tuple containing: PID, Total Energy, MomentumVector, Position, - * Time - */ - void setParticleData(typename super_type::particle_data_momentum_type const& v); - - /** - * - * @param v which is a tuple containing: PID, Total Energy, MomentumVector, Position, - * Time, A, Z - */ - void setParticleData(nuclear_particle_data_momentum_type const& v); - - /** - * - * @param p parent particle - * @param v which is a tuple containing: PID, Total Energy, MomentumVector, Position, - * Time - */ - void setParticleData(super_type& p, - typename super_type::particle_data_momentum_type const& v); - - /** - * - * @param p parent particle - * @param v which is a tuple containing: PID, Total Energy, MomentumVector, Position, - * Time, A, Z - */ - void setParticleData(super_type& p, nuclear_particle_data_momentum_type const& v); - - std::string asString() const; - - /** - * @name individual setters - * @{ - */ - void setNuclearA(const unsigned short vA) { - super_type::getStackData().setNuclearA(super_type::getIndex(), vA); - } - void setNuclearZ(const unsigned short vZ) { - super_type::getStackData().setNuclearZ(super_type::getIndex(), vZ); - } - /// @} - - /** - * @name individual getters - * @{ - */ - int getNuclearA() const { - return super_type::getStackData().getNuclearA(super_type::getIndex()); - } - int getNuclearZ() const { - return super_type::getStackData().getNuclearZ(super_type::getIndex()); - } - /// @} - - /** - * Overwrite normal getPDG function with nuclear version - */ - PDGCode getPDG() const; - - /** - * Overwrite normal setMomentum function with nuclear version - */ - void setMomentum(MomentumVector const& v); - - /** - * Overwrite normal getMomentum function with nuclear version - */ - MomentumVector getMomentum() const; - - /** - * Overwrite normal getEnergy function with nuclear version - */ - void setEnergy(HEPEnergyType const& e); - - /** - * Overwrite normal getVelocity function with nuclear version - */ - VelocityVector getVelocity() const; - - /** - * Overwrite normal getMass function with nuclear version - */ - HEPMassType getMass() const; - - /** - * Overwrite normal getParticleCharge function with nuclear version - */ - ElectricChargeType getCharge() const; - - /** - * Overwrite normal getEnergy function with nuclear version - */ - HEPEnergyType getEnergy() const; - - /** - * Overwirte normal getChargeNumber function with nuclear version - **/ - int16_t getChargeNumber() const; - - int getNucleusRef() const { - return super_type::getStackData().getNucleusRef(super_type::getIndex()); - } // LCOV_EXCL_LINE - - protected: - void setNucleusRef(const int vR) { - super_type::getStackData().setNucleusRef(super_type::getIndex(), vR); - } - - bool isNucleus() const { - return super_type::getStackData().isNucleus(super_type::getIndex()); - } - }; - - /** - * @class NuclearStackExtension - * - * Memory implementation of adding nuclear inforamtion to the - * existing particle stack defined in class InnerStackImpl. - * - * Inside the NuclearStackExtension class there is a dedicated - * fNucleusRef index, where fNucleusRef[i] is referring to the - * correct A and Z for a specific particle index i. fNucleusRef[i] - * == -1 means that this is not a nucleus, and a subsequent call to - * getNucleusA would produce an exception. - */ - template <typename InnerStackImpl> - class NuclearStackExtensionImpl : public InnerStackImpl { - - typedef InnerStackImpl super_type; - - public: - typedef std::vector<int> nucleus_ref_type; - typedef std::vector<unsigned short> nuclear_a_type; - typedef std::vector<unsigned short> nuclear_z_type; - - NuclearStackExtensionImpl() = default; - - NuclearStackExtensionImpl(NuclearStackExtensionImpl<InnerStackImpl> const&) = default; - - NuclearStackExtensionImpl(NuclearStackExtensionImpl<InnerStackImpl>&&) = default; - - NuclearStackExtensionImpl<InnerStackImpl>& operator=( - NuclearStackExtensionImpl<InnerStackImpl> const&) = default; - - NuclearStackExtensionImpl<InnerStackImpl>& operator=( - NuclearStackExtensionImpl<InnerStackImpl>&&) = default; - - void init() { super_type::init(); } - - void dump() { super_type::dump(); } - - void clear(); - - unsigned int getSize() const { return nucleusRef_.size(); } - - unsigned int getCapacity() const { return nucleusRef_.capacity(); } - - void setNuclearA(const unsigned int i, const unsigned short vA) { - nuclearA_[getNucleusRef(i)] = vA; - } - - void setNuclearZ(const unsigned int i, const unsigned short vZ) { - nuclearZ_[getNucleusRef(i)] = vZ; - } - - void setNucleusRef(const unsigned int i, const int v) { nucleusRef_[i] = v; } - - int getNuclearA(const unsigned int i) const { return nuclearA_[getNucleusRef(i)]; } - - int getNuclearZ(const unsigned int i) const { return nuclearZ_[getNucleusRef(i)]; } - - // this function will create new storage for Nuclear Properties, and return the - // reference to it - int getNucleusNextRef(); - - int getNucleusRef(const unsigned int i) const; - - bool isNucleus(const unsigned int i) const { return nucleusRef_[i] >= 0; } - - /** - * Function to copy particle at location i1 in stack to i2 - */ - void copy(const unsigned int i1, const unsigned int i2); - /** - * Function to copy particle at location i2 in stack to i1 - */ - void swap(const unsigned int i1, const unsigned int i2); - - void incrementSize(); - - void decrementSize(); - - private: - /// the actual memory to store particle data - - nucleus_ref_type nucleusRef_; - nuclear_a_type nuclearA_; - nuclear_z_type nuclearZ_; - - }; // end class NuclearStackExtensionImpl - - template <typename TInnerStack, template <typename> typename PI_> - using NuclearStackExtension = - Stack<NuclearStackExtensionImpl<typename TInnerStack::stack_data_type>, PI_>; - - // - template <typename TStackIter> - using ExtendedParticleInterfaceType = - NuclearParticleInterface<VectorStack::pi_type, TStackIter>; - - // the particle data stack with extra nuclear information: - using ParticleDataStack = - NuclearStackExtension<VectorStack, ExtendedParticleInterfaceType>; - -} // namespace corsika::nuclear_stack - -#include <corsika/detail/stack/NuclearStackExtension.inl> diff --git a/corsika/stack/VectorStack.hpp b/corsika/stack/VectorStack.hpp index 32dc0af1706197730dcf4d9fd911d80a2276b83c..f58f6cd5616c823b655b6ddd84cca1273f04e1b1 100644 --- a/corsika/stack/VectorStack.hpp +++ b/corsika/stack/VectorStack.hpp @@ -10,6 +10,7 @@ #include <corsika/framework/core/ParticleProperties.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> +#include <corsika/framework/core/EnergyMomentumOperations.hpp> #include <corsika/framework/stack/Stack.hpp> #include <corsika/framework/geometry/Point.hpp> @@ -63,8 +64,6 @@ namespace corsika { * * @param v tuple containing of type particle_data_type * - * MomentumVector is only used to determine the DirectionVector, the normalization - * is lost. */ void setParticleData(particle_data_type const& v); @@ -102,23 +101,6 @@ namespace corsika { super_type::getStackData().setKineticEnergy(super_type::getIndex(), ekin); } - /** - * The MomentumVector v is used to determine the DirectionVector, and to update the - * particle energy. - */ - void setMomentum(MomentumVector const& v) { - HEPMomentumType const P = v.getNorm(); - if (P == 0_eV) { - super_type::getStackData().setKineticEnergy(super_type::getIndex(), 0_eV); - super_type::getStackData().setDirection( - super_type::getIndex(), DirectionVector(v.getCoordinateSystem(), {0, 0, 0})); - } else { - super_type::getStackData().setKineticEnergy( - super_type::getIndex(), - sqrt(square(getMass()) + square(P)) - this->getMass()); - super_type::getStackData().setDirection(super_type::getIndex(), v / P); - } - } //! Set direction void setDirection(DirectionVector const& v) { super_type::getStackData().setDirection(super_type::getIndex(), v); @@ -165,7 +147,7 @@ namespace corsika { } //! Get momentum MomentumVector getMomentum() const { - auto const P = sqrt(square(getEnergy()) - square(this->getMass())); + auto const P = calculate_momentum(this->getEnergy(), this->getMass()); return super_type::getStackData().getDirection(super_type::getIndex()) * P; } //! Get mass of particle diff --git a/corsika/stack/history/HistoryStackExtension.hpp b/corsika/stack/history/HistoryStackExtension.hpp index 9d517b0acae18d541be59f86d3540238a28b8c9a..4dc5f1df9646144cf2d13fb2b5ffa15f8e038e7e 100644 --- a/corsika/stack/history/HistoryStackExtension.hpp +++ b/corsika/stack/history/HistoryStackExtension.hpp @@ -67,10 +67,8 @@ namespace corsika::history { /** * @class HistoryDataInterface * - * corresponding defintion of a stack-readout object, the iteractor - * dereference operator will deliver access to these function - // defintion of a stack-readout object, the iteractor dereference - // operator will deliver access to these function + * corresponding definition of a stack-readout object, the iteractor + * dereference operator will deliver access to these function. */ template <typename T, typename TEvent> class HistoryDataInterface : public T { diff --git a/tests/modules/testObservationPlane.cpp b/tests/modules/testObservationPlane.cpp index e350c2fb2f0f5d24a8f69c6719658e5c1d6e6391..6411d9738b5cef34e36290091d5adb57621b6d5a 100644 --- a/tests/modules/testObservationPlane.cpp +++ b/tests/modules/testObservationPlane.cpp @@ -100,7 +100,7 @@ TEST_CASE("ObservationPlane", "interface") { MomentumVector const pnew = MomentumVector(cs, {1_GeV, 0.5_GeV, -0.4_GeV}); HEPEnergyType const enew = sqrt(pnew.dot(pnew)); - particle.setMomentum(pnew); + particle.setDirection(pnew.normalized()); particle.setEnergy(enew); Plane const obsPlane(Point(cs, {10_m, 5_m, 5_m}), diff --git a/tests/modules/testTracking.cpp b/tests/modules/testTracking.cpp index 1710844b19c6423842bc7b2a9a95bed9b084ea6b..4906bc58c486d8dbb43a3d790f1426ccfadd862a 100644 --- a/tests/modules/testTracking.cpp +++ b/tests/modules/testTracking.cpp @@ -35,31 +35,30 @@ int sgn(T val) { } /** - @file testTracking.cpp - - This is the unified and common unit test for all Tracking algorithms: - - - tracking_leapfrog_curved::Tracking - - tracking_leapfrog_straight::Tracking - - tracking_line::Tracking - - - The main part of tests are to inject particles at 10GeV momentum at - (-Rg,0,0) in +x direction into a sphere of radius Rg, where Rg is - the gyroradius (or 10m for neutral particles). Then it is checked - where the particles leaves the sphere for different charges - (-1,0,+1) and field strength (-50uT, 0T, +50uT). - - Each test is perfromed once, with the particles starting logically - outside of the Rg sphere (thus it first has to enter insides) and a - second time with the particle already logically inside the sphere. - - There is a second smaller, internal sphere at +z displacement. Only - neutral particles are allowed and expected to hit this. - - All those tests are parameterized, thus, they can be easily extended - or applied to new algorithms. - + * @file testTracking.cpp + * + * This is the unified and common unit test for all Tracking algorithms: + * + * - tracking_leapfrog_curved::Tracking + * - tracking_leapfrog_straight::Tracking + * - tracking_line::Tracking + * + * + * The main part of tests are to inject particles at 10GeV momentum at + * (-Rg,0,0) in +x direction into a sphere of radius Rg, where Rg is + * the gyroradius (or 10m for neutral particles). Then it is checked + * where the particles leaves the sphere for different charges + * (-1,0,+1) and field strength (-50uT, 0T, +50uT). + * + * Each test is perfromed once, with the particles starting logically + * outside of the Rg sphere (thus it first has to enter insides) and a + * second time with the particle already logically inside the sphere. + * + * There is a second smaller, internal sphere at +z displacement. Only + * neutral particles are allowed and expected to hit this. + * + * All those tests are parameterized, thus, they can be easily extended + * or applied to new algorithms. */ TEMPLATE_TEST_CASE("Tracking", "tracking", tracking_leapfrog_curved::Tracking, @@ -185,7 +184,7 @@ TEMPLATE_TEST_CASE("Tracking", "tracking", tracking_leapfrog_curved::Tracking, auto [traj, nextVol] = tracking.getTrack(particle); particle.setNode(nextVol); particle.setPosition(traj.getPosition(1)); - particle.setMomentum(traj.getDirection(1) * particle.getMomentum().getNorm()); + particle.setDirection(traj.getDirection(1)); SpeedType const speed_0 = particle.getVelocity().getNorm(); if (outer) { // now we know we are in target volume, depending on "outer" @@ -206,7 +205,7 @@ TEMPLATE_TEST_CASE("Tracking", "tracking", tracking_leapfrog_curved::Tracking, nextVol = nextVol2; particle.setNode(nextVol); particle.setPosition(traj2.getPosition(1)); - particle.setMomentum(traj2.getDirection(1) * particle.getMomentum().getNorm()); + particle.setDirection(traj2.getDirection(1)); CORSIKA_LOG_TRACE("pos={}, p={}, |p|={} |v|={}, delta-l={}, delta-t={}", particle.getPosition(), particle.getMomentum(), particle.getMomentum().getNorm(), @@ -234,7 +233,7 @@ TEMPLATE_TEST_CASE("Tracking", "tracking", tracking_leapfrog_curved::Tracking, } } -/** specifc test for curved leap-frog algorithm **/ +/** specifc test for curved leap-frog algorithm. */ TEST_CASE("TrackingLeapFrogCurved") { diff --git a/tests/stack/CMakeLists.txt b/tests/stack/CMakeLists.txt index 1314fd435a88474ce1df7cc8bf54cc918f30e5e9..149aa0533746dcc4af77c5eee7d01ce4717415de 100644 --- a/tests/stack/CMakeLists.txt +++ b/tests/stack/CMakeLists.txt @@ -1,6 +1,7 @@ set (test_stack_sources TestMain.cpp testHistoryStack.cpp + testHistoryView.cpp testGeometryNodeStackExtension.cpp testWeightStackExtension.cpp testDummyStack.cpp diff --git a/tests/stack/testHistoryView.cpp b/tests/stack/testHistoryView.cpp index 1633b8212c5c59903e99617fd4b2851f8ab133f7..198e98993123c8d0449ac1ba3d07013e334146b6 100644 --- a/tests/stack/testHistoryView.cpp +++ b/tests/stack/testHistoryView.cpp @@ -9,52 +9,34 @@ #include <corsika/stack/history/Event.hpp> #include <corsika/stack/history/HistorySecondaryProducer.hpp> #include <corsika/stack/history/HistoryStackExtension.hpp> - -#include <corsika/framework/stack/CombinedStack.hpp> +#include <corsika/stack/history/HistorySecondaryProducer.hpp> #include <corsika/stack/DummyStack.hpp> -#include <corsika/stack/NuclearStackExtension.hpp> - +#include <corsika/framework/stack/CombinedStack.hpp> #include <corsika/framework/core/Logging.hpp> #include <catch2/catch.hpp> using namespace corsika; -/** - Need to replicate setup::SetupStack in a maximally simplified - way, but with real particle data - */ +// the GeometryNode stack needs to know the type of geometry-nodes from the DummyEnv: +template <typename TStackIter> +using DummyHistoryDataInterface = + typename history::MakeHistoryDataInterface<TStackIter, history::Event>::type; // combine dummy stack with geometry information for tracking template <typename TStackIter> using StackWithHistoryInterface = - CombinedParticleInterface<nuclear_stack::ParticleDataStack::pi_type, - history::HistoryEventDataInterface, TStackIter>; + CombinedParticleInterface<dummy_stack::DummyStack::pi_type, DummyHistoryDataInterface, + TStackIter>; using TestStack = - CombinedStack<typename nuclear_stack::ParticleDataStack::stack_data_type, - history::HistoryEventData, StackWithHistoryInterface>; - -/* - See Issue 161 - - unfortunately clang does not support this in the same way (yet) as - gcc, so we have to distinguish here. If clang cataches up, we - could remove the clang branch here and also in - corsika::Cascade. The gcc code is much more generic and - universal. If we could do the gcc version, we won't had to define - StackView globally, we could do it with MakeView whereever it is - actually needed. Keep an eye on this! - */ -#if defined(__clang__) -using TheTestStackView = - SecondaryView<typename TestStack::stack_data_type, StackWithHistoryInterface, + CombinedStack<typename dummy_stack::DummyStack::stack_data_type, + history::HistoryData<history::Event>, StackWithHistoryInterface, history::HistorySecondaryProducer>; -#elif defined(__GNUC__) || defined(__GNUG__) -using TheTestStackView = MakeView<TestStack, history::HistorySecondaryProducer>::type; -#endif -using TestStackView = TheTestStackView; +// the correct secondary stack view +using TestStackView = typename TestStack::stack_view_type; +using EvtPtr = std::shared_ptr<history::Event>; template <typename Event> int count_generations(Event const* event) { @@ -70,27 +52,24 @@ int count_generations(Event const* event) { TEST_CASE("HistoryStackExtensionView", "[stack]") { logging::set_level(logging::level::info); - corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v"); - - CoordinateSystemPtr const& dummyCS = get_root_CoordinateSystem(); // in this test we only use one singel stack ! + const dummy_stack::NoData noData; TestStack stack; // add primary particle - auto p0 = stack.addParticle( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto p0 = stack.addParticle(std::make_tuple(noData)); CHECK(stack.getEntries() == 1); - corsika::history::EventPtr evt = p0.getEvent(); + EvtPtr evt = p0.getEvent(); CHECK(evt == nullptr); CHECK(count_generations(evt.get()) == 0); SECTION("interface test, view") { // add secondaries, 1st generation - TestStackView hview0(p0); + auto pnext = stack.getNextParticle(); + TestStackView hview0(pnext); auto const ev0 = p0.getEvent(); CHECK(ev0 == nullptr); @@ -99,12 +78,10 @@ TEST_CASE("HistoryStackExtensionView", "[stack]") { // add 5 secondaries for (int i = 0; i < 5; ++i) { - auto sec = hview0.addSecondary( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto sec = hview0.addSecondary(std::make_tuple(noData)); CHECK(sec.getParentEventIndex() == i); - CHECK(sec.getEvent() != nullptr); + CHECK(sec.getEvent().get() != nullptr); CHECK(sec.getEvent()->parentEvent() == nullptr); CHECK(count_generations(sec.getEvent().get()) == 1); } @@ -120,9 +97,7 @@ TEST_CASE("HistoryStackExtensionView", "[stack]") { // add second generation of secondaries // add 10 secondaries for (int i = 0; i < 10; ++i) { - auto sec = hview1.addSecondary( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto sec = hview1.addSecondary(std::make_tuple(noData)); CHECK(sec.getParentEventIndex() == i); CHECK(sec.getEvent()->parentEvent() == ev1); @@ -146,9 +121,7 @@ TEST_CASE("HistoryStackExtensionView", "[stack]") { for (int i = 0; i < 15; ++i) { CORSIKA_LOG_TRACE("loop, view: " + std::to_string(i)); - auto sec = hview2.addSecondary( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto sec = hview2.addSecondary(std::make_tuple(noData)); CORSIKA_LOG_TRACE("loop, ---- "); CHECK(sec.getParentEventIndex() == i); @@ -175,9 +148,7 @@ TEST_CASE("HistoryStackExtensionView", "[stack]") { // add 5 secondaries for (int i = 0; i < 5; ++i) { CORSIKA_LOG_TRACE("loop " + std::to_string(i)); - auto sec = proj0.addSecondary( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto sec = proj0.addSecondary(std::make_tuple(noData)); CHECK(sec.getParentEventIndex() == i); CHECK(sec.getEvent() != nullptr); @@ -195,9 +166,7 @@ TEST_CASE("HistoryStackExtensionView", "[stack]") { // add second generation of secondaries // add 10 secondaries for (unsigned int i = 0; i < 10; ++i) { - auto sec = proj1.addSecondary( - std::make_tuple(Code::Electron, MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), - Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s)); + auto sec = proj1.addSecondary(std::make_tuple(noData)); CHECK(sec.getParentEventIndex() == int(i)); CHECK(sec.getEvent()->parentEvent() == ev1);