IAP GITLAB

Skip to content
Snippets Groups Projects
hybrid_MC.cpp 10.4 KiB
Newer Older
ralfulrich's avatar
ralfulrich committed
/*
 * (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.
 */

/* clang-format off */
// InteractionCounter used boost/histogram, which
// fails if boost/type_traits have been included before. Thus, we have
// to include it first...
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/process/InteractionCounter.hpp>
ralfulrich's avatar
ralfulrich committed
/* clang-format on */
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/process/ProcessSequence.hpp>
#include <corsika/framework/process/SwitchProcessSequence.hpp>
#include <corsika/framework/process/InteractionCounter.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/geometry/Plane.hpp>
#include <corsika/framework/geometry/Sphere.hpp>
#include <corsika/framework/geometry/PhysicalGeometry.hpp>
#include <corsika/framework/utility/SaveBoostHistogram.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/utility/CorsikaFenv.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/core/Logging.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/core/Cascade.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/framework/core/EnergyMomentumOperations.hpp>
#include <corsika/framework/random/RNGManager.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/output/OutputManager.hpp>

ralfulrich's avatar
ralfulrich committed
#include <corsika/media/Environment.hpp>
#include <corsika/media/FlatExponential.hpp>
#include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp>
#include <corsika/media/NuclearComposition.hpp>
#include <corsika/media/MediumPropertyModel.hpp>
#include <corsika/media/UniformMagneticField.hpp>
#include <corsika/media/ShowerAxis.hpp>
ralfulrich's avatar
ralfulrich committed
#include <corsika/media/CORSIKA7Atmospheres.hpp>
ralfulrich's avatar
ralfulrich committed

#include <corsika/modules/BetheBlochPDG.hpp>
#include <corsika/modules/LongitudinalProfile.hpp>
#include <corsika/modules/ObservationPlane.hpp>
#include <corsika/modules/OnShellCheck.hpp>
#include <corsika/modules/ParticleCut.hpp>
#include <corsika/modules/Pythia8.hpp>
#include <corsika/modules/Sibyll.hpp>
#include <corsika/modules/UrQMD.hpp>
#include <corsika/modules/PROPOSAL.hpp>
#include <corsika/modules/CONEX.hpp>

#include <corsika/setup/SetupStack.hpp>
#include <corsika/setup/SetupTrajectory.hpp>
ralfulrich's avatar
ralfulrich committed

#include <iomanip>
#include <iostream>
#include <limits>
#include <string>

ralfulrich's avatar
ralfulrich committed
/*
  NOTE, WARNING, ATTENTION
ralfulrich's avatar
ralfulrich committed

  The file Random.hpp implements the hooks of external modules to the C8 random
ralfulrich's avatar
ralfulrich committed
  number generator. It has to occur excatly ONCE per linked
  executable. If you include the header below multiple times and
  link this togehter, it will fail.
 */
#include <corsika/modules/Random.hpp>
ralfulrich's avatar
ralfulrich committed

using namespace corsika;
ralfulrich's avatar
ralfulrich committed
using namespace std;

ralfulrich's avatar
ralfulrich committed
void registerRandomStreams(uint64_t seed) {
  RNGManager<>::getInstance().registerRandomStream("cascade");
  RNGManager<>::getInstance().registerRandomStream("qgsjet");
  RNGManager<>::getInstance().registerRandomStream("sibyll");
ralfulrich's avatar
ralfulrich committed
  RNGManager<>::getInstance().registerRandomStream("epos");
  RNGManager<>::getInstance().registerRandomStream("pythia");
  RNGManager<>::getInstance().registerRandomStream("urqmd");
  RNGManager<>::getInstance().registerRandomStream("proposal");
ralfulrich's avatar
ralfulrich committed
  RNGManager<>::getInstance().registerRandomStream("conex");
  if (seed == 0) {
    std::random_device rd;
    seed = rd();
    cout << "new random seed (auto) " << seed << endl;
  }
  RNGManager<>::getInstance().setSeed(seed);
ralfulrich's avatar
ralfulrich committed
}

ralfulrich's avatar
ralfulrich committed
class TrackCheck : public ContinuousProcess<TrackCheck> {

public:
  TrackCheck(Plane const& plane)
      : plane_(plane) {}

  template <typename TParticle, typename TTrack>
  ProcessReturn doContinuous(TParticle const& particle, TTrack const&, bool const) {
    auto const delta = particle.getPosition() - plane_.getCenter();
ralfulrich's avatar
ralfulrich committed
    auto const n = plane_.getNormal();
    auto const proj = n.dot(delta);
    if (proj < -1_m) {
      CORSIKA_LOG_INFO("particle {} failes: proj={}, delta={}, p={}", particle.asString(),
                       proj, delta, particle.getPosition());
ralfulrich's avatar
ralfulrich committed
      throw std::runtime_error("particle below obs level");
    }
    return ProcessReturn::Ok;
  }

