From 19be0728b5d8bb1f2c624f6657f4a2ea144ba65e Mon Sep 17 00:00:00 2001
From: Nikos Karastathis <n.karastathis@kit.edu>
Date: Fri, 20 Jan 2023 12:18:19 +0100
Subject: [PATCH] refractive index using Gladstone-Dale law & some first tests

---
 .../media/GladstoneDaleRefractiveIndex.inl    | 30 +++++++
 .../media/GladstoneDaleRefractiveIndex.hpp    | 55 ++++++++++++
 tests/media/testRefractiveIndex.cpp           | 84 ++++++++++++++++++-
 3 files changed, 166 insertions(+), 3 deletions(-)
 create mode 100644 corsika/detail/media/GladstoneDaleRefractiveIndex.inl
 create mode 100644 corsika/media/GladstoneDaleRefractiveIndex.hpp

diff --git a/corsika/detail/media/GladstoneDaleRefractiveIndex.inl b/corsika/detail/media/GladstoneDaleRefractiveIndex.inl
new file mode 100644
index 000000000..d0a13a981
--- /dev/null
+++ b/corsika/detail/media/GladstoneDaleRefractiveIndex.inl
@@ -0,0 +1,30 @@
+/*
+* (c) Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <corsika/media/IRefractiveIndexModel.hpp>
+
+namespace corsika {
+
+  template <typename T>
+  template <typename... Args>
+  inline GladstoneDaleRefractiveIndex<T>::GladstoneDaleRefractiveIndex(double const seaLevelRefractiveIndex,
+                                                                       Point const point, Args&&... args)
+      : T(std::forward<Args>(args)...)
+      , seaLevelRefractiveIndex_(seaLevelRefractiveIndex)
+      , earthSurface_(point)
+      , seaLevelDensity_(this->getMassDensity(earthSurface_)) {}
+//      , ratio_((1. - seaLevelRefractiveIndex_) / (seaLevelDensity_ * cube(1_m) / 1_kg)) {}
+
+  template <typename T>
+  inline double GladstoneDaleRefractiveIndex<T>::getRefractiveIndex(Point const& point) const {
+    return (seaLevelRefractiveIndex_ - 1.) * (this->getMassDensity(point) / seaLevelDensity_) + 1.;
+  }
+
+} // namespace corsika
diff --git a/corsika/media/GladstoneDaleRefractiveIndex.hpp b/corsika/media/GladstoneDaleRefractiveIndex.hpp
new file mode 100644
index 000000000..767351d8f
--- /dev/null
+++ b/corsika/media/GladstoneDaleRefractiveIndex.hpp
@@ -0,0 +1,55 @@
+/*
+* (c) Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <corsika/media/IRefractiveIndexModel.hpp>
+
+namespace corsika {
+
+  /**
+  * A tabulated refractive index.
+  *
+  * This class returns the value of refractive index
+  * for a specific height bin.
+   */
+  template <typename T>
+  class GladstoneDaleRefractiveIndex final : public T {
+
+    double const seaLevelRefractiveIndex_; ///< The constant refractive index at sea level.
+    MassDensityType const seaLevelDensity_; ///< The constant mass density at sea level.
+    Point const earthSurface_; ///< A point at earth's surface.
+//    MassDensityType ratio_; ///< (1 - seaLevelRefractiveIndex_) / seaLevelDensity_.
+
+  public:
+    /**
+    * Construct a GladstoneDaleRefractiveIndex.
+    *
+    * This is initialized with a fixed refractive index
+    * at sea level and uses the Gladstone-Dale law to
+    * calculate the refractive index at a given point.
+    *
+    * @param seaLevelRefractiveIndex  The refractive index at sea level.
+    * @param point AA point at earth's surface.
+     */
+    template <typename... Args>
+    GladstoneDaleRefractiveIndex(double const seaLevelRefractiveIndex, Point const point, Args&&... args);
+
+    /**
+    * Evaluate the refractive index at a given location.
+    *
+    * @param  point    The location to evaluate at.
+    * @returns    The refractive index at this point.
+     */
+    double getRefractiveIndex(Point const& point) const override;
+
+  }; // END: class GladstoneDaleRefractiveIndex
+
+} // namespace corsika
+
+#include <corsika/detail/media/GladstoneDaleRefractiveIndex.inl>
diff --git a/tests/media/testRefractiveIndex.cpp b/tests/media/testRefractiveIndex.cpp
index 63d1310f3..3a7bc077b 100644
--- a/tests/media/testRefractiveIndex.cpp
+++ b/tests/media/testRefractiveIndex.cpp
@@ -20,6 +20,7 @@
 #include <corsika/media/NuclearComposition.hpp>
 #include <corsika/media/UniformRefractiveIndex.hpp>
 #include <corsika/media/ExponentialRefractiveIndex.hpp>
