diff --git a/Framework/Utilities/SaveBoostHistogram.hpp b/Framework/Utilities/SaveBoostHistogram.hpp
index c6ffbe064df6b0d707a37177bb1d811d40534ffa..508c982aa4b0e06444eb0d95186d3e5138381a9d 100644
--- a/Framework/Utilities/SaveBoostHistogram.hpp
+++ b/Framework/Utilities/SaveBoostHistogram.hpp
@@ -15,10 +15,14 @@
 #include <numeric>
 #include <utility>
 #include <vector>
+#include <string>
 
 #pragma once
 
 namespace corsika::utl {
+
+  enum class SaveMode { overwrite, append };
+
   /**
    * This functions saves a boost::histogram into a numpy file. Only rather basic axis
    * types are supported: regular, variable, integer, category<int>. Only "ordinary" bin
@@ -29,9 +33,12 @@ namespace corsika::utl {
    */
   template <class Axes, class Storage>
   inline void save_hist(boost::histogram::histogram<Axes, Storage> const& h,
-                        std::string const& filename) {
+                        std::string const& filename, SaveMode mode = SaveMode::append) {
     unsigned const rank = h.rank();
 
+    // append vs. overwrite
+    const std::string mode_str = (mode == SaveMode::append ? "a" : "w");
+
     std::vector<size_t> axes_dims;
     axes_dims.reserve(rank);
 
@@ -61,7 +68,7 @@ namespace corsika::utl {
         ax_edges.push_back(ax.bin(ax.size() - 1).upper());
 
         cnpy::npz_save(filename, std::string{"binedges_"} + std::to_string(i),
-                       ax_edges.data(), {ax_edges.size()}, "a");
+                       ax_edges.data(), {ax_edges.size()}, mode_str);
       } else {
         axis_types.push_back('d');
         std::vector<int64_t> bins; // we assume that discrete axes have integer bins
@@ -70,13 +77,14 @@ namespace corsika::utl {
         for (int j = 0; j < ax.size(); ++j) { bins.push_back(ax.bin(j).lower()); }
 
         cnpy::npz_save(filename, std::string{"bins_"} + std::to_string(i), bins.data(),
-                       {bins.size()}, "a");
+                       {bins.size()}, mode_str);
       }
     }
 
-    cnpy::npz_save(filename, std::string{"axistypes"}, axis_types.data(), {rank}, "a");
-    cnpy::npz_save(filename, std::string{"overflow"}, overflow.get(), {rank}, "a");
-    cnpy::npz_save(filename, std::string{"underflow"}, underflow.get(), {rank}, "a");
+    cnpy::npz_save(filename, std::string{"axistypes"}, axis_types.data(), {rank},
+                   mode_str);
+    cnpy::npz_save(filename, std::string{"overflow"}, overflow.get(), {rank}, mode_str);
+    cnpy::npz_save(filename, std::string{"underflow"}, underflow.get(), {rank}, mode_str);
 
     auto const prod_axis_size = std::accumulate(axes_dims.cbegin(), axes_dims.cend(),
                                                 unsigned{1}, std::multiplies<>());
@@ -100,7 +108,7 @@ namespace corsika::utl {
       temp[p] = *x;
     }
 
-    cnpy::npz_save(filename, "data", temp.get(), axes_dims, "a");
+    cnpy::npz_save(filename, "data", temp.get(), axes_dims, mode_str);
     // In Python this array can directly be assigned to a histogram view if that
     // histogram has its axes correspondingly: hist.view(flow=True)[:] = file['data']
   }
diff --git a/Processes/InteractionCounter/CMakeLists.txt b/Processes/InteractionCounter/CMakeLists.txt
index e7f374dbf345b888659c7b035b03ec1f24cf7494..a8c0cf5dda53fd966c7bce56098cb1d479f3ea1f 100644
--- a/Processes/InteractionCounter/CMakeLists.txt
+++ b/Processes/InteractionCounter/CMakeLists.txt
@@ -50,6 +50,11 @@ CORSIKA_ADD_TEST(testInteractionCounter SOURCES
   ${MODEL_HEADERS}
 )
 
+target_compile_definitions (
+  testInteractionCounter
+  PRIVATE
+  REFDATADIR="${CMAKE_CURRENT_SOURCE_DIR}"
+  )
 target_link_libraries (
   testInteractionCounter
   ProcessInteractionCounter
diff --git a/Processes/InteractionCounter/InteractionHistogram.cc b/Processes/InteractionCounter/InteractionHistogram.cc
index 8ae626ffe57d1b0dd1cc016667b409a26b697f9a..45d04469b4c8fa7f9dd7ed1f22b41817ab4f3a2a 100644
--- a/Processes/InteractionCounter/InteractionHistogram.cc
+++ b/Processes/InteractionCounter/InteractionHistogram.cc
@@ -41,12 +41,14 @@ void InteractionHistogram::fill(particles::Code projectile_id,
   }
 }
 
