diff --git a/benchmarks/dis/analysis/dis_electrons.cxx b/benchmarks/dis/analysis/dis_electrons.cxx
index c3ce781f2e804e36593ad65fdd1d5c27ba4c19c8..6a4d9896210442546ce282fabf492db64f7792f6 100644
--- a/benchmarks/dis/analysis/dis_electrons.cxx
+++ b/benchmarks/dis/analysis/dis_electrons.cxx
@@ -1,6 +1,7 @@
 #include "common_bench/benchmark.h"
 #include "common_bench/mt.h"
 #include "common_bench/util.h"
+#include "common_bench/plot.h"
 
 #include <cmath>
 #include <fstream>
@@ -14,120 +15,15 @@
 #include <TH1D.h>
 #include <TFitResult.h>
 #include <TRandom3.h>
+#include <TCanvas.h>
 
 #include "fmt/color.h"
 #include "fmt/core.h"
 
 #include "nlohmann/json.hpp"
+#include "eicd/InclusiveKinematicsData.h"
 #include "eicd/ReconstructedParticleData.h"
 
-// Get a vector of 4-momenta from the reconstructed data.
-inline auto momenta_from_reconstruction(const std::vector<eic::ReconstructedParticleData>& parts)
-{
-  std::vector<ROOT::Math::PxPyPzEVector> momenta{parts.size()};
-  // transform our reconstructed particle data into 4-momenta
-  std::transform(parts.begin(), parts.end(), momenta.begin(), [](const auto& part) {
-    return ROOT::Math::PxPyPzEVector{part.p.x, part.p.y, part.p.z, part.energy};
-  });
-  return momenta;
-}
-
-// Convert PxPyPzMVector to PxPyPzEVector
-inline auto convertMtoE(const std::vector<ROOT::Math::PxPyPzMVector>& mom)
-{
-  std::vector<ROOT::Math::PxPyPzEVector> momenta{mom.size()};
-  std::transform(mom.begin(), mom.end(), momenta.begin(), [](const auto& part) {
-    return ROOT::Math::PxPyPzEVector{part.Px(), part.Py(), part.Pz(), part.energy()};
-  });
-  return momenta;
-}
-
-// Momentum sorting bool
-bool sort_mom_bool(ROOT::Math::PxPyPzEVector &mom1, ROOT::Math::PxPyPzEVector &mom2)
-{
-  return  mom1.energy() > mom2.energy(); 
-}
-
-// Momentunm sorting function
-inline auto sort_momenta(const std::vector<ROOT::Math::PxPyPzEVector>& mom)
-{
-  std::vector <ROOT::Math::PxPyPzEVector> sort_mom = mom;
-  sort(sort_mom.begin(), sort_mom.end(), sort_mom_bool);
-  return sort_mom;
-}
-
-// Q2 calculation from 4 Vector
-inline auto Q2(const std::vector<ROOT::Math::PxPyPzEVector>& mom)
-{
-  std::vector<double> Q2Vec(mom.size() );
-  ROOT::Math::PxPyPzEVector beamMom = {0, 0, 18, 18};
-  std::transform(mom.begin(), mom.end(), Q2Vec.begin(), [beamMom](const auto& part) {
-    return -(part - beamMom).M2();
-  });
-  return Q2Vec;
-}
-
-// Difference between two 4 Vectors
-inline auto sub(const std::vector<ROOT::Math::PxPyPzEVector>& mom1, const std::vector<ROOT::Math::PxPyPzEVector>& mom2)
-{
-  std::vector<ROOT::Math::PxPyPzEVector> sub(mom1.size() );
-  for (int i = 0; i < sub.size(); i++)
-  {
-    sub[i] = mom1[i] - mom2[i];
-  }
-  return sub;
-}
-
-// Multiplies a double by a gaussian distributed number 
-inline auto randomize(const std::vector<double>& doubleVec)
-{
-  std::vector<double> outVec(doubleVec.size() );
-  TRandom3 rand;
-  std::transform(doubleVec.begin(), doubleVec.end(), outVec.begin(), [&rand](const auto& indouble) {
-    return indouble * rand.Gaus(1.0, 0.2);
-  });
-  return outVec;
-}
-
-//Simulation functions
-/*
-bool mom_sort_sim(dd4pod::Geant4ParticleData& part1, dd4pod::Geant4ParticleData& part2)
-{
-  return (part1.psx*part1.psx + part1.psy*part1.psy + part1.psz*part1.psz > 
-          part2.psx*part2.psx + part2.psy*part2.psy + part2.psz*part2.psz);
-}
-
-inline auto momenta_from_sim(const std::vector<dd4pod::Geant4ParticleData>& parts)
-{
-  std::vector<dd4pod::Geant4ParticleData> sort_parts = parts;
-  sort(sort_parts.begin(), sort_parts.end(), mom_sort_sim);
-  return sort_parts;
-}
-
-inline auto Q2_from_sim(const std::vector<dd4pod::Geant4ParticleData>& parts)
-{
-  std::vector<double> Q2Vec(parts.size() );
-  double beamEnergy = 18;
-  std::transform(parts.begin(), parts.end(), Q2Vec.begin(), [beamEnergy](const auto& part) {
-    double energy = sqrt(part.psx*part.psx + part.psy*part.psy + part.psz*part.psz + part.mass*part.mass);
-    double q2 = pow(beamEnergy - energy, 2.0) - part.psx*part.psx - part.psy*part.psy - pow(part.psz - beamEnergy, 2.0);
-    return -q2;
-  });
-  return Q2Vec;
-}
-
-inline auto elec_PID_sim(const std::vector<dd4pod::Geant4ParticleData>& parts)
-{
-  std::vector<dd4pod::Geant4ParticleData> electrons;
-  for (auto part : parts)
-  {
-    if (part.pdgID == 11){electrons.push_back(part);}
-  }
-  return electrons;
-}
-*/
-
-
 int dis_electrons(const std::string& config_name)
 {
   // read our configuration
@@ -137,7 +33,7 @@ int dis_electrons(const std::string& config_name)
 
   const std::string rec_file      = config["rec_file"];
   const std::string detector      = config["detector"];
-  std::string       output_prefix = config["output_prefix"];
+  const std::string output_prefix = config["output_prefix"];
   const std::string test_tag      = config["test_tag"];
 
   fmt::print(fmt::emphasis::bold | fg(fmt::color::forest_green),
@@ -158,115 +54,62 @@ int dis_electrons(const std::string& config_name)
        {"target", "0.1"}}};
 
   // Run this in multi-threaded mode if desired
