diff --git a/CMakeLists.txt b/CMakeLists.txt
index a04d2acbb9eeca7ef29f2e45091be5bc652a5a70..ad72d64fd53f581ba66d7aad0c836f3db1d42a5d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,7 @@ find_package (Eigen3 REQUIRED)
 # order of subdirectories 
 add_subdirectory (ThirdParty)
 add_subdirectory (Framework)
+add_subdirectory (Environment)
 add_subdirectory (Stack)
 add_subdirectory (Processes)
 add_subdirectory (Documentation)
diff --git a/Environment/CMakeLists.txt b/Environment/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c69ef36554cf8209b9f186200be47f26c8dd3e68
--- /dev/null
+++ b/Environment/CMakeLists.txt
@@ -0,0 +1,51 @@
+set (
+  ENVIRONMENT_HEADERS
+  VolumeTreeNode.h
+  IMediumModel.h
+  NuclearComposition.h
+  HomogeneousMedium.h
+  )
+
+set (
+  ENVIRONMENT_NAMESPACE
+  corsika/environment
+  )
+
+add_library (CORSIKAenvironment INTERFACE)
+CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKAenvironment ${ENVIRONMENT_NAMESPACE} ${ENVIRONMENT_HEADERS})
+
+# target dependencies on other libraries (also the header onlys)
+target_link_libraries (
+  CORSIKAenvironment
+  INTERFACE
+  CORSIKAgeometry
+  CORSIKAparticles
+  CORSIKAunits
+  )
+
+target_include_directories (
+  CORSIKAenvironment
+  INTERFACE
+  $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
+  $<INSTALL_INTERFACE:include>
+  )
+
+install (
+  TARGETS CORSIKAenvironment
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+  PUBLIC_HEADER DESTINATION include/${ENVIRONMENT_NAMESPACE}
+  )
+
+# --------------------
+# code unit testing
+add_executable (testEnvironment testEnvironment.cc)
+
+target_link_libraries (
+  testEnvironment
+  CORSIKAenvironment
+  CORSIKAthirdparty # for catch2
+  )
+
+add_test (NAME testGeometry COMMAND testGeometry)
+
diff --git a/Environment/HomogeneousMedium.h b/Environment/HomogeneousMedium.h
index b1a465959741daedc3a2d27c9cf44986be47da2c..60800a97789abcad1d0c54276d7c70609b82e822 100644
--- a/Environment/HomogeneousMedium.h
+++ b/Environment/HomogeneousMedium.h
@@ -2,6 +2,8 @@
 #define _include_HomogeneousMedium_h_
 
 #include <corsika/environment/NuclearComposition.h>
+#include <corsika/geometry/BaseTrajectory.h>
+#include <corsika/geometry/Point.h>
 #include <corsika/particles/ParticleProperties.h>
 #include <corsika/units/PhysicalUnits.h>
 
@@ -13,16 +15,33 @@ namespace corsika::environment {
 
   template <class T>
   class HomogeneousMedium : T {
-    MassDensityType const fDensity;
+    corsika::units::si::MassDensityType const fDensity;
     NuclearComposition const fNuclComp;
 
   public:
-    HomogeneousMedium(MassDensityType pDensity, NuclearComposition pNuclComp)
+    HomogeneousMedium(corsika::units::si::MassDensityType pDensity,
+                      NuclearComposition pNuclComp)
         : fDensity(pDensity)
         , fNuclComp(pNuclComp){};
 
-    MassDensityType GetMassDensity(Point const& p) const override { return fDensity; }
+    corsika::units::si::MassDensityType GetMassDensity([
+        [maybe_unused]] corsika::geometry::Point const& p) const override {
+      return fDensity;
+    }
     NuclearComposition const& GetNuclearComposition() const override { return fNuclComp; }
+
+    corsika::units::si::GrammageType IntegratedGrammage(
+        corsika::geometry::BaseTrajectory const& pTraj,
+        corsika::units::si::TimeType pTo) const override {
+      using namespace corsika::units::si;
+      return pTraj.DistanceBetween(0_s, pTo) * fDensity;
+    }
+
+    corsika::units::si::TimeType FromGrammage(
+        corsika::geometry::BaseTrajectory const& pTraj,
+        corsika::units::si::GrammageType pGrammage) const override {
+      return pTraj.TimeFromArclength(pGrammage / fDensity);
+    }
   };
 
 } // namespace corsika::environment
diff --git a/Environment/IMediumModel.h b/Environment/IMediumModel.h
index f291246cb6da9ffe4fa139c72cc1af61a48fe40a..8b4548ae764b91ad3be4672ca200dad41b17863a 100644
--- a/Environment/IMediumModel.h
+++ b/Environment/IMediumModel.h
@@ -3,6 +3,7 @@
 
 #include <corsika/environment/NuclearComposition.h>
 #include <corsika/geometry/BaseTrajectory.h>
