diff --git a/Processes/CONEXSourceCut/CONEXSourceCut.cc b/Processes/CONEXSourceCut/CONEXSourceCut.cc
index a13f56501e0d3a3cfeb04519f26d71fce4fae77e..fee7a912dbbf2c83435c324ae5a36de0d7ac04ce 100644
--- a/Processes/CONEXSourceCut/CONEXSourceCut.cc
+++ b/Processes/CONEXSourceCut/CONEXSourceCut.cc
@@ -9,9 +9,11 @@
  */
 
 #include <corsika/process/conex_source_cut/CONEXSourceCut.h>
+#include <corsika/process/conex_source_cut/CONEX_f.h>
 #include <corsika/random/RNGManager.h>
 #include <corsika/units/PhysicalConstants.h>
 #include <algorithm>
+#include <fstream>
 #include <iomanip>
 #include <utility>
 
@@ -23,7 +25,6 @@ using namespace corsika::setup;
 corsika::process::EProcessReturn CONEXSourceCut::DoSecondaries(
     corsika::setup::StackView& vS) {
   auto p = vS.begin();
-  HEPEnergyType const energy = p.GetEnergy();
 
   while (p != vS.end()) {
     Code const pid = p.GetPID();
@@ -34,91 +35,39 @@ corsika::process::EProcessReturn CONEXSourceCut::DoSecondaries(
       continue; // no EM particle
     }
 
-    auto const& position = p.GetPosition();
-    auto const direction = p.GetMomentum().normalized();
-
     int egs_pid = it->second;
 
-    double E =
-        energy / 1_MeV; // total energy, TODO: check if maybe kinetic should be used
-
-    auto coords = position.GetCoordinates(conexObservationCS_) / 1_m;
-    double x = coords[0].magnitude();
-    double y = coords[1].magnitude();
-
-    double altitude = ((position - center_).norm() - conex::earthRadius) / 1_m;
-
-    double slantDistance =
-        (position - showerAxis_.GetStart()).dot(showerAxis_.GetDirection()) / 1_m;
-
-    // lateral coordinates in CONEX shower frame
-    auto const d = position - showerAxis_.GetStart();
-    auto const dShowerPlane = d - d.parallelProjectionOnto(showerAxis_.GetDirection());
-    double lateralX = dShowerPlane.dot(x_sf_) / 1_m;
-    double lateralY = dShowerPlane.dot(y_sf_) / 1_m;
-
-    double slantX = showerAxis_.projectedX(position) * (1_cm * 1_cm / 1_g);
-
-    double time = (p.GetTime() * units::constants::c - groundDist_) / 1_m;
-
-    // fill u,v,w momentum direction in EGS frame
-    double u = direction.dot(y_sf_).magnitude();
-    double v = direction.dot(x_sf_).magnitude();
-    double w = direction.dot(showerAxis_.GetDirection()).magnitude();
-
-    int iri = 2; // EGS medium air
-
-    double weight = 1;
-
-    int latchin = 1; // generation, we don't have the actual value...
-
-    std::cout << "CONEXSourceCut: removing " << pid << " " << std::scientific << energy
-              << std::endl;
-    p.Delete();
-
-    // conex_.Shower(egs_pid, E, x, y, altitude, slantDistance, lateralX, lateralY,
-    // slantX,
-    //              time, u, v, w, iri, weight, latchin);
-    conex::show_(egs_pid, E, x, y, altitude, slantDistance, lateralX, lateralY, slantX,
-                 time, u, v, w, iri, weight, latchin);
+    addParticle(egs_pid, p.GetEnergy(), p.GetPosition(), p.GetMomentum().normalized(),
+                p.GetTime());
   }
 
   return corsika::process::EProcessReturn::eOk;
 }
 
