IAP GITLAB

Skip to content
Snippets Groups Projects
NuclearStackExtension.h 10.4 KiB
Newer Older
ralfulrich's avatar
ralfulrich committed

/*
 * (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 <corsika/particles/ParticleProperties.h>
#include <corsika/stack/Stack.h>
#include <corsika/units/PhysicalUnits.h>

#include <corsika/geometry/Point.h>
#include <corsika/geometry/Vector.h>

#include <algorithm>
ralfulrich's avatar
ralfulrich committed
#include <vector>

namespace corsika::stack {

  namespace nuclear_extension {

    typedef corsika::geometry::Vector<corsika::units::si::hepmomentum_d> MomentumVector;

    /**
ralfulrich's avatar
ralfulrich committed
     * Define ParticleInterface for NuclearStackExtension Stack derived from
     * ParticleInterface of Inner stack class
     */
    template <template <typename> typename InnerParticleInterface,
              typename StackIteratorInterface>
    class NuclearParticleInterface
        : public InnerParticleInterface<StackIteratorInterface> {
ralfulrich's avatar
ralfulrich committed
      using ExtendedParticleInterface =
          NuclearParticleInterface<InnerParticleInterface, StackIteratorInterface>;

ralfulrich's avatar
ralfulrich committed
    protected:
      using InnerParticleInterface<StackIteratorInterface>::GetStackData;
      using InnerParticleInterface<StackIteratorInterface>::GetIndex;
ralfulrich's avatar
ralfulrich committed

    public:
      void SetParticleData(const corsika::particles::Code vDataPID,
                           const corsika::units::si::HEPEnergyType vDataE,
                           const MomentumVector& vMomentum,
ralfulrich's avatar
ralfulrich committed
                           const corsika::geometry::Point& vPosition,
ralfulrich's avatar
ralfulrich committed
                           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(
              GetStackData().GetNucleusNextRef()); // store this nucleus data ref
          SetNuclearA(vA);
          SetNuclearZ(vZ);
        } else {
          SetNuclearRef(-1); // this is not a nucleus
        }
        InnerParticleInterface<StackIteratorInterface>::
            SetParticleData(vDataPID, vDataE, vMomentum, vPosition, vTime);
      void SetParticleData(InnerParticleInterface<StackIteratorInterface>&,
ralfulrich's avatar
ralfulrich committed
                           const corsika::particles::Code vDataPID,
                           const corsika::units::si::HEPEnergyType vDataE,
                           const MomentumVector& vMomentum,
ralfulrich's avatar
ralfulrich committed
                           const corsika::geometry::Point& vPosition,
ralfulrich's avatar
ralfulrich committed
                           const corsika::units::si::TimeType vTime, const int vA = 0,
                           const int vZ = 0) {
        SetParticleData(vDataPID, vDataE, vMomentum, vPosition, vTime, vA, vZ);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
      /**
       * @name individual setters
       * @{
       */
      void SetNuclearA(const int vA) { GetStackData().SetNuclearA(GetIndex(), vA); }
ralfulrich's avatar
ralfulrich committed
      void SetNuclearZ(const int vZ) { GetStackData().SetNuclearZ(GetIndex(), vZ); }
ralfulrich's avatar
ralfulrich committed
      /// @}

      /**
       * @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.
     */
ralfulrich's avatar
ralfulrich committed
    template <typename InnerStackImpl>
    class NuclearStackExtensionImpl : public InnerStackImpl {
      void Init() { InnerStackImpl::Init(); }
ralfulrich's avatar
ralfulrich committed

      void Clear() {
ralfulrich's avatar
ralfulrich committed
        fNuclearRef.clear();
        fNuclearA.clear();
        fNuclearZ.clear();
      }

      unsigned int GetSize() const { return fNuclearRef.size(); }
      unsigned int GetCapacity() const { return fNuclearRef.size(); }
ralfulrich's avatar
ralfulrich committed
      void SetNuclearA(const unsigned int i, const int vA) {
        fNuclearA[GetNucleusRef(i)] = vA;
      }
      void SetNuclearZ(const unsigned int i, const int vZ) {
        fNuclearZ[GetNucleusRef(i)] = vZ;
      }
      void SetNuclearRef(const unsigned int i, const int v) { fNuclearRef[i] = v; }
ralfulrich's avatar
ralfulrich committed

      int GetNuclearA(const unsigned int i) const { return fNuclearA[GetNucleusRef(i)]; }
      int GetNuclearZ(const unsigned int i) const { return fNuclearZ[GetNucleusRef(i)]; }
ralfulrich's avatar
ralfulrich committed
      // 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 unsigned int i) const {
ralfulrich's avatar
ralfulrich committed
        if (fNuclearRef[i] >= 0) return fNuclearRef[i];
        std::ostringstream err;
        err << "NuclearStackExtension: no nucleus at ref=" << i;
        throw std::runtime_error(err.str());
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
      /**
       *   Function to copy particle at location i1 in stack to i2
       */
      void Copy(const unsigned int i1, const unsigned int i2) {
ralfulrich's avatar
ralfulrich committed
        if (i1 >= GetSize() || i2 >= GetSize()) {
          std::ostringstream err;
          err << "NuclearStackExtension: trying to access data beyond size of stack!";
          throw std::runtime_error(err.str());
        }
ralfulrich's avatar
ralfulrich committed
        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.cbegin() + ref2);
            fNuclearZ.erase(fNuclearZ.cbegin() + ref2);
            const int n = fNuclearRef.size();
            for (int i = 0; i < n; ++i) {
              if (fNuclearRef[i] >= ref2) { fNuclearRef[i] -= 1; }
            }
          }
        }
ralfulrich's avatar
ralfulrich committed
      }

      /**
       *   Function to copy particle at location i2 in stack to i1
       */
      void Swap(const unsigned int i1, const unsigned int i2) {
ralfulrich's avatar
ralfulrich committed
        if (i1 >= GetSize() || i2 >= GetSize()) {
          std::ostringstream err;
          err << "NuclearStackExtension: trying to access data beyond size of stack!";
          throw std::runtime_error(err.str());
        }
ralfulrich's avatar
ralfulrich committed
        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]);
          }
        }