+#include <corsika/geometry/Point.h>
 #include <corsika/units/PhysicalUnits.h>
 #include <tuple>
 #include <vector>
@@ -15,8 +16,11 @@ namespace corsika::environment {
 
     virtual corsika::units::si::MassDensityType GetMassDensity(
         corsika::geometry::Point const&) const = 0;
-    virtual corsika::units::si::GrammageType IntegratedGrammage(BaseTrajectory const&,
-                                                                double, double) const = 0;
+    virtual corsika::units::si::GrammageType IntegratedGrammage(
+        corsika::geometry::BaseTrajectory const&, corsika::units::si::TimeType) const = 0;
+    virtual corsika::units::si::TimeType FromGrammage(
+        corsika::geometry::BaseTrajectory const&,
+        corsika::units::si::GrammageType) const = 0;
     virtual NuclearComposition const& GetNuclearComposition() const = 0;
   };
 
diff --git a/Environment/NuclearComposition.h b/Environment/NuclearComposition.h
index 0fda0ee44ee31acebc8d8f760a2d4a48ba8750b4..484f9837547c13996da409beb70d99a589cfc688 100644
--- a/Environment/NuclearComposition.h
+++ b/Environment/NuclearComposition.h
@@ -1,12 +1,13 @@
 #ifndef _include_NuclearComposition_h
 #define _include_NuclearComposition_h
 
