diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/CMakeLists.txt b/Simulation/Tools/CaloSamplingFractionAnalysis/CMakeLists.txt
index 79c27a60b40f628bcab172367786753ac7ff36e1..c78226828e64b0a5de8e569e2f5921932f294a99 100644
--- a/Simulation/Tools/CaloSamplingFractionAnalysis/CMakeLists.txt
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/CMakeLists.txt
@@ -10,20 +10,25 @@ atlas_depends_on_subdirs( PUBLIC
                           GaudiKernel
                           PRIVATE
                           Calorimeter/CaloDetDescr
+                          Calorimeter/CaloEvent
                           Calorimeter/CaloIdentifier
                           Calorimeter/CaloSimEvent
-                          Calorimeter/CaloEvent
                           Control/AthenaBaseComps
                           DetectorDescription/GeoModel/GeoAdaptors
+                          DetectorDescription/Identifier
                           Event/EventInfo
-                          Generators/AtlasHepMC
-                          LArCalorimeter/LArSimEvent
+                          External/AtlasHepMC/AtlasHepMC
                           LArCalorimeter/LArElecCalib
+                          LArCalorimeter/LArG4/LArG4RunControl
+                          LArCalorimeter/LArGeoModel/LArReadoutGeometry
+                          LArCalorimeter/LArSimEvent
                           TileCalorimeter/TileDetDescr
                           TileCalorimeter/TileSimEvent )
 
 # External dependencies:
 find_package( CLHEP )
+find_package( HepMC )
+find_package( Eigen )
 find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread Table MathMore Minuit Minuit2 Matrix Physics HistPainter Rint Graf Graf3d Gpad Html Postscript Gui GX11TTF GX11 )
 
 # tag ROOTBasicLibs was not recognized in automatic conversion in cmt2cmake
