IAP GITLAB

Skip to content
Snippets Groups Projects
cascade_example.cc 10.7 KiB
Newer Older
 * (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/cascade/Cascade.h>
#include <corsika/process/ProcessSequence.h>
#include <corsika/process/hadronic_elastic_model/HadronicElasticModel.h>
#include <corsika/process/stack_inspector/StackInspector.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/process/tracking_line/TrackingLine.h>

#include <corsika/setup/SetupStack.h>
#include <corsika/setup/SetupTrajectory.h>

#include <corsika/environment/Environment.h>
#include <corsika/environment/HomogeneousMedium.h>
#include <corsika/environment/NuclearComposition.h>
#include <corsika/geometry/Sphere.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/process/sibyll/Decay.h>
#include <corsika/process/sibyll/Interaction.h>
#include <corsika/process/sibyll/NuclearInteraction.h>
#include <corsika/process/track_writer/TrackWriter.h>

#include <corsika/units/PhysicalUnits.h>
#include <corsika/random/RNGManager.h>

#include <corsika/utl/CorsikaFenv.h>

#include <iostream>
#include <limits>
#include <typeinfo>

using namespace corsika;
using namespace corsika::process;
using namespace corsika::units;
using namespace corsika::particles;
using namespace corsika::random;
using namespace corsika::geometry;
using namespace corsika::environment;

using namespace std;
using namespace corsika::units::si;
class ProcessCut : public process::ContinuousProcess<ProcessCut> {
ralfulrich's avatar
ralfulrich committed

  HEPEnergyType fEnergy = 0_GeV;
  HEPEnergyType fEmEnergy = 0_GeV;
  HEPEnergyType fInvEnergy = 0_GeV;
ralfulrich's avatar
ralfulrich committed

Felix Riehn's avatar
Felix Riehn committed
public:
  ProcessCut(const HEPEnergyType cut)
      : fECut(cut) {}

Felix Riehn's avatar
Felix Riehn committed
  template <typename Particle>
Felix Riehn's avatar
Felix Riehn committed
  bool isBelowEnergyCut(Particle& p) const {
    if (p.GetPID() == particles::Code::Nucleus) {
      auto const ElabNuc = p.GetEnergy() / p.GetNuclearA();
      auto const EcmNN = sqrt(2. * ElabNuc * 0.93827_GeV);
      if (ElabNuc < fECut || EcmNN < 10_GeV)
        return true;
      else
        return false;
    } else {
      // TODO: center-of-mass energy hard coded
      const HEPEnergyType Ecm = sqrt(2. * p.GetEnergy() * 0.93827_GeV);
      if (p.GetEnergy() < fECut || Ecm < 10_GeV)
        return true;
      else
        return false;
    }
Felix Riehn's avatar
Felix Riehn committed
  bool isEmParticle(Code pCode) const {
Felix Riehn's avatar
Felix Riehn committed
    bool is_em = false;
    // FOR NOW: switch
Felix Riehn's avatar
Felix Riehn committed
    switch (pCode) {
      case Code::Electron:
        is_em = true;
        break;
Felix Riehn's avatar
Felix Riehn committed
      case Code::Gamma:
        is_em = true;
        break;
      default:
        break;
Felix Riehn's avatar
Felix Riehn committed
    }
    return is_em;
  }

Felix Riehn's avatar
Felix Riehn committed
  void defineEmParticles() const {
    // create bool array identifying em particles
Felix Riehn's avatar
Felix Riehn committed
  bool isInvisible(Code pCode) const {
Felix Riehn's avatar
Felix Riehn committed
    bool is_inv = false;
    // FOR NOW: switch
Felix Riehn's avatar
Felix Riehn committed
    switch (pCode) {
      case Code::NuE:
        is_inv = true;
        break;
      case Code::NuEBar:
        is_inv = true;
        break;
      case Code::NuMu:
        is_inv = true;
        break;
      case Code::NuMuBar:
        is_inv = true;
        break;
      case Code::MuPlus:
        is_inv = true;
        break;
      case Code::MuMinus:
        is_inv = true;
        break;

      case Code::Neutron:
        is_inv = true;
        break;

      case Code::AntiNeutron:
        is_inv = true;
        break;

Felix Riehn's avatar
Felix Riehn committed
      default:
        break;
Felix Riehn's avatar
Felix Riehn committed
    }
    return is_inv;
  }

  template <typename Particle>
  LengthType MaxStepLength(Particle& p, setup::Trajectory&) const {
ralfulrich's avatar
ralfulrich committed
    cout << "ProcessCut: MinStep: pid: " << p.GetPID() << endl;
    cout << "ProcessCut: MinStep: energy (GeV): " << p.GetEnergy() / 1_GeV << endl;
Felix Riehn's avatar
Felix Riehn committed
    const Code pid = p.GetPID();
ralfulrich's avatar
ralfulrich committed
    if (isEmParticle(pid) || isInvisible(pid) || isBelowEnergyCut(p)) {
Felix Riehn's avatar
Felix Riehn committed
      cout << "ProcessCut: MinStep: next cut: " << 0. << endl;
Felix Riehn's avatar
Felix Riehn committed
    } else {
      LengthType next_step = 1_m * std::numeric_limits<double>::infinity();
Felix Riehn's avatar
Felix Riehn committed
      cout << "ProcessCut: MinStep: next cut: " << next_step << endl;
      return next_step;
    }
  }

  template <typename Particle, typename Stack>
  EProcessReturn DoContinuous(Particle& p, setup::Trajectory&, Stack&) {
    HEPEnergyType energy = p.GetEnergy();
ralfulrich's avatar
ralfulrich committed
    cout << "ProcessCut: DoContinuous: " << pid << " E= " << energy
         << ", EcutTot=" << (fEmEnergy + fInvEnergy + fEnergy) / 1_GeV << " GeV" << endl;
ralfulrich's avatar
ralfulrich committed
    EProcessReturn ret = EProcessReturn::eOk;
    if (isEmParticle(pid)) {
      cout << "removing em. particle..." << endl;
ralfulrich's avatar
ralfulrich committed
      ret = EProcessReturn::eParticleAbsorbed;
    } else if (isInvisible(pid)) {
      cout << "removing inv. particle..." << endl;
ralfulrich's avatar
ralfulrich committed
      ret = EProcessReturn::eParticleAbsorbed;
    } else if (isBelowEnergyCut(p)) {
      cout << "removing low en. particle..." << endl;
ralfulrich's avatar
ralfulrich committed
      ret = EProcessReturn::eParticleAbsorbed;
ralfulrich's avatar
ralfulrich committed
    return ret;
Felix Riehn's avatar
Felix Riehn committed
  void Init() {
    fEmEnergy = 0. * 1_GeV;
    fEmCount = 0;
Felix Riehn's avatar
Felix Riehn committed
    fInvEnergy = 0. * 1_GeV;
Felix Riehn's avatar
Felix Riehn committed
    fInvCount = 0;
    fEnergy = 0. * 1_GeV;
    // defineEmParticles();
Felix Riehn's avatar
Felix Riehn committed
  void ShowResults() {
Felix Riehn's avatar
Felix Riehn committed
    cout << " ******************************" << endl
Felix Riehn's avatar
Felix Riehn committed
         << " ParticleCut: " << endl
         << " energy in em.  component (GeV):  " << fEmEnergy / 1_GeV << endl
         << " no. of em.  particles injected:  " << fEmCount << endl
         << " energy in inv. component (GeV):  " << fInvEnergy / 1_GeV << endl
         << " no. of inv. particles injected:  " << fInvCount << endl
         << " energy below particle cut (GeV): " << fEnergy / 1_GeV << endl
Felix Riehn's avatar
Felix Riehn committed
         << " ******************************" << endl;
  HEPEnergyType GetInvEnergy() const { return fInvEnergy; }
  HEPEnergyType GetCutEnergy() const { return fEnergy; }
  HEPEnergyType GetEmEnergy() const { return fEmEnergy; }
struct MyBoundaryCrossingProcess
    : public BoundaryCrossingProcess<MyBoundaryCrossingProcess> {
  template <typename Particle>
  EProcessReturn DoBoundaryCrossing(Particle&, environment::BaseNodeType const& from,
                                    environment::BaseNodeType const& to) {
    std::cout << "boundary crossing! from:" << &from << "; to: " << &to << std::endl;
    return EProcessReturn::eOk;
  }

  void Init() {}
};

//
// The example main program for a particle cascade
//
ralfulrich's avatar
ralfulrich committed
int main() {
  feenableexcept(FE_INVALID);
  // initialize random number sequence(s)
  random::RNGManager::GetInstance().RegisterRandomStream("cascade");
  environment::Environment env;
  auto& universe = *(env.GetUniverse());
  auto outerMedium = environment::Environment::CreateNode<Sphere>(
      Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
      1_km * std::numeric_limits<double>::infinity());

  // fraction of oxygen
  const float fox = 0.20946;
  using MyHomogeneousModel = environment::HomogeneousMedium<environment::IMediumModel>;
  outerMedium->SetModelProperties<MyHomogeneousModel>(
      environment::NuclearComposition(
          std::vector<particles::Code>{particles::Code::Nitrogen,
                                       particles::Code::Oxygen},
Felix Riehn's avatar
Felix Riehn committed
          std::vector<float>{(float)1. - fox, fox}));
  auto innerMedium = environment::Environment::CreateNode<Sphere>(
      Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m}, 10_m);

  innerMedium->SetModelProperties<MyHomogeneousModel>(
      1_kg / (1_m * 1_m * 1_m),
      environment::NuclearComposition(
          std::vector<particles::Code>{particles::Code::Nitrogen,
                                       particles::Code::Oxygen},
          std::vector<float>{(float)1. - fox, fox}));

  outerMedium->AddChild(std::move(innerMedium));

  universe.AddChild(std::move(outerMedium));
  const CoordinateSystem& rootCS = env.GetCoordinateSystem();
Felix Riehn's avatar
Felix Riehn committed

  // setup processes, decays and interactions
ralfulrich's avatar
ralfulrich committed
  tracking_line::TrackingLine<setup::Stack, setup::Trajectory> tracking(env);
ralfulrich's avatar
ralfulrich committed
  stack_inspector::StackInspector<setup::Stack> p0(true);
ralfulrich's avatar
ralfulrich committed

  random::RNGManager::GetInstance().RegisterRandomStream("s_rndm");
  process::sibyll::Interaction sibyll(env);
  process::sibyll::NuclearInteraction sibyllNuc(env, sibyll);
  process::sibyll::Decay decay;
  random::RNGManager::GetInstance().RegisterRandomStream("HadronicElasticModel");
  process::HadronicElasticModel::HadronicElasticInteraction hadronicElastic(env);
  process::TrackWriter::TrackWriter trackWriter("tracks.dat");

  // assemble all processes into an ordered process list
Felix Riehn's avatar
Felix Riehn committed
  // auto sequence = p0 << sibyll << decay << hadronicElastic << cut << trackWriter;
  auto sequence = p0 << sibyll << sibyllNuc << decay << cut << MyBoundaryCrossingProcess()
                     << trackWriter;
Felix Riehn's avatar
Felix Riehn committed

  // setup particle stack, and add primary particle
  setup::Stack stack;
  const Code beamCode = Code::Nucleus;
  const int nuclA = 56;
  const int nuclZ = int(nuclA / 2.15 + 0.7);
  const HEPMassType mass = particles::Proton::GetMass() * nuclZ +
                           (nuclA - nuclZ) * particles::Neutron::GetMass();
  const HEPEnergyType E0 = nuclA * 100_GeV;
  double theta = 27.234;
ralfulrich's avatar
ralfulrich committed
  double phi = 0.;
Felix Riehn's avatar
Felix Riehn committed

Felix Riehn's avatar
Felix Riehn committed
    auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) {
      return sqrt(Elab * Elab - m * m);
    };
    HEPMomentumType P0 = elab2plab(E0, mass);
    auto momentumComponents = [](double theta, double phi, HEPMomentumType ptot) {
      return std::make_tuple(ptot * sin(theta) * cos(phi), ptot * sin(theta) * sin(phi),
ralfulrich's avatar
ralfulrich committed
                             -ptot * cos(theta));
    };
    auto const [px, py, pz] =
        momentumComponents(theta / 180. * M_PI, phi / 180. * M_PI, P0);
    auto plab = corsika::stack::MomentumVector(rootCS, {px, py, pz});
    cout << "input particle: " << beamCode << endl;
    cout << "input angles: theta=" << theta << " phi=" << phi << endl;
    cout << "input momentum: " << plab.GetComponents() / 1_GeV << endl;
ralfulrich's avatar
ralfulrich committed
    Point pos(rootCS, 0_m, 0_m, 0_m);
    stack.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
                                 corsika::stack::MomentumVector, geometry::Point,
                                 units::si::TimeType, unsigned short, unsigned short>{
        beamCode, E0, plab, pos, 0_ns, nuclA, nuclZ});
  // define air shower object, run simulation
  cascade::Cascade EAS(env, tracking, sequence, stack);
  EAS.Init();
  EAS.Run();

  cout << "Result: E0=" << E0 / 1_GeV << endl;
Felix Riehn's avatar
Felix Riehn committed
  const HEPEnergyType Efinal =
      cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy();
  cout << "total energy (GeV): " << Efinal / 1_GeV << endl
       << "relative difference (%): " << (Efinal / E0 - 1.) * 100 << endl;