IAP GITLAB

Skip to content
Snippets Groups Projects
Cascade.h 28.4 KiB
Newer Older
 * (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
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
#include <corsika/environment/Environment.h>
#include <corsika/logging/Logging.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/process/ProcessReturn.h>
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
#include <corsika/random/ExponentialDistribution.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/random/RNGManager.h>
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
#include <corsika/random/UniformRealDistribution.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/stack/SecondaryView.h>
#include <corsika/units/PhysicalUnits.h>
#include <corsika/stack/history/EventType.hpp>
#include <corsika/stack/history/HistorySecondaryProducer.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/setup/SetupTrajectory.h>

/*  see Issue 161, we need to include SetupStack only because we need
    to globally define StackView. This is clearly not nice and should
    be changed, when possible. It might be that StackView needs to be
    templated in Cascade, but this would be even worse... so we don't
    do that until it is really needed.
 */
#include <corsika/setup/SetupStack.h>

#include <cassert>
André Schmidt's avatar
André Schmidt committed
#include <boost/type_index.hpp>
using boost::typeindex::type_id_with_cvr;

Andre Schmidt's avatar
Andre Schmidt committed
#include <fstream>
#include <boost/histogram.hpp>
#include <boost/histogram/ostream.hpp>
#include <corsika/process/tracking_line/dump_bh.hpp>
using namespace boost::histogram;
/*static auto histL2 = make_histogram(axis::regular<>(100, 0, 60000, "L'"));
Andre Schmidt's avatar
Andre Schmidt committed
static auto histS2 = make_histogram(axis::regular<>(100, 0, 60000, "S"));
static auto histB2 = make_histogram(axis::regular<>(100, 0, 60000, "Bogenlnge"));*/
static auto histLlog2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLlog2int = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLlog2dec = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLlog2max = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLlog2geo = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLlog2mag = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));

/*static auto histSlog2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Direct Length S"));
static auto histBlog2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Arc Length B"));
Andre Schmidt's avatar
Andre Schmidt committed
static auto histLB2 = make_histogram(axis::regular<>(100, 0, 0.01, "L - B"));
static auto histLS2 = make_histogram(axis::regular<>(100, 0, 0.01, "L - S"));
static auto histLBrel2 = make_histogram(axis::regular<double, axis::transform::log> (20,1e-11,1e-6,"L/B -1"));
static auto histLSrel2 = make_histogram(axis::regular<double, axis::transform::log>(20,1e-11,1e-6, "L/S -1"));
static auto histELSrel2 = make_histogram(axis::regular<double, axis::transform::log>(20,1e-11,1e-6, "L/S -1"),axis::regular<double, axis::transform::log>(20, 0.1, 1e4, "E / GeV"));
static auto histBS2 = make_histogram(axis::regular<>(100, 0, 0.01, "B - S")); */

static auto histLp2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "L' fr Protonen"));
static auto histLpi2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "L' fr Pionen"));
static auto histLpi2int = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLpi2dec = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLpi2max = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLpi2geo = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLpi2mag = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLmu2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "L' fr Myonen"));
static auto histLmu2int = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLmu2dec = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLmu2max = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLmu2geo = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLmu2mag = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "Leap-Frog-length L'"));
static auto histLe2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "L' fr Elektronen"));
static auto histLy2 = make_histogram(axis::regular<double, axis::transform::log>(100, 1e-3, 1e7, "L' fr Photonen"));
Andre Schmidt's avatar
Andre Schmidt committed
static double stepradius = 0;
static int N = 0;
static double stepradiusp = 0;
static int Np = 0;
static double stepradiuspi = 0;
static int Npi = 0;
static double stepradiusmu = 0;
static int Nmu = 0;

ralfulrich's avatar
ralfulrich committed
/**
 * The cascade namespace assembles all objects needed to simulate full particles cascades.
 */