-void InteractionHistogram::saveLab(std::string const& filename) const {
-  corsika::utl::save_hist(inthist_lab_, filename);
+void InteractionHistogram::saveLab(std::string const& filename,
+                                   utl::SaveMode mode) const {
+  corsika::utl::save_hist(inthist_lab_, filename, mode);
 }
 
-void InteractionHistogram::saveCMS(std::string const& filename) const {
-  corsika::utl::save_hist(inthist_cms_, filename);
+void InteractionHistogram::saveCMS(std::string const& filename,
+                                   utl::SaveMode mode) const {
+  corsika::utl::save_hist(inthist_cms_, filename, mode);
 }
 
 InteractionHistogram& InteractionHistogram::operator+=(
diff --git a/Processes/InteractionCounter/InteractionHistogram.hpp b/Processes/InteractionCounter/InteractionHistogram.hpp
index 96d243f1223505498d211d675fc8cba6ec620fb6..d374eb8d1778379134222b8de0beeb0dcfc181fb 100644
--- a/Processes/InteractionCounter/InteractionHistogram.hpp
+++ b/Processes/InteractionCounter/InteractionHistogram.hpp
@@ -54,9 +54,11 @@ namespace corsika::process::interaction_counter {
 
     hist_type const& labHist() const { return inthist_lab_; }
 
-    void saveLab(std::string const& filename) const;
+    void saveLab(std::string const& filename,
+                 utl::SaveMode mode = utl::SaveMode::append) const;
 
-    void saveCMS(std::string const& filename) const;
+    void saveCMS(std::string const& filename,
+                 utl::SaveMode mode = utl::SaveMode::append) const;
 
     InteractionHistogram& operator+=(InteractionHistogram const& other);
 
diff --git a/Processes/InteractionCounter/testInteractionCounter.cc b/Processes/InteractionCounter/testInteractionCounter.cc
index 95b8925cc9ca4fce1160b188568b59cc8f559e09..ad88405b5ae0717f45f89e2c1d37f5b67a20da44 100644
--- a/Processes/InteractionCounter/testInteractionCounter.cc
+++ b/Processes/InteractionCounter/testInteractionCounter.cc
@@ -27,6 +27,8 @@ using namespace corsika::process::interaction_counter;
 using namespace corsika::units;
 using namespace corsika::units::si;
 
+const std::string refDataDir = std::string(REFDATADIR);
+
 struct DummyProcess {
   template <typename TParticle>
   GrammageType GetInteractionLength([[maybe_unused]] TParticle const& particle) {
@@ -39,7 +41,7 @@ struct DummyProcess {
   }
 };
 
-TEST_CASE("InteractionCounter") {
+TEST_CASE("InteractionCounter", "[process]") {
 
   logging::SetLevel(logging::level::debug);
 
@@ -69,15 +71,14 @@ TEST_CASE("InteractionCounter") {
 
     auto const& h2 = countedProcess.GetHistogram().CMSHist();
     REQUIRE(h2.at(h2.axis(0).index(1'000'070'140), h2.axis(1).index(1.6e12)) == 1);
-    // REQUIRE(h2.at(1'000'070'140, 92) == 1); // bin 1.584 .. 1.995 TeV √s
     REQUIRE(std::accumulate(h2.cbegin(), h2.cend(), 0) == 1);
 
-    countedProcess.GetHistogram().saveLab("testInteractionCounter_file1.npz");
-    countedProcess.GetHistogram().saveCMS("testInteractionCounter_file2.npz");
+    countedProcess.GetHistogram().saveLab("testInteractionCounter_file1.npz",
+                                          utl::SaveMode::overwrite);
+    countedProcess.GetHistogram().saveCMS("testInteractionCounter_file2.npz",
+                                          utl::SaveMode::overwrite);
   }
 
-  SECTION("check saving") {}
-
   SECTION("DoInteraction Lambda") {
     auto constexpr code = particles::Code::Lambda0;
     auto [stackPtr, secViewPtr] =
@@ -97,3 +98,38 @@ TEST_CASE("InteractionCounter") {
     REQUIRE(std::accumulate(h2.cbegin(), h2.cend(), 0) == 1);
   }
 }
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <fstream>
+
+TEST_CASE("InteractionCounterOutput", "[output validation]") {
+
+  auto file = GENERATE(as<std::string>{}, "testInteractionCounter_file1",
+                       "testInteractionCounter_file2");
+
+  SECTION(std::string("check saved data, ") + file + ".npz") {
+
+    std::cout << file + ".npz vs " << refDataDir + "/" + file + "_REF.npz" << std::endl;
+
+    // compare to binary reference data
+    std::ifstream file1(file + ".npz");
+    std::ifstream file1ref(refDataDir + "/" + file + "_REF.npz");
+
+    std::istreambuf_iterator<char> begin1(file1);
+    std::istreambuf_iterator<char> begin1ref(file1ref);
+
+    std::istreambuf_iterator<char> end;
+
+    while (begin1 != end && begin1ref != end) {
+      CHECK(*begin1 == *begin1ref);
+      ++begin1;
+      ++begin1ref;
+    }
+    CHECK(begin1 == end);
+    CHECK(begin1ref == end);
+    file1.close();
+    file1ref.close();
+  }
+}
diff --git a/Processes/InteractionCounter/testInteractionCounter_file1_REF.npz b/Processes/InteractionCounter/testInteractionCounter_file1_REF.npz
new file mode 100644
index 0000000000000000000000000000000000000000..13e2d5d49e16b6a2e7eb6b95dc1a26bccab18ae8
Binary files /dev/null and b/Processes/InteractionCounter/testInteractionCounter_file1_REF.npz differ
diff --git a/Processes/InteractionCounter/testInteractionCounter_file2_REF.npz b/Processes/InteractionCounter/testInteractionCounter_file2_REF.npz
new file mode 100644
index 0000000000000000000000000000000000000000..8509b27e4d690a386c2710a24ceda6a1143bf757
Binary files /dev/null and b/Processes/InteractionCounter/testInteractionCounter_file2_REF.npz differ