From 9fc9ff1bf952850401783a42083213885027b318 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Fri, 2 Oct 2020 22:15:37 +0200
Subject: [PATCH] added a hash as member of NuclearComposition, so that it can
 be used as unique map-key etc.

---
 Environment/NuclearComposition.h          | 24 +++++++++++++++++++++++
 Processes/Proposal/ContinuousProcess.cc   |  6 +++---
 Processes/Proposal/ProposalProcessBase.cc |  7 +++----
 Processes/Proposal/ProposalProcessBase.h  |  8 ++++----
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/Environment/NuclearComposition.h b/Environment/NuclearComposition.h
index 596302609..3e45513a4 100644
--- a/Environment/NuclearComposition.h
+++ b/Environment/NuclearComposition.h
@@ -18,6 +18,8 @@
 #include <stdexcept>
 #include <vector>
 
+
+    
 namespace corsika::environment {
   class NuclearComposition {
     std::vector<float> const fNumberFractions; //!< relative fractions of number density
@@ -26,6 +28,8 @@ namespace corsika::environment {
 
     double const fAvgMassNumber;
 
+    std::size_t hash_;
+    
     template <class AConstIterator, class BConstIterator>
     class WeightProviderIterator {
       AConstIterator fAIter;
@@ -77,6 +81,7 @@ namespace corsika::environment {
       if (!(0.999f < sumFractions && sumFractions < 1.001f)) {
         throw std::runtime_error("element fractions do not add up to 1");
       }
+      updateHash();
     }
 
     template <typename TFunction>
@@ -125,6 +130,25 @@ namespace corsika::environment {
       auto const iChannel = channelDist(randomStream);
       return fComponents[iChannel];
     }
+
+    // Note: when this class ever modifies its internal data, the hash
+    // must be updated, too!
+    size_t hash() const { return hash_; }
+    
+  private:
+    void updateHash() const {
+      std::vector<std::size_t> hashes;
+      for (float ifrac : GetFractions())
+	hashes.push_back(std::hash<float>{}(ifrac));
+      for (corsika::particles::Code icode : GetComponents())
+	hashes.push_back(std::hash<int>{}(static_cast<int>(icode)));
+      std::size_t h = std::hash<double>{}(GetAverageMassNumber());
+      for (std::size_t ih : hashes)
+	h = h ^ (ih<<1);
+      hash_ = h;
+    }
+
   };
 
 } // namespace corsika::environment
+
diff --git a/Processes/Proposal/ContinuousProcess.cc b/Processes/Proposal/ContinuousProcess.cc
index 7ceb75b47..ef1216788 100644
--- a/Processes/Proposal/ContinuousProcess.cc
+++ b/Processes/Proposal/ContinuousProcess.cc
@@ -30,14 +30,14 @@ namespace corsika::process::proposal {
     // 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), emCut_);
+    auto c = p_cross->second(media.at(comp.hash()), emCut_);
 
     // 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)] =
+    auto scatter = PROPOSAL::make_scattering("highland", particle[code], media.at(comp.hash()));
+    calc[std::make_pair(comp.hash(), code)] =
         std::make_tuple(std::move(disp), std::move(scatter));
   }
 
diff --git a/Processes/Proposal/ProposalProcessBase.cc b/Processes/Proposal/ProposalProcessBase.cc
index 0211b4788..3d1bd1e98 100644
--- a/Processes/Proposal/ProposalProcessBase.cc
+++ b/Processes/Proposal/ProposalProcessBase.cc
@@ -43,7 +43,7 @@ namespace corsika::process::proposal {
                               *frac_iter);
         ++frac_iter;
       }
-      media[ncarg] = PROPOSAL::Medium(
+      media[ncarg->hash()] = PROPOSAL::Medium(
           "Modified Air", PROPOSAL::Air().GetI(), PROPOSAL::Air().GetC(),
           PROPOSAL::Air().GetA(), PROPOSAL::Air().GetM(), PROPOSAL::Air().GetX0(),
           PROPOSAL::Air().GetX1(), PROPOSAL::Air().GetD0(), 1.0, comp_vec);
@@ -64,10 +64,9 @@ namespace corsika::process::proposal {
           "table directory. ");
     }
   }
-
+  
   size_t ProposalProcessBase::hash::operator()(const calc_key_t& p) const noexcept {
-    return std::hash<const environment::NuclearComposition*>{}(p.first) ^
-           std::hash<particles::Code>{}(p.second);
+    return p.first ^ std::hash<particles::Code>{}(p.second);
   }
 
 } // namespace corsika::process::proposal
diff --git a/Processes/Proposal/ProposalProcessBase.h b/Processes/Proposal/ProposalProcessBase.h
index b1696526a..82d833022 100644
--- a/Processes/Proposal/ProposalProcessBase.h
+++ b/Processes/Proposal/ProposalProcessBase.h
@@ -73,7 +73,7 @@ namespace corsika::process::proposal {
                                 //!< will be handeled continuously.
     corsika::random::RNG& fRNG; //!< random number generator used by proposal
 
-    std::unordered_map<const environment::NuclearComposition*, PROPOSAL::Medium>
+    std::unordered_map<std::size_t, PROPOSAL::Medium>
         media; //!< maps nuclear composition from univers to media to produce
                //!< crosssections, which requires further ionization constants.
 
@@ -89,7 +89,7 @@ namespace corsika::process::proposal {
     //!
     bool CanInteract(particles::Code pcode) const;
 
-    using calc_key_t = std::pair<const environment::NuclearComposition*, particles::Code>;
+    using calc_key_t = std::pair<std::size_t, particles::Code>;
 
     //!
     //! Hash to store interpolation tables related to a pair of particle and nuclear
@@ -112,8 +112,8 @@ namespace corsika::process::proposal {
     //!
     template <typename Particle, typename Calculators>
     auto GetCalculator(Particle& vP, Calculators& calc) {
-      auto& comp = vP.GetNode()->GetModelProperties().GetNuclearComposition();
-      auto calc_it = calc.find(std::make_pair(&comp, vP.GetPID()));
+      const auto& comp = vP.GetNode()->GetModelProperties().GetNuclearComposition();
+      auto calc_it = calc.find(std::make_pair(comp.hash(), vP.GetPID()));
       if (calc_it != calc.end()) return calc_it;
       BuildCalculator(vP.GetPID(), comp);
       return GetCalculator(vP, calc);
-- 
GitLab