diff --git a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py
index be31e19994c9e93391f12228f80ca1096c222d51..0d94cf0c344b4010627ad63826c4d7aa4732a580 100755
--- a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py
+++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py
@@ -10,8 +10,11 @@
 # For MDC, we assume this is TI12 geometry
 #
 import sys
+import time
 import argparse
 
+a = time.time()
+
 parser = argparse.ArgumentParser(description="Run FASER reconstruction")
 
 parser.add_argument("file_path",
@@ -20,7 +23,7 @@ parser.add_argument("run_type", nargs="?", default="",
                     help="Specify run type (if it can't be parsed from path)")
 parser.add_argument("-t", "--tag", default="",
                     help="Specify digi tag (to append to output filename)")
-parser.add_argument("-n", "--nevents", type=int, default=-1,
+parser.add_argument("-n", "--nevts", type=int, default=-1,
                     help="Specify number of events to process (default: all)")
 parser.add_argument("-v", "--verbose", action='store_true', 
                     help="Turn on DEBUG output")
@@ -40,8 +43,8 @@ else:
     print(f"Assuming {runtype} geometry for MDC")
 
 print(f"Starting digitization of {filepath.name} with type {runtype}")
-if args.nevents > 0:
-    print(f"Reconstructing {args.nevents} events by command-line option")
+if args.nevts > 0:
+    print(f"Reconstructing {args.nevts} events by command-line option")
 
 # Start digitization
 
@@ -93,7 +96,11 @@ if filestem[-5:] == "-HITS":
     filestem = filestem[:-5]
 
 if len(args.tag) > 0:
-    filestem += f"-{args.tag}"
+    print(f"{args.tag} in {filestem}?")
+    if args.tag in filestem:
+        print(f"Not adding tag {args.tag} to file {filestem}")
+    else:
+        filestem += f"-{args.tag}"
 
 ConfigFlags.Output.RDOFileName = f"{filestem}-RDO.root"
 
@@ -141,4 +148,10 @@ acc.foreach_component("*ClassID*").OutputLevel = INFO
 acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M"
 
 # Execute and finish
-sys.exit(int(acc.run(maxEvents=args.nevents).isFailure()))
+sc = acc.run(maxEvents=args.nevts)
+
+b = time.time()
+from AthenaCommon.Logging import log
+log.info(f"Finish execution in {b-a} seconds")
+
+sys.exit(not sc.isSuccess())
diff --git a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py
new file mode 100755
index 0000000000000000000000000000000000000000..9c656de660dc7957aa222b691e50af457a870bf0
--- /dev/null
+++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Run with:
+# ./faser_digi.py filepath runtype
+# 
+# filepath - fully qualified path, including url if needed, to the input HITS file
+#   example: "root://eospublic.cern.ch//eos/experiment/faser/sim/GeniePilot/HITS/1/faser.150fbInv.1.001.HITS.pool.root"
+# 
+# For MDC, we assume this is TI12 geometry
+#
+import sys
+import time
+import argparse
+
+a = time.time()
+
+parser = argparse.ArgumentParser(description="Run FASER reconstruction")
+
+parser.add_argument("dir_path",
+                    help="Fully qualified path of the input file directory")
+parser.add_argument("run_type", nargs="?", default="",
+                    help="Specify run type (if it can't be parsed from path)")
+parser.add_argument("-s", "--slice", type=int, default=0,
+                    help="Specify file slice to produce")
+parser.add_argument("-f", "--files", type=int, default=5,
+                    help="Specify number of input files to run in one batch")
+parser.add_argument("-t", "--tag", default="",
+                    help="Specify digi tag (to append to output filename)")
+parser.add_argument("-n", "--nevts", type=int, default=-1,
+                    help="Specify number of events to process (default: all)")
+parser.add_argument("-v", "--verbose", action='store_true', 
+                    help="Turn on DEBUG output")
+
+args = parser.parse_args()
+
+from pathlib import Path
+
+dirpath = Path(args.dir_path)
+
+# runtype has been provided
+if len(args.run_type) > 0:
+    runtype=args.run_type
+
+else:
+    runtype = "TI12MC"
+    print(f"Assuming {runtype} geometry for MDC")
+
+# Does the directory exist?
+if not (dirpath.exists() and dirpath.is_dir()):
+    print(f"Problem with directory {args.dir_path}")
+    sys.exit(1)
+
+# Create segment list
+seglist = list(range(args.slice*args.files, (args.slice+1)*args.files))
+
+# Now build file list
+filelist = []
+dirlist = list(dirpath.glob('FaserMC-*-HITS.root'))
+if len(dirlist) == 0:
+    print(f"No HITS file found in directory {args.dir_path}")
+    sys.exit(1)
+
+for seg in seglist:
+    # Assume these are in numerical order from 0
+    if seg >= len(dirlist):
+        print(f"Requested file segment {seg} but only {len(dirlist)} files found")
+        break
+    filelist.append(dirlist[seg])  
+
+if len(filelist) == 0:
+    # Asked for range that doesn't exist
+    print(f"No files found for slice {args.slice} with Nfiles={args.files}")
+    sys.exit(1)
+
+# Figure out the file pattern for the output
+stem = filelist[0].stem
+spl = stem.split('-')
+short = spl[1]
+run = spl[2]
+seglo = int(spl[3])
+# Can be multiple tags
+tagstr = ''
+for tag in spl[4:]:
+    if tag == "HITS": break
+    if len(tagstr) > 0:
+        tagstr += "-"
+    tagstr += tag
+
+# Also find the largest file number
+stem = filelist[-1].stem
+spl = stem.split('-')
+seghi = int(spl[3])
+
+# Build output filename
+if seglo == 0 and (seghi+1) == len(dirlist):  # Full run
+    outfile = f"FaserMC-{short}-{run}"
+elif seglo == seghi:  # Single segment
+    outfile = f"FaserMC-{short}-{run}-{seglo:05}"
+else:
+    outfile = f"FaserMC-{short}-{run}-{seglo:05}-{seghi:05}"
+
+# Add existing tag
+if len(tagstr) > 0:
+    outfile += f"-{tagstr}"
+
+# Was a tag requested?  
+if len(args.tag) > 0:
+    if args.tag in tagstr:
+        print(f"Not adding tag {args.tag} to file {filelist[0]}")
+    else:
+        outfile += f"-{args.tag}"
+
+# Finish output file
+outfile += "-RDO.root"
+
+print(f"Found files from {seglo} to {seghi}")
+print(f"Starting digitization of outfile {outfile} with type {runtype}")
+if args.nevts > 0:
+    print(f"Reconstructing {args.nevts} events by command-line option")
+
+# Start digitization
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from AthenaCommon.Constants import VERBOSE, INFO
+
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+
+Configurable.configurableRun3Behavior = True
+    
+# Flags for this job
+ConfigFlags.Input.isMC = True                    # Needed to bypass autoconfig
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"   # Use MC conditions for now
+
+ConfigFlags.Input.ProjectName = "mc20"
+ConfigFlags.GeoModel.Align.Dynamic    = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.Digitization.TruthOutput = True
+
+# TI12 old geometry
+if runtype == "TI12OldMC":
+    ConfigFlags.GeoModel.FaserVersion = "FASER-01" 
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+
+# Testbeam setup 
+elif runtype == "TestBeamMC" :
+    ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" 
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00"
+
+# New TI12 geometry (ugh)
+elif runtype == "TI12MC":
+    ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" 
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"
+
+else:
+    print("Invalid run type found:", runtype)
+    print("Specify correct type or update list")
+    sys.exit(-1)
+
+
+# Try just passing the filelist
+ConfigFlags.Input.Files = [str(file) for file in filelist]
+ConfigFlags.Output.RDOFileName = outfile
+
+#
+# Play around with this?
+# ConfigFlags.Concurrency.NumThreads = 2
+# ConfigFlags.Concurrency.NumConcurrentEvents = 2
+ConfigFlags.lock()
+
+#
+# Configure components
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+    
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(PoolWriteCfg(ConfigFlags))
+
+#
+# Needed, or move to MainServicesCfg?
+from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+acc.merge(FaserGeometryCfg(ConfigFlags))
+
+# Set up algorithms
+from FaserSCT_Digitization.FaserSCT_DigitizationConfigNew import FaserSCT_DigitizationCfg
+acc.merge(FaserSCT_DigitizationCfg(ConfigFlags))
+
+from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg
+acc.merge(CaloWaveformDigitizationCfg(ConfigFlags))
+
+from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg
+acc.merge(ScintWaveformDigitizationCfg(ConfigFlags))
+
+# Configure verbosity    
+# ConfigFlags.dump()
+if args.verbose:
+    acc.foreach_component("*").OutputLevel = VERBOSE
+
+else:
+    acc.foreach_component("*").OutputLevel = INFO
+
+acc.foreach_component("*ClassID*").OutputLevel = INFO
+
+acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M"
+
+# Execute and finish
+sc = acc.run(maxEvents=args.nevts)
+
+b = time.time()
+from AthenaCommon.Logging import log
+log.info(f"Finish execution in {b-a} seconds")
+
+sys.exit(not sc.isSuccess())
diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh
index 2070b43f3979c92823d2cdd78e0077cb7343c4d9..449bd8074f93c09bc3d0aa8b5bc940022e528885 100755
--- a/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh
+++ b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh
@@ -15,6 +15,8 @@
 # If this matches gen/g???? it will be passed to the job
 #
 #----------------------------------------
+# Keep track of time
+SECONDS=0
 #
 # Parse command-line options
 file_path=${1}
@@ -96,7 +98,11 @@ if [[ "$recotag" == "reco/r"???? ]]; then
 fi
 if [[ "$recotag" == "digi/d"???? ]]; then
   tag=`echo "$recotag" | cut -c 6-11`
-  echo "Found reco tag: $tag"
+  echo "Found digi tag: $tag"
+fi
+if [[ "$recotag" == "sim/s"???? ]]; then
+  tag=`echo "$recotag" | cut -c 5-10`
+  echo "Found sim tag: $tag"
 fi
 #
 # Move to the run directory
@@ -126,3 +132,4 @@ fi
 #
 # Print out ending time
 date
+echo "Job finished after $SECONDS seconds"
diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json
index d4e9bf1c6b154d39e240f4e094bf648a593613bd..998137d88277e5a4dd579e8dac02382ca525e9bf 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json
@@ -1,7 +1,7 @@
 {
     "run": 110004,
     "segment": 0,
-    "file_length": 100,
+    "file_length": 1000,
     "model": "DarkPhoton",
     "model_path": "/eos/experiment/faser/gen/ForeseeMDC/DarkPhoton/npy/events_14TeV_m0.3162GeV_c2e-06to_13_-13.npy",
     "short": "MDC_FS_Amm_316MeV_2Em6",
diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json
index d2e0ab8e3c6ef9186f3efc1c6edde50d36295d62..e7e27b8b4948b13b635a9caa58cbef09b4011323 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json
@@ -1,5 +1,5 @@
 {
-    "file_length": 200,
+    "file_length": 250,
     "mass": 0.511,
     "maxE": 1000.0,
     "minE": 10.0,
diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json
index e40ea323a2b5e79165e8826f263f43e5d6c7c97c..6802663e959bb6021e4187eed9eb65351b58e36d 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json
@@ -1,5 +1,5 @@
 {
-    "file_length": 500,
+    "file_length": 250,
     "mass": 139.6,
     "maxE": 100.0,
     "minE": 100.0,
diff --git a/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py b/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py
index 9579e2cf5432a5210fe365ecd5e08ba10ad3d643..607ce904658f777b0403a5b452b58b4160f66b0e 100755
--- a/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py
+++ b/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py
@@ -67,13 +67,13 @@ if __name__ == '__main__':
     ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file
 
     # Property bag for particle gun keyword:argument pairs
-    # Apply +80mm vertical shift (to get to FASER CL)
-    # And 150 uRad crossing angle
+    # Apply +12mm vertical shift (to get to FASER CL)
+    # And 150 uRad crossing angle (Jamie claims this is half-angle)
     ConfigFlags.addFlag("Sim.Gun",{"Generator" : "Foresee"})  
     ConfigFlags.addFlag("Sim.Beam.xangle", 0)  # Potential beam crossing angles
     ConfigFlags.addFlag("Sim.Beam.yangle", -0.000150)    
     ConfigFlags.addFlag("Sim.Beam.xshift", 0)  # Potential beam shift
-    ConfigFlags.addFlag("Sim.Beam.yshift", 80.)        
+    ConfigFlags.addFlag("Sim.Beam.yshift", 12.) 
 
     ConfigFlags.GeoModel.FaserVersion = "FASERNU-03"   # Geometry set-up
     ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"   # Conditions set-up
diff --git a/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py b/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py
index 75ad61956491d76f6ddfd5d5b6695479098b36b2..d583c0127917f626c6bd51a4b2dfd487eef655fa 100755
--- a/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py
+++ b/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py
@@ -83,14 +83,20 @@ if __name__ == '__main__':
     from AthenaCommon.SystemOfUnits import GeV, TeV, cm, m
     from AthenaCommon.PhysicalConstants import pi
 
-    print(f"Using pid: {args.pid}")
+    if isinstance(args.pid, list):
+        # Note args.pid is a list, must make this a set for ParticleGun
+        pidarg = set(args.pid)
+    else:
+        # Just pass a single value
+        pidarg = args.pid
+
+    print(f"Using pid: {args.pid} => {pidarg}")
 
-    # Note args.pid is a list
     # For ParticleGun to accept this, we need to turn it into a set...
     import ParticleGun as PG
     ConfigFlags.Sim.Gun = {
         "Generator" : "SingleParticle", 
-        "pid" : set(args.pid), "mass" : args.mass, 
+        "pid" : pidarg, "mass" : args.mass, 
         "theta" :  PG.GaussianSampler(0, args.angle, oneside = True), 
         "phi" : [0, 2*pi], "radius" : args.radius, 
         "randomSeed" : args.outfile }
diff --git a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh
index 435250baa549a0be2417ae7bc303e078ca26ba03..6278fddba9c504ae360c0947c445553b455cdccc 100755
--- a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh
+++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh
@@ -16,6 +16,8 @@
 # If this matches gen/g???? or sim/s???? it will be passed to the job
 #
 #----------------------------------------
+# Keep track of time
+SECONDS=0
 #
 # Parse command-line options
 config_path=${1}
@@ -110,11 +112,11 @@ source build/x86*/setup.sh
 cd calypso
 gentag=`git describe`
 if [[ "$gentag" == "gen/g"???? ]]; then
-  gtag=`echo "$gentag" | cut -c 5-10`
-  echo "Found gen tag: $gtag"
+  tag=`echo "$gentag" | cut -c 5-10`
+  echo "Found gen tag: $tag"
 fi
 if [[ "$gentag" == "sim/s"???? ]]; then
-  tag=`echo "$recotag" | cut -c 6-11`
+  tag=`echo "$gentag" | cut -c 5-10`
   echo "Found sim tag: $tag"
 fi
 #
@@ -137,11 +139,12 @@ fi
 cd "${config_file_stem}-${seg_str}"
 #
 # Run job
-if [[ -z "$gtag" ]]; then
+if [[ -z "$tag" ]]; then
     faserMDC_foresee.py  "--conf=$config_path" "--segment=$seg_str"
 else
-    faserMDC_foresee.py  "--conf=$config_path" "--segment=$seg_str" "--tag=$gtag"
+    faserMDC_foresee.py  "--conf=$config_path" "--segment=$seg_str" "--tag=$tag"
 fi
 #
 # Print out ending time
 date
+echo "Job finished after $SECONDS seconds"
diff --git a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh
index 7cca0b66dab4e42f23d86594f6ce5e7397430d82..c85fa4803a7fe9d2acfd0d3e29beaf26e515afe6 100755
--- a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh
+++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh
@@ -16,6 +16,8 @@
 # If this matches gen/g???? or sim/s???? it will be passed to the job
 #
 #----------------------------------------
+# Keep track of time
+SECONDS=0
 #
 # Parse command-line options
 config_path=${1}
@@ -110,11 +112,11 @@ source build/x86*/setup.sh
 cd calypso
 gentag=`git describe`
 if [[ "$gentag" == "gen/g"???? ]]; then
-  gtag=`echo "$gentag" | cut -c 5-10`
-  echo "Found gen tag: $gtag"
+  tag=`echo "$gentag" | cut -c 5-10`
+  echo "Found gen tag: $tag"
 fi
 if [[ "$gentag" == "sim/s"???? ]]; then
-  tag=`echo "$recotag" | cut -c 6-11`
+  tag=`echo "$gentag" | cut -c 5-10`
   echo "Found sim tag: $tag"
 fi
 #
@@ -137,11 +139,14 @@ fi
 cd "${config_file_stem}-${seg_str}"
 #
 # Run job
-if [[ -z "$gtag" ]]; then
+if [[ -z "$tag" ]]; then
     faserMDC_particlegun.py  "--conf=$config_path" "--segment=$seg_str"
 else
-    faserMDC_particlegun.py  "--conf=$config_path" "--segment=$seg_str" "--tag=$gtag"
+    faserMDC_particlegun.py  "--conf=$config_path" "--segment=$seg_str" "--tag=$tag"
 fi
 #
 # Print out ending time
 date
+echo "Job finished after $SECONDS seconds"
+#
+
diff --git a/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py
index 30b40afce32b6ce8e124a9d2fcee3b32f0f7ae6e..15632432e6aa0a4b9a737b191955481212358024 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py
+++ b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py
@@ -14,8 +14,11 @@
 #   MDC will assume this geometry.
 #
 import sys
+import time
 import argparse
 
+a = time.time()
+
 parser = argparse.ArgumentParser(description="Run FASER reconstruction")
 
 parser.add_argument("file_path",
@@ -204,4 +207,11 @@ acc.foreach_component("*ClassID*").OutputLevel = INFO
 acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M"
 
 # Execute and finish
-sys.exit(int(acc.run(maxEvents=args.nevents).isFailure()))
+sc = acc.run(maxEvents=args.nevents)
+
+b = time.time()
+from AthenaCommon.Logging import log
+log.info(f"Finish execution in {b-a} seconds")
+
+sys.exit(int(sc.isFailure))
+
diff --git a/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py b/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py
index 0c93b9fe6191dff44c1db47a38a747653f8d7bc4..323adda69d9228ecdbde65431b09bf42a579745d 100755
--- a/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py
+++ b/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py
@@ -4,9 +4,10 @@ Produce simulated hits from input 4-vectors
 Derived from G4FaserAlgConfigNew
 
 Usage:
-faserMDC_simulate.py filepath
+faserMDC_simulate.py filepath outfile
 
 filepath - full path, including url if needed, to the input 4-vector file
+outfile - output filename, parameters will be inferred from this name
 
 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations
 """
@@ -27,8 +28,25 @@ if __name__ == '__main__':
     parser.add_argument("file_path",
                         help="Fully qualified path of the raw input file")
 
+    parser.add_argument("output",
+                        help="Output file name")
+
+    #parser.add_argument("--run", type=int, default=123456,
+    #                    help="Specify run number to use in simulated data")
+
+    parser.add_argument("--xangle", type=float, default=0.0,
+                        help="Specify H crossing angle (in Radians)")
+    parser.add_argument("--yangle", type=float, default=0.0,
+                        help="Specify V crossing angle (in Radians)")
+    parser.add_argument("--xshift", type=float, default=0.0,
+                        help="Specify H shift of events wrt FASER (in mm)")
+    parser.add_argument("--yshift", type=float, default=0.0,
+                        help="Specify V shift of events wrt FASER (in mm)")
+
     parser.add_argument("-t", "--tag", default="",
                         help="Specify sim tag (to append to output filename)")
+    parser.add_argument("-s", "--skip", type=int, default=0,
+                        help="Specify number of events to skip (default: none)")
     parser.add_argument("-n", "--nevents", type=int, default=-1,
                         help="Specify number of events to process (default: all)")
     parser.add_argument("-v", "--verbose", action='store_true', 
@@ -47,17 +65,36 @@ if __name__ == '__main__':
 
     filestem = filepath.stem
     if len(args.tag) > 0:
-        filestem += f"-{args.tag}"
+        if args.tag in filestem:
+            print(f"Not adding tag {args.tag} to {filestem}")
+        else:
+            filestem += f"-{args.tag}"
+
+    if args.output:
+        # Just directly specify the output filename
+        outfile = args.output
+
+        spl = outfile.split('-')
+        if len(spl) < 4:
+            print(f"Can't get run number from {outfile}!")
+            sys.exit(1)
+
+        runnum = int(spl[2])
+        segnum = int(spl[3])
 
-    outfile = f"{filestem}-HITS.root"
-    runnumber = 123456   # To be improved...
-    segment = 0
+    else:
+        outfile = f"{filestem}-HITS.root"
+        print(f"Output file name not specified")
+        sys.exit(1)
 
     print(f"Outfile: {outfile}")
 
 #
 # Figure out events to run
 #
+    if args.skip > 0:
+        print(f"Skipping {args.skip} events by command-line option")
+
     if args.nevents > 0:
         print(f"Reconstructing {args.nevents} events by command-line option")
 #
@@ -77,15 +114,19 @@ if __name__ == '__main__':
 #
 # All these must be specified to avoid auto-configuration
 #
-    ConfigFlags.Input.RunNumber = [runnumber] #Isn't updating - todo: investigate
+    ConfigFlags.Input.RunNumber = [ runnum ] 
     ConfigFlags.Input.OverrideRunNumber = True
-    ConfigFlags.Input.LumiBlockNumber = [(segment+1)]
+    ConfigFlags.Input.LumiBlockNumber = [ (segnum+1) ]
     ConfigFlags.Input.isMC = True
 #
 # Input file name
 # 
     # Path mangles // in url, so use direct file_path here
-    ConfigFlags.Input.Files = args.file_path
+    ConfigFlags.Input.Files = [ args.file_path ]
+#
+# Skip events
+#
+    ConfigFlags.Exec.SkipEvents = args.skip
 #
 # Output file name
 # 
@@ -98,12 +139,15 @@ if __name__ == '__main__':
     ConfigFlags.Sim.ReleaseGeoModel = False
     ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file
 
-    ConfigFlags.addFlag("Sim.Beam.xangle", 0)  # Potential beam crossing angles
-    ConfigFlags.addFlag("Sim.Beam.yangle", 0)    
+    # Units are radians and mm
+    ConfigFlags.addFlag("Sim.Beam.xangle", args.xangle)  # Potential beam crossing angles
+    ConfigFlags.addFlag("Sim.Beam.yangle", args.yangle)    
+    ConfigFlags.addFlag("Sim.Beam.xshift", args.xshift)  # Potential beam shift
+    ConfigFlags.addFlag("Sim.Beam.yshift", args.yshift)    
 
-    ConfigFlags.GeoModel.FaserVersion = "FASERNU-02"             # Geometry set-up
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"             # Conditions set-up
-    ConfigFlags.addFlag("Input.InitialTimeStamp", 0)             # To avoid autoconfig 
+    ConfigFlags.GeoModel.FaserVersion = "FASERNU-03"     # Geometry set-up
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"     # Conditions set-up
+    ConfigFlags.addFlag("Input.InitialTimeStamp", 0)     # To avoid autoconfig 
     ConfigFlags.GeoModel.Align.Dynamic = False
 
     # import sys
@@ -112,7 +156,7 @@ if __name__ == '__main__':
 #
 # MDC geometry configuration
 #
-    detectors = ['Veto', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion']
+    detectors = ['Veto', 'VetoNu', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion']
 #
 # Setup detector flags
 #
@@ -154,16 +198,21 @@ if __name__ == '__main__':
 #
 # Shift LOS
 #
+    if (ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle or
+        ConfigFlags.Sim.Beam.xshift or ConfigFlags.Sim.Beam.yshift):
 
-    if ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle:
         MCEventKey = "BeamTruthEventShifted"
         import McParticleEvent.Pythonizations
         from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg
         cfg.merge(ShiftLOSCfg(ConfigFlags, OutputMCEventKey = MCEventKey,
-                              xcross = ConfigFlags.Sim.Beam.xangle, ycross = ConfigFlags.Sim.Beam.yangle))
+                              xcross = ConfigFlags.Sim.Beam.xangle, 
+                              ycross = ConfigFlags.Sim.Beam.yangle,
+                              xshift = ConfigFlags.Sim.Beam.xshift,
+                              yshift = ConfigFlags.Sim.Beam.yshift))
+
     else:    
         MCEventKey = "BeamTruthEvent"
-    
+
 #
 # Add the G4FaserAlg
 #
@@ -194,9 +243,9 @@ if __name__ == '__main__':
     sc = cfg.run(maxEvents=args.nevents)
 
     b = time.time()
-    log.info("Run G4FaserAlg in " + str(b-a) + " seconds")
+    log.info("Finish execution in " + str(b-a) + " seconds")
 #
 # Success should be 0
 #
-    sys.exit(not sc.isSuccess())
+    sys.exit(int(sc.isFailure()))
 
diff --git a/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh b/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e00adfd50005e3d3600a7a5df55a45039f89e391
--- /dev/null
+++ b/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh
@@ -0,0 +1,153 @@
+#!/bin/bash
+# Used with a condor file to submit to vanilla universe
+#
+# Usage:
+# submit_faserMDC_simluate.sh input_file output_file [release_directory] [working_directory] [skip] [nevts]
+# 
+# input_file - full file name (with path)
+# output_file - full output file name
+# release_directory - optional path to release install directory (default pwd)
+# working_directory - optional path to output directory location (default pwd)
+# skip - events in input file to skip
+# nevts = events in input file to process
+#
+# The release directory must already be set up 
+# (so an unqualified asetup can set up the release properly)
+#
+# Script will use git describe to find the release tag.  
+# If this matches gen/g???? or sim/s???? it will be passed to the job
+#
+#----------------------------------------
+# Keep track of time
+SECONDS=0
+#
+# Parse command-line options
+infile=${1}
+outfile=${2}
+release_directory=${3}
+working_directory=${4}
+skip_events=${5}
+nevts=${6}
+#
+# Set defaults if arguments aren't provided
+if [ -z "$infile" ]
+then
+  echo "No input file specified!"
+  echo "Usage: submit_faserMDC_simulate.sh input_file output_file [release dir] [output dir]"
+  exit 1
+fi
+#
+if [ -z "$outfile" ]
+then
+  outfile="FaserMC-Test-123456-00000-HITS.root"
+  echo "No output file specified, using $outfile !"
+fi
+#
+if [ -z "$release_directory" ]
+then
+  release_directory=`pwd`
+fi
+#
+if [ -z "$working_directory" ]
+then
+  working_directory=`pwd`
+fi
+#
+if [ -z "$skip_events" ]
+then
+  skip_events=0
+fi
+#
+if [ -z "$nevts" ]
+then
+  nevts=-1
+fi
+#
+starting_directory=`pwd`
+#
+# Now extract the file information
+# Here we do this on the output file, as the input files can be non-standard
+#
+# First, get the filename
+outfilename=$(basename "$outfile")
+# 
+# Now split based on '.' to get stem
+defaultIFS=$IFS
+IFS='.'
+read file_stem ext <<< "$outfilename"
+#
+# Try to find the run number
+IFS='-'
+# Read the split words into an array based on delimeter
+read faser short run_number seg <<< "$file_stem"
+#
+# Set the IFS delimeter back or else echo doesn't work...
+IFS=$defaultIFS
+#
+# Check if we found a number, use full input file name if not
+output_directory="$working_directory/${run_number}"
+re='^[0-9]+$'
+if ! [[ $run_number =~ $re ]] ; then
+    # Not a number...
+    output_directory="$working_directory/${file_stem}"
+fi
+#
+# Make output directory if needed
+mkdir -p "$output_directory"
+#
+# This magic redirects everything in this script to our log file
+exec >& "$output_directory/${file_stem}.log"
+echo `date` - $HOSTNAME
+echo "Input File: $infile"
+echo "Output File: $outfilename"
+echo "Release: $release_directory"
+echo "Output: $output_directory"
+echo "Starting: $starting_directory"
+echo "Skip: $skip_events"
+echo "Nevts: $nevts"
+#
+# Set up the release (do this automatically)?
+export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
+source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh 
+#
+# Try automatic
+# Always go back to the starting directory in case paths are relative
+cd "$starting_directory"
+cd "$release_directory"
+# This doesn't seem to work, as we need the --input argument
+#asetup 
+#source build/x8*/setup.sh
+#
+# Do this by hand
+asetup --input=calypso/asetup.faser Athena,22.0.49
+source build/x86*/setup.sh
+#
+# Move to the run directory
+cd "$starting_directory"
+cd "$output_directory"
+#
+# Remove any previous directory if it exists
+#if [[ -e "$file_stem" ]]; then
+#    echo "Remove previous directory $file_stem"
+#    rm -rf "$file_stem"
+#fi
+#
+# Make run directory
+if [[ -e "${file_stem}" ]]; then
+    echo "Directory ${file_stem} already exists"
+else
+    mkdir "${file_stem}"
+fi
+cd "${file_stem}"
+#
+# Run job
+#if [[ -z "$tag" ]]; then
+#fi
+faserMDC_simulate.py  --skip "$skip_events" -n "$nevts" "$infile" "$outfile"
+
+#
+# Print out ending time
+date
+echo "Job finished after $SECONDS seconds"
+#
+