IAP GITLAB

Skip to content
Snippets Groups Projects
cascade_example.cc 18.3 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/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/random/RNGManager.h>
Felix Riehn's avatar
Felix Riehn committed
#include <corsika/cascade/SibStack.h>
ralfulrich's avatar
ralfulrich committed
#include <corsika/cascade/sibyll2.3c.h>
#include <corsika/geometry/Sphere.h>
Felix Riehn's avatar
Felix Riehn committed
#include <corsika/process/sibyll/ParticleConversion.h>
#include <corsika/process/sibyll/ProcessDecay.h>

#include <corsika/units/PhysicalUnits.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;

static int fCount = 0;
Felix Riehn's avatar
Felix Riehn committed
static EnergyType fEnergy = 0. * 1_GeV;

// FOR NOW: global static variables for ParticleCut process
// this is just wrong...
Felix Riehn's avatar
Felix Riehn committed
static EnergyType fEmEnergy;
static int fEmCount;
Felix Riehn's avatar
Felix Riehn committed
static EnergyType fInvEnergy;
static int fInvCount;
Felix Riehn's avatar
Felix Riehn committed

class ProcessEMCut : public corsika::process::BaseProcess<ProcessEMCut> {
public:
  ProcessEMCut() {}
  template <typename Particle>
Felix Riehn's avatar
Felix Riehn committed
  bool isBelowEnergyCut(Particle& p) const {
Felix Riehn's avatar
Felix Riehn committed
    // FOR NOW: center-of-mass energy hard coded
Felix Riehn's avatar
Felix Riehn committed
    const EnergyType Ecm = sqrt(2. * p.GetEnergy() * 0.93827_GeV);
    if (p.GetEnergy() < 50_GeV || Ecm < 10_GeV)
Felix Riehn's avatar
Felix Riehn committed
      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;
      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;

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

  template <typename Particle>
Felix Riehn's avatar
Felix Riehn committed
  double MinStepLength(Particle& p, setup::Trajectory&) const {
Felix Riehn's avatar
Felix Riehn committed
    const Code pid = p.GetPID();
Felix Riehn's avatar
Felix Riehn committed
    if (isEmParticle(pid) || isInvisible(pid)) {
Felix Riehn's avatar
Felix Riehn committed
      cout << "ProcessCut: MinStep: next cut: " << 0. << endl;
      return 0.;
Felix Riehn's avatar
Felix Riehn committed
    } else {
Felix Riehn's avatar
Felix Riehn committed
      double next_step = std::numeric_limits<double>::infinity();
      cout << "ProcessCut: MinStep: next cut: " << next_step << endl;
      return next_step;
    }
  }

  template <typename Particle, typename Stack>
ralfulrich's avatar
ralfulrich committed
  EProcessReturn DoContinuous(Particle&, setup::Trajectory&, Stack&) const {
Felix Riehn's avatar
Felix Riehn committed
    // cout << "ProcessCut: DoContinous: " << p.GetPID() << endl;
    // cout << " is em: " << isEmParticle( p.GetPID() ) << endl;
    // cout << " is inv: " << isInvisible( p.GetPID() ) << endl;
    // const Code pid = p.GetPID();
    // if( isEmParticle( pid ) ){
    //   cout << "removing em. particle..." << endl;
    //   fEmEnergy += p.GetEnergy();
    //   fEmCount  += 1;
    //   p.Delete();
    //   return EProcessReturn::eParticleAbsorbed;
    // }
    // if ( isInvisible( pid ) ){
    //   cout << "removing inv. particle..." << endl;
    //   fInvEnergy += p.GetEnergy();
    //   fInvCount  += 1;
    //   p.Delete();
    //   return EProcessReturn::eParticleAbsorbed;
    // }
Felix Riehn's avatar
Felix Riehn committed
    return EProcessReturn::eOk;
Felix Riehn's avatar
Felix Riehn committed
  }

  template <typename Particle, typename Stack>
ralfulrich's avatar
ralfulrich committed
  void DoDiscrete(Particle& p, Stack&) const {
Felix Riehn's avatar
Felix Riehn committed
    cout << "ProcessCut: DoDiscrete: " << p.GetPID() << endl;
    const Code pid = p.GetPID();
Felix Riehn's avatar
Felix Riehn committed
    if (isEmParticle(pid)) {
Felix Riehn's avatar
Felix Riehn committed
      cout << "removing em. particle..." << endl;
      fEmEnergy += p.GetEnergy();
Felix Riehn's avatar
Felix Riehn committed
      fEmCount += 1;
Felix Riehn's avatar
Felix Riehn committed
      p.Delete();
Felix Riehn's avatar
Felix Riehn committed
    } else if (isInvisible(pid)) {
Felix Riehn's avatar
Felix Riehn committed
      cout << "removing inv. particle..." << endl;
      fInvEnergy += p.GetEnergy();
Felix Riehn's avatar
Felix Riehn committed
      fInvCount += 1;
Felix Riehn's avatar
Felix Riehn committed
      p.Delete();
Felix Riehn's avatar
Felix Riehn committed
    } else if (isBelowEnergyCut(p)) {
Felix Riehn's avatar
Felix Riehn committed
      cout << "removing low en. particle..." << endl;
      fEnergy += p.GetEnergy();
Felix Riehn's avatar
Felix Riehn committed
      fCount += 1;
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
         << " ******************************" << endl;
Felix Riehn's avatar
Felix Riehn committed
  EnergyType GetInvEnergy() { return fInvEnergy; }
Felix Riehn's avatar
Felix Riehn committed
  EnergyType GetCutEnergy() { return fEnergy; }
Felix Riehn's avatar
Felix Riehn committed
  EnergyType GetEmEnergy() { return fEmEnergy; }
class ProcessSplit : public corsika::process::InteractionProcess<ProcessSplit> {
public:
  ProcessSplit() {}

  void setTrackedParticlesStable() const {
    /*
      Sibyll is hadronic generator
      only hadrons decay
     */
Felix Riehn's avatar
Felix Riehn committed
    // set particles unstable
    corsika::process::sibyll::setHadronsUnstable();
    // make tracked particles stable
    std::cout << "ProcessSplit: setting tracked hadrons stable.." << std::endl;
    setup::Stack ds;
    ds.NewParticle().SetPID(Code::PiPlus);
    ds.NewParticle().SetPID(Code::PiMinus);
    ds.NewParticle().SetPID(Code::KPlus);
    ds.NewParticle().SetPID(Code::KMinus);
    ds.NewParticle().SetPID(Code::K0Long);
    ds.NewParticle().SetPID(Code::K0Short);
Felix Riehn's avatar
Felix Riehn committed

    for (auto& p : ds) {
      int s_id = process::sibyll::ConvertToSibyllRaw(p.GetPID());
      // set particle stable by setting table value negative
Felix Riehn's avatar
Felix Riehn committed
      s_csydec_.idb[s_id - 1] = (-1) * abs(s_csydec_.idb[s_id - 1]);
Felix Riehn's avatar
Felix Riehn committed

Ralf Ulrich's avatar
Ralf Ulrich committed
  template <typename Particle, typename Track>
ralfulrich's avatar
ralfulrich committed
  double GetInteractionLength(Particle& p, Track&) const {
    // coordinate system, get global frame of reference
    CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
Felix Riehn's avatar
Felix Riehn committed

Felix Riehn's avatar
Felix Riehn committed

    // beam particles for sibyll : 1, 2, 3 for p, pi, k
Felix Riehn's avatar
Felix Riehn committed
    int kBeam = process::sibyll::GetSibyllXSCode(corsikaBeamId);
ralfulrich's avatar
ralfulrich committed

Felix Riehn's avatar
Felix Riehn committed
    bool kInteraction = process::sibyll::CanInteract(corsikaBeamId);
ralfulrich's avatar
ralfulrich committed

    /*
       the target should be defined by the Environment,
ralfulrich's avatar
ralfulrich committed
       ideally as full particle object so that the four momenta
       and the boosts can be defined..
     */
    // target nuclei: A < 18
    // FOR NOW: assume target is oxygen
Felix Riehn's avatar
Felix Riehn committed
    EnergyType Etot = p.GetEnergy() + kTarget * corsika::particles::Proton::GetMass();
    super_stupid::MomentumVector Ptot(
        rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
    // FOR NOW: assume target is at rest
Felix Riehn's avatar
Felix Riehn committed
    super_stupid::MomentumVector pTarget(
        rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
    Ptot += p.GetMomentum();
    Ptot += pTarget;
    // calculate cm. energy
Felix Riehn's avatar
Felix Riehn committed
    EnergyType sqs = sqrt(Etot * Etot - Ptot.squaredNorm() * si::constants::cSquared);
Felix Riehn's avatar
Felix Riehn committed

    std::cout << "ProcessSplit: "
              << "MinStep: input en: " << p.GetEnergy() / 1_GeV << endl
              << " beam can interact:" << kBeam << endl
              << " beam XS code:" << kBeam << endl
              << " beam pid:" << p.GetPID() << endl
              << " target mass number:" << kTarget << std::endl;
    double int_length = 0;
Felix Riehn's avatar
Felix Riehn committed
    if (kInteraction) {

      double prodCrossSection, dummy, dum1, dum2, dum3, dum4;
Felix Riehn's avatar
Felix Riehn committed

      if (kTarget == 1)
        sib_sigma_hp_(kBeam, Ecm, dum1, dum2, prodCrossSection, dumdif, dum3, dum4);
Felix Riehn's avatar
Felix Riehn committed
        sib_sigma_hnuc_(kBeam, kTarget, Ecm, prodCrossSection, dummy);

      std::cout << "ProcessSplit: "
                << "MinStep: sibyll return: " << prodCrossSection << std::endl;
      CrossSectionType sig = prodCrossSection * 1_mbarn;
Felix Riehn's avatar
Felix Riehn committed
      std::cout << "ProcessSplit: "
                << "MinStep: CrossSection (mb): " << sig / 1_mbarn << std::endl;

      const MassType nucleon_mass = 0.93827_GeV / corsika::units::si::constants::cSquared;
Felix Riehn's avatar
Felix Riehn committed
      std::cout << "ProcessSplit: "
                << "nucleon mass " << nucleon_mass << std::endl;
      int_length = kTarget * (nucleon_mass / 1_g) / (sig / 1_cmeter / 1_cmeter);
Felix Riehn's avatar
Felix Riehn committed
      std::cout << "ProcessSplit: "
                << "interaction length (g/cm2): " << int_length << std::endl;
    } else
      int_length = std::numeric_limits<double>::infinity();
Felix Riehn's avatar
Felix Riehn committed

    /*
      what are the units of the output? slant depth or 3space length?
ralfulrich's avatar
ralfulrich committed

ralfulrich's avatar
ralfulrich committed
    return int_length;
    //
    // int a = 0;
    // const double next_step = -int_length * log(s_rndm_(a));
    // std::cout << "ProcessSplit: "
ralfulrich's avatar
ralfulrich committed
    //        << "next step (g/cm2): " << next_step << std::endl;
    // return next_step;
Ralf Ulrich's avatar
Ralf Ulrich committed
  template <typename Particle, typename Track, typename Stack>
  EProcessReturn DoContinuous(Particle&, Track&, Stack&) const {
    return EProcessReturn::eOk;
  }

  template <typename Particle, typename Stack>
  void DoInteraction(Particle& p, Stack& s) const {
    cout << "ProcessSibyll: "
         << "DoInteraction: " << p.GetPID() << " interaction? "
Felix Riehn's avatar
Felix Riehn committed
         << process::sibyll::CanInteract(p.GetPID()) << endl;
    if (process::sibyll::CanInteract(p.GetPID())) {
      cout << "defining coordinates" << endl;
      // coordinate system, get global frame of reference
      CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();

      QuantityVector<length_d> const coordinates{0_m, 0_m, 0_m};
      Point pOrig(rootCS, coordinates);
Felix Riehn's avatar
Felix Riehn committed

      /*
         the target should be defined by the Environment,
         ideally as full particle object so that the four momenta
         and the boosts can be defined..

         here we need: GetTargetMassNumber() or GetTargetPID()??
                       GetTargetMomentum() (zero in EAS)
Felix Riehn's avatar
Felix Riehn committed
      int kTarget = 1; // env.GetTargetParticle().GetPID();

      cout << "defining target momentum.." << endl;
      // FOR NOW: target is always at rest
Felix Riehn's avatar
Felix Riehn committed
      const EnergyType Etarget = 0. * 1_GeV + corsika::particles::Proton::GetMass();
      const auto pTarget = super_stupid::MomentumVector(
          rootCS, 0. * 1_GeV / si::constants::c, 0. * 1_GeV / si::constants::c,
          0. * 1_GeV / si::constants::c);
      cout << "target momentum (GeV/c): "
           << pTarget.GetComponents() / 1_GeV * si::constants::c << endl;
      cout << "beam momentum (GeV/c): "
           << p.GetMomentum().GetComponents() / 1_GeV * si::constants::c << endl;

ralfulrich's avatar
ralfulrich committed
      // get energy of particle from stack
Felix Riehn's avatar
Felix Riehn committed
      /*
ralfulrich's avatar
ralfulrich committed
        stack is in GeV in lab. frame
        convert to GeV in cm. frame
        (assuming proton at rest as target AND
        assuming no pT, i.e. shower frame-z is aligned with hadron-int-frame-z)
Felix Riehn's avatar
Felix Riehn committed
      */
      // total energy: E_beam + E_target
      // in lab. frame: E_beam + m_target*c**2
Felix Riehn's avatar
Felix Riehn committed
      EnergyType E = p.GetEnergy();
      EnergyType Etot = E + Etarget;
      // total momentum
      super_stupid::MomentumVector Ptot = p.GetMomentum(); // + pTarget;
      // invariant mass, i.e. cm. energy
Felix Riehn's avatar
Felix Riehn committed
      EnergyType Ecm = sqrt(Etot * Etot -
                            Ptot.squaredNorm() *
                                si::constants::cSquared); // sqrt( 2. * E * 0.93827_GeV );
      /*
       get transformation between Stack-frame and SibStack-frame
       for EAS Stack-frame is lab. frame, could be different for CRMC-mode
       the transformation should be derived from the input momenta
     */
      const double gamma = Etot / Ecm;
      const auto gambet = Ptot / (Ecm / si::constants::c);

      std::cout << "ProcessSplit: "
                << " DoDiscrete: gamma:" << gamma << endl;
      std::cout << "ProcessSplit: "
                << " DoDiscrete: gambet:" << gambet.GetComponents() << endl;

      int kBeam = process::sibyll::ConvertToSibyllRaw(p.GetPID());

      std::cout << "ProcessSplit: "
                << " DoInteraction: E(GeV):" << E / 1_GeV << " Ecm(GeV): " << Ecm / 1_GeV
Felix Riehn's avatar
Felix Riehn committed
                << std::endl;
      if (E < 8.5_GeV || Ecm < 10_GeV) {
        std::cout << "ProcessSplit: "
                  << " DoInteraction: dropping particle.." << std::endl;
ralfulrich's avatar
ralfulrich committed
        p.Delete();
        fCount++;
Felix Riehn's avatar
Felix Riehn committed
      } else {
Felix Riehn's avatar
Felix Riehn committed
        // Sibyll does not know about units..
        double sqs = Ecm / 1_GeV;
        // running sibyll, filling stack
        sibyll_(kBeam, kTarget, sqs);
        // running decays
        setTrackedParticlesStable();
        decsib_();
        // print final state
        int print_unit = 6;
        sib_list_(print_unit);

        // delete current particle
        p.Delete();

        // add particles from sibyll to stack
        // link to sibyll stack
        SibStack ss;

        // SibStack does not know about momentum yet so we need counter to access momentum
        // array in Sibyll
        int i = -1;
        super_stupid::MomentumVector Ptot_final(
            rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
        for (auto& psib : ss) {
          ++i;
          // skip particles that have decayed in Sibyll
          if (abs(s_plist_.llist[i]) > 100) continue;

          // transform energy to lab. frame, primitve
          // compute beta_vec * p_vec
          // arbitrary Lorentz transformation based on sibyll routines
          const auto gammaBetaComponents = gambet.GetComponents();
          const auto pSibyllComponents = psib.GetMomentum().GetComponents();
          EnergyType en_lab = 0. * 1_GeV;
          MomentumType p_lab_components[3];
          en_lab = psib.GetEnergy() * gamma;
          EnergyType pnorm = 0. * 1_GeV;
          for (int j = 0; j < 3; ++j)
            pnorm += (pSibyllComponents[j] * gammaBetaComponents[j] * si::constants::c) /
                     (gamma + 1.);
          pnorm += psib.GetEnergy();

          for (int j = 0; j < 3; ++j) {
            p_lab_components[j] = pSibyllComponents[j] - (-1) * pnorm *
                                                             gammaBetaComponents[j] /
                                                             si::constants::c;
            en_lab -=
                (-1) * pSibyllComponents[j] * gammaBetaComponents[j] * si::constants::c;
          }

          // add to corsika stack
          auto pnew = s.NewParticle();
          pnew.SetEnergy(en_lab);
          pnew.SetPID(process::sibyll::ConvertFromSibyll(psib.GetPID()));

          corsika::geometry::QuantityVector<momentum_d> p_lab_c{
              p_lab_components[0], p_lab_components[1], p_lab_components[2]};
          pnew.SetMomentum(super_stupid::MomentumVector(rootCS, p_lab_c));
          Ptot_final += pnew.GetMomentum();
        }
        // cout << "tot. momentum final (GeV/c): " << Ptot_final.GetComponents() / 1_GeV *
        // si::constants::c << endl;
Felix Riehn's avatar
Felix Riehn committed
    }
ralfulrich's avatar
ralfulrich committed

  void Init() {
ralfulrich's avatar
ralfulrich committed
    corsika::random::RNGManager& rmng = corsika::random::RNGManager::GetInstance();

    rmng.RegisterRandomStream("s_rndm");
ralfulrich's avatar
ralfulrich committed

    // test random number generator
ralfulrich's avatar
ralfulrich committed
    std::cout << "ProcessSplit: "
              << " test sequence of random numbers." << std::endl;
ralfulrich's avatar
ralfulrich committed
    for (int i = 0; i < 8; ++i) std::cout << i << " " << s_rndm_(a) << std::endl;

    // initialize Sibyll
ralfulrich's avatar
ralfulrich committed

  int GetCount() { return fCount; }
Felix Riehn's avatar
Felix Riehn committed
  EnergyType GetEnergy() { return fEnergy; }
Felix Riehn's avatar
Felix Riehn committed

ralfulrich's avatar
ralfulrich committed
double s_rndm_(int&) {
  static corsika::random::RNG& rmng =
      corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
  ;
  return rmng() / (double)rmng.max();
ralfulrich's avatar
ralfulrich committed
int main() {
  corsika::environment::Environment env; // dummy environment
  auto& universe = *(env.GetUniverse());
  auto theMedium = corsika::environment::Environment::CreateNode<Sphere>(
      Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
      1_km * std::numeric_limits<double>::infinity());

  using MyHomogeneousModel =
      corsika::environment::HomogeneousMedium<corsika::environment::IMediumModel>;
  theMedium->SetModelProperties<MyHomogeneousModel>(
      1_g / (1_m * 1_m * 1_m),
      corsika::environment::NuclearComposition(
          std::vector<corsika::particles::Code>{corsika::particles::Code::Proton},
          std::vector<float>{1.}));

  universe.AddChild(std::move(theMedium));
  CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
Felix Riehn's avatar
Felix Riehn committed

  tracking_line::TrackingLine<setup::Stack> tracking(env);
ralfulrich's avatar
ralfulrich committed
  stack_inspector::StackInspector<setup::Stack> p0(true);
  ProcessSplit p1;
  corsika::process::sibyll::ProcessDecay p2;
Felix Riehn's avatar
Felix Riehn committed
  ProcessEMCut p3;
ralfulrich's avatar
ralfulrich committed
  const auto sequence = /*p0 +*/ p1 + p2 + p3;
ralfulrich's avatar
ralfulrich committed
  corsika::cascade::Cascade EAS(tracking, sequence, stack);

  stack.Clear();
  auto particle = stack.NewParticle();
Felix Riehn's avatar
Felix Riehn committed
  MomentumType P0 = sqrt(E0 * E0 - 0.93827_GeV * 0.93827_GeV) / si::constants::c;
  auto plab = super_stupid::MomentumVector(rootCS, 0. * 1_GeV / si::constants::c,
                                           0. * 1_GeV / si::constants::c, P0);
  particle.SetEnergy(E0);
Felix Riehn's avatar
Felix Riehn committed
  particle.SetPID(Code::Proton);
ralfulrich's avatar
ralfulrich committed
  particle.SetTime(0_ns);
  Point p(rootCS, 0_m, 0_m, 0_m);
  particle.SetPosition(p);
  EAS.Init();
  EAS.Run();
Felix Riehn's avatar
Felix Riehn committed
  cout << "Result: E0=" << E0 / 1_GeV
       << "GeV, particles below energy threshold =" << p1.GetCount() << endl;
Felix Riehn's avatar
Felix Riehn committed
  cout << "total energy below threshold (GeV): " << p1.GetEnergy() / 1_GeV << std::endl;
  p3.ShowResults();
  cout << "total energy (GeV): "
Felix Riehn's avatar
Felix Riehn committed
       << (p3.GetCutEnergy() + p3.GetInvEnergy() + p3.GetEmEnergy()) / 1_GeV << endl;