-  //ROOT::EnableImplicitMT(kNumThreads);
-
-  //Particle number enumeration
-  enum sidis_particle_ID
-  {
-    electron = 11,
-    pi_0     = 111,
-    pi_plus  = 211,
-    pi_minus = -211,
-    k_0      = 311,
-    k_plus   = 321,
-    k_minus  = -321,
-    proton   = 2212,
-    neutron  = 2112
-  };
-
-
-  const double electron_mass = util::get_pdg_mass("electron");
-
-  // Ensure our output prefix always ends on a dot, a slash or a dash
-  // Necessary when generating output plots
-  if (output_prefix.back() != '.' && output_prefix.back() != '/' && output_prefix.back() != '-') {
-    output_prefix += "-";
-  }
-
+  ROOT::EnableImplicitMT(kNumThreads);
   ROOT::RDataFrame d("events", rec_file);
 
-  // utility lambda functions to bind the reconstructed particle type
-  // (as we have no PID yet)
-  auto momenta_from_tracking =
-      [electron_mass](const std::vector<eic::TrackParametersData>& tracks) {
-        return util::momenta_from_tracking(tracks, electron_mass);
-      };
+  auto combinatorial_diff_ratio = [] (
+      const ROOT::VecOps::RVec<float>& v1,
+      const ROOT::VecOps::RVec<float>& v2
+  ) {
+    std::vector<float> v;
+    for (auto& i1: v1) {
+      for (auto& i2: v2) {
+        if (i1 != 0) {
+          v.push_back((i1-i2)/i1);
+        }
+      }
+    }
+    return v;
+  };
 