-void CONEXSourceCut::dummyAddPhoton() {
-  HEPEnergyType const energy = 1_TeV;
-
-  geometry::Point position(center_.GetCoordinateSystem(), 0_m, 0_m,
-                           20_km + conex::earthRadius);
-
+void CONEXSourceCut::addParticle(int egs_pid, HEPEnergyType energy,
+                                 geometry::Point const& position,
+                                 geometry::Vector<dimensionless_d> const& direction,
+                                 TimeType t) {
   std::cout << "position conexObs: " << position.GetCoordinates(conexObservationCS_)
             << std::endl;
 
-  auto const direction = showerAxis_.GetDirection();
-
-  int egs_pid = 0;
-
-  double E = energy / 1_MeV; // total energy, TODO: check if maybe kinetic should be used
-
   auto coords = position.GetCoordinates(conexObservationCS_) / 1_m;
   double x = coords[0].magnitude();
   double y = coords[1].magnitude();
 
   double altitude = ((position - center_).norm() - conex::earthRadius) / 1_m;
+  auto const d = position - showerCore_;
 
-  double slantDistance =
-      (position - showerAxis_.GetStart()).dot(showerAxis_.GetDirection()) / 1_m;
+  // distance from core to particle projected along shower axis
+  double slantDistance = -d.dot(showerAxis_.GetDirection()) / 1_m;
 
   // lateral coordinates in CONEX shower frame
-  auto const d = position - showerAxis_.GetStart();
   auto const dShowerPlane = d - d.parallelProjectionOnto(showerAxis_.GetDirection());
   double lateralX = dShowerPlane.dot(x_sf_) / 1_m;
   double lateralY = dShowerPlane.dot(y_sf_) / 1_m;
 
   double slantX = showerAxis_.projectedX(position) * (1_cm * 1_cm / 1_g);
 
-  auto t = 0_s;
   double time = (t * units::constants::c - groundDist_) / 1_m;
 
   // fill u,v,w momentum direction in EGS frame
@@ -131,6 +80,7 @@ void CONEXSourceCut::dummyAddPhoton() {
   double weight = 1;
 
   int latchin = 1; // generation, we don't have the actual value...
+  double E = energy / 1_GeV;
 
   std::cout << "CONEXSourceCut: removing " << egs_pid << " " << std::scientific << energy
             << std::endl;
@@ -154,8 +104,23 @@ void CONEXSourceCut::dummyAddPhoton() {
   std::cout << "v = " << v << std::endl;
   std::cout << "w = " << w << std::endl;
 
-  conex::show_(egs_pid, E, x, y, altitude, slantDistance, lateralX, lateralY, slantX,
-               time, u, v, w, iri, weight, latchin);
+  conex::cxoptl_.dptl[10 - 1] = egs_pid;
+  conex::cxoptl_.dptl[4 - 1] = E;
+  conex::cxoptl_.dptl[6 - 1] = x;
+  conex::cxoptl_.dptl[7 - 1] = y;
+  conex::cxoptl_.dptl[8 - 1] = altitude;
+  conex::cxoptl_.dptl[9 - 1] = time;
+  conex::cxoptl_.dptl[11 - 1] = weight;
+  conex::cxoptl_.dptl[13 - 1] = slantX;
+  conex::cxoptl_.dptl[14 - 1] = lateralX;
+  conex::cxoptl_.dptl[15 - 1] = lateralY;
+  conex::cxoptl_.dptl[16 - 1] = slantDistance;
+  conex::cxoptl_.dptl[2 - 1] = u;
+  conex::cxoptl_.dptl[1 - 1] = v;
+  conex::cxoptl_.dptl[3 - 1] = w;
+
+  int n = 0, i = 0;
+  conex::cegs4_(n, i);
 }
 
 void CONEXSourceCut::Init() {}
@@ -209,13 +174,18 @@ void CONEXSourceCut::SolveCE() {
   conex::get_shower_electron_(icute, nX, Electrons[0]);
   conex::get_shower_hadron_(icuth, nX, Hadrons[0]);
 
-  for (int i = 0; i < nX; ++i) { std::cout << X[i] << "  " << dEdX[i] << std::endl; }
+  std::ofstream file{"conex_output.txt"};
+  for (int i = 0; i < nX; ++i) {
+    file << X[i] << " " << N[i] << " " << dEdX[i] << " " << Mu[i] << " " << dMu[i] << " "
+         << Gamma[i] << " " << Electrons[i] << " " << Hadrons[i] << std::endl;
+  }
 }
 
 // RU: move all the non-C8 code from the following c++ function into a new file. Here we
 // only want to have a single function call to CONEX left.
 
-CONEXSourceCut::CONEXSourceCut(geometry::Point center, environment::ShowerAxis showerAxis,
+CONEXSourceCut::CONEXSourceCut(geometry::Point center,
+                               environment::ShowerAxis const& showerAxis,
                                units::si::LengthType groundDist,
                                units::si::LengthType injectionHeight,
                                units::si::HEPEnergyType primaryEnergy,
@@ -224,18 +194,28 @@ CONEXSourceCut::CONEXSourceCut(geometry::Point center, environment::ShowerAxis s
     center_{center}
     , showerAxis_{showerAxis}
     , groundDist_{groundDist}
+    , showerCore_{showerAxis_.GetStart() + showerAxis_.GetDirection() * groundDist_}
     , conexObservationCS_{std::invoke([&]() {
       auto const& c8cs = center.GetCoordinateSystem();
-      auto const showerCore =
-          showerAxis.GetStart() + showerAxis.GetDirection() * groundDist;
-      auto const translation = showerCore - center;
+      auto const translation = showerCore_ - center;
       auto const intermediateCS = c8cs.translate(translation.GetComponents(c8cs));
       auto const intermediateCS2 = intermediateCS.RotateToZ(translation);
 
-      std::cout << "translation C8/CONEX obs: " << translation.norm() << std::endl;
+      std::cout << "translation C8/CONEX obs: " << translation.GetComponents()
+                << std::endl;
 
       auto const transform = geometry::CoordinateSystem::GetTransformation(
           intermediateCS2, c8cs); // either this way or vice versa... TODO: test this!
+      std::cout << transform.matrix() << std::endl << std::endl;
+      std::cout
+          << geometry::CoordinateSystem::GetTransformation(intermediateCS, c8cs).matrix()
+          << std::endl
+          << std::endl;
+      std::cout << geometry::CoordinateSystem::GetTransformation(intermediateCS2,
+                                                                 intermediateCS)
+                       .matrix()
+                << std::endl;
+
       return geometry::CoordinateSystem(c8cs, transform);
     })}
     , x_sf_{std::invoke([&]() {
@@ -246,15 +226,31 @@ CONEXSourceCut::CONEXSourceCut(geometry::Point center, environment::ShowerAxis s
         b = geometry::Vector<length_d>{conexObservationCS_, 1_m, 0_m, 0_m};
       }
 
-      std::cout << "x_sf (conexObservationCS): " << b.GetComponents(conexObservationCS_)
-                << std::endl;
-      std::cout << "x_sf (C8): " << b.GetComponents(center.GetCoordinateSystem())
-                << std::endl;
-
       return b.normalized();
     })}
     , y_sf_{showerAxis_.GetDirection().cross(x_sf_)} {
 
+  std::cout << "x_sf (conexObservationCS): " << x_sf_.GetComponents(conexObservationCS_)
+            << std::endl;
+  std::cout << "x_sf (C8): " << x_sf_.GetComponents(center.GetCoordinateSystem())
+            << std::endl;
+
+  std::cout << "y_sf (conexObservationCS): " << y_sf_.GetComponents(conexObservationCS_)
+            << std::endl;
+  std::cout << "y_sf (C8): " << y_sf_.GetComponents(center.GetCoordinateSystem())
+            << std::endl;
+
+  std::cout << "showerAxisDirection (conexObservationCS): "
+            << showerAxis_.GetDirection().GetComponents(conexObservationCS_) << std::endl;
+  std::cout << "showerAxisDirection (C8): "
+            << showerAxis_.GetDirection().GetComponents(center.GetCoordinateSystem())
+            << std::endl;
+
+  std::cout << "showerCore (conexObservationCS): "
+            << showerCore_.GetCoordinates(conexObservationCS_) << std::endl;
+  std::cout << "showerCore (C8): "
+            << showerCore_.GetCoordinates(center.GetCoordinateSystem()) << std::endl;
+
   int randomSeeds[3] = {1234, 0, 0}; // will be overwritten later??
   int heModel = eSibyll23;
 
@@ -273,15 +269,17 @@ CONEXSourceCut::CONEXSourceCut(geometry::Point center, environment::ShowerAxis s
   double eprima = primaryEnergy / 1_GeV;
 
   // set phi, theta
-  geometry::Vector<length_d> ez{conexObservationCS_, {0._m, 0._m, 1_m}};
+  geometry::Vector<length_d> ez{conexObservationCS_, {0._m, 0._m, -1_m}};
   auto const c = showerAxis_.GetDirection().dot(ez) / 1_m;
-  double theta = 180 * (M_PI - std::acos(c));
+  double theta = std::acos(c) * 180 / M_PI;
 
   auto const showerAxisConex =
       showerAxis_.GetDirection().GetComponents(conexObservationCS_);
-  double phi = 180 * std::atan2(-showerAxisConex.GetY().magnitude(),
-                                showerAxisConex.GetX().magnitude());
-  // double XmaxP_ = Xcut / (1_g / 1_cm / 1_cm);
+  double phi = std::atan2(-showerAxisConex.GetY().magnitude(),
+                          showerAxisConex.GetX().magnitude()) *
+               180 / M_PI;
+
+  std::cout << "theta (deg) = " << theta << "; phi (deg) = " << phi << std::endl;
 
   int ipart = static_cast<int>(primaryID);
   auto rng = corsika::random::RNGManager::GetInstance().GetRandomStream("cascade");
diff --git a/Processes/CONEXSourceCut/CONEXSourceCut.h b/Processes/CONEXSourceCut/CONEXSourceCut.h
index 25aba57af1e179631d37e636d9385c64c6e146f7..a8e4d627a9d840397df8b7cde4d3106677c951e5 100644
--- a/Processes/CONEXSourceCut/CONEXSourceCut.h
+++ b/Processes/CONEXSourceCut/CONEXSourceCut.h
@@ -34,7 +34,7 @@ namespace corsika::process {
     class CONEXSourceCut : public process::SecondariesProcess<CONEXSourceCut> {
 
     public:
-      CONEXSourceCut(geometry::Point center, environment::ShowerAxis showerAxis,
+      CONEXSourceCut(geometry::Point center, environment::ShowerAxis const& showerAxis,
                      units::si::LengthType groundDist,
                      units::si::LengthType injectionHeight,
                      units::si::HEPEnergyType primaryEnergy,
@@ -45,7 +45,12 @@ namespace corsika::process {
 
       void SolveCE();
 
-      void dummyAddPhoton();
+      void addParticle(int egs_pid, units::si::HEPEnergyType energy,
+                       geometry::Point const& position,
+                       geometry::Vector<units::si::dimensionless_d> const& direction,
+                       units::si::TimeType t);
+
+      auto const& GetObserverCS() const { return conexObservationCS_; }
 
     private:
       // ConexDynamicInterface conex_;
@@ -59,6 +64,7 @@ namespace corsika::process {
       geometry::Point const center_; //!< center of CONEX Earth
       environment::ShowerAxis const& showerAxis_;
       units::si::LengthType groundDist_; //!< length from injection point to shower core
+      geometry::Point const showerCore_; //!< shower core
       geometry::CoordinateSystem const conexObservationCS_; //!< CONEX observation frame
       geometry::Vector<units::si::dimensionless_d> const x_sf_,
           y_sf_; //!< unit vectors of CONEX shower frame, z_sf is shower axis direction