diff --git a/CMakeLists.txt b/CMakeLists.txt
index c436d8906e31f56c3d010e255736cc16c87a7050..5a38c4ecb422e5ea823f864deaf0df7acceb5ac9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ set (CMAKE_INSTALL_MESSAGE LAZY)
 set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
 include (CorsikaUtilities) # a few cmake function
 
-# --std=c++14
+# --std=c++17
 set (CMAKE_CXX_STANDARD 17)
 enable_testing ()
 set (CTEST_OUTPUT_ON_FAILURE 1)
diff --git a/Framework/Geometry/BaseTrajectory.h b/Framework/Geometry/BaseTrajectory.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec5e4062cfe2be63d1f7be83bdb4a3e02cc1d596
--- /dev/null
+++ b/Framework/Geometry/BaseTrajectory.h
@@ -0,0 +1,23 @@
+#ifndef _include_BASETRAJECTORY_H
+#define _include_BASETRAJECTORY_H
+
+#include <corsika/geometry/Point.h>
+#include <corsika/geometry/Vector.h>
+#include <corsika/units/PhysicalUnits.h>
+#include <string>
+
+namespace corsika::geometry {
+
+  /*!
+   * Base class for trajectories.
+   */
+  class BaseTrajectory {
+
+  public:
+    //!< t for \f$ t = 0 \f$, the starting Point shall be returned.
+    virtual Point GetPosition(corsika::units::TimeType t) const = 0;
+  };
+
+} // namespace corsika::geometry
+
+#endif
diff --git a/Framework/Geometry/CMakeLists.txt b/Framework/Geometry/CMakeLists.txt
index 36fab64cc742c8eb292ccb2420b0e7f3f6bebbd3..a4fc43cb3364881d7f3e42939b0985b69df4afab 100644
--- a/Framework/Geometry/CMakeLists.txt
+++ b/Framework/Geometry/CMakeLists.txt
@@ -13,7 +13,9 @@ set (
   Helix.h
   BaseVector.h
   QuantityVector.h
+  BaseTrajectory.h
   LineTrajectory.h
+  Trajectory.h
   )
 
 set (
diff --git a/Framework/Geometry/Helix.h b/Framework/Geometry/Helix.h
index ca97fa8bf8c4100cb9031607485ce291c76a636e..29bb49438f23387413094c8319486db8eea67e70 100644
--- a/Framework/Geometry/Helix.h
+++ b/Framework/Geometry/Helix.h
@@ -1,31 +1,38 @@
 #ifndef _include_HELIX_H_
 #define _include_HELIX_H_
 
+#include <corsika/geometry/BaseTrajectory.h>
 #include <corsika/geometry/Point.h>
 #include <corsika/geometry/Vector.h>
 #include <corsika/units/PhysicalUnits.h>
 #include <cmath>
 
 namespace corsika::geometry {
+  /*!
+   * A Helix is defined by the cyclotron frequency \f$ \omega_c \f$, the initial
+   * Point r0 and
+   * the velocity vectors \f$ \vec{v}_{\parallel} \f$ and \f$ \vec{v}_{\perp} \f$
+   * denoting the projections of the initial velocity \f$ \vec{v}_0 \f$ parallel
+   * and perpendicular to the axis \f$ \vec{B} \f$, respectively, i.e.
+   * \f{align*}{
+        \vec{v}_{\parallel} &= \frac{\vec{v}_0 \cdot \vec{B}}{\vec{B}^2} \vec{B} \\
+        \vec{v}_{\perp} &= \vec{v}_0 - \vec{v}_{\parallel}
+     \f}
+   */
+
+  class Helix : public BaseTrajectory {
+    using VelocityVec = Vector<corsika::units::SpeedType::dimension_type>;
 
-  using corsika::units::frequency_d;
-  using corsika::units::FrequencyType;
-  using corsika::units::quantity;
-  using corsika::units::SpeedType;
-  using corsika::units::TimeType;
-
-  class Helix // TODO: inherit from to-be-implemented "Trajectory"
-  {
-    using SpeedVec = Vector<SpeedType::dimension_type>;
     Point const r0;
-    FrequencyType const omegaC;
-    SpeedVec const vPar;
-    SpeedVec vPerp, uPerp;
-    LengthType const radius;
+    corsika::units::FrequencyType const omegaC;
+    VelocityVec const vPar;
+    VelocityVec const vPerp, uPerp;
+
+    corsika::units::LengthType const radius;
 
   public:
-    Helix(Point const& pR0, quantity<frequency_d> pOmegaC, SpeedVec const& pvPar,
-          SpeedVec const& pvPerp)
+    Helix(Point const& pR0, corsika::units::FrequencyType pOmegaC,
+          VelocityVec const& pvPar, VelocityVec const& pvPerp)
         : r0(pR0)
         , omegaC(pOmegaC)
         , vPar(pvPar)
@@ -33,7 +40,7 @@ namespace corsika::geometry {
         , uPerp(vPerp.cross(vPar.normalized()))
         , radius(pvPar.norm() / abs(pOmegaC)) {}
 
-    auto GetPosition(TimeType t) const {
+    Point GetPosition(corsika::units::TimeType t) const {
       return r0 + vPar * t +
              (vPerp * (cos(omegaC * t) - 1) + uPerp * sin(omegaC * t)) / omegaC;
     }
diff --git a/Framework/Geometry/LineTrajectory.h b/Framework/Geometry/LineTrajectory.h
index fc550d4bdd87c63af1bb307721ba4b675e245c57..556da4642c52689c492fbd619863a3bfc0729d99 100644
--- a/Framework/Geometry/LineTrajectory.h
+++ b/Framework/Geometry/LineTrajectory.h
@@ -1,25 +1,25 @@
 #ifndef _include_LINETRAJECTORY_H
 #define _include_LINETRAJECTORY_H
 
+#include <corsika/geometry/BaseTrajectory.h>
 #include <corsika/geometry/Point.h>
 #include <corsika/geometry/Vector.h>
 #include <corsika/units/PhysicalUnits.h>
 
 namespace corsika::geometry {
 
-  class LineTrajectory // TODO: inherit from Trajectory
-  {
-    using SpeedVec = Vector<corsika::units::SpeedType::dimension_type>;
+  class LineTrajectory : public BaseTrajectory {
+    using VelocityVec = Vector<corsika::units::SpeedType::dimension_type>;
 
     Point const r0;
-    SpeedVec const v0;
+    VelocityVec const v0;
 
   public:
-    LineTrajectory(Point const& pR0, SpeedVec const& pV0)
-        : r0(r0)
+    LineTrajectory(Point const& pR0, VelocityVec const& pV0)
+        : r0(pR0)
         , v0(pV0) {}
 
-    auto GetPosition(corsika::units::TimeType t) const { return r0 + v0 * t; }
+    Point GetPosition(corsika::units::TimeType t) const override { return r0 + v0 * t; }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/QuantityVector.h b/Framework/Geometry/QuantityVector.h
index c5af419ee4df97ec731a7fb0c95123fc2c843de5..671a6856092a0811aaf5d407ef68b0f7fbd37e4f 100644
--- a/Framework/Geometry/QuantityVector.h
+++ b/Framework/Geometry/QuantityVector.h
@@ -101,6 +101,8 @@ namespace corsika {
     auto& operator-() const { return QuantityVector<dim>(-eVector); }
 
     auto normalized() const { return (*this) * (1 / norm()); }
+
+    auto operator==(QuantityVector<dim> const& p) const { return eVector == p.eVector; }
   };
 
 } // end namespace corsika
diff --git a/Framework/Geometry/Sphere.h b/Framework/Geometry/Sphere.h
index 552dfde6f1341a7c0bbfb3903e27c8fbab5e1e05..28b4e7dc63d5ded1ecd6d047df442af4557e4f20 100644
--- a/Framework/Geometry/Sphere.h
+++ b/Framework/Geometry/Sphere.h
@@ -15,6 +15,7 @@ namespace corsika::geometry {
         : center(pCenter)
         , radius(pRadius) {}
 
+    //! returns true if the Point p is within the sphere
     auto isInside(Point const& p) const {
       return radius * radius > (center - p).squaredNorm();
     }
diff --git a/Framework/Geometry/Trajectory.h b/Framework/Geometry/Trajectory.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a640cacd027510a64d0c574c48e66dbe11fd1d9
--- /dev/null
+++ b/Framework/Geometry/Trajectory.h
@@ -0,0 +1,31 @@
+#ifndef _include_TRAJECTORY_H
+#define _include_TRAJECTORY_H
+
+#include <corsika/geometry/BaseTrajectory.h>
+#include <corsika/units/PhysicalUnits.h>
+
+namespace corsika::geometry {
+
+  class Trajectory {
+    corsika::units::TimeType const fTStart, fTEnd;
+    BaseTrajectory const& fTrajectory;
+
+  public:
+    Trajectory(corsika::units::TimeType pTStart, corsika::units::TimeType pTEnd,
+               BaseTrajectory const& pTrajectory)
+        : fTStart(pTStart)
+        , fTEnd(pTEnd)
+        , fTrajectory(pTrajectory) {}
+
+    Point GetPosition(corsika::units::TimeType t) const {
+      return fTrajectory.GetPosition(t + fTStart);
+    }
+
+    Point GetPosition(double u) const {
+      return GetPosition(fTEnd * u + fTStart * (1 - u));
+    }
+  };
+
+} // namespace corsika::geometry
+
+#endif
diff --git a/Framework/Geometry/testGeometry.cc b/Framework/Geometry/testGeometry.cc
index a2f5181dc6f837b8608563541c3b6cca80b29248..469d2dec68643215ac7a0d33bb55edbee3e211ad 100644
--- a/Framework/Geometry/testGeometry.cc
+++ b/Framework/Geometry/testGeometry.cc
@@ -2,19 +2,166 @@
                           // cpp file
 #include <catch2/catch.hpp>
 
+#include <corsika/geometry/CoordinateSystem.h>
+#include <corsika/geometry/Helix.h>
+#include <corsika/geometry/LineTrajectory.h>
+#include <corsika/geometry/Point.h>
+#include <corsika/geometry/Sphere.h>
+#include <corsika/geometry/Trajectory.h>
 #include <corsika/units/PhysicalUnits.h>
+#include <cmath>
 
-using namespace phys::units;
-using namespace phys::units::literals;
+using namespace corsika::geometry;
+using namespace corsika::units;
 
-TEST_CASE("Geometry", "[Geometry]") {
-  SECTION("Coordinate Systems") {}
+double constexpr absMargin = 1.0e-8;
+;
 
-  SECTION("Point") {}
+TEST_CASE("transformations between CoordinateSystems") {
+  CoordinateSystem rootCS;
 
-  SECTION("Vector") {}
+  REQUIRE(CoordinateSystem::GetTransformation(rootCS, rootCS)
+              .isApprox(EigenTransform::Identity()));
 
-  SECTION("Helix") {}
+  corsika::QuantityVector<length_d> const coordinates{0_m, 0_m, 0_m};
+  Point p1(rootCS, coordinates);
 
-  SECTION("Line") {}
+  corsika::QuantityVector<magnetic_flux_density_d> components{1. * tesla, 0. * tesla,
+                                                              0. * tesla};
+  Vector<magnetic_flux_density_d> v1(rootCS, components);
+
+  REQUIRE((p1.GetCoordinates() - coordinates).norm().magnitude() ==
+          Approx(0).margin(absMargin));
+  REQUIRE((p1.GetCoordinates(rootCS) - coordinates).norm().magnitude() ==
+          Approx(0).margin(absMargin));
+
+  SECTION("unconnected CoordinateSystems") {
+    CoordinateSystem rootCS2;
+    REQUIRE_THROWS(CoordinateSystem::GetTransformation(rootCS, rootCS2));
+  }
+
+  SECTION("translations") {
+    corsika::QuantityVector<length_d> const translationVector{0_m, 4_m, 0_m};
+
+    CoordinateSystem translatedCS = rootCS.translate(translationVector);
+
+    REQUIRE(translatedCS.GetReference() == &rootCS);
+
+    REQUIRE((p1.GetCoordinates(translatedCS) + translationVector).norm().magnitude() ==
+            Approx(0).margin(absMargin));
+
+    // Vectors are not subject to translations
+    REQUIRE(
+        (v1.GetComponents(rootCS) - v1.GetComponents(translatedCS)).norm().magnitude() ==
+        Approx(0).margin(absMargin));
+
+    Point p2(translatedCS, {0_m, 0_m, 0_m});
+    REQUIRE(((p2 - p1).GetComponents() - translationVector).norm().magnitude() ==
+            Approx(0).margin(absMargin));
+  }
+
+  SECTION("multiple translations") {
+    corsika::QuantityVector<length_d> const tv1{0_m, 5_m, 0_m};
+    CoordinateSystem cs2 = rootCS.translate(tv1);
+
+    corsika::QuantityVector<length_d> const tv2{3_m, 0_m, 0_m};
+    CoordinateSystem cs3 = rootCS.translate(tv2);
+
+    corsika::QuantityVector<length_d> const tv3{0_m, 0_m, 2_m};
+    CoordinateSystem cs4 = cs3.translate(tv3);
+
+    REQUIRE(cs4.GetReference()->GetReference() == &rootCS);
+
+    REQUIRE(CoordinateSystem::GetTransformation(cs3, cs2).isApprox(
+        rootCS.translate({3_m, -5_m, 0_m}).GetTransform()));
+    REQUIRE(CoordinateSystem::GetTransformation(cs2, cs3).isApprox(
+        rootCS.translate({-3_m, +5_m, 0_m}).GetTransform()));
+  }
+
+  SECTION("rotations") {
+    corsika::QuantityVector<length_d> const axis{0_m, 0_m, 1_km};
+    double const angle = 90. / 180. * M_PI;
+
+    CoordinateSystem rotatedCS = rootCS.rotate(axis, angle);
+    REQUIRE(rotatedCS.GetReference() == &rootCS);
+
+    REQUIRE(v1.GetComponents(rotatedCS)[1].magnitude() ==
+            Approx((-1. * tesla).magnitude()));
+
+    // vector norm invariant under rotation
+    REQUIRE(v1.GetComponents(rotatedCS).norm().magnitude() ==
+            Approx(v1.GetComponents(rootCS).norm().magnitude()));
+  }
+
+  SECTION("multiple rotations") {
+    corsika::QuantityVector<length_d> const zAxis{0_m, 0_m, 1_km};
+    corsika::QuantityVector<length_d> const yAxis{0_m, 7_nm, 0_m};
+    corsika::QuantityVector<length_d> const xAxis{2_m, 0_nm, 0_m};
+
+    double const angle = 90. / 180. * M_PI;
+
+    CoordinateSystem rotated1 = rootCS.rotate(zAxis, angle);
+    CoordinateSystem rotated2 = rotated1.rotate(yAxis, angle);
+    CoordinateSystem rotated3 = rotated2.rotate(zAxis, -angle);
+
+    CoordinateSystem combined = rootCS.rotate(xAxis, -angle);
+
+    auto comp1 = v1.GetComponents(rootCS);
+    auto comp3 = v1.GetComponents(combined);
+    REQUIRE((comp1 - comp3).norm().magnitude() == Approx(0).margin(absMargin));
+  }
+}
+
+TEST_CASE("Sphere") {
+  CoordinateSystem rootCS;
+  Point center(rootCS, {0_m, 3_m, 4_m});
+  Sphere sphere(center, 5_m);
+
+  SECTION("isInside") {
+    REQUIRE_FALSE(sphere.isInside(Point(rootCS, {100_m, 0_m, 0_m})));
+    REQUIRE(sphere.isInside(Point(rootCS, {2_m, 3_m, 4_m})));
+  }
+}
+
+TEST_CASE("Trajectories") {
+  CoordinateSystem rootCS;
+  Point r0(rootCS, {0_m, 0_m, 0_m});
+
+  SECTION("Line") {
+    Vector<SpeedType::dimension_type> v0(rootCS,
+                                         {1_m / second, 0_m / second, 0_m / second});
+
+    LineTrajectory const lineTrajectory(r0, v0);
+    CHECK((lineTrajectory.GetPosition(2_s).GetCoordinates() -
+           corsika::QuantityVector<length_d>(2_m, 0_m, 0_m))
+              .norm()
+              .magnitude() == Approx(0).margin(absMargin));
+
+    BaseTrajectory const* base = &lineTrajectory;
+    CHECK(lineTrajectory.GetPosition(2_s).GetCoordinates() ==
+          base->GetPosition(2_s).GetCoordinates());
+  }
+
+  SECTION("Helix") {
+    Vector<SpeedType::dimension_type> const vPar(
+        rootCS, {0_m / second, 0_m / second, 4_m / second}),
+        vPerp(rootCS, {1_m / second, 0_m / second, 0_m / second});
+    auto const omegaC = 2 * M_PI / 1_s;
+
+    Helix const helix(r0, omegaC, vPar, vPerp);
+
+    CHECK((helix.GetPosition(1_s).GetCoordinates() -
+           corsika::QuantityVector<length_d>(0_m, 0_m, 4_m))
+              .norm()
+              .magnitude() == Approx(0).margin(absMargin));
+
+    CHECK((helix.GetPosition(0.25_s).GetCoordinates() -
+           corsika::QuantityVector<length_d>(-1_m / (2 * M_PI), -1_m / (2 * M_PI), 1_m))
+              .norm()
+              .magnitude() == Approx(0).margin(absMargin));
+
+    BaseTrajectory const* base = &helix;
+    CHECK(helix.GetPosition(1234_s).GetCoordinates() ==
+          base->GetPosition(1234_s).GetCoordinates());
+  }
 }
diff --git a/Framework/Particles/ParticleClassNames.xml b/Framework/Particles/ParticleClassNames.xml
index 98772d67e38f568a91cf1dea6cc4dc91198e4bb4..2c909fb1ae904e9f22d3af0da1682ef842aee54b 100644
--- a/Framework/Particles/ParticleClassNames.xml
+++ b/Framework/Particles/ParticleClassNames.xml
@@ -3,20 +3,20 @@
   <!-- For selected particles it is possible to specify the C++ class
        names for a specific unique PDG code -->
   
-  <particle id="0" classname="unknown"> </particle> <!-- VOID in Pythia8 -->
+  <particle pdgID="0" classname="unknown"/> <!-- VOID in Pythia8 -->
   
-  <particle id="11" classname="Electron"> </particle>
-  <particle id="-11" classname="Positron"> </particle>
-  <particle id="22" classname="Gamma"> </particle>
+  <particle pdgID="11" classname="Electron"/>
+  <particle pdgID="-11" classname="Positron"/>
+  <particle pdgID="22" classname="Gamma"/>
 
-  <particle id="130" classname="K0Long"> </particle>
-  <particle id="310" classname="K0Short"> </particle>
+  <particle pdgID="130" classname="K0Long"/>
+  <particle pdgID="310" classname="K0Short"/>
 
-  <particle id="2112" classname="Neutron"> </particle>
-  <particle id="-2112" classname="AntiNeutron"> </particle>
+  <particle pdgID="2112" classname="Neutron"/>
+  <particle pdgID="-2112" classname="AntiNeutron"/>
 
-  <particle id="2212" classname="Proton"> </particle>
-  <particle id="-2212" classname="AntiProton"> </particle>
+  <particle pdgID="2212" classname="Proton"/>
+  <particle pdgID="-2212" classname="AntiProton"/>
 
 </chapter>
 
diff --git a/Framework/Particles/ParticleProperties.h b/Framework/Particles/ParticleProperties.h
index 7df92b661d891cf252cbef52205e1818e71a834d..23ef2369886f8b102f973c89dd921c0aab731e28 100644
--- a/Framework/Particles/ParticleProperties.h
+++ b/Framework/Particles/ParticleProperties.h
@@ -4,15 +4,16 @@
    Interface to particle properties
  */
 
-#ifndef _include_Particle_h_
-#define _include_Particle_h_
+#ifndef _include_ParticleProperties_h_
+#define _include_ParticleProperties_h_
 
 #include <array>
 #include <cstdint>
 #include <iostream>
+#include <type_traits>
 
+#include <corsika/units/PhysicalConstants.h>
 #include <corsika/units/PhysicalUnits.h>
-#include <corsika/particles/GeneratedParticleProperties.inc>
 
 /**
  * @namespace particle
@@ -23,31 +24,50 @@
  */
 
 namespace corsika::particles {
+  enum class Code : int16_t;
+
+  using PDGCodeType = int16_t;
+  using CodeIntType = std::underlying_type<Code>::type;
+
+  // forward declarations to be used in GeneratedParticleProperties
+  int16_t constexpr GetElectricChargeNumber(Code const);
+  corsika::units::ElectricChargeType constexpr GetElectricCharge(Code const);
+  corsika::units::MassType constexpr GetMass(Code const);
+  PDGCodeType constexpr GetPDG(Code const);
+  std::string const GetName(Code const);
+
+#include <corsika/particles/GeneratedParticleProperties.inc>
 
-  /**
-   * @function GetMass
-   *
-   * return mass of particle
+  /*!
+   * returns mass of particle
    */
-  auto constexpr GetMass(Code const p) { return masses[static_cast<uint8_t const>(p)]; }
+  corsika::units::MassType constexpr GetMass(Code const p) {
+    return masses[static_cast<CodeIntType const>(p)];
+  }
 
-  auto constexpr GetPDG(Code const p) { return pdg_codes[static_cast<uint8_t const>(p)]; }
+  PDGCodeType constexpr GetPDG(Code const p) {
+    return pdg_codes[static_cast<CodeIntType const>(p)];
+  }
 
-  auto constexpr GetElectricChargeNumber(Code const p) {
-    return electric_charge[static_cast<uint8_t const>(p)] / 3;
+  /*!
+   * returns electric charge of particle / (e/3).
+   */
+  int16_t constexpr GetElectricChargeNumber(Code const p) {
+    return electric_charges[static_cast<CodeIntType const>(p)];
   }
 
-  auto constexpr GetElectricCharge(Code const p) {
-    return GetElectricChargeNumber(p) * (corsika::units::constants::e);
+  corsika::units::ElectricChargeType constexpr GetElectricCharge(Code const p) {
+    return GetElectricChargeNumber(p) * (corsika::units::constants::e / 3.);
   }
 
-  auto const GetName(Code const p) { return names[static_cast<uint8_t const>(p)]; }
+  std::string const GetName(Code const p) {
+    return names[static_cast<CodeIntType const>(p)];
+  }
 
   namespace io {
 
     std::ostream& operator<<(std::ostream& stream, Code const p) {
-      stream << GetName(p);
-      return stream;
+      return stream << GetName(p);
     }
 
   } // namespace io
diff --git a/Framework/Particles/pdxml_reader.py b/Framework/Particles/pdxml_reader.py
index 46958ea055785689515d4cb6aa6a127dbe125a7d..4c271e8fbbcf4b8030b7f6df86f6ae8831681f83 100755
--- a/Framework/Particles/pdxml_reader.py
+++ b/Framework/Particles/pdxml_reader.py
@@ -51,7 +51,7 @@ def class_names(filename):
     
     for particle in root.iter("particle"):
         name = particle.attrib["classname"]
-        pdg_id = int(particle.attrib["id"])
+        pdg_id = int(particle.attrib["pdgID"])
         map[pdg_id] = name
         
     return map 
@@ -97,9 +97,10 @@ def c_identifier(name):
 # 
 # This function produces names of type "DeltaPlusPlus"
 # 
-def c_identifier_cammel(name):
+def c_identifier_camel(name):
     orig = name
     name = name[0].upper() + name[1:].lower() # all lower case
+    
     for c in "() /": # replace funny characters
         name = name.replace(c, "_")
     
@@ -111,9 +112,9 @@ def c_identifier_cammel(name):
 
     # move "Bar" to end of name
     ibar = name.find('Bar')
-    if (ibar>0 and ibar<len(name)-3) :
+    if ibar > 0 and ibar < len(name)-3:
         name = name[:ibar] + name[ibar+3:] + str('Bar')
-            
+    
     # cleanup "_"s
     while True:
         tmp = name.replace("__", "_")
@@ -127,18 +128,18 @@ def c_identifier_cammel(name):
     istart = 0
     while True:
         i = name.find('_', istart)
-        if (i<1 or i>len(name)-1):
+        if i < 1 or i > len(name)-1:
             break
         istart = i
-        if (name[i-1].isdigit() and name[i+1].isdigit()):
+        if name[i-1].isdigit() and name[i+1].isdigit():
             # there is a number on both sides
             break
         name = name[:i] + name[i+1:]
         # and last, for example: make NuE out of Nue
-        if (name[i-1].islower() and name[i].islower()) :
-            if (i<len(name)-1) :
+        if name[i-1].islower() and name[i].islower():
+            if i < len(name)-1:
                 name = name[:i] + name[i].upper() + name[i+1:]
-            else :
+            else:
                 name = name[:i] + name[i].upper()
 
     # check if name is valid C++ identifier
@@ -146,27 +147,25 @@ def c_identifier_cammel(name):
     if pattern.match(name):
         return name
     else:
-        raise Exception("could not generate C identifier for '{:s}' name='{:s}'".format(orig, name))
+        raise Exception("could not generate C identifier for '{:s}': result '{:s}'".format(orig, name))
 
 
     
-# ########################################################
+##########################################################
 # 
 # returns dict containing all data from pythia-xml input
 # 
     
 def build_pythia_db(filename, classnames):    
-    particle_db = OrderedDict()    
+    particle_db = OrderedDict()
     for (pdg, name, mass, electric_charge, antiName) in parse(filename):
 
         c_id = "unknown"
-        if (pdg in classnames):
+        if pdg in classnames:
             c_id = classnames[pdg]
         else:
-            c_id = c_identifier_cammel(name) # the cammel case names
+            c_id = c_identifier_camel(name) # the camel case names
         
-        #~ print(name, c_id, sep='\t', file=sys.stderr)
-        #~ enums += "{:s} = {:d}, ".format(c_id, corsika_id)
         particle_db[c_id] = {
             "name" : name,
             "antiName" : antiName,
@@ -186,17 +185,20 @@ def build_pythia_db(filename, classnames):
 # 
 
 def gen_internal_enum(pythia_db):
-    string = "enum class Code : uint8_t {\n"
-
-    string += "  FirstParticle = 1, // if you want to loop over particles, you want to start with \"1\"  \n" # identifier for eventual loops...
-    last_ngc_id = 0 
+    string = ("enum class Code : int16_t {\n"
+              "  FirstParticle = 1, // if you want to loop over particles, you want to start with \"1\"  \n") # identifier for eventual loops...
+    
+    
     for k in filter(lambda k: "ngc_code" in pythia_db[k], pythia_db):
         last_ngc_id = pythia_db[k]['ngc_code']
         string += "  {key:s} = {code:d},\n".format(key = k, code = last_ngc_id)
 
-    string += "  LastParticle = " + str(last_ngc_id+1) + ",\n" # identifier for eventual loops...
+    string += ("  LastParticle = {:d},\n" # identifier for eventual loops...
+               "}};").format(last_ngc_id + 1)
+               
+    if last_ngc_id > 0x7fff: # does not fit into int16_t
+        raise Exception("Integer overflow in internal particle code definition prevented!")
     
-    string += "};"
     return string
 
 
@@ -214,13 +216,13 @@ def gen_properties(pythia_db):
     string += "\n"
     
     # particle masses table
-    string += "static constexpr std::array<quantity<energy_d> const, size> masses = {\n"    
+    string += "static constexpr std::array<corsika::units::MassType const, size> masses = {\n"    
     for p in pythia_db.values():
-        string += "  {mass:f}_GeV, // {name:s}\n".format(mass = p['mass'], name = p['name'])              
+        string += "  {mass:f} * (1e9 * corsika::units::constants::eV / corsika::units::constants::cSquared), // {name:s}\n".format(mass = p['mass'], name = p['name'])              
     string += "};\n\n"
                    
     # PDG code table
-    string += "static constexpr std::array<PDGCode const, size> pdg_codes = {\n"
+    string += "static constexpr std::array<PDGCodeType const, size> pdg_codes = {\n"
     for p in pythia_db.values():
         string += "  {pdg:d}, // {name:s}\n".format(pdg = p['pdg'], name = p['name'])    
     string += "};\n"
@@ -232,7 +234,7 @@ def gen_properties(pythia_db):
     string += "};\n"
     
     # electric charges table
-    string += "static constexpr std::array<int16_t, size> electric_charge = {\n"
+    string += "static constexpr std::array<int16_t, size> electric_charges = {\n"
     for p in pythia_db.values():
         string += "  {charge:d},\n".format(charge = p['electric_charge'])
     string += "};\n"
@@ -269,23 +271,23 @@ def gen_classes(pythia_db):
         string += "/** @class " + cname + "\n\n"
         string += " * Particle properties are taken from the PYTHIA8 ParticleData.xml file:<br>\n"
         string += " *  - pdg=" + str(pythia_db[cname]['pdg']) +"\n"
-        string += " *  - mass=" + str(pythia_db[cname]['mass']) + " GeV \n"
+        string += " *  - mass=" + str(pythia_db[cname]['mass']) + " GeV/c² \n"
         string += " *  - charge= " + str(pythia_db[cname]['electric_charge']/3) + " \n"
         string += " *  - name=" + str(cname) + "\n"
         string += " *  - anti=" + str(antiP) + "\n"
         string += "*/\n\n"
-        string += "class " + cname + "{\n"
+        string += "class " + cname + " {\n"
         string += "  public:\n"
-        string += "   static Code GetCode() { return Type; }\n"
-        string += "   static quantity<energy_d> GetMass() { return masses[TypeIndex]; }\n"
-        string += "   static quantity<electric_charge_d> GetCharge() { return corsika::units::constants::e*electric_charge[TypeIndex]/3; }\n"
-        string += "   static int GetChargeNumber() { return electric_charge[TypeIndex]/3; }\n"
-        string += "   static std::string GetName() { return names[TypeIndex]; }\n"
-        string += "   static Code GetAntiParticle() { return AntiType; }\n"
-        string += "   static const Code Type = Code::" + cname + ";\n"
-        string += "   static const Code AntiType = Code::" + antiP + ";\n"
+        string += "   static constexpr Code GetCode() { return Type; }\n"
+        string += "   static constexpr corsika::units::MassType GetMass() { return corsika::particles::GetMass(Type); }\n"
+        string += "   static constexpr corsika::units::ElectricChargeType GetCharge() { return corsika::particles::GetElectricCharge(Type); }\n"
+        string += "   static constexpr int16_t GetChargeNumber() { return corsika::particles::GetElectricChargeNumber(Type); }\n"
+        string += "   static std::string const GetName() { return corsika::particles::GetName(Type); }\n"
+        string += "   static constexpr Code GetAntiParticle() { return AntiType; }\n"
+        string += "   static constexpr Code Type = Code::" + cname + ";\n"
+        string += "   static constexpr Code AntiType = Code::" + antiP + ";\n"
         string += " private:\n"
-        string += "   static const uint8_t TypeIndex = static_cast<uint8_t const>(Type);\n"
+        string += "   static constexpr CodeIntType TypeIndex = static_cast<CodeIntType const>(Type);\n"
         string += "};\n"
 
     return string
@@ -296,22 +298,8 @@ def gen_classes(pythia_db):
 # 
 
 def inc_start():
-    string = ""
-    string += "#ifndef _include_GeneratedParticleDataTable_h_\n"
-    string += "#define _include_GeneratedParticleDataTable_h_\n\n"
-    string += "#include <corsika/units/PhysicalUnits.h>\n"
-    string += "#include <corsika/units/PhysicalConstants.h>\n"
-    string += "#include <array>\n"
-    string += "#include <cstdint>\n"
-#    string += "#include <iostream>\n\n"
-    string += "namespace corsika { \n\n"
-#    string += "using namespace literals; \n"
-    string += "namespace particles { \n\n"
-    string += "using corsika::units::energy_d;\n"
-    string += "using corsika::units::electric_charge_d;\n"
-    string += "using corsika::units::quantity;\n"
-    string += "using corsika::units::operator\"\"_GeV;\n"
-    string += "typedef int16_t PDGCode;\n\n"
+    string = ('// generated by pdxml_reader.py\n'
+              '// MANUAL EDITS ON OWN RISK\n')
     return string
 
 
@@ -321,9 +309,6 @@ def inc_start():
 
 def inc_end():
     string = ""
-    string += "\n}\n\n"
-    string += "\n}\n\n"
-    string += "#endif\n"
     return string
 
 
@@ -334,14 +319,14 @@ def inc_end():
 
 if __name__ == "__main__":
 
-    if (len(sys.argv)!=3) :
-        print ("pdxml_reader.py Pythia8.xml ClassNames.xml")
-        sys.exit(0)
+    if len(sys.argv) != 3:
+        print("usage: {:s} <Pythia8.xml> <ClassNames.xml>".format(sys.argv[0]))
+        sys.exit(1)
         
     names = class_names(sys.argv[2])
     pythia_db = build_pythia_db(sys.argv[1], names)
 
-    print ("\n       pdxml_reader.py: Automatically produce particle-properties from PYTHIA8 xml file\n")
+    print("\n       pdxml_reader.py: Automatically produce particle-properties from PYTHIA8 xml file\n")
     
     counter = itertools.count(0)
     
diff --git a/Framework/Particles/testParticles.cc b/Framework/Particles/testParticles.cc
index 476264171bb8be56f715f0eee3ee9fe74f77116b..a04f36515c720c6f55938238c5a42f685b527f99 100644
--- a/Framework/Particles/testParticles.cc
+++ b/Framework/Particles/testParticles.cc
@@ -14,7 +14,7 @@ TEST_CASE("Particles", "[Particles]") {
   SECTION("Types") { REQUIRE(Electron::GetCode() == Code::Electron); }
 
   SECTION("Data") {
-    REQUIRE(Electron::GetMass() / 0.511_MeV == Approx(1));
+    REQUIRE(Electron::GetMass() / (511_keV / constants::cSquared) == Approx(1));
     REQUIRE(Electron::GetMass() / GetMass(Code::Electron) == Approx(1));
     REQUIRE(Electron::GetCharge() / constants::e == Approx(-1));
     REQUIRE(Positron::GetCharge() / constants::e == Approx(+1));
diff --git a/Framework/Units/PhysicalConstants.h b/Framework/Units/PhysicalConstants.h
index a666f15ef3bfc61d7abfb589a9763597db4f7d62..5c1b3a91c8bce590416b1889e1021a3e00dcfca9 100644
--- a/Framework/Units/PhysicalConstants.h
+++ b/Framework/Units/PhysicalConstants.h
@@ -39,16 +39,17 @@ namespace corsika::units::constants {
   // Avogadro constant
   constexpr quantity<dimensions<0, 0, 0, 0, 0, -1> > N_sub_A{Rep(6.02214199e+23L) / mole};
   // electronvolt
-  constexpr quantity<energy_d> eV{Rep(1.60217733e-19L) * joule};
+  constexpr quantity<energy_d> eV{Rep(1.6021766208e-19L) * joule};
 
   // elementary charge
-  constexpr quantity<electric_charge_d> e{Rep(1.602176462e-19L) * coulomb};
+  constexpr quantity<electric_charge_d> e{Rep(1.6021766208e-19L) * coulomb};
 
   // Planck constant
   constexpr quantity<dimensions<2, 1, -1> > h{Rep(6.62606876e-34L) * joule * second};
 
   // speed of light in a vacuum
   constexpr quantity<speed_d> c{Rep(299792458L) * meter / second};
+  constexpr auto cSquared = c * c;
 
   // unified atomic mass unit
   constexpr quantity<mass_d> u{Rep(1.6605402e-27L) * kilogram};
diff --git a/Framework/Units/PhysicalUnits.h b/Framework/Units/PhysicalUnits.h
index 91f8161637a8a84b34e3218e54ff4a9165f2ecf9..c1cf07bb9c05e4b74ff26e7ad4da48d1a22e5ca1 100644
--- a/Framework/Units/PhysicalUnits.h
+++ b/Framework/Units/PhysicalUnits.h
@@ -25,7 +25,6 @@ namespace phys {
 } // namespace phys
 
 namespace corsika::units {
-
   using namespace phys::units;
   using namespace phys::units::literals;
   // namespace literals = phys::units::literals;
@@ -37,6 +36,7 @@ namespace corsika::units {
   using ElectricChargeType =
       phys::units::quantity<phys::units::electric_charge_d, double>;
   using EnergyType = phys::units::quantity<phys::units::energy_d, double>;
+  using MassType = phys::units::quantity<phys::units::mass_d, double>;
 
 } // end namespace corsika::units