-/*
-  //Old dataframe
-  auto d0 = d.Define("p_rec", momenta_from_tracking, {"outputTrackParameters"})
-                .Define("N", "p_rec.size()")
-                .Define("p_sim", util::momenta_from_simulation, {"mcparticles"})
-                .Define("mom_sim", util::mom, {"p_sim"})
-                .Define("mom_rec", util::mom, {"p_rec"});
-*/
+  auto d0 = d.Define("Q2_sim", "InclusiveKinematicsTruth.Q2")
+             .Define("Q2_rec", "InclusiveKinematicsElectron.Q2")
+             .Define("Q2_res", combinatorial_diff_ratio, {"Q2_sim", "Q2_rec"})
+             .Define("x_sim", "InclusiveKinematicsTruth.x")
+             .Define("x_rec", "InclusiveKinematicsElectron.x")
+             .Define("x_res", combinatorial_diff_ratio, {"x_sim", "x_rec"})
+             ;
 
-  auto d0 = d.Define("p_recon", momenta_from_reconstruction, {"DummyReconstructedParticles"})
-                .Define("p_recon_sort", sort_momenta, {"p_recon"})
-                .Define("Q2_recon", Q2, {"p_recon_sort"})
-                .Define("Q2_recon_rand", randomize, {"Q2_recon"})
-                .Define("elec_Q2_recon_rand", "Q2_recon_rand[0]")
-                .Define("p_sim_M", util::momenta_from_simulation, {"mcparticles"})
-                .Define("p_sim", convertMtoE, {"p_sim_M"})
-                .Define("p_sim_sort", sort_momenta, {"p_sim"})
-                .Define("Q2_sim", Q2, {"p_sim_sort"})
-                .Define("elec_Q2_sim", "Q2_sim[0]")
-                .Define("Q2_diff", "(elec_Q2_recon_rand - elec_Q2_sim)/elec_Q2_sim")
-                .Define("p_diff", sub, {"p_recon","p_sim"});
-                /*
-                .Define("electrons_sim", elec_PID_sim, {"sorted_sim"})
-                .Define("Q2_sim_elec_pid", Q2_from_sim, {"electrons_sim"})
-                .Define("elec_Q2_sim_pid", "Q2_sim_elec_pid[0]");
-                */
-  //Testing script
-/*
-  auto dis = d0.Display({"p_diff"});
-  //dis -> Print();
-  cout << *d0.Max<double>("elec_Q2_recon_rand") << " " << *d0.Min<double>("elec_Q2_recon_rand") << endl;
-  cout << *d0.Max<double>("elec_Q2_sim") << " " << *d0.Min<double>("elec_Q2_sim") << endl;
-/**/
-  //cout << *d0.Count() << endl;
-  //Momentum
-  //auto h_mom_sim = d0.Histo1D({"h_mom_sim", "; GeV; counts", 100, 0, 50}, "mom_sim");
-  //auto h_mom_rec = d0.Histo1D({"h_mom_rec", "; GeV; counts", 100, 0, 50}, "mom_rec");
   //Q2
-  auto h_Q2_sim = d0.Histo1D({"h_Q2_sim", "; GeV; counts", 100, -5, 25}, "elec_Q2_sim");
-  auto h_Q2_rec = d0.Histo1D({"h_Q2_rec", "; GeV; counts", 100, -5, 25}, "elec_Q2_recon_rand");
-  auto h_Q2_res = d0.Histo1D({"h_Q2_res", ";    ; counts", 100, -10, 10}, "Q2_diff");
-/*
-  TH1D *h_Q2_res = (TH1D *)h_Q2_sim -> Clone();
-  TH1D *h_Q2_rec_copy = (TH1D *)h_Q2_rec -> Clone();
-  h_Q2_res -> Scale(1.0 / h_Q2_res -> Integral() );
-  h_Q2_res -> Add(h_Q2_rec_copy, -1.0 / h_Q2_rec_copy -> Integral() );
- */
-  TFitResultPtr f1  = h_Q2_res -> Fit("gaus", "S");
-  f1 -> Print("V");
-/*
-  printf("chisq %f A %f mean %f sigma %f \n", f1 -> Chi2(), 
-                                              f1 -> GetParameter(0), 
-                                              f1 -> GetParameter(1),
-                                              f1 -> GetParameter(2));
-*/
-
-  
-  auto c = new TCanvas();
+  auto h_Q2_sim = d0.Histo1D({"h_Q2_sim", "; GeV^2; counts", 100, -5, 25}, "Q2_sim");
+  auto h_Q2_rec = d0.Histo1D({"h_Q2_rec", "; GeV^2; counts", 100, -5, 25}, "Q2_rec");
+  auto h_Q2_res = d0.Histo1D({"h_Q2_res", ";      ; counts", 100, -10, 10}, "Q2_res");
+  //x
+  auto h_x_sim = d0.Histo1D({"h_x_sim", "; ; counts", 100, 0, +1}, "x_sim");
+  auto h_x_rec = d0.Histo1D({"h_x_rec", "; ; counts", 100, 0, +1}, "x_rec");
+  auto h_x_res = d0.Histo1D({"h_x_res", "; ; counts", 100, -1, 1}, "x_res");
+
+  TFitResultPtr f_Q2_res = h_Q2_res->Fit("gaus", "S");
+  if (f_Q2_res == 0) f_Q2_res->Print("V");
+  TFitResultPtr f_x_res = h_x_res->Fit("gaus", "S");
+  if (f_x_res == 0) f_x_res->Print("V");
 
   // Plot our histograms.
   // TODO: to start I'm explicitly plotting the histograms, but want to
   // factorize out the plotting code moving forward.
