From c96767ee8747aa3d7bfbc9da155ef1ebaaa76722 Mon Sep 17 00:00:00 2001
From: Maximilian Sackel <maximilian.sackel@tu-dortmund.de>
Date: Wed, 30 Sep 2020 15:48:56 +0000
Subject: [PATCH] add further doc and some minor fixes in particle cut

---
 Documentation/Examples/vertical_EAS.cc  | 11 -----
 Processes/ParticleCut/ParticleCut.cc    |  2 +-
 Processes/ParticleCut/ParticleCut.h     |  4 +-
 Processes/Proposal/ContinuousProcess.cc | 66 +++++++++++++++++++------
 Processes/Proposal/ContinuousProcess.h  |  9 +---
 Processes/Proposal/Interaction.cc       | 20 +++++++-
 Processes/Proposal/Interaction.h        | 26 ++++++++--
 7 files changed, 99 insertions(+), 39 deletions(-)

diff --git a/Documentation/Examples/vertical_EAS.cc b/Documentation/Examples/vertical_EAS.cc
index 26b259c84..738bd73e4 100644
--- a/Documentation/Examples/vertical_EAS.cc
+++ b/Documentation/Examples/vertical_EAS.cc
@@ -195,7 +195,6 @@ int main(int argc, char** argv) {
 
   process::on_shell_check::OnShellCheck reset_particle_mass(1.e-3, 1.e-1, false);
 
-  process::energy_loss::EnergyLoss eLoss(showerAxis);
   process::longitudinal_profile::LongitudinalProfile longprof{showerAxis};
 
   Plane const obsPlane(showerCore, Vector<dimensionless_d>(rootCS, {0., 0., 1.}));
@@ -205,10 +204,6 @@ int main(int argc, char** argv) {
   process::UrQMD::UrQMD urqmd;
   process::interaction_counter::InteractionCounter urqmdCounted{urqmd};
 
-  /* process::conex_source_cut::CONEXSourceCut conexSource( */
-  /*     center, showerAxis, t, injectionHeight, E0, */
-  /*     particles::GetPDG(particles::Code::Proton)); */
-
   // assemble all processes into an ordered process list
 
   auto sibyllSequence = sibyllNucCounted << sibyllCounted;
@@ -216,8 +211,6 @@ int main(int argc, char** argv) {
                                                        55_GeV);
   auto decaySequence = decayPythia << decaySibyll;
 
-  //auto sequence = switchProcess << reset_particle_mass << decaySequence << conexSource
-  //                            << longprof << eLoss << cut << observationLevel;
   auto sequence = switchProcess << reset_particle_mass << decaySequence << proposalCounted << cut << em_continuous
 				<< longprof << observationLevel;
 
@@ -231,16 +224,12 @@ int main(int argc, char** argv) {
 
   EAS.Run();
 
-  eLoss.PrintProfile(); // print longitudinal profile
-  /* conexSource.SolveCE(); */
 
   cut.ShowResults();
   const HEPEnergyType Efinal =
       cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy();
   cout << "total cut energy (GeV): " << Efinal / 1_GeV << endl
        << "relative difference (%): " << (Efinal / E0 - 1) * 100 << endl;
-  cout << "total dEdX energy (GeV): " << eLoss.GetTotal() / 1_GeV << endl
-       << "relative difference (%): " << eLoss.GetTotal() / E0 * 100 << endl;
 
   auto const hists = sibyllCounted.GetHistogram() + sibyllNucCounted.GetHistogram() +
     urqmdCounted.GetHistogram() + proposalCounted.GetHistogram();
diff --git a/Processes/ParticleCut/ParticleCut.cc b/Processes/ParticleCut/ParticleCut.cc
index defc68bad..e59addccc 100644
--- a/Processes/ParticleCut/ParticleCut.cc
+++ b/Processes/ParticleCut/ParticleCut.cc
@@ -84,7 +84,7 @@ namespace corsika::process {
 
     ParticleCut::ParticleCut(const units::si::HEPEnergyType eCut, bool discardEm, bool discardInv)
         : eCut_(eCut)
-        , discardEm_(cutEm)
+        , discardEm_(discardEm)
         , discardInv_(discardInv) {
 
       emEnergy_ = 0_GeV;
diff --git a/Processes/ParticleCut/ParticleCut.h b/Processes/ParticleCut/ParticleCut.h
index 68639471a..0edab21e3 100644
--- a/Processes/ParticleCut/ParticleCut.h
+++ b/Processes/ParticleCut/ParticleCut.h
@@ -18,8 +18,8 @@ namespace corsika::process {
     class ParticleCut : public process::SecondariesProcess<ParticleCut> {
 
       units::si::HEPEnergyType const eCut_;
-      bool cutEm_;
-      bool cutInv_;
+      bool discardEm_;
+      bool discardInv_;
 
       units::si::HEPEnergyType energy_ = 0 * units::si::electronvolt;
       units::si::HEPEnergyType emEnergy_ = 0 * units::si::electronvolt;
diff --git a/Processes/Proposal/ContinuousProcess.cc b/Processes/Proposal/ContinuousProcess.cc
index 49427f03e..eb5f8d3f7 100644
--- a/Processes/Proposal/ContinuousProcess.cc
+++ b/Processes/Proposal/ContinuousProcess.cc
@@ -23,10 +23,19 @@ namespace corsika::process::proposal {
 
   void ContinuousProcess::BuildCalculator(particles::Code code,
                                           environment::NuclearComposition const& comp) {
+    // search crosssection builder for given particle
     auto p_cross = cross.find(code);
     if (p_cross == cross.end())
       throw std::runtime_error("PROPOSAL could not find corresponding builder");
+
+    // interpolate the crosssection for given media and energy cut. These may
+    // take some minutes if you have to build the tables and cannot read the
+    // from disk
     auto c = p_cross->second(media.at(&comp), cut);
+
+    // Build displacement integral and scattering object and interpolate them too and
+    // saved in the calc map by a key build out of a hash of composed of the component and
+    // particle code.
     auto disp = PROPOSAL::make_displacement(c, true);
     auto scatter = PROPOSAL::make_scattering("highland", particle[code], media.at(&comp));
     calc[std::make_pair(&comp, code)] =
@@ -38,31 +47,35 @@ namespace corsika::process::proposal {
                                        particle_cut::ParticleCut& _cut)
       : ProposalProcessBase(_env, _cut) {}
 
-  template <>
-  HEPEnergyType ContinuousProcess::TotalEnergyLoss(setup::Stack::ParticleType const& vP,
-                                                   GrammageType const& vDX) {
-    auto c = GetCalculator(vP, calc);
-    return vP.GetEnergy() - get<DISPLACEMENT>(c->second)->UpperLimitTrackIntegral(
-                                vP.GetEnergy() / 1_MeV, vDX / 1_g * 1_cm * 1_cm) *
-                                1_MeV;
-  }
-
   template <>
   void ContinuousProcess::Scatter(setup::Stack::ParticleType& vP,
                                   HEPEnergyType const& loss,
                                   GrammageType const& grammage) {
+    // Get or build corresponding calculators
     auto c = GetCalculator(vP, calc);
+
+    // Cast corsika vector to proposal vector
     auto d = vP.GetDirection().GetComponents();
     auto direction = PROPOSAL::Vector3D(d.GetX().magnitude(), d.GetY().magnitude(),
                                         d.GetZ().magnitude());
-    auto E_f = vP.GetEnergy() - loss; // final energy
+
+    auto E_f = vP.GetEnergy() - loss;
+
+    // draw random numbers required for scattering process
     std::uniform_real_distribution<double> distr(0., 1.);
     auto rnd = array<double, 4>();
     for (auto& it : rnd) it = distr(fRNG);
+
+    // calculate deflection based on particle energy, loss
     auto [mean_dir, final_dir] = get<SCATTERING>(c->second)->Scatter(
         grammage / 1_g * square(1_cm), vP.GetEnergy() / 1_MeV, E_f / 1_MeV, direction,
         rnd);
+
+    // TODO: neglect mean direction deflection because Trajectory is a const ref
     (void)mean_dir;
+
+    // update particle direction after continuous loss caused by multiple
+    // scattering
     auto vec = corsika::geometry::QuantityVector(
         final_dir.GetX() * E_f, final_dir.GetY() * E_f, final_dir.GetZ() * E_f);
     vP.SetMomentum(corsika::stack::MomentumVector(
@@ -74,11 +87,26 @@ namespace corsika::process::proposal {
   EProcessReturn ContinuousProcess::DoContinuous(setup::Stack::ParticleType& vP,
                                                  setup::Trajectory const& vT) {
     if (!CanInteract(vP.GetPID())) return process::EProcessReturn::eOk;
+
+    // calculate passed grammage
     auto dX = vP.GetNode()->GetModelProperties().IntegratedGrammage(vT, vT.GetLength());
-    auto energy_loss = TotalEnergyLoss(vP, dX);
-    if (vP.GetChargeNumber() != 0) Scatter(vP, energy_loss, dX);
-    vP.SetEnergy(vP.GetEnergy() - energy_loss);
-    if (vP.GetEnergy() <= cut.GetECut()) return process::EProcessReturn::eParticleAbsorbed;
+
+    // Get or build corresponding track integral calculator and solve the
+    // integral
+    auto c = GetCalculator(vP, calc);
+    auto final_energy = get<DISPLACEMENT>(c->second)->UpperLimitTrackIntegral(
+                            vP.GetEnergy() / 1_MeV, dX / 1_g * 1_cm * 1_cm) *
+                        1_MeV;
+
+    // if the particle has a charge take multiple scattering into account
+    if (vP.GetChargeNumber() != 0 && vP.GetEnergy() > final_energy)
+      Scatter(vP, vP.GetEnergy() - final_energy, dX);
+
+    // Update the energy and absorbe the particle if it's below the energy
+    // threshold, because it will no longer propagated.
+    vP.SetEnergy(final_energy);
+    if (std::fabs((vP.GetEnergy() - cut.GetECut() )/ cut.GetECut()) < 0.01)
+      return process::EProcessReturn::eParticleAbsorbed;
     vP.SetMomentum(vP.GetMomentum() * vP.GetEnergy() / vP.GetMomentum().GetNorm());
     return process::EProcessReturn::eOk;
   }
@@ -88,12 +116,22 @@ namespace corsika::process::proposal {
       setup::Stack::ParticleType const& vP, setup::Trajectory const& vT) {
     if (!CanInteract(vP.GetPID()))
       return units::si::meter * std::numeric_limits<double>::infinity();
+
+    // Limit the step size of a conitnous loss. The maximal continuous loss seems to be a
+    // hyper parameter which must be adjusted.
     auto energy_lim = 0.9 * vP.GetEnergy();
+
+    // If energy lim is below the cut it couldn't be descriped by these process. So the
+    // energy_lim is replaced by the cut.
     if (cut.GetECut() > energy_lim) energy_lim = cut.GetECut();
+
+    // solving the track integral for giving energy lim
     auto c = GetCalculator(vP, calc);
     auto grammage = get<DISPLACEMENT>(c->second)->SolveTrackIntegral(
                         vP.GetEnergy() / 1_MeV, energy_lim / 1_MeV) *
                     1_g / square(1_cm);
+
+    // return it in distance aequivalent
     return vP.GetNode()->GetModelProperties().ArclengthFromGrammage(vT, grammage);
   }
 
diff --git a/Processes/Proposal/ContinuousProcess.h b/Processes/Proposal/ContinuousProcess.h
index c50ac8d54..9449d9c74 100644
--- a/Processes/Proposal/ContinuousProcess.h
+++ b/Processes/Proposal/ContinuousProcess.h
@@ -43,19 +43,14 @@ namespace corsika::process::proposal {
     void BuildCalculator(particles::Code, environment::NuclearComposition const&) final;
 
   public:
+
+    //!
     //! Produces the continuous loss calculator for leptons based on nuclear
     //! compositions and stochastic description limited by the particle cut.
     //!
     template <typename TEnvironment>
     ContinuousProcess(TEnvironment const&, particle_cut::ParticleCut&);
 
-    //!
-    //! Calculates the energy of the particle which has passed the given
-    //! grammage.
-    //!
-    template <typename Particle>
-    corsika::units::si::HEPEnergyType TotalEnergyLoss(
-        Particle const&, corsika::units::si::GrammageType const&);
 
     //!
     //! Multiple Scattering of the lepton. Stochastic deflection is not yet taken into
diff --git a/Processes/Proposal/Interaction.cc b/Processes/Proposal/Interaction.cc
index 2ac0e7b70..b88653360 100644
--- a/Processes/Proposal/Interaction.cc
+++ b/Processes/Proposal/Interaction.cc
@@ -31,10 +31,20 @@ namespace corsika::process::proposal {
 
   void Interaction::BuildCalculator(particles::Code code,
                                     environment::NuclearComposition const& comp) {
+    // search crosssection builder for given particle
     auto p_cross = cross.find(code);
     if (p_cross == cross.end())
       throw std::runtime_error("PROPOSAL could not find corresponding builder");
+
+    // interpolate the crosssection for given media and energy cut. These may
+    // take some minutes if you have to build the tables and cannot read the
+    // from disk
     auto c = p_cross->second(media.at(&comp), cut);
+
+    // Look which interactions take place and build the corresponding
+    // interaction and secondarie builder. The interaction integral will
+    // interpolated too and saved in the calc map by a key build out of a hash
+    // of composed of the component and particle code.
     auto inter_types = PROPOSAL::CrossSectionVector::GetInteractionTypes(c);
     calc[std::make_pair(&comp, code)] = std::make_tuple(
         PROPOSAL::make_secondaries(inter_types, particle[code], media.at(&comp)),
@@ -45,11 +55,19 @@ namespace corsika::process::proposal {
   corsika::process::EProcessReturn Interaction::DoInteraction(
       setup::StackView::StackIterator& vP) {
     if (CanInteract(vP.GetPID())) {
-      auto c = GetCalculator(vP, calc); // [CrossSections]
+      // Get or build corresponding calculators
+      auto c = GetCalculator(vP, calc);
+
+      // Get the rates of the interaction types for every component.
       std::uniform_real_distribution<double> distr(0., 1.);
+
+      // sample a interaction-type, loss and component
       auto rates = get<INTERACTION>(c->second)->Rates(vP.GetEnergy() / 1_MeV);
       auto [type, comp_ptr, v] = get<INTERACTION>(c->second)->SampleLoss(
           vP.GetEnergy() / 1_MeV, rates, distr(fRNG));
+
+      // Read how much random numbers are required to calculate the secondaries.
+      // Calculate the secondaries and deploy them on the corsika stack.
       auto rnd = vector<double>(get<SECONDARIES>(c->second)->RequiredRandomNumbers(type));
       for (auto& it : rnd) it = distr(fRNG);
       auto point = PROPOSAL::Vector3D(vP.GetPosition().GetX() / 1_cm,
diff --git a/Processes/Proposal/Interaction.h b/Processes/Proposal/Interaction.h
index 990cf1115..c96cf00df 100644
--- a/Processes/Proposal/Interaction.h
+++ b/Processes/Proposal/Interaction.h
@@ -23,24 +23,44 @@ namespace corsika::process::proposal {
 
   using namespace corsika::units::si;
 
+  //!
+  //! Electro-magnetic and gamma stochastic losses produced by proposal. It makes
+  //! use of interpolation tables which are runtime intensive calculation, but can be
+  //! reused by setting the \param PROPOSAL::InterpolationDef::path_to_tables variable.
+  //!
   class Interaction : public InteractionProcess<Interaction>, ProposalProcessBase {
 
+    enum { SECONDARIES, INTERACTION };
     using calculator_t = tuple<unique_ptr<PROPOSAL::SecondariesCalculator>,
                                unique_ptr<PROPOSAL::Interaction>>;
 
-    std::unordered_map<calc_key_t, calculator_t, hash> calc;
+    std::unordered_map<calc_key_t, calculator_t, hash>
+        calc; //!< Stores the secondaries and interaction calculators.
 
+    //!
+    //! Build the secondaries and interaction calculators and add it to calc.
+    //!
     void BuildCalculator(particles::Code, environment::NuclearComposition const&) final;
 
-    enum { SECONDARIES, INTERACTION };
-
   public:
+    //!
+    //! Produces the stoachastic loss calculator for leptons based on nuclear
+    //! compositions and stochastic description limited by the particle cut.
+    //!
     template <typename TEnvironment>
     Interaction(TEnvironment const& env, particle_cut::ParticleCut& cut);
 
+    //!
+    //! Calculate the rates for the different targets and interactions. Sample a
+    //! pair of interaction-type, component and rate, followed by sampling a loss and
+    //! produce the corresponding secondaries and store them on the particle stack.
+    //!
     template <typename Particle>
     corsika::process::EProcessReturn DoInteraction(Particle&);
 
+    //!
+    //! Calculates the  mean free path length
+    //!
     template <typename TParticle>
     corsika::units::si::GrammageType GetInteractionLength(TParticle const& p);
   };
-- 
GitLab