diff --git a/corsika/detail/framework/core/Cascade.inl b/corsika/detail/framework/core/Cascade.inl
index 021b8c50aa1ae690df165b92ce68a0021df59a96..32127908c714d79dfdd7e22e74615aed449b1b7c 100644
--- a/corsika/detail/framework/core/Cascade.inl
+++ b/corsika/detail/framework/core/Cascade.inl
@@ -269,8 +269,8 @@ namespace corsika {
     if (actual_decay_time * 0.99 > initial_inv_decay_time) {
       CORSIKA_LOG_WARN(
           "Decay time decreased during step! This leads to un-physical step length. "
-          "initial_decay_time={}, actual_decay_time={}",
-          1 / initial_inv_decay_time, 1 / actual_decay_time);
+          "delta_inverse_decay_time={}",
+          1 / initial_inv_decay_time - 1 / actual_decay_time);
     }
 #endif
 
@@ -303,9 +303,8 @@ namespace corsika {
     if (actual_inv_length * 0.99 > initial_inv_int_length) {
       CORSIKA_LOG_WARN(
           "Interaction length decreased during step! This leads to un-physical step "
-          "length. "
-          "initial_inv_int_length={}, actual_inv_length={}",
-          1 / initial_inv_int_length, 1 / actual_inv_length);
+          "length. delta_innverse_interaction_length={}",
+          1 / initial_inv_int_length - 1 / actual_inv_length);
     }
 #endif
 