+
+  // Q2 comparison
   {
-    TCanvas c{"canvas", "canvas", 1200, 1200};
+    TCanvas c("c", "c", 1200, 1200);
     c.cd();
-    // gPad->SetLogx(false);
+    gPad->SetLogx(false);
     gPad->SetLogy(true);
-    //auto& h1 = *h_mom_sim;
-    //auto& h2 = *h_mom_rec;
     auto& h1 = *h_Q2_sim;
     auto& h2 = *h_Q2_rec;
     // histogram style
-    h1.SetLineColor(plot::kMpBlue);
+    h1.SetLineColor(common_bench::plot::kMpBlue);
     h1.SetLineWidth(2);
-    h2.SetLineColor(plot::kMpOrange);
+    h2.SetLineColor(common_bench::plot::kMpOrange);
     h2.SetLineWidth(2);
     // axes
     h1.GetXaxis()->CenterTitle();
@@ -275,20 +118,94 @@ int dis_electrons(const std::string& config_name)
     h1.DrawClone("hist");
     h2.DrawClone("hist same");
     // FIXME hardcoded beam configuration
-    plot::draw_label(18, 275, detector);
+    common_bench::plot::draw_label(18, 275, detector);
     TText* tptr1;
-    auto   t1 = new TPaveText(.6, .8417, .9, .925, "NB NDC");
-    t1->SetFillColorAlpha(kWhite, 0);
-    t1->SetTextFont(43);
-    t1->SetTextSize(25);
-    tptr1 = t1->AddText("simulated");
-    tptr1->SetTextColor(plot::kMpBlue);
-    tptr1 = t1->AddText("reconstructed");
-    tptr1->SetTextColor(plot::kMpOrange);
-    t1->Draw();
+    TPaveText t1(.6, .8417, .9, .925, "NB NDC");
+    t1.SetFillColorAlpha(kWhite, 0);
+    t1.SetTextFont(43);
+    t1.SetTextSize(25);
+    tptr1 = t1.AddText("simulated");
+    tptr1->SetTextColor(common_bench::plot::kMpBlue);
+    tptr1 = t1.AddText("reconstructed");
+    tptr1->SetTextColor(common_bench::plot::kMpOrange);
+    t1.Draw();
+    c.Print(fmt::format("{}Q2.png", output_prefix).c_str());
+  }
 
-    c.Print(fmt::format("{}momentum.png", output_prefix).c_str());
+  // Q2 resolution
+  {
+    TCanvas c("c", "c", 1200, 1200);
+    c.cd();
+    gPad->SetLogx(false);
+    gPad->SetLogy(true);
+    auto& h1 = *h_Q2_res;
+    // histogram style
+    h1.SetLineColor(common_bench::plot::kMpBlue);
+    h1.SetLineWidth(2);
+    // axes
+    h1.GetXaxis()->CenterTitle();
+    h1.GetYaxis()->CenterTitle();
+    // draw everything
+    h1.DrawClone("hist");
+    // FIXME hardcoded beam configuration
+    common_bench::plot::draw_label(18, 275, detector);
+    c.Print(fmt::format("{}Q2resolution.png", output_prefix).c_str());
   }