ralfulrich's avatar
ralfulrich committed
      }

    protected:
      void IncrementSize() {
        InnerStackImpl::IncrementSize();
ralfulrich's avatar
ralfulrich committed
        fNuclearRef.push_back(-1);
      }

      void DecrementSize() {
        InnerStackImpl::DecrementSize();
ralfulrich's avatar
ralfulrich committed
        if (fNuclearRef.size() > 0) {
ralfulrich's avatar
ralfulrich committed
          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; }
            }
          }
        }
ralfulrich's avatar
ralfulrich committed
      }

    private:
      /// the actual memory to store particle data

      std::vector<int> fNuclearRef;
      std::vector<int> fNuclearA;
      std::vector<int> fNuclearZ;

    }; // end class NuclearStackExtensionImpl
    //    template<typename StackIteratorInterface>
ralfulrich's avatar
ralfulrich committed
    // using NuclearParticleInterfaceType<StackIteratorInterface> =
    // NuclearParticleInterface< ,StackIteratorInterface>
    // works, but requires stupd _PI class
ralfulrich's avatar
ralfulrich committed
    // template<typename SS> using TEST =
    // NuclearParticleInterface<corsika::stack::super_stupid::SuperStupidStack::PIType,
    // SS>;
    template <typename InnerStack, template <typename> typename _PI>
    using NuclearStackExtension =
        Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, _PI>;

ralfulrich's avatar
ralfulrich committed

    // I'm dont't manage to do this properly.......
    /*
ralfulrich's avatar
ralfulrich committed
    template<typename TT, typename SS> using TESTi = typename
    NuclearParticleInterface<TT::template PIType, SS>::ExtendedParticleInterface;
    template<typename TT, typename SS> using TEST1 = TESTi<TT, SS>;
    template<typename SS> using TEST2 = TEST1<typename
    corsika::stack::super_stupid::SuperStupidStack, SS>;

    using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
    InnerStack::StackImpl>, TEST2>;
    */
    /*
      // .... this should be fixed ....

    template <typename InnerStack, typename SS=StackIteratorInterface>
ralfulrich's avatar
ralfulrich committed
      //using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
    InnerStack::StackImpl>, NuclearParticleInterface<typename InnerStack::template PIType,
    StackIteratorInterface>::ExtendedParticleInterface>; using NuclearStackExtension =
    Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, TEST1<typename
    corsika::stack::super_stupid::SuperStupidStack, SS> >;

    //template <typename InnerStack>
ralfulrich's avatar
ralfulrich committed
      //  using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
    InnerStack::StackImpl>, TEST<typename
    corsika::stack::super_stupid::SuperStupidStack::PIType>>;
    //using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
    InnerStack::StackImpl>, TEST>;
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  } // namespace nuclear_extension
} // namespace corsika::stack

#endif