  template <typename TParticle, typename TTrack>
  LengthType getMaxStepLength(TParticle const&, TTrack const&) const {
    return std::numeric_limits<double>::infinity() * 1_m;
  }

private:
  Plane plane_;
};

ralfulrich's avatar
ralfulrich committed
template <typename T>
ralfulrich's avatar
ralfulrich committed
using MyExtraEnv = MediumPropertyModel<UniformMagneticField<T>>;
ralfulrich's avatar
ralfulrich committed

int main(int argc, char** argv) {

ralfulrich's avatar
ralfulrich committed
  logging::set_level(logging::level::info);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  CORSIKA_LOG_INFO("hybrid_MC");
ralfulrich's avatar
ralfulrich committed

  if (argc < 4) {
    std::cerr << "usage: hybrid_MC <A> <Z> <energy/GeV> [seed]" << std::endl;
    std::cerr << "       if no seed is given, a random seed is chosen" << std::endl;
    return 1;
  }
  feenableexcept(FE_INVALID);

  uint64_t seed = 0;
  if (argc > 4) seed = std::stol(std::string(argv[4]));
ralfulrich's avatar
ralfulrich committed
  // initialize random number sequence(s)
  registerRandomStreams(seed);

  // setup environment, geometry
  using EnvType = setup::Environment;
  EnvType env;
ralfulrich's avatar
ralfulrich committed
  CoordinateSystemPtr const& rootCS = env.getCoordinateSystem();
ralfulrich's avatar
ralfulrich committed
  Point const center{rootCS, 0_m, 0_m, 0_m};
ralfulrich's avatar
ralfulrich committed

  // build a Linsley US Standard atmosphere into `env`
  create_5layer_atmosphere<setup::EnvironmentInterface, MyExtraEnv>(
      env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm,
      MagneticFieldVector{rootCS, 0_T, 50_uT, 0_T});
ralfulrich's avatar
ralfulrich committed

  // setup particle stack, and add primary particle
  setup::Stack stack;
ralfulrich's avatar
ralfulrich committed
  stack.clear();
ralfulrich's avatar
ralfulrich committed
  unsigned short const A = std::stoi(std::string(argv[1]));
  unsigned short const Z = std::stoi(std::string(argv[2]));
  Code const beamCode = get_nucleus_code(A, Z);
ralfulrich's avatar
ralfulrich committed
  auto const mass = get_mass(beamCode);
  HEPEnergyType const E0 = 1_GeV * std::stof(std::string(argv[3]));
ralfulrich's avatar
ralfulrich committed
  auto const thetaRad = theta / 180. * M_PI;

  auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) {
    return sqrt((Elab - m) * (Elab + m));
  };
  HEPMomentumType P0 = elab2plab(E0, mass);
  auto momentumComponents = [](double thetaRad, HEPMomentumType ptot) {
    return std::make_tuple(ptot * sin(thetaRad), 0_eV, -ptot * cos(thetaRad));
  };

  auto const [px, py, pz] = momentumComponents(thetaRad, P0);
ralfulrich's avatar
ralfulrich committed
  auto plab = MomentumVector(rootCS, {px, py, pz});
ralfulrich's avatar
ralfulrich committed
  cout << "input particle: " << beamCode << endl;
  cout << "input angles: theta=" << theta << endl;
ralfulrich's avatar
ralfulrich committed
  cout << "input momentum: " << plab.getComponents() / 1_GeV
       << ", norm = " << plab.getNorm() << endl;
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  auto const observationHeight = 0_km + constants::EarthRadius::Mean;
  auto const injectionHeight = 112.75_km + constants::EarthRadius::Mean;
ralfulrich's avatar
ralfulrich committed
  auto const t = -observationHeight * cos(thetaRad) +
ralfulrich's avatar
ralfulrich committed
                 sqrt(-static_pow<2>(sin(thetaRad) * observationHeight) +
                      static_pow<2>(injectionHeight));
ralfulrich's avatar
ralfulrich committed
  Point const showerCore{rootCS, 0_m, 0_m, observationHeight};
  Point const injectionPos =
      showerCore +
      Vector<dimensionless_d>{rootCS, {-sin(thetaRad), 0, cos(thetaRad)}} * t;

ralfulrich's avatar
ralfulrich committed
  std::cout << "point of injection: " << injectionPos.getCoordinates() << std::endl;
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  stack.addParticle(std::make_tuple(
ralfulrich's avatar
ralfulrich committed
      Code::Proton, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)),
ralfulrich's avatar
ralfulrich committed
      plab.normalized(), injectionPos, 0_ns));
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  std::cout << "shower axis length: " << (showerCore - injectionPos).getNorm() * 1.02
ralfulrich's avatar
ralfulrich committed
            << std::endl;

ralfulrich's avatar
ralfulrich committed
  OutputManager output("hybrid_MC_outputs");
  ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.02, env, true,
                              1000};
ralfulrich's avatar
ralfulrich committed

  // setup processes, decays and interactions

