From ae81c13aff136adabf91bf63c1ac8cb2875198ce Mon Sep 17 00:00:00 2001 From: ralfulrich <ralf.ulrich@kit.edu> Date: Wed, 30 Jan 2019 12:07:44 +0100 Subject: [PATCH] added nuclearstackextension --- Stack/NuclearStackExtension/CMakeLists.txt | 49 ++++ .../NuclearStackExtension.h | 235 ++++++++++++++++++ .../testNuclearStackExtension.cc | 192 ++++++++++++++ 3 files changed, 476 insertions(+) create mode 100644 Stack/NuclearStackExtension/CMakeLists.txt create mode 100644 Stack/NuclearStackExtension/NuclearStackExtension.h create mode 100644 Stack/NuclearStackExtension/testNuclearStackExtension.cc diff --git a/Stack/NuclearStackExtension/CMakeLists.txt b/Stack/NuclearStackExtension/CMakeLists.txt new file mode 100644 index 00000000..f2f34cfc --- /dev/null +++ b/Stack/NuclearStackExtension/CMakeLists.txt @@ -0,0 +1,49 @@ + +set (NuclearStackExtension_HEADERS NuclearStackExtension.h) +set (NuclearStackExtension_NAMESPACE corsika/stack/nuclear_extension) + +add_library (NuclearStackExtension INTERFACE) + +CORSIKA_COPY_HEADERS_TO_NAMESPACE (NuclearStackExtension ${NuclearStackExtension_NAMESPACE} ${NuclearStackExtension_HEADERS}) + +target_link_libraries ( + NuclearStackExtension + INTERFACE + CORSIKAstackinterface + CORSIKAunits + CORSIKAparticles + CORSIKAgeometry + ) + +target_include_directories ( + NuclearStackExtension + INTERFACE + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include> + $<INSTALL_INTERFACE:include> + ) + +install ( + FILES + ${NuclearStackExtension_HEADERS} + DESTINATION + include/${NuclearStackExtension_NAMESPACE} + ) + +# ---------------- +# code unit testing +add_executable ( + testNuclearStackExtension + testNuclearStackExtension.cc + ) + +target_link_libraries ( + testNuclearStackExtension + SuperStupidStack + NuclearStackExtension + # CORSIKAutls + ProcessStackInspector + CORSIKAgeometry + CORSIKAunits + CORSIKAthirdparty # for catch2 + ) +CORSIKA_ADD_TEST(testNuclearStackExtension) diff --git a/Stack/NuclearStackExtension/NuclearStackExtension.h b/Stack/NuclearStackExtension/NuclearStackExtension.h new file mode 100644 index 00000000..1d5955fd --- /dev/null +++ b/Stack/NuclearStackExtension/NuclearStackExtension.h @@ -0,0 +1,235 @@ + +/* + * (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_stack_nuclearstackextension_h_ +#define _include_stack_nuclearstackextension_h_ + +#include <corsika/stack/super_stupid/SuperStupidStack.h> + +#include <vector> + +namespace corsika::stack { + + namespace nuclear_extension { + + using corsika::stack::super_stupid::MomentumVector; + + template <typename StackIteratorInterface> + class ParticleInterface + : public corsika::stack::super_stupid::ParticleInterface<StackIteratorInterface> { + + protected: + // using corsika::stack::ParticleBase<StackIteratorInterface>::GetStack; + //using corsika::stack::super_stupid::ParticleInterface<StackIteratorInterface>::GetStackData; + using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData; + using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex; + + public: + void SetParticleData(const corsika::particles::Code vDataPID, + const corsika::units::si::HEPEnergyType vDataE, + const corsika::stack::super_stupid::MomentumVector& vMomentum, + const corsika::geometry::Point& vPosition, + const corsika::units::si::TimeType vTime, + const int vA = 0, + const int vZ = 0) { + if (vDataPID == corsika::particles::Code::Nucleus) { + if (vA==0 || vZ==0) { + std::ostringstream err; + err << "NuclearStackExtension: no A and Z specified for new Nucleus!"; + throw std::runtime_error(err.str()); + } + SetNuclearRef(corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData().GetNucleusNextRef()); // store this nucleus data ref + SetNuclearA(vA); + SetNuclearZ(vZ); + } else { + SetNuclearRef(-1); // this is not a nucleus + } + corsika::stack::super_stupid::ParticleInterface<StackIteratorInterface>::SetParticleData(vDataPID, + vDataE, + vMomentum, + vPosition, + vTime); + } + + void SetParticleData(ParticleInterface<StackIteratorInterface>& parent, + const corsika::particles::Code vDataPID, + const corsika::units::si::HEPEnergyType vDataE, + const corsika::stack::super_stupid::MomentumVector& vMomentum, + const corsika::geometry::Point& vPosition, + const corsika::units::si::TimeType vTime, + const int vA = 0, + const int vZ = 0) { + SetParticleData(vDataPID, + vDataE, + vMomentum, + vPosition, + vTime, + vA, + vZ); + } + + /** + * @name individual setters + * @{ + */ + void SetNuclearA(const int vA) { GetStackData().SetNuclearA(GetIndex(), vA); } + void SetNuclearZ(const int vZ) { GetStackData().SetNuclearZ(GetIndex(), vZ); } + /// @} + + /** + * @name individual getters + * @{ + */ + int GetNuclearA() const { return GetStackData().GetNuclearA(GetIndex()); } + int GetNuclearZ() const { return GetStackData().GetNuclearZ(GetIndex()); } + /// @} + + protected: + void SetNuclearRef(const int vR) { GetStackData().SetNuclearRef(GetIndex(), vR); } + }; + + + /** + * Memory implementation of the most simple (stupid) particle stack object. + */ + + class NuclearStackExtensionImpl + : public corsika::stack::super_stupid::SuperStupidStackImpl { + + public: + void Init() { corsika::stack::super_stupid::SuperStupidStackImpl::Init(); } + + void Clear() { + corsika::stack::super_stupid::SuperStupidStackImpl::Clear(); + fNuclearRef.clear(); + fNuclearA.clear(); + fNuclearZ.clear(); + } + + int GetSize() const { return fNuclearRef.size(); } + int GetCapacity() const { return fNuclearRef.size(); } + + void SetNuclearA(const int i, const int vA) { fNuclearA[GetNucleusRef(i)] = vA; } + void SetNuclearZ(const int i, const int vZ) { fNuclearZ[GetNucleusRef(i)] = vZ; } + void SetNuclearRef(const int i, const int v) { fNuclearRef[i] = v; } + + int GetNuclearA(const int i) const { return fNuclearA[GetNucleusRef(i)]; } + int GetNuclearZ(const int i) const { return fNuclearZ[GetNucleusRef(i)]; } + // this function will create new storage for Nuclear Properties, and return the reference to it + int GetNucleusNextRef() { fNuclearA.push_back(0); fNuclearZ.push_back(0); return fNuclearA.size()-1; } + + int GetNucleusRef(const int i) const { + if (fNuclearRef[i]>=0) + return fNuclearRef[i]; + std::ostringstream err; + err << "NuclearStackExtension: no nucleus at ref=" << i; + throw std::runtime_error(err.str()); + } + + /** + * Function to copy particle at location i1 in stack to i2 + */ + void Copy(const int i1, const int i2) { + corsika::stack::super_stupid::SuperStupidStackImpl::Copy(i1, i2); + const int ref1 = fNuclearRef[i1]; + const int ref2 = fNuclearRef[i2]; + if (ref2<0) { + if (ref1>=0) { + // i1 is nucleus, i2 is not + fNuclearRef[i2] = GetNucleusNextRef(); + fNuclearA[fNuclearRef[i2]] = fNuclearA[ref1]; + fNuclearZ[fNuclearRef[i2]] = fNuclearZ[ref1]; + } else { + // neither i1 nor i2 are nuclei + } + } else { + if (ref1>=0) { + // both are nuclei, i2 is overwritten with nucleus i1 + fNuclearA[ref2] = fNuclearA[ref1]; + fNuclearZ[ref2] = fNuclearZ[ref1]; + } else { + // i2 is overwritten with non-nucleus i1 + fNuclearA.erase(fNuclearA.begin() + ref2); + fNuclearZ.erase(fNuclearZ.begin() + ref2); + const int n = fNuclearRef.size(); + for (int i=0; i<n; ++i) { + if (fNuclearRef[i]>=ref2) { + fNuclearRef[i] -= 1; + } + } + } + } + } + + /** + * Function to copy particle at location i2 in stack to i1 + */ + void Swap(const int i1, const int i2) { + corsika::stack::super_stupid::SuperStupidStackImpl::Swap(i1, i2); + const int ref1 = fNuclearRef[i1]; + const int ref2 = fNuclearRef[i2]; + if (ref2<0) { + if (ref1>=0) { + // i1 is nucleus, i2 is not + std::swap(fNuclearRef[i2], fNuclearRef[i1]); + } else { + // neither i1 nor i2 are nuclei + } + } else { + if (ref1>=0) { + // both are nuclei, i2 is overwritten with nucleus i1 + std::swap(fNuclearRef[i2], fNuclearRef[i1]); + } else { + // i2 is overwritten with non-nucleus i1 + std::swap(fNuclearRef[i2], fNuclearRef[i1]); + } + } + } + + protected: + void IncrementSize() { + corsika::stack::super_stupid::SuperStupidStackImpl::IncrementSize(); + fNuclearRef.push_back(-1); + } + + void DecrementSize() { + corsika::stack::super_stupid::SuperStupidStackImpl::DecrementSize(); + if (fNuclearRef.size() > 0) { + const int ref = fNuclearRef.back(); + fNuclearRef.pop_back(); + if (ref>=0) { + fNuclearA.erase(fNuclearA.begin() + ref); + fNuclearZ.erase(fNuclearZ.begin() + ref); + const int n = fNuclearRef.size(); + for (int i=0; i<n; ++i) { + if (fNuclearRef[i] >= ref) { + fNuclearRef[i] -= 1; + } + } + } + } + } + + private: + /// the actual memory to store particle data + + std::vector<int> fNuclearRef; + std::vector<int> fNuclearA; + std::vector<int> fNuclearZ; + + }; // end class SuperStupidStackImpl + + typedef Stack<NuclearStackExtensionImpl, ParticleInterface> NuclearStackExtension; + + } // namespace nuclear_extension +} // namespace corsika::stack + +#endif diff --git a/Stack/NuclearStackExtension/testNuclearStackExtension.cc b/Stack/NuclearStackExtension/testNuclearStackExtension.cc new file mode 100644 index 00000000..f8fac4bd --- /dev/null +++ b/Stack/NuclearStackExtension/testNuclearStackExtension.cc @@ -0,0 +1,192 @@ + +/* + * (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/geometry/RootCoordinateSystem.h> +#include <corsika/stack/nuclear_extension/NuclearStackExtension.h> +#include <corsika/units/PhysicalUnits.h> + +using namespace corsika::geometry; +using namespace corsika::units::si; + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one + // cpp file +#include <catch2/catch.hpp> + +using namespace corsika; +using namespace corsika::stack::nuclear_extension; + +#include <iostream> +using namespace std; + +TEST_CASE("NuclearStackExtension", "[stack]") { + + geometry::CoordinateSystem& dummyCS = + geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); + + SECTION("write non nucleus") { + NuclearStackExtension s; + s.AddParticle(particles::Code::Electron, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s); + REQUIRE(s.GetSize() == 1); + } + + SECTION("write nucleus") { + NuclearStackExtension s; + s.AddParticle(particles::Code::Nucleus, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 10); + REQUIRE(s.GetSize() == 1); + } + + SECTION("write invalid nucleus") { + NuclearStackExtension s; + REQUIRE_THROWS(s.AddParticle(particles::Code::Nucleus, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 0, 0)); + } + + SECTION("read non nucleus") { + NuclearStackExtension s; + s.AddParticle(particles::Code::Electron, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s); + const auto pout = s.GetNextParticle(); + REQUIRE(pout.GetPID() == particles::Code::Electron); + REQUIRE(pout.GetEnergy() == 1.5_GeV); + REQUIRE(pout.GetTime() == 100_s); + } + + SECTION("read nucleus") { + NuclearStackExtension s; + s.AddParticle(particles::Code::Nucleus, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9); + const auto pout = s.GetNextParticle(); + REQUIRE(pout.GetPID() == particles::Code::Nucleus); + REQUIRE(pout.GetEnergy() == 1.5_GeV); + REQUIRE(pout.GetTime() == 100_s); + REQUIRE(pout.GetNuclearA() == 10); + REQUIRE(pout.GetNuclearZ() == 9); + } + + SECTION("read invalid nucleus") { + NuclearStackExtension s; + s.AddParticle(particles::Code::Electron, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s); + const auto pout = s.GetNextParticle(); + REQUIRE_THROWS(pout.GetNuclearA()); + REQUIRE_THROWS(pout.GetNuclearZ()); + } + + + SECTION("stack fill and cleanup") { + + NuclearStackExtension s; + // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2! + for (int i = 0; i < 99; ++i) { + if ((i+1)%10 == 0) { + s.AddParticle(particles::Code::Nucleus, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i/2); + } else { + s.AddParticle(particles::Code::Electron, 1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s); + } + } + + REQUIRE(s.GetSize() == 99); + + for (int i = 0; i < 99; ++i) s.GetNextParticle().Delete(); + + REQUIRE(s.GetSize() == 0); + } + + + SECTION("stack operations") { + + NuclearStackExtension s; + // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2! + for (int i = 0; i < 99; ++i) { + if ((i+1)%10 == 0) { + s.AddParticle(particles::Code::Nucleus, i*15_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i/2); + } else { + s.AddParticle(particles::Code::Electron, i*1.5_GeV, + MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s); + } + } + + // copy + { + s.Copy(s.begin()+9, s.begin()+10); + const auto& p9 = s.cbegin() + 9; + const auto& p10 = s.cbegin() + 10; + + REQUIRE(p9.GetPID() == particles::Code::Nucleus); + REQUIRE(p9.GetEnergy() == 9*15_GeV); + REQUIRE(p9.GetTime() == 100_s); + REQUIRE(p9.GetNuclearA() == 9); + REQUIRE(p9.GetNuclearZ() == 9/2); + + REQUIRE(p10.GetPID() == particles::Code::Nucleus); + REQUIRE(p10.GetEnergy() == 9*15_GeV); + REQUIRE(p10.GetTime() == 100_s); + REQUIRE(p10.GetNuclearA() == 9); + REQUIRE(p10.GetNuclearZ() == 9/2); + } + + // swap + { + s.Swap(s.begin()+11, s.begin()+10); + const auto& p11 = s.cbegin() + 11; // now: nucleus + const auto& p10 = s.cbegin() + 10; // now: electron + + REQUIRE(p11.GetPID() == particles::Code::Nucleus); + REQUIRE(p11.GetEnergy() == 9*15_GeV); + REQUIRE(p11.GetTime() == 100_s); + REQUIRE(p11.GetNuclearA() == 9); + REQUIRE(p11.GetNuclearZ() == 9/2); + + REQUIRE(p10.GetPID() == particles::Code::Electron); + REQUIRE(p10.GetEnergy() == 11*1.5_GeV); + REQUIRE(p10.GetTime() == 100_s); + } + + // swap two nuclei + { + s.Copy(s.begin()+29, s.begin()+59); + const auto& p29 = s.cbegin() + 29; + const auto& p59 = s.cbegin() + 59; + + REQUIRE(p29.GetPID() == particles::Code::Nucleus); + REQUIRE(p29.GetEnergy() == 59*15_GeV); + REQUIRE(p29.GetTime() == 100_s); + REQUIRE(p29.GetNuclearA() == 59); + REQUIRE(p29.GetNuclearZ() == 59/2); + + REQUIRE(p59.GetPID() == particles::Code::Nucleus); + REQUIRE(p59.GetEnergy() == 29*15_GeV); + REQUIRE(p59.GetTime() == 100_s); + REQUIRE(p59.GetNuclearA() == 29); + REQUIRE(p59.GetNuclearZ() == 29/2); + } + + for (int i = 0; i < 99; ++i) s.DeleteLast(); + REQUIRE(s.GetSize() == 0); + + } + +} -- GitLab