diff --git a/dvmp/analysis/vm_mass.cxx b/dvmp/analysis/vm_mass.cxx
index a292c108a4adcc328e2291605cf6eb8d8b592c65..79f34eb9897c3628c4c22463864f787cbfcdc7d4 100644
--- a/dvmp/analysis/vm_mass.cxx
+++ b/dvmp/analysis/vm_mass.cxx
@@ -7,7 +7,9 @@
 #include <cmath>
 #include <fmt/color.h>
 #include <fmt/core.h>
+#include <fstream>
 #include <iostream>
+#include <nlohmann/json.hpp>
 #include <string>
 #include <vector>
 
@@ -17,9 +19,18 @@
 // file prefix), and labeled with our detector name.
 // TODO: I think it would be better to pass small json configuration file to
 //       the test, instead of this ever-expanding list of function arguments.
-int vm_mass(std::string_view rec_file, std::string_view vm_name,
-            std::string_view decay_name, std::string_view detector,
-            std::string output_prefix) {
+int vm_mass(const std::string& config_name) {
+  // read our configuration
+  std::ifstream config_file{config_name};
+  nlohmann::json config;
+  config_file >> config;
+
+  const std::string vm_name = config["vm_name"];
+  const std::string decay_name = config["decay_name"];
+  const std::string detector = config["detector"];
+  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),
              "Running VM invariant mass analysis...\n");
   fmt::print(" - Vector meson: {}\n", vm_name);