diff --git a/corsika/detail/framework/utility/LinearSolver.inl b/corsika/detail/framework/utility/LinearSolver.inl
index e9583acf2f08514e881ddc4a30b2db0b8852fb25..b2fc96ee7ae9a2a6947f1858b7c097e001b920bc 100644
--- a/corsika/detail/framework/utility/LinearSolver.inl
+++ b/corsika/detail/framework/utility/LinearSolver.inl
@@ -14,7 +14,7 @@
 
 namespace corsika {
 
-  inline std::vector<double> solve_linear_real(double a, double b, double const epsilon) {
+  inline std::vector<double> solve_linear_real(double a, double b) {
 
     if (a == 0) {
       return {}; // no (b!=0), or infinite number (b==0) of solutions....
@@ -23,8 +23,7 @@ namespace corsika {
     return {-b / a};
   }
 
-  inline std::vector<std::complex<double>> solve_linear(double a, double b,
-                                                        double const epsilon) {
+  inline std::vector<std::complex<double>> solve_linear(double a, double b) {
 
     if (std::abs(a) == 0) {
       return {}; // no (b!=0), or infinite number (b==0) of solutions....
diff --git a/corsika/detail/framework/utility/QuadraticSolver.inl b/corsika/detail/framework/utility/QuadraticSolver.inl
index d3b3f86714af097745e9879c3543244ddf4fbcb4..9e67ea031c11d6160602a520746c4e3aead33a48 100644
--- a/corsika/detail/framework/utility/QuadraticSolver.inl
+++ b/corsika/detail/framework/utility/QuadraticSolver.inl
@@ -11,10 +11,10 @@ namespace corsika {
   inline std::vector<std::complex<double>> solve_quadratic(long double a, long double b,
                                                            long double c,
                                                            double const epsilon) {
-    if (std::abs(a) < epsilon) { return solve_linear(b, c, epsilon); }
+    if (std::abs(a) < epsilon) { return solve_linear(b, c); }
 
     if (std::abs(c) < epsilon) {
-      std::vector<std::complex<double>> lin_result = solve_linear(a, b, epsilon);
+      std::vector<std::complex<double>> lin_result = solve_linear(a, b);
       lin_result.push_back({0.});
       return lin_result;
     }
@@ -45,9 +45,9 @@ namespace corsika {
 
     CORSIKA_LOG_TRACE("quadratic: a={} b={} c={}", a, b, c);
 
-    if (std::abs(a) < epsilon) { return solve_linear_real(b, c, epsilon); }
+    if (std::abs(a) < epsilon) { return solve_linear_real(b, c); }
     if (std::abs(c) < epsilon) {
-      std::vector<double> lin_result = solve_linear_real(a, b, epsilon);
+      std::vector<double> lin_result = solve_linear_real(a, b);
       lin_result.push_back(0.);
       return lin_result;
     }
diff --git a/corsika/detail/modules/tracking/TrackingLeapFrogCurved.inl b/corsika/detail/modules/tracking/TrackingLeapFrogCurved.inl
index cad673519f8de048c7df4bdaeb3a62e55be126b1..35ebad050be46604a48a364ecefe8b9f7f35e449 100644
--- a/corsika/detail/modules/tracking/TrackingLeapFrogCurved.inl
+++ b/corsika/detail/modules/tracking/TrackingLeapFrogCurved.inl
@@ -61,14 +61,14 @@ namespace corsika {
 
       auto const position = particle.getPosition();
       CORSIKA_LOG_DEBUG(
-          "Tracking pid: {}"
-          " , E = {} GeV",
-          particle.getPID(), particle.getEnergy() / 1_GeV);
-      CORSIKA_LOG_DEBUG("Tracking pos: {}", position.getCoordinates());
-      CORSIKA_LOG_DEBUG("Tracking   E: {} GeV", particle.getEnergy() / 1_GeV);
-      CORSIKA_LOG_DEBUG("Tracking   p: {} GeV",
-                        particle.getMomentum().getComponents() / 1_GeV);
-      CORSIKA_LOG_DEBUG("Tracking   v: {} ", initialVelocity.getComponents());
+          "TrackingLeapfrog_Curved pid: {}"
+          " , E = {} GeV \n"
+          "\tTracking pos: {} \n"
+          "\tTracking   p: {} GeV \n"
+          "\tTracking   v: {}",
+          particle.getPID(), particle.getEnergy() / 1_GeV, position.getCoordinates(),
+          particle.getMomentum().getComponents() / 1_GeV,
+          initialVelocity.getComponents());
 
       typedef
           typename std::remove_reference<decltype(*particle.getNode())>::type node_type;
@@ -84,7 +84,10 @@ namespace corsika {
       ElectricChargeType const charge = particle.getCharge();
       bool const no_deflection = (charge == 0 * constants::e) || magnitudeB == 0_T;
 
-      if (no_deflection) { return getLinearTrajectory(particle); }
+      if (no_deflection) {
+        CORSIKA_LOG_TRACE("no_deflection");
+        return getLinearTrajectory(particle);
+      }
 
       HEPMomentumType const p_perp =
           (particle.getMomentum() -
diff --git a/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl b/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl
index 77cef175de6d136b8681456752fdbaec725c03d4..4e7efed775468a6525a236fe7b5a72b45896e518 100644
--- a/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl
+++ b/corsika/detail/modules/tracking/TrackingLeapFrogStraight.inl
@@ -29,15 +29,17 @@ namespace corsika {
           particle.getMomentum() / particle.getEnergy() * constants::c;
 
       Point const initialPosition = particle.getPosition();
+
       CORSIKA_LOG_DEBUG(
-          "TrackingB pid: {}"
-          " , E = {} GeV",
-          particle.getPID(), particle.getEnergy() / 1_GeV);
-      CORSIKA_LOG_DEBUG("TrackingB pos: {}", initialPosition.getCoordinates());
-      CORSIKA_LOG_DEBUG("TrackingB   E: {} GeV", particle.getEnergy() / 1_GeV);
-      CORSIKA_LOG_DEBUG("TrackingB   p: {} GeV",
-                        particle.getMomentum().getComponents() / 1_GeV);
-      CORSIKA_LOG_DEBUG("TrackingB   v: {} ", initialVelocity.getComponents());
+          "TrackingLeapFrogStraight pid: {}"
+          " , E = {} GeV \n"
+          "\tTracking pos: {} \n"
+          "\tTracking   p: {} GeV \n"
+          "\tTracking   v: {} ",
+          particle.getPID(), particle.getEnergy() / 1_GeV,
+          initialPosition.getCoordinates(),
+          particle.getMomentum().getComponents() / 1_GeV,
+          initialVelocity.getComponents());
 
       typedef decltype(particle.getNode()) node_type;
       node_type const volumeNode = particle.getNode();
@@ -93,7 +95,7 @@ namespace corsika {
       // need to follow strongly curved trajectories segment-wise,
       // at least if we don't employ concepts as "Helix
       // Trajectories" or similar
-      double const maxRadians = 0.01;
+      double const maxRadians = 0.001;
       LengthType const steplimit = 2 * cos(maxRadians) * sin(maxRadians) * gyroradius;
       CORSIKA_LOG_DEBUG("gyroradius {}, Steplimit: {}", gyroradius, steplimit);
 
diff --git a/corsika/detail/modules/tracking/TrackingStraight.inl b/corsika/detail/modules/tracking/TrackingStraight.inl
index 36e0975605bbdc48b5335a36516de059a5a41d34..7f41291885e628bf62360c5e870f95ddd78f2873 100644
--- a/corsika/detail/modules/tracking/TrackingStraight.inl
+++ b/corsika/detail/modules/tracking/TrackingStraight.inl
@@ -31,14 +31,13 @@ namespace corsika::tracking_line {
 
     auto const initialPosition = particle.getPosition();
     CORSIKA_LOG_DEBUG(
-        "Tracking pid: {}"
-        " , E = {} GeV",
-        particle.getPID(), particle.getEnergy() / 1_GeV);
-    CORSIKA_LOG_DEBUG("Tracking pos: {}", initialPosition.getCoordinates());
-    CORSIKA_LOG_DEBUG("Tracking   E: {} GeV", particle.getEnergy() / 1_GeV);
-    CORSIKA_LOG_DEBUG("Tracking   p: {} GeV",
-                      particle.getMomentum().getComponents() / 1_GeV);
-    CORSIKA_LOG_DEBUG("Tracking   v: {} ", initialVelocity.getComponents());
+        "TrackingStraight pid: {}"
+        " , E = {} GeV \n"
+        "\tTracking pos: {} \n"
+        "\tTracking   p: {} GeV \n"
+        "\tTracking   v: {}",
+        particle.getPID(), particle.getEnergy() / 1_GeV, initialPosition.getCoordinates(),
+        particle.getMomentum().getComponents() / 1_GeV, initialVelocity.getComponents());
 
     // traverse the environment volume tree and find next
     // intersection
@@ -52,7 +51,8 @@ namespace corsika::tracking_line {
   template <typename TParticle>
   inline Intersections Tracking::intersect(TParticle const& particle,
                                            Sphere const& sphere) {
-    auto const delta = particle.getPosition() - sphere.getCenter();
+    auto const position = particle.getPosition();
+    auto const delta = position - sphere.getCenter();
     auto const velocity = particle.getMomentum() / particle.getEnergy() * constants::c;
     auto const vSqNorm = velocity.getSquaredNorm();
     auto const R = sphere.getRadius();
@@ -64,6 +64,9 @@ namespace corsika::tracking_line {
     if (discriminant.magnitude() > 0) {
       auto const sqDisc = sqrt(discriminant);
       auto const invDenom = 1 / vSqNorm;
+
+      bool const numericallyInside = sphere.contains(position);
+      CORSIKA_LOG_TRACE("numericallyInside={}", numericallyInside);
       return Intersections((-vDotDelta - sqDisc) * invDenom,
                            (-vDotDelta + sqDisc) * invDenom);
     }
diff --git a/corsika/framework/core/Logging.hpp b/corsika/framework/core/Logging.hpp
index 67f059c2fe6d1dc5d4b228e551f4ebbbcd1acf9e..d127040b036dab150ce06a40644050f20a3fab2a 100644
--- a/corsika/framework/core/Logging.hpp
+++ b/corsika/framework/core/Logging.hpp
@@ -49,7 +49,8 @@ namespace corsika {
   /*
    * The default pattern for CORSIKA8 loggers.
    */
-  const std::string default_pattern{"[%n:%^%-8l%$] %v"};
+  const std::string minimal_pattern{"[%n:%^%-8l%$] %v"};
+  const std::string default_pattern{"[%n:%^%-8l%$(%s:%#)] %v"};
   const std::string source_pattern{"[%n:%^%-8l%$(%s:%!:%#)] %v"};
 
   /**
@@ -91,7 +92,6 @@ namespace corsika {
    */
   static inline std::shared_ptr<spdlog::logger> corsika_logger =
       get_logger("corsika", true);
-  // corsika_logger->set_pattern("[%n:%^%-8l%$] custom pattern: %v");
 
   // many of these free functions are special to the logging
   // infrastructure so we hide them in the corsika::logging namespace.
diff --git a/corsika/framework/utility/LinearSolver.hpp b/corsika/framework/utility/LinearSolver.hpp
index 95322958d09c744ccc4971930fec2616a7d1dde2..754039571287a1a816c77ec741b7d850b87c46da 100644
--- a/corsika/framework/utility/LinearSolver.hpp
+++ b/corsika/framework/utility/LinearSolver.hpp
@@ -14,10 +14,9 @@
 
 namespace corsika {
 
-  std::vector<double> solve_linear_real(double a, double b, double const epsilon = 1e-12);
+  std::vector<double> solve_linear_real(double a, double b);
 
-  std::vector<std::complex<double>> solve_linear(double a, double b,
-                                                 double const epsilon = 1e-12);
+  std::vector<std::complex<double>> solve_linear(double a, double b);
 
 } // namespace corsika
 
diff --git a/tests/modules/testTracking.cpp b/tests/modules/testTracking.cpp
index 3f1d6ecaa9978bdf0a9f927cb6e1c760e45b7e08..f09297e7699483f6fb25b9a9d6514eefcb76d6d9 100644
--- a/tests/modules/testTracking.cpp
+++ b/tests/modules/testTracking.cpp
@@ -20,15 +20,22 @@
 
 #include <catch2/catch.hpp>
 
+#include <boost/type_index.hpp>
+
 using namespace corsika;
 
+struct NonExistingDummyObject : public IVolume {
+  NonExistingDummyObject const& getVolume() const { return *this; }
+  bool contains(Point const&) const { return false; }
+};
+
 template <typename T>
 int sgn(T val) {
   return (T(0) < val) - (val < T(0));
 }
 
 /**
- \file testTracking.cpp
+   @file testTracking.cpp
 
   This is the unified and commond unit test for all Tracking algorithms:
 
@@ -36,14 +43,29 @@ int sgn(T val) {
   - tracking_leapfrog_straight::Tracking
   - tracking_line::Tracking
 
+
+  The main part of tests are to inject particles at 10GeV momentum at
+  (-Rg,0,0) in +x direction into a sphere of radius Rg, where Rg is
+  the gyroradius (or 10m for neutral particles). Then it is checked
+  where the particles leaves the sphere for different charges
+  (-1,0,+1) and field strength (-50uT, 0T, +50uT).
+
+  Each test is perfromed once, with the particles starting logically
+  outside of the Rg sphere (thus it first has to enter insides) and a
+  second time with the particle already logically inside the sphere.
+
+  There is a second smaller, internal sphere at +z displacement. Only
+  neutral particles are allowed and expected to hit this.
+
+  All those tests are parameterized, thus, they can be easily extended
+  or applied to new algorithms.
+
  */
 
-TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
-                   tracking_leapfrog_curved::Tracking,
+TEMPLATE_TEST_CASE("Tracking", "tracking", tracking_leapfrog_curved::Tracking,
                    tracking_leapfrog_straight::Tracking, tracking_line::Tracking) {
 
   logging::set_level(logging::level::info);
-  logging::set_level(logging::level::trace);
 
   const HEPEnergyType P0 = 10_GeV;
 
@@ -67,9 +89,10 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
                       Bfield / 1_uT, outer)) {
 
     CORSIKA_LOG_DEBUG(
-        "********************\n                          TEST section PID={}, Bfield={} "
-        "uT, outer (?)={}",
-        PID, Bfield / 1_uT, outer);
+        "********************\n                          TEST algo={} section PID={}, "
+        "Bfield={} "
+        "uT, start_outside={}",
+        boost::typeindex::type_id<TestType>().pretty_name(), PID, Bfield / 1_uT, outer);
 
     const int chargeNumber = get_charge_number(PID);
     LengthType radius = 10_m;
@@ -90,6 +113,12 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
     TestType tracking;
     Point const center(cs, {0_m, 0_m, 0_m});
     auto target = setup::Environment::createNode<Sphere>(center, radius);
+    // every particle should hit target_2
+    auto target_2 = setup::Environment::createNode<Sphere>(
+        Point(cs, {-radius * 3 / 4, 0_m, 0_m}), radius * 0.2);
+    // only neutral particles hit_target_neutral
+    auto target_neutral = setup::Environment::createNode<Sphere>(
+        Point(cs, {radius / 2, 0_m, 0_m}), radius * 0.1);
 
     using MyHomogeneousModel = MediumPropertyModel<
         UniformMagneticField<HomogeneousMedium<setup::EnvironmentInterface>>>;
@@ -98,8 +127,18 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
     target->setModelProperties<MyHomogeneousModel>(
         Medium::AirDry1Atm, magneticfield, 1_g / (1_m * 1_m * 1_m),
         NuclearComposition(std::vector<Code>{Code::Oxygen}, std::vector<float>{1.}));
+    target_neutral->setModelProperties<MyHomogeneousModel>(
+        Medium::AirDry1Atm, magneticfield, 1_g / (1_m * 1_m * 1_m),
+        NuclearComposition(std::vector<Code>{Code::Oxygen}, std::vector<float>{1.}));
+    target_2->setModelProperties<MyHomogeneousModel>(
+        Medium::AirDry1Atm, magneticfield, 1_g / (1_m * 1_m * 1_m),
+        NuclearComposition(std::vector<Code>{Code::Oxygen}, std::vector<float>{1.}));
     auto* targetPtr = target.get();
+    auto* targetPtr_2 = target_2.get();
+    auto* targetPtr_neutral = target_neutral.get();
     worldPtr->addChild(std::move(target));
+    targetPtr->addChild(std::move(target_2));
+    targetPtr->addChild(std::move(target_neutral));
 
     auto [stack, viewPtr] = setup::testing::setup_stack(PID, 0, 0, P0, targetPtr, cs);
     { [[maybe_unused]] auto& viewPtr_dum = viewPtr; }
@@ -126,7 +165,11 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
       CHECK(nextVol == targetPtr);
     }
     // move forward, until we leave target volume
-    while (nextVol == targetPtr) {
+    bool hit_neutral = false;
+    bool hit_2nd = false;
+    while (nextVol != worldPtr) {
+      if (nextVol == targetPtr_neutral) hit_neutral = true;
+      if (nextVol == targetPtr_2) hit_2nd = true;
       const auto [traj2, nextVol2] = tracking.getTrack(particle);
       nextVol = nextVol2;
       particle.setNode(nextVol);
@@ -139,6 +182,8 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
                         traj2.getLength(1) / particle.getVelocity().getNorm());
     }
     CHECK(nextVol == worldPtr);
+    CHECK(hit_2nd == true);
+    CHECK(hit_neutral == (deflect == 0 ? true : false));
 
     Point pointCheck(cs, (deflect == 0 ? radius : 0_m), (deflect * radius), 0_m);
 
@@ -151,3 +196,165 @@ TEMPLATE_TEST_CASE("TrackingLeapfrog_Curved", "tracking",
           Approx(0).margin(1e-3));
   }
 }
+
+/** specifc test for curved leap-frog algorithm **/
+
+TEST_CASE("TrackingLeapFrogCurved") {
+
+  logging::set_level(logging::level::info);
+
+  const HEPEnergyType P0 = 10_GeV;
+
+  corsika::Code PID = Code::MuPlus;
+
+  using MyHomogeneousModel = MediumPropertyModel<
+      UniformMagneticField<HomogeneousMedium<setup::EnvironmentInterface>>>;
+
+  SECTION("infinite sphere / universe") {
+
+    auto [env, csPtr, worldPtr] =
+        corsika::setup::testing::setup_environment(Code::Oxygen, 100_uT);
+    { [[maybe_unused]] const auto& env_dummy = env; }
+    auto const& cs = *csPtr;
+
+    tracking_leapfrog_curved::Tracking tracking;
+    Point const center(cs, {0_m, 0_m, 0_m});
+
+    auto [stack, viewPtr] = setup::testing::setup_stack(PID, 0, 0, P0, worldPtr, cs);
+    { [[maybe_unused]] auto& viewPtr_dum = viewPtr; }
+    auto particle = stack->first();
+    // Note: momentum in X-direction
+    //       magnetic field in X-direction
+
+    particle.setPosition(Point(cs, 0_m, 0_m, 0_m));
+
+    Sphere sphere(center, 1_km * std::numeric_limits<double>::infinity());
+
+    auto intersections = tracking.intersect(particle, sphere);
+    // this must be a "linear trajectory" with no curvature
+
+    CHECK(intersections.hasIntersections() == false);
+  }
+
+  SECTION("momentum along field") {
+
+    auto [env, csPtr, worldPtr] =
+        corsika::setup::testing::setup_environment(Code::Oxygen, 100_uT);
+    { [[maybe_unused]] const auto& env_dummy = env; }
+    auto const& cs = *csPtr;
+
+    tracking_leapfrog_curved::Tracking tracking;
+    Point const center(cs, {0_m, 0_m, 0_m});
+    auto target = setup::Environment::createNode<Sphere>(center, 10_km);
+
+    MagneticFieldVector magneticfield(cs, 100_T, 0_T, 0_uT);
+    target->setModelProperties<MyHomogeneousModel>(
+        Medium::AirDry1Atm, magneticfield, 1_g / (1_m * 1_m * 1_m),
+        NuclearComposition(std::vector<Code>{Code::Oxygen}, std::vector<float>{1.}));
+    auto* targetPtr = target.get();
+    worldPtr->addChild(std::move(target));
+
+    auto [stack, viewPtr] = setup::testing::setup_stack(PID, 0, 0, P0, targetPtr, cs);
+    { [[maybe_unused]] auto& viewPtr_dum = viewPtr; }
+    auto particle = stack->first();
+    // Note: momentum in X-direction
+    //       magnetic field in X-direction
+
+    particle.setNode(targetPtr); // set particle outside "target" volume
+    particle.setPosition(Point(cs, 0_m, 0_m, 0_m));
+
+    auto [traj, nextVol] = tracking.getTrack(particle);
+    // this must be a "linear trajectory" with no curvature
+
+    CHECK(traj.getDirection(0).getComponents() == traj.getDirection(1).getComponents());
+  }
+}
+
+TEMPLATE_TEST_CASE("TrackingFail", "doesntwork", tracking_leapfrog_curved::Tracking,
+                   tracking_leapfrog_straight::Tracking, tracking_line::Tracking) {
+
+  logging::set_level(logging::level::info);
+
+  const HEPEnergyType P0 = 10_GeV;
+
+  auto [env, csPtr, worldPtr] =
+      corsika::setup::testing::setup_environment(Code::Oxygen, 1_mT);
+  { [[maybe_unused]] const auto& env_dummy = env; }
+  auto const& cs = *csPtr;
+
+  TestType tracking;
+  Point const center(cs, {0_m, 0_m, 0_m});
+
+  auto [stack, viewPtr] =
+      setup::testing::setup_stack(Code::Proton, 0, 0, P0, worldPtr, cs);
+  { [[maybe_unused]] auto& viewPtr_dum = viewPtr; }
+  auto particle = stack->first();
+  NonExistingDummyObject const dummy;
+  CHECK_THROWS(tracking.intersect(particle, dummy));
+}
+
+TEMPLATE_TEST_CASE("TrackingPlane", "plane", tracking_leapfrog_curved::Tracking,
+                   tracking_leapfrog_straight::Tracking, tracking_line::Tracking) {
+
+  logging::set_level(logging::level::trace);
+
+  const HEPEnergyType P0 = 10_GeV;
+
+  auto PID = GENERATE(as<Code>{}, Code::MuPlus, Code::MuPlus, Code::Gamma);
+  // for algorithms that know magnetic deflections choose: +-50uT, 0uT
+  // otherwise just 0uT
+  auto Bfield = GENERATE(filter(
+      []([[maybe_unused]] MagneticFluxType v) {
+        if constexpr (std::is_same_v<TestType, tracking_line::Tracking>)
+          return v == 0_uT;
+        else
+          return true;
+      },
+      values<MagneticFluxType>({50_uT, 0_uT, -50_uT})));
+
+  SECTION(fmt::format("Tracking PID={}, Bfield={} uT", PID, Bfield / 1_uT)) {
+
+    CORSIKA_LOG_DEBUG(
+        "********************\n                          TEST algo={} section PID={}, "
+        "Bfield={}uT ",
+        boost::typeindex::type_id<TestType>().pretty_name(), PID, Bfield / 1_uT);
+
+    const int chargeNumber = get_charge_number(PID);
+    LengthType radius = 10_m;
+    int deflect = 0;
+    if (chargeNumber != 0 and Bfield != 0_T) {
+      deflect = 1;
+      LengthType const gyroradius = (convert_HEP_to_SI<MassType::dimension_type>(P0) *
+                                     constants::c / (abs(get_charge(PID)) * abs(Bfield)));
+      CORSIKA_LOG_DEBUG("Rg={} deflect={}", gyroradius, deflect);
+      radius = gyroradius;
+    }
+
+    auto [env, csPtr, worldPtr] =
+        corsika::setup::testing::setup_environment(Code::Oxygen, Bfield);
+    { [[maybe_unused]] const auto& env_dummy = env; }
+    auto const& cs = *csPtr;
+
+    TestType tracking;
+    Point const center(cs, {0_m, 0_m, 0_m});
+
+    auto [stack, viewPtr] = setup::testing::setup_stack(PID, 0, 0, P0, worldPtr, cs);
+    { [[maybe_unused]] auto& viewPtr_dum = viewPtr; }
+    auto particle = stack->first();
+    // Note: momentum in X-direction
+    //       magnetic field in Z-direction
+
+    particle.setPosition(Point(cs, -radius, 0_m, 0_m));
+
+    // put plane where we expect deflection by radius/2
+    Plane const plane(Point(cs, radius * (1 - sqrt(3. / 4.)), 0_m, 0_m),
+                      DirectionVector(cs, {-1., 0., 0.}));
+    Intersections const hit = tracking.intersect(particle, plane);
+
+    CORSIKA_LOG_DEBUG("entry={} exit={}", hit.getEntry(), hit.getExit());
+
+    CHECK(hit.hasIntersections());
+    CHECK(hit.getEntry() / 1_s == Approx(0.00275 * deflect).margin(0.0003));
+    CHECK(hit.getExit() == 1_s * std::numeric_limits<double>::infinity());
+  }
+}