ralfulrich's avatar
ralfulrich committed
  corsika::sibyll::Interaction sibyll;
  InteractionCounter sibyllCounted(sibyll);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  corsika::sibyll::NuclearInteraction sibyllNuc(sibyll, env);
  InteractionCounter sibyllNucCounted(sibyllNuc);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  corsika::pythia8::Decay decayPythia;
ralfulrich's avatar
ralfulrich committed

  // use sibyll decay routine for decays of particles unknown to pythia
ralfulrich's avatar
ralfulrich committed
  corsika::sibyll::Decay decaySibyll{{
ralfulrich's avatar
ralfulrich committed
      Code::N1440Plus,
      Code::N1440MinusBar,
      Code::N1440_0,
      Code::N1440_0Bar,
      Code::N1710Plus,
      Code::N1710MinusBar,
      Code::N1710_0,
      Code::N1710_0Bar,

      Code::Pi1300Plus,
      Code::Pi1300Minus,
      Code::Pi1300_0,

      Code::KStar0_1430_0,
      Code::KStar0_1430_0Bar,
      Code::KStar0_1430_Plus,
      Code::KStar0_1430_MinusBar,
  }};

ralfulrich's avatar
ralfulrich committed
  decaySibyll.printDecayConfig();
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  ParticleCut cut(3_GeV, false, true);
  BetheBlochPDG eLoss(showerAxis);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  CONEXhybrid conex_model(center, showerAxis, t, injectionHeight, E0,
                          get_PDG(Code::Proton));
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  OnShellCheck reset_particle_mass(1.e-3, 1.e-1, false);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  LongitudinalProfile longprof(showerAxis);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.}));
  ObservationPlane<setup::Tracking> observationLevel(
      obsPlane, DirectionVector(rootCS, {1., 0., 0.}), "particles.dat");
ralfulrich's avatar
ralfulrich committed
  output.add("obsplane", observationLevel);
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  corsika::urqmd::UrQMD urqmd_model;
  InteractionCounter urqmdCounted{urqmd_model};
ralfulrich's avatar
ralfulrich committed

  // assemble all processes into an ordered process list
  struct EnergySwitch {
    HEPEnergyType cutE_;
    EnergySwitch(HEPEnergyType cutE)
        : cutE_(cutE) {}
ralfulrich's avatar
ralfulrich committed
    bool operator()(const setup::Stack::particle_type& p) const {
      return (p.getEnergy() < cutE_);
ralfulrich's avatar
ralfulrich committed
    }
  };
  auto hadronSequence = make_select(EnergySwitch(55_GeV), urqmdCounted,
                                    make_sequence(sibyllNucCounted, sibyllCounted));
ralfulrich's avatar
ralfulrich committed
  auto decaySequence = make_sequence(decayPythia, decaySibyll);
  auto sequence = make_sequence(hadronSequence, reset_particle_mass, decaySequence, eLoss,
                                cut, conex_model, longprof, observationLevel);
ralfulrich's avatar
ralfulrich committed

  // define air shower object, run simulation
  setup::Tracking tracking;
  Cascade EAS(env, tracking, sequence, output, stack);
ralfulrich's avatar
ralfulrich committed

  // to fix the point of first interaction, uncomment the following two lines:
  //  EAS.SetNodes();
  //  EAS.forceInteraction();
ralfulrich's avatar
ralfulrich committed

  output.startOfShower();
ralfulrich's avatar
ralfulrich committed
  EAS.run();
  output.endOfShower();
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
  cut.showResults();
ralfulrich's avatar
ralfulrich committed
  eLoss.showResults();
ralfulrich's avatar
ralfulrich committed
  observationLevel.showResults();
  const HEPEnergyType Efinal = cut.getCutEnergy() + cut.getInvEnergy() +
                               cut.getEmEnergy() + eLoss.getEnergyLost() +
                               observationLevel.getEnergyGround();
ralfulrich's avatar
ralfulrich committed
  cout << "total cut energy (GeV): " << Efinal / 1_GeV << endl
       << "relative difference (%): " << (Efinal / E0 - 1) * 100 << endl;
ralfulrich's avatar
ralfulrich committed
  observationLevel.reset();
  cut.reset();
ralfulrich's avatar
ralfulrich committed
  eLoss.reset();

ralfulrich's avatar
ralfulrich committed
  auto const hists = sibyllCounted.getHistogram() + sibyllNucCounted.getHistogram() +
                     urqmdCounted.getHistogram();
ralfulrich's avatar
ralfulrich committed

  save_hist(hists.labHist(), "inthist_lab_hybrid.npz", true);
  save_hist(hists.CMSHist(), "inthist_cms_hybrid.npz", true);
ralfulrich's avatar
ralfulrich committed

  longprof.save("longprof.txt");

  std::ofstream finish("finished");
  finish << "run completed without error" << std::endl;
ralfulrich's avatar
ralfulrich committed

  output.endOfLibrary();
ralfulrich's avatar
ralfulrich committed
}