namespace corsika::cascade {

ralfulrich's avatar
ralfulrich committed
  /**
   * \class Cascade
   *
ralfulrich's avatar
ralfulrich committed
   * The Cascade class is constructed from template arguments making
   * it very versatile. Via the template arguments physics models are
   * plugged into the cascade simulation.
   *
ralfulrich's avatar
ralfulrich committed
   * <b>TTracking</b> must be a class according to the
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
   * TrackingInterface providing the functions:
   * <code>auto GetTrack(Particle const& p)</auto>,
   * with the return type <code>geometry::Trajectory<corsika::geometry::Line>
   * </code>
ralfulrich's avatar
ralfulrich committed
   *
ralfulrich's avatar
ralfulrich committed
   * <b>TProcessList</b> must be a ProcessSequence.   *
ralfulrich's avatar
ralfulrich committed
   * <b>Stack</b> is the storage object for particle data, i.e. with
   * Particle class type <code>Stack::ParticleType</code>
   *
   *
   */

  template <typename TTracking, typename TProcessList, typename TStack,
            /*
ralfulrich's avatar
ralfulrich committed
              TStackView is needed as explicit template parameter because
              of issue 161 and the
              inability of clang to understand "stack::MakeView" so far.
             */
            typename TStackView = corsika::setup::StackView>
  class Cascade {
ralfulrich's avatar
ralfulrich committed
    using Particle = typename TStack::ParticleType;
    using VolumeTreeNode =
        std::remove_pointer_t<decltype(((Particle*)nullptr)->GetNode())>;
    using MediumInterface = typename VolumeTreeNode::IModelProperties;
ralfulrich's avatar
ralfulrich committed
  private:
    // Data members
    corsika::environment::Environment<MediumInterface> const& environment_;
    TTracking& tracking_;
    TProcessList& process_sequence_;
    TStack& stack_;
    corsika::random::RNG& rng_ =
ralfulrich's avatar
ralfulrich committed
        corsika::random::RNGManager::GetInstance().GetRandomStream("cascade");
    unsigned int count_ = 0;