+
+  // x comparison
+  {
+    TCanvas c("c", "c", 1200, 1200);
+    c.cd();
+    gPad->SetLogx(true);
+    gPad->SetLogy(true);
+    auto& h1 = *h_x_sim;
+    auto& h2 = *h_x_rec;
+    // histogram style
+    h1.SetLineColor(common_bench::plot::kMpBlue);
+    h1.SetLineWidth(2);
+    h2.SetLineColor(common_bench::plot::kMpOrange);
+    h2.SetLineWidth(2);
+    // axes
+    h1.GetXaxis()->CenterTitle();
+    h1.GetYaxis()->CenterTitle();
+    // draw everything
+    h1.DrawClone("hist");
+    h2.DrawClone("hist same");
+    // FIXME hardcoded beam configuration
+    common_bench::plot::draw_label(18, 275, detector);
+    TText* tptr1;
+    TPaveText t1(.6, .8417, .9, .925, "NB NDC");
+    t1.SetFillColorAlpha(kWhite, 0);
+    t1.SetTextFont(43);
+    t1.SetTextSize(25);
+    tptr1 = t1.AddText("simulated");
+    tptr1->SetTextColor(common_bench::plot::kMpBlue);
+    tptr1 = t1.AddText("reconstructed");
+    tptr1->SetTextColor(common_bench::plot::kMpOrange);
+    t1.Draw();
+    c.Print(fmt::format("{}x.png", output_prefix).c_str());
+  }
+
+  // x resolution
+  {
+    TCanvas c("c", "c", 1200, 1200);
+    c.cd();
+    gPad->SetLogx(true);
+    gPad->SetLogy(true);
+    auto& h1 = *h_x_res;
+    // histogram style
+    h1.SetLineColor(common_bench::plot::kMpBlue);
+    h1.SetLineWidth(2);
+    // axes
+    h1.GetXaxis()->CenterTitle();
+    h1.GetYaxis()->CenterTitle();
+    // draw everything
+    h1.DrawClone("hist");
+    // FIXME hardcoded beam configuration
+    common_bench::plot::draw_label(18, 275, detector);
+    c.Print(fmt::format("{}xresolution.png", output_prefix).c_str());
+  }
+
   common_bench::write_test({dis_Q2_resolution}, fmt::format("{}dis_electrons.json", output_prefix));
 
   return 0;
diff --git a/benchmarks/dis/config.yml b/benchmarks/dis/config.yml
index a3bb11959f757b7598afec95a8f9a8048baa4afa..4b50d5e6379b3fc5dd60f9cc68d18307fb826a43 100644
--- a/benchmarks/dis/config.yml
+++ b/benchmarks/dis/config.yml
@@ -1,5 +1,6 @@
 dis:generate:
   stage: generate
+  extends: .phy_benchmark
   needs: ["common:detector"]
   timeout: 1 hours
   script:
@@ -7,12 +8,12 @@ dis:generate:
 
 dis:process:
   stage: process
+  extends: .phy_benchmark
   needs: ["common:detector", "dis:generate"]
   timeout: 2 hour
   script:
-    - echo "Temporarily disabling!!!"
-      #- compile_analyses.py dis
-      #- ./benchmarks/dis/dis.sh --config barrel --ebeam 18 --pbeam 275
+    - compile_analyses.py dis
+    - bash benchmarks/dis/dis.sh --config barrel --ebeam 18 --pbeam 275
   retry:
     max: 2
     when:
diff --git a/benchmarks/dis/gen.sh b/benchmarks/dis/gen.sh
index f0e74c99e0cf97d70a68caba5a5c62a29e258cde..2714b1ab224bbd7df5206d7b948c6d247a1ea0ce 100755
--- a/benchmarks/dis/gen.sh
+++ b/benchmarks/dis/gen.sh
@@ -65,8 +65,8 @@ echo "Compiling   benchmarks/dis/generator/pythia_dis.cxx ..."
 g++ benchmarks/dis/generator/pythia_dis.cxx -o ${TMP_PATH}/pythia_dis  \
    -I/usr/local/include  -I${LOCAL_PREFIX}/include \
    -O2 -std=c++11 -pedantic -W -Wall -Wshadow -fPIC  \
-   -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lpythia8 -ldl \
-   -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lHepMC3
+   $(pythia8-config --cxxflags --ldflags) \
+   $(HepMC3-config --cxxflags --ldflags)
 if [[ "$?" -ne "0" ]] ; then
   echo "ERROR compiling pythia"
   exit 1