@@ -27,6 +38,18 @@ int vm_mass(std::string_view rec_file, std::string_view vm_name,
   fmt::print(" - Detector package: {}\n", detector);
   fmt::print(" - output prefix: {}\n", output_prefix);
 
+  // create our test definition
+  // test_tag
+  juggler_util::test vm_mass_resolution_test{
+      {{"name",
+        fmt::format("{}_{}_{}_mass_resolution", test_tag, vm_name, decay_name)},
+       {"title", fmt::format("{} --> {}{} Invariant Mass Resolution", vm_name,
+                             decay_name, decay_name)},
+       {"description", "Invariant Mass Resolution calculated from raw "
+                       "tracking data using a Gaussian fit."},
+       {"quantity", "resolution"},
+       {"target", ".1"}}};
+
   // Run this in multi-threaded mode if desired
   ROOT::EnableImplicitMT(kNumThreads);
 
@@ -41,9 +64,10 @@ int vm_mass(std::string_view rec_file, std::string_view vm_name,
   }
 
   // Open our input file file as a dataframe
-  ROOT::RDataFrame d{"events", rec_file};
+  ROOT::RDataFrame d{"events", config["rec_file"]};
 
-  // utility lambda functions to bind the vector meson and decay particle types
+  // utility lambda functions to bind the vector meson and decay particle
+  // types
   auto momenta_from_tracking =
       [decay_mass](const std::vector<eic::TrackParametersData>& tracks) {
         return util::momenta_from_tracking(tracks, decay_mass);
@@ -104,6 +128,15 @@ int vm_mass(std::string_view rec_file, std::string_view vm_name,
     // Print canvas to output file
     c.Print(fmt::format("{}vm_mass.png", output_prefix).c_str());
   }
+
+  // TODO we're not actually doing an IM fit yet, so for now just return an
+  // error for the test result
+  vm_mass_resolution_test.error(-1);
+
+  // write out our test data
+  juggler_util::write_test(vm_mass_resolution_test,
+                           fmt::format("{}vm_mass.json", output_prefix));
+
   // That's all!
   return 0;
 }
diff --git a/dvmp/dvmp.sh b/dvmp/dvmp.sh
index 6d4e184438196a4de0f5aa2f4eb58021847ed281..409853cfc5a098c71014007982bc36be76a22aac 100755
--- a/dvmp/dvmp.sh
+++ b/dvmp/dvmp.sh
@@ -42,6 +42,7 @@ source config/env.sh
 ## We also need the following benchmark-specific variables:
 ##
 ## - BENCHMARK_TAG: Unique identified for this benchmark process.
+## - BEAM_TAG:      Identifier for the chosen beam configuration
 ## - INPUT_PATH:    Path for generator-level input to the benchmarks
 ## - TMP_PATH:      Path for temporary data (not exported as artifacts)
 ## - RESULTS_PATH:  Path for benchmark output figures and files
@@ -109,12 +110,22 @@ ls -l
 
 ## =============================================================================
 ## Step 4: Analysis
-root -b -q "dvmp/analysis/vm_mass.cxx(\
- \"${REC_FILE}\", \
- \"${LEADING}\", \
- \"${DECAY}\", \
- \"${JUGGLER_DETECTOR}\", \
- \"${RESULTS_PATH}/${PLOT_TAG}\")"
+
+## write a temporary configuration file for the analysis script
+CONFIG="${TMP_PATH}/${PLOT_TAG}.json"
+cat << EOF >> ${CONFIG}
+{
+  "rec_file": "${REC_FILE}",
+  "vm_name": "${LEADING}",
+  "decay": "${DECAY}",
+  "detector": "${JUGGLER_DETECTOR}",
+  "output_prefix": "${RESULTS_PATH}/${PLOT_TAG}",
+  "test_tag": "${LEADING}_${DECAY}_${BEAM_TAG}"
+}
+EOF
+
+## run the analysis script with this configuration
+root -b -q "dvmp/analysis/vm_mass.cxx(\"${CONFIG}\")"
 
 if [ "$?" -ne "0" ] ; then
   echo "ERROR running root script"
diff --git a/dvmp/env.sh b/dvmp/env.sh
index d449f479b3d2ffacb26cbbcaf65e8e43d9b0d512..17ef386b0a67b964e75470576f5374566f471621 100644
--- a/dvmp/env.sh
+++ b/dvmp/env.sh
@@ -5,6 +5,7 @@
 ## It defines the following additional variables: 
 ##
 ##  - BENCHMARK_TAG:          Tag to identify this particular benchmark
+##  - BEAM_TAG                Tag to identify the beam configuration
 ##  - INPUT_PATH:             Path for generator-level input to the benchmarks
 ##  - TMP_PATH:               Path for temporary data (not exported as artifacts)
 ##  - RESULTS_PATH:           Path for benchmark output figures and files
@@ -21,22 +22,25 @@
 export BENCHMARK_TAG="dvmp"
 echo "Setting up the local environment for the ${BENCHMARK_TAG^^} benchmarks"
 
+## Extra beam tag to identify the desired beam configuration
+export BEAM_TAG="${EBEAM}on${PBEAM}"
+
 ## Data path for input data (generator-level hepmc file)
-INPUT_PATH="input/${BENCHMARK_TAG}/${EBEAM}on${PBEAM}"
+INPUT_PATH="input/${BENCHMARK_TAG}/${BEAM_TAG}"
 mkdir -p ${INPUT_PATH}
 export INPUT_PATH=`realpath ${INPUT_PATH}`
 echo "INPUT_PATH:             ${INPUT_PATH}"
 
 
 ## Data path for temporary data (not exported as artifacts)
-TMP_PATH=${LOCAL_PREFIX}/tmp/${EBEAM}on${PBEAM}
+TMP_PATH=${LOCAL_PREFIX}/tmp/${BEAM_TAG}
 mkdir -p ${TMP_PATH}
 export TMP_PATH=`realpath ${TMP_PATH}`
 echo "TMP_PATH:               ${TMP_PATH}"
 
 ## Data path for benchmark output (plots and reconstructed files
 ## if not too big).
-RESULTS_PATH="results/${BENCHMARK_TAG}/${EBEAM}on${PBEAM}"
+RESULTS_PATH="results/${BENCHMARK_TAG}/${BEAM_TAG}"
 mkdir -p ${RESULTS_PATH}
 export RESULTS_PATH=`realpath ${RESULTS_PATH}`
 echo "RESULTS_PATH:           ${RESULTS_PATH}"