  private:
    // we only want fully configured objects
ralfulrich's avatar
ralfulrich committed
    /**
     * Cascade class cannot be default constructed, but needs a valid
     * list of physics processes for configuration at construct time.
     */
ralfulrich's avatar
ralfulrich committed
    Cascade(corsika::environment::Environment<MediumInterface> const& env, TTracking& tr,
            TProcessList& pl, TStack& stack)
        : environment_(env)
        , tracking_(tr)
        , process_sequence_(pl)
        , stack_(stack)
ralfulrich's avatar
ralfulrich committed
        , count_(0) {
      C8LOG_INFO(c8_ascii_);
      if constexpr (TStackView::has_event) {
        C8LOG_INFO(" - With full cascade HISTORY.");
      }
    
    ~Cascade(){    
		  /*std::ofstream myfile;
Andre Schmidt's avatar
Andre Schmidt committed
          myfile.open ("stepradius.txt");
          myfile << "All charged particles " << stepradius/N << std::endl;
          myfile << "Protons " << stepradiusp/Np << std::endl;
          myfile << "Pions " << stepradiuspi/Npi << std::endl;
          myfile << "Muons " << stepradiusmu/Nmu << std::endl;
          myfile.close();
Andre Schmidt's avatar
Andre Schmidt committed
		  
		  /*std::cout << histLBrel << std::endl;
		  std::cout << histLSrel << std::endl;*/

		  
		      /*std::ofstream file1("histL2.json");
Andre Schmidt's avatar
Andre Schmidt committed
          dump_bh(file1, histL2);
          file1.close();
          std::ofstream file2("histS2.json");
          dump_bh(file2, histS2);
          file2.close();
          std::ofstream file3("histB2.json");
          dump_bh(file3, histB2);
          file3.close();
          std::ofstream file4("histLB.json");
Andre Schmidt's avatar
Andre Schmidt committed
          dump_bh(file4, histLB);
          file4.close();
          std::ofstream file5("histLS.json");
          dump_bh(file5, histLS);
          file5.close();
          std::ofstream file6("histBS.json");
          dump_bh(file6, histBS);
          file6.close();
          std::ofstream file7("histLBrel.json");
          dump_bh(file7, histLBrel);
          file7.close();
          std::ofstream file8("histLSrel.json");
          dump_bh(file8, histLSrel);
          file8.close();
          
          std::ofstream file10("histELSrel.json");
          dump_bh(file10, histELSrel);
Andre Schmidt's avatar
Andre Schmidt committed
          file10.close(); //hier ende
Andre Schmidt's avatar
Andre Schmidt committed
          std::ofstream file19("histLy2.json");
          dump_bh(file19, histLy2);
          file19.close();
          std::ofstream file10("histLe2.json");
          dump_bh(file10, histLe2);
          file10.close();
Andre Schmidt's avatar
Andre Schmidt committed
          std::ofstream file11("histLmu2.json");
          dump_bh(file11, histLmu2);
          file11.close();
          std::ofstream file12("histLpi2.json");
          dump_bh(file12, histLpi2);
          file12.close();
          std::ofstream file13("histLp2.json");
          dump_bh(file13, histLp2);
          file13.close();
Andre Schmidt's avatar
Andre Schmidt committed
          std::ofstream file14("histLlog2.json");
          dump_bh(file14, histLlog2);
          file14.close();
          /*std::ofstream file15("histBlog2.json");
Andre Schmidt's avatar
Andre Schmidt committed
          dump_bh(file15, histBlog2);
          file15.close();
          std::ofstream file16("histSlog2.json");
          dump_bh(file16, histSlog2);
Andre Schmidt's avatar
Andre Schmidt committed
          file16.close(); //hier ende
Andre Schmidt's avatar
Andre Schmidt committed
          std::ofstream file17("histLlog2int.json");
          dump_bh(file17, histLlog2int);
          file17.close();
          std::ofstream file18("histLlog2dec.json");
          dump_bh(file18, histLlog2dec);
          file18.close();
          
          std::ofstream file20("histLlog2mag.json");
          dump_bh(file20, histLlog2mag);
          file20.close();
          std::ofstream file21("histLlog2geo.json");
          dump_bh(file21, histLlog2geo);
          file21.close();
          std::ofstream file22("histLlog2max.json");
          dump_bh(file22, histLlog2max);
          file22.close();
          
          std::ofstream filepi1("histLpi2int.json");
          dump_bh(filepi1, histLpi2int);
          filepi1.close();
          std::ofstream filepi2("histLpi2dec.json");
          dump_bh(filepi2, histLpi2dec);
          filepi2.close();
          std::ofstream filepi3("histLpi2mag.json");
          dump_bh(filepi3, histLpi2mag);
          filepi3.close();
          std::ofstream filepi4("histLpi2geo.json");
          dump_bh(filepi4, histLpi2geo);
          filepi4.close();
          std::ofstream filepi5("histLpi2max.json");
          dump_bh(filepi5, histLpi2max);
          filepi5.close();
          
          std::ofstream filemu1("histLmu2int.json");
          dump_bh(filemu1, histLmu2int);
          filemu1.close();
          std::ofstream filemu2("histLmu2dec.json");
          dump_bh(filemu2, histLmu2dec);
          filemu2.close();
          std::ofstream filemu3("histLmu2mag.json");
          dump_bh(filemu3, histLmu2mag);
          filemu3.close();
          std::ofstream filemu4("histLmu2geo.json");
          dump_bh(filemu4, histLmu2geo);
          filemu4.close();
          std::ofstream filemu5("histLmu2max.json");
          dump_bh(filemu5, histLmu2max);
Andre Schmidt's avatar
Andre Schmidt committed
          filemu5.close();*/
Andre Schmidt's avatar
Andre Schmidt committed
		  
		  };

    /**
     * set the nodes for all particles on the stack according to their numerical
     * position
     */
    void SetNodes() {
      std::for_each(fStack.begin(), fStack.end(), [&](auto& p) {
        auto const* numericalNode =
            fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
        p.SetNode(numericalNode);
      });
    }

ralfulrich's avatar
ralfulrich committed
    /**
     * The Run function is the main simulation loop, which processes
     * particles from the Stack until the Stack is empty.
     */
      setNodes();
      while (!stack_.IsEmpty()) {
        while (!stack_.IsEmpty()) {
          C8LOG_TRACE("Stack: {}", stack_.as_string());
          auto pNext = stack_.GetNextParticle();
          C8LOG_DEBUG(
ralfulrich's avatar
ralfulrich committed
              "============== next particle : count={}, pid={}, "
              ", stack entries={}"
              ", stack deleted={}",
              count_, pNext.GetPID(), stack_.getEntries(), stack_.getDeleted());
        }
        // do cascade equations, which can put new particles on Stack,
        // thus, the double loop
ralfulrich's avatar
ralfulrich committed
        // DoCascadeEquations();
    /**
     * Force an interaction of the top particle of the stack at its current position.
     * Note that SetNodes() or an equivalent procedure needs to be called first if you
     * want to call forceInteraction() for the primary interaction.
     */
    void forceInteraction() {
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG("forced interaction!");
      setNodes();
      TStackView secondaries(vParticle);
      interaction(secondaries);
      process_sequence_.DoSecondaries(secondaries);
      vParticle.Delete(); // primary particle has interacted and is gone
ralfulrich's avatar
ralfulrich committed
  private:
ralfulrich's avatar
ralfulrich committed
    /**
     * The Step function is executed for each particle from the
     * stack. It will calcualte geometric transport of the particles,
     * and apply continuous and stochastic processes to it, which may
     * lead to energy losses, scattering, absorption, decays and the
     * production of secondary particles.
     *
     * New particles produced in one step are subject to further
     * processing, e.g. thinning, etc.
     */
ralfulrich's avatar
ralfulrich committed
    void Step(Particle& vParticle) {
      using namespace corsika;
ralfulrich's avatar
ralfulrich committed
      using namespace corsika::units::si;
      // determine geometric tracking
      auto [step, geomMaxLength, nextVol] = tracking_.GetTrack(vParticle);
      [[maybe_unused]] auto const& dummy_nextVol = nextVol;

      // determine combined total interaction length (inverse)
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
      InverseGrammageType const total_inv_lambda =
          process_sequence_.GetInverseInteractionLength(vParticle);
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
      // sample random exponential step length in grammage
      corsika::random::ExponentialDistribution expDist(1 / total_inv_lambda);
      GrammageType const next_interact = expDist(rng_);
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG(
          "total_lambda={} g/cm2, "
          ", next_interact={} g/cm2",
          double((1. / total_inv_lambda) / 1_g * 1_cm * 1_cm),
          double(next_interact / 1_g * 1_cm * 1_cm));
      auto const* currentLogicalNode = vParticle.GetNode();
      // assert that particle stays outside void Universe if it has no
      // model properties set
      assert(currentLogicalNode != &*environment_.GetUniverse() ||
             environment_.GetUniverse()->HasModelProperties());
      // determine combined total inverse decay time
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
      InverseTimeType const total_inv_lifetime =
          process_sequence_.GetInverseLifetime(vParticle);
      // sample random exponential decay time
      corsika::random::ExponentialDistribution expDistDecay(1 / total_inv_lifetime);
      TimeType const next_decay = expDistDecay(rng_);
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG(
          "total_lifetime={} s"
          ", next_decay={} s",
          (1 / total_inv_lifetime) / 1_s, next_decay / 1_s);

      // convert next_decay from time to length [m]
ralfulrich's avatar
ralfulrich committed
      LengthType const distance_decay = next_decay * vParticle.GetMomentum().norm() /
                                        vParticle.GetEnergy() * units::constants::c;
André Schmidt's avatar
André Schmidt committed
      // determine geometric tracking
Andre Schmidt's avatar
Andre Schmidt committed
      auto [step, geomMaxLength, magMaxLength, nextVol] = fTracking.GetTrack(vParticle);
André Schmidt's avatar
André Schmidt committed
      [[maybe_unused]] auto const& dummy_nextVol = nextVol;
André Schmidt's avatar
André Schmidt committed
      // convert next_step from grammage to length
      LengthType const distance_interact =
Andre Schmidt's avatar
Andre Schmidt committed
          currentLogicalNode->GetModelProperties().ArclengthFromGrammage(step,
André Schmidt's avatar
André Schmidt committed
                                                                         next_interact);
André Schmidt's avatar
André Schmidt committed
      // determine the maximum geometric step length
Andre Schmidt's avatar
Andre Schmidt committed
      LengthType const distance_max = fProcessSequence.MaxStepLength(vParticle, stepWithoutB);
      C8LOG_DEBUG("distance_max={} m", distance_max / 1_m);
Andre Schmidt's avatar
Andre Schmidt committed
      // take minimum of geometry, interaction, decay for next step
Andre Schmidt's avatar
Andre Schmidt committed
      auto min_distance = std::min(
Andre Schmidt's avatar
Andre Schmidt committed
          {distance_interact, distance_decay, distance_max, geomMaxLength, magMaxLength});

      C8LOG_DEBUG("transport particle by : {} m "
		  "Max Displacement after: {} m "
		  "Medium transition after: {} m "
		  "Decay after: {} m "
		  "Interaction after: {} m", 
		  min_distance/1_m, magMaxLength/1_m, geomMaxLength/1_m, distance_decay/1_m, distance_interact/1_m);

Andre Schmidt's avatar
Andre Schmidt committed
      // determine steplength for the magnetic field
      // because Steplength should not be min_distance
Andre Schmidt's avatar
Andre Schmidt committed
      /*
      int chargeNumber;
	    if (corsika::particles::IsNucleus(vParticle.GetPID())) {
	      chargeNumber = vParticle.GetNuclearZ();
	    } else {
	      chargeNumber = corsika::particles::GetChargeNumber(vParticle.GetPID());
	    }
	    auto const* currentLogicalVolumeNode = vParticle.GetNode();
	    auto magneticfield = currentLogicalVolumeNode->GetModelProperties().GetMagneticField(vParticle.GetPosition());
Andre Schmidt's avatar
Andre Schmidt committed
      geometry::Vector<dimensionless_d> const directionBefore = vParticle.GetMomentum().normalized();
	    auto c = directionBefore.cross(magneticfield) * chargeNumber * corsika::units::constants::c * 1_eV / 
               (vParticle.GetMomentum().norm() * 1_V)
Andre Schmidt's avatar
Andre Schmidt committed
	    LengthType Steplength = min_distance;
	    if (chargeNumber != 0) {
Andre Schmidt's avatar
Andre Schmidt committed
	      Steplength = sqrt(2 / c.squaredNorm() * (sqrt(c.squaredNorm() * min_distance * min_distance + 1) -1));
        std::cout << "Steplength " << Steplength << std::endl;
Andre Schmidt's avatar
Andre Schmidt committed
	    // This formula hasnt been tested
Andre Schmidt's avatar
Andre Schmidt committed
      auto [position, direction, L2] = fTracking.MagneticStep(vParticle, min_distance);
      //histL2(L2);
Andre Schmidt's avatar
Andre Schmidt committed
      histLlog2(L2);
      int pdg = static_cast<int>(particles::GetPDG(vParticle.GetPID()));
      if (min_distance == distance_interact){
Andre Schmidt's avatar
Andre Schmidt committed
        histLlog2int(L2);
        if (abs(pdg) == 13)
              histLmu2int(L2);
      
        if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2int(L2);
      }
      if (min_distance == distance_decay) {
Andre Schmidt's avatar
Andre Schmidt committed
        histLlog2dec(L2);
        if (abs(pdg) == 13)
              histLmu2dec(L2);
        if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2dec(L2);
      }
      if (min_distance == distance_max) {
Andre Schmidt's avatar
Andre Schmidt committed
        histLlog2max(L2);
        if (abs(pdg) == 13)
              histLmu2max(L2);
        if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2max(L2);
      }
      if (min_distance == geomMaxLength) {
Andre Schmidt's avatar
Andre Schmidt committed
        histLlog2geo(L2);
        if (abs(pdg) == 13)
              histLmu2geo(L2);
        if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2geo(L2);
      }
Andre Schmidt's avatar
Andre Schmidt committed
      if (min_distance == magMaxLength) {
        histLlog2mag(L2);
        if (abs(pdg) == 13)
              histLmu2mag(L2);
        if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2mag(L2);
Andre Schmidt's avatar
Andre Schmidt committed
      }
Andre Schmidt's avatar
Andre Schmidt committed
            if (abs(pdg) == 13)
              histLmu2(L2);
Andre Schmidt's avatar
Andre Schmidt committed
            if (abs(pdg) == 11)
              histLe2(L2);
            if (abs(pdg) == 22)
              histLy2(L2);
Andre Schmidt's avatar
Andre Schmidt committed
            if (abs(pdg) == 211 || abs(pdg) == 111)
              histLpi2(L2);
            if (abs(pdg) == 2212 || abs(pdg) == 2112)
              histLp2(L2);
Andre Schmidt's avatar
Andre Schmidt committed
              
              
              
     int chargeNumber = 0;
        if (corsika::particles::IsNucleus(vParticle.GetPID())) {
        	chargeNumber = vParticle.GetNuclearZ();
        } else {
        	chargeNumber = corsika::particles::GetChargeNumber(vParticle.GetPID());
        }
     if(chargeNumber != 0) {
     auto const* currentLogicalVolumeNode = vParticle.GetNode();
     auto magneticfield = currentLogicalVolumeNode->GetModelProperties().GetMagneticField(vParticle.GetPosition());
             geometry::Vector<SpeedType::dimension_type> velocity =
            vParticle.GetMomentum() / vParticle.GetEnergy() * corsika::units::constants::c;
              geometry::Vector<SpeedType::dimension_type> const velocityVerticalMag = velocity -
                   velocity.parallelProjectionOnto(magneticfield);
              LengthType const gyroradius = vParticle.GetEnergy() * velocityVerticalMag.GetNorm() * 1_V / 
                                            (corsika::units::constants::cSquared * abs(chargeNumber) * 
                                            magneticfield.GetNorm() * 1_eV);
     stepradius = stepradius + min_distance/gyroradius;
     N ++;
     if (abs(pdg) == 13) {
       stepradiusmu += min_distance/gyroradius;
       Nmu ++;
     }
     if (abs(pdg) == 211 || abs(pdg) == 111) {
       stepradiuspi += min_distance/gyroradius;
       Npi ++;
     }
     if (abs(pdg) == 2212 || abs(pdg) == 2112) {
       stepradiusp += min_distance/gyroradius;
       Np ++;
     }
     }         
              
              
Andre Schmidt's avatar
Andre Schmidt committed
      auto distance = position - vParticle.GetPosition();
Andre Schmidt's avatar
Andre Schmidt committed
      
      //Building Trajectory for Continuous processes
      //could also be done in MagneticStep
Andre Schmidt's avatar
Andre Schmidt committed
      geometry::Vector<SpeedType::dimension_type> velocity =
            vParticle.GetMomentum() / vParticle.GetEnergy() * corsika::units::constants::c;
      if (distance.norm() != 0_m) {
        velocity = distance.normalized() * velocity.norm();
      }
      geometry::Line line(vParticle.GetPosition(), velocity);
      geometry::Trajectory<geometry::Line> stepNew(line, distance.norm() / line.GetV0().norm());
Andre Schmidt's avatar
Andre Schmidt committed
      
      // here the particle is actually moved along the trajectory to new position:
      // std::visit(setup::ParticleUpdate<Particle>{vParticle}, step);
Andre Schmidt's avatar
Andre Schmidt committed
      vParticle.SetMomentum(direction * vParticle.GetMomentum().norm());
Andre Schmidt's avatar
Andre Schmidt committed
      vParticle.SetPosition(position);
      vParticle.SetTime(vParticle.GetTime() + distance.norm() / velocity.norm());
Andre Schmidt's avatar
Andre Schmidt committed
      std::cout << "New Position: " << vParticle.GetPosition().GetCoordinates() << std::endl;
      // apply all continuous processes on particle + track
Andre Schmidt's avatar
Andre Schmidt committed
      process::EProcessReturn status = fProcessSequence.DoContinuous(vParticle, stepNew);
Andre Schmidt's avatar
Andre Schmidt committed

      if (status == process::EProcessReturn::eParticleAbsorbed) {
ralfulrich's avatar
ralfulrich committed
        C8LOG_DEBUG("Cascade: delete absorbed particle PID={} E={} GeV",
                    vParticle.GetPID(), vParticle.GetEnergy() / 1_GeV);
        if (!vParticle.isDeleted()) vParticle.Delete();
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG("sth. happening before geometric limit ? {}",
                  ((min_distance < geomMaxLength) ? "yes" : "no"));
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
      if (min_distance < geomMaxLength) { // interaction to happen within geometric limit

        // check whether decay or interaction limits this step the
        // outcome of decay or interaction MAY be a) new particles in
        // secondaries, b) the projectile particle deleted (or
        // changed)

        TStackView secondaries(vParticle);

Andre Schmidt's avatar
Andre Schmidt committed
        if (min_distance != distance_max && min_distance != magMaxLength) {
          /*
            Create SecondaryView object on Stack. The data container
            remains untouched and identical, and 'projectil' is identical
            to 'vParticle' above this line. However,
            projectil.AddSecondaries populate the SecondaryView, which can
            then be used afterwards for further processing. Thus: it is
ralfulrich's avatar
ralfulrich committed
            important to use projectle/view (and not vParticle) for Interaction,
            and Decay!
          */

          [[maybe_unused]] auto projectile = secondaries.GetProjectile();

          if (min_distance == distance_interact) {
          } else {
            assert(min_distance == distance_decay);
ralfulrich's avatar
ralfulrich committed
            // make sure particle actually did decay if it should have done so
            if (secondaries.getSize() == 1 &&
ralfulrich's avatar
ralfulrich committed
                projectile.GetPID() == secondaries.GetNextParticle().GetPID())
              throw std::runtime_error(
                  fmt::format("Cascade: {} decayed into itself!",
                              particles::GetName(projectile.GetPID())));
ralfulrich's avatar
ralfulrich committed
          vParticle.Delete();
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
        } else { // step-length limitation within volume
ralfulrich's avatar
ralfulrich committed
          C8LOG_DEBUG("step-length limitation");
          // no extra physics happens here. just proceed to next step.
        [[maybe_unused]] auto const assertion = [&] {
          auto const* numericalNodeAfterStep =
              environment_.GetUniverse()->GetContainingNode(vParticle.GetPosition());
          C8LOG_TRACE("Geometry check: numericalNodeAfterStep={} currentLogicalNode={}",
                      fmt::ptr(numericalNodeAfterStep), fmt::ptr(currentLogicalNode));
          return numericalNodeAfterStep == currentLogicalNode;
        };
        assert(assertion()); // numerical and logical nodes don't match
ralfulrich's avatar
ralfulrich committed
      } else {               // boundary crossing, step is limited by volume boundary
        /*
          DoBoundary may delete the particle (or not)

          caveat: any changes to vParticle, or even the production
          of new secondaries is currently not passed to ParticleCut,
          thus, particles outside the desired phase space may be produced.
        process_sequence_.DoBoundaryCrossing(vParticle, *currentLogicalNode, *nextVol);
ralfulrich's avatar
ralfulrich committed

    process::EProcessReturn decay(TStackView& view) {
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG("decay");
      units::si::InverseTimeType const actual_decay_time =
          process_sequence_.GetInverseLifetime(view.parent());

      random::UniformRealDistribution<units::si::InverseTimeType> uniDist(
          actual_decay_time);
      const auto sample_process = uniDist(rng_);
      auto const returnCode = process_sequence_.SelectDecay(view, sample_process);
      if (returnCode != process::EProcessReturn::eDecayed) {
        C8LOG_WARN("Particle did not decay!");
      }
      SetEventType(view, history::EventType::Decay);
      return returnCode;
    process::EProcessReturn interaction(TStackView& view) {
ralfulrich's avatar
ralfulrich committed
      C8LOG_DEBUG("collide");

      units::si::InverseGrammageType const current_inv_length =
          process_sequence_.GetInverseInteractionLength(view.parent());

      random::UniformRealDistribution<units::si::InverseGrammageType> uniDist(
          current_inv_length);
      const auto sample_process = uniDist(rng_);
      auto const returnCode = process_sequence_.SelectInteraction(view, sample_process);
      if (returnCode != process::EProcessReturn::eInteracted) {
        C8LOG_WARN("Particle did not interace!");
      }
      SetEventType(view, history::EventType::Interaction);
      return returnCode;
    }

    /**
     * set the nodes for all particles on the stack according to their numerical
     * position
     */
    void setNodes() {
      std::for_each(stack_.begin(), stack_.end(), [&](auto& p) {
        auto const* numericalNode =
            environment_.GetUniverse()->GetContainingNode(p.GetPosition());
        p.SetNode(numericalNode);
      });
    }

    void SetEventType(TStackView& view, [[maybe_unused]] history::EventType eventType) {
      if constexpr (TStackView::has_event) {
        for (auto&& sec : view) { sec.GetEvent()->setEventType(eventType); }
ralfulrich's avatar
ralfulrich committed
    // but this here temporarily. Should go into dedicated file later:
ralfulrich's avatar
ralfulrich committed
  ,ad8888ba,     ,ad8888ba,    88888888ba    ad88888ba   88  88      a8P          db              ad88888ba   
 d8"'    `"8b   d8"'    `"8b   88      "8b  d8"     "8b  88  88    ,88'          d88b            d8"     "8b  
d8'            d8'        `8b  88      ,8P  Y8,          88  88  ,88"           d8'`8b           Y8a     a8P  
88             88          88  88aaaaaa8P'  `Y8aaaaa,    88  88,d88'           d8'  `8b           "Y8aaa8P"   
88             88          88  88""""88'      `"""""8b,  88  8888"88,         d8YaaaaY8b          ,d8"""8b,   
Y8,            Y8,        ,8P  88    `8b            `8b  88  88P   Y8b       d8""""""""8b        d8"     "8b  
 Y8a.    .a8P   Y8a.    .a8P   88     `8b   Y8a     a8P  88  88     "88,    d8'        `8b       Y8a     a8P  
  `"Y8888Y"'     `"Y8888Y"'    88      `8b   "Y88888P"   88  88       Y8b  d8'          `8b       "Y88888P"
	)V0G0N";
} // namespace corsika::cascade