+#include <corsika/media/GladstoneDaleRefractiveIndex.hpp>
 #include <corsika/media/CORSIKA7Atmospheres.hpp>
 
 #include <SetupTestTrajectory.hpp>
@@ -31,8 +32,11 @@ using namespace corsika;
 template <typename TInterface>
 using MyExtraEnv =
     ExponentialRefractiveIndex<MediumPropertyModel<UniformMagneticField<TInterface>>>;
+template <typename TInterface2>
+using MyExtraEnv2 =
+    GladstoneDaleRefractiveIndex<MediumPropertyModel<UniformMagneticField<TInterface2>>>;
 
-TEST_CASE("UniformRefractiveIndex w/ Homogeneous") {
+TEST_CASE("UniformRefractiveIndex w/ Homogeneous medium") {
 
   logging::set_level(logging::level::info);
 
@@ -40,7 +44,7 @@ TEST_CASE("UniformRefractiveIndex w/ Homogeneous") {
 
   Point const gOrigin(gCS, {0_m, 0_m, 0_m});
 
-  // setup our interface types
+  // set up our interface types
   using IModelInterface = IRefractiveIndexModel<IMediumModel>;
   using AtmModel = UniformRefractiveIndex<HomogeneousMedium<IModelInterface>>;
 
@@ -50,7 +54,7 @@ TEST_CASE("UniformRefractiveIndex w/ Homogeneous") {
   // the composition we use for the homogenous medium
   NuclearComposition const protonComposition({Code::Proton}, {1.});
 
-  // the refrative index that we use
+  // the refractive index that we use
   const double n{1.000327};
 
   // create the atmospheric model
@@ -213,3 +217,77 @@ TEST_CASE("ExponentialRefractiveIndex w/ 5-layered atmosphere") {
 
   CHECK(rIndex - n0 == Approx(0));
 }
+
+TEST_CASE("GladstoneDaleRefractiveIndex w/ Homogeneous medium") {
+
+  logging::set_level(logging::level::info);
+
+  // get a CS and a point
+  CoordinateSystemPtr const& gCS = get_root_CoordinateSystem();
+
+  Point const gOrigin(gCS, {0_m, 0_m, 0_m});
+
+  // setup interface types
+  using IModelInterface = IRefractiveIndexModel<IMediumModel>;
+  using AtmModel = GladstoneDaleRefractiveIndex<HomogeneousMedium<IModelInterface>>;
+
+  // the constant density
+  const auto density{19.2_g / cube(1_cm)};
+
+  // the composition we use for the homogenous medium
+  NuclearComposition const protonComposition({Code::Proton}, {1.});
+
+  // the refractive index at sea level
+  const double n0{1.000327};
+
+  // a point at the surface of the earth
+  Point const surface_{gCS, 0_m, 0_m, constants::EarthRadius::Mean};
+
+  // a random point in the atmosphere
+  Point const p1_{gCS, 1_km, 1_km, constants::EarthRadius::Mean + 10_km};
+
+  // create the atmospheric model and check refractive index
+  AtmModel medium(n0, surface_, density, protonComposition);
+
+  CHECK(n0 - medium.getRefractiveIndex(surface_) == Approx(0));
+  CHECK(n0 - medium.getRefractiveIndex(p1_) == Approx(0));
+
+}
+
+TEST_CASE("GladstoneDaleRefractiveIndex w/ 5-layered atmosphere") {
+
+  logging::set_level(logging::level::info);
+
+  // get a CS
+  CoordinateSystemPtr const& gCS = get_root_CoordinateSystem();
+
+  // the center of the earth
+  Point const center_{gCS, 0_m, 0_m, 0_m};
+
+  // a point at the surface of the earth
+  Point const surface_{gCS, 0_m, 0_m, constants::EarthRadius::Mean};
+
+  // the refractive index at sea level
+  const double n0{1.000327};
+
+  // a reference point to calculate the refractive index there
+  Point const ref_{gCS, 0_km, 0_km, constants::EarthRadius::Mean + 10_km};
+
+  // setup a 5-layered environment
+  using EnvironmentInterface =
+      IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
+  using EnvType = Environment<EnvironmentInterface>;
+  EnvType env;
+
+  create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv2>(
+      env, AtmosphereId::LinsleyUSStd, center_, n0, surface_,
+      Medium::AirDry1Atm, MagneticFieldVector{gCS, 0_T, 50_uT, 0_T});
+
+  // get the universe for this environment
+  auto const* const universe{env.getUniverse().get()};
+  auto const* node{universe->getContainingNode(ref_)};
+  // get the refractive index
+  auto const rIndex{node->getModelProperties().getRefractiveIndex(ref_)};
+
+//  CHECK(rIndex - n0 == Approx(0));
+}
\ No newline at end of file
-- 
GitLab