@@ -34,8 +39,8 @@ find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread Table MathMore
 atlas_add_component( CaloSamplingFractionAnalysis
                      src/*.cxx
                      src/components/*.cxx
-                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} 
-                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AtlasHepMCLib GaudiKernel CaloDetDescrLib CaloIdentifier CaloSimEvent CaloEvent AthenaBaseComps GeoAdaptors EventInfo LArSimEvent TileDetDescr TileSimEvent )
+                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} ${HEPMC_LIBRARIES} GaudiKernel CaloDetDescrLib CaloIdentifier CaloSimEvent CaloEvent AthenaBaseComps GeoAdaptors EventInfo LArSimEvent LArG4RunControl LArReadoutGeometry TileDetDescr TileSimEvent )
 
 # Install files from the package:
 # atlas_install_headers( CaloSamplingFractionAnalysis )
diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_G4Atlas_jobOptions.py b/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_G4Atlas_jobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..89866a0979e458e31b7bcf7959480ebc6394a09d
--- /dev/null
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_G4Atlas_jobOptions.py
@@ -0,0 +1,173 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+"""
+Job options file for Geant4 ATLAS detector simulations to measure the FCal
+sampling fractions.
+
+Set the 'module' variable to one of 'fcal1', 'fcal2' or 'fcal3' to simulate
+particle interactions in the FCal1, FCal2 or FCal3 modules, respectively.
+
+Additionaly parameters, such as the number of events to simulate and the
+particle gun energy and coordinates, may be set in the 'params' variable.
+"""
+
+import random
+
+## Common parameters
+module = "fcal1"   # Choose from "fcal1", "fcal2" or "fcal3"
+
+## Distance from IP to face of each FCal module [mm]
+
+## Values based on Table 3 in JINST 3 P02010 (2008), "The ATLAS Forward Calorimeter"
+## These numbers do not necessarily reflect the geometry and location of the FCal in the Geant4 model!
+# fcal1_z = 4708.90  # Distance from IP to FCal1 face [mm]; = 4683.5 + 26.4 - 1.0
+# fcal2_z = 5166.10  # Distance from IP to FCal2 face [mm]; = 4683.5 + 483.6 - 1.0
+# fcal3_z = 5648.20  # Distance from IP to FCal3 face [mm]; = 4683.5 + 965.7 - 1.0
+
+## Values for the Geant4 module
+fcal1_z = 4713.5
+fcal2_z = 5173.3
+fcal3_z = 5647.8
+
+params = {
+    'n_event': 200,          # Number of events to simulate
+    'pg_E': 40000,           # Particle gun energy [MeV]
+    'pg_x': [212.5, 277.5],  # Particle gun x-coordinate; constant or range
+    'pg_y': [7.5, 72.5],     # Particle gun y-coordinate; constant or range
+    'pg_z': None,            # Particle gun z-coordinate (distance to IP); should be constant
+    'pg_eta': None,          # Particle gun eta; constant or range
+}
+
+if module.lower() == "fcal1":
+    params['pg_z'] = fcal1_z
+    params['pg_eta'] = [3.5, 3.8]
+elif module.lower() == "fcal2":
+    params['pg_z'] = fcal2_z
+    params['pg_eta'] = [3.5, 3.8]
+elif module.lower() == "fcal3":
+    params['pg_z'] = fcal3_z
+    params['pg_eta'] = [3.5, 3.8]
+
+
+## Algorithm sequence
+from AthenaCommon.AlgSequence import AlgSequence
+topSeq = AlgSequence()
+
+## Output threshold (DEBUG, INFO, WARNING, ERROR, FATAL)
+ServiceMgr.MessageSvc.OutputLevel = INFO
+
+## Detector flags
+from AthenaCommon.DetFlags import DetFlags
+DetFlags.ID_setOff()
+DetFlags.Calo_setOn()
+DetFlags.Muon_setOff()
+DetFlags.HEC_setOff()
+DetFlags.em_setOff()
+DetFlags.Tile_setOff()
+# DetFlags.Lucid_setOn()
+DetFlags.Truth_setOn()
+DetFlags.simulate.Truth_setOn()
+
+## Global conditions tag
+from AthenaCommon.GlobalFlags import jobproperties
+jobproperties.Global.ConditionsTag = "OFLCOND-MC16-SDR-16"
+
+## AthenaCommon flags
+from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+athenaCommonFlags.PoolHitsOutput = "atlasG4.hits.pool.root"
+athenaCommonFlags.EvtMax = params['n_event']
+
+## Simulation flags
+from G4AtlasApps.SimFlags import simFlags
+simFlags.load_atlas_flags()
+simFlags.RandomSvc = "AtDSFMTGenSvc"
+
+## Layout tags: see simFlags.SimLayout for allowed values
+## Use the default layout:
+simFlags.SimLayout.set_On()
+## Set a specific layout tag:
+simFlags.SimLayout = "ATLAS-R2-2016-01-00-01"
+## Set a specific non-officially-supported layout tag using the _VALIDATION suffix, e.g.:
+# simFlags.SimLayout = "ATLAS-R2-2016-01-00-01_VALIDATION"
+
+## Set the EtaPhi, VertexSpread and VertexRange checks on
+simFlags.EventFilter.set_Off()
+
+## Set CalibrationRun
+simFlags.CalibrationRun = "LAr"
+
+## Set random seeds
+## Seeds need to explicitly set, otherwise default constants are used
+simFlags.RandomSeedList.addSeed('AtlasG4',random.randint(10000, 99999999), random.randint(10000, 99999999))
+simFlags.RandomSeedList.addSeed('VERTEX', random.randint(10000, 99999999), random.randint(10000, 99999999))
+simFlags.RandomSeedList.addSeed('SINGLE', random.randint(10000, 99999999), random.randint(10000, 99999999))
+
+## No magnetic field
+# simFlags.MagneticField.set_Off()
+
+## Register callback functions at various init stages
+# def test_preInit():
+#     print "CALLBACK AT PREINIT"
+# def test_postInit():
+#     print "CALLBACK AT POSTINIT"
+# simFlags.InitFunctions.add_function("preInit", test_preInit)
+# simFlags.InitFunctions.add_function("postInit", test_postInit)
+
+## Change the field stepper or use verbose G4 tracking
+# from G4AtlasApps import callbacks
+# simFlags.InitFunctions.add_function("postInit", callbacks.use_simplerunge_stepper)
+# simFlags.InitFunctions.add_function("postInit", callbacks.use_verbose_tracking)
+
+## Use single particle generator
+from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+athenaCommonFlags.PoolEvgenInput.set_Off()
+athenaCommonFlags.SkipEvents.set_Off()
+
+## Set particle gun parameters
+import AthenaCommon.AtlasUnixGeneratorJob
+import ParticleGun as PG
+pg = PG.ParticleGun(randomSvcName=simFlags.RandomSvc.get_Value(), randomStream="SINGLE")
+pg.sampler.pid = 11
+pg.sampler.mom = PG.EEtaMPhiSampler(energy=params['pg_E'], eta=params['pg_eta'])
+pg.sampler.pos = PG.PosSampler(x=params['pg_x'], y=params['pg_y'], z=params['pg_z'], t=params['pg_z'])
+topSeq += pg
+
+## Dump truth information
+# from TruthExamples.TruthExamplesConf import DumpMC
+# topSeq += DumpMC()
+
+StoreGateSvc = Service( "StoreGateSvc" )
+StoreGateSvc.Dump = True
+
+include("G4AtlasApps/G4Atlas.flat.configuration.py")
+
+## Use GeoCheckAction
+## If using GeoCheckAction, make sure the particle type id is set to 999 (geantinos)
+# def add_GeoCheckAction():
+#     from G4AtlasApps import PyG4Atlas, AtlasG4Eng
+#     GeoCheckAction = PyG4Atlas.UserAction( 'G4UserActions', 'GeoCheckAction', ['BeginOfEvent','EndOfEvent','Step','EndOfRun'] )
+#     AtlasG4Eng.G4Eng.menu_UserActions.add_UserAction(GeoCheckAction)
+
+# simFlags.InitFunctions.add_function("postInit", add_GeoCheckAction)
+
+
+from AthenaCommon.CfgGetter import getAlgorithm
+topSeq += getAlgorithm("G4AtlasAlg", tryDefaultConfigurable=True)
+topSeq.G4AtlasAlg.InputTruthCollection = "GEN_EVENT"
+
+## Tool to merge dead material containers into a single container
+from LArG4SD import LArG4SDConfig
+topSeq += LArG4SDConfig.getDeadMaterialCalibrationHitMerger()
+
+myAlg = CfgMgr.LArFCalSamplingFraction()
+myAlg.Calibration = True
+topSeq += myAlg
+
+
+from GaudiSvc.GaudiSvcConf import THistSvc
+ServiceMgr += THistSvc()
+ServiceMgr.THistSvc.Output = [
+    "AANT DATAFILE='LArFCalSamplingFraction.{}.{:g}GeV.aan.root' OPT='RECREATE'".format(module, params['pg_E']/1000)
+]
+
+print topSeq
diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_analysis.py b/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_analysis.py
new file mode 100755
index 0000000000000000000000000000000000000000..9987534a5d71ceb0196236f47650f3b1233b2abb
--- /dev/null
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/share/LarFCalSamplingFraction_analysis.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+"""
+Calculate FCal Sampling Fractions
+=================================
+
+Calculate the FCal sampling fractions from Geant4 simulation.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+import argparse
+import glob
+import math
+import sys
+
+import ROOT as root
+
+# To stop ROOT from hijacking '--help'
+root.PyConfig.IgnoreCommandLineOptions = True
+
+
+def _docstring(docstring):
+    """Return summary of docstring
+    """
+    return docstring.split('\n')[4] if docstring else ""
+
+
+def parse_args():
+    """Parse command-line arguments
+    """
+    parser = argparse.ArgumentParser(description=_docstring(__doc__))
+    parser.add_argument("--version", action="version", version="%(prog)s 0.1")
+    parser.add_argument("-v", "--verbose", action="count", default=0,
+                        help="print verbose messages; multiple -v result in more verbose messages")
+    parser.add_argument("infile", default="LArFCalSamplingFraction.aan.root",
+                        help="Path to input file; wildcards are supported (default: %(default)s)")
+    parser.add_argument("-m", "--module", choices=["FCal1", "FCal2", "FCal3"],
+                        help="Calculate the sampling fraction for this FCal module only; "
+                             "if unspecified, it will try to parse the module from the file name")
+    parser.add_argument("-o", "--outfile", default="out.txt",
+                        help="Path to output file where sampling fraction results are written "
+                             "(default: %(default)s)")
+
+    args = parser.parse_args()
+
+    return args
+
+
+def calculate_samp_frac(args):
+    """Read ntuple from the Geant4 simulation and calculate FCal sampling
+    fractions.
+
+    Returns (E_init, samp_frac, samp_frac_err)
+    """
+    tree_name = "tree_AS"
+    print("Reading tree '{}' from file '{}'...".format(tree_name, args.infile))
+
+    aan_chain = root.TChain(tree_name)
+    aan_chain.Add(args.infile)
+
+    n_event = aan_chain.GetEntries()
+
+    # Get initial electron energy [GeV]
+    for event in aan_chain:
+        E_init = round(event.E, 2) / 1000
+        break
+
+    samp_frac = 0
+    samp_frac_sq = 0
+
+    if args.verbose:
+        print("Event  Active E [MeV]  Total E [MeV]")
+
+    # Loop over events and sum energy values
+    for event in aan_chain:
+        if args.module.lower() == "fcal1":
+            totalE = event.Calib_FCal1Active + event.Calib_FCal1Inactive
+            activeE = event.FCal1_E
+        elif args.module.lower() == "fcal2":
+            totalE = event.Calib_FCal2Active + event.Calib_FCal2Inactive
+            activeE = event.FCal2_E
+        elif args.module.lower() == "fcal3":
+            totalE = event.Calib_FCal3Active + event.Calib_FCal3Inactive
+            activeE = event.FCal3_E
+
+        samp_frac += activeE / totalE
+        samp_frac_sq += (activeE / totalE)**2
+
+        if args.verbose:
+            print("{:<6} {:<15g} {:<15g}".format(event.Event, activeE, totalE))
+
+    if args.verbose:
+        print("")
+
+    # Mean sampling fractions
+    samp_frac /= n_event
+    samp_frac_sq /= n_event
+
+    # Sampling fraction error = sqrt(<x^2> - <x>^2) / sqrt(N)
+    samp_frac_err = math.sqrt(samp_frac_sq - samp_frac**2) / math.sqrt(n_event)
+
+    print("{} sampling fraction (E = {:g} GeV): {:g} +/- {:g}".format(args.module, E_init, samp_frac, samp_frac_err))
+
+    return E_init, samp_frac, samp_frac_err
+
+
+def write_results(results, args):
+    with open(args.outfile, "w") as outfile:
+        outfile.write("[{}]\n".format(args.module))
+
+        for key in sorted(results.keys()):
+            outfile.write("{:g} GeV: {} +/- {}\n".format(key, results[key][0], results[key][1]))
+
+def main():
+    try:
+        args = parse_args()
+
+        if args.module is None:
+            if "fcal1" in args.infile.lower():
+                args.module = "fcal1"
+            elif "fcal2" in args.infile.lower():
+                args.module = "fcal2"
+            elif "fcal3" in args.infile.lower():
+                args.module = "fcal3"
+            else:
+                raise Exception("unknown FCal module")
+
+        infiles = glob.glob(args.infile)
+        infiles.sort()
+
+        results = {}
+
+        for infile in infiles:
+            args.infile = infile
+            E_init, samp_frac, samp_frac_err = calculate_samp_frac(args)
+
+            results[E_init] = (samp_frac, samp_frac_err)
+
+        print("Writing results to '{}'".format(args.outfile))
+        write_results(results, args)
+
+    except KeyboardInterrupt:
+        return 1
+
+    except Exception as err:
+        print("error: {}".format(err))
+        return 1
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.cxx b/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..64930200a4250f5157b5f35cf70abc21761bbb20
--- /dev/null
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.cxx
@@ -0,0 +1,1056 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "LArFCalSamplingFraction.h"
+
+// C++ stdlib
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <cmath>
+
+// Root
+#include "TTree.h"
+
+// ATLAS Software
+#include "GaudiKernel/IToolSvc.h"
+
+// Event Info
+#include "EventInfo/EventID.h"
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventType.h"
+#include "EventInfo/TriggerInfo.h"
+#include "GaudiKernel/ITHistSvc.h"
+
+// ID classes
+#include "CaloDetDescr/CaloDetDescrElement.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/CaloDM_ID.h"
+#include "CaloIdentifier/CaloIdManager.h"
+#include "Identifier/Identifier.h"
+
+// Hits and hit collections
+#include "LArSimEvent/LArHit.h"
+#include "LArSimEvent/LArHitContainer.h"
+#include "LArReadoutGeometry/FCALModule.h"
+#include "LArReadoutGeometry/FCALTile.h"
+#include "CaloSimEvent/CaloCalibrationHit.h"
+#include "CaloSimEvent/CaloCalibrationHitContainer.h"
+#include "GeoAdaptors/GeoLArHit.h"
+#include "GeoAdaptors/GeoCaloCalibHit.h"
+
+// For Cryostat Positions
+#include "LArG4RunControl/LArG4TBPosOptions.h"
+
+// Other useful tools for particle/event/beam info
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventID.h"
+#include "GeneratorObjects/McEventCollection.h"
+#include "HepMC/GenEvent.h"
+#include "HepMC/GenVertex.h"
+#include "HepMC/GenParticle.h"
+#include "HepMC/SimpleVector.h"
+#include "CLHEP/Vector/LorentzVector.h"
+#include "CLHEP/Vector/ThreeVector.h"
+#include "CLHEP/Geometry/Point3D.h"
+
+
+static const double mZ = 91.19 * CLHEP::GeV;
+static const int MAX_PARTICLES = 20;
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Constructor
+
+LArFCalSamplingFraction::LArFCalSamplingFraction(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthAlgorithm(name, pSvcLocator),
+      m_calibrationRun(false),
+      m_cx1(0.0), m_cx2(0.0), m_cx3(0.0),
+      m_cy1(0.0), m_cy2(0.0), m_cy3(0.0)
+{
+    declareProperty("Calibration", m_calibrationRun);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Destructor
+
+LArFCalSamplingFraction::~LArFCalSamplingFraction() {}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize
+///  - Get a handle on the analysis tools
+///  - Set up output TTree
+
+StatusCode LArFCalSamplingFraction::initialize()
+{
+    ATH_MSG_INFO("Initializing LArFCalSamplingFraction");
+
+    // Get a handle on the NTuple and histogramming service
+    ServiceHandle<ITHistSvc> histSvc("THistSvc", name());
+    CHECK(histSvc.retrieve());
+    ATH_MSG_DEBUG(" retrieved THistSvc");
+
+    const CaloIdManager *caloIdManager;
+    ATH_CHECK(detStore()->retrieve(caloIdManager));
+
+    // Use just for now for Calibration... change later to GeoCalibHit
+    m_larFCalID = caloIdManager->getFCAL_ID();
+
+    if (m_larFCalID == 0)
+        throw GaudiException("Invalid LAr FCAL ID helper", "LArHitAnalysis", StatusCode::FAILURE);
+
+    // Use for now... soon change to GeoCalibHit
+    m_caloCellID = caloIdManager->getCaloCell_ID();
+
+    if (m_caloCellID == 0)
+        throw GaudiException("Invalid Calo Cell ID helper", "LArHitAnalysis", StatusCode::FAILURE);
+
+    m_pdg_id = new std::vector<int>; // particle id
+
+    m_hit_x1 = new std::vector<double>; // hit positions of cells
+    m_hit_y1 = new std::vector<double>;
+
+    m_hit_x2 = new std::vector<double>;
+    m_hit_y2 = new std::vector<double>;
+
+    m_hit_x3 = new std::vector<double>;
+    m_hit_y3 = new std::vector<double>;
+
+    m_hit_ieta1 = new std::vector<double>; // hit indices of cells
+    m_hit_iphi1 = new std::vector<double>;
+    m_hit_ieta2 = new std::vector<double>;
+    m_hit_iphi2 = new std::vector<double>;
+    m_hit_ieta3 = new std::vector<double>;
+    m_hit_iphi3 = new std::vector<double>;
+
+    m_cell1_E = new std::vector<double>; // Energy in cells
+    m_cell2_E = new std::vector<double>;
+    m_cell3_E = new std::vector<double>;
+
+    // Now add branches and leaves to the AAN tree
+    m_tree_AS = new TTree("tree_AS", "TTree of AnalysisSkleton");
+
+    // Event info
+    m_tree_AS->Branch("Run", &m_runNumber, "Run/I");             // run number
+    m_tree_AS->Branch("Event", &m_eventNumber, "Event/I");       // event number
+    m_tree_AS->Branch("Time", &m_eventTime, "Time/I");           // time stamp
+    m_tree_AS->Branch("LumiBlock", &m_lumiBlock, "LumiBlock/I"); // lumi block num
+    m_tree_AS->Branch("BCID", &m_bCID, "BCID/I");                // bunch crossing ID
+    m_tree_AS->Branch("Weight", &m_eventWeight, "Weight/D");     // weight
+
+    // FCal-specific and other variables
+    m_tree_AS->Branch("EFCal", &m_totalFCalEnergy, "EFCal/D");
+    m_tree_AS->Branch("NHitsFCal", &m_numHitsFCal, "NhitsFCal/I");
+
+    m_tree_AS->Branch("Vertex_Eta", &m_vertex_eta, "Vertex_Eta/D");
+    m_tree_AS->Branch("Vertex_Phi", &m_vertex_phi, "Vertex_Phi/D");
+
+    m_tree_AS->Branch("Pt", &m_pt, "Pt/D");
+    m_tree_AS->Branch("px", &m_px, "px/D");
+    m_tree_AS->Branch("py", &m_py, "py/D");
+    m_tree_AS->Branch("pz", &m_pz, "pz/D");
+    m_tree_AS->Branch("E", &m_E, "E/D");
+
+    m_tree_AS->Branch("VertexX", &m_vertx, "VertexX/D");
+    m_tree_AS->Branch("VertexY", &m_verty, "VertexY/D");
+    m_tree_AS->Branch("VertexZ", &m_vertz, "VertexZ/D");
+
+    m_tree_AS->Branch("MC_CCX1", &m_x_mc_cc1, "MC_CCX1/D");
+    m_tree_AS->Branch("MC_CCY1", &m_y_mc_cc1, "MC_CCY1/D");
+
+    m_tree_AS->Branch("MC_CCX2", &m_x_mc_cc2, "MC_CCX2/D");
+    m_tree_AS->Branch("MC_CCY2", &m_y_mc_cc2, "MC_CCY2/D");
+
+    m_tree_AS->Branch("MC_CCX3", &m_x_mc_cc3, "MC_CCX3/D");
+    m_tree_AS->Branch("MC_CCY3", &m_y_mc_cc3, "MC_CCY3/D");
+
+    m_tree_AS->Branch("CCX1", &m_x_cc1, "CCX1/D");
+    m_tree_AS->Branch("CCY1", &m_y_cc1, "CCY1/D");
+
+    m_tree_AS->Branch("CCX2", &m_x_cc2, "CCX2/D");
+    m_tree_AS->Branch("CCY2", &m_y_cc2, "CCY2/D");
+
+    m_tree_AS->Branch("CCX3", &m_x_cc3, "CCX3/D");
+    m_tree_AS->Branch("CCY3", &m_y_cc3, "CCY3/D");
+
+    m_tree_AS->Branch("NCell_1", &m_NCell1, "NCell1_1/I");
+    m_tree_AS->Branch("NCell_2", &m_NCell2, "NCell1_2/I");
+    m_tree_AS->Branch("NCell_3", &m_NCell3, "NCell1_3/I");
+
+    m_tree_AS->Branch("ParticleID", &m_pdg_id);
+
+    m_tree_AS->Branch("Hit_X1", &m_hit_x1);
+    m_tree_AS->Branch("Hit_Y1", &m_hit_y1);
+
+    m_tree_AS->Branch("Hit_X2", &m_hit_x2);
+    m_tree_AS->Branch("Hit_Y2", &m_hit_y2);
+
+    m_tree_AS->Branch("Hit_X3", &m_hit_x3);
+    m_tree_AS->Branch("Hit_Y3", &m_hit_y3);
+
+    m_tree_AS->Branch("Hit_eta1", &m_hit_ieta1);
+    m_tree_AS->Branch("Hit_phi1", &m_hit_iphi1);
+    m_tree_AS->Branch("Hit_eta2", &m_hit_ieta2);
+    m_tree_AS->Branch("Hit_phi2", &m_hit_iphi2);
+    m_tree_AS->Branch("Hit_eta3", &m_hit_ieta3);
+    m_tree_AS->Branch("Hit_phi3", &m_hit_iphi3);
+
+    m_tree_AS->Branch("Cell1_E", &m_cell1_E);
+    m_tree_AS->Branch("Cell2_E", &m_cell2_E);
+    m_tree_AS->Branch("Cell3_E", &m_cell3_E);
+
+    m_tree_AS->Branch("FCal1_E", &m_FCal1_SumE, "FCal1_E/D");
+    m_tree_AS->Branch("FCal2_E", &m_FCal2_SumE, "FCal2_E/D");
+    m_tree_AS->Branch("FCal3_E", &m_FCal3_SumE, "FCal3_E/D");
+
+    if (m_calibrationRun) {
+        m_caloDmID = caloIdManager->getDM_ID();
+
+        if (m_caloDmID == 0)
+            throw GaudiException("Invalid Calo DM ID helper", "LArFCalTB_MC_CBNT_AA", StatusCode::FAILURE);
+
+        // Define the hit containers that we'll analyze in this program.
+        // For now, initialize the pointers to the containers to NULL (zero).
+        m_calibHitMap["LArCalibrationHitActive"] = 0;
+        m_calibHitMap["LArCalibrationHitInactive"] = 0;
+        m_calibHitMap["LArCalibrationHitDeadMaterial"] = 0;
+
+        m_tree_AS->Branch("Calib_TotalEnergy", &m_totalCalibrationEnergy, "Calib_TotalEnergy/D");
+        m_tree_AS->Branch("Calib_TotalEm", &m_totalEmEnergy, "Calib_TotalEm/D");
+        m_tree_AS->Branch("Calib_TotalNonEm", &m_totalNonEmEnergy, "Calib_TotalNonEm/D");
+        m_tree_AS->Branch("Calib_TotalInvisible", &m_totalInvisibleEnergy, "Calib_TotalInvisible/D");
+        m_tree_AS->Branch("Calib_TotalEscaped", &m_totalEscapedEnergy, "Calib_TotalEscaped/D");
+        m_tree_AS->Branch("Calib_FCalEnergy", &m_totalFCalCalibrationEnergy, "Calib_FCalEnergy/D");
+        m_tree_AS->Branch("Calib_TotalActive", &m_totalActiveEnergy, "Calib_TotalActive/D");
+        m_tree_AS->Branch("Calib_TotalInactive", &m_totalInactiveEnergy, "Calib_TotalInactive/D");
+        m_tree_AS->Branch("Calib_DeadEnergy", &m_totalDeadMaterialEnergy, "Calib_DeadEnergy/D");
+        m_tree_AS->Branch("Calib_NHitsInactive", &m_numHitsInactive, "Calib_NHitsInactive/I");
+        m_tree_AS->Branch("Calib_NHitsDead", &m_numHitsDead, "Calib_NHitsDead/I");
+        m_tree_AS->Branch("Calib_FCal1Energy", &m_totalFCal1CalibrationEnergy, "Calib_FCal1Energy/D");
+        m_tree_AS->Branch("Calib_FCal2Energy", &m_totalFCal2CalibrationEnergy, "Calib_FCal2Energy/D");
+        m_tree_AS->Branch("Calib_FCal3Energy", &m_totalFCal3CalibrationEnergy, "Calib_FCal3Energy/D");
+
+        m_tree_AS->Branch("Calib_FCalActive", &m_FCalActive, "Calib_FCalActive/D");
+        m_tree_AS->Branch("Calib_FCalInactive", &m_FCalInactive, "Calib_FCalInactive/D");
+        m_tree_AS->Branch("Calib_FCalDead", &m_FCalDead, "Calib_FCalDead/D");
+        m_tree_AS->Branch("Calib_FCalEm", &m_FCalEm, "Calib_FCalEm/D");
+        m_tree_AS->Branch("Calib_FCal1Em", &m_FCal1Em, "Calib_FCal1Em/D");
+        m_tree_AS->Branch("Calib_FCal2Em", &m_FCal2Em, "Calib_FCal2Em/D");
+        m_tree_AS->Branch("Calib_FCal3Em", &m_FCal3Em, "Calib_FCal3Em/D");
+        m_tree_AS->Branch("Calib_FCalNonEm", &m_FCalNonEm, "Calib_FCalNonEm/D");
+        m_tree_AS->Branch("Calib_FCal1NonEm", &m_FCal1NonEm, "Calib_FCal1NonEm/D");
+        m_tree_AS->Branch("Calib_FCal2NonEm", &m_FCal2NonEm, "Calib_FCal2NonEm/D");
+        m_tree_AS->Branch("Calib_FCal3NonEm", &m_FCal3NonEm, "Calib_FCal3NonEm/D");
+        m_tree_AS->Branch("Calib_FCalInvisible", &m_FCalInvisible, "Calib_FCalInvisible/D");
+        m_tree_AS->Branch("Calib_FCal1Invisible", &m_FCal1Invisible, "Calib_FCal1Invisible/D");
+        m_tree_AS->Branch("Calib_FCal2Invisible", &m_FCal2Invisible, "Calib_FCal2Invisible/D");
+        m_tree_AS->Branch("Calib_FCal3Invisible", &m_FCal3Invisible, "Calib_FCal3Invisible/D");
+        m_tree_AS->Branch("Calib_FCalEscaped", &m_FCalEscaped, "Calib_FCalEscaped/D");
+        m_tree_AS->Branch("Calib_FCal1Escaped", &m_FCal1Escaped, "Calib_FCal1Escaped/D");
+        m_tree_AS->Branch("Calib_FCal2Escaped", &m_FCal2Escaped, "Calib_FCal2Escaped/D");
+        m_tree_AS->Branch("Calib_FCal3Escaped", &m_FCal3Escaped, "Calib_FCal3Escaped/D");
+        m_tree_AS->Branch("Calib_FCal1Active", &m_FCal1Active, "Calib_FCal1Active/D");
+        m_tree_AS->Branch("Calib_FCal2Active", &m_FCal2Active, "Calib_FCal2Active/D");
+        m_tree_AS->Branch("Calib_FCal3Active", &m_FCal3Active, "Calib_FCal3Active/D");
+        m_tree_AS->Branch("Calib_FCal1Inactive", &m_FCal1Inactive, "Calib_FCal1Inactive/D");
+        m_tree_AS->Branch("Calib_FCal2Inactive", &m_FCal2Inactive, "Calib_FCal2Inactive/D");
+        m_tree_AS->Branch("Calib_FCal3Inactive", &m_FCal3Inactive, "Calib_FCal3Inactive/D");
+        m_tree_AS->Branch("Calib_FCalActiveEm", &m_FCalActiveEm, "Calib_FCalActiveEm/D");
+        m_tree_AS->Branch("Calib_FCalActiveNonEm", &m_FCalActiveNonEm, "Calib_FCalActiveNonEm/D");
+        m_tree_AS->Branch("Calib_FCalActiveInvisible", &m_FCalActiveInvisible, "Calib_FCalActiveInvisible/D");
+        m_tree_AS->Branch("Calib_FCalActiveEscaped", &m_FCalActiveEscaped, "Calib_FCalActiveEscaped/D");
+    }
+
+    CHECK(histSvc->regTree("/AANT/tree_AS", m_tree_AS));
+
+    m_eventNumber = 0;
+
+    return StatusCode::SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Finalize
+///  - delete any memory allocation from the heap
+
+StatusCode LArFCalSamplingFraction::finalize()
+{
+    return StatusCode::SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Init event
+///  - clear CBNT members
+
+StatusCode LArFCalSamplingFraction::initEvent()
+{
+    /// For Athena-Aware NTuple
+
+    ATH_MSG_INFO("Initializing event, clearing variables");
+
+    m_vertx = 0; // x-position for vertex generated particle (beam)
+    m_verty = 0;
+    m_vertz = 0;
+
+    m_vertex_eta = 0; // eta value of generated particle
+    m_vertex_phi = 0;
+
+    m_pt = 0; // Momentum of generated particle
+    m_px = 0;
+    m_py = 0;
+    m_pz = 0;
+
+    m_E = 0; // Energy of generated particle
+
+    m_NCell1 = 0; // Number of cells hit
+    m_NCell2 = 0;
+    m_NCell3 = 0;
+
+    m_x_mc_cc1 = 0; // Center of cluster in x (FCal1, extrapolated)
+    m_y_mc_cc1 = 0;
+
+    m_x_mc_cc2 = 0; // Center of cluster in x (FCal2, extrapolated)
+    m_y_mc_cc2 = 0;
+
+    m_x_mc_cc3 = 0; // Center of cluster in x (FCal3, extrapolated)
+    m_y_mc_cc3 = 0;
+
+    m_x_cc1 = 0; // Center of cluster in x (FCal1, c of g)
+    m_y_cc1 = 0;
+
+    m_x_cc2 = 0; // Center of cluster in x (FCal2, c of g)
+    m_y_cc2 = 0;
+
+    m_x_cc3 = 0; // Center of cluster in x (FCal3, c of g)
+    m_y_cc3 = 0;
+
+    m_pdg_id->clear(); // particle id
+
+    m_hit_x1->clear(); // hit positions of cells
+    m_hit_y1->clear();
+
+    m_hit_x2->clear();
+    m_hit_y2->clear();
+
+    m_hit_x3->clear();
+    m_hit_y3->clear();
+
+    m_hit_ieta1->clear(); // hit indices of cells
+    m_hit_iphi1->clear();
+    m_hit_ieta2->clear();
+    m_hit_iphi2->clear();
+    m_hit_ieta3->clear();
+    m_hit_iphi3->clear();
+
+    m_cell1_E->clear(); // Energy in cells
+    m_cell2_E->clear();
+    m_cell3_E->clear();
+
+    m_FCal1_SumE = 0; // Energy in individual FCal modules
+    m_FCal2_SumE = 0;
+    m_FCal3_SumE = 0;
+    m_TCScint_E = 0;
+    m_TCIron_E = 0;
+
+    m_totalFCalEnergy = 0;
+    m_numHitsFCal = 0;
+
+    m_totalCalibrationEnergy = 0; // Total energy
+
+    // Physic Processes
+    m_totalEmEnergy = 0;
+    m_totalNonEmEnergy = 0;
+    m_totalInvisibleEnergy = 0;
+    m_totalEscapedEnergy = 0;
+
+    // Energy deposited in different material categories
+    m_totalActiveEnergy = 0;
+    m_totalInactiveEnergy = 0;
+    m_totalDeadMaterialEnergy = 0;
+
+    // Number of hits in different material categories
+    m_numHitsActive = 0;
+    m_numHitsInactive = 0;
+    m_numHitsDead = 0;
+
+    // Total energy deposited in the different FCal Modules
+    m_totalFCalCalibrationEnergy = 0; // Energy in all FCal
+    m_totalFCal1CalibrationEnergy = 0;
+    m_totalFCal2CalibrationEnergy = 0;
+    m_totalFCal3CalibrationEnergy = 0;
+
+    m_FCalActive = 0;
+    m_FCalInactive = 0;
+    m_FCalDead = 0;
+    m_FCalActiveEm = 0;
+    m_FCalActiveNonEm = 0;
+    m_FCalActiveInvisible = 0;
+    m_FCalActiveEscaped = 0;
+    m_FCalEm = 0;
+    m_FCal1Em = 0;
+    m_FCal2Em = 0;
+    m_FCal3Em = 0;
+    m_FCalNonEm = 0;
+    m_FCal1NonEm = 0;
+    m_FCal2NonEm = 0;
+    m_FCal3NonEm = 0;
+    m_FCalInvisible = 0;
+    m_FCal1Invisible = 0;
+    m_FCal2Invisible = 0;
+    m_FCal3Invisible = 0;
+    m_FCalEscaped = 0;
+    m_FCal1Escaped = 0;
+    m_FCal2Escaped = 0;
+    m_FCal3Escaped = 0;
+    m_PhysTotE = 0;
+    m_FCal1Active = 0;
+    m_FCal2Active = 0;
+    m_FCal3Active = 0;
+    m_FCal1Inactive = 0;
+    m_FCal2Inactive = 0;
+    m_FCal3Inactive = 0;
+
+    return StatusCode::SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Calculate FCal hit center
+
+void LArFCalSamplingFraction::FCalHitCenter(const LArHitContainer *container)
+{
+    double max1 = 0.0;
+    double max2 = 0.0;
+    double max3 = 0.0;
+
+    // Loop over hits in container
+    for (LArHit* const& hit : *container) {
+
+        GeoLArHit fcalhit(*hit);
+
+        if ((!fcalhit) || (!fcalhit.getDetDescrElement()->is_lar_fcal())) {
+            ATH_MSG_WARNING("Hit in LarHitContainer is not a GeoFCalHit");
+            continue;
+        }
+
+        double energy = fcalhit.Energy();
+
+        int module_index = fcalhit.getDetDescrElement()->getLayer();
+
+        double x = fcalhit.getDetDescrElement()->x();
+        double y = fcalhit.getDetDescrElement()->y();
+
+        // Determine the center of the cluster for each FCal module
+        if (module_index == 1) {
+            // FCal1
+            if (max1 < energy) {
+                max1 = energy;
+                m_cx1 = x;
+                m_cy1 = y;
+            }
+        }
+        else if (module_index == 2) {
+            // FCal2
+            if (max2 < energy) {
+                max2 = energy;
+                m_cx2 = x;
+                m_cy2 = y;
+            }
+        }
+        else if (module_index == 3) {
+            // FCal3
+            if (max3 < energy) {
+                max3 = energy;
+                m_cx3 = x;
+                m_cy3 = y;
+            }
+        }
+
+    } // End loop over hits in container
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Calculate FCal cluster center
+
+void LArFCalSamplingFraction::FCalClusterCenter(const LArHitContainer *container)
+{
+    float xNumer1 = 0.0, xNumer2 = 0.0, xNumer3 = 0.0;
+    float yNumer1 = 0.0, yNumer2 = 0.0, yNumer3 = 0.0;
+    float Denom1 = 0.0, Denom2 = 0.0, Denom3 = 0.0;
+
+    double subClusterSize = 30.0;  // [mm]
+    double thisCG_R = 0.0;
+
+    // Loop over hits in container
+    for (LArHit* const& hit : *container) {
+
+        GeoLArHit fcalhit(*hit);
+
+        if ((!fcalhit) || (!fcalhit.getDetDescrElement()->is_lar_fcal())) {
+            ATH_MSG_WARNING("Hit in LarHitContainer is not a GeoFCalHit");
+            continue;
+        }
+
+        double energy = fcalhit.Energy();
+        int module_index = fcalhit.getDetDescrElement()->getLayer();
+
+        double x = fcalhit.getDetDescrElement()->x();
+        double y = fcalhit.getDetDescrElement()->y();
+
+        // Determine center of cluster
+        if (module_index == 1) {
+            // FCal1
+            double x_subcheck1 = m_cx1 - x;
+            double y_subcheck1 = m_cy1 - y;
+            thisCG_R = sqrt(x_subcheck1 * x_subcheck1 + y_subcheck1 * y_subcheck1);
+
+            if (thisCG_R <= subClusterSize) {
+                xNumer1 += x * energy;
+                yNumer1 += y * energy;
+                Denom1 += energy;
+            }
+        }
+        else if (module_index == 2) {
+            // FCal2
+            double x_subcheck2 = m_cx2 - x;
+            double y_subcheck2 = m_cy2 - y;
+            thisCG_R = sqrt(x_subcheck2 * x_subcheck2 + y_subcheck2 * y_subcheck2);
+
+            if (thisCG_R <= subClusterSize) {
+                xNumer2 += x * energy;
+                yNumer2 += y * energy;
+                Denom2 += energy;
+            }
+        }
+        else if (module_index == 3) {
+            // FCal3
+            double x_subcheck3 = m_cx3 - x;
+            double y_subcheck3 = m_cy3 - y;
+            thisCG_R = sqrt(x_subcheck3 * x_subcheck3 + y_subcheck3 * y_subcheck3);
+
+            if (thisCG_R <= subClusterSize) {
+                xNumer3 += x * energy;
+                yNumer3 += y * energy;
+                Denom3 += energy;
+            }
+        }
+
+    } // End loop over hits in container
+
+    if (fabs(Denom1) > 0.0) {
+        m_x_cc1 = xNumer1 / Denom1;
+        m_y_cc1 = yNumer1 / Denom1;
+    }
+
+    if (fabs(Denom2) > 0.0) {
+        m_x_cc2 = xNumer2 / Denom2;
+        m_y_cc2 = yNumer2 / Denom2;
+    }
+
+    if (fabs(Denom3) > 0.0) {
+        m_x_cc3 = xNumer3 / Denom3;
+        m_y_cc3 = yNumer3 / Denom3;
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Calibration hit analysis
+
+StatusCode LArFCalSamplingFraction::doCalib()
+{
+    StatusCode sc;
+
+    ATH_MSG_DEBUG("Starting FCal Calibration Analysis");
+
+    // Get the calibration hit containers (if any)
+    for (m_calibHitMap_ptr_t i = m_calibHitMap.begin();
+         i != m_calibHitMap.end();
+         i++)
+    {
+        std::string name = (*i).first;
+        const CaloCalibrationHitContainer *container = 0;
+        sc = evtStore()->retrieve(container, name);
+
+        if (sc.isFailure() || container == 0) {
+            ATH_MSG_ERROR("CaloCalibrationHit container was not found");
+            m_numHitsActive = 0;
+            m_numHitsInactive = 0;
+            m_numHitsDead = 0;
+            (*i).second = 0;
+
+            return StatusCode::FAILURE;
+        }
+
+        ATH_MSG_DEBUG("CaloCalibrationHit container successfully retrieved");
+
+        (*i).second = container;
+    }
+
+    // Get the number of hits in each container
+    // (The braces let us re-use the name 'container')
+    {
+        const CaloCalibrationHitContainer *container = m_calibHitMap["LArCalibrationHitActive"];
+
+        if (container != 0)
+            m_numHitsActive = container->Size();
+        else
+            m_numHitsActive = 0;
+    }
+    {
+        const CaloCalibrationHitContainer *container = m_calibHitMap["LArCalibrationHitInactive"];
+
+        if (container != 0)
+            m_numHitsInactive = container->Size();
+        else
+            m_numHitsInactive = 0;
+    }
+    {
+        const CaloCalibrationHitContainer *container = m_calibHitMap["LArCalibrationHitDeadMaterial"];
+
+        if (container != 0)
+            m_numHitsDead = container->Size();
+        else
+            m_numHitsDead = 0;
+    }
+
+    // Loop over all the hit containers, inspecting each hit within the collection
+    for (m_calibHitMap_ptr_t i = m_calibHitMap.begin();
+         i != m_calibHitMap.end();
+         i++)
+    {
+        std::string name = (*i).first;
+        const CaloCalibrationHitContainer *container = (*i).second;
+
+        // Skip rest of loop if it's a null container.
+        if (container == 0)
+            continue;
+
+        // Loop over calibration hits in container
+        for (CaloCalibrationHit* const& calibhit : *container) {
+
+            Identifier identifier = calibhit->cellID();
+            double energy = calibhit->energyTotal();
+
+            // Accumulate energy sums. Use the ID helpers to determine in which
+            // detector the hit took place.
+
+            m_totalCalibrationEnergy += energy;
+            m_totalEmEnergy += calibhit->energyEM();
+            m_totalNonEmEnergy += calibhit->energyNonEM();
+            m_totalInvisibleEnergy += calibhit->energyInvisible();
+            m_totalEscapedEnergy += calibhit->energyEscaped();
+
+            if (name == "LArCalibrationHitActive")
+                m_totalActiveEnergy += energy;
+
+            if (name == "LArCalibrationHitInactive")
+                m_totalInactiveEnergy += energy;
+
+            if (name == "LArCalibrationHitDeadMaterial") {
+                m_totalDeadMaterialEnergy += energy;
+
+                if (m_caloDmID->is_lar(identifier) && (m_caloDmID->sampling(identifier) == 3) && (m_caloDmID->dmat(identifier) == 1))
+                    m_FCalDead += energy;
+            }
+
+            if (m_caloCellID->is_lar_fcal(identifier))
+                FCalCalibAnalysis(name, calibhit);
+
+        } // End loop over calibration hits in container
+    } // End loop over containers
+
+    // Execution completed
+
+    ATH_MSG_DEBUG("doCalib() completed successfully");
+    return sc;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// FCal Analysis with Calibration Hits on
+/// Added by JPA, June 2005
+
+void LArFCalSamplingFraction::FCalCalibAnalysis(const std::string name, const CaloCalibrationHit *CalibHit)
+{
+    Identifier id = CalibHit->cellID();
+    double energy = CalibHit->energyTotal();
+
+    m_totalFCalCalibrationEnergy += energy;
+    //// Added by JPA Feb. 2005
+    m_FCalEm += CalibHit->energyEM();
+    m_FCalNonEm += CalibHit->energyNonEM();
+    m_FCalInvisible += CalibHit->energyInvisible();
+    m_FCalEscaped += CalibHit->energyEscaped();
+
+    if (m_larFCalID->module(id) == 1) {
+        // FCal1
+        m_totalFCal1CalibrationEnergy += energy;
+        m_FCal1Em += CalibHit->energyEM();
+        m_FCal1NonEm += CalibHit->energyNonEM();
+        m_FCal1Invisible += CalibHit->energyInvisible();
+        m_FCal1Escaped += CalibHit->energyEscaped();
+    }
+    else if (m_larFCalID->module(id) == 2) {
+        // FCal2
+        m_totalFCal2CalibrationEnergy += energy;
+        m_FCal2Em += CalibHit->energyEM();
+        m_FCal2NonEm += CalibHit->energyNonEM();
+        m_FCal2Invisible += CalibHit->energyInvisible();
+        m_FCal2Escaped += CalibHit->energyEscaped();
+    }
+    else if (m_larFCalID->module(id) == 3) {
+        // FCal3
+        m_totalFCal3CalibrationEnergy += energy;
+        m_FCal3Em += CalibHit->energyEM();
+        m_FCal3NonEm += CalibHit->energyNonEM();
+        m_FCal3Invisible += CalibHit->energyInvisible();
+        m_FCal3Escaped += CalibHit->energyEscaped();
+    }
+
+    if (name == "LArCalibrationHitActive") {
+        m_FCalActive += energy;
+        m_FCalActiveEm += CalibHit->energyEM();
+        m_FCalActiveNonEm += CalibHit->energyNonEM();
+        m_FCalActiveInvisible += CalibHit->energyInvisible();
+        m_FCalActiveEscaped += CalibHit->energyEscaped();
+
+        if (m_larFCalID->module(id) == 1)
+            m_FCal1Active += energy;
+
+        if (m_larFCalID->module(id) == 2)
+            m_FCal2Active += energy;
+
+        if (m_larFCalID->module(id) == 3)
+            m_FCal3Active += energy;
+    }
+
+    if (name == "LArCalibrationHitInactive") {
+        m_FCalInactive += energy;
+
+        if (m_larFCalID->module(id) == 1)
+            m_FCal1Inactive += energy;
+
+        if (m_larFCalID->module(id) == 2)
+            m_FCal2Inactive += energy;
+
+        if (m_larFCalID->module(id) == 3)
+            m_FCal3Inactive += energy;
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Calculate truth impact position
+
+void LArFCalSamplingFraction::TruthImpactPosition(McEventCollection::const_iterator e)
+{
+    for (HepMC::GenEvent::particle_const_iterator p = (**e).particles_begin();
+         p != (**e).particles_end(); p++)
+    {
+        const HepMC::GenParticle *theParticle = *p;
+
+        // Note: old GenParticles used HepLorentzVectors, now they use HepMC::FourVectors
+
+        // Get the kinematic variables
+        HepMC::FourVector HMCmom = theParticle->momentum();
+        CLHEP::HepLorentzVector momentum(CLHEP::Hep3Vector(HMCmom.px(), HMCmom.py(), HMCmom.pz()), HMCmom.e());
+
+        HepMC::ThreeVector HMC3vec = theParticle->production_vertex()->point3d();
+        HepGeom::Point3D<double> origin = HepGeom::Point3D<double>(HMC3vec.x(), HMC3vec.y(), HMC3vec.z());
+
+        // Put VEta and VPhi into the Ntuple
+        m_vertex_phi = momentum.vect().phi();
+        m_vertex_eta = -log(tan(momentum.vect().theta() / 2));
+
+        if (!finite(m_vertex_eta))
+            m_vertex_eta = 0;
+
+        m_pt = momentum.vect().perp();
+
+        m_px = momentum.px();
+        m_py = momentum.py();
+        m_pz = momentum.pz();
+
+        m_E = momentum.e();
+
+        m_vertx = theParticle->production_vertex()->point3d().x();
+        m_verty = theParticle->production_vertex()->point3d().y();
+        m_vertz = theParticle->production_vertex()->point3d().z();
+
+        // Must get x-offset depending on TB position. The 90.0 mm is from the
+        // initial x-offset of FCal in cryostat. The -15.0 mm is from the
+        // initial y-offset of FCal in cryostat. The second number changes
+        // between different positions (these numbers will be in database soon)
+
+        std::string nickname;
+        double xoffset = 0;
+        double sinangle = 0;
+        double yoffset = 0;
+        const double z1 = -32668.5 * CLHEP::mm; // This is 4668.5 (z=0 to FCal1 Face) + 28000 (B9 to z=0)
+        const double z2 = -33128.3 * CLHEP::mm; // This is 5128.3 (z=0 to FCal1 Face) + 28000 (B9 to z=0)
+        const double z3 = -33602.8 * CLHEP::mm; // This is 5602.8 (z=0 to FCal1 Face) + 28000 (B9 to z=0)
+
+        double shift2 = sinangle * (5128.3 - 4668.5) * CLHEP::mm;
+        double shift3 = sinangle * (5602.8 - 4668.5) * CLHEP::mm;
+
+        // Accounts for rotation of Fcal + cryostat.
+        m_x_mc_cc1 = origin.x() + m_px * z1 / m_pz + xoffset;
+        m_y_mc_cc1 = origin.y() + m_py * z1 / m_pz + yoffset;
+
+        m_x_mc_cc2 = origin.x() + m_px * z2 / m_pz + shift2 + xoffset;
+        m_y_mc_cc2 = origin.y() + m_py * z2 / m_pz + yoffset;
+
+        m_x_mc_cc3 = origin.x() + m_px * z3 / m_pz + shift3 + xoffset;
+        m_y_mc_cc3 = origin.y() + m_py * z3 / m_pz + yoffset;
+
+    } // particles
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// The main FCal analysis method
+
+StatusCode LArFCalSamplingFraction::doFCal()
+{
+    ATH_MSG_INFO("Starting main FCal analysis");
+
+    ATH_MSG_DEBUG("LArFCalSamplingFraction parameters are:");
+    ATH_MSG_DEBUG("Calibration: " << m_calibrationRun);
+
+    StatusCode sc;
+
+    // ACCESSING EVENT INFORMATION
+    // Get the basic event information (run number, event number).
+
+    const EventInfo *eventInfo = 0;
+    sc = evtStore()->retrieve(eventInfo);
+
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("Could not fetch event information");
+        return sc;
+    }
+
+    const EventID *eventID = eventInfo->event_ID();
+    m_runNumber = eventID->run_number();
+    m_eventNumber = eventID->event_number();
+
+    ATH_MSG_INFO("Run " << m_runNumber << ", event " << m_eventNumber);
+
+    // How to access MC Truth information:
+    const McEventCollection *mcEventCollection;
+    sc = evtStore()->retrieve(mcEventCollection, "TruthEvent");
+
+    if (sc.isSuccess()) {
+        // There can potentially be more than one MC event in the collection.
+        McEventCollection::const_iterator mcEvent;
+        int numMcEvent = 0;
+
+        for (mcEvent = mcEventCollection->begin();
+             mcEvent != mcEventCollection->end();
+             mcEvent++, numMcEvent++)
+            TruthImpactPosition(mcEvent);
+    } // retrieved MC event collection
+    else {
+        ATH_MSG_DEBUG("Run " << m_runNumber << ", event " << m_eventNumber
+                      << ": could not fetch MC event collection");
+    }
+
+    // Accessing Hits
+    // Regular hits
+    std::string FCalContainerName = "LArHitFCAL";
+    const LArHitContainer *container = 0;
+    sc = evtStore()->retrieve(container, FCalContainerName);
+
+    if (sc.isFailure() || container == 0) {
+        ATH_MSG_ERROR("LArHitFCAL container was not found");
+        m_numHitsFCal = 0;
+        return StatusCode::FAILURE;
+    }
+
+    ATH_MSG_DEBUG("LArHitFCAL container successfully retrieved");
+
+    // Get the number of hits in the LArHitFCAL container
+    m_numHitsFCal = container->size();
+    ATH_MSG_INFO("NumHitsFCal = " << m_numHitsFCal);
+
+    if (m_numHitsFCal > 0) {
+        // Calculate the center of gravity
+        FCalHitCenter(container);
+        FCalClusterCenter(container);
+    }
+
+    // Loop over hits in container
+    for (LArHit* const& hit : *container) {
+
+        GeoLArHit fcalhit(*hit);
+
+        // Added by JPA to get particle id for each hit
+        const McEventCollection *mcEventCollection;
+        sc = evtStore()->retrieve(mcEventCollection, "TruthEvent");
+
+        if (sc.isSuccess()) {
+            // There can potentially be more than one MC event in the collection
+            McEventCollection::const_iterator mcEvent;
+            int numParticles = 0;
+
+            for (mcEvent = mcEventCollection->begin();
+                 mcEvent != mcEventCollection->end();
+                 mcEvent++)
+            {
+                // There may be many particles per event
+                for (HepMC::GenEvent::particle_const_iterator p = (**mcEvent).particles_begin();
+                     p != (**mcEvent).particles_end();
+                     p++)
+                {
+                    const HepMC::GenParticle *theParticle = *p;
+                    m_pdg_id->push_back(theParticle->pdg_id());
+                    numParticles++;
+                }
+            }
+        } // retrieved MC event collection
+
+        // End JPA particle id
+
+        if ((!fcalhit) || (!fcalhit.getDetDescrElement()->is_lar_fcal())) {
+            ATH_MSG_ERROR("GeoFCalHit is not defined");
+        }
+
+        double energy = fcalhit.Energy();
+        int module_index = fcalhit.getDetDescrElement()->getLayer();
+        m_totalFCalEnergy += energy;
+
+        if (module_index == 1) {
+            m_FCal1_SumE += energy;
+            FillCellInfo(fcalhit, m_cell1_E, m_hit_x1, m_hit_y1, m_hit_ieta1, m_hit_iphi1, m_NCell1);
+        }
+        else if (module_index == 2) {
+            m_FCal2_SumE += energy;
+            FillCellInfo(fcalhit, m_cell2_E, m_hit_x2, m_hit_y2, m_hit_ieta2, m_hit_iphi2, m_NCell2);
+        }
+        else if (module_index == 3) {
+            m_FCal3_SumE += energy;
+            FillCellInfo(fcalhit, m_cell3_E, m_hit_x3, m_hit_y3, m_hit_ieta3, m_hit_iphi3, m_NCell3);
+        }
+    } // End loop over hits in container
+
+    // Calibration hit analysis.
+    if (m_calibrationRun)
+        CHECK(doCalib());
+
+    ATH_MSG_DEBUG("doFCal() completed successfully");
+
+    return StatusCode::SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Fill FCal cell information
+
+void LArFCalSamplingFraction::FillCellInfo(const GeoLArHit &fcalhit, std::vector<double> *cell_E,
+                                           std::vector<double> *hit_x, std::vector<double> *hit_y,
+                                           std::vector<double> *hit_ieta, std::vector<double> *hit_iphi,
+                                           int &NCell)
+{
+    const double energy = fcalhit.Energy();
+
+    //const FCALTile *tile = fcalhit.getTile();
+    const double hitx = fcalhit.getDetDescrElement()->x(); //tile->getX();
+    const double hity = fcalhit.getDetDescrElement()->y(); //tile->getY();
+    const double hiteta = 7;                               //tile->getIndexI();
+    const double hitphi = 7;                               //tile->getIndexJ();
+
+    bool cellHit = true;
+
+    if (NCell != 0) {
+        for (int icell = 0; icell < NCell; icell++) {
+            if ((hitx == hit_x->at(icell)) && (hity == hit_y->at(icell))) {
+                cellHit = false;
+                cell_E->at(icell) += energy;
+                break;
+            }
+        }
+    }
+
+    if (cellHit) {
+        cell_E->push_back(energy);
+        hit_x->push_back(hitx);
+        hit_y->push_back(hity);
+        hit_ieta->push_back(hiteta);
+        hit_iphi->push_back(hitphi);
+        NCell += 1;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+/// Execute (event by event)
+
+StatusCode LArFCalSamplingFraction::execute()
+{
+    ATH_MSG_DEBUG(" in execute()");
+
+    m_eventNumber++;
+
+    // Initialize first before processing each event
+    StatusCode sc = initEvent();
+
+    if (sc.isFailure())
+        ATH_MSG_WARNING("initEvent failed. Continue");
+
+    sc = doFCal();
+
+    sc = addEventInfo();
+
+    if (sc.isFailure()) {
+        ATH_MSG_WARNING("Failure in getEventInfo() ");
+        return StatusCode::SUCCESS;
+    }
+
+    m_tree_AS->Fill();
+
+    return StatusCode::SUCCESS;
+}
+
+
+StatusCode LArFCalSamplingFraction::addEventInfo()
+{
+    ATH_MSG_DEBUG("in addEventInfo()");
+
+    // This code has been taken from AnalysisExamples/VFitZmmOnAOD
+    // I have the actual EventNumber, but skipped the sequential count of event #
+
+    // Get EventInfo for run and event number
+    const EventInfo *eventInfo;
+    StatusCode sc = evtStore()->retrieve(eventInfo);
+
+    if (sc.isFailure()) {
+        ATH_MSG_WARNING("Could not retrieve event info");
+        return sc;
+    }
+
+    const EventID *myEventID = eventInfo->event_ID();
+
+    m_runNumber = myEventID->run_number();
+    m_eventNumber = myEventID->event_number();
+    ATH_MSG_DEBUG("event " << m_eventNumber);
+
+    m_eventTime = myEventID->time_stamp();
+    m_lumiBlock = myEventID->lumi_block();
+    m_bCID = myEventID->bunch_crossing_id();
+
+    const EventType *myEventType = eventInfo->event_type();
+
+    if (myEventType != 0)
+        m_eventWeight = myEventType->mc_event_weight();
+
+    else
+        m_eventWeight = -999;
+
+    return StatusCode::SUCCESS;
+}
diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.h b/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d53b40e7bdb3752c45368594391dae376735fa8
--- /dev/null
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/src/LArFCalSamplingFraction.h
@@ -0,0 +1,225 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef LAR_FCAL_SAMPLING_FRACTION_H
+#define LAR_FCAL_SAMPLING_FRACTION_H
+
+// C++ stdlib
+#include <string>
+
+// ATLAS Software
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/ObjectVector.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GeneratorObjects/McEventCollection.h"
+#include "GeoAdaptors/GeoLArHit.h"
+#include "LArSimEvent/LArHit.h"
+#include "LArSimEvent/LArHitContainer.h"
+#include "StoreGate/StoreGateSvc.h"
+
+class JetCollection;
+class ISvcLocator;
+class StoreGateSvc;
+class LArFCAL_ID;
+class CaloDM_ID;
+class CaloCell_ID;
+class LArHitContainer;
+class CaloCalibrationHit;
+class CaloCalibrationHitContainer;
+class CaloDetDescrManager;
+class TCECollection;
+class TCEnergies;
+
+
+class LArFCalSamplingFraction : public AthAlgorithm
+{
+public:
+    LArFCalSamplingFraction(const std::string &name, ISvcLocator *pSvcLocator);
+    ~LArFCalSamplingFraction();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute();
+    virtual StatusCode initEvent();
+    StatusCode doFCal();
+    void TruthImpactPosition(McEventCollection::const_iterator);
+
+    void FCalCalibAnalysis(const std::string name, const CaloCalibrationHit *CalibHit);
+    void FCalClusterCenter(const LArHitContainer *container);
+    void FCalHitCenter(const LArHitContainer *container);
+    void FillCellInfo(const GeoLArHit &fcalhit, std::vector<double> *cell_E,
+                      std::vector<double> *hit_x, std::vector<double> *hit_y,
+                      std::vector<double> *hit_ieta, std::vector<double> *hit_iphi,
+                      int &NCell);
+    StatusCode doCalib();
+
+private:
+    /** methods called by execute() */
+
+    // To add event info to new ntuple (used to go by default in CollectionTree)
+    StatusCode addEventInfo();
+
+private:
+    /** A handle on the Hist/TTree registration service */
+    ITHistSvc *m_thistSvc;
+
+    /** A handle on Store Gate for access to the Event Store */
+    StoreGateSvc *m_storeGate;
+
+    /** Athena-Aware Ntuple (AAN) variables - branches of the AAN TTree */
+    TTree *m_tree_AS;
+
+    unsigned int m_runNumber;
+    unsigned int m_eventNumber;
+    unsigned int m_eventTime;
+    unsigned int m_lumiBlock;
+    unsigned int m_bCID;
+    double m_eventWeight;
+    unsigned int m_statusElement;
+
+    /* ----- FCal-related variables ----- */
+    double m_vertx; // x-position for vertex generated particle (beam)
+    double m_verty;
+    double m_vertz;
+
+    double m_vertex_eta; // eta value of generated particle
+    double m_vertex_phi;
+
+    double m_pt; // Momentum of generated particle
+    double m_px;
+    double m_py;
+    double m_pz;
+
+    double m_E; // Energy of generated particle
+
+    int m_NCell1; // Number of cells hit
+    int m_NCell2;
+    int m_NCell3;
+
+    double m_x_mc_cc1; // Center of cluster in x (FCal1, extrapolated)
+    double m_y_mc_cc1;
+
+    double m_x_mc_cc2; // Center of cluster in x (FCal2, extrapolated)
+    double m_y_mc_cc2;
+
+    double m_x_mc_cc3; // Center of cluster in x (FCal3, extrapolated)
+    double m_y_mc_cc3;
+
+    double m_x_cc1; // Center of cluster in x (FCal1, c of g)
+    double m_y_cc1;
+
+    double m_x_cc2; // Center of cluster in x (FCal2, c of g)
+    double m_y_cc2;
+
+    double m_x_cc3; // Center of cluster in x (FCal3, c of g)
+    double m_y_cc3;
+
+    std::vector<int> *m_pdg_id;  // particle id
+
+    std::vector<double> *m_hit_x1; // hit positions of cells
+    std::vector<double> *m_hit_y1;
+
+    std::vector<double> *m_hit_x2;
+    std::vector<double> *m_hit_y2;
+
+    std::vector<double> *m_hit_x3;
+    std::vector<double> *m_hit_y3;
+
+    std::vector<double> *m_hit_ieta1; // hit indices of cells
+    std::vector<double> *m_hit_iphi1;
+    std::vector<double> *m_hit_ieta2;
+    std::vector<double> *m_hit_iphi2;
+    std::vector<double> *m_hit_ieta3;
+    std::vector<double> *m_hit_iphi3;
+
+    std::vector<double> *m_cell1_E; // Energy in cells
+    std::vector<double> *m_cell2_E;
+    std::vector<double> *m_cell3_E;
+
+    double m_FCal1_SumE; // Energy in individual FCal modules
+    double m_FCal2_SumE;
+    double m_FCal3_SumE;
+    double m_TCScint_E;
+    double m_TCIron_E;
+
+    double m_totalFCalEnergy;
+    int m_numHitsFCal;
+
+    /* ----- Calibration Hits Variables ----- */
+    double m_totalCalibrationEnergy; // Total energy
+
+    // Physic processes
+    double m_totalEmEnergy;
+    double m_totalNonEmEnergy;
+    double m_totalInvisibleEnergy;
+    double m_totalEscapedEnergy;
+
+    // Energy deposited in different material categories
+    double m_totalActiveEnergy;
+    double m_totalInactiveEnergy;
+    double m_totalDeadMaterialEnergy;
+
+    // Number of hits in different material categories
+    int m_numHitsActive;
+    int m_numHitsInactive;
+    int m_numHitsDead;
+
+    // Total energy deposited in the different FCal Modules
+    double m_totalFCalCalibrationEnergy; // Energy in all FCal
+    double m_totalFCal1CalibrationEnergy;
+    double m_totalFCal2CalibrationEnergy;
+    double m_totalFCal3CalibrationEnergy;
+
+    double m_FCalActive;
+    double m_FCalInactive;
+    double m_FCalDead;
+    double m_FCalActiveEm;
+    double m_FCalActiveNonEm;
+    double m_FCalActiveInvisible;
+    double m_FCalActiveEscaped;
+    double m_FCalEm;
+    double m_FCal1Em;
+    double m_FCal2Em;
+    double m_FCal3Em;
+    double m_FCalNonEm;
+    double m_FCal1NonEm;
+    double m_FCal2NonEm;
+    double m_FCal3NonEm;
+    double m_FCalInvisible;
+    double m_FCal1Invisible;
+    double m_FCal2Invisible;
+    double m_FCal3Invisible;
+    double m_FCalEscaped;
+    double m_FCal1Escaped;
+    double m_FCal2Escaped;
+    double m_FCal3Escaped;
+    double m_PhysTotE;
+    double m_FCal1Active;
+    double m_FCal2Active;
+    double m_FCal3Active;
+    double m_FCal1Inactive;
+    double m_FCal2Inactive;
+    double m_FCal3Inactive;
+
+    const CaloDM_ID *m_caloDmID;
+    const CaloCell_ID *m_caloCellID;
+    const LArFCAL_ID *m_larFCalID;
+
+    // For LAr analysis: Do we have any calibration hits at all?
+    bool m_calibrationRun;
+
+    // In order to write some clever loops, store all the hit containers
+    // of a given type in a map.
+    typedef std::map<std::string, const CaloCalibrationHitContainer *> m_calibHitMap_t;
+    typedef m_calibHitMap_t::iterator m_calibHitMap_ptr_t;
+    m_calibHitMap_t m_calibHitMap;
+
+    // Variables needed for cluster centers
+    double m_cx1, m_cx2, m_cx3;
+    double m_cy1, m_cy2, m_cy3;
+};
+
+#endif // LAR_FCAL_SAMPLING_FRACTION_H
diff --git a/Simulation/Tools/CaloSamplingFractionAnalysis/src/components/CaloSamplingFractionAnalysis_entries.cxx b/Simulation/Tools/CaloSamplingFractionAnalysis/src/components/CaloSamplingFractionAnalysis_entries.cxx
index ce7ff66556fa8e9596951aefb42ee04d47ef0f41..fc5934fe7f5e0cc3ca083aa9f8f2a5046dfdc035 100755
--- a/Simulation/Tools/CaloSamplingFractionAnalysis/src/components/CaloSamplingFractionAnalysis_entries.cxx
+++ b/Simulation/Tools/CaloSamplingFractionAnalysis/src/components/CaloSamplingFractionAnalysis_entries.cxx
@@ -1,4 +1,6 @@
 #include "../LarEMSamplingFraction.h"
+#include "../LArFCalSamplingFraction.h"
 
 DECLARE_COMPONENT( LarEMSamplingFraction )
+DECLARE_COMPONENT( LArFCalSamplingFraction )