-#include <algorithm>
+#include <corsika/particles/ParticleProperties.h>
+#include <numeric>
 #include <vector>
 
 namespace corsika::environment {
   class NuclearComposition {
-    std::vector<float> const fNumberFractions; //<! relative fractions of number density
+    std::vector<float> const fNumberFractions; //!< relative fractions of number density
     std::vector<corsika::particles::Code> const
         fComponents; //!< particle codes of consitutents
 
@@ -18,7 +19,7 @@ namespace corsika::environment {
       auto const sumFractions =
           std::accumulate(pFractions.cbegin(), pFractions.cend(), 0.f);
 
-      if (!(0.999f < sum && sum < 1.001f)) {
+      if (!(0.999f < sumFractions && sumFractions < 1.001f)) {
         throw std::string("element fractions do not add up to 1");
       }
     }
diff --git a/Environment/VolumeTreeNode.h b/Environment/VolumeTreeNode.h
index 7026ff06e33d5cfff661b440731bae70387da543..a1f70554233318d296b89b93afbe0fb46ff69eef 100644
--- a/Environment/VolumeTreeNode.h
+++ b/Environment/VolumeTreeNode.h
@@ -81,7 +81,7 @@ namespace corsika::environment {
       fModelProperties = std::make_unique<ModelProperties>(std::forward<Args>(args)...);
     }
 
-    auto SetModelProperties(IMPSharedPtr ptr) { fModelProperties = IMPSharedPtr; }
+    void SetModelProperties(IMPSharedPtr ptr) { fModelProperties = ptr; }
 
     template <class MediumType, typename... Args>
     static auto CreateMedium(Args&&... args) {
@@ -94,8 +94,9 @@ namespace corsika::environment {
     // factory methods for creation of nodes
     template <class VolumeType, typename... Args>
     static auto CreateNode(Args&&... args) {
-      static_assert(std::is_base_of_v<Volume, VolumeType>,
-                    "unusable type provided, needs to be derived from \"Volume\"");
+      static_assert(std::is_base_of_v<corsika::geometry::Volume, VolumeType>,
+                    "unusable type provided, needs to be derived from "
+                    "\"corsika::geometry::Volume\"");
 
       return std::make_unique<VolumeTreeNode<IModelProperties>>(
           std::make_unique<VolumeType>(std::forward<Args>(args)...));
diff --git a/Environment/testEnvironment.cc b/Environment/testEnvironment.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1efbc4e8f62bd90e6b2a9a53a966f3da890cf32b
--- /dev/null
+++ b/Environment/testEnvironment.cc
@@ -0,0 +1,20 @@
+#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one
+                          // cpp file
+
+#include <corsika/environment/HomogeneousMedium.h>
+#include <corsika/environment/IMediumModel.h>
+#include <corsika/environment/NuclearComposition.h>
+#include <corsika/environment/VolumeTreeNode.h>
+#include <corsika/particles/ParticleProperties.h>
+#include <catch2/catch.hpp>
+
+using namespace corsika::geometry;
+using namespace corsika::environment;
+using namespace corsika::units::si;
+
+TEST_CASE("HomogeneousMedium") {
+  NuclearComposition const protonComposition(
+      std::vector<corsika::particles::Code>{corsika::particles::Code::Proton},
+      std::vector<float>{1.f});
+  HomogeneousMedium<IMediumModel> const medium(19.2_g / cube(1_cm), protonComposition);
+}
diff --git a/Framework/Geometry/BaseTrajectory.h b/Framework/Geometry/BaseTrajectory.h
index e4eafb853117b47e4778e14b17c4ba54f46ad7b4..1b4fd8416dcd11bc010369f5f50ea27165f5b72c 100644
--- a/Framework/Geometry/BaseTrajectory.h
+++ b/Framework/Geometry/BaseTrajectory.h
@@ -24,6 +24,9 @@ namespace corsika::geometry {
 
     virtual LengthType DistanceBetween(corsika::units::si::TimeType t1,
                                        corsika::units::si::TimeType t2) const = 0;
+
+    virtual corsika::units::si::TimeType TimeFromArclength(
+        corsika::units::si::LengthType) const = 0;
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/Helix.h b/Framework/Geometry/Helix.h
index bd62d1919b5500ab22f2bad1eb2968a93dc90c0f..5d9001d340f339bf48a3106d044975a829be8da1 100644
--- a/Framework/Geometry/Helix.h
+++ b/Framework/Geometry/Helix.h
@@ -47,10 +47,15 @@ namespace corsika::geometry {
 
     auto GetRadius() const { return radius; }
 
-    LengthType DistanceBetween(corsika::units::si::TimeType t1,
-                               corsika::units::si::TimeType t2) const override {
+    corsika::units::si::LengthType DistanceBetween(
+        corsika::units::si::TimeType t1, corsika::units::si::TimeType t2) const override {
       return (vPar + vPerp).norm() * (t2 - t1);
     }
+
+    corsika::units::si::TimeType TimeFromArclength(
+        corsika::units::si::LengthType t) const override {
+      return t / (vPar + vPerp).norm();
+    }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/LineTrajectory.h b/Framework/Geometry/LineTrajectory.h
index ee65b5e54e9ec3743b12b6aa8a14a6965e6d4eeb..996d0c431b1764a2e2fbd05f1ec270c9f6a4aa7c 100644
--- a/Framework/Geometry/LineTrajectory.h
+++ b/Framework/Geometry/LineTrajectory.h
@@ -28,6 +28,11 @@ namespace corsika::geometry {
       assert(t2 >= t1);
       return v0.norm() * (t2 - t1);
     }
+
+    corsika::units::si::TimeType TimeFromArclength(
+        corsika::units::si::LengthType t) const override {
+      return t / v0.norm();
+    }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/Sphere.h b/Framework/Geometry/Sphere.h
index 76699690c5d49b40a7e25d4f44e95cbead64b5e0..cba9726bcd448109fb9c8ef309fca3353f8effc4 100644
--- a/Framework/Geometry/Sphere.h
+++ b/Framework/Geometry/Sphere.h
@@ -1,8 +1,8 @@
 #ifndef _include_SPHERE_H_
 #define _include_SPHERE_H_
 
-#include <corsika/geometry/Volume.h>
 #include <corsika/geometry/Point.h>
+#include <corsika/geometry/Volume.h>
 #include <corsika/units/PhysicalUnits.h>
 
 namespace corsika::geometry {
diff --git a/Framework/Geometry/Volume.h b/Framework/Geometry/Volume.h
index badbeb9df00ee72d77894ddd175b699e2fac19ae..ac892e50b926758d76298675a3c0db80557ab9a4 100644
--- a/Framework/Geometry/Volume.h
+++ b/Framework/Geometry/Volume.h
@@ -6,11 +6,11 @@
 namespace corsika::geometry {
 
   class Volume {
-  
+
   public:
     //! returns true if the Point p is within the volume
     virtual bool Contains(Point const& p) const = 0;
-    
+
     virtual ~Volume() = default;
   };
 
diff --git a/Framework/Units/PhysicalUnits.h b/Framework/Units/PhysicalUnits.h
index 515db9e08415de1b91ec4a65d018dc50b173f902..a37c1d4b70ae98066e19562201380f7868d28411 100644
--- a/Framework/Units/PhysicalUnits.h
+++ b/Framework/Units/PhysicalUnits.h
@@ -38,7 +38,7 @@ namespace corsika::units::si {
   using EnergyType = phys::units::quantity<phys::units::energy_d, double>;
   using MassType = phys::units::quantity<phys::units::mass_d, double>;
   using MassDensityType = phys::units::quantity<phys::units::mass_density_d, double>;
-  using GrammageType = phys::units::quantity<phys::units::dimensions<-2,1>, double>;
+  using GrammageType = phys::units::quantity<phys::units::dimensions<-2, 1, 0>, double>;
 
 } // end namespace corsika::units::si