From 02645fc8b7530828de329b37f695c11776023c65 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 13 Sep 2019 08:49:36 -0700
Subject: [PATCH 01/47] First commit of the offline monitoring code

---
 Monitoring/CMakeLists.txt                  |  15 ++
 Monitoring/python/LegacySelector.py        |  65 ++++++
 Monitoring/python/Monitor1DValue.py        | 200 ++++++++++++++++
 Monitoring/python/MonitorValueBase.py      | 253 +++++++++++++++++++++
 Monitoring/python/MonitorValueManager.py   | 200 ++++++++++++++++
 Monitoring/python/README                   |  11 +
 Monitoring/python/__init__.py              |   2 +
 Monitoring/share/simpleMonitoringTest.json | 106 +++++++++
 Monitoring/share/simpleMonitoringTest.py   |  41 ++++
 9 files changed, 893 insertions(+)
 create mode 100644 Monitoring/CMakeLists.txt
 create mode 100644 Monitoring/python/LegacySelector.py
 create mode 100755 Monitoring/python/Monitor1DValue.py
 create mode 100644 Monitoring/python/MonitorValueBase.py
 create mode 100755 Monitoring/python/MonitorValueManager.py
 create mode 100644 Monitoring/python/README
 create mode 100644 Monitoring/python/__init__.py
 create mode 100644 Monitoring/share/simpleMonitoringTest.json
 create mode 100755 Monitoring/share/simpleMonitoringTest.py

diff --git a/Monitoring/CMakeLists.txt b/Monitoring/CMakeLists.txt
new file mode 100644
index 000000000..7e33f8b89
--- /dev/null
+++ b/Monitoring/CMakeLists.txt
@@ -0,0 +1,15 @@
+################################################################################
+# Package: Monitoring
+# Contains python code to implement offline monitoring
+################################################################################
+
+
+# Declare the package name:
+atlas_subdir( Monitoring )
+
+# External dependencies:
+find_package( ROOT COMPONENTS Core Tree )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+atlas_install_scripts( share/*.py )
diff --git a/Monitoring/python/LegacySelector.py b/Monitoring/python/LegacySelector.py
new file mode 100644
index 000000000..0481d7e6e
--- /dev/null
+++ b/Monitoring/python/LegacySelector.py
@@ -0,0 +1,65 @@
+#
+#  LegacySelector.py
+#
+#  Class to select values from legacy ntuples
+#
+#  E.Torrence, Sept. 2019
+#
+#
+# Use Python3-style print statements
+from __future__ import print_function
+
+class LegacySelector ():
+    """Class to select values from Legacy ntuple"""
+
+    def __init__(self):
+        """Constructor"""
+
+        self.conf = None
+
+    # Pass MonitorValue conf object
+    def init(self, conf):
+        """Initialization"""
+
+        # Just save full conf object
+        self.conf = conf
+
+    # Return list of values from data object event
+    def get1DValue(self, event, varName):
+
+        # print ("LegacySelector.get1DValue called for", varName)
+
+        values = []
+
+        #varName = self.conf.xvar
+
+        # Variable name should first give the list, followed by the specific parameter
+        # Only the event number doesn't follow this pattern
+        if varName == 'fEventNumber':
+            # OK, this is weird, event is actually the tree, while event.event is the FaserEvent class.  
+            # For the lists, we can get them directly from event...
+            return event.event.GetEventNumber()
+
+        theListName = varName.split('.')[0]
+
+        theList = getattr(event, theListName)
+
+        # Loop over truth list
+        for obj in theList:
+            # Try to parse the variable string
+            # Find chunks separated by a point
+            # Each is either a method or an attribute
+            theObj = obj
+            varList = self.conf.xvar.split('.')[1:]      # Skip the list [1:]
+            for varName in varList:
+                # Is this an attribute or a method?
+                if callable(getattr(theObj, varName)):
+                    theObj = getattr(theObj, varName)()  # Method (function)
+                else:
+                    theObj = getattr(theObj, varName)    # Attribute (value)
+
+            # Once we have walked through the list, have our value
+            values.append(theObj)
+
+
+        return values
diff --git a/Monitoring/python/Monitor1DValue.py b/Monitoring/python/Monitor1DValue.py
new file mode 100755
index 000000000..1f43dc623
--- /dev/null
+++ b/Monitoring/python/Monitor1DValue.py
@@ -0,0 +1,200 @@
+#!/bin/env python
+#
+#  Monitor1DValue.py
+#
+#  Defines classes to implement monitored values
+#
+#  Classes
+#    Monitor1DValue
+#    Monitor1DValueConfig
+#
+#  E.Torrence, Aug. 2019
+#
+#
+# Use Python3-style print statements
+from __future__ import print_function
+
+import sys
+import ROOT
+
+from Monitoring.MonitorValueBase import MonitorValueBase, MonitorConfigBase
+
+#
+# 1D Monitoring class and configuration
+#
+class Monitor1DValueConfig(MonitorConfigBase):
+    """Configuration for Monitor1DValue"""
+
+    # Everything in this configuration must be simple values so JSON works
+
+    def __init__(self):
+        """Constructor providing default values"""
+
+        MonitorConfigBase.__init__(self)
+        # Defines tag, type, and desc
+
+        # Variable
+        self.selector = None # Text string describing selector class
+
+        self.xvar = None   # Text string describing value to fill
+
+        # Scale factor
+        self.xscale = 1
+
+        # Histogram parameters
+        self.nbins = 0
+        self.xlo = 0.
+        self.xhi = 0.
+        self.xlabel = ""
+        self.ylabel = ""
+
+        # Plot under/overflows
+        self.overflow = True
+
+        # Draw as linear or log scale by default
+        self.logy = False
+
+    # Utility function to make it easier to define hist parameters
+    def setBinning(self, nbins, xlo, xhi, xlabel="", ylabel=""):
+        """Define histogram bins and range"""
+
+        # Utility function to set histogram parameters in one go
+        self.nbins = nbins
+        self.xlo = xlo
+        self.xhi = xhi
+        self.xlabel = xlabel
+        self.ylabel = ylabel
+
+    
+class Monitor1DValue (MonitorValueBase):
+    """One dimensional monitored value class"""
+
+    def __init__(self, tag=''):
+        """Constructor, tag is a unique identification string"""
+
+        # Instantiate the configuration object
+        self.conf = Monitor1DValueConfig()
+
+        # Set the tag if provided
+        self.conf.tag = tag
+
+    def init(self):
+        """Initialize class and create histogram"""
+
+        # First call the base class, which checks a few things
+        MonitorValueBase.init(self)
+
+        # Now create our histogram with the parameters in self.conf
+        # Check if we want to store integers or floats
+        if isinstance(self.conf.xlo, int) and isinstance(self.conf.xhi, int):
+            self.hist = ROOT.TH1I(self.conf.tag+"_h", "", 
+                                  self.conf.nbins, self.conf.xlo, self.conf.xhi)
+        else: 
+            self.hist = ROOT.TH1D(self.conf.tag+"_h", "", 
+                                  self.conf.nbins, self.conf.xlo, self.conf.xhi)
+
+        # Also set labels
+        self.hist.GetXaxis().SetTitle(self.conf.xlabel)
+        self.hist.GetYaxis().SetTitle(self.conf.ylabel)
+
+    def fill(self, event):
+        """Fill histogram from event object"""
+
+        self.fillValue(self.selector.get1DValue(event, self.conf.xvar))
+
+        #varstr = self.conf.xvar
+        #theVar = getattr(event, varstr)
+        #self.fillValue(theVar)
+
+    def fillValue(self, val):
+        """Fill histogram with one or more values"""
+
+        #print ("Monitor1DValue.fillValue called with", val)
+
+        # Check if this is a single value or an iterable sequence
+        if hasattr(val, '__iter__'):
+            for v in val:
+                self.hist.Fill(v*self.conf.xscale)
+        else:
+            self.hist.Fill(val*self.conf.xscale)
+
+
+    def plot(self, c):
+        """Plot histogram to canvas c"""
+
+        # Log or lin?
+        if self.conf.logy:
+            c.SetLogy(True)
+        else:
+            c.SetLogy(False)
+
+        # Do something fancy to draw the overflow?
+        if self.conf.overflow:
+            # Must make a new histogram and fill under/overflow in first/last bins
+            h = self.hist.Clone()
+            nb = h.GetNbinsX()
+
+            under = h.GetBinContent(0)
+            h.SetBinContent(1, h.GetBinContent(1)+under)
+            over = h.GetBinContent(nb+1)
+            h.SetBinContent(nb, h.GetBinContent(nb)+over)
+
+        else:
+            h = self.hist
+
+        # Draw with default parameters
+        h.DrawCopy()
+
+# Testing code
+if __name__ == '__main__':
+
+    mv1 = Monitor1DValue('test1')
+    mv1.conf.setBinning(30, -3., 3.)
+    mv1.init()
+
+    mv2 = Monitor1DValue('test2')
+    mv2.conf.setBinning(30, -3., 3.)
+    mv2.init()
+
+    # Fill a list
+    import random
+    values = [random.gauss(0., 1.) for x in range(100)]
+    mv1.fill(values)
+
+    # Try one more
+    mv1.fill(random.gauss(0., 1.))
+
+    # Print something out
+    mv1.dump()
+
+    # Write to file
+    print()
+    print("Test writing to ROOT file")
+    tf = ROOT.TFile("test.root", "recreate")
+    mv1.writeRoot(tf)
+    mv2.writeRoot(tf)
+    #writeMonitorValue(tf, mv1)
+    #writeMonitorValue(tf, mv2)
+    tf.Close()
+
+    print()
+    print("Test reading from ROOT file")
+    tf = ROOT.TFile('test.root')
+
+    print()
+    print("Directory listing")
+    tf.ls()
+
+    from Monitoring.MonitorValueBase import readMonitorValueFromRoot
+
+    print()
+    print("Read objects back from ROOT file")    
+    mvr1 = readMonitorValueFromRoot(tf, "test1")
+    mvr1.dump()
+    mvr2 = readMonitorValueFromRoot(tf, "test2")
+    mvr2.dump()
+    try:
+        readMonitorValueFromRoot(tf, "test3")
+    except Exception as e:
+        print(e)
+
diff --git a/Monitoring/python/MonitorValueBase.py b/Monitoring/python/MonitorValueBase.py
new file mode 100644
index 000000000..82220c35c
--- /dev/null
+++ b/Monitoring/python/MonitorValueBase.py
@@ -0,0 +1,253 @@
+#
+#  MonitorValueBase.py
+#
+#  Defines base classes to implement monitored values
+#
+#  Functions
+#    readMonitorValueFromRoot - read MonitorValue from ROOT file
+#    monitorValueFromJSON - construct MonitorValue from JSON
+#
+#  Classes
+#    MonitorValueBase
+#    MonitorConfigBase
+#
+#  E.Torrence, Aug. 2019
+#
+#
+# Use Python3-style print statements
+from __future__ import print_function
+
+import sys
+import ROOT
+import json
+
+# Utility function to create object instance from ROOT file
+def readMonitorValueFromRoot(f, tag):
+    """Read class named tag from open root file f"""
+
+    # Objects stored in subdirectory, make sure it exists
+    if not f.cd(tag):
+        print("Object", tag, "not present in file!")
+        f.ls()
+        raise ObjectNotFoundError("Error: directory not found for object "+tag+"!")
+    
+    #print ("Changed to directory", tag)
+    #f.ls()
+
+    # Read histogram first
+    histName = tag+"_h"
+    #print("Reading histogram", histName)
+    hist = ROOT.gROOT.FindObject(histName)
+    if hist is None:
+        f.cd("..")
+        raise ObjectNotFoundError("Error: unable to read histogram", histName,"!")
+
+    # Read JSON string stored in a TNamed object
+    objectName = tag+"_j"
+    tobj = ROOT.gROOT.FindObject(objectName)
+    if tobj is None:
+        f.cd("..")
+        raise ObjectNotFoundError("Error: unable to read JSON from",objectName, "!")
+
+    # Get JSON string from TNamed
+    jsonString = tobj.GetTitle()
+
+    #print(jsonString)
+    #obj = pickle.loads(unicode(pickleString.GetTitle(), 'utf-8'))
+
+    # Call our utility function to create a new (un-initalized) object
+    obj = monitorValueFromJSON(json.loads(jsonString))
+
+    # And put the histogram back
+    obj.hist = hist
+
+    # Return to the parent directory in the ROOT file
+    f.cd("..")
+
+    # Return the recreated object
+    return obj
+
+
+# Utility to create a new class from a JSON description
+# This does not initialize the class
+def monitorValueFromJSON(jsonDict):
+
+    # jsonDict = json.loads(jsonString)
+
+    # Get the object class name
+    className = jsonDict.get('type', None)
+    if className is None:
+        print ("monitorValueFromJSON: no class type specified!")
+        return None
+
+    # Find the class object in our module
+    # This is some voodoo
+    # Monitoring is the package name
+    # className is both the class but also the submodule to search in
+    # The fromlist=[] needs to specify the submodules
+    # So this works as long as each MV type has a unique module
+    # Need a better way to do this (perhaps using __init__.py?
+    class_ = getattr(__import__("Monitoring."+className, fromlist=[className]), className)
+
+    # Instantiate this class
+    obj = class_()
+
+    if obj is None:
+        f.cd("..")
+        raise ObjectNotFoundError("Error: unable to instantiate object", objectName, "!")
+
+    # Update the configuration from the JSON file
+    obj.conf.fromJSON(jsonDict)
+
+    # Also instantiate the selector
+    className = jsonDict.get('selector', None)
+
+    if className is None:
+        obj.selector = None
+        print ("monitorValueFromJSON: No selector specified for value", jsonDict["tag"])
+
+    else:
+        # Find the class name in our module
+        class_ = getattr(__import__("Monitoring."+className, fromlist=[className]), className)
+    # And instantiate this class
+        obj.selector = class_()
+
+        if obj.selector is None:
+            raise ObjectNotFoundError("Error: unable to instantiate object", objectName, "!")
+
+    # Done with selector object
+
+    # Don't call obj.init here, make user do this
+    return obj
+
+# Error in case histogram can't be read
+class ObjectNotFoundError(KeyError):
+     pass
+
+class MonitorValueBase ():
+    """Base class for monitored values"""
+
+    def __init__(self):
+        """Dummy Constructor"""
+
+        # Configuration object to store all needed parameters
+        self.conf = None
+
+        # Histogram (or other ROOT class) containing data
+        self.hist = None
+
+        # Selector class to fill histogram
+        self.selector = None
+
+    # Common init functions
+    def init(self):    
+
+        if self.conf is None:
+            print ("MonitorValueBase: init() called with no valid configuration!")
+            return
+
+        # Set type if not configured
+        actualType = self.__class__.__name__
+        if self.conf.type == None:
+            self.conf.type = actualType
+
+        # Check that type is correct
+        elif actualType != self.conf.type:
+            print ("actualType", actualType, "does not match configured type", self.conf.type,"!")
+            print ("...overriding conf.type")
+            self.conf.type = actualType
+
+        # Initialize the selector
+        if self.selector is not None:
+            self.selector.init(self.conf)
+
+
+    def fill(self, v):
+        # Dummy fill function
+        pass
+
+    def plot(self, c):
+        # Dummy plot function, must pass canvas in case we want to make log scale
+        pass
+
+    def dump(self):
+        """Write histogram to specified stream (stdout by default)"""
+
+        #print("Dump called for", self.conf.tag)
+        print(self.conf)
+        if self.hist is not None:
+            self.hist.Print()
+
+    def __str__(self):
+        return str(self.conf)
+
+    def writeRoot(self, f):
+        """Write hist and conf to open root file f"""
+
+        # Make a subdirectory to contain the components and switch
+        cwd = f.mkdir(self.conf.tag)
+        cwd.cd()
+
+        # Write the histogram first (if it isn't NULL)
+        if self.hist is not None:
+            self.hist.Write()
+
+        # Also write the conf JSON to TString
+        # ROOT name is tag_p
+        jsonString = self.conf.toJSON()
+        ts = ROOT.TNamed(self.conf.tag+"_j", jsonString)
+        ts.Write()
+
+        # Also write pickled object to TString
+        # pickleString = pickle.dumps(self)
+        # ts = ROOT.TNamed(self.tag+"_p", pickleString.decode("utf-8"))
+        # ts.Write()
+
+        # Now go back to starting directory to not screw things up
+        cwd.cd("..")
+
+    # These aren't needed any more
+    # Remove hist from elements to pickle (we save this separately)
+    def __getstate__(self):
+        state = self.__dict__.copy()
+        # Don't pickle hist
+        del state["hist"]
+        return state
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        # Add hist back since it doesn't exist in the pickle
+        self.hist = None
+
+#
+# Base class for configuration objects
+class MonitorConfigBase:
+
+    def __init__(self):
+        """Constructor provides default values"""
+        self.tag = ""    # Unique identifier string
+        self.type = None # Class name of instantiated MonitorValue object
+        self.desc = ""   # Helpful description string
+
+    def toJSON(self, indentLevel=0):
+        """Return JSON string describing values in this class"""
+        return json.dumps(self, default=lambda o: o.__dict__,
+                          sort_keys=True, indent=indentLevel)
+
+    def fromJSONStr(self, jsonString):
+        """Update class attributes using values read in from JSON string"""
+
+        # Note, values not specified will not be changed
+        jsonDict = json.loads(jsonString)
+        self.fromJSON(jsonDict)
+
+    def fromJSON(self, jsonDict):
+        """Update class attributes using values in parsed JSON dict"""
+
+        # This will only work for simple parameters
+        for (key, val) in jsonDict.iteritems():
+            setattr(self, key, val)
+
+    def __str__(self):
+        return self.toJSON(indentLevel=2)
+
diff --git a/Monitoring/python/MonitorValueManager.py b/Monitoring/python/MonitorValueManager.py
new file mode 100755
index 000000000..af869e229
--- /dev/null
+++ b/Monitoring/python/MonitorValueManager.py
@@ -0,0 +1,200 @@
+#!/bin/env python
+#
+# MonitorValueManager.py
+#
+# Defines the MonitorValueManager class that coordinates actions
+# for a large set of instantiated MonitorValue objects
+#
+# Classes
+#   MonitorValueManager
+#
+#  E.Torrence, Aug. 2019 
+#
+# Use python3-style print statements
+from __future__ import print_function
+
+import ROOT
+import json
+
+from Monitoring.MonitorValueBase import monitorValueFromJSON
+
+# Need to import all defined MV types so we can find them below
+from Monitoring.Monitor1DValue import Monitor1DValue
+
+
+class MonitorValueManager:
+    """Class to instantiate and manage a large set of MonitorValue objects"""
+
+    def __init__(self):
+        """Constructor"""
+
+        # Flag to print out some monitoring information
+        self.debug = True
+
+        # dict containing all MonitorValues, tags are used for keys
+        self.mvalDict = dict()
+
+        # Key list, used to keep order straight
+        self.tagList = []
+
+    def addValue(self, val):
+        """Add an instantiated MonitorValue to the dictionary"""
+
+        tag = val.conf.tag
+        if tag in self.mvalDict.keys():
+            print("Value with tag", tag,"already exists!")
+            print(self.mvalDict[tag].conf)
+            return
+
+        self.mvalDict[tag] = val
+        self.tagList.append(tag)
+        
+    def initValues(self):
+        """Call the init method on all stored MVs"""
+        # Loop through all MonitorValues defined and call the init() function
+        for val in self.mvalDict.itervalues():
+            if (self.debug):
+                print("Initializing value", val.conf.tag)
+
+            val.init()
+
+    def fillValues(self, event):
+        """Call the fill method on all stored MVs"""
+        for val in self.mvalDict.itervalues():
+            val.fill(event)
+
+    def writeValues(self, filename):
+        """Write out value histograms to file"""
+
+        # Simplest implementation for now
+        # Add some directory structure later
+        f = ROOT.TFile(filename, "RECREATE")
+
+        for val in self.mvalDict.itervalues():
+            val.writeRoot(f)
+
+        # Cleanup
+        f.Close()
+
+    def plotValuesToPDF(self, filename):
+        """Call the plot methods with output going to a PDF file"""
+        
+        # Lets see if this works
+        c = ROOT.TCanvas()
+        c.Print(filename+"[")
+
+        for tag in self.tagList:
+            val = self.mvalDict[tag]
+            val.plot(c)
+            c.Print(filename)
+
+        c.Print(filename+"]")
+
+    def createValuesFromJSON(self, filename):
+        """ Create values from JSON file of name filename"""
+
+        if self.debug: print("Opening JSON file", filename)
+        # Open file
+        try:
+            f = open(filename)
+        except Exception as e:
+            print("Error opening file", filename)
+            print(e)
+            return
+
+        # Parse JSON
+        if self.debug: print("Parsing JSON")
+        jsonList = json.load(f)
+
+        # Close the file
+        f.close()
+
+        # Keep track of what we are doing
+        count = 0
+        if self.debug: print("Creating objects from JSON")
+        for item in jsonList:
+            try:
+                newval = monitorValueFromJSON(item)
+            except Exception as e:
+                # On error, print error and continue
+                print("MonitorValueManager.createValuesFromJSON - Error creating object", item, "!")
+                print(e)
+                continue
+
+            self.addValue(newval)
+            count += 1
+
+        # Print out some results
+        if (self.debug):
+            print("Created", count, "new values")
+            print("Full list of MonitorValue tags:")
+            for key in sorted(self.mvalDict.keys()):
+                print(key)
+
+    def listValues(self):
+        """Print out type and tags for all defined values"""
+
+
+        print ("Listing of MonitorValues")
+
+        if len(self.mvalDict) == 0:
+            print("Value list is empty!")
+            return
+
+
+        print("Tag   ValueType")
+        print("---   ---------")
+        for tag in self.tagList:
+            print(tag, self.mvalDict[tag].conf.type)
+
+    def dumpValues(self):
+        """Print out verbose information for all defined values"""
+
+        if len(self.mvalDict) == 0:
+            print("Value list is empty!")
+            return
+
+        for tag in self.tagList:         # Sort to get alphabetical listing
+            print()
+            print(tag, self.mvalDict[tag].conf.type)
+            self.mvalDict[tag].dump()
+
+    def writeJSON(self, stream):
+        """Write out JSON for all configured objects to specified stream"""
+
+        jsonList = []
+        for tag in self.tagList:
+            val = self.mvalDict[tag]
+            jsonList.append(val.conf)
+
+        json.dump(jsonList, stream, default=lambda o: o.__dict__, 
+                  sort_keys=True, indent=2)
+
+# Testing code
+if __name__ == '__main__':
+
+    from Monitoring.Monitor1DValue import Monitor1DValue
+
+    mv1 = Monitor1DValue('test1')
+    mv1.conf.setBinning(30, -3., 3.)
+
+    mv2 = Monitor1DValue('test2')
+    mv2.conf.setBinning(60, -3., 3.)
+
+    mvm = MonitorValueManager()
+
+    mvm.addValue(mv1)  # Add already defined mv
+    mvm.addValue(mv2)
+    mvm.initValues()   # Initialize all values
+    mvm.listValues()   # Brief printout of all values
+    mvm.dumpValues()
+
+
+    import sys
+    mvm.writeJSON(sys.stdout)
+    print()
+
+    mvm.createValuesFromJSON('test.json')
+
+    mvm.listValues()
+
diff --git a/Monitoring/python/README b/Monitoring/python/README
new file mode 100644
index 000000000..fb7bb8fe1
--- /dev/null
+++ b/Monitoring/python/README
@@ -0,0 +1,11 @@
+Things to do:
+-) Add some structure to the JSON config file, in particular, create
+   some kind of set structure that will be reflected in ROOT file,
+   but also groups monitored quantities by type.
+
+-) Remove JSON text from ROOT file (or store in separate structure)
+
+-) Figure out how to read ntuple variables.  Possibly have a 'handler' by 
+   data type, i.e. TruthParticle or SpacePoints.  These will know how to 
+   decode variables by simple string, and also might have their own config
+   parameters to be set.
diff --git a/Monitoring/python/__init__.py b/Monitoring/python/__init__.py
new file mode 100644
index 000000000..447ad57d5
--- /dev/null
+++ b/Monitoring/python/__init__.py
@@ -0,0 +1,2 @@
+# 
+__author__ = "Eric Torrence"
diff --git a/Monitoring/share/simpleMonitoringTest.json b/Monitoring/share/simpleMonitoringTest.json
new file mode 100644
index 000000000..60e8fe250
--- /dev/null
+++ b/Monitoring/share/simpleMonitoringTest.json
@@ -0,0 +1,106 @@
+[
+  {
+    "tag": "eventNumber", 
+    "type": "Monitor1DValue", 
+    "desc": "Event Number",
+    "selector": "LegacySelector",
+    "xvar": "fEventNumber",
+    "nbins": 1000, 
+    "xlo":  0, 
+    "xhi":  10000, 
+    "xlabel": "Event Number", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": false
+  }, 
+  {
+    "tag": "pdgCode", 
+    "type": "Monitor1DValue", 
+    "desc": "Truth particle PDG Code",
+    "selector": "LegacySelector",
+    "xvar": "fParticles.PdgCode",
+    "nbins": 53, 
+    "xlo": -12, 
+    "xhi":  40, 
+    "xlabel": "PDG Code", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": true
+  }, 
+  {
+    "tag": "truthEnergy", 
+    "type": "Monitor1DValue", 
+    "desc": "Truth particle energy",
+    "selector": "LegacySelector",
+    "xvar": "fParticles.Energy",
+    "xscale": 0.001,
+    "nbins": 50, 
+    "xlo": 0.0, 
+    "xhi": 1000.0, 
+    "xlabel": "Energy (GeV)", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": false
+  },
+  {
+    "tag": "truthVertexX", 
+    "type": "Monitor1DValue", 
+    "desc": "Truth particle X Vertex",
+    "selector": "LegacySelector",
+    "xvar": "fParticles.Vertex.x",
+    "xscale": 0.001,
+    "nbins": 50, 
+    "xlo": -0.5, 
+    "xhi": 0.5, 
+    "xlabel": "Truth Vertex X (m)", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": false
+  },
+  {
+    "tag": "truthVertexY", 
+    "type": "Monitor1DValue", 
+    "desc": "Truth particle Y Vertex",
+    "selector": "LegacySelector",
+    "xvar": "fParticles.Vertex.y",
+    "xscale": 0.001,
+    "nbins": 50, 
+    "xlo": -0.5, 
+    "xhi": 0.5, 
+    "xlabel": "Truth Vertex Y (m)", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": false
+  },
+  {
+    "tag": "truthVertexZ", 
+    "type": "Monitor1DValue", 
+    "desc": "Truth particle Z Vertex",
+    "selector": "LegacySelector",
+    "xvar": "fParticles.Vertex.z",
+    "xscale": 0.001,
+    "nbins": 50, 
+    "xlo": -2.5, 
+    "xhi": 2.5, 
+    "xlabel": "Truth Vertex Z (m)", 
+    "ylabel": "Entries",
+    "overflow": true, 
+    "logy": false
+  },
+
+  {
+    "tag": "trackerDigiPlane", 
+    "type": "Monitor1DValue", 
+    "desc": "Tracker Digi Plane",
+    "selector": "LegacySelector",
+    "xvar": "fTrackerDigis.Plane",
+    "nbins": 11, 
+    "xlo": -1, 
+    "xhi": 10, 
+    "xlabel": "Plane", 
+    "ylabel": "Digis",
+    "overflow": true, 
+    "logy": false
+  }
+
+]
\ No newline at end of file
diff --git a/Monitoring/share/simpleMonitoringTest.py b/Monitoring/share/simpleMonitoringTest.py
new file mode 100755
index 000000000..f33301e0d
--- /dev/null
+++ b/Monitoring/share/simpleMonitoringTest.py
@@ -0,0 +1,41 @@
+#!/bin/env python
+#
+# simpleMonitoringTest.py
+#
+# Example of simple monitoring job using hte MonitorValueManager
+# Need JSON file simpleMonitoringTest.json and a TDR-style
+# ntuple in the run directory
+#
+# E. Torrence, Aug. 2019
+#
+# Use python3-style print statements
+from __future__ import print_function
+
+from Monitoring.MonitorValueManager import MonitorValueManager
+
+import ROOT
+
+# Start by instantiating mvm
+mvm = MonitorValueManager()
+
+# Load the configuration
+mvm.createValuesFromJSON('simpleMonitoringTest.json')
+mvm.initValues()
+# mvm.listValues()  # Check what we have
+mvm.dumpValues()  # Check what we have
+
+# Open ntuple
+tf = ROOT.TFile('ntuple.root')
+tt = tf.Get('faser')
+
+# Loop over events
+for event in tt:
+    mvm.fillValues(event)
+
+tf.Close()
+
+# Write to file
+mvm.writeValues('simpleMonitoringTest.root')
+
+# Plot values
+mvm.plotValuesToPDF('simpleMonitoringTest.pdf')
-- 
GitLab


From 4e88975593b582d2f9ce83665b1a25d836b4aeb8 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 9 Jun 2020 16:12:21 -0700
Subject: [PATCH 02/47] First commit of bytestream reading changes

---
 .gitmodules                                   |    3 +
 Event/FaserByteStreamCnvSvc/CMakeLists.txt    |  109 ++
 .../ByteStreamExceptions.h                    |   40 +
 .../ByteStreamInputSvc.h                      |   69 ++
 .../FaserByteStreamCnvSvc.h                   |  102 ++
 .../python/ReadByteStream.py                  |   69 ++
 .../FaserByteStreamCnvSvc/python/__init__.py  |    2 +
 Event/FaserByteStreamCnvSvc/src/DumpFrags.h   |  111 ++
 .../src/EventInfoByteStreamAuxCnv.cxx         |  284 +++++
 .../src/EventInfoByteStreamAuxCnv.h           |   60 +
 .../src/EventInfoByteStreamxAODCnv.cxx        |   81 ++
 .../src/EventInfoByteStreamxAODCnv.h          |   45 +
 .../src/FaserByteStreamCnvSvc.cxx             |  292 +++++
 .../src/FaserByteStreamInputSvc.cxx           |  465 ++++++++
 .../src/FaserByteStreamInputSvc.h             |  135 +++
 .../src/FaserEventContextByteStream.cxx       |   26 +
 .../src/FaserEventContextByteStream.h         |   38 +
 .../src/FaserEventSelectorByteStream.cxx      | 1041 +++++++++++++++++
 .../src/FaserEventSelectorByteStream.h        |  167 +++
 .../FaserByteStreamCnvSvc_entries.cxx         |   28 +
 Event/FaserEventStorage/CMakeLists.txt        |   32 +
 .../FaserEventStorage/DRError.h               |   21 +
 .../FaserEventStorage/DataReader.h            |  146 +++
 .../FaserEventStorage/ESCompression.h         |   20 +
 .../FaserEventStorage/EventStorageIssues.h    |  134 +++
 .../FaserEventStorage/EventStorageRecords.h   |  126 ++
 .../FaserEventStorage/FileNameCallback.h      |   39 +
 .../FaserEventStorage/RawFileName.h           |  263 +++++
 .../FaserEventStorage/fRead.h                 |   70 ++
 .../FaserEventStorage/loadfRead.h             |   14 +
 .../FaserEventStorage/pickFaserDataReader.h   |   26 +
 Event/FaserEventStorage/README                |    4 +
 .../src/DataReaderController.cxx              |  681 +++++++++++
 .../src/DataReaderController.h                |  122 ++
 Event/FaserEventStorage/src/ESLMultiFile.cxx  |  167 +++
 Event/FaserEventStorage/src/ESLMultiFile.h    |   51 +
 .../FaserEventStorage/src/ESLOriginalFile.cxx |  654 +++++++++++
 Event/FaserEventStorage/src/ESLOriginalFile.h |  111 ++
 .../FaserEventStorage/src/EventStackLayer.cxx |  281 +++++
 Event/FaserEventStorage/src/EventStackLayer.h |  164 +++
 .../src/EventStorageInternalRecords.h         |   91 ++
 .../src/EventStorageRecords.cxx               |   59 +
 Event/FaserEventStorage/src/RawFileName.cxx   |  738 ++++++++++++
 Event/FaserEventStorage/src/fReadPlain.cxx    |  148 +++
 Event/FaserEventStorage/src/fReadPlain.h      |   35 +
 Event/FaserEventStorage/src/loadfRead.cxx     |   40 +
 .../src/pickFaserDataReader.cxx               |  132 +++
 faser-common                                  |    1 +
 48 files changed, 7537 insertions(+)
 create mode 100644 .gitmodules
 create mode 100644 Event/FaserByteStreamCnvSvc/CMakeLists.txt
 create mode 100644 Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamExceptions.h
 create mode 100644 Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
 create mode 100644 Event/FaserByteStreamCnvSvc/python/__init__.py
 create mode 100644 Event/FaserByteStreamCnvSvc/src/DumpFrags.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
 create mode 100644 Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
 create mode 100644 Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
 create mode 100644 Event/FaserEventStorage/CMakeLists.txt
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/DRError.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/DataReader.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/ESCompression.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/EventStorageIssues.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/EventStorageRecords.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/FileNameCallback.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/RawFileName.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/fRead.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/loadfRead.h
 create mode 100644 Event/FaserEventStorage/FaserEventStorage/pickFaserDataReader.h
 create mode 100644 Event/FaserEventStorage/README
 create mode 100644 Event/FaserEventStorage/src/DataReaderController.cxx
 create mode 100644 Event/FaserEventStorage/src/DataReaderController.h
 create mode 100644 Event/FaserEventStorage/src/ESLMultiFile.cxx
 create mode 100644 Event/FaserEventStorage/src/ESLMultiFile.h
 create mode 100644 Event/FaserEventStorage/src/ESLOriginalFile.cxx
 create mode 100644 Event/FaserEventStorage/src/ESLOriginalFile.h
 create mode 100644 Event/FaserEventStorage/src/EventStackLayer.cxx
 create mode 100644 Event/FaserEventStorage/src/EventStackLayer.h
 create mode 100644 Event/FaserEventStorage/src/EventStorageInternalRecords.h
 create mode 100644 Event/FaserEventStorage/src/EventStorageRecords.cxx
 create mode 100644 Event/FaserEventStorage/src/RawFileName.cxx
 create mode 100644 Event/FaserEventStorage/src/fReadPlain.cxx
 create mode 100644 Event/FaserEventStorage/src/fReadPlain.h
 create mode 100644 Event/FaserEventStorage/src/loadfRead.cxx
 create mode 100644 Event/FaserEventStorage/src/pickFaserDataReader.cxx
 create mode 160000 faser-common

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..5fba28a15
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "faser-common"]
+	path = faser-common
+	url = https://:@gitlab.cern.ch:8443/faser/faser-common.git
diff --git a/Event/FaserByteStreamCnvSvc/CMakeLists.txt b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
new file mode 100644
index 000000000..80fae1ae4
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
@@ -0,0 +1,109 @@
+################################################################################
+# Package: FaserByteStreamCnvSvc
+################################################################################
+
+# Declare the package name:
+atlas_subdir( FaserByteStreamCnvSvc )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs(
+   PUBLIC
+   Control/AthenaBaseComps
+   Event/ByteStreamCnvSvcBase
+   #Event/ByteStreamData
+   GaudiKernel
+   PRIVATE
+   Control/AthenaKernel
+   Control/SGTools
+   Control/StoreGate
+   Database/APR/CollectionBase
+   Database/APR/FileCatalog
+   Database/AthenaPOOL/AthenaPoolUtilities
+   Database/PersistentDataModel
+   Event/FaserEventStorage
+   Event/EventInfo
+   Event/xAOD/xAODEventInfo
+   Event/xAOD/xAODTrigger
+   EventFormats
+   Logging)
+
+# External dependencies:
+find_package( Boost COMPONENTS system )
+find_package( CORAL COMPONENTS CoralBase )
+#find_package( tdaq-common COMPONENTS eformat_old eformat_write RawFileName
+#   DataReader DataWriter )
+
+# Libraries in the package:
+atlas_add_library( FaserByteStreamCnvSvcLib
+   FaserByteStreamCnvSvc/*.h src/*.h src/*.cxx
+   PUBLIC_HEADERS FaserByteStreamCnvSvc
+   PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
+   LINK_LIBRARIES AthenaBaseComps ByteStreamData GaudiKernel
+   ByteStreamCnvSvcLib ByteStreamCnvSvcBaseLib StoreGateLib rt
+   PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES}
+   AthenaKernel SGTools CollectionBase FileCatalog
+   AthenaPoolUtilities PersistentDataModel FaserEventStorageLib EventInfo 
+   xAODEventInfo xAODTrigger)
+
+atlas_add_component( FaserByteStreamCnvSvc
+   src/components/*.cxx
+   LINK_LIBRARIES FaserByteStreamCnvSvcLib )
+
+# Executables in the package:
+# atlas_add_executable( AtlFindBSEvent test/AtlFindBSEvent.cxx
+#    INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
+#    LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${Boost_LIBRARIES} )
+
+# atlas_add_executable( AtlCopyBSEvent test/AtlCopyBSEvent.cxx
+#    INCLUDE_DIRS ${CORAL_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS}
+#    ${Boost_INCLUDE_DIRS}
+#    LINK_LIBRARIES ${CORAL_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} ${Boost_LIBRARIES}
+#    CollectionBase FileCatalog PersistentDataModel )
+
+# atlas_add_executable( AtlListBSEvents test/AtlListBSEvents.cxx
+#    INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
+#    LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${Boost_LIBRARIES} )
+
+
+# Test(s) in the package:
+# atlas_add_test( BSEventSelector
+#    SCRIPT "athena.py FaserByteStreamCnvSvc/BSEventSelector_test_jobOptions.py"
+#    LOG_SELECT_PATTERN "ByteStream.*Svc" )
+
+# atlas_add_test( AtlCopyBSEvent1_test
+#    PRE_EXEC_SCRIPT "rm -f test.data"
+#    SCRIPT "AtlCopyBSEvent -e 186882810,187403142,187404922,187419528 -o test.data /cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_BSEventSelector_ctest )
+
+# atlas_add_test( AtlFindBSEvent2_test
+#    SCRIPT "AtlFindBSEvent -e 187403142 test.data"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_AtlCopyBSEvent1_test_ctest )
+
+# atlas_add_test( AtlCopyBSEvent3_test
+#    PRE_EXEC_SCRIPT "rm -f test_defl.data"
+#    SCRIPT "AtlCopyBSEvent -d -e 186882810,187403142,187419528 -o test_defl.data test.data"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_AtlCopyBSEvent1_test_ctest )
+
+# atlas_add_test( AtlFindBSEvent4_test
+#    SCRIPT "AtlFindBSEvent -e 187403142 test_defl.data"
+#    LOG_IGNORE_PATTERN "+Timestamp"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_AtlCopyBSEvent3_test_ctest )
+
+# atlas_add_test( AtlCopyBSEvent5_test
+#    PRE_EXEC_SCRIPT "rm -f test_infl.data"
+#    SCRIPT "AtlCopyBSEvent -e 186882810,187403142,187419528 -o test_infl.data test_defl.data"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_AtlCopyBSEvent3_test_ctest )
+
+# atlas_add_test( AtlCopyBSEvent6_test
+#    PRE_EXEC_SCRIPT "rm -f empty*.data && python ${CMAKE_CURRENT_SOURCE_DIR}/test/create_empty_bsfile.py"
+#    SCRIPT "AtlCopyBSEvent -e all -o empty.data empty._0001.data"
+#    PROPERTIES DEPENDS FaserByteStreamCnvSvc_AtlCopyBSEvent5_test_ctest )
+
+# atlas_add_test( FaserByteStreamConfigTest
+#    SCRIPT python -m FaserByteStreamCnvSvc.FaserByteStreamConfig
+#    POST_EXEC_SCRIPT nopost.sh )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
+atlas_install_joboptions( share/*.py )
+# atlas_install_scripts( share/catalogBytestreamFiles.sh )
diff --git a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamExceptions.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamExceptions.h
new file mode 100644
index 000000000..2a946c784
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamExceptions.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef BYTESTREAMCNVSVC_BYTESTREAMEXCEPTIONS_H
+#define BYTESTREAMCNVSVC_BYTESTREAMEXCEPTIONS_H
+
+/** @file ByteExceptions.h
+ *  $Id: ByteStreamInputSvc.h,v 1.51 2009-03-03 16:03:22 gemmeren Exp $
+ **/
+ 
+// EXCEPTIONS 
+namespace ByteStreamExceptions 
+{
+   class fileAccessError
+   {
+     virtual const char* what() const throw() {
+       return "Problem accessing file";
+     }
+   };  
+   class readError
+   { 
+     virtual const char* what() const throw() {
+       return "Problem during DataReader getData";
+     }
+   }; 
+   class badFragment
+   {
+     virtual const char* what() const throw() {
+       return "Unable to build RawEvent, fragment does not match known formats.";
+     }
+   }; 
+   class badFragmentData
+   {
+     virtual const char* what() const throw() {
+       return "RawEvent does not pass validation";
+     }
+   }; 
+} 
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
new file mode 100644
index 000000000..2d92e6523
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
@@ -0,0 +1,69 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef BYTESTREAMCNVSVC_BYTESTREAMINPUTSVC_H
+#define BYTESTREAMCNVSVC_BYTESTREAMINPUTSVC_H
+
+/** @file ByteStreamInputSvc.h
+ *  @brief This file contains the class definition for the ByteStreamInputSvc class.
+ *  @author Peter van Gemmeren <gemmeren@anl.gov>
+ *  $Id: ByteStreamInputSvc.h,v 1.51 2009-03-03 16:03:22 gemmeren Exp $
+ **/
+
+#include <exception>
+#include "AthenaBaseComps/AthService.h"
+#include "EventFormats/DAQFormats.hpp"
+
+//#include "ByteStreamData/RawEvent.h"
+//#include "ByteStreamCnvSvc/ByteStreamExceptions.h"
+
+
+/** @class ByteStreamInputSvc
+ *  @brief This class provides the base class to services to read bytestream data.
+ *  The concrete class can provide Raw event from a file, transient store, or through network.
+ **/
+class ByteStreamInputSvc : public ::AthService {
+ public:
+  /// constructor
+  ByteStreamInputSvc(const std::string& name, ISvcLocator* svcloc);
+  /// destructor
+  virtual ~ByteStreamInputSvc(void);
+
+  /// Retrieve interface ID
+  static const InterfaceID& interfaceID();
+
+  /// virtual method for advance to the next event
+  virtual const DAQFormats::EventFull* nextEvent() = 0;
+  virtual const DAQFormats::EventFull* previousEvent() = 0;
+  virtual void setEvent(void* /*data*/, unsigned int /*status*/) {}
+  /// virtual method for accessing the current event
+  virtual const DAQFormats::EventFull* currentEvent() const = 0;
+  /// virtual method for accessing the current event status
+  virtual unsigned int currentEventStatus() const;
+  virtual std::pair<long,std::string> getBlockIterator(const std::string /* file */);
+  virtual void closeBlockIterator(bool);
+  virtual bool ready() const;
+  virtual StatusCode generateDataHeader(); 
+  virtual long positionInBlock();
+  virtual void validateEvent();
+};
+
+inline const InterfaceID& ByteStreamInputSvc::interfaceID() {
+  /// Declaration of the interface ID ( interface id, major version, minor version)
+  static const InterfaceID IID_ByteStreamInputSvc("ByteStreamInputSvc", 1, 0);
+  return(IID_ByteStreamInputSvc);
+}
+
+inline unsigned int ByteStreamInputSvc::currentEventStatus() const {
+  return(0);
+}
+
+// Virtual methods needed for file input
+inline std::pair<long,std::string> ByteStreamInputSvc::getBlockIterator(const std::string /* file */) {return std::make_pair(-1,"GUID");}
+inline void ByteStreamInputSvc::closeBlockIterator(bool) {}
+inline bool ByteStreamInputSvc::ready() const {return false;}
+inline StatusCode ByteStreamInputSvc::generateDataHeader() {return StatusCode::SUCCESS;}
+inline long ByteStreamInputSvc::positionInBlock() {return -1;} 
+inline void ByteStreamInputSvc::validateEvent() {}
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
new file mode 100644
index 000000000..1258f3869
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVC_FASERBYTESTREAMCNVSVC_H
+#define FASERBYTESTREAMCNVSVC_FASERBYTESTREAMCNVSVC_H
+
+#include "ByteStreamCnvSvcBase/ByteStreamCnvSvcBase.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include <map>
+
+class ByteStreamOutputSvc;
+class FullEventAssemblerBase;
+
+/** @class FaserByteStreamCnvSvc
+    @brief Gaudi COnversion Service class for ByteStream Persistency
+
+    This class is responsible for converting data object to and from BS format
+    It inherits from ByteStreamCnvSvcBase, which is used by HLT in online.
+
+    When reading the ByteStream data, the ByteStream converters are called, which in turn call
+    IRODDataProviderSvc to retrieve the raw data.
+
+    When writing the object data to ByteStream, an FullEventFragment is assembled
+    from lower level fragments using FullEventAssembler, and writen out to BS in commitOutput
+    method through ByteStreamOutputSvc.
+*/
+
+class FaserByteStreamCnvSvc : public ByteStreamCnvSvcBase/*, virtual public IService*/ {
+
+public:
+   /// Standard Constructor
+   FaserByteStreamCnvSvc(const std::string& name, ISvcLocator* svc);
+
+   /// Standard Destructor
+   virtual ~FaserByteStreamCnvSvc();
+
+   /// Gaudi Service Interface method implementations:
+   virtual StatusCode initialize();
+   virtual StatusCode finalize();
+
+   /// Implements ConversionSvc's connectOutput
+   virtual StatusCode connectOutput(const std::string& t, const std::string& mode);
+   virtual StatusCode connectOutput(const std::string& t);
+
+   /// Implements ConversionSvc's commitOutput
+   virtual StatusCode commitOutput(const std::string& outputConnection, bool b);
+
+   /// @brief Access to FullEventAssembler
+   template <class T> StatusCode getFullEventAssembler(T*&t, std::string nm);
+
+private:
+   /// name of the service
+   std::string m_ioSvcName;
+
+   /// list of service names
+   Gaudi::Property<std::vector<std::string>> m_ioSvcNameList;
+
+   /// Services for writing output
+   std::map<std::string, ByteStreamOutputSvc*> m_ioSvcMap;
+
+   /// flags for Simulation EventType
+   Gaudi::Property<bool> m_isSimulation;
+   /// flags for TestBeam EventType
+   Gaudi::Property<bool> m_isTestbeam;
+   /// flags for Calibration EventType
+   Gaudi::Property<bool> m_isCalibration;
+   /// flags for getting Detector Mask from COOL
+   Gaudi::Property<bool> m_getDetectorMask;
+
+   /// Event store.
+   ServiceHandle<StoreGateSvc> m_evtStore;
+
+   /// user type
+   std::string m_userType;
+
+   /// @brief common FEA, indexed by string key
+   std::map<std::string, FullEventAssemblerBase*> m_feaMap;
+};
+
+// Implementation of template method:
+template <class T> StatusCode FaserByteStreamCnvSvc::getFullEventAssembler(T*& t, std::string nm) {
+   std::map<std::string, FullEventAssemblerBase*>::const_iterator it = m_feaMap.find(nm);
+   if (it != m_feaMap.end()) {
+      T* p = dynamic_cast<T*>((*it).second);
+      if (p == 0) {
+         ATH_MSG_WARNING(" Key = " << nm << " exists, but of different type");
+         return(StatusCode::FAILURE);
+      }
+      t = p;
+      return(StatusCode::SUCCESS);
+   }
+
+   // reach here if key does not exist
+   t = new T();
+   m_feaMap[nm] = t;
+   return(StatusCode::SUCCESS);
+}
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py b/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
new file mode 100644
index 000000000..027eb5973
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
@@ -0,0 +1,69 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+###############################################################
+#
+# module for reading EventStorage BS input file.
+#==============================================================
+
+from AthenaCommon import CfgMgr
+from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+from AthenaCommon.AppMgr import theApp
+
+# Load ByteStreamEventStorageInputSvc
+if not hasattr (svcMgr, 'ByteStreamInputSvc'):
+    svcMgr += CfgMgr.FaserByteStreamInputSvc ("ByteStreamInputSvc")
+
+# Load ROBDataProviderSvc
+if not hasattr (svcMgr, 'ROBDataProviderSvc'):
+    svcMgr += CfgMgr.ROBDataProviderSvc ("ROBDataProviderSvc")
+
+# Load EventSelectorByteStream
+if not hasattr (svcMgr, 'EventSelector'):
+    svcMgr += CfgMgr.FaserEventSelectorByteStream ("EventSelector")
+theApp.EvtSel = "EventSelector"
+
+from xAODEventInfoCnv.xAODEventInfoCnvConf import xAODMaker__EventInfoSelectorTool 
+xconv = xAODMaker__EventInfoSelectorTool()
+svcMgr.EventSelector.HelperTools += [xconv]
+
+# Load ByteStreamCnvSvc
+if not hasattr (svcMgr, 'ByteStreamCnvSvc'):
+    svcMgr += CfgMgr.FaserByteStreamCnvSvc ("ByteStreamCnvSvc")
+
+# Properties
+svcMgr.EventSelector.ByteStreamInputSvc = "ByteStreamInputSvc"
+
+svcMgr.EventPersistencySvc.CnvServices += [ "ByteStreamCnvSvc" ]
+
+# Load ProxyProviderSvc
+if not hasattr (svcMgr, 'ProxyProviderSvc'):
+    svcMgr += CfgMgr.ProxyProviderSvc()
+
+# Add in ByteStreamAddressProviderSvc
+#if not hasattr (svcMgr, 'ByteStreamAddressProviderSvc'):
+#    svcMgr += CfgMgr.ByteStreamAddressProviderSvc ("ByteStreamAddressProviderSvc")
+#svcMgr.ProxyProviderSvc.ProviderNames += [ "ByteStreamAddressProviderSvc" ]
+
+# Add in MetaDataSvc
+#if not hasattr (svcMgr, 'MetaDataSvc'):
+#    svcMgr += CfgMgr.MetaDataSvc ("MetaDataSvc")
+#svcMgr.ProxyProviderSvc.ProviderNames += [ "MetaDataSvc" ]
+
+# Add in MetaData Stores
+from StoreGate.StoreGateConf import StoreGateSvc
+#if not hasattr (svcMgr, 'InputMetaDataStore'):
+#    svcMgr += StoreGateSvc( "InputMetaDataStore" )
+#if not hasattr (svcMgr, 'MetaDataStore'):
+#    svcMgr += StoreGateSvc( "MetaDataStore" )
+
+# enable IOVDbSvc to read metadata
+#svcMgr.MetaDataSvc.MetaDataContainer = "MetaDataHdr"
+#svcMgr.MetaDataSvc.MetaDataTools += [ "IOVDbMetaDataTool" ]
+
+#if not hasattr (svcMgr.ToolSvc, 'IOVDbMetaDataTool'):
+#    svcMgr.ToolSvc += CfgMgr.IOVDbMetaDataTool()
+
+# Enable ByteStream to read MetaData
+#svcMgr.MetaDataSvc.MetaDataTools += [ "ByteStreamMetadataTool" ]
+#if not hasattr (svcMgr.ToolSvc, 'ByteStreamMetadataTool'):
+#    svcMgr.ToolSvc += CfgMgr.ByteStreamMetadataTool()
diff --git a/Event/FaserByteStreamCnvSvc/python/__init__.py b/Event/FaserByteStreamCnvSvc/python/__init__.py
new file mode 100644
index 000000000..74583d364
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/python/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/Event/FaserByteStreamCnvSvc/src/DumpFrags.h b/Event/FaserByteStreamCnvSvc/src/DumpFrags.h
new file mode 100644
index 000000000..af1553d68
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/DumpFrags.h
@@ -0,0 +1,111 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  -*-c++-*-
+*/
+
+/**
+   @class      DumpFrags
+   @brief      Dump header and payload fragments
+*/
+
+#ifndef BYTESTREAMCNVSVC_DUMPFRAGS
+#define BYTESTREAMCNVSVC_DUMPFRAGS
+
+#include <iostream> 
+#include "EventFormats/DAQFormats.hpp"
+#include "EventFormats/TLBDataFragment.hpp"
+#include "EventFormats/TLBMonitoringFragment.hpp"
+#include "EventFormats/DigitizerDataFragment.hpp"
+
+using namespace DAQFormats;
+
+class DumpFrags {
+
+  public:
+    DumpFrags() {} 
+
+  /// dump fragments from FullEventFragment
+static void dump(const EventFull* re)
+  {
+
+    std::cout << " ---EventFull run number = " 
+	      << re->run_number() << " event number = " << re->event_counter()
+	      << " Size = " << re->size() << std::endl;
+    
+    std::cout<<" Event id  "<<re->event_id()<<std::endl;
+    std::cout<<" Event tag  "<<re->event_tag()<< " [";
+    switch (re->event_tag()) {
+    case PhysicsTag:
+      std::cout << "Physics]" << std::endl;
+      break;
+    case CalibrationTag:
+      std::cout << "Calibration]" << std::endl;
+      break;
+    case MonitoringTag:
+      std::cout << "Monitoring]" << std::endl;
+      break;
+    case TLBMonitoringTag:
+      std::cout << "TLBMonitoring]" << std::endl;
+      break;
+    case CorruptedTag:
+      std::cout << "Corrupted]" << std::endl;
+      break;
+    case IncompleteTag:
+      std::cout << "Incomplete]" << std::endl;
+      break;
+    case DuplicateTag:
+      std::cout << "Duplicate]" << std::endl;
+      break;
+    default:
+      std::cout << "Unknown]" << std::endl;
+    }
+
+    std::cout<<" Status   "<<re->status()<<std::endl;
+    std::cout<<" Bunch crossing id   "<<re->bc_id()<<std::endl;
+    std::cout<<" Timestamp in microseconds  "<<re->timestamp()<<std::endl;
+    std::cout<<" Trigger bits   " << std::hex << re->trigger_bits()<<std::dec << std::endl;
+
+    for(const auto &id : re->getFragmentIDs()) {
+      const EventFragment* frag=re->find_fragment(id);
+      std::cout << *frag << std::endl;
+      
+      switch (frag->source_id()&0xFFFF0000) {
+      case TriggerSourceID:
+          if (re->event_tag() == PhysicsTag ) {
+	    TLBDataFragment tlb_data_frag = TLBDataFragment(frag->payload<const uint32_t*>(), frag->payload_size());
+	    std::cout<<"TLB data fragment:"<<std::endl;
+	    std::cout<<tlb_data_frag<<std::endl;
+	  }
+	  else if (re->event_tag() == TLBMonitoringTag ) {
+	    TLBMonitoringFragment tlb_mon_frag = TLBMonitoringFragment(frag->payload<const uint32_t*>(), frag->payload_size());
+	    std::cout<<"TLB monitoring fragment:"<<std::endl;
+	    std::cout<<tlb_mon_frag<<std::endl;
+	  }
+	
+	break;
+      case TrackerSourceID: //FIXME put in specific 
+      case PMTSourceID:
+	  if (re->event_tag() == PhysicsTag ) {
+	    DigitizerDataFragment digitizer_data_frag = DigitizerDataFragment(frag->payload<const uint32_t*>(), frag->payload_size());
+	    std::cout<<"Digitizer data fragment:"<<std::endl;
+	    std::cout<<digitizer_data_frag<<std::endl;
+	  }
+	break;
+      default:
+	const uint32_t* payload=frag->payload<const uint32_t *>();
+	unsigned int ii=0;
+	for(;ii<frag->payload_size()/4;ii++) {
+          if (ii%8==0) std::cout<<" ";
+          std::cout<<" 0x"<<std::setw(8)<<std::hex<<std::setfill('0')<<payload[ii];
+          if (ii%8==7) std::cout<<std::endl;
+	}
+	if (ii%8!=0) std::cout<<std::endl;
+	std::cout<<std::dec<<std::setfill(' ');
+	break;
+      }
+    }
+  }  
+};
+  
+#endif 
+
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
new file mode 100644
index 000000000..a8ec0f185
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
@@ -0,0 +1,284 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EventInfoByteStreamAuxCnv.h"
+#include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
+#include "FaserByteStreamCnvSvc/ByteStreamInputSvc.h"
+
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+
+/*
+#include "ByteStreamData/RawEvent.h"
+#include "ByteStreamData/ByteStreamMetadata.h"
+#include "ByteStreamData/ByteStreamMetadataContainer.h"
+*/
+
+#include "EventFormats/DAQFormats.hpp"
+
+#include "AthenaKernel/errorcheck.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/DataObject.h"
+#include "GaudiKernel/IRegistry.h"
+
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODEventInfo/EventAuxInfo.h"
+
+#include "StoreGate/StoreGateSvc.h"
+
+//#include "eformat/StreamTag.h"
+
+#include <time.h>
+
+using DAQFormats::EventFull;
+
+EventInfoByteStreamAuxCnv::EventInfoByteStreamAuxCnv(ISvcLocator* svcloc)
+  : Converter(storageType(), classID(), svcloc)
+  , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "EventInfoByteStreamAuxCnv")
+  , m_ByteStreamCnvSvc(nullptr)
+  , m_robDataProvider("ROBDataProviderSvc", "EventInfoByteStreamAuxCnv")
+    //  , m_mdSvc("InputMetaDataStore", "EventInfoByteStreamAuxCnv")
+  , m_isSimulation(false)
+  , m_isTestbeam(false)
+  , m_isCalibration(false)
+{
+}
+
+const CLID& EventInfoByteStreamAuxCnv::classID() 
+{
+  return ClassID_traits<xAOD::EventAuxInfo>::ID();
+}
+
+long EventInfoByteStreamAuxCnv::storageType() 
+{
+  return ByteStreamAddress::storageType();
+}
+
+StatusCode EventInfoByteStreamAuxCnv::initialize() 
+{
+  ATH_MSG_DEBUG("EventInfoByteStreamAuxCnv::Initialize");
+
+  CHECK(Converter::initialize());
+
+  // Check ByteStreamCnvSvc
+  IService* svc{nullptr};
+  StatusCode sc = serviceLocator()->getService("ByteStreamCnvSvc", svc);
+  if (!sc.isSuccess()) {
+    ATH_MSG_ERROR("Cannot get ByteStreamCnvSvc ");
+    return sc;
+  } else {
+    ATH_MSG_DEBUG("Located ByteStreamCnvSvc");
+  }
+
+  m_ByteStreamCnvSvc = dynamic_cast<FaserByteStreamCnvSvc*>(svc);
+  if (!m_ByteStreamCnvSvc) {
+    ATH_MSG_ERROR("Cannot cast to ByteStreamCnvSvc");
+    return StatusCode::FAILURE;
+  }
+
+  //CHECK(m_robDataProvider.retrieve());
+  //CHECK(m_mdSvc.retrieve());
+
+  SimpleProperty<bool> propIsSimulation("IsSimulation", m_isSimulation);
+  sc = m_ByteStreamCnvSvc->getProperty(&propIsSimulation);
+  if (sc.isSuccess()) {
+    m_isSimulation = propIsSimulation.value();
+    ATH_MSG_INFO("IsSimulation : " << m_isSimulation);
+  } 
+  else {
+    ATH_MSG_ERROR("Cannot get IsSimulation");
+    return sc;
+  }
+
+  SimpleProperty<bool> propIsTestbeam("IsTestbeam", m_isTestbeam);
+  sc = m_ByteStreamCnvSvc->getProperty(&propIsTestbeam);
+  if (sc.isSuccess()) {
+    m_isTestbeam = propIsTestbeam.value();
+    ATH_MSG_INFO("IsTestbeam : " << m_isTestbeam);
+  } 
+  else {
+    ATH_MSG_ERROR("Cannot get IsTestbeam");
+    return sc;
+  }
+
+  SimpleProperty<bool> propIsCalibration("IsCalibration", m_isCalibration);
+  sc = m_ByteStreamCnvSvc->getProperty(&propIsCalibration);
+  if (sc.isSuccess()) {
+    m_isCalibration = propIsCalibration.value();
+    ATH_MSG_INFO("IsCalibration : " << m_isCalibration);
+  } 
+  else {
+    ATH_MSG_ERROR("Cannot get IsCalibration");
+    return sc;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode EventInfoByteStreamAuxCnv::finalize() 
+{
+  ATH_MSG_DEBUG("Finalize");
+  
+  StatusCode sc = Converter::finalize();
+  if (sc.isFailure()) {
+    ATH_MSG_WARNING("Converter::finalize() failed");
+  }
+  return sc;
+}
+
+StatusCode EventInfoByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
+{
+
+  ATH_MSG_DEBUG("EventInfoByteStreamAuxCnv::createObj() called");
+
+  ByteStreamAddress *pRE_Addr{nullptr};
+  pRE_Addr = dynamic_cast<ByteStreamAddress*>(pAddr);
+  if (!pRE_Addr) {
+    ATH_MSG_ERROR("Cannot cast to ByteStreamAddress ");
+    return StatusCode::FAILURE;
+  }
+
+
+  // get RawEvent
+  const EventFull* re = reinterpret_cast<const EventFull*>(m_robDataProvider->getEvent());
+
+  if (!re) {
+    ATH_MSG_ERROR("Can not get RawEvent ");
+    return StatusCode::FAILURE;
+  }
+
+  // Run Number
+  int runNumber = re->run_number();
+
+  // Event Number
+  uint64_t eventNumber = re->event_id();
+  
+  // Time Stamp
+  uint32_t bc_time_sec = re->timestamp()/1E6;  // timestamp in usec
+  uint32_t bc_time_ns  = 1E9 * (re->timestamp() - 1E6 * bc_time_sec);
+  // bc_time_ns should be lt 1e9.
+  if (bc_time_ns > 1000000000) {
+      // For later runs, the nanosecond clock sometimes is not reset, making it overrun 1e9. Round it off to 1e9
+      ATH_MSG_WARNING("bc_time nanosecond number larger than 1e9, it is " << bc_time_ns << ", reset it to 1 sec");
+      bc_time_ns = 1000000000;
+  }
+
+  // luminosity block number
+  uint16_t lumiBlock = 0;
+
+  // bunch crossing identifier
+  uint16_t bcID = re->bc_id();
+
+  unsigned int detMask0 = 0xFFFFFFFF, detMask1 = 0xFFFFFFFF, detMask2 = 0xFFFFFFFF, detMask3 = 0xFFFFFFFF;
+
+  xAOD::EventInfo evtInfo;
+  xAOD::EventAuxInfo* pEvtInfoAux = new xAOD::EventAuxInfo();
+  evtInfo.setStore(pEvtInfoAux);
+
+  evtInfo.setRunNumber(runNumber);
+  evtInfo.setEventNumber(eventNumber);
+  evtInfo.setLumiBlock(lumiBlock);
+  evtInfo.setTimeStamp(bc_time_sec);
+  evtInfo.setTimeStampNSOffset(bc_time_ns);
+  evtInfo.setBCID(bcID);
+  evtInfo.setDetectorMask(detMask0,detMask1);
+  evtInfo.setDetectorMaskExt(detMask2,detMask3);
+
+  // The following values were implicitly set by the BS converter of the legacy EventInfo
+  // Setting them here too
+  evtInfo.setMCChannelNumber(0);
+  evtInfo.setMCEventNumber(0);
+  evtInfo.setMCEventWeights(std::vector<float>(1,1));
+
+  // Set Event Type
+  uint32_t eventTypeBitmask{0};
+  if (m_isSimulation) {
+    eventTypeBitmask |= xAOD::EventInfo::IS_SIMULATION;
+  }
+  if (m_isTestbeam) {
+    eventTypeBitmask |= xAOD::EventInfo::IS_TESTBEAM;
+  }
+  if (m_isCalibration) {
+    eventTypeBitmask |= xAOD::EventInfo::IS_CALIBRATION;
+  }
+  evtInfo.setEventTypeBitmask(eventTypeBitmask);
+
+  /*
+  // Trigger Info
+  const OFFLINE_FRAGMENTS_NAMESPACE::DataType* buffer;
+  // status element
+  re->status(buffer);
+  uint32_t statusElement = *buffer;
+
+  // extended LVL1ID
+  uint32_t extendedLevel1ID = re->lvl1_id();
+
+  // LVL1 trigger type
+  uint32_t level1TriggerType = re->lvl1_trigger_type();
+  */
+
+  // stream tag
+  /*
+  std::vector<xAOD::EventInfo::StreamTag> streamTags;
+  std::vector<eformat::helper::StreamTag> onl_streamTags;
+  re->stream_tag(buffer);
+  eformat::helper::decode(re->nstream_tag(), buffer, onl_streamTags);
+  for (const eformat::helper::StreamTag& onl_streamTag : onl_streamTags) {
+    std::set<uint32_t> tmp_off_dets = std::set<uint32_t>();
+    if (!onl_streamTag.dets.empty()) {
+      std::set<eformat::SubDetector> tmp_onl_dets = onl_streamTag.dets;
+      for (const eformat::SubDetector& subdet : tmp_onl_dets) {
+        tmp_off_dets.insert((uint32_t) subdet);
+      }
+    }
+    streamTags.push_back(xAOD::EventInfo::StreamTag(onl_streamTag.name
+						    , onl_streamTag.type
+						    , onl_streamTag.obeys_lumiblock
+						    , onl_streamTag.robs
+						    , tmp_off_dets)
+			 );
+  }
+
+  evtInfo.setStatusElement(statusElement);
+  evtInfo.setExtendedLevel1ID(extendedLevel1ID);
+  evtInfo.setLevel1TriggerType(level1TriggerType);
+  evtInfo.setStreamTags(streamTags);
+  */
+
+  // record EventInfo
+  evtInfo.setEventFlags(xAOD::EventInfo::Core, m_robDataProvider->getEventStatus());
+  pObj = StoreGateSvc::asStorable(pEvtInfoAux);
+
+  ATH_MSG_DEBUG(" New xAOD::EventAuxInfo made, run/event= " << runNumber 
+		<< " " << eventNumber
+		<< " Time stamp  = " << ascTime(bc_time_sec) 
+		);
+
+  return StatusCode::SUCCESS;
+    
+}
+
+StatusCode EventInfoByteStreamAuxCnv::createRep(DataObject* /*pObj*/, IOpaqueAddress*& /*pAddr*/) 
+{
+  ATH_MSG_DEBUG("Nothing to be done for xAOD::EventAuxInfo createReps");
+  return StatusCode::SUCCESS;
+}
+
+const char* EventInfoByteStreamAuxCnv::ascTime(unsigned int tstamp) 
+{
+  struct tm t;
+  t.tm_sec   = tstamp;
+  t.tm_min   = 0;
+  t.tm_hour  = 0;
+  t.tm_mday  = 0;
+  t.tm_mon   = 0;
+  t.tm_year  = 70;
+  t.tm_wday  = 00;
+  t.tm_yday  = 00;
+  t.tm_isdst = 0;
+  time_t ct = mktime(&t);
+  tm* t2 = gmtime(&ct);
+  return(asctime(t2));
+}
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
new file mode 100644
index 000000000..90fb3113e
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASEREVENTINFOBYTESTREAMAUXCNV_H
+#define FASEREVENTINFOBYTESTREAMAUXCNV_H
+
+/**
+ * @file EventInfoByteStreamAuxCnv.h
+ *
+ * @class EventInfoByteStreamAuxCnv
+ *
+ * @brief This is the class definition of ByteStream converter for xAOD::EventInfoAux
+ * Event Info is built from RawEvent when reading. Nothing is done when writing ByteStream
+ *
+ */ 
+
+#include "GaudiKernel/Converter.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "AthenaBaseComps/AthMessaging.h"
+
+class FaserByteStreamCnvSvc;
+class IROBDataProviderSvc;
+class StoreGateSvc;
+
+// Abstract factory to create the converter
+template <class TYPE> class CnvFactory;
+
+class EventInfoByteStreamAuxCnv : public Converter, public AthMessaging
+{
+ public:
+  EventInfoByteStreamAuxCnv(ISvcLocator* svcloc);
+  virtual ~EventInfoByteStreamAuxCnv() override {}
+  
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  
+  /// converter method to create object
+  virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj) override;
+  /// converter method to write object
+  virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr) override;
+
+  /// Storage type and class ID
+  virtual long repSvcType() const override { return i_repSvcType(); }
+  static long storageType();
+  static const CLID& classID();
+
+ private:
+  const char* ascTime(unsigned int t);    //!< convert timestamp to ascii time.
+  FaserByteStreamCnvSvc* m_ByteStreamCnvSvc;   //!< pointer to BS CnvSvc
+  ServiceHandle<IROBDataProviderSvc> m_robDataProvider; //!< RODDataProviderSvc handle
+  //ServiceHandle<StoreGateSvc> m_mdSvc;                  //!< TDS handle
+  
+  // flags for EventType
+  bool m_isSimulation;
+  bool m_isTestbeam;
+  bool m_isCalibration;
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
new file mode 100644
index 000000000..8fd407d8f
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EventInfoByteStreamxAODCnv.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+
+#include "AthenaKernel/errorcheck.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/DataObject.h"
+#include "GaudiKernel/IRegistry.h"
+
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODEventInfo/EventAuxInfo.h"
+
+#include "StoreGate/StoreGateSvc.h"
+
+EventInfoByteStreamxAODCnv::EventInfoByteStreamxAODCnv(ISvcLocator* svcloc)
+  : Converter(storageType(), classID(), svcloc)
+  , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "EventInfoByteStreamxAODCnv")
+{
+}
+
+const CLID& EventInfoByteStreamxAODCnv::classID() 
+{
+  return ClassID_traits<xAOD::EventInfo>::ID();
+}
+
+long EventInfoByteStreamxAODCnv::storageType() 
+{
+  return ByteStreamAddress::storageType();
+}
+
+StatusCode EventInfoByteStreamxAODCnv::initialize() 
+{
+  ATH_MSG_DEBUG("EventInfoByteStreamxAODCnv::Initialize");
+  CHECK(Converter::initialize());
+  return StatusCode::SUCCESS;
+}
+
+StatusCode EventInfoByteStreamxAODCnv::finalize() 
+{
+  ATH_MSG_DEBUG("EventInfoByteStreamxAODCnv::Finalize");
+  
+  StatusCode sc = Converter::finalize();
+  if (sc.isFailure()) {
+    ATH_MSG_WARNING("Converter::finalize() failed");
+  }
+  return sc;
+}
+
+StatusCode EventInfoByteStreamxAODCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
+{
+  ByteStreamAddress *pRE_Addr{nullptr};
+  pRE_Addr = dynamic_cast<ByteStreamAddress*>(pAddr);
+  if (!pRE_Addr) {
+    ATH_MSG_ERROR("Cannot cast to ByteStreamAddress ");
+    return StatusCode::FAILURE;
+  }
+               
+  ATH_MSG_DEBUG("EventInfoByteStreamxAODCnv::Creating Objects");
+
+  const std::string nm = *(pRE_Addr->par());
+  const std::string nmAux = nm + "Aux.";
+
+  xAOD::EventInfo* pEvtInfo = new xAOD::EventInfo();
+  DataLink<xAOD::EventAuxInfo> link(nmAux);
+  pEvtInfo->setStore(link);
+  pObj = StoreGateSvc::asStorable(pEvtInfo);
+
+  ATH_MSG_DEBUG(" New EventInfo made, run/event= " << pEvtInfo->runNumber() << " " << pEvtInfo->eventNumber());
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode EventInfoByteStreamxAODCnv::createRep(DataObject* /*pObj*/, IOpaqueAddress*& /*pAddr*/) 
+{
+  ATH_MSG_DEBUG("Nothing to be done for xAOD::EventInfo createReps");
+  return StatusCode::SUCCESS;
+}
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.h b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.h
new file mode 100644
index 000000000..a3ec402be
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.h
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASEREVENTINFOBYTESTREAMXAODCNV_H
+#define FASEREVENTINFOBYTESTREAMXAODCNV_H
+
+/**
+ * @file EventInfoByteStreamxAODCnv.h
+ *
+ * @class EventInfoByteStreamxAODCnv
+ *
+ * @brief This is the class definition of ByteStream converter for xAOD::EventInfo
+ * Event Info is built from RawEvent when reading. Nothing is done when writing ByteStream
+ *
+ */ 
+
+#include "GaudiKernel/Converter.h"
+#include "AthenaBaseComps/AthMessaging.h"
+
+// Abstract factory to create the converter
+template <class TYPE> class CnvFactory;
+
+class EventInfoByteStreamxAODCnv : public Converter, public AthMessaging
+{
+ public:
+  EventInfoByteStreamxAODCnv(ISvcLocator* svcloc);
+  virtual ~EventInfoByteStreamxAODCnv() override {}
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  
+  /// converter method to create object
+  virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj) override;
+  /// converter method to write object
+  virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr) override;
+
+  /// Storage type and class ID
+  virtual long repSvcType() const override { return i_repSvcType(); }
+  static long storageType();
+  static const CLID& classID();
+
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
new file mode 100644
index 000000000..437f0f4ca
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
@@ -0,0 +1,292 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
+//#include "ByteStreamCnvSvc/ByteStreamOutputSvc.h"
+#include "ByteStreamCnvSvcBase/FullEventAssembler.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+
+#include "StoreGate/StoreGate.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODTrigger/TrigDecision.h"
+
+//#include "eformat/SourceIdentifier.h"
+//#include "eformat/StreamTag.h"
+
+#include "AthenaKernel/IClassIDSvc.h"
+
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+
+#include <algorithm>
+
+/// Standard constructor
+FaserByteStreamCnvSvc::FaserByteStreamCnvSvc(const std::string& name, ISvcLocator* pSvcLocator)
+  : ByteStreamCnvSvcBase(name, pSvcLocator),
+    m_evtStore ("StoreGateSvc", name)
+{
+  declareProperty("ByteStreamOutputSvc",     m_ioSvcName);
+  declareProperty("ByteStreamOutputSvcList", m_ioSvcNameList);
+  declareProperty("IsSimulation",  m_isSimulation = false);
+  declareProperty("IsTestbeam",    m_isTestbeam   = false);
+  declareProperty("IsCalibration", m_isCalibration= false);
+  declareProperty("GetDetectorMask", m_getDetectorMask = false);
+  declareProperty("UserType",      m_userType     = "RawEvent");
+  declareProperty("EventStore",    m_evtStore);
+}
+
+/// Standard Destructor
+FaserByteStreamCnvSvc::~FaserByteStreamCnvSvc() {
+}
+
+/// Initialize the service.
+StatusCode FaserByteStreamCnvSvc::initialize() {
+   if (!ByteStreamCnvSvcBase::initialize().isSuccess()) {
+      ATH_MSG_FATAL("FaserByteStreamCnvSvcBase::initialize() failed");
+      return(StatusCode::FAILURE);
+   }
+
+   ATH_CHECK( m_evtStore.retrieve() );
+
+   // get ready for output
+   std::vector<std::string> ioSvcNames = m_ioSvcNameList.value();
+   if (!m_ioSvcName.empty()) {
+      // add ioSvcName if ioSvcNameList is missing it
+      std::vector<std::string>::iterator it = find(ioSvcNames.begin(), ioSvcNames.end(), m_ioSvcName);
+      if (it == ioSvcNames.end()) {
+         ioSvcNames.push_back(m_ioSvcName);
+      }
+   }
+   
+   if (ioSvcNames.size() != 0) {
+      // Check FaserByteStreamCnvSvc
+      for (std::vector<std::string>::iterator itSvc = ioSvcNames.begin(), itSvcE = ioSvcNames.end();
+	      itSvc != itSvcE; ++itSvc) {
+         ATH_MSG_DEBUG("get " << *itSvc);
+
+	 ATH_MSG_WARNING("not doing anything with" << *itSvc);
+	 /*
+         // get service
+         IService* svc;
+         if (!service(*itSvc, svc).isSuccess()) {
+            ATH_MSG_FATAL("Cannot get ByteStreamOutputSvc");
+            return(StatusCode::FAILURE);
+         }
+         ByteStreamOutputSvc* ioSvc = dynamic_cast<ByteStreamOutputSvc*>(svc);
+         if (ioSvc == 0) {
+            ATH_MSG_FATAL("Cannot cast to  ByteStreamOutputSvc");
+            return(StatusCode::FAILURE);
+         }
+         // get stream name
+         std::string bsOutputStreamName;
+         SimpleProperty<std::string> propBSO("BSOutputStreamName", bsOutputStreamName);
+         if (!ioSvc->getProperty(&propBSO).isSuccess()) {
+            ATH_MSG_FATAL("Cannot get BSOutputStreamName from " << *itSvc);
+            return(StatusCode::FAILURE);
+         }
+         bsOutputStreamName = propBSO.value();
+         // append
+         m_ioSvcMap[bsOutputStreamName] = ioSvc;
+	 */
+      }
+   }
+   return(StatusCode::SUCCESS);
+}
+
+StatusCode FaserByteStreamCnvSvc::finalize() {
+  return(ByteStreamCnvSvcBase::finalize());
+}
+
+StatusCode FaserByteStreamCnvSvc::connectOutput(const std::string& t, const std::string& /*mode*/) {
+   return(connectOutput(t));
+}
+
+StatusCode FaserByteStreamCnvSvc::connectOutput(const std::string& /*t*/) {
+   ATH_MSG_DEBUG("In connectOutput");
+
+   /*
+   // Get the EventInfo obj for run/event number
+   const xAOD::EventInfo* evtInfo{nullptr};
+   ATH_CHECK( m_evtStore->retrieve(evtInfo) );
+   uint64_t event = evtInfo->eventNumber();
+   uint32_t run_no = evtInfo->runNumber();
+   uint32_t bc_time_sec = evtInfo->timeStamp();
+   uint32_t bc_time_ns = evtInfo->timeStampNSOffset();
+   uint32_t run_type = 0;
+   uint32_t lvl1_id = evtInfo->extendedLevel1ID();
+   if (lvl1_id == 0) {
+      lvl1_id = event;
+   }
+   uint32_t lvl1_type = evtInfo->level1TriggerType();
+   uint64_t global_id = event;
+   uint16_t lumi_block = evtInfo->lumiBlock();
+   uint16_t bc_id = evtInfo->bcid();
+   static uint8_t nevt = 0;
+   nevt = nevt%255;
+   // create an empty RawEvent
+   eformat::helper::SourceIdentifier sid = eformat::helper::SourceIdentifier(eformat::FULL_SD_EVENT, nevt);
+   m_rawEventWrite = new RawEventWrite(sid.code(), bc_time_sec, bc_time_ns, global_id, run_type, run_no, lumi_block, lvl1_id, bc_id, lvl1_type);
+   */
+   return(StatusCode::SUCCESS);
+}
+
+StatusCode FaserByteStreamCnvSvc::commitOutput(const std::string& outputConnection, bool /*b*/) {
+   ATH_MSG_DEBUG("In flushOutput " << outputConnection);
+
+   if (m_ioSvcMap.size() == 0) {
+      ATH_MSG_ERROR("FaserByteStreamCnvSvc not configure for output");
+      return(StatusCode::FAILURE);
+   }
+   /*
+   writeFEA();
+
+   // Get EventInfo
+   const xAOD::EventInfo* evtInfo{nullptr};
+   ATH_CHECK( m_evtStore->retrieve(evtInfo) );
+
+   // Try to get TrigDecision
+   const xAOD::TrigDecision* trigDecision{nullptr};
+   if(m_evtStore->retrieve(trigDecision)!=StatusCode::SUCCESS) {
+     ATH_MSG_WARNING("Failed to retrieve xAOD::TrigDecision. Will write empty trigger decision vectors");
+     trigDecision = nullptr;
+   }
+
+   // change trigger info in Header
+   uint32_t *l1Buff{nullptr};
+   uint32_t *l2Buff{nullptr};
+   uint32_t *efBuff{nullptr};
+   uint32_t *encTag{nullptr};
+
+   m_rawEventWrite->lvl1_id(evtInfo->extendedLevel1ID());
+   m_rawEventWrite->lvl1_trigger_type((uint8_t)(evtInfo->level1TriggerType()));
+
+   // LVL1 info
+   uint32_t l1Size{0};
+   if(trigDecision) {
+     const std::vector<uint32_t>& tbp = trigDecision->tbp();
+     const std::vector<uint32_t>& tap = trigDecision->tap();
+     const std::vector<uint32_t>& tav = trigDecision->tav();
+     size_t l1TotSize = tbp.size()+tap.size()+tav.size();
+     if(l1TotSize>0) {
+       l1Buff = new uint32_t[l1TotSize];
+       for(uint32_t tb : tbp) {
+	 l1Buff[l1Size++] = tb;
+       }
+       for(uint32_t tb : tap) {
+	 l1Buff[l1Size++] = tb;
+       }
+       for(uint32_t tb : tav) {
+	 l1Buff[l1Size++] = tb;
+       }
+     }
+   }
+   m_rawEventWrite->lvl1_trigger_info(l1Size, l1Buff);
+
+   // LVL2 info
+   uint32_t l2Size{0};
+   if(trigDecision) {
+     const std::vector<uint32_t>& lvl2PP = trigDecision->lvl2PassedPhysics();
+     if(lvl2PP.size()>0) {
+       l2Buff = new uint32_t[lvl2PP.size()];
+       for(uint32_t tb : lvl2PP) {
+	 l2Buff[l2Size++] = tb;
+       }
+     }
+   }
+   m_rawEventWrite->lvl2_trigger_info(l2Size, l2Buff);
+
+   // EF info
+   uint32_t efSize{0};
+   if(trigDecision) {
+     const std::vector<uint32_t>& efPP = trigDecision->efPassedPhysics();
+     if(efPP.size()>0) {
+       efBuff = new uint32_t[efPP.size()];
+       for(uint32_t tb : efPP) {
+	 efBuff[efSize++] = tb;
+       }
+     }
+   }
+   m_rawEventWrite->event_filter_info(efSize, efBuff);
+
+   // stream tag
+   std::vector<eformat::helper::StreamTag> on_streamTags;
+   const std::vector<xAOD::EventInfo::StreamTag>& off_streamTags = evtInfo->streamTags();
+   for(const auto& sTag : off_streamTags) {
+     // convert offline -> online
+     eformat::helper::StreamTag tmpTag;
+     tmpTag.name = sTag.name();
+     tmpTag.type = sTag.type();
+     tmpTag.obeys_lumiblock = sTag.obeysLumiblock();
+     for(uint32_t rob : sTag.robs()) {
+       tmpTag.robs.insert(rob);
+     }
+     for(uint32_t det : sTag.dets()) {
+       tmpTag.dets.insert((eformat::SubDetector)det);
+     }
+     on_streamTags.push_back(tmpTag);
+   }
+   // encode
+   uint32_t encSize = eformat::helper::size_word(on_streamTags);
+   encTag = new uint32_t[encSize];
+   eformat::helper::encode(on_streamTags, encSize, encTag);
+   m_rawEventWrite->stream_tag(encSize, encTag);
+
+   // convert RawEventWrite to RawEvent
+   uint32_t rawSize = m_rawEventWrite->size_word();
+   OFFLINE_FRAGMENTS_NAMESPACE::DataType* buffer = new OFFLINE_FRAGMENTS_NAMESPACE::DataType[rawSize];
+   uint32_t count = eformat::write::copy(*(m_rawEventWrite->bind()), buffer, rawSize);
+   if (count != rawSize) {
+      ATH_MSG_ERROR("Memcopy failed");
+      return(StatusCode::FAILURE);
+   }
+   RawEvent rawEvent(buffer);
+   // check validity
+   try {
+      rawEvent.check_tree();
+   } catch (...) {
+      ATH_MSG_ERROR("commitOutput failed, because FullEventFragment invalid");
+      return(StatusCode::FAILURE);
+   }
+   ATH_MSG_DEBUG("commitOutput: Size of Event (words) = " << rawEvent.fragment_size_word());
+   // put event to OutputSvc
+   if ((m_ioSvcMap.size() == 1) or (m_ioSvcMap.count(outputConnection) > 0)) {
+      std::map<std::string, ByteStreamOutputSvc*>::iterator itSvc = m_ioSvcMap.find(outputConnection);
+      // for backward compatibility
+      if (itSvc == m_ioSvcMap.end()) {
+         itSvc = m_ioSvcMap.begin();
+      }
+      // put
+      if (!itSvc->second->putEvent(&rawEvent)) {
+         ATH_MSG_ERROR("commitOutput failed to send output");
+         return(StatusCode::FAILURE);
+      }
+   }
+   // delete
+   delete [] buffer; buffer = 0;
+   delete m_rawEventWrite; m_rawEventWrite = 0;
+   delete [] l1Buff; l1Buff = 0;
+   delete [] l2Buff; l2Buff = 0;
+   delete [] efBuff; efBuff = 0;
+   delete [] encTag; encTag = 0;
+   // delete FEA
+   for (std::map<std::string, FullEventAssemblerBase*>::const_iterator it = m_feaMap.begin(),
+	   itE = m_feaMap.end(); it != itE; it++) {
+      delete it->second;
+   }
+   m_feaMap.clear();
+
+*/
+   return(StatusCode::SUCCESS);
+}
+
+/*
+void FaserByteStreamCnvSvc::writeFEA() {
+   ATH_MSG_DEBUG("before FEAMAP size = " << m_feaMap.size());
+   for (std::map<std::string, FullEventAssemblerBase*>::const_iterator it = m_feaMap.begin(),
+	   itE = m_feaMap.end(); it != itE; it++) {
+      MsgStream log(msgSvc(), name());
+      (*it).second->fill(m_rawEventWrite, log);
+   }
+   ATH_MSG_DEBUG("after FEAMAP size = " << m_feaMap.size());
+}
+*/
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
new file mode 100644
index 000000000..593bd1891
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
@@ -0,0 +1,465 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserByteStreamInputSvc.h"
+#include "DumpFrags.h"
+
+#include "ByteStreamData/ByteStreamMetadataContainer.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+#include "FaserEventStorage/pickFaserDataReader.h"
+
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "GaudiKernel/Property.h"
+
+#include "PersistentDataModel/DataHeader.h"
+#include "PersistentDataModel/Token.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODEventInfo/EventAuxInfo.h"
+
+#include "EventFormats/DAQFormats.hpp"
+
+// Don't know what these do, comment for now
+// #include "eformat/HeaderMarker.h"
+// #include "eformat/SourceIdentifier.h"
+// #include "eformat/Issue.h"
+// #include "eformat/Problem.h"
+// #include "eformat/Version.h"
+// #include "eformat/Status.h"
+// #include "eformat/old/util.h"
+
+#include <cstdio>
+#include <string>
+#include <vector>
+#include <unistd.h>
+
+using DAQFormats::EventFull;
+
+// Constructor.
+FaserByteStreamInputSvc::FaserByteStreamInputSvc(
+       const std::string& name, ISvcLocator* svcloc) 
+  : ByteStreamInputSvc(name, svcloc)
+  , m_readerMutex()
+  , m_eventsCache()
+  , m_reader()
+  , m_evtOffsets()
+  , m_evtInFile(0)
+  , m_evtFileOffset(0)
+  , m_fileGUID("")
+  , m_storeGate    ("StoreGateSvc", name)
+    //, m_inputMetadata("StoreGateSvc/InputMetaDataStore", name)
+  , m_robProvider  ("ROBDataProviderSvc", name)
+  , m_sequential   (this, "EnableSequential",   false, "")
+  , m_dump         (this, "DumpFlag",           false, "Dump fragments")
+  , m_wait         (this, "WaitSecs",              0., "Seconds to wait if input is in wait state")
+  , m_valEvent     (this, "ValidateEvent",       true, "switch on check_tree when reading events")
+  , m_eventInfoKey (this, "EventInfoKey", "EventInfo", "Key of EventInfo in metadata store")
+
+{
+  assert(pSvcLocator != nullptr);
+
+  declareProperty("EventStore",    m_storeGate);
+  //declareProperty("MetaDataStore", m_inputMetadata);
+}
+//------------------------------------------------------------------------------
+FaserByteStreamInputSvc::~FaserByteStreamInputSvc() {  
+}
+//------------------------------------------------------------------------------
+StatusCode FaserByteStreamInputSvc::initialize() {
+   ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
+
+   ATH_CHECK(ByteStreamInputSvc::initialize());
+   //ATH_CHECK(m_inputMetadata.retrieve());
+   ATH_CHECK(m_storeGate.retrieve());
+   ATH_CHECK(m_robProvider.retrieve());
+
+   return(StatusCode::SUCCESS);
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamInputSvc::stop() {
+   ATH_MSG_DEBUG("Calling ByteStreamInputSvc::stop()");
+   // close moved to EventSelector for explicit coupling with incident
+   return(StatusCode::SUCCESS);
+}
+//------------------------------------------------------------------------------
+StatusCode FaserByteStreamInputSvc::finalize() {
+
+  ATH_CHECK(m_storeGate.release());
+  ATH_CHECK(m_robProvider.release()); 
+  //ATH_CHECK(m_inputMetadata.release());
+
+  return(ByteStreamInputSvc::finalize());
+}
+//------------------------------------------------------------------------------
+long FaserByteStreamInputSvc::positionInBlock()
+{
+  return m_evtOffsets.size();
+}
+
+const EventFull* FaserByteStreamInputSvc::previousEvent() {
+  ATH_MSG_WARNING("previousEvent called, but not implemented!");
+  return NULL;
+}
+//------------------------------------------------------------------------------
+// Read the next event.
+const EventFull* FaserByteStreamInputSvc::nextEvent() {
+
+  ATH_MSG_DEBUG("FaserByteStreamInputSvc::nextEvent() called");
+
+  std::lock_guard<std::mutex> lock( m_readerMutex );
+  const EventContext context{ Gaudi::Hive::currentContext() };
+
+  // Load event from file
+  EventFull* theEvent=0;
+
+  if (readerReady()) {
+
+    m_evtInFile ++; // increment iterator
+
+    if (m_evtInFile+1 > m_evtOffsets.size()) { 
+      // get current event position (cast to long long until native tdaq implementation)
+      ATH_MSG_DEBUG("nextEvent _above_ high water mark");
+      m_evtFileOffset = (long long)m_reader->getPosition();
+      m_evtOffsets.push_back(m_evtFileOffset);
+      m_reader->getData(theEvent);
+    }
+
+    else {
+      // Load from previous offset
+      ATH_MSG_DEBUG("nextEvent below high water mark");
+      m_evtFileOffset = m_evtOffsets.at( m_evtInFile-1 );
+      m_reader->getData( theEvent, m_evtFileOffset );
+    }
+
+    ATH_MSG_DEBUG("Read Event:\n" << *theEvent);
+  }
+  else {
+    ATH_MSG_ERROR("DataReader not ready. Need to getBlockIterator first");
+    return 0;
+  }
+
+  
+  EventCache* cache = m_eventsCache.get(context);
+
+  // initialize before building RawEvent
+  cache->releaseEvent(); 
+   
+  // Use buffer to build FullEventFragment
+  try {
+    buildEvent( cache,  theEvent, true );
+  }
+  catch (...) {
+    // rethrow any exceptions
+    throw;
+  }
+
+  if ( cache->rawEvent == NULL ) {
+    ATH_MSG_ERROR("Failure to build fragment");
+    return NULL;
+  }
+
+  // Set it for the data provider
+  ATH_MSG_DEBUG( "call robProvider->setNextEvent ");
+  m_robProvider->setNextEvent(context, reinterpret_cast<const RawEvent*>(cache->rawEvent.get()) );
+  m_robProvider->setEventStatus(context, cache->eventStatus );
+
+  // dump
+  if (m_dump) {
+    DumpFrags::dump(cache->rawEvent.get());
+  }
+
+  ATH_MSG_DEBUG( "switched to next event in slot " << context );
+  return( cache->rawEvent.get() );
+
+}
+
+void FaserByteStreamInputSvc::validateEvent() {
+  const EventContext& context{ Gaudi::Hive::currentContext() };
+  const EventFull* const event = m_eventsCache.get(context)->rawEvent.get();
+  m_eventsCache.get(context)->eventStatus = validateEvent( event );
+}
+
+unsigned FaserByteStreamInputSvc::validateEvent( const EventFull* const rawEvent ) const
+{
+  unsigned int status = 0;
+  if (m_valEvent) {
+    ATH_MSG_WARNING("validateEvent called, but not implemented");
+    ATH_MSG_INFO("event:\n" << *rawEvent);
+    /*
+    // check validity
+    std::vector<eformat::FragmentProblem> p;
+    rawEvent->problems(p);
+    if (!p.empty()) {
+      status += 0x01000000;
+      // bad event
+      ATH_MSG_WARNING("Failed to create FullEventFragment");
+      for (std::vector<eformat::FragmentProblem>::const_iterator i = p.begin(), iEnd = p.end();
+	        i != iEnd; i++) {
+        ATH_MSG_WARNING(eformat::helper::FragmentProblemDictionary.string(*i));
+      }
+      //      releaseCurrentEvent();
+      throw ByteStreamExceptions::badFragmentData();
+    }
+    if ( !ROBFragmentCheck( rawEvent ) ) {
+      status += 0x02000000;
+      // bad event
+      //      releaseCurrentEvent();
+      ATH_MSG_ERROR("Skipping bad event");
+      throw ByteStreamExceptions::badFragmentData();
+    }
+    */
+  } 
+  else {
+    ATH_MSG_DEBUG("Processing event without validating.");
+  }
+  return status;
+}
+
+void FaserByteStreamInputSvc::buildEvent(EventCache* cache, EventFull* theEvent, bool validate) const
+{
+  ATH_MSG_DEBUG("FaserByteStreamInputSvc::buildEvent() called");
+
+  if (validate) {
+    // Nothing to do
+  }
+
+  cache->eventStatus = 0;
+  //cache->rawEvent = std::make_unique<EventFull>();
+  cache->rawEvent.reset(theEvent);
+}
+
+//__________________________________________________________________________
+StatusCode FaserByteStreamInputSvc::generateDataHeader()
+{
+  ATH_MSG_DEBUG("FaserByteStreamInputSvc::generateDataHeader() called");
+
+  // get file GUID
+  m_fileGUID = m_reader->GUID();
+
+  // reader returns -1 when end of the file is reached
+  if (m_evtFileOffset != -1) {
+    ATH_MSG_DEBUG("ByteStream File GUID:" << m_fileGUID);
+    ATH_MSG_DEBUG("ByteStream Event Position in File: " << m_evtFileOffset);
+
+    // To accomodate for skipEvents option in EventSelector
+    // While skipping BS event Selector does not return SUCCESS code,
+    // just advances silently through events. So SG content is not refreshed
+    // Lets do refresh of the event header here
+    std::string key = "ByteStreamDataHeader";
+    ATH_CHECK(deleteEntry<DataHeader>(key));
+
+
+    // Created data header element with BS provenance information
+    std::unique_ptr<DataHeaderElement> dataHeaderElement = makeBSProvenance();
+    // Create data header itself
+    std::unique_ptr<DataHeader> dataHeader = std::make_unique<DataHeader>();
+    // Declare header primary
+    dataHeader->setStatus(DataHeader::Input);
+    //add the data header elenebt self reference to the object vector
+    dataHeader->insert(*std::move(dataHeaderElement));
+
+
+    // Clean up EventInfo from the previous event
+    key = m_eventInfoKey.value();
+    ATH_CHECK(deleteEntry<xAOD::EventInfo>(key));
+    // Now add ref to xAOD::EventInfo
+    std::unique_ptr<IOpaqueAddress> iopx = std::make_unique<ByteStreamAddress>(
+									       ClassID_traits<xAOD::EventInfo>::ID(), key, "");
+    ATH_CHECK(m_storeGate->recordAddress(key, iopx.release()));
+    const SG::DataProxy* ptmpx = m_storeGate->transientProxy(
+							     ClassID_traits<xAOD::EventInfo>::ID(), key);
+    if (ptmpx != nullptr) {
+      DataHeaderElement element(ptmpx, 0, key);
+      dataHeader->insert(element);
+    }
+
+    // Clean up auxiliary EventInfo from the previous event
+    key = m_eventInfoKey.value() + "Aux.";
+    ATH_CHECK(deleteEntry<xAOD::EventAuxInfo>(key));
+    // Now add ref to xAOD::EventAuxInfo
+    std::unique_ptr<IOpaqueAddress> iopaux = std::make_unique<ByteStreamAddress>(
+										 ClassID_traits<xAOD::EventAuxInfo>::ID(), key, "");
+    ATH_CHECK(m_storeGate->recordAddress(key, iopaux.release()));
+    const SG::DataProxy* ptmpaux = m_storeGate->transientProxy(
+							       ClassID_traits<xAOD::EventAuxInfo>::ID(), key);
+    if (ptmpaux !=0) {
+      DataHeaderElement element(ptmpaux, 0, key);
+      dataHeader->insert(element);
+    }
+
+    // Record new data header.Boolean flags will allow it's deletionin case
+    // of skipped events.
+    ATH_CHECK(m_storeGate->record<DataHeader>(dataHeader.release(),
+					      "ByteStreamDataHeader", true, false, true));
+  }
+  return StatusCode::SUCCESS;
+}
+
+/******************************************************************************/
+void
+FaserByteStreamInputSvc::EventCache::releaseEvent()
+{
+  // cleanup parts of previous event and re-init them
+  if(rawEvent) {
+    rawEvent.reset(nullptr);
+    eventStatus = 0;
+  }
+}
+
+/******************************************************************************/
+FaserByteStreamInputSvc::EventCache::~EventCache()
+{
+  releaseEvent();
+}
+
+
+
+/******************************************************************************/
+void
+FaserByteStreamInputSvc::closeBlockIterator(bool clearMetadata)
+{
+  if (clearMetadata) {
+    ATH_MSG_WARNING("Clearing input metadata store");
+    // StatusCode status = m_inputMetadata->clearStore();
+    // if (!status.isSuccess()) {
+    //   ATH_MSG_WARNING("Unable to clear Input MetaData Proxies");
+    // }
+  }
+
+  if (!readerReady()) {
+    ATH_MSG_INFO("No more events in this run, high water mark for this file = "
+		 << m_evtOffsets.size()-1);
+  }
+
+  m_reader.reset();
+}
+
+
+/******************************************************************************/
+bool
+FaserByteStreamInputSvc::setSequentialRead()
+{
+  // enable SequenceReading
+  m_reader->enableSequenceReading();
+  return true;
+}
+
+/******************************************************************************/
+bool
+FaserByteStreamInputSvc::ready() const
+{
+  return readerReady();
+}
+
+
+/******************************************************************************/
+std::pair<long,std::string>
+FaserByteStreamInputSvc::getBlockIterator(const std::string fileName)
+{
+  // open the file
+  if(m_reader != 0) closeBlockIterator();
+
+  m_reader = std::unique_ptr<FaserEventStorage::DataReader>(pickFaserDataReader(fileName));
+
+  if(m_reader == nullptr) {
+    ATH_MSG_ERROR("Failed to open file " << fileName);
+    closeBlockIterator();
+    return std::make_pair(-1,"END"); 
+  }
+
+  // Initilaize offset vector
+  m_evtOffsets.resize(m_reader->eventsInFile(), -1);
+  m_evtOffsets.clear();
+
+  m_evtInFile = 0;
+
+  // enable sequentialReading if multiple files
+  if(m_sequential) {
+    bool test = setSequentialRead();
+    if (!test) return std::make_pair(-1,"SEQ");
+  }
+
+  ATH_MSG_INFO("Picked valid file: " << m_reader->fileName());
+  // initialize offsets and counters
+  m_evtOffsets.push_back(static_cast<long long>(m_reader->getPosition()));
+  return std::make_pair(m_reader->eventsInFile(), m_reader->GUID());
+}
+
+
+//__________________________________________________________________________
+bool FaserByteStreamInputSvc::readerReady() const
+{
+  bool eofFlag(false);
+  if (m_reader!=0) eofFlag = m_reader->endOfFile();
+  else {
+    ATH_MSG_INFO("eformat reader object not initialized");
+    return false;
+  }
+  bool moreEvent = m_reader->good();
+  
+  return (!eofFlag)&&moreEvent;
+}
+//__________________________________________________________________________
+void FaserByteStreamInputSvc::setEvent(void* data, unsigned int eventStatus) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setEvent( context, data, eventStatus );
+}
+
+void FaserByteStreamInputSvc::setEvent( const EventContext& context, void* data, unsigned int eventStatus )
+{
+  ATH_MSG_DEBUG("FaserByteStreamInputSvc::setEvent() called");
+
+  EventCache* cache = m_eventsCache.get( context );
+  cache->releaseEvent();
+
+  EventFull* event = reinterpret_cast<EventFull*>(data);
+  cache->rawEvent.reset(event);
+  cache->eventStatus = eventStatus;
+
+  // Set it for the data provider
+  m_robProvider->setNextEvent(context, reinterpret_cast<const RawEvent*>(cache->rawEvent.get()) );
+  m_robProvider->setEventStatus(context, cache->eventStatus );
+
+  // Build a DH for use by other components
+  StatusCode rec_sg = generateDataHeader();
+  if (rec_sg != StatusCode::SUCCESS) {
+    ATH_MSG_ERROR("Fail to record BS DataHeader in StoreGate. Skipping events?! " << rec_sg);
+  }
+}
+//__________________________________________________________________________
+const EventFull* FaserByteStreamInputSvc::currentEvent() const {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return m_eventsCache.get(context)->rawEvent.get();
+}
+//__________________________________________________________________________
+unsigned int FaserByteStreamInputSvc::currentEventStatus() const {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return m_eventsCache.get(context)->eventStatus;
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamInputSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+   if (ByteStreamInputSvc::interfaceID().versionMatch(riid)) {
+      *ppvInterface = dynamic_cast<ByteStreamInputSvc*>(this);
+   } else {
+     // Interface is not directly available: try out a base class
+     return(::AthService::queryInterface(riid, ppvInterface));
+   }
+   addRef();
+   return(StatusCode::SUCCESS);
+}
+
+
+std::unique_ptr<DataHeaderElement>
+FaserByteStreamInputSvc::makeBSProvenance() const
+{
+  std::unique_ptr<Token> token = std::make_unique<Token>();
+  token->setDb(m_fileGUID);
+  token->setTechnology(0x00001000);
+  token->setOid(Token::OID_t(0LL, m_evtFileOffset));
+
+  // note: passing ownership of token to DataHeaderElement
+  return std::make_unique<DataHeaderElement>(ClassID_traits<DataHeader>::ID(),
+					     "StreamRAW", token.release());
+}
+
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h
new file mode 100644
index 000000000..00efecd0a
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h
@@ -0,0 +1,135 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMINPUTSVC_H
+#define FASERBYTESTREAMINPUTSVC_H
+
+/** @file FaserByteStreaInputSvc.h
+ *  @brief This file contains the class definition for the FaserByteStreamInputSvc class.
+ *  @author Eric Torrence <torrence@uoregon.edu>
+ **/
+
+// Originally copied from ByteStreamEventStorageInputSvc
+
+// Include files.
+#include "FaserByteStreamCnvSvc/ByteStreamInputSvc.h"
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "AthenaKernel/SlotSpecificObj.h"
+#include "FaserEventStorage/DataReader.h"
+
+// Do I want to try to update this?  It looks like it is only used
+// here and in the detector-specific code.  Lets try without it.
+//#include "ByteStreamData/RawEvent.h"
+
+// FrameWork includes
+#include "GaudiKernel/ServiceHandle.h"
+
+//#include "EventFormats/DAQFormats.hpp"
+
+//typedef DAQFormats::EventFull RawEvent;
+namespace DAQFormats {
+  class EventFull;
+}
+class StoreGateSvc;
+class DataHeaderElement;
+
+/** @class ByteStreamFaserInputSvc
+ *  @brief This class is the ByteStreamInputSvc for reading events written by Faser.
+ **/
+class FaserByteStreamInputSvc : public ByteStreamInputSvc {
+
+public:
+   /// Constructors:
+   FaserByteStreamInputSvc(const std::string& name, ISvcLocator* svcloc);
+
+   /// Destructor.
+   virtual ~FaserByteStreamInputSvc();
+
+   /// Required of all Gaudi Services
+   virtual StatusCode initialize();
+   virtual StatusCode stop();
+   /// Required of all Gaudi Services
+   virtual StatusCode finalize();
+
+   /// Required of all Gaudi services:  see Gaudi documentation for details
+   StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
+
+   /// Implementation of the ByteStreamInputSvc interface methods.
+   virtual const DAQFormats::EventFull* currentEvent() const;
+   virtual const DAQFormats::EventFull* nextEvent();            //!< ++, new
+   virtual const DAQFormats::EventFull* previousEvent();        //!< --, old
+   virtual       void setEvent(void* data, unsigned int eventStatus);
+
+   /// Return the current event status
+   virtual unsigned int currentEventStatus() const;
+   virtual void validateEvent(); 
+
+
+   virtual long positionInBlock();
+   virtual std::pair<long,std::string> getBlockIterator(const std::string fileName);
+   void         closeBlockIterator(bool clearMetadata=true);
+   bool         setSequentialRead();
+   bool         ready() const;
+   StatusCode   generateDataHeader();
+
+private: // data
+   std::mutex m_readerMutex;
+
+   struct EventCache {
+     std::unique_ptr<DAQFormats::EventFull> rawEvent = NULL;
+     //DAQFormats::EventFull*          rawEvent = 0;            //!< current event
+     unsigned int       eventStatus = 0;   //!< check_tree() status of the current event
+     long long int      eventOffset = 0;   //!< event offset within a file, can be -1          
+     void               releaseEvent(); //!< deletes event
+     virtual            ~EventCache();  //!< calls releaseEvent
+   };
+
+   SG::SlotSpecificObj<EventCache> m_eventsCache;
+   std::unique_ptr<FaserEventStorage::DataReader>  m_reader; //!< DataReader from EventStorage
+
+   mutable std::vector<long long int> m_evtOffsets;  //!< offset for event i in that file
+   unsigned int                 m_evtInFile;
+   long long int      m_evtFileOffset = 0;   //!< last read in event offset within a file, can be -1     
+   // Event back navigation info
+   std::string        m_fileGUID;      //!< current file GUID
+
+
+private: // properties
+   ServiceHandle<StoreGateSvc>                m_storeGate;     //!< StoreGateSvc
+   //ServiceHandle<StoreGateSvc>                m_inputMetadata; //!< StoreGateSvc
+   ServiceHandle<IROBDataProviderSvc>         m_robProvider;
+
+
+   Gaudi::Property<bool>                      m_sequential;    //!< enable sequential reading.
+   Gaudi::Property<bool>                      m_dump;
+   Gaudi::Property<float>                     m_wait;
+   Gaudi::Property<bool>                      m_valEvent;
+   Gaudi::Property<std::string>               m_eventInfoKey;
+
+private: // internal helper functions
+
+   // void buildFragment( EventCache* cache, void* data, uint32_t eventSize, bool validate ) const;
+   void buildEvent( EventCache* cache, DAQFormats::EventFull* theEvent, bool validate ) const;
+   bool readerReady() const;
+   unsigned validateEvent( const DAQFormats::EventFull* rawEvent ) const;
+   void setEvent( const EventContext& context, void* data, unsigned int eventStatus );
+   
+   enum Advance{ PREVIOUS = -1, NEXT = 1 };
+   const DAQFormats::EventFull* getEvent( Advance step );
+   std::unique_ptr<DataHeaderElement> makeBSProvenance() const;
+
+
+   template<typename T>
+     StatusCode deleteEntry(const std::string& key)
+     {
+       if (m_storeGate->contains<T>(key)) {
+	 const T* tmp = m_storeGate->tryConstRetrieve<T>(key);
+	 if (tmp != nullptr) ATH_CHECK(m_storeGate->remove<T>(tmp));
+       }
+       return StatusCode::SUCCESS;
+     }
+
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.cxx b/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.cxx
new file mode 100644
index 000000000..f7d24aa9d
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.cxx
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** @file FaserEventContextByteStream.cxx
+ *  @brief This file contains the implementation for the FaserEventContextByteStream class.
+ *  @author Peter van Gemmeren <gemmeren@bnl.gov>
+ *  @author Hong Ma <hma@bnl.gov>
+ **/
+
+#include "FaserEventContextByteStream.h"
+
+//________________________________________________________________________________
+FaserEventContextByteStream::FaserEventContextByteStream(const IEvtSelector* selector) : m_evtSelector(selector) {
+}
+//________________________________________________________________________________
+FaserEventContextByteStream::FaserEventContextByteStream(const FaserEventContextByteStream& ctxt) : IEvtSelector::Context(),
+										     m_evtSelector(ctxt.m_evtSelector) {
+}
+//________________________________________________________________________________
+FaserEventContextByteStream::~FaserEventContextByteStream() {
+}
+//________________________________________________________________________________
+void* FaserEventContextByteStream::identifier() const {
+  return((void*)(m_evtSelector));
+}
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.h b/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.h
new file mode 100644
index 000000000..7e277a1bc
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventContextByteStream.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EVENTCONTEXTBYTESTREAM_H
+#define EVENTCONTEXTBYTESTREAM_H
+
+/** @file EventContextByteStream.h
+ *  @brief This file contains the class definition for the EventContextByteStream class.
+ *  @author Hong Ma <hma@bnl.gov>
+ **/
+
+#include "GaudiKernel/IEvtSelector.h"
+
+class FaserEventSelectorByteStream;
+class IOpaqueAddress;
+
+/** @class FaserEventContextByteStream
+ *  @brief This class provides the Context for EventSelectorByteStream
+ **/
+class FaserEventContextByteStream : virtual public IEvtSelector::Context {
+
+ public:
+  /// Constructor
+  FaserEventContextByteStream(const IEvtSelector* selector);
+  /// Copy constructor
+  FaserEventContextByteStream(const FaserEventContextByteStream& ctxt);
+  /// Destructor
+  virtual ~FaserEventContextByteStream();
+
+  /// Inequality operator.
+  virtual void* identifier() const;
+
+ private:
+  const IEvtSelector* m_evtSelector;
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
new file mode 100644
index 000000000..6311fc550
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
@@ -0,0 +1,1041 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//====================================================================
+// FaserEventSelectorByteStream.cxx
+//====================================================================
+//
+// Include files.
+#include "FaserEventSelectorByteStream.h"
+#include "FaserEventContextByteStream.h"
+#include "FaserByteStreamInputSvc.h"
+#include "FaserByteStreamCnvSvc/ByteStreamExceptions.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+
+#include "GaudiKernel/ClassID.h"
+#include "GaudiKernel/FileIncident.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/IIoComponentMgr.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+
+#include "AthenaKernel/IAthenaIPCTool.h"
+#include "EventInfo/EventInfo.h"
+#include "StoreGate/StoreGate.h"
+
+// EventInfoAttributeList includes
+#include "AthenaPoolUtilities/AthenaAttributeList.h"
+#include "EventInfo/TriggerInfo.h"
+#include "PersistentDataModel/DataHeader.h"
+#include "eformat/StreamTag.h"
+
+#include <vector>
+#include <algorithm>
+
+using DAQFormats::EventFull;
+
+// Constructor.
+FaserEventSelectorByteStream::FaserEventSelectorByteStream(const std::string& name, ISvcLocator* svcloc) : ::AthService(name, svcloc),
+												 m_fileCount(0),
+												 m_beginIter(0),
+												 m_endIter(0),
+												 m_eventSource(0),
+												 m_incidentSvc("IncidentSvc", name),
+  m_evtStore( "StoreGateSvc", name ),
+  m_firstFileFired(false),
+  m_beginFileFired(false),
+												 m_inputCollectionsFromIS(false),
+  m_NumEvents(0),
+  m_eventStreamingTool("", this),
+												 m_helperTools(this),
+  m_counterTool("", this) {
+  declareProperty("ByteStreamInputSvc",  m_eventSourceName);
+  declareProperty("Input",               m_inputCollectionsProp);
+  declareProperty("MaxBadEvents",        m_maxBadEvts = -1);
+  declareProperty("ProcessBadEvent",     m_procBadEvent = false);
+  declareProperty("SkipEvents",          m_SkipEvents = 0);
+  declareProperty("SkipEventSequence",   m_skipEventSequenceProp);
+
+  declareProperty("HelperTools",         m_helperTools);
+  declareProperty("CounterTool",         m_counterTool);
+  declareProperty("SharedMemoryTool",    m_eventStreamingTool);
+
+  // RunNumber, OldRunNumber and OverrideRunNumberFromInput are used
+  // to override the run number coming in on the input stream
+  declareProperty("RunNumber",           m_runNo = 0);
+  m_runNo.verifier().setLower(0);
+  // The following properties are only for compatibility with
+  // McEventSelector and are not really used anywhere
+  declareProperty("EventsPerRun",        m_eventsPerRun = 1000000);
+  m_eventsPerRun.verifier().setLower(0);
+  declareProperty("FirstEvent",          m_firstEventNo = 0);
+  m_firstEventNo.verifier().setLower(0);
+  declareProperty("FirstLB",             m_firstLBNo = 0);
+  m_firstLBNo.verifier().setLower(0);
+  declareProperty("EventsPerLB",         m_eventsPerLB = 1000);
+  m_eventsPerLB.verifier().setLower(0);
+  declareProperty("InitialTimeStamp",    m_initTimeStamp = 0);
+  m_initTimeStamp.verifier().setLower(0);
+  declareProperty("TimeStampInterval",   m_timeStampInterval = 0);
+  declareProperty("OverrideRunNumber",   m_overrideRunNumber = false);
+  declareProperty("OverrideEventNumber", m_overrideEventNumber = false);
+  declareProperty("OverrideTimeStamp",   m_overrideTimeStamp = false);
+  declareProperty("FileBased", m_filebased = true);
+
+  m_inputCollectionsProp.declareUpdateHandler(&FaserEventSelectorByteStream::inputCollectionsHandler, this);
+}
+//________________________________________________________________________________
+void FaserEventSelectorByteStream::inputCollectionsHandler(Property&) {
+  if (this->FSMState() != Gaudi::StateMachine::OFFLINE) {
+    this->reinit().ignore();
+  }
+}
+//________________________________________________________________________________
+FaserEventSelectorByteStream::~FaserEventSelectorByteStream() {
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::initialize() {
+  ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
+  if (!::AthService::initialize().isSuccess()) {
+    ATH_MSG_FATAL("Cannot initialize AthService base class.");
+    return(StatusCode::FAILURE);
+  }
+
+  // Check for input setting
+  if (m_filebased && m_inputCollectionsProp.value().size() == 0) {
+    ATH_MSG_WARNING("InputCollections not properly set, checking EventStorageInputSvc properties");
+    ServiceHandle<IJobOptionsSvc> joSvc("JobOptionsSvc", name());
+    bool retrieve(false);
+    if (!joSvc.retrieve().isSuccess()) {
+      ATH_MSG_FATAL("Cannot get JobOptionsSvc.");
+    } else {
+      // Check if FullFileName is set in the InputSvc
+      typedef std::vector<const Property*> Properties_t;
+      const Properties_t* esProps = joSvc->getProperties("ByteStreamInputSvc");
+      std::vector<const Property*>::const_iterator ii = esProps->begin();
+      if (esProps != 0) {
+	while (ii != esProps->end()) {
+	  if ((*ii)->name() == "FullFileName") {
+	    StringArrayProperty temp;
+	    if ((*ii)->load(temp)) {
+	      retrieve = true;
+	      m_inputCollectionsProp.assign(temp);
+	      m_inputCollectionsFromIS = true;
+	      ATH_MSG_INFO("Retrieved InputCollections from InputSvc");
+	    }
+	  }
+	  if ((*ii)->name() == "EventStore") {
+	    StringProperty temp2;
+	    if ((*ii)->load(temp2)) {
+	      m_evtStore = ServiceHandle<StoreGateSvc>(temp2.value(),this->name());
+	      ATH_MSG_INFO("Retrieved StoreGateSvc name of " << temp2);
+	    }
+	  }
+	  ++ii;
+	}
+      } else {
+	ATH_MSG_WARNING("Did not find InputSvc jobOptions properties");
+      }
+    }
+    if (!retrieve) {
+      ATH_MSG_FATAL("Unable to retrieve valid input list");
+      return(StatusCode::FAILURE);
+    }
+  }
+  m_skipEventSequence = m_skipEventSequenceProp.value();
+  std::sort(m_skipEventSequence.begin(), m_skipEventSequence.end());
+
+  // Check ByteStreamCnvSvc
+  IService* svc;
+  if (!serviceLocator()->getService(m_eventSourceName, svc).isSuccess()) {
+    ATH_MSG_FATAL("Cannot get ByteStreamInputSvc");
+    return(StatusCode::FAILURE);
+  }
+  m_eventSource = dynamic_cast<FaserByteStreamInputSvc*>(svc);
+  if (m_eventSource == 0) {
+    ATH_MSG_FATAL("Cannot cast ByteStreamInputSvc");
+    return(StatusCode::FAILURE);
+  }
+  m_eventSource->addRef();
+  if (!m_evtStore.retrieve().isSuccess()) {
+    ATH_MSG_FATAL("Cannot get StoreGateSvc");
+    return(StatusCode::FAILURE);
+  }
+
+  // Get CounterTool (if configured)
+  if (!m_counterTool.empty()) {
+    if (!m_counterTool.retrieve().isSuccess()) {
+      ATH_MSG_FATAL("Cannot get CounterTool.");
+      return(StatusCode::FAILURE);
+    }
+  }
+  // Get HelperTools
+  if (!m_helperTools.empty()) {
+    if (!m_helperTools.retrieve().isSuccess()) {
+      ATH_MSG_FATAL("Cannot get " << m_helperTools);
+      return(StatusCode::FAILURE);
+    }
+  }
+  // Get SharedMemoryTool (if configured)
+  if (!m_eventStreamingTool.empty() && !m_eventStreamingTool.retrieve().isSuccess()) {
+    ATH_MSG_FATAL("Cannot get AthenaSharedMemoryTool");
+    return(StatusCode::FAILURE);
+  }
+
+  // Register this service for 'I/O' events
+  ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
+  if (!iomgr.retrieve().isSuccess()) {
+    ATH_MSG_FATAL("Cannot retrieve IoComponentMgr.");
+    return(StatusCode::FAILURE);
+  }
+  if (!iomgr->io_register(this).isSuccess()) {
+    ATH_MSG_FATAL("Cannot register myself with the IoComponentMgr.");
+    return(StatusCode::FAILURE);
+  }
+
+  // Register the input files with the iomgr
+  bool allGood = true;
+  const std::vector<std::string>& incol = m_inputCollectionsProp.value();
+  for (std::size_t icol = 0, imax = incol.size(); icol != imax; ++icol) {
+    if (!iomgr->io_register(this, IIoComponentMgr::IoMode::READ, incol[icol]).isSuccess()) {
+      ATH_MSG_FATAL("could not register [" << incol[icol] << "] for output !");
+      allGood = false;
+    } else {
+      ATH_MSG_VERBOSE("io_register[" << this->name() << "](" << incol[icol] << ") [ok]");
+    }
+  }
+  if (!allGood) {
+    return(StatusCode::FAILURE);
+  }
+
+  // For backward compatibility, check InputSvc properties for bad events
+  ServiceHandle<IJobOptionsSvc> joSvc("JobOptionsSvc", name());
+  if (!joSvc.retrieve().isSuccess()) {
+    ATH_MSG_FATAL("Cannot get JobOptionsSvc.");
+    return(StatusCode::FAILURE);
+  }
+  typedef std::vector<const Property*> Properties_t;
+  const Properties_t* esProps = joSvc->getProperties("ByteStreamInputSvc");
+  if (esProps != 0) {
+    std::vector<const Property*>::const_iterator ii = esProps->begin();
+    while (ii != esProps->end()) {
+      IntegerProperty temp;
+      if ((*ii)->name() == "MaxBadEvents") {     // find it
+	if ((*ii)->load(temp)) {                // load it
+	  if (temp.value() != -1) {            // check if it is set
+	    m_maxBadEvts = temp.value();
+	    ATH_MSG_INFO("Retrieved MaxBadEvents=" << m_maxBadEvts << " from ByteStreamInputSvc");
+	  }
+	}
+      }
+      BooleanProperty temp2;
+      if ((*ii)->name() == "ProcessBadEvents") {     // find it
+	if ((*ii)->load(temp)) {                // load it
+	  if (temp.value()) {            // check if it is set
+	    m_procBadEvent = temp.value();
+	    ATH_MSG_INFO("Retrieved ProcessBadEvents=" << m_procBadEvent << " from ByteStreamInputSvc");
+	  }
+	}
+      }
+      ++ii;
+    }
+  } else {
+    ATH_MSG_WARNING("Did not find ByteStreamInputSvc jobOptions properties");
+  }
+   
+  // Must happen before trying to open a file
+  StatusCode risc = this->reinit();
+
+  return risc;
+}
+//__________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::reinit() {
+  ATH_MSG_INFO("reinitialization...");
+  // reset markers
+  if (m_inputCollectionsProp.value().size()>0) {
+    m_numEvt.resize(m_inputCollectionsProp.value().size(), -1);
+    m_firstEvt.resize(m_inputCollectionsProp.value().size(), -1);
+  }
+  else {
+    m_numEvt.resize(1);
+    m_firstEvt.resize(1);
+  }
+
+  // Initialize InputCollectionsIterator
+  m_inputCollectionsIterator = m_inputCollectionsProp.value().begin();
+  m_NumEvents = 0;
+  bool retError = false;
+  if (!m_helperTools.empty()) {
+    for (std::vector<ToolHandle<IAthenaSelectorTool> >::iterator iter = m_helperTools.begin(),
+           last = m_helperTools.end(); iter != last; iter++) {
+      if (!(*iter)->postInitialize().isSuccess()) {
+	ATH_MSG_FATAL("Failed to postInitialize() " << (*iter)->name());
+	retError = true;
+      }
+    }
+  }
+  if (retError) {
+    ATH_MSG_FATAL("Failed to postInitialize() helperTools");
+    return(StatusCode::FAILURE);
+  }
+  return(StatusCode::SUCCESS);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::start() {
+  ATH_MSG_DEBUG("Calling FaserEventSelectorByteStream::start()");
+  // If file based input then fire appropriate incidents
+  if (m_filebased) {
+    if (!m_firstFileFired) {
+      FileIncident firstInputFileIncident(name(), "FirstInputFile", "BSF:" + *m_inputCollectionsIterator);
+      m_incidentSvc->fireIncident(firstInputFileIncident);
+      m_firstFileFired = true;
+    }
+
+    // try to open a file
+    if (this->openNewRun().isFailure()) { 
+      ATH_MSG_FATAL("Unable to open any file in initialize"); 
+      return(StatusCode::FAILURE);
+    }
+    // should be in openNewRun, but see comment there
+    m_beginFileFired = true;
+  }
+
+  // Create the begin and end iterator's for this selector.
+  m_beginIter =  new FaserEventContextByteStream(this);
+  // Increment to get the new event in.
+  m_endIter   =  new FaserEventContextByteStream(0);
+
+  return(StatusCode::SUCCESS);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::stop() {
+  ATH_MSG_DEBUG("Calling FaserEventSelectorByteStream::stop()");
+  // Handle open files
+  if (m_filebased) {
+    // Close the file
+    if (m_eventSource->ready()) { 
+      m_eventSource->closeBlockIterator(false);
+      FileIncident endInputFileIncident(name(), "EndInputFile", "stop");
+      m_incidentSvc->fireIncident(endInputFileIncident);
+    }
+    // Fire LastInputFile incident
+    FileIncident lastInputFileIncident(name(), "LastInputFile", "stop");
+    m_incidentSvc->fireIncident(lastInputFileIncident);
+  }
+  return(StatusCode::SUCCESS);
+}
+
+//__________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::finalize() {
+  if (!m_counterTool.empty()) {
+    if (!m_counterTool->preFinalize().isSuccess()) {
+      ATH_MSG_WARNING("Failed to preFinalize() CounterTool");
+    }
+  }
+  for (std::vector<ToolHandle<IAthenaSelectorTool> >::iterator iter = m_helperTools.begin(),
+	 last = m_helperTools.end(); iter != last; iter++) {
+    if (!(*iter)->preFinalize().isSuccess()) {
+      ATH_MSG_WARNING("Failed to preFinalize() " << (*iter)->name());
+    }
+  }
+  delete m_beginIter; m_beginIter = 0;
+  delete m_endIter; m_endIter = 0;
+  // Release AthenaSharedMemoryTool
+  if (!m_eventStreamingTool.empty() && !m_eventStreamingTool.release().isSuccess()) {
+    ATH_MSG_WARNING("Cannot release AthenaSharedMemoryTool");
+  }
+  // Release CounterTool
+  if (!m_counterTool.empty()) {
+    if (!m_counterTool.release().isSuccess()) {
+      ATH_MSG_WARNING("Cannot release CounterTool.");
+    }
+  }
+  // Release HelperTools
+  if (!m_helperTools.release().isSuccess()) {
+    ATH_MSG_WARNING("Cannot release " << m_helperTools);
+  }
+  if (m_eventSource) m_eventSource->release();
+  // Finalize the Service base class.
+  return(AthService::finalize());
+}
+
+void FaserEventSelectorByteStream::nextFile() const {
+  ATH_MSG_DEBUG("nextFile() called");
+  FileIncident endInputFileIncident(name(), "EndInputFile", "BSF:" + *m_inputCollectionsIterator);
+  m_incidentSvc->fireIncident(endInputFileIncident);
+  ++m_inputCollectionsIterator;
+  ++m_fileCount;
+}
+
+StatusCode FaserEventSelectorByteStream::openNewRun() const {
+  ATH_MSG_DEBUG("openNewRun() called");
+  // Should be protected upstream, but this is further protection
+  if (!m_filebased) {
+    ATH_MSG_ERROR("cannot open new run for non-filebased inputs");
+    return(StatusCode::FAILURE);
+  }
+  // Check for end of file list
+  if (m_inputCollectionsIterator == m_inputCollectionsProp.value().end()) {
+    ATH_MSG_INFO("End of input file list reached");
+    return(StatusCode::FAILURE);
+  }
+  std::string blockname = *m_inputCollectionsIterator;
+  // try to open a file, if failure go to next FIXME: PVG: silient failure?
+  //long nev = m_eventSource->getBlockIterator(blockname);
+  auto nevguid = m_eventSource->getBlockIterator(blockname);
+  long nev = nevguid.first;
+  if (nev == -1) {
+    ATH_MSG_FATAL("Unable to access file " << *m_inputCollectionsIterator << ", stopping here");
+    throw ByteStreamExceptions::fileAccessError();
+  }
+  // Fire the incident
+  if (!m_beginFileFired) {
+    FileIncident beginInputFileIncident(name(), "BeginInputFile", "BSF:" + *m_inputCollectionsIterator,nevguid.second);
+    m_incidentSvc->fireIncident(beginInputFileIncident);
+    //m_beginFileFired = true;   // Should go here, but can't because IEvtSelector next is const
+  }
+
+  // check if file is empty
+  if (nev == 0) {
+    ATH_MSG_WARNING("no events in file " << blockname << " try next");
+    if (m_eventSource->ready()) m_eventSource->closeBlockIterator(true);
+    this->nextFile();
+    return openNewRun();
+    // check if skipping all events in that file (minus events already skipped)
+  } else if (m_SkipEvents - m_NumEvents > nev) {
+    ATH_MSG_WARNING("skipping more events " << m_SkipEvents-m_NumEvents << "(" << nev <<") than in file " << *m_inputCollectionsIterator << ", try next");
+    m_NumEvents += nev;
+    m_numEvt[m_fileCount] = nev;
+    if (m_eventSource->ready()) m_eventSource->closeBlockIterator(true);
+    this->nextFile();
+    return openNewRun();
+  }
+
+  ATH_MSG_DEBUG("Opened block/file " << blockname); 
+  m_firstEvt[m_fileCount] = m_NumEvents;
+  m_numEvt[m_fileCount] = nev;
+
+  return(StatusCode::SUCCESS);
+}
+
+StatusCode FaserEventSelectorByteStream::createContext(IEvtSelector::Context*& it) const {
+  it = new FaserEventContextByteStream(this);
+  return(StatusCode::SUCCESS);
+}
+
+StatusCode FaserEventSelectorByteStream::next(IEvtSelector::Context& it) const {
+
+  static int n_bad_events = 0;   // cross loop counter of bad events
+  // Check if this is an athenaMP client process
+  if (!m_eventStreamingTool.empty() && m_eventStreamingTool->isClient()) {
+    ATH_MSG_DEBUG("FaserEventSelectorByteStream::next() called for MT");
+    void* source = 0;
+    unsigned int status = 0;
+    if (!m_eventStreamingTool->getLockedEvent(&source, status).isSuccess()) {
+      ATH_MSG_FATAL("Cannot get NextEvent from AthenaSharedMemoryTool");
+      return(StatusCode::FAILURE);
+    }
+    m_eventSource->setEvent(static_cast<char*>(source), status);
+    return(StatusCode::SUCCESS);
+  }
+
+  ATH_MSG_DEBUG("FaserEventSelectorByteStream::next() called for non-MT");
+
+  // Call all selector tool preNext before starting loop
+  for (std::vector<ToolHandle<IAthenaSelectorTool> >::const_iterator iter = m_helperTools.begin(),
+	 last = m_helperTools.end(); iter != last; iter++) {
+    if (!(*iter)->preNext().isSuccess()) {
+      ATH_MSG_WARNING("Failed to preNext() " << (*iter)->name());
+    }
+  }
+  if (!m_counterTool.empty()) {
+    if (!m_counterTool->preNext().isSuccess()) {
+      ATH_MSG_WARNING("Failed to preNext() CounterTool.");
+    }
+  }
+  // Find an event to return
+  for (;;) {
+    const EventFull* pre = 0; 
+    bool badEvent(false);
+    // if event source not ready from init, try next file
+    if (m_filebased && !m_eventSource->ready()) {
+      // next file
+      this->nextFile();
+      if (this->openNewRun().isFailure()) {
+	ATH_MSG_DEBUG("Event source found no more valid files left in input list");
+	m_NumEvents = -1;
+	return StatusCode::FAILURE; 
+      }
+    }
+    try { 
+      ATH_MSG_DEBUG("Call eventSource->nextEvent()");
+      pre = m_eventSource->nextEvent(); 
+    } 
+    catch (const ByteStreamExceptions::readError&) { 
+      ATH_MSG_FATAL("Caught ByteStreamExceptions::readError"); 
+      return StatusCode::FAILURE; 
+    } 
+    catch (const ByteStreamExceptions::badFragment&) { 
+      ATH_MSG_ERROR("badFragment encountered");
+      badEvent = true;
+    }
+    catch (const ByteStreamExceptions::badFragmentData&) { 
+      ATH_MSG_ERROR("badFragment data encountered");
+      badEvent = true;
+    }
+    // Check whether a RawEvent has actually been provided
+    if (pre == 0) {
+      ATH_MSG_INFO("No event built");
+      it = *m_endIter;
+      return(StatusCode::FAILURE);
+    }
+      
+    // increment that an event was found
+    ++m_NumEvents;
+
+    // check bad event flag and handle as configured 
+    if (badEvent) {
+      ++n_bad_events;
+      ATH_MSG_INFO("Bad event encountered, current count at " << n_bad_events);
+      bool toomany = (m_maxBadEvts >= 0 && n_bad_events > m_maxBadEvts);
+      if (toomany) {ATH_MSG_FATAL("too many bad events ");}
+      if (!m_procBadEvent || toomany) {
+	// End of file
+	it = *m_endIter;
+	return(StatusCode::FAILURE);
+      }
+      ATH_MSG_WARNING("Continue with bad event");
+    }
+
+    // Build a DH for use by other components
+    StatusCode rec_sg = m_eventSource->generateDataHeader();
+    if (rec_sg != StatusCode::SUCCESS) {
+      ATH_MSG_ERROR("Fail to record BS DataHeader in StoreGate. Skipping events?! " << rec_sg);
+    }
+
+    // Check whether properties or tools reject this event
+    if ( m_NumEvents > m_SkipEvents && 
+	 (m_skipEventSequence.empty() || m_NumEvents != m_skipEventSequence.front()) ) {
+      StatusCode status(StatusCode::SUCCESS);
+      // Build event info attribute list
+      ATH_MSG_DEBUG("FaserEventSelectorByteStream::next() calling buildEventAttributeList()");
+      if (buildEventAttributeList().isFailure()) ATH_MSG_WARNING("Unable to build event info att list");
+      for (std::vector<ToolHandle<IAthenaSelectorTool> >::const_iterator iter = m_helperTools.begin(),
+	     last = m_helperTools.end(); iter != last; iter++) {
+	StatusCode toolStatus = (*iter)->postNext();
+	if (toolStatus.isRecoverable()) {
+	  ATH_MSG_INFO("Request skipping event from: " << (*iter)->name());
+	  status = StatusCode::RECOVERABLE;
+	} else if (toolStatus.isFailure()) {
+	  ATH_MSG_WARNING("Failed to postNext() " << (*iter)->name());
+	  status = StatusCode::FAILURE;
+	}
+      }
+      if (status.isRecoverable()) {
+	ATH_MSG_INFO("skipping event " << m_NumEvents);
+      } else if (status.isFailure()) {
+	ATH_MSG_WARNING("Failed to postNext() HelperTool.");
+      } else {
+	if (!m_counterTool.empty()) {
+	  if (!m_counterTool->postNext().isSuccess()) {
+	    ATH_MSG_WARNING("Failed to postNext() CounterTool.");
+	  }
+	}
+	break;
+      }
+
+      ATH_MSG_DEBUG("FaserEventSelectorByteStream::next() calling eventSource->validateEvent()");
+      // Validate the event
+      try {
+	m_eventSource->validateEvent();
+      }
+      catch (const ByteStreamExceptions::badFragmentData&) { 
+	ATH_MSG_ERROR("badFragment data encountered");
+
+	++n_bad_events;
+	ATH_MSG_INFO("Bad event encountered, current count at " << n_bad_events);
+
+	bool toomany = (m_maxBadEvts >= 0 && n_bad_events > m_maxBadEvts);
+	if (toomany) {ATH_MSG_FATAL("too many bad events ");}
+	if (!m_procBadEvent || toomany) {
+	  // End of file
+	  it = *m_endIter;
+	  return(StatusCode::FAILURE);
+	}
+	ATH_MSG_WARNING("Continue with bad event");
+      }
+    } else {
+      if (!m_skipEventSequence.empty() && m_NumEvents == m_skipEventSequence.front()) {
+	m_skipEventSequence.erase(m_skipEventSequence.begin());
+      }
+      ATH_MSG_DEBUG("Skipping event " << m_NumEvents - 1);
+    }
+  } // for loop
+  ATH_MSG_DEBUG("FaserEventSelectorByteStream::next() done");
+  return(StatusCode::SUCCESS);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::next(IEvtSelector::Context& ctxt, int jump) const {
+  if (jump > 0) {
+    if ( m_NumEvents+jump != m_SkipEvents) {
+      // Save initial event count
+      unsigned int cntr = m_NumEvents;
+      // In case NumEvents increments multiple times in a single next call
+      while (m_NumEvents+1 <= cntr + jump) {
+	if (!next(ctxt).isSuccess()) {
+	  return(StatusCode::FAILURE);
+	}
+      }
+    }
+    else ATH_MSG_DEBUG("Jump covered by skip event " << m_SkipEvents);
+    return(StatusCode::SUCCESS);
+  }
+  else { 
+    ATH_MSG_WARNING("Called jump next with non-multiple jump");
+  }
+  return(StatusCode::SUCCESS);
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::previous(IEvtSelector::Context& /*ctxt*/) const {
+  ATH_MSG_DEBUG(" ... previous");
+  const EventFull* pre = 0; 
+  bool badEvent(false);
+  // if event source not ready from init, try next file
+  if (m_eventSource->ready()) {
+    try { 
+      pre = m_eventSource->previousEvent(); 
+    } 
+    catch (const ByteStreamExceptions::readError&) { 
+      ATH_MSG_FATAL("Caught ByteStreamExceptions::readError"); 
+      return StatusCode::FAILURE; 
+    } 
+    catch (const ByteStreamExceptions::badFragment&) { 
+      ATH_MSG_ERROR("badFragment encountered");
+      badEvent = true;
+    }
+    catch (const ByteStreamExceptions::badFragmentData&) { 
+      ATH_MSG_ERROR("badFragment data encountered");
+      badEvent = true;
+    }
+    // Check whether a RawEvent has actually been provided
+    if (pre == 0) {
+      ATH_MSG_ERROR("No event built");
+      //it = *m_endIter;
+      return(StatusCode::FAILURE);
+    }
+  }
+  else {
+    ATH_MSG_FATAL("Attempt to read previous data on invalid reader");
+    return(StatusCode::FAILURE);
+  }
+  // increment that an event was found
+  //++m_NumEvents;
+ 
+  // check bad event flag and handle as configured 
+  if (badEvent) {
+    ATH_MSG_ERROR("Called previous for bad event");
+    if (!m_procBadEvent) {
+      // End of file
+      //it = *m_endIter;
+      return(StatusCode::FAILURE);
+    }
+    ATH_MSG_WARNING("Continue with bad event");
+  }
+
+  // Build a DH for use by other components
+  StatusCode rec_sg = m_eventSource->generateDataHeader();
+  if (rec_sg != StatusCode::SUCCESS) {
+    ATH_MSG_ERROR("Fail to record BS DataHeader in StoreGate. Skipping events?! " << rec_sg);
+  }
+
+  return StatusCode::SUCCESS;
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::previous(IEvtSelector::Context& ctxt, int jump) const {
+  if (jump > 0) {
+    for (int i = 0; i < jump; i++) {
+      if (!previous(ctxt).isSuccess()) {
+	return(StatusCode::FAILURE);
+      }
+    }
+    return(StatusCode::SUCCESS);
+  }
+  return(StatusCode::FAILURE);
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::last(IEvtSelector::Context& it)const {
+  if (it.identifier() == m_endIter->identifier()) {
+    ATH_MSG_DEBUG("last(): Last event in InputStream.");
+    return(StatusCode::SUCCESS);
+  }
+  return(StatusCode::FAILURE);
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::rewind(IEvtSelector::Context& /*it*/) const {
+  ATH_MSG_ERROR("rewind() not implemented");
+  return(StatusCode::FAILURE);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::resetCriteria(const std::string& /*criteria*/, IEvtSelector::Context& /*ctxt*/) const {
+  return(StatusCode::SUCCESS);
+}
+
+//__________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::seek(Context& it, int evtNum) const {
+  // Check that input is seekable
+  if (!m_filebased) {
+    ATH_MSG_ERROR("Input not seekable, choose different input svc");
+    return StatusCode::FAILURE;
+  }
+  // find the file index with that event
+  long fileNum = findEvent(evtNum);
+  if (fileNum == -1 && evtNum >= m_firstEvt[m_fileCount] && evtNum < m_NumEvents) {
+    fileNum = m_fileCount;
+  }
+  // if unable to locate file, exit
+  if (fileNum == -1) {
+    ATH_MSG_INFO("seek: Reached end of Input.");
+    return(StatusCode::RECOVERABLE);
+  }
+  // check if it is the current file
+  if (fileNum != m_fileCount) { // event in different file
+    // Close input file if open
+    if (m_eventSource->ready()) m_eventSource->closeBlockIterator(true);
+    ATH_MSG_DEBUG("Seek to item: \"" << m_inputCollectionsProp.value()[fileNum] << "\" from the explicit file list.");
+    std::string fileName = m_inputCollectionsProp.value()[fileNum];
+    m_fileCount = fileNum;
+    // Open the correct file
+    auto nevguid = m_eventSource->getBlockIterator(fileName);
+    long nev = nevguid.first;
+    if (nev == -1) {
+      ATH_MSG_FATAL("Unable to open file with seeked event " << evtNum << " file " << fileName);
+      return StatusCode::FAILURE;
+    }
+    int delta = evtNum - m_firstEvt[m_fileCount];
+    if (delta > 0) {
+      if (next(*m_beginIter,delta).isFailure()) return StatusCode::FAILURE;
+    }
+    else return this->seek(it, evtNum);
+  } 
+  else { // event in current file
+    int delta = (evtNum - m_firstEvt[m_fileCount] + 1) - m_eventSource->positionInBlock();
+    ATH_MSG_DEBUG("Seeking event " << evtNum << " in current file wiht delta " << delta);
+    if ( delta == 0 ) { // current event
+      // nothing to do
+    } 
+    else if ( delta > 0 ) { // forward
+      if ( this->next(*m_beginIter, delta).isFailure() ) return StatusCode::FAILURE;
+    } 
+    else if ( delta < 0 ) { // backward
+      if ( this->previous(*m_beginIter, -1*delta).isFailure() ) return(StatusCode::FAILURE);
+    } 
+  }
+  return(StatusCode::SUCCESS);
+}
+
+StatusCode FaserEventSelectorByteStream::buildEventAttributeList() const
+{
+  //ServiceHandle<StoreGateSvc> m_evtStore("StoreGateSvc/StoreGateSvc",this->name());
+  //StatusCode sc = m_evtStore.retrieve();
+  //if (sc.isFailure()) return StatusCode::FAILURE;
+  std::string listName("EventInfoAtts");
+  //bool found  = m_evtStore->contains<AthenaAttributeList>(listName);
+  //if (found) {
+  if (m_evtStore->contains<AthenaAttributeList>(listName)) {
+    const AthenaAttributeList* oldAttrList = nullptr;
+    if (!m_evtStore->retrieve(oldAttrList, listName).isSuccess()) {
+      ATH_MSG_ERROR("Cannot retrieve old AttributeList from StoreGate.");
+      return(StatusCode::FAILURE);
+    }
+    if (!m_evtStore->removeDataAndProxy(oldAttrList).isSuccess()) {
+      ATH_MSG_ERROR("Cannot remove old AttributeList from StoreGate.");
+      return(StatusCode::FAILURE);
+    }
+    //ATH_MSG_ERROR("Event store not cleared properly after previous event");
+    //return StatusCode::FAILURE;
+  }
+  // build spec
+  // fill att list spec
+  coral::AttributeListSpecification* spec = new coral::AttributeListSpecification();
+  AthenaAttributeList* attlist = new AthenaAttributeList(*spec);
+  attlist->extend("RunNumber"  ,"long");
+  attlist->extend("EventNumber","long");
+  attlist->extend("Lumiblock"  ,"int");
+  attlist->extend("BunchID"    ,"int");
+  attlist->extend("CrossingTimeSec", "unsigned int");
+  attlist->extend("CrossingTimeNSec", "unsigned int");
+
+  // fill attribute list
+  const EventFull* event = m_eventSource->currentEvent();
+
+  (*attlist)["RunNumber"].data<long>() = event->run_number();
+  (*attlist)["EventNumber"].data<long>() = event->event_counter();
+  (*attlist)["Lumiblock"].data<int>() = 0;
+  (*attlist)["BunchID"].data<int>() = event->bc_id();
+
+  // Timestamp is in microseconds
+  unsigned int bc_time_sec = event->timestamp() / 1E6;
+  unsigned int bc_time_ns  = 1000 * (event->timestamp() - 1E6*bc_time_sec);
+  (*attlist)["CrossingTimeSec"].data<unsigned int>() = bc_time_sec;
+  (*attlist)["CrossingTimeNSec"].data<unsigned int>() = bc_time_ns;
+
+  // Not used
+  attlist->extend("TriggerStatus","unsigned int");
+  (*attlist)["TriggerStatus"].data<unsigned int>() = event->status();
+
+  // Not used
+  attlist->extend("ExtendedL1ID","unsigned int");
+  attlist->extend("L1TriggerType","unsigned int");
+  (*attlist)["ExtendedL1ID"].data<unsigned int>() = 0;
+  (*attlist)["L1TriggerType"].data<unsigned int>() = event->trigger_bits();
+
+  // Add our event tag
+  attlist->extend("EventTag", "unsigned int");
+  (*attlist)["EventTag"].data<unsigned int>() = event->event_tag();
+
+  attlist->extend("Timestamp", "unsigned long");
+  (*attlist)["Timestamp"].data<unsigned long>() = event->timestamp();
+
+  // And our us time
+
+  // Grab stream tags
+  /* Not sure what do do with this
+  event->stream_tag(buffer);
+  std::vector<eformat::helper::StreamTag> onl_streamTags;
+  eformat::helper::decode(event->nstream_tag(), buffer, onl_streamTags);
+  for (std::vector<eformat::helper::StreamTag>::const_iterator itS = onl_streamTags.begin(),
+	 itSE = onl_streamTags.end(); itS != itSE; ++itS) {
+    attlist->extend(itS->name,"string");
+    (*attlist)[itS->name].data<std::string>() = itS->type;
+  }
+  */
+
+  // Pur our own event_tag
+
+  // put result in event store
+  if (m_evtStore->record(attlist,"EventInfoAtts").isFailure()) return StatusCode::FAILURE;
+   
+  return(StatusCode::SUCCESS);
+}
+
+//__________________________________________________________________________
+int FaserEventSelectorByteStream::findEvent(int evtNum) const {
+  // Loop over file event counts
+  //ATH_MSG_INFO("try to find evnum = " << evtNum << " in " << m_numEvt.size() << " files");
+  for (size_t i = 0; i < m_inputCollectionsProp.value().size(); i++) {
+    if (m_inputCollectionsProp.value().size() != m_numEvt.size()) {
+      ATH_MSG_ERROR("vector size incompatibility");
+      break;
+    }
+    // if file not opened yet, check it
+    if (m_numEvt[i] == -1) {
+      std::string fileName = m_inputCollectionsProp.value()[i];
+      auto nevguid = m_eventSource->getBlockIterator(fileName);
+      long nev = nevguid.first;
+      // if failure on file open, exit
+      if (nev==-1) {
+	break;
+      }
+      // set initial event counter for that file
+      if (i > 0) {
+	m_firstEvt[i] = m_firstEvt[i - 1] + m_numEvt[i - 1];
+      } else {
+	m_firstEvt[i] = 0;
+      }
+      // log number of events in that file
+      m_numEvt[i] = nev;
+    }
+    // if sought event is in this file, then return the index of that file
+    if (evtNum >= m_firstEvt[i] && evtNum < m_firstEvt[i] + m_numEvt[i]) {
+      ATH_MSG_INFO("found " << evtNum << " in file " << i);
+      return(i);
+    }
+  }
+  ATH_MSG_INFO("did not find ev " << evtNum);
+  // return file not found marker
+  return(-1);
+}
+
+//__________________________________________________________________________
+int FaserEventSelectorByteStream::curEvent (const Context& /*it*/) const {
+  // event counter in IEvtSelectorSeek interface
+  return int(m_NumEvents);
+}
+
+//__________________________________________________________________________
+int FaserEventSelectorByteStream::size (Context& /*it*/) const {
+  return -1;
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::makeServer(int /*num*/) {
+  if (m_eventStreamingTool.empty()) {
+    return(StatusCode::FAILURE);
+  }
+  return(m_eventStreamingTool->makeServer(1));
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::makeClient(int /*num*/) {
+  if (m_eventStreamingTool.empty()) {
+    return(StatusCode::FAILURE);
+  }
+  return(m_eventStreamingTool->makeClient(0));
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::share(int evtNum) {
+  if (m_eventStreamingTool.empty()) {
+    return(StatusCode::FAILURE);
+  }
+  if (m_eventStreamingTool->isClient()) {
+    StatusCode sc = m_eventStreamingTool->lockEvent(evtNum);
+    while (sc.isRecoverable()) {
+      usleep(1000);
+      sc = m_eventStreamingTool->lockEvent(evtNum);
+    }
+    return(sc);
+  }
+  return(StatusCode::FAILURE);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::readEvent(int maxevt) {
+  
+  if (m_eventStreamingTool.empty()) {
+    return(StatusCode::FAILURE);
+  }
+  ATH_MSG_VERBOSE("Called read Event " << maxevt);
+  for (int i = 0; i < maxevt || maxevt == -1; ++i) {
+    //const RawEvent* pre = m_eventSource->nextEvent();
+    const EventFull* pre = 0;
+    if (this->next(*m_beginIter).isSuccess()) {
+      pre = m_eventSource->currentEvent();
+    } else {
+      if (m_NumEvents == -1) {
+	ATH_MSG_VERBOSE("Called read Event and read last event from input: " << i);
+	break;
+      }
+      ATH_MSG_ERROR("Unable to retrieve next event for " << i << "/" << maxevt);
+      return(StatusCode::FAILURE);
+    }
+    if (pre == 0) {
+      // End of file, wait for last event to be taken
+      StatusCode sc = m_eventStreamingTool->putEvent(0, 0, 0, 0);
+      while (sc.isRecoverable()) {
+	usleep(1000);
+	sc = m_eventStreamingTool->putEvent(0, 0, 0, 0);
+      }
+      if (!sc.isSuccess()) {
+	ATH_MSG_ERROR("Cannot put last Event marker to AthenaSharedMemoryTool");
+      }
+      return(StatusCode::FAILURE);
+    }
+    if (m_eventStreamingTool->isServer()) {
+
+      ATH_MSG_WARNING("Called FaserEventSelectorByteStream::readEvent() in the eventStreamingTool->isServer() section, but not implemented!");
+
+      /*
+      StatusCode sc = m_eventStreamingTool->putEvent(m_NumEvents - 1, pre->start(), pre->fragment_size_word() * sizeof(uint32_t), m_eventSource->currentEventStatus());
+      while (sc.isRecoverable()) {
+	usleep(1000);
+	sc = m_eventStreamingTool->putEvent(m_NumEvents - 1, pre->start(), pre->fragment_size_word() * sizeof(uint32_t), m_eventSource->currentEventStatus());
+      }
+      if (!sc.isSuccess()) {
+	ATH_MSG_ERROR("Cannot put Event " << m_NumEvents - 1 << " to AthenaSharedMemoryTool");
+	return(StatusCode::FAILURE);
+      }
+      */
+    }
+  }
+  return(StatusCode::SUCCESS);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::createAddress(const IEvtSelector::Context& /*it*/,
+						  IOpaqueAddress*& iop) const {
+  SG::DataProxy* proxy = m_evtStore->proxy(ClassID_traits<DataHeader>::ID(),"ByteStreamDataHeader");
+  if (proxy !=0) {
+    iop = proxy->address();
+    return(StatusCode::SUCCESS);
+  } else {
+    iop = 0;
+    return(StatusCode::FAILURE);
+  }
+}
+
+//________________________________________________________________________________
+StatusCode
+FaserEventSelectorByteStream::releaseContext(IEvtSelector::Context*& /*it*/) const {
+  return(StatusCode::SUCCESS);
+}
+
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+  if (riid == IEvtSelector::interfaceID()) {
+    *ppvInterface = dynamic_cast<IEvtSelector*>(this);
+  } else if (riid == IIoComponent::interfaceID()) {
+    *ppvInterface = dynamic_cast<IIoComponent*>(this);
+  } else if (riid == IProperty::interfaceID()) {
+    *ppvInterface = dynamic_cast<IProperty*>(this);
+  } else if (riid == IEvtSelectorSeek::interfaceID()) {
+    *ppvInterface = dynamic_cast<IEvtSelectorSeek*>(this);
+  } else if (riid == IEventShare::interfaceID()) {
+    *ppvInterface = dynamic_cast<IEventShare*>(this);
+  } else {
+    return(Service::queryInterface(riid, ppvInterface));
+  }
+  addRef();
+  return(StatusCode::SUCCESS);
+}
+//________________________________________________________________________________
+StatusCode FaserEventSelectorByteStream::io_reinit() {
+  ATH_MSG_INFO("I/O reinitialization...");
+  ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
+  if (!iomgr.retrieve().isSuccess()) {
+    ATH_MSG_FATAL("Could not retrieve IoComponentMgr !");
+    return(StatusCode::FAILURE);
+  }
+  if (!iomgr->io_hasitem(this)) {
+    ATH_MSG_FATAL("IoComponentMgr does not know about myself !");
+    return(StatusCode::FAILURE);
+  }
+  if (m_inputCollectionsFromIS) {
+    /*   MN: don't copy the FullFileName again - rely on FileSchedulingTool
+           to modify the EventSelector Input property directly
+      IProperty* propertyServer = dynamic_cast<IProperty*>(m_eventSource);
+      std::vector<std::string> vect;
+      StringArrayProperty inputFileList("FullFileName", vect);
+      StatusCode sc = propertyServer->getProperty(&inputFileList);
+      if(sc.isFailure()) {
+         ATH_MSG_FATAL("Unable to retrieve ByteStreamInputSvc");
+         return(StatusCode::FAILURE);
+      }
+      m_inputCollectionsProp = inputFileList;
+    */
+  }
+  std::vector<std::string> inputCollections = m_inputCollectionsProp.value();
+  for (std::size_t i = 0, imax = inputCollections.size(); i != imax; ++i) {
+    ATH_MSG_INFO("I/O reinitialization, file = "  << inputCollections[i]);
+    std::string &fname = inputCollections[i];
+    if (!iomgr->io_contains(this, fname)) {
+      ATH_MSG_ERROR("IoComponentMgr does not know about [" << fname << "] !");
+      return(StatusCode::FAILURE);
+    }
+    if (!iomgr->io_retrieve(this, fname).isSuccess()) {
+      ATH_MSG_FATAL("Could not retrieve new value for [" << fname << "] !");
+      return(StatusCode::FAILURE);
+    }
+  }
+  // all good... copy over.
+  m_beginFileFired = false;
+  m_inputCollectionsProp = inputCollections;
+   
+  return(this->reinit());
+}
+
+
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
new file mode 100644
index 000000000..34bdec974
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
@@ -0,0 +1,167 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASEREVENTSELECTORBYTESTREAM_H
+#define FASEREVENTSELECTORBYTESTREAM_H
+
+/**  @class  FaserEventSelectorByteStream
+     @brief  concrete implementation of IEvtSelector for ByteStream
+
+     An event selector service that steps through Event
+     Filter packed raw events by use of an event source
+     object and an iterator object called EventIteratorByteStream.
+     The type of event source is specified at run time. It
+     can be a single file, a set of files or the network.
+//---------------------------------------------------------------------
+*/
+
+#include "GaudiKernel/IEvtSelector.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/IIoComponent.h"
+
+#include "AthenaKernel/IAthenaSelectorTool.h"
+#include "AthenaKernel/IEvtSelectorSeek.h"
+#include "AthenaKernel/IEventShare.h"
+#include "AthenaBaseComps/AthService.h"
+
+// #include "ByteStreamData/RawEvent.h"
+
+// Forward declarations.
+class ISvcLocator;
+class IAthenaIPCTool;
+class FaserEventContextByteStream;
+class FaserByteStreamInputSvc;
+class IROBDataProviderSvc;
+
+// Class EventSelectorByteStream.
+class FaserEventSelectorByteStream : public ::AthService,
+  virtual public IEvtSelector,
+  virtual public IEvtSelectorSeek,
+  virtual public IEventShare,
+  virtual public IIoComponent {
+ public:
+  /// Standard Constructor.
+  FaserEventSelectorByteStream(const std::string& name, ISvcLocator* svcloc);
+  /// Standard Destructor.
+  virtual ~FaserEventSelectorByteStream();
+
+  /// Implementation of Service base class methods.
+  virtual StatusCode initialize() override;
+  virtual StatusCode start() override;
+  virtual StatusCode stop() override;
+  virtual StatusCode finalize() override;
+
+  // Implementation of IInterface methods.
+  virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface) override;
+
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode createContext(Context*& it) const override;
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode next(Context& it) const override;
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode next(Context& it, int jump) const override;
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode previous(Context& it) const override;
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode previous(Context& it, int jump) const override;
+
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode last(Context& it) const override;
+  /// Implementation of the IEvtSelector interface methods.
+  virtual StatusCode rewind(Context& it) const override;
+
+  virtual StatusCode createAddress(const Context& it,IOpaqueAddress*& iop) const override;
+  virtual StatusCode releaseContext(Context*& it) const override;
+  virtual StatusCode resetCriteria(const std::string& criteria, Context& context) const override;
+
+  /// Seek to a given event number.
+  /// @param evtnum [IN]  The event number to which to seek.
+  virtual StatusCode seek (Context& it, int evtnum) const override;
+
+  /// Return the current event number.
+  virtual int curEvent (const Context& it) const override;
+
+  /// Always returns -1.
+  virtual int size (Context& it) const override;
+
+  /// Make this a server.
+  virtual StatusCode makeServer(int num) override;
+
+  /// Make this a client.
+  virtual StatusCode makeClient(int num) override;
+
+  /// Request to share a given event number.
+  /// @param evtnum [IN]  The event number to share.
+  virtual StatusCode share(int evtnum) override;
+
+  /// Read the next maxevt events.
+  /// @param evtnum [IN]  The number of events to read.
+  virtual StatusCode readEvent(int maxevt) override;
+
+  /// Callback method to reinitialize the internal state of the component for I/O purposes (e.g. upon @c fork(2))
+  virtual StatusCode io_reinit() override;
+
+ private: // internal member functions
+  /// reinitialize the service when a @c fork() occured/was-issued
+  StatusCode reinit();
+  StatusCode openNewRun() const;
+  void nextFile() const; 
+  int findEvent(int evtNum) const; //>! Search for event number evtNum.
+  StatusCode buildEventAttributeList() const;
+
+ private:
+  // property
+  std::string      m_eventSourceName;
+  Gaudi::Property<int>  m_maxBadEvts;    //!< number of bad events allowed before quitting.
+  mutable int              m_fileCount;     //!< number of files to process.
+
+  mutable std::vector<int>     m_numEvt;
+  mutable std::vector<int>     m_firstEvt;
+
+  FaserEventContextByteStream*  m_beginIter;
+  FaserEventContextByteStream*  m_endIter;
+  FaserByteStreamInputSvc*      m_eventSource;
+  Gaudi::Property<std::vector<std::string>> m_inputCollectionsProp;
+  mutable std::vector<std::string>::const_iterator m_inputCollectionsIterator;
+  void inputCollectionsHandler(Property&);
+  ServiceHandle<IIncidentSvc> m_incidentSvc;
+  ServiceHandle<StoreGateSvc> m_evtStore;
+
+  long m_SkipEvents; // Number of events to skip at the beginning
+  Gaudi::Property<std::vector<long>> m_skipEventSequenceProp;
+  mutable std::vector<long> m_skipEventSequence;
+
+  bool m_firstFileFired;
+  bool m_beginFileFired;
+  bool m_inputCollectionsFromIS;
+  mutable long m_NumEvents; // Number of Events read so far.
+
+  mutable ToolHandle<IAthenaIPCTool> m_eventStreamingTool;
+
+  Gaudi::Property<bool>    m_procBadEvent;  //!< process bad events, which fail check_tree().
+
+  /// HelperTools, vector of names of AlgTools that are executed by the EventSelector
+  ToolHandleArray<IAthenaSelectorTool> m_helperTools;
+  ToolHandle<IAthenaSelectorTool> m_counterTool;
+         
+  /**@name Athena standard EventSelector properties */
+
+  /// Flags to indicate override of run/event/time
+  ///  These are almost always false.
+  Gaudi::Property<bool> m_overrideRunNumber;
+  Gaudi::Property<bool> m_overrideEventNumber;
+  Gaudi::Property<bool> m_overrideTimeStamp;
+  Gaudi::Property<bool> m_filebased;
+
+  Gaudi::CheckedProperty<int> m_runNo;
+  Gaudi::CheckedProperty<int> m_firstEventNo;
+  Gaudi::CheckedProperty<int> m_eventsPerRun;
+  Gaudi::CheckedProperty<int> m_firstLBNo;
+  Gaudi::CheckedProperty<int> m_eventsPerLB;
+  Gaudi::CheckedProperty<int> m_initTimeStamp;
+  Gaudi::Property<int> m_timeStampInterval;
+  };
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx b/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
new file mode 100644
index 000000000..c3490e2bb
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
@@ -0,0 +1,28 @@
+#include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
+#include "../FaserByteStreamInputSvc.h"
+#include "../FaserEventSelectorByteStream.h"
+#include "../EventInfoByteStreamxAODCnv.h"
+#include "../EventInfoByteStreamAuxCnv.h"
+/*
+#include "../ByteStreamMergeOutputSvc.h"
+#include "../ByteStreamRDP_OutputSvc.h"
+#include "../ByteStreamEventStorageInputSvc.h"
+#include "../ByteStreamEventStorageOutputSvc.h"
+#include "../ByteStreamOutputStreamCopyTool.h"
+#include "../ByteStreamMetadataTool.h"
+*/
+
+DECLARE_COMPONENT( FaserByteStreamCnvSvc )
+DECLARE_COMPONENT( FaserByteStreamInputSvc )
+DECLARE_COMPONENT( FaserEventSelectorByteStream )
+DECLARE_CONVERTER( EventInfoByteStreamxAODCnv )
+DECLARE_CONVERTER( EventInfoByteStreamAuxCnv )
+/*
+DECLARE_COMPONENT( ByteStreamMergeOutputSvc )
+DECLARE_COMPONENT( ByteStreamRDP_OutputSvc )
+DECLARE_COMPONENT( ByteStreamEventStorageInputSvc )
+DECLARE_COMPONENT( ByteStreamEventStorageOutputSvc )
+
+DECLARE_COMPONENT( ByteStreamOutputStreamCopyTool )
+DECLARE_COMPONENT( ByteStreamMetadataTool )
+*/
diff --git a/Event/FaserEventStorage/CMakeLists.txt b/Event/FaserEventStorage/CMakeLists.txt
new file mode 100644
index 000000000..9cd19ab23
--- /dev/null
+++ b/Event/FaserEventStorage/CMakeLists.txt
@@ -0,0 +1,32 @@
+################################################################################
+# Package: FaserEventStorage
+################################################################################
+
+# Declare the package name:
+atlas_subdir( FaserEventStorage )
+
+atlas_depends_on_subdirs (
+PRIVATE
+EventFormats
+)
+
+# External dependencies:
+find_package( tdaq-common COMPONENTS ers EventStorage )
+find_package( Boost COMPONENTS system )
+
+atlas_add_library( FaserEventStorageLib
+    FaserEventStorage/*.h src/*.h src/*.cxx
+    PUBLIC_HEADERS FaserEventStorage
+    INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS}
+    LINK_LIBRARIES ${Boost_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} )
+
+
+# atlas_add_library(fReadPlain 
+#     src/fReadPlain.h src/fReadPlain.cxx 
+#     PUBLIC_HEADERS src
+#     INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS}
+#     LINK_LIBRARIES ${Boost_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} -rdynamic)
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
+atlas_install_joboptions( share/*.py )
diff --git a/Event/FaserEventStorage/FaserEventStorage/DRError.h b/Event/FaserEventStorage/FaserEventStorage/DRError.h
new file mode 100644
index 000000000..493df0e15
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/DRError.h
@@ -0,0 +1,21 @@
+#ifndef _ERROR_ESTORE_R_
+#define _ERROR_ESTORE_R_
+
+/** 
+    \brief Return codes of the DataReader interface.
+    \file EventStorage/DRError.h
+*/
+
+namespace FaserEventStorage {
+
+  enum DRError { DROK = 0, /**< All OK */
+		 DRNOOK,   /**< an error, no way to read more data */
+                 DRWAIT,   /**< No way to read more data now, but there is a new file to which another process is writing. */
+		 DRNOSEQ,  /**< Not possible to make a file sequence. File name does not end with <number>.data */ 
+		 DRWOFF    /**< Wrong offset was given. No event data was found. You can still try another offset. */
+  };
+
+}        
+
+#endif //_ERROR_ESTORE_R_
+ 
diff --git a/Event/FaserEventStorage/FaserEventStorage/DataReader.h b/Event/FaserEventStorage/FaserEventStorage/DataReader.h
new file mode 100644
index 000000000..39282122b
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/DataReader.h
@@ -0,0 +1,146 @@
+//Dear emacs, this is -*- c++ -*-
+
+
+/** 
+    \brief The API for reading of raw data data files 
+    written by ATLAS TDAQ applications.
+    \author Szymon Gadomski
+    \date May 2002 - Feb 2007
+    \file EventStorage/DataReader.h
+*/
+
+#ifndef FASEREVENTSTORAGE_DATAREADER_H
+#define FASEREVENTSTORAGE_DATAREADER_H
+
+#include <vector>
+#include <string>
+#include <stdint.h>
+#include <bitset>
+#include "FaserEventStorage/DRError.h"
+#include "FaserEventStorage/ESCompression.h"
+
+#include <boost/utility.hpp>
+
+namespace DAQFormats {
+  class EventFull;
+}
+
+using namespace FaserEventStorage;
+
+namespace FaserEventStorage {  
+
+  class DataReader : boost::noncopyable
+  {
+  protected:
+    DataReader() {};
+
+  public: 
+    /** the virual destructor */
+    virtual ~DataReader() {};
+
+  public:
+    /** 
+	  The method to enamble reading of file sequences.
+	    You need to call this method if you want to enable reading of 
+	      file sequences (*0001.data, *0002.data ...).
+	        By default, i.e. unless you call this method, only one file will 
+		  be read 
+    */ 
+    virtual DRError enableSequenceReading() = 0;
+
+    /** Feedback to user. Check if you can still read more data. */ 
+    virtual bool good() const = 0;
+
+    /** true if no more events left in the current file */
+    virtual bool endOfFile() const = 0;
+
+    /** true if no more events left in the file sequence */
+    virtual bool endOfFileSequence() const = 0; 
+ 
+    /** number of the file currently open; make sense only if you are reading a sequence */
+    virtual unsigned int currentFileNumber() const = 0; 
+
+    virtual unsigned int latestDataNumber() const = 0;
+
+
+    /** 
+	  read the event data 
+	    \param &eventSize the event (or data block) size will be returned here
+	      \param **event start of the data block
+	        \param pos if you give this parameter, you are trying to get an event from the offset pos
+		
+		  Possible return codes are decribed in the file EventStorage/DataReader.h
+    */
+    virtual DRError getData(DAQFormats::EventFull*& theEvent, int64_t pos) = 0;
+    virtual DRError getData(DAQFormats::EventFull*& theEvent) = 0; 
+    //    virtual DRError getDataPreAlloced(unsigned int &eventSize, char **event, int64_t allocSizeInBytes) = 0;
+ 
+    //    virtual DRError getDataPreAllocedWitPos(unsigned int &eventSize, char **event,  int64_t allocSizeInBytes, int64_t pos = -1) = 0; 
+ 
+ 
+    /** name of the current file */
+    virtual std::string fileName() const = 0;
+     
+    /** get the current offset within the file */
+    virtual int64_t getPosition() const = 0;
+
+    /** 
+	  The following methogs give access to metadata stored in the files.
+	  
+	    Dates and times are the local time of the PC that was writing tha data file.
+	      Human-readable encoding as integers was used. 
+	        For instance date 31012007 is 31 Jan 2007.
+		  Time 184422 is 18:44:22. 
+
+		    The following information is available without penalty at any stage during reading:
+    */
+    virtual unsigned int fileStartDate() const = 0; ///< Date when the file writing has started.
+    virtual unsigned int fileStartTime() const = 0; ///< Time when the file writing was started.
+    virtual unsigned int fileSizeLimitInDataBlocks() const = 0; ///< Maximum number of data blocks that was given when writing.
+    virtual unsigned int fileSizeLimitInMB() const = 0; ///< Maximum size in MB given when writing.
+    virtual std::string appName() const = 0;       ///< Name of the application that has written the file.
+    virtual std::string fileNameCore() const = 0;  ///< File name not including ._<file number>.data
+
+    /** 
+	  The following parameters of the run come from the Information System of the DAQ. 
+	    The information is also available without penalty at any stage during reading.
+    */
+    virtual unsigned int runNumber() const = 0;    ///< Run number 
+    virtual unsigned int maxEvents() const = 0;    ///< Maximum number of events specified for this run
+    virtual unsigned int recEnable() const = 0;    ///< Was recording enabled?     
+    virtual unsigned int triggerType() const = 0;  ///< Trigger type
+    virtual std::bitset<128> detectorMask() const = 0; ///< Detector mask
+    virtual unsigned int beamType() const = 0;     ///< Beam type
+    virtual unsigned int beamEnergy() const = 0;   ///< Beam energy
+    virtual std::vector<std::string> freeMetaDataStrings() const = 0; ///< Vector of strings containing metadata
+
+    /// Unique ID of the file represened as a string on POOL style.
+    /// For instance 10605EAF-52B1-DB11-94A4-000347D7BFE1
+    virtual std::string GUID() const = 0; 
+
+    virtual CompressionType compression() const = 0; ///< File compression technology
+
+    /** 
+	  The following methods will rewind to the end of file.
+	    Reading of data can continue undisturbed. 
+    */    
+    virtual unsigned int fileEndDate() = 0;            ///< Date when writing has stopped.
+    virtual unsigned int fileEndTime() = 0;            ///< Time when writing has stopped.
+    virtual unsigned int eventsInFile() = 0;           ///< Number of events in this file.
+    virtual unsigned int dataMB_InFile() = 0;          ///< Number of megabytes in this file.
+    virtual unsigned int eventsInFileSequence() = 0;   ///< Number of events in this file sequence written so far.
+    virtual unsigned int dataMB_InFileSequence() = 0;  ///< Number of MB in this file sequence written so far. 
+
+    virtual uint32_t lumiblockNumber() = 0;
+    virtual std::string stream() = 0;
+    virtual std::string projectTag() = 0;
+
+  };
+
+}
+
+#endif // EVENTSTORAGE_DATAREADER_H
+
+
+
+
diff --git a/Event/FaserEventStorage/FaserEventStorage/ESCompression.h b/Event/FaserEventStorage/FaserEventStorage/ESCompression.h
new file mode 100644
index 000000000..bf6f1e957
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/ESCompression.h
@@ -0,0 +1,20 @@
+//Dear emacs, this is -*- c++ -*-
+
+#ifndef FASEREVENTSTORAGE_ESCOMPRESSION_H
+#define FASEREVENTSTORAGE_ESCOMPRESSION_H
+
+#include <string>
+#include "ers/ers.h"
+
+namespace FaserEventStorage {
+      
+  enum CompressionType { NONE, RESERVED, UNKNOWN, ZLIB};
+
+  static const std::string compressiontag("Compression");
+  
+  CompressionType string_to_type(const std::string& type);
+  std::string type_to_string(const CompressionType& type);
+
+}
+
+#endif
diff --git a/Event/FaserEventStorage/FaserEventStorage/EventStorageIssues.h b/Event/FaserEventStorage/FaserEventStorage/EventStorageIssues.h
new file mode 100644
index 000000000..c01990455
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/EventStorageIssues.h
@@ -0,0 +1,134 @@
+#ifndef FASEREVENTSTORAGEISSUES_H
+#define FASEREVENTSTORAGEISSUES_H
+
+#include "ers/ers.h"
+
+
+/**
+   To report problems with configuration data base
+*/
+
+
+
+ERS_DECLARE_ISSUE(FaserEventStorage,
+		  WritingIssue,
+		  "FaserEventStorage writing problem" << ": " << reason,
+		  ((const char*) reason)
+		  )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_SingleFile,
+		       FaserEventStorage::WritingIssue,
+		       "ES_SingleFile" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_SingleFileAlreadyExists,
+		       FaserEventStorage::WritingIssue,
+		       "ES_SingleFileAlreadyExists" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+
+
+
+ERS_DECLARE_ISSUE(FaserEventStorage,
+		  ReadingIssue,
+		  "FaserEventStorage reading problem" << ": " << reason,
+		  ((const char*) reason)
+		  )
+
+ERS_DECLARE_ISSUE(FaserEventStorage,
+		  RawFileNameIssue,
+		  "FaserEventStorage problem with RawFileName" << ": " << reason,
+		  ((const char*) reason)
+		  )
+
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_InternalError,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_InternalError" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_WrongFileFormat,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_WrongFileFormat" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_OutOfFileBoundary,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_OutOfFileBoundary" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_NoEventFound,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_NoEventFound" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_WrongEventSize,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_WrongEventSize" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_NoEndOfFileRecord,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_NoEndOfFileRecord" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_AllocatedMemoryTooLittle,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_AllocatedMemoryTooLittle" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_AllocatingMemoryFailed,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_AllocatingMemoryFailed" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+
+
+ERS_DECLARE_ISSUE_BASE(FaserEventStorage,
+		       ES_SquenceNextFileMissing,
+		       FaserEventStorage::ReadingIssue,
+		       "ES_SquenceNextFileMissing" << ": " << reason  ,
+		       ((const char*) reason), ERS_EMPTY
+		       )
+
+
+
+/*
+ES_InternalError
+
+ES_WrongFileFormat
+
+ES_OutOfFileBoundary
+ES_NoEventFound
+ES_WrongEventSize
+
+
+ES_NoEndOfFileRecord
+ES_AllocatedMemoryTooLittle
+
+
+
+*/
+
+#endif
diff --git a/Event/FaserEventStorage/FaserEventStorage/EventStorageRecords.h b/Event/FaserEventStorage/FaserEventStorage/EventStorageRecords.h
new file mode 100644
index 000000000..129b128df
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/EventStorageRecords.h
@@ -0,0 +1,126 @@
+/**
+   \brief metadata records for EventStorage library
+   \author Szymon Gadomski
+   \date January 2004
+*/
+
+#ifndef FASEREVENTSTORAGE_RECORDS_H
+#define FASEREVENTSTORAGE_RECORDS_H
+
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+// version of file format
+#define FILE_FORMAT_VERSION 0x00000006
+
+// markers as in DAQ-1
+#define FILE_START_MARKER 0x1234aaaa
+#define RUN_PARAMETERS_MARKER 0x1234bbbb
+
+#define EVENT_RECORD_MARKER 0x1234cccc
+
+#define STRING_SECTION_MARKER 0x1234aabb
+#define FREE_STRINGS_MARKER 0x1234aabc
+
+#define FILE_END_MARKER 0x1234dddd
+#define FILE_END_MARKER_LAST 0x1234eeee
+
+namespace FaserEventStorage {
+    
+  struct  file_start_record 
+  {
+    uint32_t marker;         /* Start of record marker          */
+    uint32_t record_size;    /* Total record size               */
+    uint32_t version;        /* Format version number           */
+    uint32_t file_number;    /* File number in the sequence     */
+    uint32_t date;           /* Date of run start               */
+    uint32_t time;           /* Time of run start               */
+    uint32_t sizeLimit_dataBlocks;  /* Max number of data blocks in the file */
+    uint32_t sizeLimit_MB;   /* Max number of data blocks in the file */
+  };
+
+  struct file_name_strings {
+    std::string appName;     
+    std::string fileNameCore; 
+  };
+
+  typedef std::vector<std::string> freeMetaDataStrings;
+
+  struct run_parameters_record {
+    uint32_t marker;         /* Start of record marker          */
+    uint32_t record_size;    /* Total record size               */
+    uint32_t run_number;     /* From IS                         */
+    uint32_t max_events;     /* From IS                         */
+    uint32_t rec_enable;     /* From IS                         */
+    uint32_t trigger_type;   /* From IS                         */
+    uint64_t detector_mask_LS;  /* From IS                      */
+    uint64_t detector_mask_MS;    /* From IS                      */
+    uint32_t beam_type;      /* From IS                         */
+    uint32_t beam_energy;    /* From IS                         */
+  };
+
+  struct data_separator_record {
+    uint32_t marker;      /* Start of record marker          */
+    uint32_t record_size;    /* Total record size               */
+    uint32_t data_block_number;  /* Index in the file sequence      */  
+    uint32_t data_block_size;    /* Size of the following block of data */
+  };
+
+  struct file_end_record {
+    uint32_t marker;         /* Start of record marker          */
+    uint32_t record_size;    /* Total record size               */
+    uint32_t date;           /* Date of run end                 */
+    uint32_t time;           /* Time of run end                 */
+    uint32_t events_in_file; /* Number of events recorded       */
+    uint32_t data_in_file;   /* Volume of data recorded         */
+    uint32_t events_in_run;  /* Number of events recorded       */
+    uint32_t data_in_run;    /* Volume of data recorded         */
+    uint32_t status;         /* Used to mark the last file. Other use possible in the future.*/
+    uint32_t end_marker;     /* End of RUNEND marker            */
+  };
+
+  // implement patterns
+  const uint32_t file_name_strings_marker = STRING_SECTION_MARKER;
+  const uint32_t free_strings_marker = FREE_STRINGS_MARKER;
+
+  const file_start_record file_start_pattern = {
+    FILE_START_MARKER,                  
+    sizeof(file_start_record)/sizeof(uint32_t),     
+    FILE_FORMAT_VERSION,                
+    0,                                  
+    0,                                  
+    0,
+    0,
+    0
+  };
+
+  const data_separator_record data_separator_pattern = {
+    EVENT_RECORD_MARKER,        
+    sizeof(data_separator_record)/sizeof(uint32_t),           
+    0,    
+    0     
+  };
+
+  const file_end_record file_end_pattern = {
+    FILE_END_MARKER,         
+    sizeof(file_end_record)/sizeof(uint32_t),          
+    0,          
+    0,          
+    0, 
+    0,   
+    0,  
+    0,    
+    0,    
+    FILE_END_MARKER_LAST    
+  };
+
+  std::string string_record(void *ri, const void *pi);
+  std::string string_record(file_name_strings nst);
+  void reset_record(void *ri, const void *pi);
+
+} // for namespace
+
+#endif // EVENTSTORAGE_RECORDS_H
+
+
diff --git a/Event/FaserEventStorage/FaserEventStorage/FileNameCallback.h b/Event/FaserEventStorage/FaserEventStorage/FileNameCallback.h
new file mode 100644
index 000000000..4a536cd10
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/FileNameCallback.h
@@ -0,0 +1,39 @@
+/**
+ \brief an interface for a call back class
+ \file EventStorage/FileNameCallback.h
+
+ a class to separate the generation of file names from the DataWriter
+
+ \author Cyril Topfel
+ \date December 2009
+*/
+
+#ifndef FASEREVENTSTORAGE_FILENAMECALLBACK_H
+#define FASEREVENTSTORAGE_FILENAMECALLBACK_H
+
+#include <string>
+
+namespace FaserEventStorage {
+  
+class FileNameCallback
+{
+ public:
+  virtual ~FileNameCallback() {};
+
+  virtual void advance() = 0;
+  virtual std::string getCurrentFileName(bool writing=false) = 0;
+  virtual std::string getCoreName() = 0;
+  /*  virtual std::string getFileNameByIndex(int index);*/
+  virtual unsigned int getIndex() = 0;
+  virtual void fileAlreadyExists() = 0;
+  
+  
+
+};
+
+}
+#endif // EVENTSTORAGE_FILENAMECALLBACK_H
+
+
+
+
diff --git a/Event/FaserEventStorage/FaserEventStorage/RawFileName.h b/Event/FaserEventStorage/FaserEventStorage/RawFileName.h
new file mode 100644
index 000000000..b1c57ff74
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/RawFileName.h
@@ -0,0 +1,263 @@
+/** 
+    \brief Class describing filenames of raw data in a format agreed for ATLAS; contruct, interpret and modify such file-names.
+    \author Kostas Kordas
+    \date Oct 2008
+    \file EventStorage/RawFileName.h
+*/
+
+#ifndef FASEREVENTSTORAGE_ONLINEFILENAME_H
+#define FASEREVENTSTORAGE_ONLINEFILENAME_H
+
+#include "FaserEventStorage/EventStorageIssues.h"
+#include "FaserEventStorage/FileNameCallback.h"
+//-----------------
+// includes for ers
+#include "ers/ers.h"
+//-----------------
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <stdexcept>
+
+
+
+namespace daq
+{
+
+  /**
+   *  Constants associated with the RAW file name convention
+   * --------------------------------------------------------
+   */
+  // extenstions of files and delimiter between fields:
+  static const std::string  RAWFILENAME_EXTENSION_UNFINISHED    = ".writing";
+  static const std::string  RAWFILENAME_EXTENSION_FINISHED      = ".data";
+  static const std::string  RAWFILENAME_DELIMITER               = ".";
+  // defaults:
+  static const unsigned int RAWFILENAME_DEFAULT_UINT            = 0;
+  static const std::string  RAWFILENAME_DEFAULT_STRING          = ""; 
+  //  width of some file name fields, for proper padding:
+  static const unsigned int RAWFILENAME_RUN_NUMBER_LENGTH       = 8;
+  static const unsigned int RAWFILENAME_LB_NUMBER_LENGTH        = 4;
+  static const unsigned int RAWFILENAME_FILE_NUMBER_LENGTH      = 4;
+  static const unsigned int RAWFILENAME_RUN_NUMBER_LENGTH_OLD   = 7;
+  static const unsigned int RAWFILENAME_FILE_NUMBER_LENGTH_OLD  = 2;
+
+
+  /**
+   * Helper class for exceptions
+   */
+  class BadConversion : public std::runtime_error {
+  public:
+  BadConversion(const std::string& s) : std::runtime_error(s) { }
+  };
+
+  /**
+   * The class implementing the online filename convention
+   */
+  class RawFileName : public FaserEventStorage::FileNameCallback {
+  public:
+    /**
+     * Contructor with all ingredients given
+     * Note: Extension will be made to start with '.' (e.g., "data" -> ".data")
+     */
+    RawFileName(std::string ProjectTag,
+		unsigned int RunNumber,
+		std::string StreamType,
+		std::string StreamName,
+		unsigned int LumiBlockNumber,
+		std::string ApplicationName,
+		std::string ProductionStep="daq",
+		std::string DataType="RAW",
+		unsigned int FileSequenceNumber=1,
+		std::string Extension="");
+    
+
+
+    void advance();
+    std::string getCurrentFileName(bool writing);
+    /*  virtual std::string getFileNameByIndex(int index);*/
+
+    std::string getCoreName();
+
+
+    unsigned int getIndex();
+    void fileAlreadyExists();
+
+
+    
+    /**
+     * Constructor with the FileNameCore, a FileSequenceNumber and 
+     * the Extension only - 
+     *  Does not alter the FileNameCore, just attaches trailer fields 
+     *  to the fileNameCore; also, tries to interpret the resulting filename
+     *  Note: Extension will be made to start with '.' (e.g., "data" -> ".data")
+     */
+    RawFileName(std::string FileNameCore,
+		unsigned int FileSequenceNumber,
+		std::string Extension="");
+
+    /**
+     * Contructor with just the filename given: for interpretation
+     */   
+    RawFileName(std::string FileName);
+     
+    /**
+     * Destructor
+     */
+    ~RawFileName();
+
+    /**
+     * given the ingedients, contruct the fileName
+     */
+    void buildFileName(std::string ProjectTag,
+		       unsigned int RunNumber,
+		       std::string StreamType,
+		       std::string StreamName,
+		       unsigned int LumiBlockNumber,
+		       std::string ApplicationName,
+		       std::string ProductionStep,
+		       std::string DataType,
+		       unsigned int FileSequenceNumber,
+		       std::string Extension);
+    
+    /**
+     * given the ingedients, contruct the fileNameCore 
+     * and set m_core_known = true
+     */
+    void buildFileNameCore(std::string ProjectTag,
+			   unsigned int RunNumber,
+			   std::string StreamType,
+			   std::string StreamName,
+			   unsigned int LumiBlockNumber,
+			   std::string ApplicationName,
+			   std::string ProductionStep,
+			   std::string DataType);
+
+    /**
+     * Complete the FileName, 
+     * by appending a FileSequenceNumber and an Extension to the FileNameCore
+     * and set m_trailers_known = true
+     * Note: Extension will be made to start with '.' (e.g., "data" -> ".data")
+     */
+    void buildFileNameTrailers(std::string FileNameCore, 
+			       unsigned int FileSequenceNumber,
+			       std::string Extension);
+
+    /**
+     * given the fileName, reconstruct the ingredients
+     */
+    bool interpretFileName(std::string FileName); 
+
+    /**
+     * contruct the complain
+     */
+    std::string complain();
+ 
+    /**
+     * print the content of this object
+     */
+    void print();
+
+    /**
+     * Get methods:
+     * ------------
+     */
+    std::string project();
+    unsigned int runNumber();
+    std::string streamType();
+    std::string streamName();
+    std::string stream();
+    unsigned int lumiBlockNumber();
+    std::string applicationName();
+    std::string productionStep();
+    std::string dataType();
+    unsigned int fileSequenceNumber();
+    std::string extension();
+
+    std::string fileNameCore() { return m_fileNameCore; }
+    std::string fileName() { return m_fileName; }
+
+    bool hasValidCore() { return m_core_known; }
+    bool hasValidTrailer() { return m_trailer_known; }
+
+    std::string datasetName();
+
+    /**
+     * Set methods:
+     * ------------
+     */
+
+    /**
+     * Default values for the filename fields 
+     * If filename is valid, the correct values will be returned when asked.
+     */
+    void setDefaults();
+
+    /**
+     * Modify the File Trailer fileds (FileSequence Number and  Extension)
+     */
+    void setTailers(unsigned int fsn_i, std::string extension_s); 
+
+    /**
+     * Modify the FileSequenceNumber at the file trailer fields
+     */
+    void setFileSequenceNumber( unsigned int fsn_i );
+
+    /**
+     * Modify the File Extension at the file trailer fields
+     */
+    void setExtension( std::string extension_s );
+    
+
+  public: 
+    /** 
+     *  Helper methods: made static for use even without an object
+     * ------------------------------------------------------------
+     */
+
+    /**
+     * given a string and a delimeter, split it in fields and return them in 
+     * a vector of strings
+     */
+    static std::vector<std::string> split(std::string const & s, 
+					  char delimiter);
+
+    /**
+     * string to integer conversion
+     */ 
+    static unsigned int convertToUINT(const std::string & s);
+
+
+  private:
+    /**
+     * Member data:
+     * ------------
+     */
+    std::string m_project;
+    unsigned int m_runNumber;
+    std::string m_streamType;
+    std::string m_streamName;
+    std::string m_stream;
+    unsigned int m_lumiBlockNumber;
+    std::string m_applicationName;
+    std::string m_productionStep;
+    std::string m_dataType;
+    std::string m_fileNameCore;
+
+    unsigned int m_fileSequenceNumber;
+    std::string m_extension;
+    std::string m_fileName;
+
+    std::string m_datasetName;
+
+    bool m_core_known;
+    bool m_trailer_known;
+    
+  }; // end RawFileName class declaration
+
+} // end "daq" namespace
+
+#endif // EVENTSTORAGE_ONLINEFILENAME_H
diff --git a/Event/FaserEventStorage/FaserEventStorage/fRead.h b/Event/FaserEventStorage/FaserEventStorage/fRead.h
new file mode 100644
index 000000000..ad4c1e8d9
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/fRead.h
@@ -0,0 +1,70 @@
+/**
+ \brief EventStorage library, an abstract interface for file I/O operations
+ \author Szymon Gadomski
+ \file EventStorage/fRead.h
+ \date Feb 2006 - Feb 2007
+
+ This is needed to support dufferent file I/O libraries:
+ - castor files are accessible with shift library,
+ - plain disk files need to be readable on computers without the shift lib,
+ - dCache is an alternative to Castor used at various sites for ATLAS.
+*/
+
+#ifndef FREAD_H
+#define FREAD_H
+
+#include <string>
+#include <stdint.h>
+
+class fRead 
+{
+ public:
+  fRead()
+    {
+      m_currentEndOfFile = -1;
+    };
+ 
+  virtual ~fRead() {}; 
+
+  uint32_t readuint32_t()
+  {
+    int64_t op = getPosition();
+    uint32_t myint;
+    readData((char*)&myint, sizeof(uint32_t));
+    setPosition(op);
+    return myint;
+  }
+
+  virtual bool isOpen() = 0;
+  virtual bool isEoF() = 0;
+  virtual bool fileExists(std::string name) const = 0;
+  virtual void openFile(std::string name) = 0;
+  virtual void closeFile() = 0;
+  virtual void readData(char *buffer, unsigned int sizeBytes) = 0;
+  virtual int64_t getPosition() = 0;
+  virtual void setPosition(int64_t p) = 0;
+  virtual void setPositionFromEnd(int64_t p) = 0;
+  
+  void setCurrentEndOfFile(int64_t p)
+  {
+    m_currentEndOfFile = p;
+  }
+  
+  void setPositionFromEndSafe(int64_t p)
+  {
+    if (m_currentEndOfFile==-1) setPositionFromEnd(p);
+    else
+      setPosition( m_currentEndOfFile + p);
+  }
+
+  virtual fRead * newReader() const = 0;
+
+ private:
+  int64_t m_currentEndOfFile;
+
+};
+
+extern "C" {
+  fRead *fReadFactory();
+}
+#endif 
diff --git a/Event/FaserEventStorage/FaserEventStorage/loadfRead.h b/Event/FaserEventStorage/FaserEventStorage/loadfRead.h
new file mode 100644
index 000000000..284bc8dbf
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/loadfRead.h
@@ -0,0 +1,14 @@
+/**
+   \brief Function to load the file lib wrapper class.
+   \author Szymon Gadomski
+   \date February 2006
+*/
+
+#ifndef FASEREVENTSTORAGE_LOADFREAD_H
+#define FASEREVENTSTORAGE_LOADFREAD_H
+
+#include "FaserEventStorage/fRead.h"
+
+fRead * loadfRead(std::string libName);
+
+#endif
diff --git a/Event/FaserEventStorage/FaserEventStorage/pickFaserDataReader.h b/Event/FaserEventStorage/FaserEventStorage/pickFaserDataReader.h
new file mode 100644
index 000000000..e809a363d
--- /dev/null
+++ b/Event/FaserEventStorage/FaserEventStorage/pickFaserDataReader.h
@@ -0,0 +1,26 @@
+/**
+ \brief Function to choose the correct reader of the data files.
+
+ It recognizes data file formats of 2003 and later.
+ It chooses a file I/O library for plain disk files, Castor 
+ files or dCache files.
+
+ \file EventStorage/pickDataReader.h
+ \author Szymon Gadomski
+ \date Feb 2004 - Feb 2007
+*/
+
+#ifndef FASEREVENTSTORAGE_PICKDATAREADER_H
+#define FASEREVENTSTORAGE_PICKDATAREADER_H
+
+#include "FaserEventStorage/DataReader.h"
+#include <string>
+
+/**
+   \param fileName the name of the data file to read
+*/
+FaserEventStorage::DataReader * pickFaserDataReader(std::string fileName);
+
+
+
+#endif
diff --git a/Event/FaserEventStorage/README b/Event/FaserEventStorage/README
new file mode 100644
index 000000000..a2a79b9a1
--- /dev/null
+++ b/Event/FaserEventStorage/README
@@ -0,0 +1,4 @@
+FaserEventStorage
+
+FASER version of utility pakcage EventStorage taken from here:
+https://gitlab.cern.ch/atlas-tdaq-software/EventStorage/-/tree/master/
diff --git a/Event/FaserEventStorage/src/DataReaderController.cxx b/Event/FaserEventStorage/src/DataReaderController.cxx
new file mode 100644
index 000000000..10c545005
--- /dev/null
+++ b/Event/FaserEventStorage/src/DataReaderController.cxx
@@ -0,0 +1,681 @@
+#include <memory>
+#include <sstream>
+#include <iomanip>
+
+
+#include "ers/ers.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+#include "FaserEventStorage/fRead.h" 
+#include "DataReaderController.h"
+#include "EventStorage/RawFileName.h"
+#include "EventStackLayer.h"
+#include "ESLMultiFile.h"
+//#include "ESLMergeFile.h"
+#include "ESLOriginalFile.h"
+#include "EventFormats/DAQFormats.hpp"
+
+using namespace std;
+using namespace FaserEventStorage;
+
+
+DataReaderController::DataReaderController(fRead *fR, string filename)
+{
+  m_fR = fR; //the raw reader
+  m_fileName = filename; //the initial filename
+  
+  m_sequenceReading = false; //seq reading off per default 
+  m_finished = false;
+  m_last_file_finished = false ;
+
+  m_markForDeletion = 0;
+  m_responsibleForMetaData = 0;
+
+  //This is the entry Point, it always starts with a MultiFileReader
+  m_filehandler = new FESLMultiFile(m_fR);
+
+  ERS_DEBUG(1,"filehandler instantiated " << m_filehandler->identify() );
+
+  m_filehandler->setFile(filename);
+
+  ERS_DEBUG(3,"filehandler file set " << m_filehandler->identify() <<  " " << filename);
+
+  // ET doesn't do anything, so OK
+  m_filehandler->prepare();
+
+  ERS_DEBUG(3,"filehandler " << m_filehandler->identify() << " prepared.");
+
+  m_stack.push(m_filehandler);
+
+  m_cFileNumber = 0; 
+  m_sizeOfFileNumber = 0;
+
+  initialize();
+
+  ERS_DEBUG(3,"Initialization complete. Exiting Controller Constructor ");
+}
+
+DataReaderController::~DataReaderController()
+{
+  if (m_fR && m_fR->isOpen()) m_fR->closeFile();
+
+  while (!m_stack.empty()) {
+    EventStackLayer *tmp = m_stack.top(); 
+    m_stack.pop();
+    if (tmp != m_markForDeletion and tmp != m_filehandler)
+      delete tmp;
+  }
+
+  if (m_markForDeletion != 0)
+    {
+      delete m_markForDeletion;
+      m_markForDeletion = 0;
+    }
+  
+  if(m_filehandler) delete m_filehandler;
+  if(m_fR) delete m_fR;
+}
+
+
+void DataReaderController::initialize()
+{
+
+  //Now we load all the Instances onto the stack. filehandler will return an instance of type ESLMergeFile or ESLOriginalFile, this instance will report (method doneLoading) if it is finished. In case of the Originalfilereader, this will be true, in case of the MergeFileReader, this will be false, because the mergereader will want to load an originalfile inside. The process continues and the stack is filled. The resulting Stack should have a top element ready for Data to be read. 
+
+  bool done=false;
+  while (!done)
+    {
+      ERS_DEBUG(2, m_stack.top()->identify() << " openNext() called");
+      EventStackLayer *ELSnew = m_stack.top()->openNext();
+      ERS_DEBUG(2, ELSnew->identify() << " instantiated");
+
+      
+      //ELSnew->prepare();
+      // prepare is already done in openNext.
+      
+      if (ELSnew->responsibleforMetaData())
+	{
+	  //if this lyer is responsible for metadata, it is linked to the internal pointer of Controller. Controller will the relay metadata requests to this layer. great.
+	  m_responsibleForMetaData = ELSnew;
+	}
+      
+      ELSnew->setCaller(m_stack.top());
+      
+      m_stack.push( ELSnew );
+      ERS_DEBUG(2, ELSnew->identify() << " put on stack");
+
+      done = ELSnew->doneLoading();
+      ERS_DEBUG(2, ELSnew->identify() << " reported doneLoading: " << done);
+    }
+
+}
+
+bool DataReaderController::good() const
+{  
+  return m_stack.size()? m_stack.top()->moreEvents():false;
+}
+
+bool DataReaderController::endOfFile() const
+{
+  //this is just to keep compatibility with calling code. they want to know i f a file just finished
+
+  bool a = m_last_file_finished;
+  //m_last_file_finished = false;
+  return a;
+}
+
+bool DataReaderController::endOfFileSequence() const
+{
+  return false;
+}  
+
+
+
+//DRError DataReaderController::getData(unsigned int &eventSize, char **event, int64_t pos = -1 , bool memAlreadyAlloc = false, int64_t allocSizeInBytes = -1)
+DRError DataReaderController::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
+{
+
+  int64_t oldpos = 0;
+  m_last_file_finished=false;
+
+
+  if (m_markForDeletion != 0)
+    {
+      delete m_markForDeletion;
+      m_markForDeletion = 0;
+    }
+
+  //if the position is defined, we need to remember the old position
+  //and jump to the given position
+  if ( pos != -1) 
+    {
+      oldpos = this->getPosition();
+      this->setPosition(pos);
+    }
+
+
+  DRError res =  m_stack.top()->getData(theEvent, -1);
+
+
+
+  //if position was defined, we need to jump back to the old position BEFORE checking for more events. Else if we are reading by offset, the program will crash.
+  if ( pos != -1) 
+    {
+      this->setPosition(oldpos);
+    }
+
+
+
+  if ( !(m_stack.top()->moreEvents()) )
+    {
+      ERS_DEBUG(2, " No more Events on top of stack ");
+      //this is the "main loop". It handles the switching from one originalfile to the next, from one mergefile to the next etc.
+      while ( !m_stack.empty() && !m_stack.top()->moreEvents() )
+{
+  ERS_DEBUG(2, m_stack.top()->identify() << " has more events?: answer was " << m_stack.top()->moreEvents() );
+
+  EventStackLayer *old = m_stack.top();    
+  bool success = old->finished();
+
+  //the following line we only use to report to the caller that just a file was closed
+  if ( m_responsibleForMetaData == old )
+    m_last_file_finished = true;
+
+    
+  ERS_DEBUG(2,  old->identify() << " finished? " << success);
+
+  m_stack.pop();
+    
+  ERS_DEBUG(2, " Popping " << old->identify() << " from stack");
+
+  if (success && !m_stack.empty()) m_stack.top()->advance(); 
+
+  if (!m_stack.empty() && m_stack.top()->handlesContinuation())
+    {
+      bool end = (old->endOfFileSequence() || !m_sequenceReading);
+      if (!end)
+{
+  //if the continuation is given, we ask for the next file
+  unsigned int nextSN = old->nextInSequence(m_cFileNumber);
+  ERS_DEBUG(2, " Next in Sequence is " << nextSN);
+  string next = this->nextInContinuation(nextSN);
+
+  m_stack.top()->setContinuationFile(next);
+
+}
+     
+    } //if continuation is not handled, nothing happens
+  if (old != m_responsibleForMetaData && old != m_filehandler)
+            {
+      //we preserve the m_metaDataResponsible Object. 
+              delete old;
+            }
+          else if (old == m_responsibleForMetaData)
+            {
+	      //the user probably still wants to read metadata, so we keep in mind that in the next get_data, this must be deleted
+              m_markForDeletion = old;
+            }
+  //while-loop will just continue to pop
+ } //end of while loop 
+      
+      if (m_stack.empty())
+	{
+	  //if the stack is empty, we are finished
+	  ERS_DEBUG(1, " Run finished, no more events ");
+	  m_finished = true;
+	}
+      else
+	{
+	  ERS_DEBUG(2, " Continuing ");
+	  //this will put the next redable item(s) on the stack
+	  initialize();
+	}
+      
+    }//end of moreEvents
+
+  //now everything should be in order, so let's read data
+  
+
+  return res;
+
+}
+
+DRError DataReaderController::getData(DAQFormats::EventFull*& theEvent) {
+  return getData(theEvent, -1);
+}
+/*
+DRError DataReaderController::getDataPreAlloced(unsigned int &eventSize, char **event, int64_t allocSizeInBytes)
+{
+  return getData(eventSize, event, -1, true, allocSizeInBytes);
+}
+
+DRError DataReaderController::getDataPreAllocedWitPos(unsigned int &eventSize, char **event,  int64_t allocSizeInBytes, int64_t pos ) 
+{
+  return getData(eventSize, event, pos, true, allocSizeInBytes);
+}
+*/
+
+
+void DataReaderController::setPosition(int64_t position)
+{
+  //if a setPosition takes place, only the instance on the stack that can handle position can do it. We are poppoing the stack until we find a responsible Instance.
+  
+  EventStackLayer *old = 0;
+
+  while ( !m_stack.top()->handlesOffset() )
+    {
+
+      old = m_stack.top();
+      m_stack.pop();
+      //delete old;
+      // WARNING: possible memory leak, if more than one Layer is popped. This should not be possible in current implementation. 
+      if (m_stack.empty()) 
+	{
+	  FaserEventStorage::ES_InternalError ci(ERS_HERE, "EventStack is empty. This should not happen.");
+	  throw ci;
+
+	}
+    }
+  //now we should be at the instance where the responisble instance is at top. 
+
+  //Please note: This only works if OriginalFile Layer is the last after Mergefile layer. There is however no reason yet to think this will change. famous last words :-~
+
+  EventStackLayer *off = m_stack.top()->loadAtOffset(position, old);
+
+  if (! (m_stack.top() == off) )
+    {
+      m_stack.push( off );
+    }
+  
+    
+  if (old && old != off) //we need to delete the old one, if the new one is not the same as the old one
+    {
+      //ERS_DEBUG(1, " deleting old " << old);
+      delete old;
+    }
+  //after this procedure, the correct originalFilehandler should be on top of the stack and ready for reading
+
+  m_finished = false;//we assume the user knows what he's doing and doesnt jump to an end of a file
+  
+  
+}
+
+int64_t DataReaderController::getPosition() const
+{
+  return m_fR->getPosition();
+}
+
+std::string DataReaderController::fileName() const
+{
+  return m_responsibleForMetaData->fileName();
+}
+
+unsigned int DataReaderController::fileStartDate() const
+{
+  return m_responsibleForMetaData->fileStartDate();
+}
+
+unsigned int DataReaderController::fileStartTime() const
+{
+  return m_responsibleForMetaData->fileStartTime();
+}
+
+
+unsigned int DataReaderController::currentFileNumber() const 
+{ 
+  return m_cFileNumber; 
+}
+
+
+DRError DataReaderController::enableSequenceReading()
+{
+  ERS_DEBUG(2,"DataReaderBase::enableSequenceReading() is called. "
+	    <<"Try parsing file name\n"<<m_fileName);
+
+  daq::RawFileName thename(m_fileName);
+  
+  if (!thename.hasValidTrailer()) 
+    {
+      ERS_DEBUG(1," Test of file name parsing has failed. "
+		<<"File sequence reading not enabled.");
+      return DRNOSEQ;
+    } 
+  else 
+    {
+      m_sizeOfFileNumber = daq::RAWFILENAME_FILE_NUMBER_LENGTH;
+      m_cFileNumber = thename.fileSequenceNumber();
+      m_fileNameCore = thename.fileNameCore();
+      
+      ERS_DEBUG(1," fileNameCore: " << m_fileNameCore);
+      
+      m_sequenceReading=true;
+      
+      // check if the actual name of this file corresponds to 
+      // the fileName reported inside the file
+      std::string test = fileName();  // name from meta-data inside the file
+      if(test != m_fileName)
+	{
+	  ERS_DEBUG(1," The name of this file is different from the fileName "
+		    << " reported inside the file itself. "
+		    << "File sequence reading not enabled.");
+	  return DRNOSEQ;
+	}
+      
+      return DROK;
+    }
+
+  /**** OLD code here - will be trhown away in due time
+
+  std::string tail= daq::RAWFILENAME_EXTENSION_FINISHED;
+
+  std:: string::size_type tailPos=m_fileName.rfind(tail);
+
+  if(tailPos==std::string::npos) {
+  ERS_DEBUG(3,"File name does not contain "<<tail);
+  return DRNOSEQ;
+  }
+  if(tailPos+tail.size() != m_fileName.size()) {
+  ERS_DEBUG(3,"File name does not end with "<<tail);
+  return DRNOSEQ; 
+  }
+
+  std::string nameCore=m_fileName.substr(0,tailPos);
+  ERS_DEBUG(3,"File name without the tail "<<nameCore);
+
+  std::string digits("0123456789");
+  std::string::size_type numPos=nameCore.find_last_not_of(digits);
+  ++numPos;
+  if(numPos==string::npos) return DRNOSEQ;
+
+  std::string num=nameCore.substr(numPos,nameCore.size());
+  ERS_DEBUG(3,"Expecting file number in this string <"<<num<<">.");
+
+  m_sizeOfFileNumber=num.size();
+  ERS_DEBUG(3,"Size of the number "<<m_sizeOfFileNumber);
+  if(m_sizeOfFileNumber==0) return DRNOSEQ;
+ 
+  m_cFileNumber=atoi(num.c_str());
+  ERS_DEBUG(3,"File number "<<m_cFileNumber);
+
+  m_fileNameCore=nameCore.substr(0,numPos);
+  ERS_DEBUG(3,"File name core "<<nameCore);
+
+  ERS_DEBUG(2,"Finished parsing, now test the result.");
+
+  m_sequenceReading=true; 
+  
+  std::string test = fileName();
+
+  if(test != m_fileName) {
+  ERS_DEBUG(1,"Test of file name parsing has failed. "
+  <<"File sequence reading not enabled.");
+  return DRNOSEQ;
+  } 
+ 
+  // --m_cFileNumber; // will be incremented at 1st open
+  return DROK;
+  
+  End of OLD code
+  ****/
+}
+
+
+std::string DataReaderController::nextInContinuation(unsigned int expected)
+{
+  int numFailed=20;
+  m_cFileNumber = expected;
+  
+  while(numFailed){
+    std::string next = this->sequenceFileName(true);
+      
+    if (m_fR->fileExists(next)){
+      ERS_DEBUG(2, "fRead reported " << next << " exists");
+      return next;
+    }else{
+      ERS_DEBUG(2, "fRead reported " << next << " does not exist");
+      m_cFileNumber++;
+      numFailed--;
+    }
+  }
+  
+  //Problem
+  FaserEventStorage::ES_SquenceNextFileMissing ci(ERS_HERE, "EndOfSequenceFlag was not found and 18 files with continuous sequnce number were not found. Aborting");
+  throw ci;
+
+  return "";
+}
+
+
+unsigned int DataReaderController::runNumber() const 
+{ 
+  return m_responsibleForMetaData->runNumber();
+}
+unsigned int DataReaderController::maxEvents() const 
+{
+  return m_responsibleForMetaData->maxEvents();
+}
+unsigned int DataReaderController::recEnable() const 
+{
+  return m_responsibleForMetaData->recEnable();
+}
+unsigned int DataReaderController::triggerType() const 
+{
+  return m_responsibleForMetaData->triggerType();
+}
+std::bitset<128> DataReaderController::detectorMask() const 
+{
+  return m_responsibleForMetaData->detectorMask();
+}
+unsigned int DataReaderController::beamType() const 
+{
+  return m_responsibleForMetaData->beamType();
+}
+unsigned int DataReaderController::beamEnergy() const  
+{
+  return m_responsibleForMetaData->beamEnergy();
+}
+
+
+CompressionType DataReaderController::compression() const{
+  return m_responsibleForMetaData->compression();
+}
+
+std::vector<std::string> DataReaderController::freeMetaDataStrings() const
+{
+  ERS_DEBUG(1, "Upper level is " << m_stack.top()->getCaller()->identify());
+  
+  std::vector<std::string> result;
+  //  if (m_stack.top()->getCaller()->identify()=="ESLMerge")
+  //  { //if a mergefiles is read, always return empty metadata
+  //   return result;
+  //  }
+  //  else
+  //  {
+  result = m_responsibleForMetaData->freeMetaDataStrings();
+  //  }
+
+
+  ERS_DEBUG(1, "RESP " << m_responsibleForMetaData->identify() << " ;et");
+
+  
+  std::vector<std::string> cleaned_result;
+  
+  std::vector<std::string> reserved;
+  reserved.push_back("Stream=");
+  reserved.push_back("Project=");
+  reserved.push_back("LumiBlock=");
+  reserved.push_back("GUID=");
+  reserved.push_back("Compression=");
+  
+  
+  for (unsigned int i = 0 ; i < result.size(); i++)
+    {
+      //check for Stream
+      
+      int is_reserved = 0;
+      for (unsigned int res = 0 ; res < reserved.size(); res++)
+	{  
+	  std::string ptn = reserved.at(res);
+	  std::string::size_type pos=result.at(i).find(ptn);
+	  if (pos==std::string::npos)
+	    {
+	      //ERS_DEBUG(1, "String " << result.at(i) << "Not reserved");
+	    }
+	  else
+	    {
+	      ERS_DEBUG(1, "String " << result.at(i) << "reserved");
+	      is_reserved=1;
+	    }
+	}
+      if (!is_reserved)
+	cleaned_result.push_back(result.at(i));
+    
+    }
+
+  return cleaned_result;
+
+  
+}
+
+std::string DataReaderController::GUID() const
+{
+  return m_responsibleForMetaData->GUID();
+}
+
+
+
+unsigned int DataReaderController::fileEndDate()
+{
+  return m_responsibleForMetaData->fileEndDate();
+}
+///< Date when writing has stopped.
+unsigned int DataReaderController::fileEndTime() 
+{
+  return m_responsibleForMetaData->fileEndTime();
+}
+///< Time when writing has stopped.
+unsigned int DataReaderController::eventsInFile() 
+{
+  return m_responsibleForMetaData->eventsInFile();
+}
+///< Number of events in this file.
+unsigned int DataReaderController::dataMB_InFile() 
+{
+  return m_responsibleForMetaData->dataMB_InFile();
+}
+///< Number of megabytes in this file.
+unsigned int DataReaderController::eventsInFileSequence() 
+{
+  return m_responsibleForMetaData->eventsInFileSequence();
+}
+///< Number of events in this file sequence written so far.
+
+
+unsigned int DataReaderController::fileSizeLimitInDataBlocks() const
+{
+  return m_responsibleForMetaData->fileSizeLimitInDataBlocks();
+}
+
+unsigned int DataReaderController::fileSizeLimitInMB() const
+{
+  return m_responsibleForMetaData->fileSizeLimitInMB();
+}
+
+std::string  DataReaderController::appName() const 
+{
+  /*if (m_responsibleForMetaData->identify()=="ESLMerge") 
+    {
+    return m_filehandler->getAppName();
+    }
+    else
+  */
+  return m_responsibleForMetaData->appName();
+}
+
+std::string  DataReaderController::fileNameCore() const 
+{
+  /*if (m_responsibleForMetaData->identify()=="ESLMerge")
+    {
+    return m_filehandler->getFileNameCore();
+    }
+    else*/
+  
+  return m_responsibleForMetaData->fileNameCore();
+}
+
+unsigned int DataReaderController::dataMB_InFileSequence() 
+{
+  ERS_DEBUG(1,"DataReaderController::dataMB_InFileSequence called but not implemented.");
+  return 0;
+  //return m_filehandler->getSum();
+}
+
+
+
+
+///< Number of MB in this file sequence written so far. 
+//unsigned int DataReaderController::fileStatusWord() 
+//{
+//  return m_responsibleForMetaData->fileStatusWord();
+//}
+///< Indicates an end of sequence. 
+
+
+std::string DataReaderController::sequenceFileName(bool isReady) const
+{
+  ERS_DEBUG(2,"DataReaderBase::sequenceFileName(...) is called.");
+    
+  daq::RawFileName name(m_fileNameCore, 
+			m_cFileNumber, 
+			isReady?daq::RAWFILENAME_EXTENSION_FINISHED:daq::RAWFILENAME_EXTENSION_UNFINISHED);
+  ERS_DEBUG(2," fileNameCore: " << m_fileNameCore);
+
+  ERS_DEBUG(2,"sequenceFileName returns " << name.fileName());
+  return name.fileName();
+    
+  /**** OLD code here - will be trhown away in due time
+	std::ostringstream n;
+ 
+	n << m_fileNameCore;
+	n << std::setw(m_sizeOfFileNumber) << std::setfill('0');
+	n << m_cFileNumber;
+
+	if(isReady) n << daq::RAWFILENAME_EXTENSION_FINISHED;
+	else n << daq::RAWFILENAME_EXTENSION_UNFINISHED;
+    
+	std::string name = n.str();
+    
+	ERS_DEBUG(2,"sequenceFileName returns " << name);
+	return name;
+
+	End of OLD code
+  ***/
+}
+
+uint32_t DataReaderController::lumiblockNumber()
+{
+  return m_responsibleForMetaData->lumiblockNumber();
+}
+std::string DataReaderController::stream()
+{
+  return m_responsibleForMetaData->stream();
+}
+std::string DataReaderController::projectTag()
+{
+  return m_responsibleForMetaData->projectTag();
+}
+
+
+
+unsigned int DataReaderController::latestDataNumber() const 
+{
+  return 1;
+}
+
+
+//void mythrowE(std::string errormessage)
+//{
+//  FaserEventStorage::ReadingIssue ci(ERS_HERE, errormessage.c_str());
+//  throw ci;
+//}
+
+
diff --git a/Event/FaserEventStorage/src/DataReaderController.h b/Event/FaserEventStorage/src/DataReaderController.h
new file mode 100644
index 000000000..c55745c4c
--- /dev/null
+++ b/Event/FaserEventStorage/src/DataReaderController.h
@@ -0,0 +1,122 @@
+#ifndef FASERDATAREADERCONTOLLER_H
+#define FASERDATAREADERCONTOLLER_H
+
+#include <fstream>
+#include <vector>
+#include <stack>
+#include <stdint.h>
+
+#include "FaserEventStorage/DataReader.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+
+namespace DAQFormats {
+  class EventFull;
+}
+class EventStackLayer;
+class fRead;
+class FESLMultiFile;
+
+namespace FaserEventStorage
+{
+  
+  class DataReaderController : public DataReader
+  {
+  public:
+    DataReaderController(fRead *fR, std::string filename); 
+    ~DataReaderController();
+    
+    void initialize();
+    
+    DRError enableSequenceReading();
+    
+    void setPosition(); //sets global position in file
+    int64_t getPosition() const;//gets current position in the file
+    void setPosition(int64_t pos);
+    
+    bool good() const;
+    bool endOfFile() const;
+    bool endOfFileSequence() const;  
+
+    unsigned int currentFileNumber() const; 
+
+    
+    //    DRError getData(unsigned int &eventSize, char **event, int64_t pos , bool memAlreadyAlloc, int64_t allocSizeInBytes );
+    DRError getData(DAQFormats::EventFull*& theEvent);
+    DRError getData(DAQFormats::EventFull*& theEvent, int64_t pos);
+
+    //    DRError getDataPreAlloced(unsigned int &eventSize, char **event, int64_t allocSizeInBytes);
+
+    //DRError getDataPreAllocedWitPos(unsigned int &eventSize, char **event,  int64_t allocSizeInBytes, int64_t pos = -1);
+
+
+    /*methods to delete
+      virtual bool fileWasFound() const = 0; 
+      
+    */
+    
+    unsigned int runNumber() const ;
+    unsigned int maxEvents() const ;
+    unsigned int recEnable() const ;
+    unsigned int triggerType() const ;
+    std::bitset<128> detectorMask() const ;
+    unsigned int beamType() const ;
+    unsigned int beamEnergy() const ;
+    std::string GUID() const;
+    
+    
+    std::vector<std::string> freeMetaDataStrings() const;
+
+    CompressionType compression() const;
+
+    std::string fileName() const;
+    
+    unsigned int fileStartDate() const;
+    unsigned int fileStartTime() const;
+    
+    unsigned int fileEndDate();            ///< Date when writing has stopped.
+    unsigned int fileEndTime() ;             ///< Time when writing has stopped.
+    unsigned int eventsInFile() ;          ///< Number of events in this file.
+    unsigned int dataMB_InFile() ;          ///< Number of megabytes in this file.
+    unsigned int eventsInFileSequence() ;   ///< Number of events in this file sequence written so far.
+    unsigned int dataMB_InFileSequence() ; ///< Number of MB in this file sequence written so far. 
+    //unsigned int fileStatusWord() ;         ///< Indicates an end of sequence.
+
+    unsigned int fileSizeLimitInDataBlocks() const ; 
+    unsigned int fileSizeLimitInMB() const ;
+    std::string appName() const ; 
+    std::string fileNameCore() const ;  
+    
+    uint32_t lumiblockNumber();
+    std::string stream();
+    std::string projectTag();
+
+    unsigned int latestDataNumber() const;
+    
+  private:
+    std::string nextInContinuation(unsigned int expected);
+    std::string sequenceFileName(bool isReady) const;
+
+
+  private:
+    std::stack<EventStackLayer*> m_stack;
+    fRead* m_fR;
+    bool m_sequenceReading; 
+    bool m_finished;
+    FESLMultiFile* m_filehandler; //the file handler //now unused
+    bool m_last_file_finished;
+    EventStackLayer* m_responsibleForMetaData;
+    EventStackLayer* m_markForDeletion;
+    
+    unsigned int m_sizeOfFileNumber;
+    unsigned int m_cFileNumber;
+    std::string m_fileNameCore;
+    std::string m_fileName;
+  };
+  
+  // fRead *fReadFactory();
+}
+
+void mythrowE(std::string errormessage);
+
+#endif 
+
diff --git a/Event/FaserEventStorage/src/ESLMultiFile.cxx b/Event/FaserEventStorage/src/ESLMultiFile.cxx
new file mode 100644
index 000000000..f7378e1f7
--- /dev/null
+++ b/Event/FaserEventStorage/src/ESLMultiFile.cxx
@@ -0,0 +1,167 @@
+#include "FaserEventStorage/fRead.h"
+#include "ESLMultiFile.h"
+//#include "ESLMergeFile.h"
+#include "ESLOriginalFile.h"
+#include "DataReaderController.h"
+//#include "MergedRawFile.h"
+#include "EventStorage/RawFileName.h"
+
+FESLMultiFile::FESLMultiFile(fRead* fR) : EventStackLayer(fR) {
+  m_me = "FESLMulti"; 
+  ERS_DEBUG(3, identify() << " Constructor called booya");
+  m_currentFileIndex = 0 ;
+  m_sumsize = 0;
+  m_rawfilename = NULL;
+}  
+
+FESLMultiFile::FESLMultiFile(){ 
+  m_rawfilename = NULL;
+}  
+
+
+//This methods takes the next string from the vector, opens, the file and tries to look at the starting marker. According to this, it decides if the file is an originalfile or a mergefile.
+
+EventStackLayer* FESLMultiFile::openNext()
+{
+  
+  EventStackLayer* nextESL = 0;
+  
+  //m_currentFileIndex++; //this is already done in moreEvents;
+
+ 
+  if ( m_fR->isOpen() ) {
+    ERS_DEBUG(3, " Closing open file ");
+    m_fR->closeFile();
+  }
+
+  std::string next = m_filenames.at(m_currentFileIndex);
+
+  ERS_DEBUG(3, this->identify() << " Trying to open next file: " << next);
+
+  m_fR->openFile(next);
+  
+  ERS_DEBUG(3, this->identify() << " file opened " << next);
+    
+  m_fR->setCurrentEndOfFile(-1);
+
+  ERS_DEBUG(3, this->identify() << " set current end of " << next);
+
+  //m_rawfilename = new daq::RawFileName(next);
+
+  // ET - no marker?
+  //uint32_t marker = m_fR->readuint32_t();
+
+
+  ERS_DEBUG(3, this->identify() << " reading start " << next);
+
+  // ET - comment out everything related to reading file start marker
+  //if ( marker == FILE_START_MARKER) //It's an Original File
+  //  {
+      ERS_DEBUG(1, this->identify() << " found original file");
+
+      FESLOriginalFile* tmpofp = new FESLOriginalFile(m_fR);
+      tmpofp -> setFile(next);
+      tmpofp -> handleOffset();
+      tmpofp -> setResponsibleForMetaData();
+      
+      nextESL = tmpofp;
+  //  }
+  // elseif ( marker == MergedRawFile::FileMarker ) //It's a Merged File
+  //   {
+
+  //     ERS_DEBUG(1, this->identify() << " found merge file");
+
+  //     ESLMergeFile* tmpmf = new ESLMergeFile(m_fR);
+  //     tmpmf -> setFile(next);
+  //     tmpmf -> handleOffset();
+  //     tmpmf -> setResponsibleForMetaData();
+      
+  //     nextESL = tmpmf;
+  //   }
+  // else
+  //   {
+  //     FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "file is of no know format. Abort.");
+  //     throw ci;
+      
+  //   }
+  
+  
+  nextESL->prepare();
+
+  // This looks for file-end sequence (which we don't have) 
+  // but it is caught, so OK
+  try
+    {
+      m_sumsize += nextESL->dataMB_InFile();
+    }
+  catch(...)
+    {
+      
+    }
+
+  return nextESL;
+  
+}
+
+bool FESLMultiFile::handlesContinuation()
+{
+  return true;
+}
+
+void FESLMultiFile::prepare()
+{
+  return;
+}
+
+bool FESLMultiFile::doneLoading()
+{
+  //multifile cannot be the last level, since it has to load either the mergefile or the originalfile.
+  return false;
+}
+
+void FESLMultiFile::advance()
+{
+  m_currentFileIndex++;
+  ERS_DEBUG(1, this->identify() << " advancing to next file " << m_currentFileIndex);
+}
+
+bool FESLMultiFile::moreEvents() 
+{
+  ERS_DEBUG(3, this->identify() << " asked for more events ");
+
+
+  if (m_filenames.size() == 0 ) return false;
+  if (m_currentFileIndex > m_filenames.size()-1) 
+    {
+      m_finished = true;
+      return false;
+    }
+  return true;
+}
+
+unsigned int FESLMultiFile::getSum()
+{
+  return m_sumsize;
+  
+}
+
+
+void FESLMultiFile::setContinuationFile(std::string next) 
+{
+  ERS_DEBUG(2, " Pushing : " << next << " on " << identify());
+  m_filenames.push_back(next);
+  ERS_DEBUG(2, " size now : " << m_filenames.size() );
+}
+
+void FESLMultiFile::setFile(std::string filename)
+{
+  m_filenames.push_back(filename);
+}
+
+void FESLMultiFile::setFiles(std::vector<std::string> filenames)
+{
+  m_filenames = filenames;
+}
+
+
+
diff --git a/Event/FaserEventStorage/src/ESLMultiFile.h b/Event/FaserEventStorage/src/ESLMultiFile.h
new file mode 100644
index 000000000..5a810d679
--- /dev/null
+++ b/Event/FaserEventStorage/src/ESLMultiFile.h
@@ -0,0 +1,51 @@
+#ifndef FASERESLMULTIFILE_H
+#define FASERESLMULTIFILE_H
+
+
+#include "FaserEventStorage/fRead.h"
+#include "EventStackLayer.h"
+#include "EventStorage/RawFileName.h"
+#include <vector>
+
+using namespace FaserEventStorage;
+
+class FESLMultiFile : public EventStackLayer
+{
+ protected:
+  FESLMultiFile();
+
+ public:
+  FESLMultiFile(fRead* fR);
+
+  
+  EventStackLayer* openNext();
+  
+  void prepare();
+  bool doneLoading();
+  
+  bool moreEvents() ;
+  bool handlesContinuation()  ;
+
+  void setContinuationFile(std::string next) ;
+
+  void advance();
+
+  unsigned int getSum();
+  
+  //distinct methods
+  void setFile(std::string filename);
+  void setFiles(std::vector<std::string> filenames);
+
+  
+
+ private:
+  std::vector<std::string> m_filenames;
+  unsigned int m_currentFileIndex;
+  unsigned int m_sumsize;
+  daq::RawFileName *m_rawfilename;
+
+};
+
+
+#endif 
+
diff --git a/Event/FaserEventStorage/src/ESLOriginalFile.cxx b/Event/FaserEventStorage/src/ESLOriginalFile.cxx
new file mode 100644
index 000000000..5a5ad7681
--- /dev/null
+++ b/Event/FaserEventStorage/src/ESLOriginalFile.cxx
@@ -0,0 +1,654 @@
+#include "ESLOriginalFile.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+#include "DataReaderController.h"
+//#include "compression/compression.h"
+//#include "compression/DataBuffer.h"
+#include "EventFormats/DAQFormats.hpp"
+
+#include <stdio.h>
+#include <string.h>
+
+FESLOriginalFile::FESLOriginalFile( fRead * m_fR) : EventStackLayer(m_fR)
+{
+  m_me = "FESLOriginal"; 
+
+  ERS_DEBUG(3, identify() << " Constructor called ");
+  
+  uint64_t cpos = m_fR->getPosition();
+  m_fR->setPositionFromEnd(0);
+  m_cfilesize = m_fR->getPosition();
+  m_fR->setPosition(cpos);
+
+  ERS_DEBUG(3, identify() << " File size found: " << m_cfilesize);
+
+  m_endOfFile = false;
+  m_fer_read = false;
+  m_advance_fer_updated = false;
+
+  m_compression = FaserEventStorage::NONE;
+  //m_uncompressed = new compression::DataBuffer();
+
+}
+ 
+FESLOriginalFile::~FESLOriginalFile() 
+{
+  //delete m_uncompressed;
+  ERS_DEBUG(3, identify() <<" destroyed ") ; 
+}
+
+ 
+EventStackLayer* FESLOriginalFile::openNext()
+{
+  return 0;
+  //does nothing
+}
+
+
+//DRError FESLOriginalFile::getData(unsigned int &eventSize, char **event, int64_t pos, bool memAlreadyAlloc, int64_t allocSizeInBytes)
+DRError FESLOriginalFile::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
+{
+  ERS_DEBUG(2,"Entered FESLOriginalFile::getData().");
+  
+  if(pos>0) m_fR->setPosition(pos);
+//uint64_t startofevent = m_fR->getPosition(); // we will need this in case of reading failure.
+
+  // Don't allow stale data
+  if (theEvent != NULL) delete theEvent;
+  theEvent = new DAQFormats::EventFull();
+
+  // Read data header
+  size_t sizeofHeader = theEvent->header_size();
+  char* buffer = new char[sizeofHeader];
+
+  if (NULL == buffer) {
+    ERS_DEBUG(1, " tried to allocate " << theEvent->header_size() << " bytes for header but failed!");
+    FaserEventStorage::ES_AllocatingMemoryFailed ci(ERS_HERE, "FESLOriginalFile tried to allocate memory for header but failed. Abort.");
+      throw ci;
+  }
+
+  m_fR->readData(buffer, sizeofHeader);
+  theEvent->loadHeader((uint8_t*)buffer, sizeofHeader);
+
+  delete[] buffer;
+
+  ERS_DEBUG(2,"DATA HEADER: Expected event size " << theEvent->size());
+
+  // Now we have the event length, create buffer to store this
+  size_t sizeofPayload = theEvent->payload_size();
+  buffer = new char[sizeofPayload];
+
+  if (NULL == buffer) {
+    ERS_DEBUG(1, "Tried to allocate " << sizeofPayload << " bytes for payload but failed!");    
+    FaserEventStorage::ES_AllocatingMemoryFailed ci(ERS_HERE, "FESLOriginalFile tried to allocate memory for payload but failed. Abort.");
+    throw ci;
+  }
+
+  // Check if we will read beyond the end of the file
+  uint64_t cpos = m_fR->getPosition();
+  ERS_DEBUG(3, "currentposition" << cpos) ;
+  uint64_t remaining = m_cfilesize - cpos;
+
+  if (remaining < sizeofPayload) {
+    ERS_DEBUG(1, "Requested " << sizeofHeader 
+	      << " bytes but only remains " << remaining << " in file ");
+
+    FaserEventStorage::ES_OutOfFileBoundary ci(ERS_HERE, "Trying to read more data than remains in the file. This could mean that either your event is truncated, or that the event size record of this event is corrupted. If you still want to read the data, catch this exception and proceed. The data block contains the rest of the data. ");
+    throw ci;
+
+    // In case this gets caught, although thee loadPayload will throw its own error
+    m_fR->readData(buffer, remaining);
+    theEvent->loadPayload((uint8_t*)buffer, remaining);
+
+    return DRNOOK;
+
+  } else {
+
+    // OK, read event
+    m_fR->readData(buffer, sizeofPayload);
+    theEvent->loadPayload((uint8_t*)buffer, sizeofPayload);
+  
+  }
+  ERS_DEBUG(2, "Event:\n" << *theEvent);
+  
+  ERS_DEBUG(3,"Finished reading the event.");
+
+  //CHECK FOR END OF FILE REACHED
+  if( /*m_fR->isEoF()*/  m_cfilesize<=m_fR->getPosition()) {
+     //isEoF only tells you an end of file if you already hit the eof. it doesn't tell you if ou are exactly at the limit. therefore we check like that
+    ReadingIssue ci(ERS_HERE,"no event record found where expected. A problem with file format. The file may not have been properly closed.");
+    ers::warning(ci); 
+    m_error = true;
+    m_finished = true;
+
+    
+    FaserEventStorage::ES_NoEndOfFileRecord rci(ERS_HERE, "End of File reached directly after Event. No end of File record found where expected. The file may not have been properly closed. To proceed anyway, catch this exception. However, the requested Data has been read correctly.");
+    throw rci;
+
+    
+    return DRNOOK;
+  }
+
+  // Need some check for end of file??  
+
+  /*
+  // check for end of file record
+  if(unfile_record(&m_latest_fer,&file_end_pattern) != 0) {
+    ERS_DEBUG(3,"Found end of file record after an event.");
+    m_endOfFile = true;
+    m_fer_read = true;
+    m_finished = true;
+    
+    // check end of run
+  }
+  */
+  return DROK;
+}
+
+
+
+EventStackLayer* FESLOriginalFile::loadAtOffset(int64_t position, EventStackLayer *old)
+{
+  if(old){}; //Avoid compilation warning
+
+  if (m_cfilesize <=  position)
+  {
+ FaserEventStorage::ES_OutOfFileBoundary ci(ERS_HERE, "Trying to jump outside Filesize Boundary. Abort.");
+  throw ci;
+ 
+  }
+  m_fR->setPosition(position);
+  return this;
+}
+
+void FESLOriginalFile::prepare()
+{
+  // ET - Mainly reads metadata.
+  // No metadata, so basically skip this
+
+  /*
+  ERS_DEBUG(2,"Read metadata from the beginning of the file.");
+ 
+  file_start_record tmpfsr = file_start_pattern;
+  tmpfsr.version = 0x0;
+ 
+ 
+  if(unfile_record(&m_latest_fsr,&tmpfsr) == 0) {
+      ERS_DEBUG(2,"File start record not found after fopen.");
+      FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "File start record not found after fopen.. FESLOriginalFile reported: File Format is not known. Abort");
+      throw ci;
+  }
+  
+  ERS_DEBUG(2,"File start record found after fopen. version "<< m_latest_fsr.version);
+  
+  m_latest_fns=unfile_name_strings();
+
+  if(m_latest_fns.appName=="there was") {
+    ERS_DEBUG(3,"File name strings not found in file.");     
+    FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "FESLOriginalFile reported: File name strings not found in file.");
+    throw ci;
+  } else {
+    ERS_DEBUG(3,"File name strings found.");         
+  }
+
+  readOptionalFreeMetaDataStrings();
+  
+  checkCompression();
+
+  if (m_latest_fsr.version == 0x2) {
+    ERS_DEBUG(3,"Version 2 found. Switching to compability mode.");
+    
+    v2_internal_run_parameters_record v2_internal_rpr;
+    if(unfile_record(&v2_internal_rpr,&v2_run_parameters_pattern) == 0) {
+      ERS_DEBUG(3,"Run parameters record not found in file.");
+      FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "FESLOriginalFile reported: Old Run parameters record not found in file.");
+      throw ci;
+    } else {
+      ERS_DEBUG(3,"Run parameters record found.");
+      m_internal_latest_rpr.marker=v2_internal_rpr.marker;              
+      m_internal_latest_rpr.record_size=v2_internal_rpr.record_size;
+      m_internal_latest_rpr.run_number=v2_internal_rpr.run_number;          
+      m_internal_latest_rpr.max_events=v2_internal_rpr.max_events;          
+      m_internal_latest_rpr.rec_enable=v2_internal_rpr.rec_enable;          
+      m_internal_latest_rpr.trigger_type=v2_internal_rpr.trigger_type;        
+      m_internal_latest_rpr.detector_mask_1of4=v2_internal_rpr.detector_mask;
+      m_internal_latest_rpr.detector_mask_2of4=0;
+      m_internal_latest_rpr.detector_mask_3of4=0;
+      m_internal_latest_rpr.detector_mask_4of4=0;
+      m_internal_latest_rpr.beam_type=v2_internal_rpr.beam_type;           
+      m_internal_latest_rpr.beam_energy=v2_internal_rpr.beam_energy;
+    }
+
+  } else if (m_latest_fsr.version == 0x5) {
+    ERS_DEBUG(3,"Version 5 found. Switching to compability mode.");
+
+    v5_internal_run_parameters_record v5_internal_rpr;
+    if(unfile_record(&v5_internal_rpr,&v5_run_parameters_pattern) == 0) {
+      ERS_DEBUG(3,"Run parameters record not found in file.");
+      FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "FESLOriginalFile reported: Old Run parameters record not found in file.");
+      throw ci;
+    } else {
+      ERS_DEBUG(3,"Run parameters record found.");
+      m_internal_latest_rpr.marker=v5_internal_rpr.marker;              
+      m_internal_latest_rpr.record_size=v5_internal_rpr.record_size;
+      m_internal_latest_rpr.run_number=v5_internal_rpr.run_number;          
+      m_internal_latest_rpr.max_events=v5_internal_rpr.max_events;          
+      m_internal_latest_rpr.rec_enable=v5_internal_rpr.rec_enable;          
+      m_internal_latest_rpr.trigger_type=v5_internal_rpr.trigger_type;      
+      m_internal_latest_rpr.detector_mask_1of4=v5_internal_rpr.detector_mask_1of2;
+      m_internal_latest_rpr.detector_mask_2of4=v5_internal_rpr.detector_mask_2of2;
+      m_internal_latest_rpr.detector_mask_3of4=0;
+      m_internal_latest_rpr.detector_mask_4of4=0;
+      m_internal_latest_rpr.beam_type=v5_internal_rpr.beam_type;           
+      m_internal_latest_rpr.beam_energy=v5_internal_rpr.beam_energy;
+    }
+
+  } else if (m_latest_fsr.version == 0x6) {
+    ERS_DEBUG(3,"New version found.");
+    
+    if(unfile_record(&m_internal_latest_rpr,&run_parameters_pattern) == 0) {
+      ERS_DEBUG(1,"Run parameters record not found in file.");
+      FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "FESLOriginalFile reported: Run parameters record not found in file.");
+      throw ci;
+    } else {
+      ERS_DEBUG(3,"Run parameters record found.");
+    }
+  } else {
+    FaserEventStorage::ES_WrongFileFormat ci(ERS_HERE, "FESLOriginalFile reported: File Format Version is not known. Abort");
+    throw ci;
+  }
+
+  ERS_DEBUG(2,"All metadata OK at the beginning of the file.");
+
+  if(unfile_record(&m_latest_fer,&file_end_pattern) != 0) 
+    {
+      //ERS_WARNING("No event data. This file contains only metadata. "
+      //  <<"End of file metadata found after the run parameters record.");
+      ERS_DEBUG(3,"End Record right after metadata. This OriginalFile contains only metadata.");
+
+      m_endOfFile = true;
+      m_fer_read = true;
+      
+    }
+  */
+  ERS_DEBUG(1,"File " << fileName() << " ready for reading."); 
+ 
+}
+
+bool FESLOriginalFile::doneLoading()
+{
+  return true; //an original file is not further merging anything
+}
+
+
+bool FESLOriginalFile::moreEvents() 
+{
+  ERS_DEBUG(3, m_me <<" more events: "<< (!m_endOfFile && !m_error));
+  return (!m_endOfFile && !m_error);
+}
+
+
+void FESLOriginalFile::readOptionalFreeMetaDataStrings() 
+{
+  ERS_DEBUG(3,"readOptionalFreeMetaDataStrings not implemented!");
+ }
+
+void FESLOriginalFile::checkCompression()
+{
+  // Always none
+  m_compression = FaserEventStorage::NONE;
+  /*
+  std::string comp = extractFromMetaData(FaserEventStorage::compressiontag+"=");
+
+  if(comp != ""){
+    m_compression = string_to_type(comp);
+    ERS_DEBUG(1,"Compressed file found. FMS: "<< comp << " Type: " 
+      << m_compression);
+  }
+  */
+}
+
+
+unsigned int FESLOriginalFile::fileStartDate() const 
+{
+  return m_latest_fsr.date;
+}
+
+unsigned int FESLOriginalFile::fileStartTime() const 
+{
+  return m_latest_fsr.time; 
+}
+
+
+std::vector<std::string> FESLOriginalFile::freeMetaDataStrings() const
+{
+  return m_fmdStrings;
+}
+
+FaserEventStorage::CompressionType FESLOriginalFile::compression() const {
+  return m_compression;
+}
+
+//Run parameter get records
+unsigned int FESLOriginalFile::runNumber() const {
+  return m_internal_latest_rpr.run_number;
+}
+
+     
+unsigned int FESLOriginalFile::maxEvents() const {
+  return  m_internal_latest_rpr.max_events;
+}
+
+     
+unsigned int FESLOriginalFile::recEnable() const {
+  return  m_internal_latest_rpr.rec_enable;
+}
+
+     
+unsigned int FESLOriginalFile::triggerType() const {
+  return m_internal_latest_rpr.trigger_type;
+}
+
+   
+std::bitset<128> FESLOriginalFile::detectorMask() const {
+    
+  uint64_t tmp = m_internal_latest_rpr.detector_mask_4of4;
+  tmp <<= 32;
+  tmp |= m_internal_latest_rpr.detector_mask_3of4;
+  
+  std::bitset<128> mask(tmp);
+  mask <<= 64;
+  
+  tmp = m_internal_latest_rpr.detector_mask_2of4;
+  tmp <<= 32;
+  tmp |= m_internal_latest_rpr.detector_mask_1of4;
+
+  mask |= tmp;
+  return mask;
+}
+
+unsigned int FESLOriginalFile::beamType() const {
+  return m_internal_latest_rpr.beam_type;
+}
+
+unsigned int FESLOriginalFile::beamEnergy() const {
+  return  m_internal_latest_rpr.beam_energy;
+}
+
+
+unsigned int FESLOriginalFile::fileEndDate() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.date;
+}
+
+    
+unsigned int FESLOriginalFile::fileEndTime() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.time;
+}
+
+    
+// This doesn't really work...
+unsigned int FESLOriginalFile::eventsInFile() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  //return m_latest_fer.events_in_file;
+  return 2; // Avoid no events in file error
+}
+
+ 
+unsigned int FESLOriginalFile::dataMB_InFile() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.data_in_file;
+}
+
+   
+unsigned int FESLOriginalFile::eventsInFileSequence() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.events_in_run; 
+}
+
+  
+unsigned int FESLOriginalFile::dataMB_InFileSequence() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.data_in_run;
+}
+
+
+unsigned int FESLOriginalFile::fileSizeLimitInDataBlocks() const 
+{
+  return m_latest_fsr.sizeLimit_dataBlocks; 
+}
+
+unsigned int FESLOriginalFile::fileSizeLimitInMB() const 
+{
+  return m_latest_fsr.sizeLimit_MB; 
+}
+
+std::string FESLOriginalFile::appName() const 
+{
+  return m_latest_fns.appName;
+}
+
+std::string FESLOriginalFile::fileNameCore() const 
+{
+  return m_latest_fns.fileNameCore;
+}
+
+
+
+
+    
+unsigned int FESLOriginalFile::fileStatusWord() 
+{
+
+  if(!m_advance_fer_updated) {
+    m_latest_fer = currentFileFER();
+    m_advance_fer_updated = true;
+  }
+
+  return m_latest_fer.status; 
+}
+
+bool FESLOriginalFile::endOfFileSequence()
+{
+  if (m_error) return true;
+  ERS_DEBUG(3, identify() << " status word has value " << this->fileStatusWord());
+  return this->fileStatusWord();
+
+}
+
+unsigned int FESLOriginalFile::nextInSequence(unsigned int current)
+{
+  return current+1; //stupid, but original file format does not support next/prev
+}
+
+
+file_end_record FESLOriginalFile::currentFileFER() {
+  ERS_DEBUG(3,"FESLOriginalFile::currentFileFER() called.");
+
+  file_end_record cfFER=file_end_pattern;
+
+  /*
+  int64_t pos = m_fR->getPosition();
+
+  //forward to the end and reverse a bit now and 
+  int64_t back=sizeof(file_end_pattern);
+  m_fR->setPositionFromEndSafe(-back);
+
+  if (unfile_record(&cfFER,&file_end_pattern)!= 0)
+    {
+      m_advance_fer_updated = true;
+    };
+  
+  // rewind back
+  m_fR->setPosition(pos);
+
+  if(cfFER.date==0)
+    {
+      ERS_DEBUG(3,"No end of file record found");
+      FaserEventStorage::ES_NoEndOfFileRecord ci(ERS_HERE, "FESLOriginalFile reported: File end record not found in file. If you still want to read data from this file, either catch these excpetions or don't ask for information inside the EOF Record");
+      throw ci;
+
+    }
+  */
+  return cfFER;
+}
+
+internal_run_parameters_record FESLOriginalFile::getRunParameterrecord()
+{
+  return m_internal_latest_rpr;
+}
+
+std::string FESLOriginalFile::GUID() const 
+{
+  ERS_DEBUG(2,"DataReaderBase::GUID() called.");
+  if(m_fmdStrings.size()==0) {
+    ERS_DEBUG(2,"No metadata strings in this file. Return empty GUID string.");
+    return std::string("");
+  }
+  std::string guid = m_fmdStrings[0];
+  std::string ptn("GUID=");
+  std::string::size_type pos=guid.find(ptn);
+  if(pos==std::string::npos) {
+    ERS_DEBUG(2,"No GUID in metadata strings of this file. Return empty GUID string.");
+    return std::string("");
+  }
+  pos+=ptn.size();
+  guid=guid.substr(pos,guid.size());
+ 
+  ERS_DEBUG(2,"Returning "<<guid);
+  return guid;
+}
+
+uint32_t FESLOriginalFile::lumiblockNumber()
+{
+  ERS_DEBUG(2,"DataReaderBase::lumiblockNumber() called.");
+  std::string lumistring = extractFromMetaData("LumiBlock=");
+  if (lumistring =="")
+    {
+      ERS_DEBUG(2,"No Lumiblock Info found. returning 0");
+      return 0;
+    }
+  std::istringstream i(lumistring);
+  i >> m_lumiblockNumber;
+
+  return m_lumiblockNumber;
+}
+
+std::string FESLOriginalFile::stream()
+{
+  m_stream = extractFromMetaData("Stream=");
+  return m_stream;
+}
+
+std::string FESLOriginalFile::projectTag()
+{
+  m_projectTag = extractFromMetaData("Project=");
+  return m_projectTag;
+}
+
+
+file_name_strings FESLOriginalFile::unfile_name_strings() 
+{
+
+  int64_t pos = m_fR->getPosition();
+
+  uint32_t tst;
+
+  FaserEventStorage::file_name_strings nst;
+  nst.appName="there was"; nst.fileNameCore="a problem";
+
+  m_fR->readData((char *)(&tst),sizeof(uint32_t));
+  if(tst != FaserEventStorage::file_name_strings_marker) {
+    m_fR->setPosition(pos);
+    return nst;
+  }
+
+  uint32_t size=0;
+  m_fR->readData((char *)(&size),sizeof(uint32_t));
+
+  char *csn=new char[size];
+  m_fR->readData(csn,size);
+  std::string name(csn,size);
+  delete [] csn;
+
+  char buf[4];
+  char ns = size % 4;
+  if(ns) m_fR->readData(buf,4-ns);
+
+  m_fR->readData((char *)(&size),sizeof(uint32_t));
+  
+  char *cst=new char[size];
+  m_fR->readData(cst,size);
+  std::string tag(cst,size);
+  delete [] cst;
+
+  ns = size % 4;
+  if(ns) m_fR->readData(buf,4-ns);
+
+  nst.appName = name;
+  nst.fileNameCore = tag;
+
+  return nst;
+}
+
+std::string FESLOriginalFile::extractFromMetaData(std::string token)
+{
+  ERS_DEBUG(2,"DataReaderBase::extractFromMetaData() called: " << token);
+  if(m_fmdStrings.size()==0) 
+    {
+      ERS_DEBUG(2,"No metadata strings in this file. Return empty string");
+      return "";
+    }
+  for (unsigned int i=0; i< m_fmdStrings.size(); i++)
+    {
+      std::string cs = m_fmdStrings.at(i);
+      std::string::size_type pos=cs.find(token);
+      if(pos==std::string::npos) 
+	{ /*not foundokay */}
+      else
+	{
+	  pos+=token.size();
+	  std::string result=cs.substr(pos,cs.size());
+	  return result;
+	}
+    }
+  ERS_DEBUG(2,"No "<< token <<" found in metadata strings of this file. Return emptystring.");
+  return "";
+}
+
diff --git a/Event/FaserEventStorage/src/ESLOriginalFile.h b/Event/FaserEventStorage/src/ESLOriginalFile.h
new file mode 100644
index 000000000..2ce8e3527
--- /dev/null
+++ b/Event/FaserEventStorage/src/ESLOriginalFile.h
@@ -0,0 +1,111 @@
+#ifndef ESLORIGINALFILE_H
+#define ESLORIGINALFILE_H
+
+
+#include "EventStackLayer.h"
+#include "FaserEventStorage/fRead.h"
+
+using namespace FaserEventStorage;
+
+// Forward declaration
+namespace DAQFormats {
+  class EventFull;
+}
+
+class FESLOriginalFile : public EventStackLayer
+{
+
+ public:
+  FESLOriginalFile( fRead * fR);
+  ~FESLOriginalFile( );
+
+  EventStackLayer* openNext();
+  EventStackLayer* loadAtOffset(int64_t position, EventStackLayer *old);
+  
+  void prepare();
+  bool doneLoading();
+
+  //DRError getData(unsigned int &eventSize, char **event, int64_t pos, bool memAlreadyAlloc, int64_t allocSizeInBytes);
+  DRError getData(DAQFormats::EventFull*& theEvent, int64_t pos);
+  
+  bool moreEvents() ;
+  //bool handlesOffset() ;
+  //bool handlesContinuation() ;
+  //std::string nextInContinuation() ;
+  //bool endOfFileSequence() ;
+
+
+  //additonal
+  internal_run_parameters_record getRunParameterrecord();
+
+  std::string GUID() const;
+  
+  unsigned int runNumber() const ;
+  unsigned int maxEvents() const ;
+  unsigned int recEnable() const ;
+  unsigned int triggerType() const ;
+  std::bitset<128> detectorMask() const ;
+  unsigned int beamType() const ;
+  unsigned int beamEnergy() const ;
+  std::vector<std::string> freeMetaDataStrings() const;
+  CompressionType compression() const;
+
+  unsigned int fileStartDate() const ;
+  unsigned int fileStartTime() const; 
+  
+  unsigned int fileEndDate() ;
+  unsigned int fileEndTime() ;
+  unsigned int eventsInFile() ;
+  unsigned int dataMB_InFile() ;
+  unsigned int eventsInFileSequence() ;
+  unsigned int dataMB_InFileSequence();
+  unsigned int fileStatusWord();
+  bool endOfFileSequence() ;
+  unsigned int nextInSequence(unsigned int current) ;
+
+  uint32_t lumiblockNumber();
+  std::string stream();
+  std::string projectTag();
+
+  unsigned int fileSizeLimitInDataBlocks() const ; 
+  unsigned int fileSizeLimitInMB() const ;
+  std::string appName() const ; 
+  std::string fileNameCore() const ;  
+  
+
+
+  
+ private:
+  void readOptionalFreeMetaDataStrings();
+  void checkCompression();
+  file_end_record currentFileFER();
+  
+  file_name_strings m_latest_fns;
+  
+  bool m_endOfFile;
+  bool m_fer_read; 
+  
+  int64_t m_cfilesize;
+  
+  file_start_record m_latest_fsr;
+  data_separator_record m_latest_dsr;
+  
+  file_end_record m_latest_fer;
+  bool m_advance_fer_updated ;
+  uint32_t m_lumiblockNumber;
+  std::string m_stream;
+  std::string m_projectTag;
+
+  file_name_strings unfile_name_strings();
+  
+  FaserEventStorage::freeMetaDataStrings m_fmdStrings;
+  internal_run_parameters_record m_internal_latest_rpr;
+
+  std::string extractFromMetaData(std::string token);
+  
+  FaserEventStorage::CompressionType m_compression;
+  //compression::DataBuffer * m_uncompressed;
+};
+
+
+#endif
diff --git a/Event/FaserEventStorage/src/EventStackLayer.cxx b/Event/FaserEventStorage/src/EventStackLayer.cxx
new file mode 100644
index 000000000..23dbc99fb
--- /dev/null
+++ b/Event/FaserEventStorage/src/EventStackLayer.cxx
@@ -0,0 +1,281 @@
+#include "ers/ers.h"
+#include <fstream>
+#include <vector>
+#include <stack>
+#include "EventStackLayer.h"
+#include "DataReaderController.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+
+#include "EventFormats/DAQFormats.hpp"
+
+EventStackLayer::EventStackLayer( fRead* fR )
+{
+  //by default, this just sets the fileReader
+  ERS_DEBUG(2,"EventStackLayer gets fRead Object ");
+  m_fR = fR;
+  m_handleCont=false;
+  m_handleOffs=false;
+  m_responsibleMetaData=false;
+  m_finished = false;
+  m_error = false;
+  m_caller = NULL;
+}
+
+bool EventStackLayer::finished()
+{
+  return m_finished;
+}
+
+void EventStackLayer::advance()
+{
+
+}
+
+
+DRError EventStackLayer::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
+{
+  if (theEvent){};
+  std::ostringstream os;
+  os << "EventStackLayerinterface::getData() was called, "
+     << " but should not have been called for this type of file!" 
+     << " position: " << pos ;  
+  
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, os.str().c_str());
+  throw ci;
+
+  return DRNOOK;
+}
+
+EventStackLayer* EventStackLayer::openNext() 
+{ 
+  return 0; 
+}
+
+
+EventStackLayer*
+EventStackLayer::loadAtOffset(int64_t position, EventStackLayer *old) 
+{ 
+  (void)old;
+  if (position < 0) ERS_DEBUG(2," called with negative position!");
+  return 0; 
+}
+
+bool EventStackLayer::handlesOffset() 
+{ 
+  return m_handleOffs; 
+}
+
+bool EventStackLayer::handlesContinuation() 
+{ 
+  return m_handleCont; 
+} 
+
+// std::string EventStackLayer::nextInContinuation() 
+//{ 
+//return "";
+//} 
+
+
+bool EventStackLayer::endOfFileSequence() 
+{ 
+  return true; 
+}
+
+void EventStackLayer::setContinuationFile(std::string next)
+{
+  if ( next == "blabla" ) ERS_DEBUG(2, " this is a blabla test");
+}
+
+void EventStackLayer::setFile( std::string filename)
+{
+  ERS_DEBUG(3, " SETTING filename " << filename);
+  m_currentFile = filename;
+}
+
+std::string EventStackLayer::fileName() 
+{ 
+  return m_currentFile;
+} 
+
+bool EventStackLayer::responsibleforMetaData()
+{
+  return m_responsibleMetaData;
+}
+
+void EventStackLayer::setResponsibleForMetaData()
+{
+  m_responsibleMetaData=true;
+}
+
+std::string EventStackLayer::GUID() const
+{
+  return "";
+}
+
+void EventStackLayer::handleContinuation() 
+{
+  m_handleCont=true;
+}
+
+
+unsigned int EventStackLayer::nextInSequence(unsigned int current) 
+{
+  std::ostringstream os;
+  os << "EventStackLayerinterface::getData() was called, "
+     << " but should not have been called for this type of file!" 
+     << " Current index: " << current;
+
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, os.str().c_str());
+  throw ci;
+
+  return 0;
+}
+
+
+
+void EventStackLayer::handleOffset() 
+{
+  m_handleOffs=true;
+}
+
+unsigned int EventStackLayer::runNumber() const { FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;return 0;}
+unsigned int EventStackLayer::maxEvents() const {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}
+unsigned int EventStackLayer::recEnable() const {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;return 0;}
+unsigned int EventStackLayer::triggerType() const {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}
+std::bitset<128>     EventStackLayer::detectorMask() const {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}
+unsigned int EventStackLayer::beamType() const { FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}
+unsigned int EventStackLayer::beamEnergy() const {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}
+std::vector<std::string> EventStackLayer::freeMetaDataStrings() const { 
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; 
+  std::vector<std::string> empty_vec;
+  return empty_vec;
+}
+
+FaserEventStorage::CompressionType EventStackLayer::compression() const{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; 
+  return FaserEventStorage::NONE;
+}
+
+unsigned int EventStackLayer::fileStartDate() const { FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0; }
+unsigned int EventStackLayer::fileStartTime() const { FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0; }
+
+unsigned int EventStackLayer::fileEndDate() {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}      ///< Date when writing has stopped.
+unsigned int EventStackLayer::fileEndTime() {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}             ///< Time when writing has stopped.
+unsigned int EventStackLayer::eventsInFile() {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}           ///< Number of events in this file.
+unsigned int EventStackLayer::dataMB_InFile() {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}           ///< Number of megabytes in this file.
+unsigned int EventStackLayer::eventsInFileSequence() {FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0;}    ///< Number of events in this file sequence written so far.
+// unsigned int EventStackLayer::dataMB_InFileSequence() {mythrowE("ESL Interface called for metadata. Abort"); return 0;}   ///< Number of MB in this file sequence written so far. 
+// unsigned int EventStackLayer::fileStatusWord() {throw 14; return 0;}          ///< Indicates an end of sequence. 
+
+
+unsigned int EventStackLayer::fileSizeLimitInDataBlocks() const
+{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;
+  return 0;
+}
+
+unsigned int EventStackLayer::fileSizeLimitInMB() const
+{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;
+  return 0;
+}
+
+std::string  EventStackLayer::appName() const 
+{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;
+  return "";
+}
+
+std::string  EventStackLayer::fileNameCore() const 
+{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;
+  return "";
+}
+
+unsigned int EventStackLayer::dataMB_InFileSequence() 
+{
+  FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci;
+  return 0;
+}
+
+
+
+
+uint32_t EventStackLayer::lumiblockNumber() 
+{FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return 0; }
+
+std::string EventStackLayer::stream() 
+{FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return ""; }
+
+std::string EventStackLayer::projectTag()
+{FaserEventStorage::ES_InternalError ci(ERS_HERE, "ESL Interface called for metadata. This should not happen. Abort.");
+  throw ci; return ""; }
+
+
+
+int EventStackLayer::unfile_record(void *ri, const void *pi) 
+{
+  ERS_DEBUG(3,"UNFILE RECORD called ");
+  uint32_t *record = (uint32_t *)ri;
+  uint32_t *pattern = (uint32_t *)pi;
+  int size=pattern[1];
+  ERS_DEBUG(3,"reading record of size "<< size);
+  int64_t pos = m_fR->getPosition();
+
+  for(int i=0; i<size; i++) 
+    {
+      ERS_DEBUG(3,"READING ");
+      if(pattern[i] != 0) 
+{
+  uint32_t tst=0;
+  m_fR->readData((char *)(&tst),sizeof(uint32_t));
+  ERS_DEBUG(3,"GOT "<< tst << " vs " <<  pattern[i] <<" expected");
+  if(not (tst==pattern[i])) 
+    {
+      m_fR->setPosition(pos);
+      return 0;
+    }
+} 
+      else 
+{
+  m_fR->readData((char *)(record+i),sizeof(uint32_t));
+  ERS_DEBUG(3,"GOT " << *(record+i));
+}
+    }
+  return size;
+}
+
+void EventStackLayer::setCaller(EventStackLayer* caller)
+{
+m_caller = caller;
+}
+
+EventStackLayer* EventStackLayer::getCaller()
+{
+return m_caller;
+}
+
+
diff --git a/Event/FaserEventStorage/src/EventStackLayer.h b/Event/FaserEventStorage/src/EventStackLayer.h
new file mode 100644
index 000000000..138f88aef
--- /dev/null
+++ b/Event/FaserEventStorage/src/EventStackLayer.h
@@ -0,0 +1,164 @@
+#ifndef FASEREVENTSTACKLAYER_H
+#define FASEREVENTSTACKLAYER_H
+
+#include "ers/ers.h"
+#include <fstream>
+#include <vector>
+#include <stack>
+#include <bitset>
+#include "FaserEventStorage/DRError.h"
+#include "FaserEventStorage/fRead.h"
+#include "FaserEventStorage/DRError.h"
+#include "FaserEventStorage/EventStorageRecords.h"
+#include "EventStorage/RawFileName.h"
+#include "FaserEventStorage/ESCompression.h"
+
+#include "EventStorageInternalRecords.h"
+
+namespace DAQFormats {
+class EventFull;
+}
+
+using namespace FaserEventStorage;
+
+
+class EventStackLayer //=ESL henceforward
+{
+ protected:
+ EventStackLayer(): 
+  m_fR(NULL),
+    m_caller(NULL)
+      {}
+
+ public:
+  EventStackLayer( fRead* fR ) ;
+  
+  virtual ~EventStackLayer() {};
+  
+  virtual std::string identify() {return m_me;}
+  
+  //virtual DRError getData(unsigned int &eventSize, char **event, int64_t pos, bool memAlreadyAlloc, int64_t allocSizeInBytes);
+  virtual DRError getData(DAQFormats::EventFull*& theEvent, int64_t pos);
+  
+  //the interface to instantiate a son-ESL instance.
+  //e.g. MergeFileReader Instantiates an Originalfilereader
+  virtual EventStackLayer* openNext();
+  
+  
+  //the instance that can handle offsets also needs to be able to "load" a new original file.
+  virtual EventStackLayer* loadAtOffset(int64_t position, EventStackLayer *old);
+  
+  
+  //the interface to prepare a recently instantiated ESL
+  //this should parse the header (if any), so that either data can be read, or openNext() can be called
+  virtual void prepare() = 0 ;
+  
+  //tells the caller if the instance is ready for data to be read. If true is given, the caller can start with getData. If false is given, openNext() should be called, so the current instance can create an Object to be put on the stack.
+  virtual bool doneLoading() = 0 ;
+  
+  
+  //tells the caller if more events can be read from this instance. 
+  // - true should be returned if this is an Originalfile and reading is not finished. 
+  // - True should be returned by MergeFileHandler and MultiFileHand have more Originalfiles or MergeFiles to load
+  // - False should be returned if a Originalfile reader reached the end of the originalfile, or the Mergefilereader has no more Originalfiles or the MultiFilereader is out of files.
+  virtual bool moreEvents() = 0 ;
+  
+  
+  //this tells the caller if the instance handles offsets inside files. This is important for the get/set Position stuff. If a setPosition is called, the stack will be emptied until an instance is found which can handle offsets. Returns true for mergefilereader and false for multifile. If Multifilereader loads originalfiles directly, Originalfile handles offsets.
+  virtual bool handlesOffset();
+  
+  //tells the caller if continuation is handled by this instance on the stack
+  virtual bool handlesContinuation();
+  
+  //if the intance can handle continuation, it needs to provide a ressource, e.g. a filename string to the loader. E.g. Multifilehandler is finished with a file, and it asks the old file which is the next
+  //virtual std::string nextInContinuation() ;
+  
+  //tells if the sequence is at an end
+  virtual bool endOfFileSequence() ;
+  
+  //sets the next "file" to be opened (by Mutifilereader)
+  virtual void setContinuationFile(std::string next);
+  
+  virtual void setFile( std::string filename);
+  
+  virtual std::string fileName();
+  
+  //A ESl can be asked id it is rsponsible for metadata responsibiliry
+  virtual bool responsibleforMetaData();
+  
+  virtual void setResponsibleForMetaData();
+  
+  virtual std::string GUID() const;
+  
+  virtual bool finished();
+  virtual void advance();
+  
+  void handleContinuation() ;
+  virtual unsigned int nextInSequence(unsigned int current) ;
+  
+  
+  void handleOffset() ;
+  
+  //Run parameter get records
+  virtual unsigned int runNumber() const;
+  virtual unsigned int maxEvents() const;
+  virtual unsigned int recEnable() const ;
+  virtual unsigned int triggerType() const;
+  virtual std::bitset<128> detectorMask() const ;
+  virtual unsigned int beamType() const ;
+  virtual unsigned int beamEnergy() const;
+  virtual std::vector<std::string> freeMetaDataStrings() const;
+  virtual CompressionType compression() const;
+  
+  virtual unsigned int fileStartDate() const;
+  virtual unsigned int fileStartTime() const;
+
+  virtual unsigned int fileEndDate();             ///< Date when writing has stopped.
+  virtual unsigned int fileEndTime();             ///< Time when writing has stopped.
+  virtual unsigned int eventsInFile();           ///< Number of events in this file.
+  virtual unsigned int dataMB_InFile();           ///< Number of megabytes in this file.
+  virtual unsigned int eventsInFileSequence();    ///< Number of events in this file sequence written so far.
+
+  virtual unsigned int fileSizeLimitInDataBlocks() const ; 
+  virtual unsigned int fileSizeLimitInMB() const ;
+  virtual std::string appName() const ; 
+  virtual std::string fileNameCore() const ;  
+
+  virtual unsigned int dataMB_InFileSequence();   ///< Number of MB in this file sequence written so far. 
+  //virtual unsigned int fileStatusWord();          ///< Indicates an end of sequence. 
+  
+  virtual uint32_t lumiblockNumber();
+  virtual std::string stream();
+  virtual std::string projectTag();
+  
+  virtual void setCaller(EventStackLayer* caller);
+  virtual EventStackLayer* getCaller();
+
+  
+ protected:
+  //This is the raw file access reader
+  //it is assigned in the constructor
+  fRead* m_fR;
+  
+  EventStackLayer* m_caller;
+  
+  bool m_finished;
+  bool m_error;
+  
+  std::string m_me;
+  bool m_handleCont;
+  bool m_handleOffs;
+  
+  bool m_responsibleMetaData;
+  std::string m_currentFile;
+  
+  //unfile record is used by the inheriting classes
+  //to read data from the file
+  int unfile_record(void *ri, const void *pi);
+  
+};
+
+
+
+#endif 
+
diff --git a/Event/FaserEventStorage/src/EventStorageInternalRecords.h b/Event/FaserEventStorage/src/EventStorageInternalRecords.h
new file mode 100644
index 000000000..c0e5f35b2
--- /dev/null
+++ b/Event/FaserEventStorage/src/EventStorageInternalRecords.h
@@ -0,0 +1,91 @@
+
+#ifndef FASEREVENTSTORAGE_INTERNAL_RECORDS_H
+#define FASEREVENTSTORAGE_INTERNAL_RECORDS_H
+
+
+namespace FaserEventStorage {
+  
+  struct internal_run_parameters_record {
+    uint32_t marker;              
+    uint32_t record_size;         
+    uint32_t run_number;          
+    uint32_t max_events;          
+    uint32_t rec_enable;          
+    uint32_t trigger_type;        
+    uint32_t detector_mask_1of4;
+    uint32_t detector_mask_2of4;
+    uint32_t detector_mask_3of4;
+    uint32_t detector_mask_4of4;
+    uint32_t beam_type;           
+    uint32_t beam_energy;         
+  };
+
+  struct v5_internal_run_parameters_record {
+    uint32_t marker;              
+    uint32_t record_size;         
+    uint32_t run_number;          
+    uint32_t max_events;          
+    uint32_t rec_enable;          
+    uint32_t trigger_type;        
+    uint32_t detector_mask_1of2;
+    uint32_t detector_mask_2of2;
+    uint32_t beam_type;           
+    uint32_t beam_energy;         
+  };
+
+  struct v2_internal_run_parameters_record {
+    uint32_t marker;              
+    uint32_t record_size;         
+    uint32_t run_number;          
+    uint32_t max_events;          
+    uint32_t rec_enable;          
+    uint32_t trigger_type;        
+    uint32_t detector_mask;
+    uint32_t beam_type;           
+    uint32_t beam_energy;         
+  };
+
+  
+  const internal_run_parameters_record run_parameters_pattern = {
+    RUN_PARAMETERS_MARKER,
+    sizeof(internal_run_parameters_record)/sizeof(uint32_t),
+    0,    
+    0,    
+    0,    
+    0,
+    0,
+    0,
+    0, 
+    0,
+    0,     
+    0
+  };   
+
+  const v2_internal_run_parameters_record v2_run_parameters_pattern = {
+    RUN_PARAMETERS_MARKER,
+    sizeof(v2_internal_run_parameters_record)/sizeof(uint32_t),
+    0,    
+    0,    
+    0,  
+    0, 
+    0,
+    0,     
+    0
+  };   
+
+  const v5_internal_run_parameters_record v5_run_parameters_pattern = {
+    RUN_PARAMETERS_MARKER,
+    sizeof(v5_internal_run_parameters_record)/sizeof(uint32_t),
+    0,    
+    0,    
+    0,  
+    0, 
+    0,
+    0,
+    0,     
+    0
+  };   
+
+}
+
+#endif
diff --git a/Event/FaserEventStorage/src/EventStorageRecords.cxx b/Event/FaserEventStorage/src/EventStorageRecords.cxx
new file mode 100644
index 000000000..801744638
--- /dev/null
+++ b/Event/FaserEventStorage/src/EventStorageRecords.cxx
@@ -0,0 +1,59 @@
+//
+// functions to convert records to strings
+// for debugging 
+// 
+#include <sstream>
+
+#include "FaserEventStorage/EventStorageRecords.h"
+
+std::string FaserEventStorage::string_record(void *ri, const void *pi) {
+
+  std::ostringstream s;
+  
+  uint32_t *record = (uint32_t *)ri;
+  uint32_t *pattern = (uint32_t *)pi;
+  int size=pattern[1];
+
+  for(int i=0; i<size; i++) {
+    if(pattern[i] != 0) {
+      s << std::hex << pattern[i] << std::dec << " ";
+    } else {
+      s << record[i] << " ";
+    }
+  }
+  
+  std::string rs = s.str();   
+  return rs;    
+}
+
+std::string FaserEventStorage::string_record(FaserEventStorage::file_name_strings nst) {
+  
+  std::ostringstream s;
+
+  s << std::hex << FaserEventStorage::file_name_strings_marker << std::dec;
+
+  s << " " << nst.appName.size();
+  s << " " << nst.appName;
+
+  char ns = nst.appName.size() % 4;
+  if(ns) s.write("____",4-ns);
+
+  s << " " << nst.fileNameCore.size();
+  s << " " << nst.fileNameCore;
+
+  ns = nst.fileNameCore.size() % 4;
+  if(ns) s.write("____",4-ns);
+
+  std::string rs = s.str();   
+  return rs;    
+
+}
+
+void FaserEventStorage::reset_record(void *ri, const void *pi) {
+
+  uint32_t *record = (uint32_t *)ri;
+  uint32_t *pattern = (uint32_t *)pi;
+  int size=pattern[1];
+
+  for(int i=0; i<size; i++) record[i] = pattern[i];
+}
diff --git a/Event/FaserEventStorage/src/RawFileName.cxx b/Event/FaserEventStorage/src/RawFileName.cxx
new file mode 100644
index 000000000..728445a8d
--- /dev/null
+++ b/Event/FaserEventStorage/src/RawFileName.cxx
@@ -0,0 +1,738 @@
+#include "FaserEventStorage/RawFileName.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+//-----------------
+// includes for ers
+#include "ers/ers.h"
+//-----------------
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <boost/tokenizer.hpp>
+
+
+namespace daq {
+
+  /**
+   * Contructor with ingredients given
+   */
+  RawFileName::RawFileName(std::string ProjectTag,
+			   unsigned int RunNumber,
+			   std::string StreamType,
+			   std::string StreamName,
+			   unsigned int LumiBlockNumber,
+			   std::string ApplicationName,
+			   std::string ProductionStep,
+			   std::string DataType,
+			   unsigned int FileSequenceNumber,
+			   std::string Extension): m_core_known(false), 
+						   m_trailer_known(false) 
+  {
+    ERS_DEBUG(1," Constructor with explicit fields");
+
+    buildFileName(ProjectTag,
+		  RunNumber,
+		  StreamType,
+		  StreamName,
+		  LumiBlockNumber,
+		  ApplicationName,
+		  ProductionStep,
+		  DataType,
+		  FileSequenceNumber,
+		  Extension);
+  }
+
+  /**
+   * Constructor with the FileNameCore, a FileSequenceNumber and 
+   * the Extension only - 
+   *  Does not alter the FileNameCore, just attaches trailer fields 
+   *  to the fileNameCore; also, tries to interpret the resulting filename
+   *  Note: delimiter must be inside the Extension (e.g., ".data")
+   */
+  RawFileName::RawFileName(std::string FileNameCore,
+			   unsigned int FileSequenceNumber,
+			   std::string Extension): m_core_known(false), 
+						   m_trailer_known(false)
+  {
+    ERS_DEBUG(1," Constructor with fileNameCore, sequenceNumber & extension");
+
+    setDefaults(); // in case the file name is not interpretable
+
+    buildFileNameTrailers(FileNameCore, 
+			  FileSequenceNumber,
+			  Extension);
+    
+    m_core_known = interpretFileName(m_fileName);
+  }
+    
+  
+  /**
+   * Contructor with just the filename given: for interpretation
+   */
+  RawFileName::RawFileName(std::string FileName): m_core_known(false), 
+						  m_trailer_known(false)
+  {
+    ERS_DEBUG(1," Constructor with fileName only, for interpretation");
+
+    setDefaults(); // in case the file name is not interpretable
+    
+    m_fileName = FileName;
+    m_fileNameCore = m_fileName; // can not know any better now... 
+
+    m_core_known = interpretFileName(m_fileName); //if OK, made m_fileNameCore
+  }
+
+  /**
+   * Destructor
+   */
+  RawFileName::~RawFileName(){
+    ERS_DEBUG(1," Destructor!");
+  }
+  
+
+
+  std::string RawFileName::getCurrentFileName(bool writing)
+  {
+    if (writing)
+      setTailers(m_fileSequenceNumber, RAWFILENAME_EXTENSION_UNFINISHED);
+    else
+      setTailers(m_fileSequenceNumber, RAWFILENAME_EXTENSION_FINISHED);
+    
+    return fileName();
+  }
+
+
+  std::string RawFileName::getCoreName()
+  {
+    return m_fileNameCore;
+  }
+
+  unsigned int RawFileName::getIndex()
+  {
+    return m_fileSequenceNumber;
+  }
+  
+  
+  void RawFileName::fileAlreadyExists()
+  {
+    m_fileSequenceNumber+=100;
+    
+  }
+  
+  void RawFileName::advance()
+  {
+    m_fileSequenceNumber+=1;
+    
+  }
+
+
+
+
+  /**
+   * given the ingedients, contruct the fileName
+   */
+  void RawFileName::buildFileName(std::string ProjectTag,
+				  unsigned int RunNumber,
+				  std::string StreamType,
+				  std::string StreamName,
+				  unsigned int LumiBlockNumber,
+				  std::string ApplicationName,
+				  std::string ProductionStep,
+				  std::string DataType,
+				  unsigned int FileSequenceNumber,
+				  std::string Extension) 
+  {
+    buildFileNameCore(ProjectTag,
+		      RunNumber,
+		      StreamType,
+		      StreamName,
+		      LumiBlockNumber,
+		      ApplicationName,
+		      ProductionStep,
+		      DataType);
+
+    buildFileNameTrailers(m_fileNameCore, // result of buildFileNameCore() 
+			  FileSequenceNumber,
+			  Extension);
+    
+    return;
+  }
+  
+  /**
+   * given the ingedients, contruct the fileNameCore 
+   * and set m_core_known = true
+   */
+  void RawFileName::buildFileNameCore(std::string ProjectTag,
+				      unsigned int RunNumber,
+				      std::string StreamType,
+				      std::string StreamName,
+				      unsigned int LumiBlockNumber,
+				      std::string ApplicationName,
+				      std::string ProductionStep,
+				      std::string DataType)
+  {
+    if (ProjectTag == "") { ProjectTag = "data_test"; } // default
+    m_project = ProjectTag;
+    m_runNumber = RunNumber;
+    m_streamType = StreamType;
+    m_streamName = StreamName;
+
+    std::ostringstream stream;
+    stream << m_streamType << "_" << m_streamName;
+    m_stream = stream.str();
+    
+    m_lumiBlockNumber = LumiBlockNumber;
+    m_applicationName = ApplicationName;
+    m_productionStep = ProductionStep;
+    m_dataType = DataType;
+    
+    std::ostringstream n;
+    n << ProjectTag << RAWFILENAME_DELIMITER; 
+    n << std::setw(RAWFILENAME_RUN_NUMBER_LENGTH) 
+      << std::setfill('0');
+    n << RunNumber << RAWFILENAME_DELIMITER;
+    n << StreamType << "_";
+    n << StreamName << RAWFILENAME_DELIMITER;
+    n << ProductionStep << RAWFILENAME_DELIMITER;
+    n << DataType;
+    m_datasetName = n.str();
+
+    n << RAWFILENAME_DELIMITER << "_lb";
+    n << std::setw(RAWFILENAME_LB_NUMBER_LENGTH) 
+      << std::setfill('0');
+    n << LumiBlockNumber << RAWFILENAME_DELIMITER;
+    n << "_" << ApplicationName;
+
+    m_fileNameCore = n.str();
+
+    m_core_known = true; // even the fileNameCore is OK to handle fileName
+  }
+  
+
+  /**
+   * construct a complete FileName, by appending a FileSequenceNumber and 
+   * an Extension to the given FileNameCore
+   * and set m_trailer_known = true
+   */
+  void RawFileName::buildFileNameTrailers(std::string FileNameCore, 
+					  unsigned int FileSequenceNumber,
+					  std::string Extension) 
+  {
+    m_fileNameCore = FileNameCore;
+    m_fileSequenceNumber = FileSequenceNumber;
+    m_extension = Extension;
+    
+    std::ostringstream n;
+    n << FileNameCore;
+    n << RAWFILENAME_DELIMITER
+      << "_"
+      << std::setw(RAWFILENAME_FILE_NUMBER_LENGTH) 
+      << std::setfill('0');
+    n << FileSequenceNumber;
+    if ( Extension != "" ) {
+      if (Extension.c_str()[0] != RAWFILENAME_DELIMITER.c_str()[0])
+	{
+	  n << RAWFILENAME_DELIMITER << Extension;
+	  m_extension = RAWFILENAME_DELIMITER + Extension;
+	} 
+      else 
+	{
+	  n << Extension; // delimiter is already in Extension
+	}
+    }
+    m_fileName = n.str();
+    
+    m_trailer_known = true;
+  }
+
+  /**
+   * Default values for the filename fields 
+   * If filename is valid, the correct values will be returned when asked.
+   */
+  void RawFileName::setDefaults() {
+    m_project            = RAWFILENAME_DEFAULT_STRING;
+    m_runNumber          = RAWFILENAME_DEFAULT_UINT;
+    m_streamType         = RAWFILENAME_DEFAULT_STRING;
+    m_streamName         = RAWFILENAME_DEFAULT_STRING;
+    m_stream             = RAWFILENAME_DEFAULT_STRING;
+    m_lumiBlockNumber    = RAWFILENAME_DEFAULT_UINT;
+    m_applicationName    = RAWFILENAME_DEFAULT_STRING;
+    m_productionStep     = RAWFILENAME_DEFAULT_STRING;
+    m_dataType           = RAWFILENAME_DEFAULT_STRING;
+    m_fileSequenceNumber = RAWFILENAME_DEFAULT_UINT;
+    m_extension          = RAWFILENAME_DEFAULT_STRING;
+
+    
+    m_fileNameCore       = RAWFILENAME_DEFAULT_STRING;
+    m_fileName           = RAWFILENAME_DEFAULT_STRING;
+
+    m_datasetName        = RAWFILENAME_DEFAULT_STRING;
+
+    m_core_known         = false;
+    m_trailer_known      = false;
+  }
+
+  /**
+   * Modify the File Trailer fileds (FileSequence Number and  Extension)
+   */
+  void RawFileName::setTailers(unsigned int fsn_i, std::string extension_s) 
+  {
+    m_fileSequenceNumber = fsn_i;
+    m_extension = extension_s;
+    
+    buildFileNameTrailers(m_fileNameCore,
+			  m_fileSequenceNumber,
+			  m_extension);
+    
+    m_core_known = interpretFileName(m_fileName);
+  }
+
+  /**
+   * Modify the FileSequenceNumber at the file trailer fields
+   */
+  void RawFileName::setFileSequenceNumber( unsigned int fsn_i ) 
+  {
+    m_fileSequenceNumber = fsn_i;
+    if ( !m_trailer_known ) {
+      m_extension = RAWFILENAME_DEFAULT_STRING;
+    }
+    
+    buildFileNameTrailers(m_fileNameCore,
+			  m_fileSequenceNumber,
+			  m_extension);
+    
+    m_core_known = interpretFileName(m_fileName);
+  }
+
+  /**
+   * Modify the File Extension at the file trailer fields
+   */
+  void RawFileName::setExtension( std::string extension_s ) 
+  {
+    m_extension = extension_s;
+    if ( !m_trailer_known ) {
+      m_fileSequenceNumber = RAWFILENAME_DEFAULT_UINT;
+      std::string mystream = "File Sequence number not known. Set this first, before trying to set the extension";
+      FaserEventStorage::RawFileNameIssue myissue(ERS_HERE, mystream.c_str() );
+      throw myissue;
+    }
+    
+    buildFileNameTrailers(m_fileNameCore,
+			  m_fileSequenceNumber,
+			  m_extension);
+    
+    m_core_known = interpretFileName(m_fileName);
+  }
+
+
+  /**
+   * given the fileName, reconstruct the ingredients
+   */
+  bool RawFileName::interpretFileName(std::string FileName)
+  {
+
+    ERS_DEBUG(1," interpretFileName: " << FileName 
+	      << "  (m_core_known = " << m_core_known
+	      << " , m_trailer_known = " << m_trailer_known << " )");
+
+    /*
+      std::cout << " interpretFileName: FileName = " << FileName
+		<< "  (m_core_known = " << m_core_known
+		<< " , m_trailer_known = " << m_trailer_known << " )"
+		<< std::endl;
+    */
+
+    // Before diving into interpretation, check if work is already done
+    if ( m_core_known && m_trailer_known ) return true;
+    if ( FileName == "" ) {
+      m_core_known = false;
+      m_trailer_known = false;
+      return false; 
+    }
+
+    // Try to interpretate the filename fields
+
+    // useful things for the spliting of the fileName in fields:
+    // when spliting with boost tokenizer :
+    typedef boost::tokenizer<boost::char_separator<char> >  tokenizer;
+    boost::char_separator<char> sep(RAWFILENAME_DELIMITER.c_str(), 
+				    "", boost::keep_empty_tokens);
+    // when spliting with std::string::find() :
+    std:: string::size_type sepPos;
+
+    // Assuming that the file finishes like: ._sequenceNumber.extension(s)
+    // we say that after the last "_" in the filename, we have the trailer,
+    // and before that "_" we have the fileNameCore
+
+    sepPos=FileName.rfind("._");
+    if(sepPos==std::string::npos) {
+      ERS_DEBUG(3,"File name does not contain ._ ");
+      return false;
+    }
+
+    // fileNameCore:
+    m_fileNameCore = FileName.substr(0,sepPos);
+
+    ERS_DEBUG(3,"Checking for . at the end of " << m_fileNameCore );
+    if (m_fileNameCore.c_str()[m_fileNameCore.size()-1] == '.') {
+      m_fileNameCore = m_fileNameCore.substr(0, m_fileNameCore.size()-1);
+    }
+    ERS_DEBUG(3,"After removing possible . at the end: " << m_fileNameCore );
+
+    // tail:
+    std::string trailers_onestring;
+    trailers_onestring = FileName.substr(sepPos+2,std::string::npos); //to end
+
+    std::vector<std::string> trailers;
+    /***
+	trailers = split(trailers_onestring,
+	RAWFILENAME_DELIMITER.c_str()[0]);
+    ***/
+    tokenizer trailer_tokens(trailers_onestring, sep);
+    trailers.assign(trailer_tokens.begin(), trailer_tokens.end());
+
+
+
+    // A) interpret trailers first:
+    // ----------------------------
+    // if the 1st filed in the trailer is a number,
+    // we can intepret the trailer, else not
+    if ( !m_trailer_known) {
+      try {
+	m_fileSequenceNumber //  = atoi( trailers[0].c_str() ); 
+	  = convertToUINT( trailers[0] );
+	m_trailer_known = true;
+	std::ostringstream myext;
+	for (unsigned int i=1; i !=  trailers.size(); i++) {
+	  if (i != 1) myext << RAWFILENAME_DELIMITER;
+	  myext << trailers[i];
+	}
+	m_extension = myext.str();
+
+	// build the file name again and set m_trailer_known = true 
+	buildFileNameTrailers(m_fileNameCore, 
+			      m_fileSequenceNumber,
+			      m_extension);
+	m_trailer_known = true;
+	
+      } catch (std::exception& ex) {
+	ERS_DEBUG(1," Can not interpret fileSequenceNumber: " << ex.what() );
+	m_trailer_known = false;
+	m_fileSequenceNumber = RAWFILENAME_DEFAULT_UINT;
+	m_extension          = RAWFILENAME_DEFAULT_STRING;
+      }
+    } // try only if trailer details are not known
+
+    ERS_DEBUG(3," =====> Trailer string: " << trailers_onestring
+	      << " has " << trailers_onestring.size() << " characters"
+	      << " ;  FileName: " << FileName 
+	      << "  , fileNameCore: " << m_fileNameCore
+	      << " , m_fileSequenceNumber = " << m_fileSequenceNumber
+	      << " , m_extension  = " << m_extension );
+
+
+    // B) Try to interpret the fileNameCore now:
+    // -----------------------------------------
+    if (m_core_known) {
+      return true;
+    }
+
+    // we are here only if m_core_known is false: interepret now
+    std::vector<std::string> fields;
+    // fields = split( FileName, RAWFILENAME_DELIMITER.c_str()[0] );
+    tokenizer core_tokens(FileName, sep);
+    fields.assign(core_tokens.begin(), core_tokens.end());
+    for ( std::vector<std::string>::iterator it=fields.begin();
+	  it != fields.end(); ++it) {
+      ERS_DEBUG(3, " field = " << *it);
+    }
+ 
+    ERS_DEBUG(3," number of . delimited fields found: " <<  fields.size());
+
+    bool can_interpret_core;
+    if (fields.size() >= 7 && fields[4] == "RAW") {
+      can_interpret_core=true;
+    } else {
+      can_interpret_core=false;
+    } 
+    
+    if ( !can_interpret_core ) {
+      ERS_DEBUG(1," Can not interpret the core of FileName: " << FileName 
+		<< " , so keeping " << m_fileNameCore << " as core.");
+      m_core_known = false;
+
+    } else {
+
+      m_project     = fields[0];
+      try {
+	m_runNumber // = atoi( fields[1].c_str() ); 
+	  = convertToUINT( fields[1] );
+      } catch (std::exception& ex) {
+	ERS_DEBUG(1," Can not interpret run-number : " << ex.what() );
+	return false; // done with intrepreting the core...
+      }
+
+      m_stream      = fields[2];
+
+      sepPos=m_stream.find("_");
+      if(sepPos==std::string::npos) {
+	ERS_DEBUG(3,"Stream does not contain _ ");
+	return false;
+      }
+      // first part is streamType:
+      m_streamType = m_stream.substr(0,sepPos);
+      // second part is streamName:
+      m_streamName = m_stream.substr(sepPos+1,std::string::npos); // to end
+
+      m_productionStep = fields[3];
+      m_dataType = fields[4];
+      m_datasetName = "datasetName";
+
+      try {
+        sepPos = fields[5].find("b");
+	m_lumiBlockNumber = 
+	  convertToUINT( fields[5].substr(sepPos+1, std::string::npos) );
+	// atoi ( fields[5].substr(sepPos+1, std::string::npos).c_str() ); 
+      } catch (std::exception& ex) {
+	ERS_DEBUG(1," Can not interpret lumi-block : " << ex.what() );
+	// m_lumiBlockNumber = 0;
+	return false; // done with intrepreting the core...
+      }
+      
+      sepPos = fields[6].find("_");
+      m_applicationName = fields[6].substr(sepPos+1, std::string::npos);
+      
+      // build the nameCore again and set m_core_known = true
+      buildFileNameCore(m_project,
+			m_runNumber,
+			m_streamType,
+			m_streamName,
+			m_lumiBlockNumber,
+			m_applicationName,
+			m_productionStep,
+			m_dataType);
+      m_core_known=true;
+    } // if ( !can_interpret_core ) )
+
+    return m_core_known;
+  } 
+
+  /**
+   * contruct the complain
+   */
+  std::string RawFileName::complain()
+  {
+    std::stringstream mystream;
+    mystream <<  "FileName " << m_fileName << " has failed interpretation";
+    return mystream.str();
+  }
+
+
+  /**
+   * Get methods:
+   * ------------
+   */
+  std::string RawFileName::project() { 
+    if ( hasValidCore() )  {
+      return m_project;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+      //FaserEventStorage::RawFileNameIssue myIssue(ERS_HERE, complain() );
+      // ers::warning(myIssue);
+      //throw myIssue;
+    }
+  }
+
+  std::string RawFileName::datasetName() { 
+    if ( hasValidCore() ) { 
+      return m_datasetName;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  unsigned int RawFileName::runNumber() { 
+    if ( hasValidCore() ) { 
+      return m_runNumber;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+
+  std::string RawFileName::streamType() { 
+    if ( hasValidCore() ) { 
+      return m_streamType; 
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  std::string RawFileName::streamName() { 
+    if ( hasValidCore() ) { 
+      return m_streamName; 
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+
+  std::string RawFileName::stream() {
+    if ( hasValidCore() ) { 
+      return m_stream; 
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  unsigned int RawFileName::lumiBlockNumber() { 
+    if ( hasValidCore() ) { 
+      return m_lumiBlockNumber; 
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  std::string RawFileName::applicationName() { 
+    if ( hasValidCore() ) { 
+      return m_applicationName;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  std::string RawFileName::productionStep() { 
+    if ( hasValidCore() ) { 
+      return m_productionStep;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  std::string RawFileName::dataType() { 
+    if ( hasValidCore() ) { 
+      return m_productionStep;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+
+  unsigned int RawFileName::fileSequenceNumber() {
+    if ( hasValidTrailer() )  {
+      return m_fileSequenceNumber;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+  std::string RawFileName::extension() { 
+    if ( hasValidTrailer() )  {
+      return m_extension;
+    } else {
+      throw FaserEventStorage::RawFileNameIssue(ERS_HERE, complain().c_str() );
+    }
+  }
+
+
+  /**
+   * print the content of this object
+   */
+  void RawFileName::print()
+  {
+    std::stringstream mystream;
+
+    mystream << " full fileName: " << m_fileName  << std::endl;
+    mystream << " fileNameCore:  " << m_fileNameCore  << std::endl;
+    if(m_core_known)
+      mystream << " datasetName:   " << m_datasetName << std::endl;
+    
+    
+    if (!m_core_known) {
+      mystream << "   Not all core fields known " << std::endl;
+    } else {
+      mystream << "   project   = " << m_project << std::endl;
+      mystream << "   runNo     = " << m_runNumber << std::endl;
+      mystream << "   stream    = " << m_stream 
+<< " ( type: " << m_streamType 
+<< " , name: " << m_streamName << " ) "
+<< std::endl;
+      mystream << "   prodStep  = " << m_productionStep << std::endl;
+      mystream << "   dataType  = " << m_dataType << std::endl;
+      mystream << "   lumiBlock = " << m_lumiBlockNumber << std::endl;
+      mystream << "   appName   = " << m_applicationName << std::endl;
+    } // end-if m_core_known
+
+    if ( !m_trailer_known ) {
+      mystream << "   Tailer fields not known " << std::endl;
+    } else {
+      mystream << "   seqNumber = " << m_fileSequenceNumber << std::endl;
+      mystream << "   extension = " << m_extension << std::endl;
+    } // end-if m_trailer_known
+
+    mystream << std::endl;
+    
+    std::string tmp = mystream.str();
+
+    ERS_LOG(tmp.c_str());
+
+    return;
+  }
+
+
+  /**
+   * split a string in its fields, using a ONE-CHARACTER-LONG delimiter
+   */
+  std::vector<std::string> RawFileName::split(std::string const & s, 
+      char delimiter) 
+  {    
+    std::vector<std::string> container;
+
+    typedef boost::tokenizer<boost::char_separator<char> >  tokenizer;
+
+    std::ostringstream os;
+    os << delimiter;
+    boost::char_separator<char> sep(os.str().c_str(), 
+    "", boost::keep_empty_tokens);
+
+    tokenizer tokens(s, sep);
+    container.assign(tokens.begin(), tokens.end());
+
+    return container;
+  }
+
+  /**
+   * string to integer conversion
+   */ 
+  unsigned int RawFileName::convertToUINT(const std::string & s) 
+  {
+    unsigned int x = 0;
+    std::istringstream i(s);
+    // check if ALL characters in "s" are numbers; otherwise throw
+    for ( unsigned int it = 0; it != s.size(); ++it) {
+      std::ostringstream temp_out; temp_out << s.c_str()[it];
+      std::istringstream temp_in(temp_out.str());
+      x=0;
+      if (!(temp_in >> x)) {
+std::string mystream = "Failed convertToUINT(\"" + s + "\")";
+FaserEventStorage::RawFileNameIssue myissue(ERS_HERE, mystream.c_str() );
+// ers::warning(ci);
+throw myissue;
+// throw daq::BadConversion("convertToUINT(\"" + s + "\")");
+      }
+    }
+    
+    x=0;
+    if (!(i >> x)) {
+      std::string mystream = "Failed convertToUINT(\"" + s + "\")";
+      FaserEventStorage::RawFileNameIssue myissue(ERS_HERE, mystream.c_str() );
+      // ers::warning(ci);
+      throw myissue;
+      // throw daq::BadConversion("convertToUINT(\"" + s + "\")");
+    }
+    
+    return x;
+  }
+
+}
+
diff --git a/Event/FaserEventStorage/src/fReadPlain.cxx b/Event/FaserEventStorage/src/fReadPlain.cxx
new file mode 100644
index 000000000..03c880d2a
--- /dev/null
+++ b/Event/FaserEventStorage/src/fReadPlain.cxx
@@ -0,0 +1,148 @@
+#include "ers/ers.h"
+#include "fReadPlain.h"
+#include "EventStorage/EventStorageIssues.h"
+
+
+fReadPlain::fReadPlain() 
+{
+} 
+
+fReadPlain::~fReadPlain() 
+{
+  this->closeFile();
+}
+
+bool fReadPlain::isOpen() 
+{
+  return m_cFile.is_open();
+}
+
+bool fReadPlain::isEoF() 
+{
+  if(this->isOpen()) {
+    return m_cFile.eof();
+  } else {
+    return false;
+  }
+}
+
+bool fReadPlain::fileExists(std::string fName) const
+{
+  std::ifstream testFile;
+  testFile.open(fName.c_str(),std::ios::binary | std::ios::in);
+
+  bool isThere = testFile.good();
+
+  if(isThere) testFile.close();
+  
+  return isThere;
+}
+
+void fReadPlain::openFile(std::string fName) 
+{
+  if(this->isOpen()) this->closeFile();
+
+  m_cFile.clear();
+  m_cFile.open(fName.c_str(),std::ios::binary | std::ios::in);
+}  
+
+void fReadPlain::closeFile() 
+{
+  m_cFile.close();
+}
+
+void fReadPlain::readData(char *buffer, unsigned int sizeBytes) 
+{
+  if (sizeBytes==0) return;
+
+  if(!m_cFile.is_open()) {
+    std::stringstream mystream;
+    mystream << "an attempt to read from a file that is not open. "
+	     <<"fReadPlain::readData called to read "
+	     <<sizeBytes<<" bytes.";
+    std::string err = mystream.str();
+    EventStorage::ReadingIssue ci(ERS_HERE, err.c_str());
+    ers::warning(ci);
+    return;
+  }
+
+  if(m_cFile.eof()) {
+    std::stringstream mystream;
+    mystream << "error reading data from disk. "
+	     <<"fReadPlain called to read "
+	     <<sizeBytes<<" bytes and finds EOF.";
+    std::string err = mystream.str();
+    EventStorage::ReadingIssue ci(ERS_HERE, err.c_str());
+    ers::warning(ci);
+    return;
+  }
+
+  if(m_cFile.bad()) {
+    std::stringstream mystream;
+    mystream << "error reading data from disk. "
+	     <<"fReadPlain called to read " 
+	     <<sizeBytes<<" bytes and finds that the bad flag is set.";
+    std::string err = mystream.str();
+    EventStorage::ReadingIssue ci(ERS_HERE, err.c_str());
+    ers::warning(ci);
+    return;
+  } 
+
+  m_cFile.read(buffer,sizeBytes);
+
+  if(m_cFile.bad()) {
+    std::stringstream mystream;
+    mystream << "error reading data from disk. "
+             <<"fReadPlain finds the file in bad state after trying to read "
+             <<sizeBytes<<" bytes.";
+    std::string err = mystream.str();
+    EventStorage::ReadingIssue ci(ERS_HERE, err.c_str());
+    ers::warning(ci);
+  } else if(m_cFile.eof()) {
+    std::stringstream mystream;
+    mystream << "error reading data from disk. "
+             <<"fReadPlain finds EOF after trying to read "
+             <<sizeBytes<<" bytes.";
+    std::string err = mystream.str();
+    EventStorage::ReadingIssue ci(ERS_HERE, err.c_str());
+    ers::warning(ci);
+  }
+}
+
+int64_t fReadPlain::getPosition() 
+{
+  if(this->isOpen()) {
+    std::streampos pos=m_cFile.tellg();
+    return pos;
+  }
+  return -1;
+}
+
+void fReadPlain::setPosition(int64_t p) 
+{  
+  if(this->isOpen()) {
+    std::streampos pos=p;
+    m_cFile.seekg(pos);
+  }
+}
+ 
+void fReadPlain::setPositionFromEnd(int64_t p)
+{  
+  if(this->isOpen()) {
+    m_cFile.seekg(p,std::ios::end);
+  }
+}
+ 
+fRead * fReadPlain::newReader() const
+{
+  fReadPlain * nfr = new fReadPlain();
+  return (fRead *)nfr;
+}
+
+extern "C" {
+  fRead *fReadFactory() 
+  {
+    fReadPlain * nfr = new fReadPlain();
+    return (fRead *)nfr;
+  }
+}
diff --git a/Event/FaserEventStorage/src/fReadPlain.h b/Event/FaserEventStorage/src/fReadPlain.h
new file mode 100644
index 000000000..3fe6738d4
--- /dev/null
+++ b/Event/FaserEventStorage/src/fReadPlain.h
@@ -0,0 +1,35 @@
+
+#ifndef FREADPLAIN_H
+#define FREADPLAIN_H
+
+#include <fstream>
+#include <string>
+
+#include "FaserEventStorage/fRead.h"
+
+class fReadPlain : public fRead
+//class fReadPlain 
+{
+ public:
+  fReadPlain(); 
+  ~fReadPlain();
+
+  bool isOpen();
+  bool isEoF();
+  bool fileExists(std::string fName) const;
+  void openFile(std::string fName);
+  void closeFile();
+  void readData(char *buffer, unsigned int sizeBytes);
+  int64_t getPosition();
+  void setPosition(int64_t p);
+  void setPositionFromEnd(int64_t p);
+  fRead * newReader() const; 
+
+ private:
+  std::ifstream m_cFile; // current file
+};
+
+// fRead *fReadFactory();
+
+#endif 
+
diff --git a/Event/FaserEventStorage/src/loadfRead.cxx b/Event/FaserEventStorage/src/loadfRead.cxx
new file mode 100644
index 000000000..0404e7385
--- /dev/null
+++ b/Event/FaserEventStorage/src/loadfRead.cxx
@@ -0,0 +1,40 @@
+#include <dlfcn.h>
+#include "ers/ers.h"
+
+#include "FaserEventStorage/fRead.h" 
+#include "FaserEventStorage/loadfRead.h"
+
+fRead * loadfRead(std::string libName){
+ 
+  ERS_DEBUG(2,"loadfRead called with library name "<<libName);
+ 
+  ::dlerror();
+ 
+  libName += ".so";
+  libName = "lib" + libName;
+
+  void * lib = ::dlopen(libName.c_str(), RTLD_NOW | RTLD_GLOBAL);
+
+  if (!lib || ::dlerror() ) {
+    ERS_DEBUG(1,"Cannot load library");
+    return NULL;
+  }
+
+  ERS_DEBUG(2,"Library OK, now find the symbol.");
+
+  ::dlerror();
+
+  // fun is defined to be: 
+  // a pointer to a function which takes no arguments "()" 
+  // and returns fRead* (e.g., look in fReadPlain fReadFactory)
+  typedef fRead* (*fun)(); 
+  fun sym = (fun)::dlsym(lib, "fReadFactory");
+
+  if (!sym || ::dlerror()) {
+    ERS_DEBUG(1,"No symbol");
+    return NULL;
+  }
+  ERS_DEBUG(2,"Symbol is OK, now get the reader.");
+
+  return sym();   // this returns an "fRead*"
+}
diff --git a/Event/FaserEventStorage/src/pickFaserDataReader.cxx b/Event/FaserEventStorage/src/pickFaserDataReader.cxx
new file mode 100644
index 000000000..e800e22aa
--- /dev/null
+++ b/Event/FaserEventStorage/src/pickFaserDataReader.cxx
@@ -0,0 +1,132 @@
+#include "ers/ers.h"
+#include "FaserEventStorage/fRead.h" 
+#include "FaserEventStorage/loadfRead.h"
+#include "FaserEventStorage/pickFaserDataReader.h"
+#include "FaserEventStorage/EventStorageIssues.h"
+#include "DataReaderController.h"
+
+DataReader * pickFaserDataReader(std::string fileName) {
+  
+  ERS_DEBUG(1,"pickFaserDataReader(file) with file name "<<fileName);
+
+  std::vector<std::string> fReadLibs;
+  fReadLibs.push_back("fReadPlain");  // Just use plain
+
+  /*
+  // Control plugins libraries via file name prefixes.
+  // Take the prefixes away from the name, in most cases anyway.
+  if(fileName.find("rfio:")==0) {
+    fileName.erase(0,std::string("rfio:").size());
+    fReadLibs.push_back("fReadCastor");
+  } else if(fileName.find("dcache:")==0) {
+    fileName.erase(0,std::string("dcache:").size());
+    fReadLibs.push_back("fReaddCache");
+  } else if(fileName.find("dcap:")==0) {
+    // Leave the prefix in the file name in this case.
+    fReadLibs.push_back("fReaddCache");
+  } else if(fileName.find("root:")==0) {
+    // Leave the prefix in the file name in this case.
+    fReadLibs.push_back("fReadXRootD");
+  } else if(fileName.find("https:")==0) {
+    // Leave the prefix in the file name in this case.
+    fReadLibs.push_back("fReadDavix");
+  } else if(fileName.find("davs:")==0) {
+    // Leave the prefix in the file name in this case.
+    fReadLibs.push_back("fReadDavix");
+  } else if(fileName.find("disk:")==0) {
+    fileName.erase(0,std::string("disk:").size());
+    fReadLibs.push_back("fReadPlain");
+  } else { // by defaul all will be tried
+    fReadLibs.push_back("fReadPlain");
+    fReadLibs.push_back("fReadCastor");
+    fReadLibs.push_back("fReadXRootD");
+    fReadLibs.push_back("fReadDavix");
+    fReadLibs.push_back("fReaddCache");
+  }
+  */
+  ERS_DEBUG(2,"After parsing the file name is "<<fileName);
+  ERS_DEBUG(2,"Number of fRead plugins to try is "<<fReadLibs.size());
+
+  std::vector<std::string>::iterator fReadLib=fReadLibs.begin();
+  fRead *pfR = NULL;
+
+  std::vector<std::string> libsNotLoaded;
+  std::vector<std::string> libsNoSuccess;
+  libsNotLoaded.clear(); libsNoSuccess.clear();
+
+  for(fReadLib=fReadLibs.begin(); fReadLib!=fReadLibs.end(); ++fReadLib) {
+    ERS_DEBUG(2,"Try to with lib "<<(*fReadLib));
+
+    pfR = loadfRead(*fReadLib);
+    if (!pfR) {
+      ERS_DEBUG(2,"No fRead");
+      libsNotLoaded.push_back(*fReadLib);
+      continue;
+    }
+    ERS_DEBUG(2,"fRead* OK. Try to open the data file "<<fileName);
+    
+    pfR->openFile(fileName);
+
+    ERS_DEBUG(2,"Is the file open? "<<pfR->isOpen());
+    if(!pfR->isOpen()) {
+      ERS_DEBUG(2,"Can not open file "<<fileName<<" with library "<<(*fReadLib));
+      libsNoSuccess.push_back(*fReadLib);
+      delete pfR;
+      pfR=NULL;
+      continue;    
+    } else {
+      break;
+    }
+  }
+
+  if(pfR==NULL || !pfR->isOpen()) {
+    if(libsNoSuccess.size()>0) {
+      std::string libList="";
+      std::vector<std::string>::iterator it;
+      for(it = libsNoSuccess.begin(); it != libsNoSuccess.end(); ++it) {
+	libList += *it + " ";
+      } 
+      //ERS_ERROR("Can not open file "<<fileName
+      //<<"\nThe following libraries were tried: "<<libList);
+      std::stringstream mystream;
+      mystream << "can not open file "<<fileName
+               <<"\nThe following libraries were tried: "<<libList;
+      std::string err = mystream.str();
+      ReadingIssue ci(ERS_HERE, err.c_str());
+      ers::error(ci);
+    } 
+    if(libsNotLoaded.size()>0) {
+      std::string libList="";
+      std::vector<std::string>::iterator it;
+      for(it = libsNotLoaded.begin(); it != libsNotLoaded.end(); ++it) {
+libList += *it + " ";
+      } 
+      //ERS_WARNING("Can not load libraries: "<<libList);
+      std::string err = "can not load libraries: " + libList;
+      ReadingIssue ci(ERS_HERE, err.c_str());
+      ers::warning(ci);
+    } 
+    
+    return NULL;
+  }
+
+  // We have a working fRead and the file is accessible.
+
+  ERS_DEBUG(1,"The file is accessible. Go through file format now.");
+
+  pfR->closeFile();
+
+  DataReader * pDR = NULL;
+  try{
+    pDR = new DataReaderController(pfR,fileName);
+  }catch(FaserEventStorage::ES_WrongFileFormat &ex){
+    ReadingIssue ci(ERS_HERE,"file format not valid for EventStorage.", ex); 
+    ers::warning(ci);
+    return NULL;
+  }
+
+  ERS_DEBUG(1,"File format is OK.");
+
+  return pDR;
+}
+
diff --git a/faser-common b/faser-common
new file mode 160000
index 000000000..d526df399
--- /dev/null
+++ b/faser-common
@@ -0,0 +1 @@
+Subproject commit d526df399f57bafedb86111851d63d98f90adddf
-- 
GitLab


From e083d4e3dce439c1a32bfe23e0be8a4f6fd9192d Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 9 Jun 2020 16:47:33 -0700
Subject: [PATCH 03/47] add faser-common submodule

---
 faser-common | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/faser-common b/faser-common
index d526df399..3908fdd22 160000
--- a/faser-common
+++ b/faser-common
@@ -1 +1 @@
-Subproject commit d526df399f57bafedb86111851d63d98f90adddf
+Subproject commit 3908fdd228bc5712ddd8ae6e4d8b9a828b75e770
-- 
GitLab


From 78bae51c25876a2c8dcd47f332e2f8859e3bc38e Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 9 Jun 2020 17:11:25 -0700
Subject: [PATCH 04/47] Try fixing faser-common

---
 .gitmodules | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 5fba28a15..487dba090 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "faser-common"]
-	path = faser-common
-	url = https://:@gitlab.cern.ch:8443/faser/faser-common.git
+	   path = faser-common
+	   url = ../faser-common.git
-- 
GitLab


From 4abf789554b68c8ba4f989813ddbcfd2538e00a8 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 16 Jun 2020 12:14:57 -0700
Subject: [PATCH 05/47] Added Base and updated files

---
 Event/FaserByteStreamCnvSvc/CMakeLists.txt    |  11 +-
 .../ByteStreamInputSvc.h                      |  69 ---
 .../FaserByteStreamCnvSvc.h                   |   4 +-
 .../FaserByteStreamInputSvc.h                 |  27 +-
 .../src/EventInfoByteStreamAuxCnv.cxx         |  16 +-
 .../src/EventInfoByteStreamAuxCnv.h           |   4 +-
 .../src/EventInfoByteStreamxAODCnv.cxx        |  10 +-
 .../src/FaserByteStreamCnvSvc.cxx             |  10 +-
 .../src/FaserByteStreamInputSvc.cxx           |  36 +-
 .../src/FaserEventSelectorByteStream.cxx      |   5 +-
 .../src/FaserEventSelectorByteStream.h        |   1 -
 .../FaserByteStreamCnvSvc_entries.cxx         |   2 +-
 .../FaserByteStreamCnvSvcBase/CMakeLists.txt  |  46 ++
 .../FaserByteStreamAddress.h                  |  65 +++
 .../FaserByteStreamAddressProviderSvc.h       |  58 +++
 .../FaserByteStreamCnvSvcBase.h               |  52 ++
 .../FaserROBDataProviderSvc.h                 | 136 +++++
 .../IFaserByteStreamEventAccess.h             |  27 +
 .../IFaserROBDataProviderSvc.h                | 117 +++++
 .../src/FaserByteStreamAddress.cxx            |  46 ++
 .../src/FaserByteStreamAddressProviderSvc.cxx | 101 ++++
 .../src/FaserByteStreamCnvSvcBase.cxx         |  89 ++++
 .../src/FaserROBDataProviderSvc.cxx           | 482 ++++++++++++++++++
 .../FaserByteStreamCnvSvcBase_entries.cxx     |   8 +
 24 files changed, 1291 insertions(+), 131 deletions(-)
 delete mode 100644 Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
 rename Event/FaserByteStreamCnvSvc/{src => FaserByteStreamCnvSvc}/FaserByteStreamInputSvc.h (85%)
 create mode 100644 Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserByteStreamEventAccess.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
 create mode 100644 Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddress.cxx
 create mode 100644 Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
 create mode 100644 Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
 create mode 100644 Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
 create mode 100644 Event/FaserByteStreamCnvSvcBase/src/components/FaserByteStreamCnvSvcBase_entries.cxx

diff --git a/Event/FaserByteStreamCnvSvc/CMakeLists.txt b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
index 80fae1ae4..5b5d18d6b 100644
--- a/Event/FaserByteStreamCnvSvc/CMakeLists.txt
+++ b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
@@ -9,8 +9,8 @@ atlas_subdir( FaserByteStreamCnvSvc )
 atlas_depends_on_subdirs(
    PUBLIC
    Control/AthenaBaseComps
-   Event/ByteStreamCnvSvcBase
    #Event/ByteStreamData
+   Event/FaserEventStorage
    GaudiKernel
    PRIVATE
    Control/AthenaKernel
@@ -20,10 +20,10 @@ atlas_depends_on_subdirs(
    Database/APR/FileCatalog
    Database/AthenaPOOL/AthenaPoolUtilities
    Database/PersistentDataModel
-   Event/FaserEventStorage
    Event/EventInfo
    Event/xAOD/xAODEventInfo
    Event/xAOD/xAODTrigger
+   Event/FaserByteStreamCnvSvcBase
    EventFormats
    Logging)
 
@@ -38,11 +38,12 @@ atlas_add_library( FaserByteStreamCnvSvcLib
    FaserByteStreamCnvSvc/*.h src/*.h src/*.cxx
    PUBLIC_HEADERS FaserByteStreamCnvSvc
    PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
-   LINK_LIBRARIES AthenaBaseComps ByteStreamData GaudiKernel
-   ByteStreamCnvSvcLib ByteStreamCnvSvcBaseLib StoreGateLib rt
+   LINK_LIBRARIES AthenaBaseComps FaserEventStorageLib  GaudiKernel
+   StoreGateLib rt
    PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES}
    AthenaKernel SGTools CollectionBase FileCatalog
-   AthenaPoolUtilities PersistentDataModel FaserEventStorageLib EventInfo 
+   AthenaPoolUtilities PersistentDataModel EventInfo 
+   FaserByteStreamCnvSvcBaseLib 
    xAODEventInfo xAODTrigger)
 
 atlas_add_component( FaserByteStreamCnvSvc
diff --git a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
deleted file mode 100644
index 2d92e6523..000000000
--- a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/ByteStreamInputSvc.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-#ifndef BYTESTREAMCNVSVC_BYTESTREAMINPUTSVC_H
-#define BYTESTREAMCNVSVC_BYTESTREAMINPUTSVC_H
-
-/** @file ByteStreamInputSvc.h
- *  @brief This file contains the class definition for the ByteStreamInputSvc class.
- *  @author Peter van Gemmeren <gemmeren@anl.gov>
- *  $Id: ByteStreamInputSvc.h,v 1.51 2009-03-03 16:03:22 gemmeren Exp $
- **/
-
-#include <exception>
-#include "AthenaBaseComps/AthService.h"
-#include "EventFormats/DAQFormats.hpp"
-
-//#include "ByteStreamData/RawEvent.h"
-//#include "ByteStreamCnvSvc/ByteStreamExceptions.h"
-
-
-/** @class ByteStreamInputSvc
- *  @brief This class provides the base class to services to read bytestream data.
- *  The concrete class can provide Raw event from a file, transient store, or through network.
- **/
-class ByteStreamInputSvc : public ::AthService {
- public:
-  /// constructor
-  ByteStreamInputSvc(const std::string& name, ISvcLocator* svcloc);
-  /// destructor
-  virtual ~ByteStreamInputSvc(void);
-
-  /// Retrieve interface ID
-  static const InterfaceID& interfaceID();
-
-  /// virtual method for advance to the next event
-  virtual const DAQFormats::EventFull* nextEvent() = 0;
-  virtual const DAQFormats::EventFull* previousEvent() = 0;
-  virtual void setEvent(void* /*data*/, unsigned int /*status*/) {}
-  /// virtual method for accessing the current event
-  virtual const DAQFormats::EventFull* currentEvent() const = 0;
-  /// virtual method for accessing the current event status
-  virtual unsigned int currentEventStatus() const;
-  virtual std::pair<long,std::string> getBlockIterator(const std::string /* file */);
-  virtual void closeBlockIterator(bool);
-  virtual bool ready() const;
-  virtual StatusCode generateDataHeader(); 
-  virtual long positionInBlock();
-  virtual void validateEvent();
-};
-
-inline const InterfaceID& ByteStreamInputSvc::interfaceID() {
-  /// Declaration of the interface ID ( interface id, major version, minor version)
-  static const InterfaceID IID_ByteStreamInputSvc("ByteStreamInputSvc", 1, 0);
-  return(IID_ByteStreamInputSvc);
-}
-
-inline unsigned int ByteStreamInputSvc::currentEventStatus() const {
-  return(0);
-}
-
-// Virtual methods needed for file input
-inline std::pair<long,std::string> ByteStreamInputSvc::getBlockIterator(const std::string /* file */) {return std::make_pair(-1,"GUID");}
-inline void ByteStreamInputSvc::closeBlockIterator(bool) {}
-inline bool ByteStreamInputSvc::ready() const {return false;}
-inline StatusCode ByteStreamInputSvc::generateDataHeader() {return StatusCode::SUCCESS;}
-inline long ByteStreamInputSvc::positionInBlock() {return -1;} 
-inline void ByteStreamInputSvc::validateEvent() {}
-#endif
diff --git a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
index 1258f3869..f3035103b 100644
--- a/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
+++ b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h
@@ -5,7 +5,7 @@
 #ifndef FASERBYTESTREAMCNVSVC_FASERBYTESTREAMCNVSVC_H
 #define FASERBYTESTREAMCNVSVC_FASERBYTESTREAMCNVSVC_H
 
-#include "ByteStreamCnvSvcBase/ByteStreamCnvSvcBase.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h"
 #include "StoreGate/StoreGateSvc.h"
 #include "GaudiKernel/ServiceHandle.h"
 
@@ -28,7 +28,7 @@ class FullEventAssemblerBase;
     method through ByteStreamOutputSvc.
 */
 
-class FaserByteStreamCnvSvc : public ByteStreamCnvSvcBase/*, virtual public IService*/ {
+class FaserByteStreamCnvSvc : public FaserByteStreamCnvSvcBase/*, virtual public IService*/ {
 
 public:
    /// Standard Constructor
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h
similarity index 85%
rename from Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h
rename to Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h
index 00efecd0a..8428beedb 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.h
+++ b/Event/FaserByteStreamCnvSvc/FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h
@@ -13,31 +13,24 @@
 // Originally copied from ByteStreamEventStorageInputSvc
 
 // Include files.
-#include "FaserByteStreamCnvSvc/ByteStreamInputSvc.h"
-#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h"
 #include "AthenaKernel/SlotSpecificObj.h"
 #include "FaserEventStorage/DataReader.h"
 
-// Do I want to try to update this?  It looks like it is only used
-// here and in the detector-specific code.  Lets try without it.
-//#include "ByteStreamData/RawEvent.h"
-
 // FrameWork includes
+#include "AthenaBaseComps/AthService.h"
 #include "GaudiKernel/ServiceHandle.h"
 
-//#include "EventFormats/DAQFormats.hpp"
+#include "EventFormats/DAQFormats.hpp"
+#include <exception>
 
-//typedef DAQFormats::EventFull RawEvent;
-namespace DAQFormats {
-  class EventFull;
-}
 class StoreGateSvc;
 class DataHeaderElement;
 
 /** @class ByteStreamFaserInputSvc
  *  @brief This class is the ByteStreamInputSvc for reading events written by Faser.
  **/
-class FaserByteStreamInputSvc : public ByteStreamInputSvc {
+class FaserByteStreamInputSvc : public ::AthService {
 
 public:
    /// Constructors:
@@ -46,10 +39,12 @@ public:
    /// Destructor.
    virtual ~FaserByteStreamInputSvc();
 
+   /// Retrieve interface ID
+   static const InterfaceID& interfaceID();
+
    /// Required of all Gaudi Services
    virtual StatusCode initialize();
    virtual StatusCode stop();
-   /// Required of all Gaudi Services
    virtual StatusCode finalize();
 
    /// Required of all Gaudi services:  see Gaudi documentation for details
@@ -59,13 +54,12 @@ public:
    virtual const DAQFormats::EventFull* currentEvent() const;
    virtual const DAQFormats::EventFull* nextEvent();            //!< ++, new
    virtual const DAQFormats::EventFull* previousEvent();        //!< --, old
-   virtual       void setEvent(void* data, unsigned int eventStatus);
+   virtual void setEvent(void* data, unsigned int eventStatus);
 
    /// Return the current event status
    virtual unsigned int currentEventStatus() const;
    virtual void validateEvent(); 
 
-
    virtual long positionInBlock();
    virtual std::pair<long,std::string> getBlockIterator(const std::string fileName);
    void         closeBlockIterator(bool clearMetadata=true);
@@ -78,7 +72,6 @@ private: // data
 
    struct EventCache {
      std::unique_ptr<DAQFormats::EventFull> rawEvent = NULL;
-     //DAQFormats::EventFull*          rawEvent = 0;            //!< current event
      unsigned int       eventStatus = 0;   //!< check_tree() status of the current event
      long long int      eventOffset = 0;   //!< event offset within a file, can be -1          
      void               releaseEvent(); //!< deletes event
@@ -98,7 +91,7 @@ private: // data
 private: // properties
    ServiceHandle<StoreGateSvc>                m_storeGate;     //!< StoreGateSvc
    //ServiceHandle<StoreGateSvc>                m_inputMetadata; //!< StoreGateSvc
-   ServiceHandle<IROBDataProviderSvc>         m_robProvider;
+   ServiceHandle<IFaserROBDataProviderSvc>         m_robProvider;
 
 
    Gaudi::Property<bool>                      m_sequential;    //!< enable sequential reading.
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
index a8ec0f185..a0998bda4 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
@@ -4,10 +4,10 @@
 
 #include "EventInfoByteStreamAuxCnv.h"
 #include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
-#include "FaserByteStreamCnvSvc/ByteStreamInputSvc.h"
+//#include "FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h"
 
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
-#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
+#include "FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h"
 
 /*
 #include "ByteStreamData/RawEvent.h"
@@ -53,7 +53,7 @@ const CLID& EventInfoByteStreamAuxCnv::classID()
 
 long EventInfoByteStreamAuxCnv::storageType() 
 {
-  return ByteStreamAddress::storageType();
+  return FaserByteStreamAddress::storageType();
 }
 
 StatusCode EventInfoByteStreamAuxCnv::initialize() 
@@ -78,7 +78,7 @@ StatusCode EventInfoByteStreamAuxCnv::initialize()
     return StatusCode::FAILURE;
   }
 
-  //CHECK(m_robDataProvider.retrieve());
+  CHECK(m_robDataProvider.retrieve());
   //CHECK(m_mdSvc.retrieve());
 
   SimpleProperty<bool> propIsSimulation("IsSimulation", m_isSimulation);
@@ -133,10 +133,10 @@ StatusCode EventInfoByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataObjec
 
   ATH_MSG_DEBUG("EventInfoByteStreamAuxCnv::createObj() called");
 
-  ByteStreamAddress *pRE_Addr{nullptr};
-  pRE_Addr = dynamic_cast<ByteStreamAddress*>(pAddr);
+  FaserByteStreamAddress *pRE_Addr{nullptr};
+  pRE_Addr = dynamic_cast<FaserByteStreamAddress*>(pAddr);
   if (!pRE_Addr) {
-    ATH_MSG_ERROR("Cannot cast to ByteStreamAddress ");
+    ATH_MSG_ERROR("Cannot cast to FaserByteStreamAddress ");
     return StatusCode::FAILURE;
   }
 
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
index 90fb3113e..a43006e1b 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.h
@@ -20,7 +20,7 @@
 #include "AthenaBaseComps/AthMessaging.h"
 
 class FaserByteStreamCnvSvc;
-class IROBDataProviderSvc;
+class IFaserROBDataProviderSvc;
 class StoreGateSvc;
 
 // Abstract factory to create the converter
@@ -48,7 +48,7 @@ class EventInfoByteStreamAuxCnv : public Converter, public AthMessaging
  private:
   const char* ascTime(unsigned int t);    //!< convert timestamp to ascii time.
   FaserByteStreamCnvSvc* m_ByteStreamCnvSvc;   //!< pointer to BS CnvSvc
-  ServiceHandle<IROBDataProviderSvc> m_robDataProvider; //!< RODDataProviderSvc handle
+  ServiceHandle<IFaserROBDataProviderSvc> m_robDataProvider; //!< RODDataProviderSvc handle
   //ServiceHandle<StoreGateSvc> m_mdSvc;                  //!< TDS handle
   
   // flags for EventType
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
index 8fd407d8f..f9dcfe9df 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
@@ -3,7 +3,7 @@
 */
 
 #include "EventInfoByteStreamxAODCnv.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 
 #include "AthenaKernel/errorcheck.h"
 #include "GaudiKernel/MsgStream.h"
@@ -29,7 +29,7 @@ const CLID& EventInfoByteStreamxAODCnv::classID()
 
 long EventInfoByteStreamxAODCnv::storageType() 
 {
-  return ByteStreamAddress::storageType();
+  return FaserByteStreamAddress::storageType();
 }
 
 StatusCode EventInfoByteStreamxAODCnv::initialize() 
@@ -52,10 +52,10 @@ StatusCode EventInfoByteStreamxAODCnv::finalize()
 
 StatusCode EventInfoByteStreamxAODCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
 {
-  ByteStreamAddress *pRE_Addr{nullptr};
-  pRE_Addr = dynamic_cast<ByteStreamAddress*>(pAddr);
+  FaserByteStreamAddress *pRE_Addr{nullptr};
+  pRE_Addr = dynamic_cast<FaserByteStreamAddress*>(pAddr);
   if (!pRE_Addr) {
-    ATH_MSG_ERROR("Cannot cast to ByteStreamAddress ");
+    ATH_MSG_ERROR("Cannot cast to FaserByteStreamAddress ");
     return StatusCode::FAILURE;
   }
                
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
index 437f0f4ca..a28f22ff8 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamCnvSvc.cxx
@@ -4,8 +4,8 @@
 
 #include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
 //#include "ByteStreamCnvSvc/ByteStreamOutputSvc.h"
-#include "ByteStreamCnvSvcBase/FullEventAssembler.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+//#include "ByteStreamCnvSvcBase/FullEventAssembler.h"
+//#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 
 #include "StoreGate/StoreGate.h"
 #include "xAODEventInfo/EventInfo.h"
@@ -22,7 +22,7 @@
 
 /// Standard constructor
 FaserByteStreamCnvSvc::FaserByteStreamCnvSvc(const std::string& name, ISvcLocator* pSvcLocator)
-  : ByteStreamCnvSvcBase(name, pSvcLocator),
+  : FaserByteStreamCnvSvcBase(name, pSvcLocator),
     m_evtStore ("StoreGateSvc", name)
 {
   declareProperty("ByteStreamOutputSvc",     m_ioSvcName);
@@ -41,7 +41,7 @@ FaserByteStreamCnvSvc::~FaserByteStreamCnvSvc() {
 
 /// Initialize the service.
 StatusCode FaserByteStreamCnvSvc::initialize() {
-   if (!ByteStreamCnvSvcBase::initialize().isSuccess()) {
+   if (!FaserByteStreamCnvSvcBase::initialize().isSuccess()) {
       ATH_MSG_FATAL("FaserByteStreamCnvSvcBase::initialize() failed");
       return(StatusCode::FAILURE);
    }
@@ -94,7 +94,7 @@ StatusCode FaserByteStreamCnvSvc::initialize() {
 }
 
 StatusCode FaserByteStreamCnvSvc::finalize() {
-  return(ByteStreamCnvSvcBase::finalize());
+  return(FaserByteStreamCnvSvcBase::finalize());
 }
 
 StatusCode FaserByteStreamCnvSvc::connectOutput(const std::string& t, const std::string& /*mode*/) {
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
index 593bd1891..8cf738593 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
@@ -2,11 +2,12 @@
   Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
-#include "FaserByteStreamInputSvc.h"
+#include "FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h"
+
 #include "DumpFrags.h"
 
 #include "ByteStreamData/ByteStreamMetadataContainer.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 #include "FaserEventStorage/pickFaserDataReader.h"
 
 #include "GaudiKernel/IJobOptionsSvc.h"
@@ -39,7 +40,7 @@ using DAQFormats::EventFull;
 // Constructor.
 FaserByteStreamInputSvc::FaserByteStreamInputSvc(
        const std::string& name, ISvcLocator* svcloc) 
-  : ByteStreamInputSvc(name, svcloc)
+  : AthService(name, svcloc)
   , m_readerMutex()
   , m_eventsCache()
   , m_reader()
@@ -49,7 +50,7 @@ FaserByteStreamInputSvc::FaserByteStreamInputSvc(
   , m_fileGUID("")
   , m_storeGate    ("StoreGateSvc", name)
     //, m_inputMetadata("StoreGateSvc/InputMetaDataStore", name)
-  , m_robProvider  ("ROBDataProviderSvc", name)
+  , m_robProvider  ("FaserROBDataProviderSvc", name)
   , m_sequential   (this, "EnableSequential",   false, "")
   , m_dump         (this, "DumpFlag",           false, "Dump fragments")
   , m_wait         (this, "WaitSecs",              0., "Seconds to wait if input is in wait state")
@@ -69,7 +70,7 @@ FaserByteStreamInputSvc::~FaserByteStreamInputSvc() {
 StatusCode FaserByteStreamInputSvc::initialize() {
    ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
 
-   ATH_CHECK(ByteStreamInputSvc::initialize());
+   ATH_CHECK(FaserByteStreamInputSvc::initialize());
    //ATH_CHECK(m_inputMetadata.retrieve());
    ATH_CHECK(m_storeGate.retrieve());
    ATH_CHECK(m_robProvider.retrieve());
@@ -78,7 +79,7 @@ StatusCode FaserByteStreamInputSvc::initialize() {
 }
 //________________________________________________________________________________
 StatusCode FaserByteStreamInputSvc::stop() {
-   ATH_MSG_DEBUG("Calling ByteStreamInputSvc::stop()");
+   ATH_MSG_DEBUG("Calling FaserByteStreamInputSvc::stop()");
    // close moved to EventSelector for explicit coupling with incident
    return(StatusCode::SUCCESS);
 }
@@ -89,7 +90,7 @@ StatusCode FaserByteStreamInputSvc::finalize() {
   ATH_CHECK(m_robProvider.release()); 
   //ATH_CHECK(m_inputMetadata.release());
 
-  return(ByteStreamInputSvc::finalize());
+  return(FaserByteStreamInputSvc::finalize());
 }
 //------------------------------------------------------------------------------
 long FaserByteStreamInputSvc::positionInBlock()
@@ -161,7 +162,7 @@ const EventFull* FaserByteStreamInputSvc::nextEvent() {
 
   // Set it for the data provider
   ATH_MSG_DEBUG( "call robProvider->setNextEvent ");
-  m_robProvider->setNextEvent(context, reinterpret_cast<const RawEvent*>(cache->rawEvent.get()) );
+  m_robProvider->setNextEvent(context, cache->rawEvent.get() );
   m_robProvider->setEventStatus(context, cache->eventStatus );
 
   // dump
@@ -264,7 +265,7 @@ StatusCode FaserByteStreamInputSvc::generateDataHeader()
     key = m_eventInfoKey.value();
     ATH_CHECK(deleteEntry<xAOD::EventInfo>(key));
     // Now add ref to xAOD::EventInfo
-    std::unique_ptr<IOpaqueAddress> iopx = std::make_unique<ByteStreamAddress>(
+    std::unique_ptr<IOpaqueAddress> iopx = std::make_unique<FaserByteStreamAddress>(
 									       ClassID_traits<xAOD::EventInfo>::ID(), key, "");
     ATH_CHECK(m_storeGate->recordAddress(key, iopx.release()));
     const SG::DataProxy* ptmpx = m_storeGate->transientProxy(
@@ -278,7 +279,7 @@ StatusCode FaserByteStreamInputSvc::generateDataHeader()
     key = m_eventInfoKey.value() + "Aux.";
     ATH_CHECK(deleteEntry<xAOD::EventAuxInfo>(key));
     // Now add ref to xAOD::EventAuxInfo
-    std::unique_ptr<IOpaqueAddress> iopaux = std::make_unique<ByteStreamAddress>(
+    std::unique_ptr<IOpaqueAddress> iopaux = std::make_unique<FaserByteStreamAddress>(
 										 ClassID_traits<xAOD::EventAuxInfo>::ID(), key, "");
     ATH_CHECK(m_storeGate->recordAddress(key, iopaux.release()));
     const SG::DataProxy* ptmpaux = m_storeGate->transientProxy(
@@ -418,8 +419,8 @@ void FaserByteStreamInputSvc::setEvent( const EventContext& context, void* data,
   cache->eventStatus = eventStatus;
 
   // Set it for the data provider
-  m_robProvider->setNextEvent(context, reinterpret_cast<const RawEvent*>(cache->rawEvent.get()) );
-  m_robProvider->setEventStatus(context, cache->eventStatus );
+  m_robProvider->setNextEvent(context, cache->rawEvent.get());
+  m_robProvider->setEventStatus(context, cache->eventStatus);
 
   // Build a DH for use by other components
   StatusCode rec_sg = generateDataHeader();
@@ -427,6 +428,13 @@ void FaserByteStreamInputSvc::setEvent( const EventContext& context, void* data,
     ATH_MSG_ERROR("Fail to record BS DataHeader in StoreGate. Skipping events?! " << rec_sg);
   }
 }
+
+//__________________________________________________________________________
+inline const InterfaceID& FaserByteStreamInputSvc::interfaceID() {
+  /// Declaration of the interface ID ( interface id, major version, minor version)
+  static const InterfaceID IID_ByteStreamInputSvc("ByteStreamInputSvc", 1, 0);
+  return(IID_ByteStreamInputSvc);
+}
 //__________________________________________________________________________
 const EventFull* FaserByteStreamInputSvc::currentEvent() const {
   const EventContext context{ Gaudi::Hive::currentContext() };
@@ -439,8 +447,8 @@ unsigned int FaserByteStreamInputSvc::currentEventStatus() const {
 }
 //________________________________________________________________________________
 StatusCode FaserByteStreamInputSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
-   if (ByteStreamInputSvc::interfaceID().versionMatch(riid)) {
-      *ppvInterface = dynamic_cast<ByteStreamInputSvc*>(this);
+   if (FaserByteStreamInputSvc::interfaceID().versionMatch(riid)) {
+      *ppvInterface = dynamic_cast<FaserByteStreamInputSvc*>(this);
    } else {
      // Interface is not directly available: try out a base class
      return(::AthService::queryInterface(riid, ppvInterface));
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
index 6311fc550..c4f3e1464 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
@@ -9,9 +9,10 @@
 // Include files.
 #include "FaserEventSelectorByteStream.h"
 #include "FaserEventContextByteStream.h"
-#include "FaserByteStreamInputSvc.h"
+#include "FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h"
 #include "FaserByteStreamCnvSvc/ByteStreamExceptions.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+//#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
+#include "EventFormats/DAQFormats.hpp"
 
 #include "GaudiKernel/ClassID.h"
 #include "GaudiKernel/FileIncident.h"
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
index 34bdec974..1cf2abb70 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.h
@@ -33,7 +33,6 @@ class ISvcLocator;
 class IAthenaIPCTool;
 class FaserEventContextByteStream;
 class FaserByteStreamInputSvc;
-class IROBDataProviderSvc;
 
 // Class EventSelectorByteStream.
 class FaserEventSelectorByteStream : public ::AthService,
diff --git a/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx b/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
index c3490e2bb..72174e55a 100644
--- a/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/components/FaserByteStreamCnvSvc_entries.cxx
@@ -1,5 +1,5 @@
 #include "FaserByteStreamCnvSvc/FaserByteStreamCnvSvc.h"
-#include "../FaserByteStreamInputSvc.h"
+#include "FaserByteStreamCnvSvc/FaserByteStreamInputSvc.h"
 #include "../FaserEventSelectorByteStream.h"
 #include "../EventInfoByteStreamxAODCnv.h"
 #include "../EventInfoByteStreamAuxCnv.h"
diff --git a/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt b/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
new file mode 100644
index 000000000..d3dcab1b3
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
@@ -0,0 +1,46 @@
+################################################################################
+# Package: FaserByteStreamCnvSvcBase
+################################################################################
+
+# Declare the package name:
+atlas_subdir( FaserByteStreamCnvSvcBase )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthenaBaseComps
+                          Control/AthenaKernel
+                          Control/StoreGate
+                          #Event/ByteStreamData
+                          GaudiKernel
+			  ByteStreamCnvSvcBase
+                          PRIVATE
+                          Control/SGTools
+			  AtlasTest/TestTools 
+			  EventFormats
+			  Logging)
+
+# External dependencies:
+# find_package( tdaq-common COMPONENTS eformat eformat_write )
+
+# Component(s) in the package:
+atlas_add_library( FaserByteStreamCnvSvcBaseLib
+                   src/*.cxx
+                   PUBLIC_HEADERS FaserByteStreamCnvSvcBase
+                   # INCLUDE_DIRS  ${TDAQ-COMMON_INCLUDE_DIRS}
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GaudiKernel StoreGateLib SGtests ByteStreamCnvSvcBaseLib
+                   PRIVATE_LINK_LIBRARIES SGTools )
+
+atlas_add_component( FaserByteStreamCnvSvcBase
+                     src/components/*.cxx
+                     # INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS}
+                     LINK_LIBRARIES AthenaBaseComps AthenaKernel StoreGateLib SGtests GaudiKernel SGTools FaserByteStreamCnvSvcBaseLib )
+
+
+#atlas_add_test( ROBDataProviderSvcMT	
+#		 SCRIPT test/test_ROBDataProviderSvcMT.sh	 
+#		 PROPERTIES TIMEOUT 1200 )
+#
+
+# Install files from the package:
+atlas_install_joboptions( share/*.py )
+
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h
new file mode 100644
index 000000000..c2f608bf8
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVCBASE_FASERBYTESTREAMADDRESS_H
+#define FASERBYTESTREAMCNVSVCBASE_FASERBYTESTREAMADDRESS_H
+
+// Framework include files
+#include "GaudiKernel/GenericAddress.h"
+#include "GaudiKernel/EventContext.h"
+
+#include <stdint.h>
+#include <vector>
+
+/**
+ *  @class  ByteStreamAddress
+ *  @brief  IOpaqueAddress for ByteStreamCnvSvc, with ROB ids
+ *
+ *  Package     : ByteStreamCnvSvcBase
+ *
+ *  description : Definition of RawEvent address class
+ *                This class holds a vector of ROBIDs
+ *  @author     : H. Ma
+ *  Revision    : July 10, 2002, Use new eformat package
+ *  Revision    : Sept 19, 2002, Store ROB IDs, to be used with ROBDataProviderSvc
+ */
+
+class FaserByteStreamAddress : public GenericAddress {
+ public:
+  // @brief Constructor
+  FaserByteStreamAddress(const CLID& clid, const std::string& fname, const std::string& cname, int p1 = 0, int p2 = 0);
+  // @brief Constructor
+  FaserByteStreamAddress(const CLID& clid);
+
+  // @brief Destructor
+  virtual ~FaserByteStreamAddress() {}; //doesn't own event
+
+  // @brief Add a rob id
+  void add(uint32_t robid);
+
+  // @brief Add event id
+  void setEventContext(const EventContext& eid);
+
+  // @brief access the ROB fragment IDs
+  const std::vector<uint32_t>& getRobIDs() const;
+
+  // @brief get event id
+  const EventContext& getEventContext() const;
+
+  // @brief storage type to be used by all bytestream converters
+  static constexpr long storageType() { return 0x43; }
+
+ private:
+  // @brief it holds a vector of rob ids
+  std::vector<uint32_t> m_robIDs;
+  EventContext m_eid;
+};
+
+inline void FaserByteStreamAddress::setEventContext(const EventContext& eid) 
+{ m_eid = eid; }
+
+inline const EventContext& FaserByteStreamAddress::getEventContext() const
+{ return m_eid; }
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h
new file mode 100644
index 000000000..7e62ffb86
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVCBASE_BYTESTREAMADDRESSPROVIDERSVC_H
+#define FASERBYTESTREAMCNVSVCBASE_BYTESTREAMADDRESSPROVIDERSVC_H
+
+#include "AthenaKernel/IAddressProvider.h"
+#include "AthenaBaseComps/AthService.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include <vector>
+#include <string>
+#include <map>
+#include <set>
+
+class IClassIDSvc;
+
+template <class TYPE> class SvcFactory;
+
+/** @class FaserByteStreamAddressProviderSvc
+    @brief An concrete IAddressProvider
+*/
+class FaserByteStreamAddressProviderSvc : public ::AthService, public virtual IAddressProvider {
+   /// Allow the factory class access to the constructor
+   friend class SvcFactory<FaserByteStreamAddressProviderSvc>;
+
+public:
+   FaserByteStreamAddressProviderSvc(const std::string& name, ISvcLocator* pSvcLocator);
+   virtual ~FaserByteStreamAddressProviderSvc();
+
+   // Service initialize
+   virtual StatusCode initialize();
+   virtual StatusCode finalize();
+
+   // IAddressProvider interface.
+   // preload the address
+   virtual StatusCode preLoadAddresses(StoreID::type id, tadList& tlist);
+
+   /// update an existing transient Address
+   virtual StatusCode updateAddress(StoreID::type id,
+                                    SG::TransientAddress* tad,
+                                    const EventContext& ctx);
+
+private:
+   // type and name of the objects to create the address for.
+   Gaudi::Property<std::vector<std::string> > m_typeNames{this,"TypeNames",{},\
+       "Type and Name of objects to create the address for","OrderedSet<std::string>"};
+
+
+   ServiceHandle<IClassIDSvc> m_clidSvc;
+
+   std::map<unsigned int, std::set<std::string> > m_clidKey;
+
+   int m_storeID;
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h
new file mode 100644
index 000000000..6496bf485
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVCBASE_BYTESTREAMCNVSVCBASE_H
+#define FASERBYTESTREAMCNVSVCBASE_BYTESTREAMCNVSVCBASE_H
+
+#include "GaudiKernel/IIncidentListener.h"
+#include "AthenaBaseComps/AthCnvSvc.h"
+#include "FaserByteStreamCnvSvcBase/IFaserByteStreamEventAccess.h"
+
+/**
+  @class FaserByteStreamCnvSvcBase
+  @brief base class for ByteStream conversion service.
+
+  description
+         This class is used as a conversion service in online HLT
+	 and it is the base class for offline bytestream conversion service.
+*/
+class FaserByteStreamCnvSvcBase : public ::AthCnvSvc,
+		public virtual IIncidentListener,
+		public virtual IFaserByteStreamEventAccess {
+
+public:
+   /// Standard Service Constructor
+   FaserByteStreamCnvSvcBase(const std::string& name, ISvcLocator* pSvcLocator);
+   /// Destructor
+
+   virtual ~FaserByteStreamCnvSvcBase();
+   /// Required of all Gaudi Services
+   virtual StatusCode initialize() override;
+
+   /// Required of all Gaudi services:  see Gaudi documentation for details
+   virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface) override;
+
+   /// Checks whether an IOpaqueAddress is a GenericAddress
+   virtual StatusCode updateServiceState(IOpaqueAddress* pAddress) override;
+
+   /// Implementation of IByteStreamEventAccess: Get RawEvent
+   // virtual RawEventWrite* getRawEvent() override { return m_rawEventWrite; }
+
+   /// Implementation of IIncidentListener: Handle for EndEvent incidence
+   virtual void handle(const Incident&) override;
+
+protected: // data
+   // RawEventWrite* m_rawEventWrite;
+
+   std::vector<std::string> m_initCnvs;
+   std::vector<std::string> m_ROD2ROBmap;
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
new file mode 100644
index 000000000..51c1e3823
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVCBASE_ROBDATAPROVIDERSVC_H
+#define FASERBYTESTREAMCNVSVCBASE_ROBDATAPROVIDERSVC_H
+
+/** ===============================================================
+ * @class    ROBDataProviderSvc.h
+ * @brief  ROBDataProvider class for accessing ROBData
+ *
+ *    Requirements: define a ROBData class in the scope
+ *                  provide a method
+ *       void getROBData(const vector<uint>& ids, vector<ROBData*>& v)
+ *    Implementation: Use an interal map to store all ROBs
+ *                    We can not assume any ROB/ROS relationship, no easy
+ *                    way to search.
+ *                    This implementation is used in offline
+ *
+ *    Created:      Sept 19, 2002
+ *         By:      Hong Ma
+ *    Modified:     Aug. 18  2003 (common class for Online/Offline)
+ *         By:      Werner Wiedenmann
+ *    Modified:     Apr  21  2005 (remove dependency on data flow repository)
+ *         By:      Werner Wiedenmann
+ */
+
+#include "FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h"
+#include "AthenaBaseComps/AthService.h"
+#include "AthenaKernel/SlotSpecificObj.h"
+
+#include <vector>
+#include <map>
+
+namespace DAQFormats {
+  class EventFull;
+}
+
+class FaserROBDataProviderSvc :  public extends<AthService, IFaserROBDataProviderSvc> {
+
+public:
+   /// ROB Fragment class
+   //typedef OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment ROBF;
+
+   /// Constructor
+   FaserROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc);
+   /// Destructor
+   virtual ~FaserROBDataProviderSvc();
+
+   /// initialize the service
+   virtual StatusCode initialize() override;
+
+   /// Gaudi queryInterface method.
+   //   virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
+
+   /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
+   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") override;
+
+   /// Add a given LVL1/LVL2 ROBFragment to cache
+   //virtual void setNextEvent(const std::vector<ROBF>& result) override;
+
+   /// Add all ROBFragments of a RawEvent to cache
+   virtual void setNextEvent(const DAQFormats::EventFull* re) override;
+
+   /// Retrieve ROBFragments for given ROB ids from cache
+   //virtual void getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, const std::string_view callerName="UNKNOWN") override;
+
+   /// Retrieve the whole event.
+   virtual const DAQFormats::EventFull* getEvent() override;
+
+   /// Store the status for the event.
+   virtual void setEventStatus(uint32_t status) override;
+
+   /// Retrieve the status for the event.
+   virtual uint32_t getEventStatus() override;
+
+
+   /// MT variants 
+   virtual void addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") override;
+   //virtual void setNextEvent(const EventContext& context, const std::vector<OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment>& result) override;
+   virtual void setNextEvent(const EventContext& context, const DAQFormats::EventFull* re) override;
+   //virtual void getROBData(const EventContext& context, const std::vector<uint32_t>& robIds, VROBFRAG& robFragments, 
+   //			   const std::string_view callerName="UNKNOWN") override;
+   virtual const DAQFormats::EventFull* getEvent(const EventContext& context) override;
+   virtual void setEventStatus(const EventContext& context, uint32_t status) override;
+   virtual uint32_t getEventStatus(const EventContext& context) override;
+
+//virtual void processCachedROBs(const EventContext& context, 
+//				  const std::function< void(const ROBF* )>& fn ) const override;
+
+   virtual bool isEventComplete(const EventContext& /*context*/) const override { return true; }
+   virtual int collectCompleteEventData(const EventContext& /*context*/, const std::string_view /*callerName*/ ) override {  return 0; }
+
+protected:
+   /// vector of ROBFragment class
+   //typedef std::vector<ROBF*> VROBF;
+
+   /// map for all the ROB fragments
+   //typedef std::map<uint32_t, const ROBF*, std::less<uint32_t> > ROBMAP;
+
+  struct EventCache {
+    ~EventCache();
+    const DAQFormats::EventFull* event = 0;
+    uint32_t eventStatus = 0;    
+    uint32_t currentLvl1ID = 0;    
+    //ROBMAP robmap;
+ 
+  };
+  SG::SlotSpecificObj<EventCache> m_eventsCache;
+
+   /// Remaining attributes are for configuration
+   /// vector of Source ids and status words to be ignored for the ROB map
+   typedef SimpleProperty< std::vector< std::pair<int, int> > > ArrayPairIntProperty;
+   ArrayPairIntProperty  m_filterRobWithStatus; // filter with full ROB SourceID
+   ArrayPairIntProperty  m_filterSubDetWithStatus;  // filter with Sub Det ID
+
+   /// map of full ROB Source ids and status words to be ignored for the ROB map
+   //typedef std::map<uint32_t, std::vector<uint32_t> > FilterRobMap;
+   //FilterRobMap          m_filterRobMap;
+   /// map of Sub Det Source ids and status words to be ignored for the ROB map
+   //typedef std::map<eformat::SubDetector, std::vector<uint32_t> > FilterSubDetMap;
+   //FilterSubDetMap       m_filterSubDetMap;
+   /// method to filter ROBs with given Status code
+   //bool filterRobWithStatus(const ROBF* rob);
+
+   /// Filter out empty ROB fragments which are send by the ROS
+   BooleanProperty m_filterEmptyROB;
+   bool m_maskL2EFModuleID = false;    
+
+private: // data
+
+private: //
+   //static void robmapClear(ROBMAP& toclear);
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserByteStreamEventAccess.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserByteStreamEventAccess.h
new file mode 100644
index 000000000..cfc5077f1
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserByteStreamEventAccess.h
@@ -0,0 +1,27 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FASERBYTESTREAMCNVSVCBASE_IBYTESTREAMEVENTACCESS_H
+#define FASERBYTESTREAMCNVSVCBASE_IBYTESTREAMEVENTACCESS_H
+
+//#include "ByteStreamData/RawEvent.h"
+#include "GaudiKernel/IInterface.h"
+
+/** @class IByteStreamEventAccess
+ * @brief interface for accessing raw data .
+ */
+static const InterfaceID
+IID_IFaserByteStreamEventAccess("IFaserByteStreamEventAccess", 2 , 0);
+
+class IFaserByteStreamEventAccess: virtual public IInterface {
+ public:
+  /// Gaudi interface id
+  static const InterfaceID& interfaceID() { return IID_IFaserByteStreamEventAccess; }
+
+  /// pure virtual method for accessing RawEventWrite
+  //virtual RawEventWrite* getRawEvent() = 0;
+
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
new file mode 100644
index 000000000..213c6b93d
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef IFASERROBDATAPROVIDERSVC_H
+#define IFASERROBDATAPROVIDERSVC_H
+
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/EventContext.h"
+
+#include <cstdint>
+#include <vector>
+#include <string>
+#include <string_view>
+#include <stdexcept>
+#include <functional>
+
+namespace DAQFormats {
+  class EventFull;
+}
+
+// Declaration of the interface ID ( interface id, major version, minor version)
+//static const InterfaceID IID_IROBDataProviderSvc("IROBDataProviderSvc", 1 , 0);
+
+/** @class IFaserROBDataProviderSvc
+    @brief Interface class for managing ROB for both online and offline.
+*/
+class IFaserROBDataProviderSvc : virtual public IInterface {
+
+public:
+  //typedef OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment ROBF;
+  //typedef std::vector<const ROBF*> VROBFRAG;
+
+   /// Retrieve interface ID
+  //   static const InterfaceID& interfaceID() { return IID_IFaserROBDataProviderSvc; }
+  DeclareInterfaceID(IFaserROBDataProviderSvc, 1, 1);
+
+   /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
+   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") = 0 ;
+
+   /// Add a given LVL1/LVL2 ROBFragment to cache
+   //virtual void setNextEvent(const std::vector<ROBF>& result) = 0 ;
+
+
+   /// Add all ROBFragments of a RawEvent to cache
+   virtual void setNextEvent(const DAQFormats::EventFull* re) = 0 ;
+
+
+   /// Retrieve ROBFragments for given ROB ids from cache
+   //virtual void getROBData(const std::vector<uint32_t>& robIds, VROBFRAG& robFragments, const std::string_view callerName="UNKNOWN") = 0;
+
+
+   /// Retrieve the whole event.
+   virtual const DAQFormats::EventFull* getEvent() = 0;
+
+
+   /// Store the status for the event.
+   virtual void setEventStatus(uint32_t status) = 0;
+
+
+   /// Retrieve the status for the event.
+   virtual uint32_t getEventStatus() = 0;
+
+
+   // variants for MT, it has an implementation for now in order not to require change in all implementations yet, they will all become pure virtual methods
+   virtual void addROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, const std::string_view callerName="UNKNOWN") { 
+     throw std::runtime_error( std::string(callerName)+ std::string(" is using unimplemented ") + __FUNCTION__ ) ; 
+   }
+   //virtual void setNextEvent(const EventContext& /*context*/, const std::vector<ROBF>& /*result*/) {
+   //  throw std::runtime_error( std::string("Unimplemented ") + __FUNCTION__ ); 
+   //}
+   virtual void setNextEvent( const EventContext& /*context*/, const DAQFormats::EventFull* /*re*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   //virtual void getROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, VROBFRAG& /*robFragments*/, 
+   //		   const std::string_view callerName="UNKNOWN") { 
+   //throw std::runtime_error( std::string(callerName)+ std::string(" is using unimplemented ") + __FUNCTION__ ) ; 
+   //}
+   virtual const DAQFormats::EventFull* getEvent(const EventContext& /*context*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual void setEventStatus(const EventContext& /*context*/, uint32_t /*status*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual uint32_t getEventStatus(const EventContext& /*context*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+     return 0;
+   }
+   
+   /// @brief Interface to access cache of ROBs (it is a full event in case of offline)
+   /// In online implementation the cache will contain only a subset of ROBs. 
+   /// This method allows read access to the cache. 
+   /// @warning in case the cache is updated in the meantime the iteration is guaranteed to be safe 
+   /// but may not give access to all the ROBs available n the very moment
+   /// Example of counting: size_t counter = 0; svc->processCahcedROBs(ctx, [&](const ROBF*){ counter ++; })
+   /// Example of printout: svc->processCahcedROBs(ctx, [&](const ROBF* rob){ log() << MSG::DEBUG << "ROB " << rob->source_id() << endmsg; })
+   //   virtual void processCachedROBs(const EventContext& /*context*/, 
+   //				  const std::function< void(const ROBF* )>& /*fn*/ ) const {
+   //     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   //}
+  
+  /// Check if complete event data are already in cache
+  virtual bool isEventComplete(const EventContext& /*context*/) const {
+    throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ );      
+  } 
+  
+  /// @brief Collect all data for an event from the ROS and put them into the cache
+  /// @return value: number of ROBs which were retrieved to complete the event
+  /// Optionally the name of the caller of this method can be specified for monitoring
+  virtual int collectCompleteEventData(const EventContext& /*context*/, const std::string_view callerName="UNKNOWN") {
+    throw std::runtime_error(std::string(callerName) + std::string(" is using unimplemented ") + __FUNCTION__ );
+    return 0;
+  }
+
+};
+
+#endif
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddress.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddress.cxx
new file mode 100644
index 000000000..96d9147af
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddress.cxx
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+//====================================================================
+//FaserByteStreamAddress implementation
+//--------------------------------------------------------------------
+//
+//Package    : ByteStreamCnvSvcBase
+//
+//  Description:     BSCnvSvc address implementation
+//
+//Author     : Hong Ma
+//      created    : MAr 2, 2001
+//  History    :
+//  Revision:  Sept 19, 2002
+//             Store ROB IDs, to be used with ROBDataProviderSvc
+//====================================================================
+
+//own
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
+
+// Framework include files
+#include "GaudiKernel/GenericAddress.h"
+
+/// Standard Constructor
+FaserByteStreamAddress::FaserByteStreamAddress(const CLID& clid,
+				     const std::string& fname , const std::string& cname, int p1, int p2)
+  : GenericAddress(storageType(), clid, fname, cname, p1, p2), m_eid(0,0) {
+}
+
+FaserByteStreamAddress::FaserByteStreamAddress(const CLID& clid)
+  : GenericAddress(storageType(), clid, "", "") {
+}
+
+/** Add ROBID
+ */
+void FaserByteStreamAddress::add( uint32_t robid) {
+  m_robIDs.push_back(robid);
+}
+
+/** access the fragment pointer
+ */
+const std::vector<uint32_t>&  FaserByteStreamAddress::getRobIDs() const {
+  return(m_robIDs);
+}
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
new file mode 100644
index 000000000..75e999d2a
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
@@ -0,0 +1,101 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Include files
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+//#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+
+#include "StoreGate/StoreGate.h"
+#include "SGTools/TransientAddress.h"
+#include "GaudiKernel/ListItem.h"
+
+#include "AthenaKernel/IClassIDSvc.h"
+
+//#include "eformat/SourceIdentifier.h"
+
+/// Standard constructor
+FaserByteStreamAddressProviderSvc::FaserByteStreamAddressProviderSvc(const std::string& name, ISvcLocator* pSvcLocator) :
+	 ::AthService(name, pSvcLocator),
+	m_clidSvc("ClassIDSvc", name),
+	m_storeID(StoreID::EVENT_STORE) {
+  declareProperty("StoreID", m_storeID);
+}
+//________________________________________________________________________________
+FaserByteStreamAddressProviderSvc::~FaserByteStreamAddressProviderSvc() {
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamAddressProviderSvc::initialize() {
+   ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
+   if (!::AthService::initialize().isSuccess()) {
+      ATH_MSG_FATAL("Cannot initialize AthService base class.");
+      return(StatusCode::FAILURE);
+   }
+
+   // Retrieve ClassIDSvc
+   if (!m_clidSvc.retrieve().isSuccess()) {
+      ATH_MSG_FATAL("Cannot get ClassIDSvc.");
+      return(StatusCode::FAILURE);
+   }
+   if (m_storeID < 0 || m_storeID > StoreID::UNKNOWN) {
+      ATH_MSG_FATAL("Invalid StoreID " << m_storeID);
+      return(StatusCode::FAILURE);
+   }
+   ATH_MSG_INFO("initialized ");
+   ATH_MSG_INFO("-- Will fill Store with id =  " << m_storeID);
+   return(StatusCode::SUCCESS);
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamAddressProviderSvc::finalize() {
+   // Release ClassIDSvc
+   if (!m_clidSvc.release().isSuccess()) {
+      ATH_MSG_WARNING("Cannot release ClassIDSvc.");
+   }
+   return(::AthService::finalize());
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamAddressProviderSvc::preLoadAddresses(StoreID::type id, tadList& tlist) {
+   ATH_MSG_DEBUG("in preLoadAddress");
+   if (id != m_storeID) {
+      ATH_MSG_DEBUG("StoreID = " << id << " does not match required id (" << m_storeID << ") skip");
+      return(StatusCode::SUCCESS);
+   }
+
+   for (std::vector<std::string>::const_iterator it = m_typeNames.begin(), it_e = m_typeNames.end();
+	   it != it_e; it++) {
+      ListItem item(*it);
+      const std::string& t = item.type();
+      const std::string& nm = item.name();
+      CLID classid;
+      if (!m_clidSvc->getIDOfTypeName(t, classid).isSuccess()) {
+         ATH_MSG_WARNING("Cannot create TAD for (type, name)" << " no CLID for " << t << " " << nm);
+      } else {
+         SG::TransientAddress* tad = new SG::TransientAddress(classid, nm);
+         tlist.push_back(tad);
+         ATH_MSG_DEBUG("Created TAD for (type, clid, name)" << t << " " << classid << " " << nm);
+         // save the clid and key.
+         m_clidKey[classid].insert(nm);
+      }
+   }
+   return(StatusCode::SUCCESS);
+}
+//________________________________________________________________________________
+StatusCode FaserByteStreamAddressProviderSvc::updateAddress(StoreID::type id,
+                                                       SG::TransientAddress* tad,
+                                                       const EventContext& ctx) {
+   if (id != m_storeID) {
+      return(StatusCode::FAILURE);
+   }
+   CLID clid = tad->clID();
+   std::string nm = tad->name();
+   std::map<CLID, std::set<std::string> >::const_iterator it = m_clidKey.find(clid);
+   if (it == m_clidKey.end() || (*it).second.count(nm) == 0) {
+      return(StatusCode::FAILURE);
+   }
+   ATH_MSG_DEBUG("Creating address for " << clid << " " << nm);
+   ByteStreamAddress* add = new ByteStreamAddress(clid, nm, "");
+   add->setEventContext(ctx);
+   tad->setAddress(add);
+   return(StatusCode::SUCCESS);
+}
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
new file mode 100644
index 000000000..53b7470ed
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
@@ -0,0 +1,89 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h"
+#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+
+#include "GaudiKernel/IOpaqueAddress.h"
+#include "GaudiKernel/GenericAddress.h"
+#include "GaudiKernel/IConverter.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/IIncidentSvc.h"
+
+#include "AthenaKernel/IClassIDSvc.h"
+#include "StoreGate/StoreGate.h" 
+
+//______________________________________________________________________________
+FaserByteStreamCnvSvcBase::FaserByteStreamCnvSvcBase(const std::string& name, ISvcLocator* pSvcLocator) :
+   ::AthCnvSvc(name, pSvcLocator, ByteStreamAddress::storageType())
+   // , m_rawEventWrite(0) 
+{
+   declareProperty("InitCnvs", m_initCnvs); 
+   // This property is used by Tile BS converter, not by this class.
+   declareProperty("ROD2ROBmap", m_ROD2ROBmap);
+}
+//______________________________________________________________________________
+/// Standard Destructor
+FaserByteStreamCnvSvcBase::~FaserByteStreamCnvSvcBase()   {
+}
+//______________________________________________________________________________
+/// Initialize the service.
+StatusCode FaserByteStreamCnvSvcBase::initialize()     {
+   if (!::AthCnvSvc::initialize().isSuccess()) {
+      ATH_MSG_FATAL("Cannot initialize AthCnvSvc base class.");
+      return(StatusCode::FAILURE);
+   }
+
+   ServiceHandle<IIncidentSvc> incsvc("IncidentSvc", this->name());
+   if (!incsvc.retrieve().isSuccess()) {
+      ATH_MSG_FATAL("Cannot get IncidentSvc.");
+      return(StatusCode::FAILURE);
+   }
+   incsvc->addListener(this, "BeginRun", 0, false, true); // true for singleshot
+   return(StatusCode::SUCCESS);
+}
+//_______________________________________________________________________
+StatusCode FaserByteStreamCnvSvcBase::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+   if (IFaserByteStreamEventAccess::interfaceID().versionMatch(riid)) {
+      *ppvInterface = dynamic_cast<IFaserByteStreamEventAccess*>(this);
+   } else {
+      // Interface is not directly available: try out a base class
+      return(::AthCnvSvc::queryInterface(riid, ppvInterface));
+   }
+   addRef();
+   return(StatusCode::SUCCESS);
+}
+//______________________________________________________________________________
+StatusCode FaserByteStreamCnvSvcBase::updateServiceState(IOpaqueAddress* pAddress) {
+   if (pAddress != 0) {
+      GenericAddress* pAddr = dynamic_cast<GenericAddress*>(pAddress);
+      if (pAddr != 0) {
+         return(StatusCode::SUCCESS);
+      }
+   }
+   return(StatusCode::FAILURE);
+}
+//______________________________________________________________________________
+void FaserByteStreamCnvSvcBase::handle(const Incident& /*incident*/) {
+   ServiceHandle<IClassIDSvc> clidSvc("ClassIDSvc", name());
+   if (!clidSvc.retrieve().isSuccess()) {
+      ATH_MSG_ERROR("Cannot get ClassIDSvc.");
+      return;
+   }
+   // Initialize the converters
+   for (std::vector<std::string>::const_iterator it = m_initCnvs.begin(), it_e = m_initCnvs.end();
+		   it != it_e; it++) {
+      ATH_MSG_DEBUG("Accessing Converter for " << *it);
+      CLID id;
+      if (!clidSvc->getIDOfTypeName(*it, id).isSuccess()) {
+         ATH_MSG_WARNING("Cannot get CLID for " << *it);
+      } else {
+         IConverter* cnv = converter(id);
+         if (cnv == 0) {
+	    ATH_MSG_WARNING("Cannot get converter for " << *it);
+         } 
+      }
+   } 
+   return;
+}
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
new file mode 100644
index 000000000..15edee977
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
@@ -0,0 +1,482 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//===================================================================
+//  Implementation of ROBDataProviderSvc
+//  Revision: November 2017
+//      MT readiness
+//  Revision:  July 11, 2002
+//      Modified for eformat
+//  Revision:  Aug 18, 2003
+//      Modified to use ROBFragments directly and include methods
+//      for online
+//  Revision:  Apr 21, 2005
+//      Remove dependency on Level-2 Data Collector, create special
+//      version for online
+//  Revision:  Oct 29, 2006
+//      Increase MAX_ROBFRAGMENTS to 2048 to cover the special case
+//      when in a "localhost" partition the complete event is given
+//      to the Event Filter as one single ROS fragment (this case
+//      should not happen for normal running when several ROSes are
+//      used and the ROB fragments are grouped under different ROS
+//      fragments)
+//  Revision:  Nov 10, 2008
+//      Mask off the module ID from the ROB source identifier of the
+//      L2 and EF result when storing it in the ROB map. This is necessary
+//      when the L2/PT node ID is stored in the source identifier as
+//      module ID. With this modification the L2 and EF result can still be
+//      found as 0x7b0000 and 0x7c0000
+//  Revision:  Jan 12, 2009
+//      Allow removal of individual ROBs and ROBs from given subdetectors
+//      from the internal ROB map according to a given status code.
+//      This may be necessary when corrupted and incomplete ROB fragments
+//      are forwarded to the algorithms and the converters are not yet
+//      prepared to handle the specific cases.
+//      The filtering can be configured with job options as:
+//
+//      for individual ROBs as :
+//      ------------------------
+//      ROBDataProviderSvc.filterRobWithStatus = [ (ROB SourceId, StatusCode to remove),
+//                                                 (ROB SourceId 2, StatusCode to remove 2), ... ]
+//      and:
+//      ROBDataProviderSvc.filterRobWithStatus += [ (ROB SourceId n, StatusCode to remove n) ]
+//
+//      Example:
+//      ROBDataProviderSvc.filterRobWithStatus  = [ (0x42002a,0x0000000f), (0x42002e,0x00000008) ]
+//      ROBDataProviderSvc.filterRobWithStatus += [ (0x42002b,0x00000000) ]
+//
+//      for all ROBs of a given sub detector as :
+//      -----------------------------------------
+//      ROBDataProviderSvc.filterSubDetWithStatus = [ (Sub Det Id, StatusCode to remove),
+//                                                    (Sub Det Id 2, StatusCode to remove 2), ... ]
+//      and:
+//      ROBDataProviderSvc.filterSubDetWithStatus += [ (Sub Det Id n, StatusCode to remove n) ]
+//
+//      Example:
+//      ROBDataProviderSvc.filterSubDetWithStatus  = [ (0x41,0x00000000), (0x42,0x00000000) ]
+//      ROBDataProviderSvc.filterSubDetWithStatus += [ (0x41,0xcb0002) ]
+//
+//      For valid ROB Source Ids, Sub Det Ids and ROB Status elements see the event format
+//      document ATL-D-ES-0019 (EDMS)
+//  Revision:  Jan 28, 2014
+//      For Run 1 the module ID from the ROB source identifier of the
+//      L2 and EF result needed to be masked off before storing the ROB fragment 
+//      in the ROB map. The module ID for these fragments contained an identifier 
+//      of the machine on which they were produced. This produced as many different ROB IDs
+//      for these fragments as HLT processors were used. The module IDs were not useful 
+//      for analysis and needed to be masked off from these fragments in the ROB map in order 
+//      to allow the access to the L2 or the EF result with the generic identifiers  
+//      0x7b0000 and 0x7c0000. Also an event contained only one L2 and EF result.
+//      From Run 2 on (eformat version 5) the HLT processor identifier is not anymore
+//      stored in the module ID of the HLT result. Further there can be in one event several HLT result
+//      records with the source identifier 0x7c. The different HLT results are distinguished
+//      now with the module ID. A module ID 0 indicates a physiscs HLT result as before, while
+//      HLT results with module IDs different from zero are produced by data scouting chains. 
+//      In Run 2 the module ID should be therefore not any more masked.
+//      The masking of the moduleID is switched on when a L2 result is found in the event or the
+//      event header contains L2 trigger info words. This means the data were produced with run 1 HLT system.
+//
+//===================================================================
+
+// Include files.
+#include "FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h"
+#include "EventFormats/DAQFormats.hpp"
+//#include "eformat/Status.h"
+
+using DAQFormats::EventFull;
+
+// Constructor.
+FaserROBDataProviderSvc::FaserROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc) 
+  : base_class(name, svcloc) {
+
+  declareProperty("filterRobWithStatus", m_filterRobWithStatus);
+  declareProperty("filterSubDetWithStatus", m_filterSubDetWithStatus);
+  declareProperty("filterEmptyROB", m_filterEmptyROB = false);
+}
+
+// Destructor.
+FaserROBDataProviderSvc::~FaserROBDataProviderSvc() {
+  // the eventsCache take care of cleaaning itself
+}
+
+// Initialization
+StatusCode FaserROBDataProviderSvc::initialize() {
+   ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
+   if (!::AthService::initialize().isSuccess()) {
+      ATH_MSG_FATAL("Cannot initialize AthService base class.");
+      return(StatusCode::FAILURE);
+   }
+   m_eventsCache = SG::SlotSpecificObj<EventCache>( SG::getNSlots() );
+
+   /*   
+   for (unsigned int i = 0; i < m_filterRobWithStatus.value().size(); i++) {
+      eformat::helper::SourceIdentifier tmpsrc(m_filterRobWithStatus.value()[i].first);
+      if (tmpsrc.human_detector() != "UNKNOWN") {
+         m_filterRobMap[tmpsrc.code()].push_back(m_filterRobWithStatus.value()[i].second);
+      }
+   }
+   for (unsigned int i = 0; i < m_filterSubDetWithStatus.value().size(); i++) {
+      eformat::helper::SourceIdentifier tmpsrc((eformat::SubDetector)m_filterSubDetWithStatus.value()[i].first, 0);
+      if (tmpsrc.human_detector() != "UNKNOWN") {
+         m_filterSubDetMap[tmpsrc.subdetector_id()].push_back(m_filterSubDetWithStatus.value()[i].second);
+      }
+   }
+   ATH_MSG_INFO(" ---> Filter out empty ROB fragments                               = " << m_filterEmptyROB);
+   ATH_MSG_INFO(" ---> Filter out specific ROBs by Status Code: # ROBs = " << m_filterRobMap.size());
+   for (FilterRobMap::const_iterator it = m_filterRobMap.begin(), itEnd = m_filterRobMap.end();
+		   it != itEnd; it++) {
+      eformat::helper::SourceIdentifier tmpsrc(it->first);
+      ATH_MSG_INFO("      RobId=0x" << MSG::hex << it->first << " -> in Sub Det = " << tmpsrc.human_detector());
+      for (std::vector<uint32_t>::const_iterator it_status = (*it).second.begin(), it_statusEnd = (*it).second.end();
+		      it_status != it_statusEnd; it_status++) {
+         eformat::helper::Status tmpstatus(*it_status);
+         ATH_MSG_INFO("         Status Code=0x"
+	         << MSG::hex << std::setfill( '0' ) << std::setw(8) << tmpstatus.code()
+	         << " Generic Part=0x" << std::setw(4) << tmpstatus.generic()
+	         << " Specific Part=0x" << std::setw(4) << tmpstatus.specific());
+      }
+   }
+
+   ATH_MSG_INFO(" ---> Filter out Sub Detector ROBs by Status Code: # Sub Detectors = " << m_filterSubDetMap.size());
+   for (FilterSubDetMap::const_iterator it = m_filterSubDetMap.begin(), itEnd = m_filterSubDetMap.end();
+		   it != itEnd; it++) {
+      eformat::helper::SourceIdentifier tmpsrc(it->first, 0);
+      ATH_MSG_INFO("      SubDetId=0x" << MSG::hex << it->first << " -> " << tmpsrc.human_detector());
+      for (std::vector<uint32_t>::const_iterator it_status = (*it).second.begin(), it_statusEnd = (*it).second.end();
+		      it_status != it_statusEnd; it_status++) {
+         eformat::helper::Status tmpstatus(*it_status);
+         ATH_MSG_INFO("         Status Code=0x"
+	         << MSG::hex << std::setfill( '0' ) << std::setw(8) << tmpstatus.code()
+	         << " Generic Part=0x" << std::setw(4) << tmpstatus.generic()
+	         << " Specific Part=0x" << std::setw(4) << tmpstatus.specific());
+      }
+   }
+   */
+   return(StatusCode::SUCCESS);
+}
+
+// /// Query interface
+// StatusCode FaserROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+//    if (IFaserROBDataProviderSvc::interfaceID().versionMatch(riid)) {
+//       *ppvInterface = dynamic_cast<IFaserROBDataProviderSvc*>(this);
+//    } else {
+//       // Interface is not directly available: try out a base class
+//       return(::AthService::queryInterface(riid, ppvInterface));
+//    }
+//    addRef();
+//    return(StatusCode::SUCCESS);
+// }
+
+/**
+    - in offline only check that given ROB ids are in the map, issue an
+      error if not
+*/
+  
+
+
+void FaserROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return addROBData( context, robIds, callerName );
+}
+
+void FaserROBDataProviderSvc::addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string_view callerName) {
+    EventCache* cache = m_eventsCache.get( context );
+
+   // Copy missing ROB ids to vector with pthread allocator
+   ATH_MSG_DEBUG(" ---> Number of ROB Id s requested : " << robIds.size() << ", Caller Name = " << callerName);
+   // for offline running all requested ROBs should be found in cache
+   // if not issue error
+   for (std::vector<uint32_t>::const_iterator it = robIds.begin(), it_end = robIds.end(); it != it_end; it++) {
+      uint32_t id = (*it);
+
+      // mask off the module ID for L2 and EF result for Run 1 data
+      /*
+      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
+	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+	 // TB if it is inconsistent we should not continue like this?
+	 if ( !m_maskL2EFModuleID ) {
+	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
+	   m_maskL2EFModuleID=true;
+	 }
+      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
+		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
+		  ( m_maskL2EFModuleID ) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+      }
+      */
+      /*
+      ROBMAP& robmap( cache->robmap );
+      ROBMAP::iterator map_it = robmap.find(id) ;
+      if (map_it != robmap.end()) {
+         ATH_MSG_DEBUG(" ---> Found   ROB Id : 0x" << MSG::hex << (*map_it).second->source_id()
+	         << MSG::dec << " in cache");
+      } else {
+         ATH_MSG_DEBUG(" ---> ROB Id : 0x" << MSG::hex << id
+	         << MSG::dec << " not found in cache for running mode OFFLINE (method addROBData),");
+	 ATH_MSG_DEBUG("      Lvl1 id  = " << cache->currentLvl1ID);
+    }
+      */
+   }
+  return;
+}
+/** - this is the online method to add the LVL1/LVL2 result
+    - this version of FaserROBDataProviderSvc does not support it
+    - this version is for offline use only
+*/
+/*
+void FaserROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setNextEvent( context, result );
+}
+*/
+/*
+void FaserROBDataProviderSvc::setNextEvent(const EventContext& context, const std::vector<ROBF>& result) { 
+  // clear the old map
+  // TB honestly, why do any action if this is FATAL mistake
+  //  robmapClear( m_eventsCache.get(context)->robmap );
+
+   // This method should never be used by offline
+   ATH_MSG_FATAL(" +-----------------------------------------------------------------+ ");
+   ATH_MSG_FATAL(" | The method FaserROBDataProviderSvc::setNextEvent(const ROBF* result) | ");
+   ATH_MSG_FATAL(" |    is not implemented for this version of FaserROBDataProviderSvc    | ");
+   ATH_MSG_FATAL(" |      Use the version from the HLT repository if you need it.    | ");
+   ATH_MSG_FATAL(" +-----------------------------------------------------------------+ ");
+   ATH_MSG_FATAL(" ---> The " << result.size() << " ROB fragments in the call will not be used.");
+   return;
+}
+*/
+
+
+
+/** - add a new Raw event
+    - rebuild the map
+*/
+void FaserROBDataProviderSvc::setNextEvent(const EventFull* re) {
+  // obtain context and redirect to the real implementation
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setNextEvent( context, re );
+}
+
+void FaserROBDataProviderSvc::setNextEvent( const EventContext& context, const EventFull* re ) {
+  EventCache* cache = m_eventsCache.get( context );
+  
+   cache->event = re;
+   // clear the old map
+   //robmapClear( cache->robmap );
+   // set the LVL1 id
+   //cache->currentLvl1ID = re->lvl1_id();
+   // set flag for masking L2/EF module ID, this is only necessary for the separate L2 and EF systems from Run 1 
+   //m_maskL2EFModuleID = (re->nlvl2_trigger_info() != 0);
+
+   // get all the ROBFragments
+   /*
+   const size_t MAX_ROBFRAGMENTS = 2048;
+   OFFLINE_FRAGMENTS_NAMESPACE::PointerType robF[MAX_ROBFRAGMENTS];
+   OFFLINE_FRAGMENTS_NAMESPACE::PointerType rePointer;
+   re->start(rePointer);
+   size_t robcount = re->children(robF, MAX_ROBFRAGMENTS);
+   if (robcount == MAX_ROBFRAGMENTS) {
+      ATH_MSG_ERROR("ROB buffer overflow");
+   }
+   // loop over all ROBs
+   for (size_t irob = 0; irob < robcount; irob++) {
+      // add to the map
+      const ROBF* rob = new ROBF(robF[irob]);
+      uint32_t id =  rob->source_id();
+      // mask off the module ID for L2 and EF result for Run 1 data
+      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
+	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+	 if (!m_maskL2EFModuleID) {
+	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
+	   m_maskL2EFModuleID=true;
+	 }
+      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
+		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
+		  (m_maskL2EFModuleID) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+      }
+      if ((rob->rod_ndata() == 0) && (m_filterEmptyROB)) {
+         ATH_MSG_DEBUG( " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
+	         << " removed for L1 Id = " << cache->currentLvl1ID);
+          delete rob;
+      } else if (filterRobWithStatus(rob)) {
+         if (rob->nstatus() > 0) {
+            const uint32_t* it_status;
+            rob->status(it_status);
+            eformat::helper::Status tmpstatus(*it_status);
+            ATH_MSG_DEBUG(" ---> ROB Id = 0x" << MSG::hex << id << std::setfill('0')
+	            << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
+	            << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific() << MSG::dec
+	            << " removed for L1 Id = " << cache->currentLvl1ID);
+         }
+         delete rob;
+      } else {
+	
+         ROBMAP::const_iterator it = cache->robmap.find(id);
+         if (it != cache->robmap.end()) {
+            ATH_MSG_WARNING(" FaserROBDataProviderSvc:: Duplicate ROBID 0x" << MSG::hex << id
+	            << " found. " << MSG::dec << " Overwriting the previous one ");
+            delete cache->robmap[id];
+            cache->robmap[id] = rob;
+         } else {
+            cache->robmap[id] = rob;
+         }
+       
+      }
+   }
+*/
+   ATH_MSG_DEBUG(" ---> setNextEvent offline for " << name() );
+   ATH_MSG_DEBUG("      current LVL1 id   = " << cache->currentLvl1ID );
+   //ATH_MSG_DEBUG("      size of ROB cache = " << cache->robmap.size() );
+   return;
+}
+/** return ROBData for ROBID
+ */
+/*
+void FaserROBDataProviderSvc::getROBData(const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, const std::string_view callerName) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getROBData( context, ids, v, callerName );
+}
+*/
+/*
+void FaserROBDataProviderSvc::getROBData(const EventContext& context, const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, 
+				    const std::string_view callerName) {
+  EventCache* cache = m_eventsCache.get( context );
+  
+   for (std::vector<uint32_t>::const_iterator it = ids.begin(), it_end = ids.end(); it != it_end; it++) {
+      uint32_t id = (*it);
+      // mask off the module ID for L2 and EF result for Run 1 data
+      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
+	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+	 if (!m_maskL2EFModuleID) {
+	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
+	   m_maskL2EFModuleID=true;
+	 }
+      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
+		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
+		  (m_maskL2EFModuleID) ) {
+	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
+      }
+      ROBMAP::iterator map_it = cache->robmap.find(id);
+      if (map_it != cache->robmap.end()) {
+         v.push_back((*map_it).second);
+      } else {
+	ATH_MSG_DEBUG("Failed to find ROB for id 0x" << MSG::hex << id << MSG::dec << ", Caller Name = " << callerName);
+#ifndef NDEBUG
+         int nrob = 0;
+         ATH_MSG_VERBOSE(" --- Dump of ROB cache ids --- total size = " << cache->robmap.size());
+         for (ROBMAP::iterator cache_it = cache->robmap.begin(), cache_end = cache->robmap.end();
+	         cache_it != cache_end; cache_it++) {
+	    ++nrob;
+	    ATH_MSG_VERBOSE(" # = " << nrob << "  id = 0x" << MSG::hex << (*cache_it).second->source_id() << MSG::dec);
+         }
+#endif
+      }
+   }
+   return;
+}
+*/
+
+/** - clear ROB map
+ */
+/*
+void FaserROBDataProviderSvc::robmapClear( ROBMAP& toclear) {
+  for (ROBMAP::const_iterator it = toclear.begin(), itE = toclear.end(); it != itE; ++it) {
+     delete it->second;
+  }
+  toclear.clear();
+}
+*/
+
+/// Retrieve the whole event.
+const EventFull* FaserROBDataProviderSvc::getEvent() {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getEvent( context );
+}
+const EventFull* FaserROBDataProviderSvc::getEvent( const EventContext& context ) {
+  
+  return m_eventsCache.get( context )->event;
+}
+
+
+/// Set the status for the event.
+void FaserROBDataProviderSvc::setEventStatus(uint32_t status) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  setEventStatus( context, status );
+}
+
+void FaserROBDataProviderSvc::setEventStatus(const EventContext& context, uint32_t status) {
+  m_eventsCache.get(context)->eventStatus = status;
+}
+/// Retrieve the status for the event.
+uint32_t FaserROBDataProviderSvc::getEventStatus() {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getEventStatus( context );
+}
+
+uint32_t FaserROBDataProviderSvc::getEventStatus( const EventContext& context ) {
+  return m_eventsCache.get( context )->eventStatus;
+}
+
+/*
+void FaserROBDataProviderSvc::processCachedROBs(const EventContext& context, 
+					   const std::function< void(const ROBF* )>& fn ) const {
+  for ( const auto&  el : m_eventsCache.get( context )->robmap ) {
+    fn( el.second );
+  }
+}
+*/
+
+
+/** - filter ROB with Sub Detector Id and Status Code
+*/
+/*
+bool FaserROBDataProviderSvc::filterRobWithStatus(const ROBF* rob) {
+   // No filter criteria defined
+   if ((m_filterRobMap.size() == 0) && (m_filterSubDetMap.size() == 0)) {
+      return(false);
+   }
+   // There should be at least one status element if there was an error
+   // in case there are 0 status elements then there was no known error
+   // (see event format document ATL-D-ES-0019 (EDMS))
+   if (rob->nstatus() == 0) {
+      return(false);
+   }
+   // The ROB has at least one status element, access it via an iterator
+   const uint32_t* rob_it_status;
+   rob->status(rob_it_status);
+   // Build the full ROB Sourceidentifier
+   eformat::helper::SourceIdentifier tmpsrc(rob->rob_source_id());
+   // Check if there is a ROB specific filter rule defined for this ROB Id and match the status code
+   FilterRobMap::iterator map_it_rob = m_filterRobMap.find(tmpsrc.code());
+   if (map_it_rob != m_filterRobMap.end()) {
+      for (std::vector<uint32_t>::const_iterator it_status = (*map_it_rob).second.begin(),
+	      it_statusEnd = (*map_it_rob).second.end(); it_status != it_statusEnd; it_status++) {
+         if (*rob_it_status == *it_status) {
+            return(true);
+         }
+      }
+   }
+   // Check if there is a sub detector specific filter rule defined for this ROB Id and match the status code
+   FilterSubDetMap::iterator map_it_subdet = m_filterSubDetMap.find(tmpsrc.subdetector_id());
+   if (map_it_subdet != m_filterSubDetMap.end()) {
+      for (std::vector<uint32_t>::const_iterator it_status = (*map_it_subdet).second.begin(),
+	      it_statusEnd = (*map_it_subdet).second.end(); it_status != it_statusEnd; it_status++) {
+         if (*rob_it_status == *it_status) {
+            return(true);
+         }
+      }
+   }
+   return(false);
+}
+*/
+
+FaserROBDataProviderSvc::EventCache::~EventCache() {
+  delete event;
+  //FaserROBDataProviderSvc::robmapClear( robmap );
+}
+
diff --git a/Event/FaserByteStreamCnvSvcBase/src/components/FaserByteStreamCnvSvcBase_entries.cxx b/Event/FaserByteStreamCnvSvcBase/src/components/FaserByteStreamCnvSvcBase_entries.cxx
new file mode 100644
index 000000000..a31a4f6b3
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/src/components/FaserByteStreamCnvSvcBase_entries.cxx
@@ -0,0 +1,8 @@
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h"
+#include "FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h"
+
+DECLARE_COMPONENT( FaserByteStreamCnvSvcBase )
+DECLARE_COMPONENT( FaserByteStreamAddressProviderSvc )
+DECLARE_COMPONENT( FaserROBDataProviderSvc )
+
-- 
GitLab


From 55b6642eae51b1d4a84fad75374220c040b96e3a Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 16 Jun 2020 15:13:02 -0700
Subject: [PATCH 06/47] First successful creation of EventInfo

---
 .../python/ReadByteStream.py                  | 33 ++++++++++---------
 .../src/EventInfoByteStreamAuxCnv.cxx         | 30 ++++++++++-------
 .../src/FaserByteStreamInputSvc.cxx           |  3 +-
 .../src/FaserEventSelectorByteStream.cxx      | 13 +++++---
 .../FaserByteStreamCnvSvcBase/CMakeLists.txt  |  4 +--
 .../FaserROBDataProviderSvc.h                 | 17 ----------
 .../src/FaserByteStreamAddressProviderSvc.cxx |  6 ++--
 .../src/FaserByteStreamCnvSvcBase.cxx         |  4 +--
 .../src/FaserROBDataProviderSvc.cxx           |  6 +---
 9 files changed, 52 insertions(+), 64 deletions(-)

diff --git a/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py b/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
index 027eb5973..9baf1043b 100644
--- a/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
+++ b/Event/FaserByteStreamCnvSvc/python/ReadByteStream.py
@@ -10,39 +10,39 @@ from AthenaCommon.AppMgr import ServiceMgr as svcMgr
 from AthenaCommon.AppMgr import theApp
 
 # Load ByteStreamEventStorageInputSvc
-if not hasattr (svcMgr, 'ByteStreamInputSvc'):
-    svcMgr += CfgMgr.FaserByteStreamInputSvc ("ByteStreamInputSvc")
+if not hasattr (svcMgr, 'FaserByteStreamInputSvc'):
+    svcMgr += CfgMgr.FaserByteStreamInputSvc ("FaserByteStreamInputSvc")
 
 # Load ROBDataProviderSvc
-if not hasattr (svcMgr, 'ROBDataProviderSvc'):
-    svcMgr += CfgMgr.ROBDataProviderSvc ("ROBDataProviderSvc")
+if not hasattr (svcMgr, 'FaserROBDataProviderSvc'):
+    svcMgr += CfgMgr.FaserROBDataProviderSvc ("FaserROBDataProviderSvc")
 
 # Load EventSelectorByteStream
-if not hasattr (svcMgr, 'EventSelector'):
-    svcMgr += CfgMgr.FaserEventSelectorByteStream ("EventSelector")
-theApp.EvtSel = "EventSelector"
+if not hasattr (svcMgr, 'FaserEventSelector'):
+    svcMgr += CfgMgr.FaserEventSelectorByteStream ("FaserEventSelector")
+theApp.EvtSel = "FaserEventSelector"
 
 from xAODEventInfoCnv.xAODEventInfoCnvConf import xAODMaker__EventInfoSelectorTool 
 xconv = xAODMaker__EventInfoSelectorTool()
-svcMgr.EventSelector.HelperTools += [xconv]
+svcMgr.FaserEventSelector.HelperTools += [xconv]
 
 # Load ByteStreamCnvSvc
-if not hasattr (svcMgr, 'ByteStreamCnvSvc'):
-    svcMgr += CfgMgr.FaserByteStreamCnvSvc ("ByteStreamCnvSvc")
+if not hasattr (svcMgr, 'FaserByteStreamCnvSvc'):
+    svcMgr += CfgMgr.FaserByteStreamCnvSvc ("FaserByteStreamCnvSvc")
 
 # Properties
-svcMgr.EventSelector.ByteStreamInputSvc = "ByteStreamInputSvc"
+svcMgr.FaserEventSelector.ByteStreamInputSvc = "FaserByteStreamInputSvc"
 
-svcMgr.EventPersistencySvc.CnvServices += [ "ByteStreamCnvSvc" ]
+svcMgr.EventPersistencySvc.CnvServices += [ "FaserByteStreamCnvSvc" ]
 
 # Load ProxyProviderSvc
 if not hasattr (svcMgr, 'ProxyProviderSvc'):
     svcMgr += CfgMgr.ProxyProviderSvc()
 
 # Add in ByteStreamAddressProviderSvc
-#if not hasattr (svcMgr, 'ByteStreamAddressProviderSvc'):
-#    svcMgr += CfgMgr.ByteStreamAddressProviderSvc ("ByteStreamAddressProviderSvc")
-#svcMgr.ProxyProviderSvc.ProviderNames += [ "ByteStreamAddressProviderSvc" ]
+if not hasattr (svcMgr, 'FaserByteStreamAddressProviderSvc'):
+    svcMgr += CfgMgr.FaserByteStreamAddressProviderSvc ("FaserByteStreamAddressProviderSvc")
+svcMgr.ProxyProviderSvc.ProviderNames += [ "FaserByteStreamAddressProviderSvc" ]
 
 # Add in MetaDataSvc
 #if not hasattr (svcMgr, 'MetaDataSvc'):
@@ -50,7 +50,8 @@ if not hasattr (svcMgr, 'ProxyProviderSvc'):
 #svcMgr.ProxyProviderSvc.ProviderNames += [ "MetaDataSvc" ]
 
 # Add in MetaData Stores
-from StoreGate.StoreGateConf import StoreGateSvc
+# from StoreGate.StoreGateConf import StoreGateSvc
+
 #if not hasattr (svcMgr, 'InputMetaDataStore'):
 #    svcMgr += StoreGateSvc( "InputMetaDataStore" )
 #if not hasattr (svcMgr, 'MetaDataStore'):
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
index a0998bda4..341fa8d72 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamAuxCnv.cxx
@@ -38,7 +38,7 @@ EventInfoByteStreamAuxCnv::EventInfoByteStreamAuxCnv(ISvcLocator* svcloc)
   : Converter(storageType(), classID(), svcloc)
   , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "EventInfoByteStreamAuxCnv")
   , m_ByteStreamCnvSvc(nullptr)
-  , m_robDataProvider("ROBDataProviderSvc", "EventInfoByteStreamAuxCnv")
+  , m_robDataProvider("FaserROBDataProviderSvc", "EventInfoByteStreamAuxCnv")
     //  , m_mdSvc("InputMetaDataStore", "EventInfoByteStreamAuxCnv")
   , m_isSimulation(false)
   , m_isTestbeam(false)
@@ -58,26 +58,29 @@ long EventInfoByteStreamAuxCnv::storageType()
 
 StatusCode EventInfoByteStreamAuxCnv::initialize() 
 {
-  ATH_MSG_DEBUG("EventInfoByteStreamAuxCnv::Initialize");
+  ATH_MSG_DEBUG("EventInfoByteStreamAuxCnv::Initialize()");
 
   CHECK(Converter::initialize());
 
   // Check ByteStreamCnvSvc
+  ATH_MSG_DEBUG("Find FaserByteStreamCnvSvc");
   IService* svc{nullptr};
-  StatusCode sc = serviceLocator()->getService("ByteStreamCnvSvc", svc);
+  StatusCode sc = serviceLocator()->getService("FaserByteStreamCnvSvc", svc);
   if (!sc.isSuccess()) {
-    ATH_MSG_ERROR("Cannot get ByteStreamCnvSvc ");
+    ATH_MSG_ERROR("Cannot get FaserByteStreamCnvSvc ");
     return sc;
   } else {
-    ATH_MSG_DEBUG("Located ByteStreamCnvSvc");
+    ATH_MSG_DEBUG("Located FaserByteStreamCnvSvc");
   }
 
+  // Don't need this as we no longer have an interface class, but OK
   m_ByteStreamCnvSvc = dynamic_cast<FaserByteStreamCnvSvc*>(svc);
   if (!m_ByteStreamCnvSvc) {
-    ATH_MSG_ERROR("Cannot cast to ByteStreamCnvSvc");
+    ATH_MSG_ERROR("Cannot cast to FaserByteStreamCnvSvc");
     return StatusCode::FAILURE;
   }
 
+  ATH_MSG_DEBUG("Find ROBDataProvider");
   CHECK(m_robDataProvider.retrieve());
   //CHECK(m_mdSvc.retrieve());
 
@@ -156,8 +159,9 @@ StatusCode EventInfoByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataObjec
   uint64_t eventNumber = re->event_id();
   
   // Time Stamp
-  uint32_t bc_time_sec = re->timestamp()/1E6;  // timestamp in usec
-  uint32_t bc_time_ns  = 1E9 * (re->timestamp() - 1E6 * bc_time_sec);
+  uint32_t bc_time_sec = re->timestamp()/1E6;  // timestamp is in usec
+  // Subtract off integer second and provide remainder in ns
+  uint32_t bc_time_ns  = 1E3 * (re->timestamp() - 1E6 * bc_time_sec);
   // bc_time_ns should be lt 1e9.
   if (bc_time_ns > 1000000000) {
       // For later runs, the nanosecond clock sometimes is not reset, making it overrun 1e9. Round it off to 1e9
@@ -171,7 +175,11 @@ StatusCode EventInfoByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataObjec
   // bunch crossing identifier
   uint16_t bcID = re->bc_id();
 
-  unsigned int detMask0 = 0xFFFFFFFF, detMask1 = 0xFFFFFFFF, detMask2 = 0xFFFFFFFF, detMask3 = 0xFFFFFFFF;
+  // Unused
+  unsigned int detMask0 = 0xFFFFFFFF, 
+    detMask1 = 0xFFFFFFFF, 
+    detMask2 = 0xFFFFFFFF, 
+    detMask3 = 0xFFFFFFFF;
 
   xAOD::EventInfo evtInfo;
   xAOD::EventAuxInfo* pEvtInfoAux = new xAOD::EventAuxInfo();
@@ -252,8 +260,8 @@ StatusCode EventInfoByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataObjec
   pObj = StoreGateSvc::asStorable(pEvtInfoAux);
 
   ATH_MSG_DEBUG(" New xAOD::EventAuxInfo made, run/event= " << runNumber 
-		<< " " << eventNumber
-		<< " Time stamp  = " << ascTime(bc_time_sec) 
+		<< "/" << eventNumber
+		<< "  Time stamp = " << ascTime(bc_time_sec) 
 		);
 
   return StatusCode::SUCCESS;
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
index 8cf738593..93fad1c3f 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
@@ -6,7 +6,7 @@
 
 #include "DumpFrags.h"
 
-#include "ByteStreamData/ByteStreamMetadataContainer.h"
+//#include "ByteStreamData/ByteStreamMetadataContainer.h"
 #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 #include "FaserEventStorage/pickFaserDataReader.h"
 
@@ -70,7 +70,6 @@ FaserByteStreamInputSvc::~FaserByteStreamInputSvc() {
 StatusCode FaserByteStreamInputSvc::initialize() {
    ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
 
-   ATH_CHECK(FaserByteStreamInputSvc::initialize());
    //ATH_CHECK(m_inputMetadata.retrieve());
    ATH_CHECK(m_storeGate.retrieve());
    ATH_CHECK(m_robProvider.retrieve());
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
index c4f3e1464..cf1adfe74 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserEventSelectorByteStream.cxx
@@ -112,7 +112,9 @@ StatusCode FaserEventSelectorByteStream::initialize() {
     } else {
       // Check if FullFileName is set in the InputSvc
       typedef std::vector<const Property*> Properties_t;
-      const Properties_t* esProps = joSvc->getProperties("ByteStreamInputSvc");
+      //const Properties_t* esProps = joSvc->getProperties("FaserByteStreamInputSvc");
+      const Properties_t* esProps = joSvc->getProperties(m_eventSourceName);
+
       std::vector<const Property*>::const_iterator ii = esProps->begin();
       if (esProps != 0) {
 	while (ii != esProps->end()) {
@@ -149,12 +151,12 @@ StatusCode FaserEventSelectorByteStream::initialize() {
   // Check ByteStreamCnvSvc
   IService* svc;
   if (!serviceLocator()->getService(m_eventSourceName, svc).isSuccess()) {
-    ATH_MSG_FATAL("Cannot get ByteStreamInputSvc");
+    ATH_MSG_FATAL("Cannot get FaserByteStreamInputSvc");
     return(StatusCode::FAILURE);
   }
   m_eventSource = dynamic_cast<FaserByteStreamInputSvc*>(svc);
   if (m_eventSource == 0) {
-    ATH_MSG_FATAL("Cannot cast ByteStreamInputSvc");
+    ATH_MSG_FATAL("Cannot cast FaserByteStreamInputSvc");
     return(StatusCode::FAILURE);
   }
   m_eventSource->addRef();
@@ -216,7 +218,8 @@ StatusCode FaserEventSelectorByteStream::initialize() {
     return(StatusCode::FAILURE);
   }
   typedef std::vector<const Property*> Properties_t;
-  const Properties_t* esProps = joSvc->getProperties("ByteStreamInputSvc");
+  //const Properties_t* esProps = joSvc->getProperties("FaserByteStreamInputSvc");
+  const Properties_t* esProps = joSvc->getProperties(m_eventSourceName);
   if (esProps != 0) {
     std::vector<const Property*>::const_iterator ii = esProps->begin();
     while (ii != esProps->end()) {
@@ -241,7 +244,7 @@ StatusCode FaserEventSelectorByteStream::initialize() {
       ++ii;
     }
   } else {
-    ATH_MSG_WARNING("Did not find ByteStreamInputSvc jobOptions properties");
+    ATH_MSG_WARNING("Did not find FaserByteStreamInputSvc jobOptions properties");
   }
    
   // Must happen before trying to open a file
diff --git a/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt b/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
index d3dcab1b3..27611f942 100644
--- a/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
+++ b/Event/FaserByteStreamCnvSvcBase/CMakeLists.txt
@@ -10,9 +10,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Control/AthenaBaseComps
                           Control/AthenaKernel
                           Control/StoreGate
-                          #Event/ByteStreamData
                           GaudiKernel
-			  ByteStreamCnvSvcBase
                           PRIVATE
                           Control/SGTools
 			  AtlasTest/TestTools 
@@ -27,7 +25,7 @@ atlas_add_library( FaserByteStreamCnvSvcBaseLib
                    src/*.cxx
                    PUBLIC_HEADERS FaserByteStreamCnvSvcBase
                    # INCLUDE_DIRS  ${TDAQ-COMMON_INCLUDE_DIRS}
-                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GaudiKernel StoreGateLib SGtests ByteStreamCnvSvcBaseLib
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GaudiKernel StoreGateLib SGtests
                    PRIVATE_LINK_LIBRARIES SGTools )
 
 atlas_add_component( FaserByteStreamCnvSvcBase
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
index 51c1e3823..7e880d92b 100644
--- a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
@@ -111,23 +111,6 @@ protected:
    /// Remaining attributes are for configuration
    /// vector of Source ids and status words to be ignored for the ROB map
    typedef SimpleProperty< std::vector< std::pair<int, int> > > ArrayPairIntProperty;
-   ArrayPairIntProperty  m_filterRobWithStatus; // filter with full ROB SourceID
-   ArrayPairIntProperty  m_filterSubDetWithStatus;  // filter with Sub Det ID
-
-   /// map of full ROB Source ids and status words to be ignored for the ROB map
-   //typedef std::map<uint32_t, std::vector<uint32_t> > FilterRobMap;
-   //FilterRobMap          m_filterRobMap;
-   /// map of Sub Det Source ids and status words to be ignored for the ROB map
-   //typedef std::map<eformat::SubDetector, std::vector<uint32_t> > FilterSubDetMap;
-   //FilterSubDetMap       m_filterSubDetMap;
-   /// method to filter ROBs with given Status code
-   //bool filterRobWithStatus(const ROBF* rob);
-
-   /// Filter out empty ROB fragments which are send by the ROS
-   BooleanProperty m_filterEmptyROB;
-   bool m_maskL2EFModuleID = false;    
-
-private: // data
 
 private: //
    //static void robmapClear(ROBMAP& toclear);
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
index 75e999d2a..9bbea53e0 100644
--- a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamAddressProviderSvc.cxx
@@ -4,8 +4,8 @@
 
 // Include files
 #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddressProviderSvc.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
-//#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
+#include "FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h"
 
 #include "StoreGate/StoreGate.h"
 #include "SGTools/TransientAddress.h"
@@ -94,7 +94,7 @@ StatusCode FaserByteStreamAddressProviderSvc::updateAddress(StoreID::type id,
       return(StatusCode::FAILURE);
    }
    ATH_MSG_DEBUG("Creating address for " << clid << " " << nm);
-   ByteStreamAddress* add = new ByteStreamAddress(clid, nm, "");
+   FaserByteStreamAddress* add = new FaserByteStreamAddress(clid, nm, "");
    add->setEventContext(ctx);
    tad->setAddress(add);
    return(StatusCode::SUCCESS);
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
index 53b7470ed..2c7bff28f 100644
--- a/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserByteStreamCnvSvcBase.cxx
@@ -3,7 +3,7 @@
 */
 
 #include "FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase.h"
-#include "ByteStreamCnvSvcBase/ByteStreamAddress.h"
+#include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 
 #include "GaudiKernel/IOpaqueAddress.h"
 #include "GaudiKernel/GenericAddress.h"
@@ -16,7 +16,7 @@
 
 //______________________________________________________________________________
 FaserByteStreamCnvSvcBase::FaserByteStreamCnvSvcBase(const std::string& name, ISvcLocator* pSvcLocator) :
-   ::AthCnvSvc(name, pSvcLocator, ByteStreamAddress::storageType())
+   ::AthCnvSvc(name, pSvcLocator, FaserByteStreamAddress::storageType())
    // , m_rawEventWrite(0) 
 {
    declareProperty("InitCnvs", m_initCnvs); 
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
index 15edee977..35dc3e015 100644
--- a/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
@@ -82,7 +82,6 @@
 // Include files.
 #include "FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h"
 #include "EventFormats/DAQFormats.hpp"
-//#include "eformat/Status.h"
 
 using DAQFormats::EventFull;
 
@@ -90,9 +89,6 @@ using DAQFormats::EventFull;
 FaserROBDataProviderSvc::FaserROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc) 
   : base_class(name, svcloc) {
 
-  declareProperty("filterRobWithStatus", m_filterRobWithStatus);
-  declareProperty("filterSubDetWithStatus", m_filterSubDetWithStatus);
-  declareProperty("filterEmptyROB", m_filterEmptyROB = false);
 }
 
 // Destructor.
@@ -188,7 +184,7 @@ void FaserROBDataProviderSvc::addROBData(const EventContext& context, const std:
    // for offline running all requested ROBs should be found in cache
    // if not issue error
    for (std::vector<uint32_t>::const_iterator it = robIds.begin(), it_end = robIds.end(); it != it_end; it++) {
-      uint32_t id = (*it);
+     // uint32_t id = (*it);
 
       // mask off the module ID for L2 and EF result for Run 1 data
       /*
-- 
GitLab


From 5b1d768ff8f88d7b3b85b5236d70697e11369c35 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 16 Jun 2020 16:26:10 -0700
Subject: [PATCH 07/47] Fixes for multi-file reading

---
 .../src/EventInfoByteStreamxAODCnv.cxx        |  2 +-
 .../src/FaserByteStreamInputSvc.cxx           |  4 +-
 .../FaserEventStorage/src/ESLOriginalFile.cxx | 62 ++++++++++---------
 Event/FaserEventStorage/src/ESLOriginalFile.h |  1 -
 4 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
index f9dcfe9df..4d241fb9d 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
@@ -69,7 +69,7 @@ StatusCode EventInfoByteStreamxAODCnv::createObj(IOpaqueAddress* pAddr, DataObje
   pEvtInfo->setStore(link);
   pObj = StoreGateSvc::asStorable(pEvtInfo);
 
-  ATH_MSG_DEBUG(" New EventInfo made, run/event= " << pEvtInfo->runNumber() << " " << pEvtInfo->eventNumber());
+  ATH_MSG_DEBUG(" New xAOD::EventInfo made, run/event= " << pEvtInfo->runNumber() << "/" << pEvtInfo->eventNumber());
 
   return StatusCode::SUCCESS;
 }
diff --git a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
index 93fad1c3f..e2849ebcd 100644
--- a/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/FaserByteStreamInputSvc.cxx
@@ -70,7 +70,6 @@ FaserByteStreamInputSvc::~FaserByteStreamInputSvc() {
 StatusCode FaserByteStreamInputSvc::initialize() {
    ATH_MSG_INFO("Initializing " << name() << " - package version " << PACKAGE_VERSION);
 
-   //ATH_CHECK(m_inputMetadata.retrieve());
    ATH_CHECK(m_storeGate.retrieve());
    ATH_CHECK(m_robProvider.retrieve());
 
@@ -87,9 +86,8 @@ StatusCode FaserByteStreamInputSvc::finalize() {
 
   ATH_CHECK(m_storeGate.release());
   ATH_CHECK(m_robProvider.release()); 
-  //ATH_CHECK(m_inputMetadata.release());
 
-  return(FaserByteStreamInputSvc::finalize());
+  return(StatusCode::SUCCESS);
 }
 //------------------------------------------------------------------------------
 long FaserByteStreamInputSvc::positionInBlock()
diff --git a/Event/FaserEventStorage/src/ESLOriginalFile.cxx b/Event/FaserEventStorage/src/ESLOriginalFile.cxx
index 5a5ad7681..621ed2560 100644
--- a/Event/FaserEventStorage/src/ESLOriginalFile.cxx
+++ b/Event/FaserEventStorage/src/ESLOriginalFile.cxx
@@ -22,7 +22,6 @@ FESLOriginalFile::FESLOriginalFile( fRead * m_fR) : EventStackLayer(m_fR)
   ERS_DEBUG(3, identify() << " File size found: " << m_cfilesize);
 
   m_endOfFile = false;
-  m_fer_read = false;
   m_advance_fer_updated = false;
 
   m_compression = FaserEventStorage::NONE;
@@ -66,6 +65,25 @@ DRError FESLOriginalFile::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
       throw ci;
   }
 
+  // Check if we will read beyond the end of the file
+  uint64_t cpos = m_fR->getPosition();
+  uint64_t remaining = m_cfilesize - cpos;
+  ERS_DEBUG(3, "current position before header " << cpos << " with " << remaining << " remaining") ;
+
+  if (remaining < sizeofHeader) {
+    ERS_DEBUG(1, "Requested" << sizeofHeader
+	      << " bytes for header but only " << remaining << " remain in file!");
+
+    FaserEventStorage::ES_OutOfFileBoundary ci(ERS_HERE, "Trying to read more data for header than remains in the file. This likely means your event is truncated. If you still want to read the data, catch this exception and proceed. The data block contains the rest of the data. ");
+    throw ci;
+
+    // In case this gets caught, but won't work well
+    m_fR->readData(buffer, remaining);
+    theEvent->loadHeader((uint8_t*)buffer, remaining);
+    delete[] buffer;
+    return DRNOOK;
+  }
+
   m_fR->readData(buffer, sizeofHeader);
   theEvent->loadHeader((uint8_t*)buffer, sizeofHeader);
 
@@ -84,13 +102,13 @@ DRError FESLOriginalFile::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
   }
 
   // Check if we will read beyond the end of the file
-  uint64_t cpos = m_fR->getPosition();
-  ERS_DEBUG(3, "currentposition" << cpos) ;
-  uint64_t remaining = m_cfilesize - cpos;
+  cpos = m_fR->getPosition();
+  ERS_DEBUG(3, "current position before payload " << cpos << " with " << remaining << " remaining");
+  remaining = m_cfilesize - cpos;
 
   if (remaining < sizeofPayload) {
-    ERS_DEBUG(1, "Requested " << sizeofHeader 
-	      << " bytes but only remains " << remaining << " in file ");
+    ERS_DEBUG(1, "Requested " << sizeofPayload 
+	      << " bytes for payload but only " << remaining << " remain in file ");
 
     FaserEventStorage::ES_OutOfFileBoundary ci(ERS_HERE, "Trying to read more data than remains in the file. This could mean that either your event is truncated, or that the event size record of this event is corrupted. If you still want to read the data, catch this exception and proceed. The data block contains the rest of the data. ");
     throw ci;
@@ -98,6 +116,7 @@ DRError FESLOriginalFile::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
     // In case this gets caught, although thee loadPayload will throw its own error
     m_fR->readData(buffer, remaining);
     theEvent->loadPayload((uint8_t*)buffer, remaining);
+    delete[] buffer;
 
     return DRNOOK;
 
@@ -112,35 +131,17 @@ DRError FESLOriginalFile::getData(DAQFormats::EventFull*& theEvent, int64_t pos)
   
   ERS_DEBUG(3,"Finished reading the event.");
 
-  //CHECK FOR END OF FILE REACHED
+  // CHECK FOR END OF FILE REACHED
+  // This is not an error
   if( /*m_fR->isEoF()*/  m_cfilesize<=m_fR->getPosition()) {
      //isEoF only tells you an end of file if you already hit the eof. it doesn't tell you if ou are exactly at the limit. therefore we check like that
-    ReadingIssue ci(ERS_HERE,"no event record found where expected. A problem with file format. The file may not have been properly closed.");
-    ers::warning(ci); 
-    m_error = true;
-    m_finished = true;
-
-    
-    FaserEventStorage::ES_NoEndOfFileRecord rci(ERS_HERE, "End of File reached directly after Event. No end of File record found where expected. The file may not have been properly closed. To proceed anyway, catch this exception. However, the requested Data has been read correctly.");
-    throw rci;
-
-    
-    return DRNOOK;
-  }
-
-  // Need some check for end of file??  
-
-  /*
-  // check for end of file record
-  if(unfile_record(&m_latest_fer,&file_end_pattern) != 0) {
-    ERS_DEBUG(3,"Found end of file record after an event.");
+    ReadingIssue ci(ERS_HERE, "End of file reached after event.");
+    ers::warning(ci);
     m_endOfFile = true;
-    m_fer_read = true;
     m_finished = true;
     
-    // check end of run
   }
-  */
+
   return DROK;
 }
 
@@ -409,7 +410,7 @@ unsigned int FESLOriginalFile::eventsInFile()
   }
 
   //return m_latest_fer.events_in_file;
-  return 2; // Avoid no events in file error
+  return 1; // Avoid no events in file error
 }
 
  
@@ -502,6 +503,7 @@ file_end_record FESLOriginalFile::currentFileFER() {
   ERS_DEBUG(3,"FESLOriginalFile::currentFileFER() called.");
 
   file_end_record cfFER=file_end_pattern;
+  m_advance_fer_updated = true;
 
   /*
   int64_t pos = m_fR->getPosition();
diff --git a/Event/FaserEventStorage/src/ESLOriginalFile.h b/Event/FaserEventStorage/src/ESLOriginalFile.h
index 2ce8e3527..c8570f8f2 100644
--- a/Event/FaserEventStorage/src/ESLOriginalFile.h
+++ b/Event/FaserEventStorage/src/ESLOriginalFile.h
@@ -83,7 +83,6 @@ class FESLOriginalFile : public EventStackLayer
   file_name_strings m_latest_fns;
   
   bool m_endOfFile;
-  bool m_fer_read; 
   
   int64_t m_cfilesize;
   
-- 
GitLab


From 3c905514de673463168a6760f1131a92bcbf047e Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 17 Jun 2020 10:49:05 -0700
Subject: [PATCH 08/47] Functional example writing xAOD from BS

---
 Event/FaserByteStreamCnvSvc/README.md         |  12 +
 .../share/jobOptions_faserBSToRDO.py          |  55 +++
 .../FaserROBDataProviderSvc.h                 |  30 +-
 .../IFaserROBDataProviderSvc.h                |   8 +-
 .../share/BSAddProvSvc_jobOptions.py          |  12 +
 .../src/FaserROBDataProviderSvc.cxx           | 326 +-----------------
 6 files changed, 91 insertions(+), 352 deletions(-)
 create mode 100644 Event/FaserByteStreamCnvSvc/README.md
 create mode 100644 Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
 create mode 100644 Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py

diff --git a/Event/FaserByteStreamCnvSvc/README.md b/Event/FaserByteStreamCnvSvc/README.md
new file mode 100644
index 000000000..27fa77df2
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/README.md
@@ -0,0 +1,12 @@
+This package provides the infrastructure to read in FASER raw data files and convert the raw information to transient data classes.  Related packages include:
+
+Event/FaserByteStreamCnvSvcBase - home of the ROBDataProvider
+Event/FaserEventStorage - low-level file handling routines
+faser-common/EventFormats - bytestream formaat definition used online
+
+A test job to read in a raw data file and write Raw Data Objects to xAOD can be found in:
+
+Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
+
+Copy this file locally, update to point to a FASER raw data file, and run with:
+athena.py jobOptions_faserBSToRDO.py
diff --git a/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py b/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
new file mode 100644
index 000000000..490d31af1
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
@@ -0,0 +1,55 @@
+#
+# Read in bytestream and write Raw Data Objects to xAOD
+#
+# Useful to set this to see ERS messages (low-level file reading):
+# export TDAQ_ERS_DEBUG_LEVEL=1
+#
+# Set debug level up to 5 for even more output
+#
+
+#
+# Configure ByteStream Input 
+from FaserByteStreamCnvSvc import ReadByteStream
+
+# Provide converters
+include( "FaserByteStreamCnvSvcBase/BSAddProvSvc_jobOptions.py" )
+
+# Read single file
+# svcMgr.FaserEventSelector.Input = [ "data/Faser-Physics-000000-00000.raw" ]
+
+# Read multiple files
+svcMgr.FaserEventSelector.Input = [ "data/Faser-Physics-000000-00000.raw",
+                                    "data/Faser-Physics-000000-00001.raw",
+                                    "data/Faser-Physics-000000-00002.raw"]
+
+# Uncomment to dump out each raw event as read
+# svcMgr.FaserByteStreamInputSvc.DumpFlag = True
+
+from AthenaCommon.AppMgr import theApp
+theApp.EvtMax = -1
+
+from AthenaCommon.AlgSequence import AthSequencer
+topSequence = AthSequencer("AthAlgSeq")
+
+# Produces lots of output...
+# MessageSvc.OutputLevel = DEBUG
+
+svcMgr.FaserEventSelector.OutputLevel = DEBUG
+svcMgr.FaserByteStreamInputSvc.OutputLevel = DEBUG
+svcMgr.FaserByteStreamCnvSvc.OutputLevel = DEBUG
+svcMgr.FaserByteStreamAddressProviderSvc.OutputLevel = DEBUG
+
+# For debugging CLID errors
+svcMgr.ClassIDSvc.OutputLevel = DEBUG
+
+# Try writing out xAOD
+from OutputStreamAthenaPool.MultipleStreamManager import MSMgr
+xaodStream = MSMgr.NewPoolRootStream( "StreamAOD", "xAOD_test.pool.root" )
+xaodStream.AddItem( "xAOD::EventInfo#*" )
+xaodStream.AddItem( "xAOD::EventAuxInfo#*" )
+xaodStream.Print()
+
+#ServiceMgr.StoreGateSvc.Dump=True
+from AthenaServices.AthenaServicesConf import AthenaEventLoopMgr
+ServiceMgr += AthenaEventLoopMgr(EventPrintoutInterval = 100)
+ServiceMgr.MessageSvc.defaultLimit = 1000
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
index 7e880d92b..2bf10dc23 100644
--- a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/FaserROBDataProviderSvc.h
@@ -53,18 +53,9 @@ public:
    /// Gaudi queryInterface method.
    //   virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
 
-   /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
-   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") override;
-
-   /// Add a given LVL1/LVL2 ROBFragment to cache
-   //virtual void setNextEvent(const std::vector<ROBF>& result) override;
-
    /// Add all ROBFragments of a RawEvent to cache
    virtual void setNextEvent(const DAQFormats::EventFull* re) override;
 
-   /// Retrieve ROBFragments for given ROB ids from cache
-   //virtual void getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, const std::string_view callerName="UNKNOWN") override;
-
    /// Retrieve the whole event.
    virtual const DAQFormats::EventFull* getEvent() override;
 
@@ -76,44 +67,25 @@ public:
 
 
    /// MT variants 
-   virtual void addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") override;
-   //virtual void setNextEvent(const EventContext& context, const std::vector<OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment>& result) override;
+
    virtual void setNextEvent(const EventContext& context, const DAQFormats::EventFull* re) override;
-   //virtual void getROBData(const EventContext& context, const std::vector<uint32_t>& robIds, VROBFRAG& robFragments, 
-   //			   const std::string_view callerName="UNKNOWN") override;
    virtual const DAQFormats::EventFull* getEvent(const EventContext& context) override;
    virtual void setEventStatus(const EventContext& context, uint32_t status) override;
    virtual uint32_t getEventStatus(const EventContext& context) override;
 
-//virtual void processCachedROBs(const EventContext& context, 
-//				  const std::function< void(const ROBF* )>& fn ) const override;
-
    virtual bool isEventComplete(const EventContext& /*context*/) const override { return true; }
    virtual int collectCompleteEventData(const EventContext& /*context*/, const std::string_view /*callerName*/ ) override {  return 0; }
 
 protected:
-   /// vector of ROBFragment class
-   //typedef std::vector<ROBF*> VROBF;
-
-   /// map for all the ROB fragments
-   //typedef std::map<uint32_t, const ROBF*, std::less<uint32_t> > ROBMAP;
 
   struct EventCache {
     ~EventCache();
     const DAQFormats::EventFull* event = 0;
     uint32_t eventStatus = 0;    
     uint32_t currentLvl1ID = 0;    
-    //ROBMAP robmap;
- 
   };
   SG::SlotSpecificObj<EventCache> m_eventsCache;
 
-   /// Remaining attributes are for configuration
-   /// vector of Source ids and status words to be ignored for the ROB map
-   typedef SimpleProperty< std::vector< std::pair<int, int> > > ArrayPairIntProperty;
-
-private: //
-   //static void robmapClear(ROBMAP& toclear);
 };
 
 #endif
diff --git a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
index 213c6b93d..fa113740f 100644
--- a/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
+++ b/Event/FaserByteStreamCnvSvcBase/FaserByteStreamCnvSvcBase/IFaserROBDataProviderSvc.h
@@ -36,7 +36,7 @@ public:
   DeclareInterfaceID(IFaserROBDataProviderSvc, 1, 1);
 
    /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
-   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") = 0 ;
+   // virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName="UNKNOWN") = 0 ;
 
    /// Add a given LVL1/LVL2 ROBFragment to cache
    //virtual void setNextEvent(const std::vector<ROBF>& result) = 0 ;
@@ -63,9 +63,9 @@ public:
 
 
    // variants for MT, it has an implementation for now in order not to require change in all implementations yet, they will all become pure virtual methods
-   virtual void addROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, const std::string_view callerName="UNKNOWN") { 
-     throw std::runtime_error( std::string(callerName)+ std::string(" is using unimplemented ") + __FUNCTION__ ) ; 
-   }
+   //virtual void addROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, const std::string_view callerName="UNKNOWN") { 
+   //  throw std::runtime_error( std::string(callerName)+ std::string(" is using unimplemented ") + __FUNCTION__ ) ; 
+   // }
    //virtual void setNextEvent(const EventContext& /*context*/, const std::vector<ROBF>& /*result*/) {
    //  throw std::runtime_error( std::string("Unimplemented ") + __FUNCTION__ ); 
    //}
diff --git a/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
new file mode 100644
index 000000000..724671414
--- /dev/null
+++ b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
@@ -0,0 +1,12 @@
+svcMgr = theApp.serviceMgr()
+if not hasattr( svcMgr, "FaserByteStreamAddressProviderSvc" ):
+    from FaserByteStreamCnvSvcBase.FaserByteStreamCnvSvcBaseConf import FaserByteStreamAddressProviderSvc
+    svcMgr += FaserByteStreamAddressProviderSvc()
+
+#
+# Add converter types here as they become available
+# svcMgr.ByteStreamAddressProviderSvc.TypeNames += [
+#        "PixelRDO_Container/PixelRDOs",
+# ]
+
+
diff --git a/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
index 35dc3e015..a897e5168 100644
--- a/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
+++ b/Event/FaserByteStreamCnvSvcBase/src/FaserROBDataProviderSvc.cxx
@@ -105,150 +105,11 @@ StatusCode FaserROBDataProviderSvc::initialize() {
    }
    m_eventsCache = SG::SlotSpecificObj<EventCache>( SG::getNSlots() );
 
-   /*   
-   for (unsigned int i = 0; i < m_filterRobWithStatus.value().size(); i++) {
-      eformat::helper::SourceIdentifier tmpsrc(m_filterRobWithStatus.value()[i].first);
-      if (tmpsrc.human_detector() != "UNKNOWN") {
-         m_filterRobMap[tmpsrc.code()].push_back(m_filterRobWithStatus.value()[i].second);
-      }
-   }
-   for (unsigned int i = 0; i < m_filterSubDetWithStatus.value().size(); i++) {
-      eformat::helper::SourceIdentifier tmpsrc((eformat::SubDetector)m_filterSubDetWithStatus.value()[i].first, 0);
-      if (tmpsrc.human_detector() != "UNKNOWN") {
-         m_filterSubDetMap[tmpsrc.subdetector_id()].push_back(m_filterSubDetWithStatus.value()[i].second);
-      }
-   }
-   ATH_MSG_INFO(" ---> Filter out empty ROB fragments                               = " << m_filterEmptyROB);
-   ATH_MSG_INFO(" ---> Filter out specific ROBs by Status Code: # ROBs = " << m_filterRobMap.size());
-   for (FilterRobMap::const_iterator it = m_filterRobMap.begin(), itEnd = m_filterRobMap.end();
-		   it != itEnd; it++) {
-      eformat::helper::SourceIdentifier tmpsrc(it->first);
-      ATH_MSG_INFO("      RobId=0x" << MSG::hex << it->first << " -> in Sub Det = " << tmpsrc.human_detector());
-      for (std::vector<uint32_t>::const_iterator it_status = (*it).second.begin(), it_statusEnd = (*it).second.end();
-		      it_status != it_statusEnd; it_status++) {
-         eformat::helper::Status tmpstatus(*it_status);
-         ATH_MSG_INFO("         Status Code=0x"
-	         << MSG::hex << std::setfill( '0' ) << std::setw(8) << tmpstatus.code()
-	         << " Generic Part=0x" << std::setw(4) << tmpstatus.generic()
-	         << " Specific Part=0x" << std::setw(4) << tmpstatus.specific());
-      }
-   }
-
-   ATH_MSG_INFO(" ---> Filter out Sub Detector ROBs by Status Code: # Sub Detectors = " << m_filterSubDetMap.size());
-   for (FilterSubDetMap::const_iterator it = m_filterSubDetMap.begin(), itEnd = m_filterSubDetMap.end();
-		   it != itEnd; it++) {
-      eformat::helper::SourceIdentifier tmpsrc(it->first, 0);
-      ATH_MSG_INFO("      SubDetId=0x" << MSG::hex << it->first << " -> " << tmpsrc.human_detector());
-      for (std::vector<uint32_t>::const_iterator it_status = (*it).second.begin(), it_statusEnd = (*it).second.end();
-		      it_status != it_statusEnd; it_status++) {
-         eformat::helper::Status tmpstatus(*it_status);
-         ATH_MSG_INFO("         Status Code=0x"
-	         << MSG::hex << std::setfill( '0' ) << std::setw(8) << tmpstatus.code()
-	         << " Generic Part=0x" << std::setw(4) << tmpstatus.generic()
-	         << " Specific Part=0x" << std::setw(4) << tmpstatus.specific());
-      }
-   }
-   */
    return(StatusCode::SUCCESS);
 }
 
-// /// Query interface
-// StatusCode FaserROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
-//    if (IFaserROBDataProviderSvc::interfaceID().versionMatch(riid)) {
-//       *ppvInterface = dynamic_cast<IFaserROBDataProviderSvc*>(this);
-//    } else {
-//       // Interface is not directly available: try out a base class
-//       return(::AthService::queryInterface(riid, ppvInterface));
-//    }
-//    addRef();
-//    return(StatusCode::SUCCESS);
-// }
-
-/**
-    - in offline only check that given ROB ids are in the map, issue an
-      error if not
-*/
-  
-
-
-void FaserROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const std::string_view callerName) {
-  const EventContext context{ Gaudi::Hive::currentContext() };
-  return addROBData( context, robIds, callerName );
-}
-
-void FaserROBDataProviderSvc::addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string_view callerName) {
-    EventCache* cache = m_eventsCache.get( context );
-
-   // Copy missing ROB ids to vector with pthread allocator
-   ATH_MSG_DEBUG(" ---> Number of ROB Id s requested : " << robIds.size() << ", Caller Name = " << callerName);
-   // for offline running all requested ROBs should be found in cache
-   // if not issue error
-   for (std::vector<uint32_t>::const_iterator it = robIds.begin(), it_end = robIds.end(); it != it_end; it++) {
-     // uint32_t id = (*it);
-
-      // mask off the module ID for L2 and EF result for Run 1 data
-      /*
-      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
-	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-	 // TB if it is inconsistent we should not continue like this?
-	 if ( !m_maskL2EFModuleID ) {
-	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
-	   m_maskL2EFModuleID=true;
-	 }
-      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
-		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
-		  ( m_maskL2EFModuleID ) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-      }
-      */
-      /*
-      ROBMAP& robmap( cache->robmap );
-      ROBMAP::iterator map_it = robmap.find(id) ;
-      if (map_it != robmap.end()) {
-         ATH_MSG_DEBUG(" ---> Found   ROB Id : 0x" << MSG::hex << (*map_it).second->source_id()
-	         << MSG::dec << " in cache");
-      } else {
-         ATH_MSG_DEBUG(" ---> ROB Id : 0x" << MSG::hex << id
-	         << MSG::dec << " not found in cache for running mode OFFLINE (method addROBData),");
-	 ATH_MSG_DEBUG("      Lvl1 id  = " << cache->currentLvl1ID);
-    }
-      */
-   }
-  return;
-}
-/** - this is the online method to add the LVL1/LVL2 result
-    - this version of FaserROBDataProviderSvc does not support it
-    - this version is for offline use only
-*/
-/*
-void FaserROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) {
-  const EventContext context{ Gaudi::Hive::currentContext() };
-  return setNextEvent( context, result );
-}
-*/
-/*
-void FaserROBDataProviderSvc::setNextEvent(const EventContext& context, const std::vector<ROBF>& result) { 
-  // clear the old map
-  // TB honestly, why do any action if this is FATAL mistake
-  //  robmapClear( m_eventsCache.get(context)->robmap );
-
-   // This method should never be used by offline
-   ATH_MSG_FATAL(" +-----------------------------------------------------------------+ ");
-   ATH_MSG_FATAL(" | The method FaserROBDataProviderSvc::setNextEvent(const ROBF* result) | ");
-   ATH_MSG_FATAL(" |    is not implemented for this version of FaserROBDataProviderSvc    | ");
-   ATH_MSG_FATAL(" |      Use the version from the HLT repository if you need it.    | ");
-   ATH_MSG_FATAL(" +-----------------------------------------------------------------+ ");
-   ATH_MSG_FATAL(" ---> The " << result.size() << " ROB fragments in the call will not be used.");
-   return;
-}
-*/
-
 
-
-/** - add a new Raw event
-    - rebuild the map
-*/
+// - add a new Raw event
 void FaserROBDataProviderSvc::setNextEvent(const EventFull* re) {
   // obtain context and redirect to the real implementation
   const EventContext context{ Gaudi::Hive::currentContext() };
@@ -256,145 +117,24 @@ void FaserROBDataProviderSvc::setNextEvent(const EventFull* re) {
 }
 
 void FaserROBDataProviderSvc::setNextEvent( const EventContext& context, const EventFull* re ) {
-  EventCache* cache = m_eventsCache.get( context );
-  
-   cache->event = re;
-   // clear the old map
-   //robmapClear( cache->robmap );
-   // set the LVL1 id
-   //cache->currentLvl1ID = re->lvl1_id();
-   // set flag for masking L2/EF module ID, this is only necessary for the separate L2 and EF systems from Run 1 
-   //m_maskL2EFModuleID = (re->nlvl2_trigger_info() != 0);
 
-   // get all the ROBFragments
-   /*
-   const size_t MAX_ROBFRAGMENTS = 2048;
-   OFFLINE_FRAGMENTS_NAMESPACE::PointerType robF[MAX_ROBFRAGMENTS];
-   OFFLINE_FRAGMENTS_NAMESPACE::PointerType rePointer;
-   re->start(rePointer);
-   size_t robcount = re->children(robF, MAX_ROBFRAGMENTS);
-   if (robcount == MAX_ROBFRAGMENTS) {
-      ATH_MSG_ERROR("ROB buffer overflow");
-   }
-   // loop over all ROBs
-   for (size_t irob = 0; irob < robcount; irob++) {
-      // add to the map
-      const ROBF* rob = new ROBF(robF[irob]);
-      uint32_t id =  rob->source_id();
-      // mask off the module ID for L2 and EF result for Run 1 data
-      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
-	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-	 if (!m_maskL2EFModuleID) {
-	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
-	   m_maskL2EFModuleID=true;
-	 }
-      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
-		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
-		  (m_maskL2EFModuleID) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-      }
-      if ((rob->rod_ndata() == 0) && (m_filterEmptyROB)) {
-         ATH_MSG_DEBUG( " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
-	         << " removed for L1 Id = " << cache->currentLvl1ID);
-          delete rob;
-      } else if (filterRobWithStatus(rob)) {
-         if (rob->nstatus() > 0) {
-            const uint32_t* it_status;
-            rob->status(it_status);
-            eformat::helper::Status tmpstatus(*it_status);
-            ATH_MSG_DEBUG(" ---> ROB Id = 0x" << MSG::hex << id << std::setfill('0')
-	            << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
-	            << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific() << MSG::dec
-	            << " removed for L1 Id = " << cache->currentLvl1ID);
-         }
-         delete rob;
-      } else {
-	
-         ROBMAP::const_iterator it = cache->robmap.find(id);
-         if (it != cache->robmap.end()) {
-            ATH_MSG_WARNING(" FaserROBDataProviderSvc:: Duplicate ROBID 0x" << MSG::hex << id
-	            << " found. " << MSG::dec << " Overwriting the previous one ");
-            delete cache->robmap[id];
-            cache->robmap[id] = rob;
-         } else {
-            cache->robmap[id] = rob;
-         }
-       
-      }
-   }
-*/
-   ATH_MSG_DEBUG(" ---> setNextEvent offline for " << name() );
-   ATH_MSG_DEBUG("      current LVL1 id   = " << cache->currentLvl1ID );
-   //ATH_MSG_DEBUG("      size of ROB cache = " << cache->robmap.size() );
-   return;
-}
-/** return ROBData for ROBID
- */
-/*
-void FaserROBDataProviderSvc::getROBData(const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, const std::string_view callerName) {
-  const EventContext context{ Gaudi::Hive::currentContext() };
-  return getROBData( context, ids, v, callerName );
-}
-*/
-/*
-void FaserROBDataProviderSvc::getROBData(const EventContext& context, const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, 
-				    const std::string_view callerName) {
   EventCache* cache = m_eventsCache.get( context );
   
-   for (std::vector<uint32_t>::const_iterator it = ids.begin(), it_end = ids.end(); it != it_end; it++) {
-      uint32_t id = (*it);
-      // mask off the module ID for L2 and EF result for Run 1 data
-      if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
-	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-	 if (!m_maskL2EFModuleID) {
-	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
-	   m_maskL2EFModuleID=true;
-	 }
-      } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
-		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
-		  (m_maskL2EFModuleID) ) {
-	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-      }
-      ROBMAP::iterator map_it = cache->robmap.find(id);
-      if (map_it != cache->robmap.end()) {
-         v.push_back((*map_it).second);
-      } else {
-	ATH_MSG_DEBUG("Failed to find ROB for id 0x" << MSG::hex << id << MSG::dec << ", Caller Name = " << callerName);
-#ifndef NDEBUG
-         int nrob = 0;
-         ATH_MSG_VERBOSE(" --- Dump of ROB cache ids --- total size = " << cache->robmap.size());
-         for (ROBMAP::iterator cache_it = cache->robmap.begin(), cache_end = cache->robmap.end();
-	         cache_it != cache_end; cache_it++) {
-	    ++nrob;
-	    ATH_MSG_VERBOSE(" # = " << nrob << "  id = 0x" << MSG::hex << (*cache_it).second->source_id() << MSG::dec);
-         }
-#endif
-      }
-   }
-   return;
-}
-*/
+  cache->event = re;
 
-/** - clear ROB map
- */
-/*
-void FaserROBDataProviderSvc::robmapClear( ROBMAP& toclear) {
-  for (ROBMAP::const_iterator it = toclear.begin(), itE = toclear.end(); it != itE; ++it) {
-     delete it->second;
-  }
-  toclear.clear();
+  ATH_MSG_DEBUG(" ---> setNextEvent offline for " << name() );
+  ATH_MSG_DEBUG("      current LVL1 id   = " << cache->currentLvl1ID );
+  
+  return;
 }
-*/
 
 /// Retrieve the whole event.
 const EventFull* FaserROBDataProviderSvc::getEvent() {
   const EventContext context{ Gaudi::Hive::currentContext() };
   return getEvent( context );
 }
+
 const EventFull* FaserROBDataProviderSvc::getEvent( const EventContext& context ) {
-  
   return m_eventsCache.get( context )->event;
 }
 
@@ -418,58 +158,6 @@ uint32_t FaserROBDataProviderSvc::getEventStatus( const EventContext& context )
   return m_eventsCache.get( context )->eventStatus;
 }
 
-/*
-void FaserROBDataProviderSvc::processCachedROBs(const EventContext& context, 
-					   const std::function< void(const ROBF* )>& fn ) const {
-  for ( const auto&  el : m_eventsCache.get( context )->robmap ) {
-    fn( el.second );
-  }
-}
-*/
-
-
-/** - filter ROB with Sub Detector Id and Status Code
-*/
-/*
-bool FaserROBDataProviderSvc::filterRobWithStatus(const ROBF* rob) {
-   // No filter criteria defined
-   if ((m_filterRobMap.size() == 0) && (m_filterSubDetMap.size() == 0)) {
-      return(false);
-   }
-   // There should be at least one status element if there was an error
-   // in case there are 0 status elements then there was no known error
-   // (see event format document ATL-D-ES-0019 (EDMS))
-   if (rob->nstatus() == 0) {
-      return(false);
-   }
-   // The ROB has at least one status element, access it via an iterator
-   const uint32_t* rob_it_status;
-   rob->status(rob_it_status);
-   // Build the full ROB Sourceidentifier
-   eformat::helper::SourceIdentifier tmpsrc(rob->rob_source_id());
-   // Check if there is a ROB specific filter rule defined for this ROB Id and match the status code
-   FilterRobMap::iterator map_it_rob = m_filterRobMap.find(tmpsrc.code());
-   if (map_it_rob != m_filterRobMap.end()) {
-      for (std::vector<uint32_t>::const_iterator it_status = (*map_it_rob).second.begin(),
-	      it_statusEnd = (*map_it_rob).second.end(); it_status != it_statusEnd; it_status++) {
-         if (*rob_it_status == *it_status) {
-            return(true);
-         }
-      }
-   }
-   // Check if there is a sub detector specific filter rule defined for this ROB Id and match the status code
-   FilterSubDetMap::iterator map_it_subdet = m_filterSubDetMap.find(tmpsrc.subdetector_id());
-   if (map_it_subdet != m_filterSubDetMap.end()) {
-      for (std::vector<uint32_t>::const_iterator it_status = (*map_it_subdet).second.begin(),
-	      it_statusEnd = (*map_it_subdet).second.end(); it_status != it_statusEnd; it_status++) {
-         if (*rob_it_status == *it_status) {
-            return(true);
-         }
-      }
-   }
-   return(false);
-}
-*/
 
 FaserROBDataProviderSvc::EventCache::~EventCache() {
   delete event;
-- 
GitLab


From 1289d6277e4f35871e8e9f1d58bf7afd6edd3d6d Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 17 Jun 2020 11:04:55 -0700
Subject: [PATCH 09/47] Fix formatting

---
 Event/FaserByteStreamCnvSvc/README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Event/FaserByteStreamCnvSvc/README.md b/Event/FaserByteStreamCnvSvc/README.md
index 27fa77df2..95b12364e 100644
--- a/Event/FaserByteStreamCnvSvc/README.md
+++ b/Event/FaserByteStreamCnvSvc/README.md
@@ -1,7 +1,9 @@
 This package provides the infrastructure to read in FASER raw data files and convert the raw information to transient data classes.  Related packages include:
 
 Event/FaserByteStreamCnvSvcBase - home of the ROBDataProvider
+
 Event/FaserEventStorage - low-level file handling routines
+
 faser-common/EventFormats - bytestream formaat definition used online
 
 A test job to read in a raw data file and write Raw Data Objects to xAOD can be found in:
-- 
GitLab


From 1be5a5b22035ff46ee3b7cb84ddaab3d7819993d Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 17 Jun 2020 13:51:57 -0700
Subject: [PATCH 10/47] Fix problem with faser-common Logging

---
 Event/FaserByteStreamCnvSvc/CMakeLists.txt | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/Event/FaserByteStreamCnvSvc/CMakeLists.txt b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
index 5b5d18d6b..4198d2133 100644
--- a/Event/FaserByteStreamCnvSvc/CMakeLists.txt
+++ b/Event/FaserByteStreamCnvSvc/CMakeLists.txt
@@ -9,7 +9,6 @@ atlas_subdir( FaserByteStreamCnvSvc )
 atlas_depends_on_subdirs(
    PUBLIC
    Control/AthenaBaseComps
-   #Event/ByteStreamData
    Event/FaserEventStorage
    GaudiKernel
    PRIVATE
@@ -24,8 +23,7 @@ atlas_depends_on_subdirs(
    Event/xAOD/xAODEventInfo
    Event/xAOD/xAODTrigger
    Event/FaserByteStreamCnvSvcBase
-   EventFormats
-   Logging)
+   EventFormats)
 
 # External dependencies:
 find_package( Boost COMPONENTS system )
@@ -33,11 +31,14 @@ find_package( CORAL COMPONENTS CoralBase )
 #find_package( tdaq-common COMPONENTS eformat_old eformat_write RawFileName
 #   DataReader DataWriter )
 
+# Stupid hack to work around faser-common Logging header
+include_directories( ../../faser-common/Logging/include )
+
 # Libraries in the package:
 atlas_add_library( FaserByteStreamCnvSvcLib
    FaserByteStreamCnvSvc/*.h src/*.h src/*.cxx
    PUBLIC_HEADERS FaserByteStreamCnvSvc
-   PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
+   PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} 
    LINK_LIBRARIES AthenaBaseComps FaserEventStorageLib  GaudiKernel
    StoreGateLib rt
    PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES}
-- 
GitLab


From 084bbff21e2c797043c92877fb021ec3e2498efa Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Jun 2020 11:52:26 -0700
Subject: [PATCH 11/47] Add faser-common submodule from master

---
 faser-common | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/faser-common b/faser-common
index 3908fdd22..f217e2de0 160000
--- a/faser-common
+++ b/faser-common
@@ -1 +1 @@
-Subproject commit 3908fdd228bc5712ddd8ae6e4d8b9a828b75e770
+Subproject commit f217e2de0bae80c7dffa914ed7406a218f353c16
-- 
GitLab


From 5d861e065dac9f41a5d3230423069eb0abae6a2e Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Jun 2020 12:05:49 -0700
Subject: [PATCH 12/47] Tie faser-common to gitlab URL

---
 .gitmodules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 487dba090..82b8e1319 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "faser-common"]
 	   path = faser-common
-	   url = ../faser-common.git
+	   url = https://gitlab.cern.ch/faser/faser-common.git
-- 
GitLab


From a6f14b8cc43397ea6b9f32798b6a5f35ba85c44c Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Jun 2020 12:12:09 -0700
Subject: [PATCH 13/47] Try again with KRB path

---
 .gitmodules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 82b8e1319..637c9b503 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "faser-common"]
 	   path = faser-common
-	   url = https://gitlab.cern.ch/faser/faser-common.git
+	   url = https://:@gitlab.cern.ch:8443/faser/faser-common.git
-- 
GitLab


From ec73adb8fecc5dfe2b1943f4de682357d0fdeaa3 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Jun 2020 12:18:20 -0700
Subject: [PATCH 14/47] Use relative path

---
 .gitmodules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 637c9b503..4ea179882 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "faser-common"]
 	   path = faser-common
-	   url = https://:@gitlab.cern.ch:8443/faser/faser-common.git
+	   url = ../faser-common
-- 
GitLab


From 86ad6c31c0de67d2dd58ee48cf59683acaea1134 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Jun 2020 15:17:37 -0700
Subject: [PATCH 15/47] Add instructions for faser-common

---
 README.md | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index d2e2cc4cf..5fdfa4df1 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,10 @@ The following sequence will allow you to compile Calypso 1.0.0 on any machine wi
 #clone the (forked) project to your local machine
 git clone https://:@gitlab.cern.ch:8443/$USERNAME/calypso.git 
 
+# You also need to add faser-common as a submodule
+cd calypso
+git submodule add https://:@gitlab.cern.ch:8443/faser/faser-common.git
+cd ..
 
 #The next three lines are used to setup the ATLAS release environment
 export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase 
@@ -14,7 +18,11 @@ asetup --input=calypso/asetup.faser master,latest,Athena
 #create build directory
 mkdir build
 cd build
+
 #build calypso
 cmake -DCMAKE_INSTALL_PREFIX=../run ../calypso ; make ; make install
 
-It can be convenient to alias the "asetup --input=calypso/asetup.faser" to something like "fsetup"
\ No newline at end of file
+It can be convenient to alias the "asetup --input=calypso/asetup.faser" to something like "fsetup"
+
+Note that in order for CI/CD to work properly on your gitlab fork of calypso, you will also need to fork the faser-common project.  To avoid having to keep this fork up to date, you can set it up to mirror from the master in gitlab.  Once you have forked the project in gitlab from https://gitlab.cern.ch/faser/faser-common, navigate to to Settings / Repository menu and select "Mirroring repositories" to set up a (Pull) mirror to keep this fork up to date.
+
-- 
GitLab


From fbf35b175cdf60416ab723807344672366a671ed Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 14 Aug 2020 15:47:02 -0700
Subject: [PATCH 16/47] failed submodule update

---
 faser-common | 1 -
 1 file changed, 1 deletion(-)
 delete mode 160000 faser-common

diff --git a/faser-common b/faser-common
deleted file mode 160000
index f217e2de0..000000000
--- a/faser-common
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f217e2de0bae80c7dffa914ed7406a218f353c16
-- 
GitLab


From 2c7797bb70ae356efed27287669ad5ed6676e964 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 14 Aug 2020 15:50:46 -0700
Subject: [PATCH 17/47] New faser-common

---
 .gitmodules  | 4 ++--
 faser-common | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)
 create mode 160000 faser-common

diff --git a/.gitmodules b/.gitmodules
index 4ea179882..5fba28a15 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "faser-common"]
-	   path = faser-common
-	   url = ../faser-common
+	path = faser-common
+	url = https://:@gitlab.cern.ch:8443/faser/faser-common.git
diff --git a/faser-common b/faser-common
new file mode 160000
index 000000000..1da690c5f
--- /dev/null
+++ b/faser-common
@@ -0,0 +1 @@
+Subproject commit 1da690c5f4481ebc34e6ac0ee0e1b104cfe5cf36
-- 
GitLab


From 671dc72516c7e50463fc18181193f66aab15b811 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 9 Sep 2020 16:21:02 -0700
Subject: [PATCH 18/47] fix remaining diffs

---
 .gitmodules                                                     | 1 -
 Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx  | 2 +-
 .../FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py  | 1 -
 3 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index d974046eb..82b8e1319 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
 [submodule "faser-common"]
 	   path = faser-common
 	   url = https://gitlab.cern.ch/faser/faser-common.git
-
diff --git a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
index 4d241fb9d..29feaa277 100644
--- a/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
+++ b/Event/FaserByteStreamCnvSvc/src/EventInfoByteStreamxAODCnv.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
 */
 
 #include "EventInfoByteStreamxAODCnv.h"
diff --git a/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
index 030362a81..ac692d56f 100644
--- a/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
+++ b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
@@ -28,4 +28,3 @@ svcMgr.FaserByteStreamAddressProviderSvc.TypeNames += [
 ]
 
 
-
-- 
GitLab


From 801c1e3046846c5974f8af8c355035ad0c68d810 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 11 Sep 2020 12:04:36 -0700
Subject: [PATCH 19/47] Create waveform POOL converter, update to latest
 waveform channel mappings

---
 .../src/ScintWaveformAccess.cxx               |  5 ++
 .../src/ScintWaveformAccess.h                 |  2 +
 .../python/FaserByteStreamCnvSvcBaseConfig.py |  1 +
 .../src/ScintWaveformDecoderTool.cxx          | 23 +++++++--
 .../src/ScintWaveformDecoderTool.h            |  1 +
 .../ScintEventAthenaPool/CMakeLists.txt       | 28 ++++++++++
 .../ScintEventAthenaPoolCnvDict.h             | 11 ++++
 .../ScintWaveformContainer_p0.h               | 39 ++++++++++++++
 .../ScintEventAthenaPool/ScintWaveform_p0.h   | 42 +++++++++++++++
 .../ScintEventAthenaPool/selection.xml        |  4 ++
 .../src/ScintWaveformCnv_p0.cxx               | 33 ++++++++++++
 .../src/ScintWaveformCnv_p0.h                 | 27 ++++++++++
 .../src/ScintWaveformContainerCnv.cxx         | 42 +++++++++++++++
 .../src/ScintWaveformContainerCnv.h           | 33 ++++++++++++
 .../src/ScintWaveformContainerCnv_p0.cxx      | 51 +++++++++++++++++++
 .../src/ScintWaveformContainerCnv_p0.h        | 28 ++++++++++
 .../src/ScintWaveformContainer_p0.cxx         |  1 +
 17 files changed, 367 insertions(+), 4 deletions(-)
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/CMakeLists.txt
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintEventAthenaPoolCnvDict.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveformContainer_p0.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/selection.xml
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.cxx
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.h
 create mode 100644 Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainer_p0.cxx

diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.cxx b/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.cxx
index 4dc33c5f2..d3de51d50 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.cxx
+++ b/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.cxx
@@ -32,6 +32,7 @@ ScintWaveformAccess::initialize()
   ATH_CHECK( m_TriggerWaveformContainer.initialize() );
   ATH_CHECK( m_PreshowerWaveformContainer.initialize() );
   ATH_CHECK( m_TestWaveformContainer.initialize() );
+  ATH_CHECK( m_ClockWaveformContainer.initialize() );
 
   return StatusCode::SUCCESS;
 }
@@ -70,5 +71,9 @@ ScintWaveformAccess::execute(const EventContext& ctx) const
   ATH_MSG_INFO("Found ReadHandle for TestWaveforms");
   ATH_MSG_INFO(*testHandle);
 
+  SG::ReadHandle<ScintWaveformContainer> clockHandle(m_ClockWaveformContainer, ctx);
+  ATH_MSG_INFO("Found ReadHandle for ClockWaveforms");
+  ATH_MSG_INFO(*clockHandle);
+
   return StatusCode::SUCCESS;
 }
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.h b/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.h
index bea751f29..ac73b688d 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.h
+++ b/Control/CalypsoExample/WaveformDataAccessExample/src/ScintWaveformAccess.h
@@ -40,6 +40,8 @@ class ScintWaveformAccess: public AthReentrantAlgorithm
     { this, "PreshowerWaveformContainerKey", "PreshowerWaveforms", "ReadHandleKey for PreshowerWaveforms Container"};
   SG::ReadHandleKey<ScintWaveformContainer> m_TestWaveformContainer
     { this, "TestWaveformContainerKey", "TestWaveforms", "ReadHandleKey for TestWaveforms Container"};
+  SG::ReadHandleKey<ScintWaveformContainer> m_ClockWaveformContainer
+    { this, "ClockWaveformContainerKey", "ClockWaveforms", "ReadHandleKey for ClockWaveforms Container"};
 };
 
 #endif /* WAVEFORMDATAACCESSEXAMPLE_SCINTWAVEFORMACCESS_H */
diff --git a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
index 63c95b014..3346c0fd6 100644
--- a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
+++ b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
@@ -17,6 +17,7 @@ def FaserByteStreamCnvSvcBaseCfg(flags, **kwargs):
         "ScintWaveformContainer/VetoWaveforms",
         "ScintWaveformContainer/TriggerWaveforms",
         "ScintWaveformContainer/PreshowerWaveforms",
+        "ScintWaveformContainer/ClockWaveforms",
         "ScintWaveformContainer/TestWaveforms"  
     ]
 
diff --git a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
index 8cb9a344e..de415ef29 100644
--- a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
+++ b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
@@ -22,18 +22,31 @@ ScintWaveformDecoderTool::ScintWaveformDecoderTool(const std::string& type,
 
   declareProperty("CaloChannels", m_caloChannels);
   m_caloChannels.push_back(0);
+  m_caloChannels.push_back(1);
+  m_caloChannels.push_back(2);
+  m_caloChannels.push_back(3);
 
   declareProperty("VetoChannels", m_vetoChannels);
-  m_vetoChannels.push_back(1);
+  m_vetoChannels.push_back(4);
+  m_vetoChannels.push_back(5);
+  m_vetoChannels.push_back(6);
+  m_vetoChannels.push_back(7);
 
   declareProperty("TriggerChannels", m_triggerChannels);
-  m_triggerChannels.push_back(2);
+  m_triggerChannels.push_back(8);
+  m_triggerChannels.push_back(9);
+  m_triggerChannels.push_back(10);
+  m_triggerChannels.push_back(11);
 
   declareProperty("PreshowerChannels", m_preshowerChannels);
-  m_preshowerChannels.push_back(3);
+  m_preshowerChannels.push_back(12);
+  m_preshowerChannels.push_back(13);
 
   declareProperty("TestChannels", m_testChannels);
-  m_testChannels.push_back(4);
+  m_testChannels.push_back(14);
+
+  declareProperty("ClockChannels", m_clockChannels);
+  m_clockChannels.push_back(15);
 
 }
 
@@ -104,6 +117,8 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     channelList = &m_preshowerChannels;
   } else if (key == std::string("TestWaveforms")) {
     channelList = &m_testChannels;
+  } else if (key == std::string("ClockWaveforms")) {
+    channelList = &m_clockChannels;
   } else {
     ATH_MSG_ERROR("Unknown key " << key);
     return StatusCode::FAILURE;
diff --git a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.h b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.h
index 0c43dc026..a5e7bd982 100644
--- a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.h
+++ b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.h
@@ -37,6 +37,7 @@ private:
   std::vector<unsigned int> m_triggerChannels;
   std::vector<unsigned int> m_preshowerChannels;
   std::vector<unsigned int> m_testChannels;
+  std::vector<unsigned int> m_clockChannels;
 
 
 };
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/CMakeLists.txt b/Scintillator/ScintEventCnv/ScintEventAthenaPool/CMakeLists.txt
new file mode 100644
index 000000000..b68ac1d60
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/CMakeLists.txt
@@ -0,0 +1,28 @@
+# $Id: CMakeLists.txt 749562 2016-05-25 04:45:43Z krasznaa $
+################################################################################
+# Package: ScintEventAthenaPool
+################################################################################
+
+# Declare the package name:
+atlas_subdir( ScintEventAthenaPool )
+
+# Component(s) in the package:
+atlas_add_poolcnv_library( ScintEventAthenaPoolPoolCnv
+   ScintEventAthenaPool/*.h src/*.h src/*.cxx
+   FILES ScintRawEvent/ScintWaveform.h
+   ScintRawEvent/ScintWaveformContainer.h
+   LINK_LIBRARIES Identifier GeneratorObjectsTPCnv AthAllocators AthContainers
+   AthenaBaseComps AthenaKernel SGTools StoreGateLib AthenaPoolCnvSvcLib
+   AthenaPoolUtilities AtlasSealCLHEP GaudiKernel ScintRawEvent
+   )
+
+atlas_add_dictionary( ScintEventAthenaPoolCnvDict
+   ScintEventAthenaPool/ScintEventAthenaPoolCnvDict.h
+   ScintEventAthenaPool/selection.xml
+   LINK_LIBRARIES Identifier GeneratorObjectsTPCnv )
+
+# Install files from the package:
+atlas_install_headers( ScintEventAthenaPool )
+
+
+
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintEventAthenaPoolCnvDict.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintEventAthenaPoolCnvDict.h
new file mode 100644
index 000000000..ddf45c647
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintEventAthenaPoolCnvDict.h
@@ -0,0 +1,11 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef SCINTEVENTATHENAPOOLCNVDICT_H
+#define SCINTEVENTATHENAPOOLCNVDICT_H
+
+#include "ScintEventAthenaPool/ScintWaveform_p0.h"
+#include "ScintEventAthenaPool/ScintWaveformContainer_p0.h"
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveformContainer_p0.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveformContainer_p0.h
new file mode 100644
index 000000000..1c7b327d1
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveformContainer_p0.h
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTWAVEFORMCONTAINER_P0_H
+#define SCINTWAVEFORMCONTAINER_P0_H
+
+// Persistent represenation of a ScintWaveformContainer.
+
+#include <vector>
+#include "ScintEventAthenaPool/ScintWaveform_p0.h"
+
+class ScintWaveformContainer_p0 {
+ public:
+  ScintWaveformContainer_p0();
+  friend class ScintWaveformContainerCnv_p0;
+ private:
+  bool         m_board_fail_flag;
+  unsigned int m_board_id;
+  unsigned int m_pattern_trig_options;
+  unsigned int m_channel_mask;
+  unsigned int m_event_counter;
+  unsigned int m_trigger_time_tag;
+  unsigned int m_samples;
+  std::vector<ScintWaveform_p0> m_waveforms;
+};
+
+inline
+ScintWaveformContainer_p0::ScintWaveformContainer_p0() : m_board_fail_flag(0),
+			  m_board_id(0), 
+			  m_pattern_trig_options(0),
+			  m_channel_mask(0),
+			  m_event_counter(0),
+			  m_trigger_time_tag(0),
+			  m_samples(0) {
+  m_waveforms.clear();
+}
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
new file mode 100644
index 000000000..b37fe2848
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef SCINTWAVEFORM_P0_H
+#define SCINTWAVEFORM_P0_H
+
+#include <vector>
+#include <iostream>
+#include <iomanip>
+
+class ScintWaveform_p0 {
+ public:
+  ScintWaveform_p0();
+
+// List of Cnv classes that convert this into Rdo objects
+  friend class ScintWaveformCnv_p0;
+
+ private:
+  unsigned int m_channel;
+  std::vector<unsigned int> m_adc_counts;
+
+ public:
+  void print() const {
+    std::cout << "Persistent Waveform data:" << std::endl
+	      << std::setw(30) << " channel:              "<<std::setfill(' ')<<std::setw(32)<<std::dec<<m_channel<<std::setfill(' ')<<std::endl
+	      << std::setw(30) << " length:               "<<std::setfill(' ')<<std::setw(32)<<std::dec<<m_adc_counts.size()<<std::setfill(' ')<<std::endl;
+  }
+};
+
+inline
+ScintWaveform_p0::ScintWaveform_p0() : m_channel(0) { 
+  m_adc_counts.clear(); 
+}
+
+// Stream operator for debugging
+//std::ostream
+//&operator<<(std::ostream &out, const ScintWaveform_p0 &wfm) {
+//  return wfm.print(out);
+//}
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/selection.xml b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/selection.xml
new file mode 100644
index 000000000..5c52a4cc6
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/selection.xml
@@ -0,0 +1,4 @@
+<lcgdict>
+  <class name="ScintWaveform_p0" />
+  <class name="ScintWaveformContainer_p0" id="344d904d-6338-41f1-94ee-ea609ea4ae44" />
+</lcgdict>
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
new file mode 100644
index 000000000..b245674d8
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintWaveformCnv_p0.h"
+
+void
+ScintWaveformCnv_p0::persToTrans(const ScintWaveform_p0* persObj, ScintWaveform* transObj, MsgStream& log) {
+
+  transObj = 0;
+  log << MSG::WARNING << "ScintWaveformCnv_p0::persToTrans not implemented!" << endmsg;
+
+}
+
+void
+ScintWaveformCnv_p0::transToPers(const ScintWaveform* transObj, ScintWaveform_p0* persObj, MsgStream& log) {
+
+  // log << MSG::DEBUG << "ScintWaveformCnv_p0::transToPers called" << endmsg;
+  // log << MSG::DEBUG << "Transient waveform:" << endmsg;
+  // log << MSG::DEBUG << (*transObj) << endmsg;
+  // log << MSG::DEBUG << "Persistent waveform (before):" << endmsg;
+  // persObj->print();
+
+  persObj->m_channel = transObj->channel();
+
+  // Use copy here
+  persObj->m_adc_counts = transObj->adc_counts();
+
+  // log << MSG::DEBUG << "Persistent waveform (after):" << endmsg;
+  // persObj->print();
+  // log << MSG::DEBUG << "ScintWaveformCnv_p0::transToPers done" << endmsg;
+
+}
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.h
new file mode 100644
index 000000000..41bb1530d
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.h
@@ -0,0 +1,27 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTWAVEFORMCNV_P0_H
+#define SCINTWAVEFORMCNV_P0_H
+
+#include "ScintRawEvent/ScintWaveform.h"
+#include "ScintEventAthenaPool/ScintWaveform_p0.h"
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h"
+
+class ScintWaveformCnv_p0 : public T_AthenaPoolTPCnvBase<ScintWaveform, ScintWaveform_p0> {
+ public:
+  ScintWaveformCnv_p0() {};
+
+  virtual void persToTrans(const ScintWaveform_p0* persObj,
+			   ScintWaveform* transObj,
+			   MsgStream& log);
+
+  virtual void transToPers(const ScintWaveform* transObj,
+			   ScintWaveform_p0* persObj,
+			   MsgStream& log);
+ private:
+};
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.cxx
new file mode 100644
index 000000000..afea1cac3
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.cxx
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintWaveformContainerCnv.h"
+
+ScintWaveformContainer_PERS* 
+ScintWaveformContainerCnv::createPersistent (ScintWaveformContainer* transCont) {
+  ATH_MSG_DEBUG("ScintWaveformContainerCnv::createPersistent()");
+
+  ScintWaveformContainerCnv_PERS converter;
+
+  ScintWaveformContainer_PERS* persObj(nullptr);
+  persObj = converter.createPersistent( transCont, msg() );
+  return persObj;
+}
+
+ScintWaveformContainer* 
+ScintWaveformContainerCnv::createTransient() {
+  ATH_MSG_DEBUG("ScintWaveformContainerCnv::createTransient()");
+
+  static const pool::Guid p0_guid("344d904d-6338-41f1-94ee-ea609ea4ae44");
+  ScintWaveformContainer* trans(0);
+
+  // Check for GUID of each persistent type
+  if ( compareClassGuid(p0_guid) ) {
+    std::unique_ptr< ScintWaveformContainer_p0 > col_vect( poolReadObject< ScintWaveformContainer_p0 >() );
+
+    ScintWaveformContainerCnv_p0 converter_p0;
+    trans = converter_p0.createTransient( col_vect.get(), msg() );
+
+  } else {
+
+    // Didn't find a known type
+    throw std::runtime_error("Unsupported persistent version of ScintWaveformContainer");
+  }
+
+  return trans;
+
+}
+
+
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.h
new file mode 100644
index 000000000..c0160c8ef
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv.h
@@ -0,0 +1,33 @@
+/*
+ Copyright 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTWAVEFORMCONTAINERCNV_H
+#define SCINTWAVEFORMCONTAINERCNV_H
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h"
+
+#include "ScintWaveformContainerCnv_p0.h"
+
+#include "ScintRawEvent/ScintWaveformContainer.h"
+#include "ScintEventAthenaPool/ScintWaveformContainer_p0.h"
+
+// The latest persistent representation
+typedef ScintWaveformContainer_p0 ScintWaveformContainer_PERS;
+typedef ScintWaveformContainerCnv_p0 ScintWaveformContainerCnv_PERS;
+
+typedef T_AthenaPoolCustomCnv< ScintWaveformContainer, ScintWaveformContainer_PERS > ScintWaveformContainerCnvBase;
+
+class ScintWaveformContainerCnv : public ScintWaveformContainerCnvBase {
+  friend class CnvFactory<ScintWaveformContainerCnv>;
+
+ public:
+  ScintWaveformContainerCnv (ISvcLocator* svcloc) : ScintWaveformContainerCnvBase(svcloc) {}
+
+ protected:
+  virtual ScintWaveformContainer_PERS* createPersistent (ScintWaveformContainer* transCont);
+  virtual ScintWaveformContainer* createTransient ();
+
+};
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
new file mode 100644
index 000000000..f808f1081
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintWaveformContainerCnv_p0.h"
+#include "ScintWaveformCnv_p0.h"
+
+void
+ScintWaveformContainerCnv_p0::persToTrans(const ScintWaveformContainer_p0* persCont, ScintWaveformContainer* transCont, MsgStream& log) {
+
+  transCont = 0;
+  log << MSG::WARNING << "ScintWaveformContainerCnv_p0::persToTrans not implemented!" << endmsg;
+
+
+}
+
+void
+ScintWaveformContainerCnv_p0::transToPers(const ScintWaveformContainer* transCont,ScintWaveformContainer_p0* persCont, MsgStream& log) {
+
+  log << MSG::DEBUG << "ScintWaveformContainerCnv_p0::transToPers preparing " << transCont->size() << " waveforms" << endmsg;
+
+  ScintWaveformCnv_p0 waveformCnv;
+
+  typedef ScintWaveformContainer TRANS;
+  TRANS::const_iterator it_Cont = transCont->begin();
+  TRANS::const_iterator it_ContEnd = transCont->end();
+
+  // Fill common information
+  const ScintWaveform* transObj = (*it_Cont);
+  persCont->m_board_fail_flag = transObj->board_fail_flag();
+  persCont->m_board_id = transObj->board_id();
+  persCont->m_pattern_trig_options = transObj->pattern_trig_options();
+  persCont->m_channel_mask = transObj->channel_mask();
+  persCont->m_event_counter = transObj->event_counter();
+  persCont->m_trigger_time_tag = transObj->trigger_time_tag();
+  persCont->m_samples = transObj->n_samples();
+
+  // Loop over each waveform and convert those as well
+  persCont->m_waveforms.resize(transCont->size());
+
+  for (int index=0; it_Cont != it_ContEnd; it_Cont++, index++) {
+    // Add new collection
+    log << MSG::DEBUG << "Converting waveform " << index << endmsg;
+    const ScintWaveform* data = (*it_Cont);
+    ScintWaveform_p0* pdata = &(persCont->m_waveforms.at(index));
+    waveformCnv.transToPers(data, pdata, log);
+  }
+
+  log << MSG::DEBUG << "ScintWaveformContainerCnv_p0::transToPers finished" << endmsg;
+
+}
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.h
new file mode 100644
index 000000000..6792e2a2e
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.h
@@ -0,0 +1,28 @@
+/*
+ Copyright 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTWAVEFORMCONTAINERCNV_P0_H
+#define SCINTWAVEFORMCONTAINERCNV_P0_H
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h"
+
+#include "ScintRawEvent/ScintWaveformContainer.h"
+#include "ScintEventAthenaPool/ScintWaveformContainer_p0.h"
+
+class ScintWaveformContainerCnv_p0 : public T_AthenaPoolTPCnvBase<ScintWaveformContainer, ScintWaveformContainer_p0> {
+
+ public:
+  ScintWaveformContainerCnv_p0() {};
+
+  virtual void persToTrans(const ScintWaveformContainer_p0* persCont,
+			   ScintWaveformContainer* transCont, 
+			   MsgStream& log);
+
+  virtual void transToPers(const ScintWaveformContainer* transCont, 
+			   ScintWaveformContainer_p0* persCont, 
+			   MsgStream& log);
+
+};
+
+#endif
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainer_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainer_p0.cxx
new file mode 100644
index 000000000..7d047238e
--- /dev/null
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainer_p0.cxx
@@ -0,0 +1 @@
+// Dummy source file so that cmake can find this
-- 
GitLab


From 188bb23b3b7efc02da8441c78210ef034593e575 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 11 Sep 2020 14:08:49 -0700
Subject: [PATCH 20/47] Add P->T conversion

---
 .../ScintEventAthenaPool/ScintWaveform_p0.h   |  1 +
 .../src/ScintWaveformCnv_p0.cxx               |  9 ++++---
 .../src/ScintWaveformContainerCnv_p0.cxx      | 24 +++++++++++++++++--
 .../ScintRawEvent/ScintWaveform.h             | 11 +++++++++
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
index b37fe2848..e91c8811f 100644
--- a/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/ScintEventAthenaPool/ScintWaveform_p0.h
@@ -17,6 +17,7 @@ class ScintWaveform_p0 {
   friend class ScintWaveformCnv_p0;
 
  private:
+  unsigned int m_ID;
   unsigned int m_channel;
   std::vector<unsigned int> m_adc_counts;
 
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
index b245674d8..ffc6f0d8d 100644
--- a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformCnv_p0.cxx
@@ -7,8 +7,11 @@
 void
 ScintWaveformCnv_p0::persToTrans(const ScintWaveform_p0* persObj, ScintWaveform* transObj, MsgStream& log) {
 
-  transObj = 0;
-  log << MSG::WARNING << "ScintWaveformCnv_p0::persToTrans not implemented!" << endmsg;
+  // Just fill available data here
+  // Rest of it patched up in ScintWaveformContainerCnv_p0
+  transObj->setIdentifier(persObj->m_ID);
+  transObj->setChannel(persObj->m_channel);
+  transObj->setCounts(persObj->m_adc_counts);
 
 }
 
@@ -20,7 +23,7 @@ ScintWaveformCnv_p0::transToPers(const ScintWaveform* transObj, ScintWaveform_p0
   // log << MSG::DEBUG << (*transObj) << endmsg;
   // log << MSG::DEBUG << "Persistent waveform (before):" << endmsg;
   // persObj->print();
-
+  persObj->m_ID = transObj->identify();
   persObj->m_channel = transObj->channel();
 
   // Use copy here
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
index f808f1081..4312a0303 100644
--- a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
@@ -8,10 +8,30 @@
 void
 ScintWaveformContainerCnv_p0::persToTrans(const ScintWaveformContainer_p0* persCont, ScintWaveformContainer* transCont, MsgStream& log) {
 
-  transCont = 0;
-  log << MSG::WARNING << "ScintWaveformContainerCnv_p0::persToTrans not implemented!" << endmsg;
+  log << MSG::DEBUG << "ScintWaveformContainerCnv_p0::persToTrans called" << endmsg;
 
+  ScintWaveformCnv_p0 waveformCnv;
+
+  // Clear this, transient container is DataVector, which stores pointers
+  // Create them below and push back to fill
+  transCont->clear();
 
+  for (unsigned int index = 0; index < persCont->m_waveforms.size(); ++index) {
+    std::unique_ptr<ScintWaveform> data = std::make_unique<ScintWaveform>();
+    const ScintWaveform_p0* pdata = &persCont->m_waveforms.at(index);
+    waveformCnv.persToTrans(pdata, data.get(), log);
+    
+    // Fill other values held by container in persistent class
+    data->setBoardFailFlag(persCont->m_board_fail_flag);
+    data->setBoardId(persCont->m_board_id);
+    data->setPatternTrigOptions(persCont->m_pattern_trig_options);
+    data->setChannelMask(persCont->m_channel_mask);
+    data->setEventCounter(persCont->m_event_counter);
+    data->setTriggerTime(persCont->m_trigger_time_tag);
+    data->setSamples(persCont->m_samples);
+
+    transCont->push_back(data.release());
+  }
 }
 
 void
diff --git a/Scintillator/ScintRawEvent/ScintRawEvent/ScintWaveform.h b/Scintillator/ScintRawEvent/ScintRawEvent/ScintWaveform.h
index 0c211be6c..c7598d446 100644
--- a/Scintillator/ScintRawEvent/ScintRawEvent/ScintWaveform.h
+++ b/Scintillator/ScintRawEvent/ScintRawEvent/ScintWaveform.h
@@ -73,6 +73,17 @@ public:
   void setHeader (const DigitizerDataFragment* frag);
   void setWaveform (unsigned int channel, const std::vector<uint16_t> waveform);
 
+  // Set functions for P->T conversion
+  void setBoardId(unsigned int id) {m_board_id = id;}
+  void setBoardFailFlag(bool flag) {m_board_fail_flag = flag;}
+  void setPatternTrigOptions(unsigned int pattern) {m_pattern_trig_options = pattern;}
+  void setChannelMask(unsigned int mask) {m_channel_mask = mask;}
+  void setEventCounter(unsigned int counter) {m_event_counter = counter;}
+  void setTriggerTime(unsigned int tag) {m_trigger_time_tag = tag;}
+  void setChannel(unsigned int chan) {m_channel = chan;}
+  void setSamples(unsigned int samp) {m_samples = samp;}
+  void setCounts(const std::vector<unsigned int>& counts) {m_adc_counts = counts;}
+
   ///////////////////////////////////////////////////////////////////
   // Private data:
   ///////////////////////////////////////////////////////////////////
-- 
GitLab


From a89c9c026591b95c74152ce1ffe8f96c12f4e841 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 18 Feb 2021 16:20:28 -0800
Subject: [PATCH 21/47] First commit of scintillator reconstruction code.

Code doesn't actually do anything, but this compiles and give the basic framework
for adding real algorithims.
---
 Scintillator/ScintRecAlgs/CMakeLists.txt      | 15 ++++
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  | 48 +++++++++++
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    | 79 +++++++++++++++++++
 .../src/components/ScintRecAlgs_entries.cxx   |  3 +
 Scintillator/ScintRecTools/CMakeLists.txt     | 24 ++++++
 .../IWaveformReconstructionTool.h             | 38 +++++++++
 .../src/WaveformReconstructionTool.cxx        | 32 ++++++++
 .../src/WaveformReconstructionTool.h          | 40 ++++++++++
 .../src/components/ScintRecTools_entries.cxx  |  3 +
 9 files changed, 282 insertions(+)
 create mode 100644 Scintillator/ScintRecAlgs/CMakeLists.txt
 create mode 100644 Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
 create mode 100644 Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
 create mode 100644 Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
 create mode 100644 Scintillator/ScintRecTools/CMakeLists.txt
 create mode 100644 Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
 create mode 100644 Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
 create mode 100644 Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
 create mode 100644 Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx

diff --git a/Scintillator/ScintRecAlgs/CMakeLists.txt b/Scintillator/ScintRecAlgs/CMakeLists.txt
new file mode 100644
index 000000000..b89582e2d
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/CMakeLists.txt
@@ -0,0 +1,15 @@
+################################################################################
+# Package: ScintRecAlgs
+################################################################################
+
+# Declare the package name:
+atlas_subdir( ScintRecAlgs )
+
+# Component(s) in the package:
+atlas_add_component( ScintRecAlgs
+                     src/*.cxx src/*.h
+                     src/components/*.cxx
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecToolsLib) #ScintRecEvent )
+
+#atlas_install_python_modules( python/*.py )
+
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
new file mode 100644
index 000000000..efd01a2cc
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -0,0 +1,48 @@
+#include "ScintWaveformRecAlg.h"
+
+ScintWaveformRecAlg::ScintWaveformRecAlg(const std::string& name, 
+					 ISvcLocator* pSvcLocator)
+  : AthReentrantAlgorithm(name, pSvcLocator) { 
+
+}
+
+StatusCode 
+ScintWaveformRecAlg::initialize() {
+  ATH_MSG_INFO(name() << "::initalize()" );
+
+  // Initalize tools
+  ATH_CHECK( m_recoTool.retrieve() );
+
+  // Make sure we have something to work with
+  ATH_CHECK( m_inputWaveformKey.length() != 0);
+  ATH_MSG_INFO(name() << "Reading from " << m_inputWaveformKey );
+  ATH_MSG_INFO(name() << "Writing to   " << m_outputWaveformKey );
+
+  // Set key to read waveform from
+  m_waveformContainer = m_inputWaveformKey;
+  ATH_CHECK( m_waveformContainer.initialize() );
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+ScintWaveformRecAlg::finalize() {
+  ATH_MSG_INFO(name() << "::finalize()");
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+ScintWaveformRecAlg::execute(const EventContext& ctx) const {
+  ATH_MSG_INFO(name() << "::execute()");
+
+  ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() 
+		<< " Event: " << ctx.eventID().event_number());
+
+  SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainer, ctx);
+  ATH_MSG_INFO("Found ReadHandle for Waveforms");
+  ATH_MSG_INFO(*waveformHandle);
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
new file mode 100644
index 000000000..16e071bcb
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -0,0 +1,79 @@
+#ifndef SCINTRECALGS_SCINTWAVEFORMRECALG_H
+#define SCINTRECALGS_SCINTWAVEFORMRECALG_H
+
+// Base class
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+
+#include "ScintRawEvent/ScintWaveformContainer.h"
+#include "ScintRecTools/IWaveformReconstructionTool.h"
+
+#include "StoreGate/ReadHandleKey.h"
+
+// Gaudi
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ToolHandle.h"
+
+// STL
+#include <string>
+
+class ScintWaveformRecAlg : public AthReentrantAlgorithm {
+
+ public:
+  // Constructor
+  ScintWaveformRecAlg(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~ScintWaveformRecAlg() = default;
+
+  /** @name Usual algorithm methods */
+  //@{
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+  //@}
+
+ private:
+
+  /** @name Disallow default instantiation, copy, assignment */
+  //@{
+  ScintWaveformRecAlg() = delete;
+  ScintWaveformRecAlg(const ScintWaveformRecAlg&) = delete;
+  ScintWaveformRecAlg &operator=(const ScintWaveformRecAlg&) = delete;
+  //@}
+
+  /**
+   * @name Reconstruction tool
+   */
+  ToolHandle<IWaveformReconstructionTool> m_recoTool
+    {this, "WaveformReconstructionTool", "WaveformReconstructionTool"};
+
+  /**
+   * @name Input data using SG::ReadHandleKey
+   */
+  //@{
+  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainer 
+    {this, "WaveformContainerKey", ""};
+  //@}
+
+  /**
+   * @name Output data using SG::ReadHandleKey
+   */
+  //@{
+  //SG::WriteHandleKey<ScintWaveformContainer> m_waveformContainer 
+  //  {this, "WaveformContainerKey", ""};
+  //@}
+
+
+  /** @brief Key for the DetectorStore (jobOptions) 
+   * The input waveform will be read from this key.
+   */
+  StringProperty m_inputWaveformKey
+  { this, "inputKey", ""};
+
+  /** @brief Key for the DetectorStore (jobOptions) 
+   * The output data will be saved to this key.
+   */
+  StringProperty m_outputWaveformKey
+  { this, "outputKey", ""};
+
+};
+
+#endif // SCINTRECALGS_SCINTWAVEFORMRECALG_H
diff --git a/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx b/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
new file mode 100644
index 000000000..bd3d88daf
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
@@ -0,0 +1,3 @@
+#include "../ScintWaveformRecAlg.h"
+
+DECLARE_COMPONENT( ScintWaveformRecAlg )
diff --git a/Scintillator/ScintRecTools/CMakeLists.txt b/Scintillator/ScintRecTools/CMakeLists.txt
new file mode 100644
index 000000000..92d9c2594
--- /dev/null
+++ b/Scintillator/ScintRecTools/CMakeLists.txt
@@ -0,0 +1,24 @@
+################################################################################
+# Package: ScintRecTools
+################################################################################
+
+# Declare the package name:
+atlas_subdir( ScintRecTools )
+
+# External dependencies:
+# find_package( Eigen )
+
+# Component(s) in the package:
+atlas_add_library( ScintRecToolsLib
+                   ScintRecTools/*.h src/*.cxx src/*.h
+                   PUBLIC_HEADERS ScintRecTools
+                   # INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent # ScintRecEvent
+                   # PRIVATE_LINK_LIBRARIES GaudiKernel TrackerIdentifier TrackerReadoutGeometry TrackerSpacePoint 
+		   )
+
+atlas_add_component( ScintRecTools
+		     src/components/*.cxx 
+		     # INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}
+                     LINK_LIBRARIES AthenaBaseComps GaudiKernel ScintRecToolsLib )
+
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
new file mode 100644
index 000000000..a392443f7
--- /dev/null
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file IWaveformReconstructionTool.h
+ * Header file for the IWaveformReconstructionTool class
+ * @author Eric Torrence, 2021
+ */
+
+
+#ifndef SCINTRECTOOLS_IWAVEFORMRECONSTRUCTIONTOOL_H
+#define SCINTRECTOOLS_IWAVEFORMRECONSTRUCTIONTOOL_H
+
+// Base class
+#include "GaudiKernel/IAlgTool.h"
+#include "ScintRawEvent/ScintWaveform.h"
+// #include "ScintRecEvent/WaveformHitCollection.h"
+#include "GaudiKernel/ToolHandle.h"
+
+///Interface for Waveform reco algorithms
+class IWaveformReconstructionTool : virtual public IAlgTool 
+{
+  public:
+
+  // InterfaceID
+  DeclareInterfaceID(IWaveformReconstructionTool, 1, 0);
+
+  virtual ~IWaveformReconstructionTool() = default;
+
+  /** Reconstruct a single waveform into a list of hits
+   * @param[in] @c RDOs the raw data objects
+   */
+  //virtual WaveformHitCollection* reconstruct(const ScintWaveform& wave) const = 0;
+
+};
+
+#endif // SCINTRECTOOLS_IWAVEFORMRECONSTRUCTIONTOOL_H
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
new file mode 100644
index 000000000..3782bcc89
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+/**
+ * @file WaveformReconstructionTool.cxx
+ * Implementation file for the WaveformReconstructionTool.cxx
+ * @ author E. Torrence, 2021
+ **/
+
+#include "WaveformReconstructionTool.h"
+
+// Constructor
+WaveformReconstructionTool::WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
+  base_class(type, name, parent)
+{
+}
+
+// Initialization
+StatusCode
+WaveformReconstructionTool::initialize() {
+  ATH_MSG_INFO( name() << "::initalize()" );
+
+  return StatusCode::SUCCESS;
+}
+
+// Reconstruction step
+/*
+WaveformHitCollection*
+WaveformReconstructionTool::reconstruct(const ScintWaveform& wave) const {
+}
+*/
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
new file mode 100644
index 000000000..84dcb2d48
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -0,0 +1,40 @@
+/*
+   Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+/** @file WaveformReconstructionTool.h
+ *  Header file for WaveformReconstructionTool.h
+ *
+ */
+#ifndef SCINTRECTOOLS_WAVEFORMRECONSTRUCTIONTOOL_H
+#define SCINTRECTOOLS_WAVEFORMRECONSTRUCTIONTOOL_H
+
+//Athena
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "ScintRecTools/IWaveformReconstructionTool.h"
+
+//Gaudi
+#include "GaudiKernel/ToolHandle.h"
+
+//STL
+#include <string>
+#include <vector>
+
+
+class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstructionTool> {
+ public:
+
+  /// Normal constructor for an AlgTool; 'properties' are also declared here
+  WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent);
+
+  /// Retrieve the necessary services in initialize
+  StatusCode initialize();
+
+  /// Reconstruct hits from waveform
+  //virtual WaveformHitCollection* reconstruct(const ScintWaveform& wave) const;
+
+ private:
+
+};
+
+#endif // SCINTRECTOOLS_WAVEFORMRECONSTRUCTIONTOOL_H
diff --git a/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx b/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx
new file mode 100644
index 000000000..a4318588f
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx
@@ -0,0 +1,3 @@
+#include "../WaveformReconstructionTool.h"
+
+DECLARE_COMPONENT( WaveformReconstructionTool )
-- 
GitLab


From e649f55620ce5b3d455da7ad9ea76f196b5d4ae1 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Sun, 21 Feb 2021 22:34:03 -0800
Subject: [PATCH 22/47] Working on reading waveform with
 WaveformReconstructionTool

---
 Scintillator/ScintRecEvent/CMakeLists.txt     | 15 ++++
 .../ScintRecEvent/WaveformBaselineData.h      | 77 +++++++++++++++++++
 .../src/WaveformBaselineData.cxx              | 50 ++++++++++++
 3 files changed, 142 insertions(+)
 create mode 100644 Scintillator/ScintRecEvent/CMakeLists.txt
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
 create mode 100644 Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx

diff --git a/Scintillator/ScintRecEvent/CMakeLists.txt b/Scintillator/ScintRecEvent/CMakeLists.txt
new file mode 100644
index 000000000..b560c284a
--- /dev/null
+++ b/Scintillator/ScintRecEvent/CMakeLists.txt
@@ -0,0 +1,15 @@
+################################################################################
+# Package: ScintRecEvent
+################################################################################
+
+# Declare the package name:
+atlas_subdir( ScintRecEvent )
+
+# External dependencies:
+
+# Component(s) in the package:
+atlas_add_library( ScintRecEvent
+                   src/*.cxx src/*.h
+                   PUBLIC_HEADERS ScintRecEvent
+                   PRIVATE_LINK_LIBRARIES ScintRawEvent)
+
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
new file mode 100644
index 000000000..5f7a25576
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// WaveformBaselineData.h
+//   Header file for class WaveformBaselineData
+///////////////////////////////////////////////////////////////////
+// Class to handle the baseline information for a raw waveform
+///////////////////////////////////////////////////////////////////
+// Version 1.0   2/21/2021 Eric Torrence
+///////////////////////////////////////////////////////////////////
+#ifndef SCINTRECEVENT_WAVEFORMBASELINEDATA_H
+#define SCINTRECEVENT_WAVEFORMBASELINEDATA_H
+
+#include <iostream>
+
+/**
+ * @class WaveformBaselineData
+ * The baseline is the estimate of the waveform reading for no signal.
+ */
+  
+class WaveformBaselineData {
+      
+ public:
+      
+  /** Default constructor */
+  WaveformBaselineData();
+
+  /**
+   * @name Parametrised constructors
+   */
+  //@{
+  WaveformBaselineData(bool valid);
+  WaveformBaselineData(double mean, double rms, int channel);    
+  //@}
+
+  /** Copy Constructor */
+  WaveformBaselineData(const WaveformBaselineData &) ;
+
+  /** Destructor */
+  virtual ~WaveformBaselineData() = default;
+
+  /** Overloading Assignment Operator */
+  WaveformBaselineData &operator=(const WaveformBaselineData &);
+
+  /** Clones */
+  virtual WaveformBaselineData* clone() const ;       
+            
+  // Access functions
+  inline double get_mean() const { return m_mean; }
+  inline double get_rms() const { return m_rms; }
+  inline int get_channel() const { return m_channel; }
+  inline double is_valid() const { return m_valid; }
+
+  private:
+
+  // Data members
+  double m_mean;
+  double m_rms;
+  int m_channel;
+  bool m_valid;
+};
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformBaselineData &wfm);
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+inline WaveformBaselineData* 
+WaveformBaselineData::clone() const { 
+  return new WaveformBaselineData(*this);  
+}
+
+#endif // SCINTRECEVENT_WAVEFORMBASELINEDATA_H
diff --git a/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx b/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
new file mode 100644
index 000000000..7bc52ab94
--- /dev/null
+++ b/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintRecEvent/WaveformBaselineData.h"
+
+WaveformBaselineData::WaveformBaselineData() {
+}
+
+WaveformBaselineData::WaveformBaselineData(const WaveformBaselineData &other) {
+  m_mean = other.get_mean();
+  m_rms = other.get_rms();
+  m_channel = other.get_channel();
+  m_valid = other.is_valid();
+}
+
+WaveformBaselineData::WaveformBaselineData(double mean, double rms, int channel) {
+  m_mean = mean;
+  m_rms = rms;
+  m_channel = channel;
+  m_valid = true;
+}
+
+WaveformBaselineData::WaveformBaselineData(bool valid) {
+  m_mean = 0.;
+  m_rms = 0.;
+  m_channel = 0;
+  m_valid = valid;
+}
+
+// Assignment operator
+WaveformBaselineData& 
+WaveformBaselineData::operator=(const WaveformBaselineData& o) {
+  if (&o !=this) {
+    WaveformBaselineData::operator=(o);
+  }
+  return *this;
+}
+
+std::ostream
+&operator<<( std::ostream& out, const WaveformBaselineData &base ) {
+  out << "WaveformBaselineData: " << std::endl;
+  out << " Mean: " << base.get_mean() << ", RMS: " << base.get_rms() << std::endl;
+  return out;
+}
+
+
+
+
+
-- 
GitLab


From 1780f519cc2a3b7b6d71ac8a56f06549e1a50e0c Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 23 Feb 2021 23:42:19 -0800
Subject: [PATCH 23/47] Add reco data type and container

---
 .../ScintRecEvent/ScintRecEventDict.h         | 10 ++
 .../ScintRecEvent/ScintRecEvent/WaveformHit.h | 96 +++++++++++++++++++
 .../ScintRecEvent/WaveformHitContainer.h      | 24 +++++
 .../ScintRecEvent/ScintRecEvent/selection.xml |  7 ++
 .../ScintRecEvent/src/WaveformHit.cxx         | 20 ++++
 .../src/WaveformHitContainer.cxx              | 14 +++
 6 files changed, 171 insertions(+)
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
 create mode 100644 Scintillator/ScintRecEvent/src/WaveformHit.cxx
 create mode 100644 Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx

diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h b/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
new file mode 100644
index 000000000..653f7b730
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
@@ -0,0 +1,10 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTRECEVENT_SCINTRECEVENTDICT_H
+#define SCINTRECEVENT_SCINTRECEVENTDICT_H
+
+#include "ScintRecEvent/WaveformHitContainer.h"
+
+#endif
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
new file mode 100644
index 000000000..0785f7fd0
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// WaveformHit.h
+//   Header file for class WaveformHit
+///////////////////////////////////////////////////////////////////
+// Class to handle reconstructed peaks in waveform data
+///////////////////////////////////////////////////////////////////
+// Version 1.0   2/21/2021 Eric Torrence
+///////////////////////////////////////////////////////////////////
+#ifndef SCINTRECEVENT_WAVEFORMHIT_H
+#define SCINTRECEVENT_WAVEFORMHIT_H
+
+#include <iostream>
+
+#include "AthenaKernel/CLASS_DEF.h"
+
+/**
+ * @class WaveformHit
+ * Class containing reconstructed informtaion for one waveform hit
+ */
+  
+class WaveformHit {
+      
+ public:
+      
+  /** Default constructor */
+  WaveformHit();
+
+  /** Destructor */
+  virtual ~WaveformHit() = default;
+
+  // move assignment defaulted
+  WaveformHit & operator= (WaveformHit &&) = default;
+  //assignment defaulted
+  WaveformHit & operator= (const WaveformHit &) = default;
+  //copy c'tor defaulted
+  WaveformHit(const WaveformHit &) = default;
+
+  /** Clones */
+  virtual WaveformHit* clone() const ;       
+            
+  // Access functions
+  inline int channel() const { return m_channel; }
+
+  // Best results (from fit)
+  double localtime() const { return m_localtime; }
+  inline double amplitude() const { return m_amplitude; }
+  inline double integral() const { return m_integral; }
+
+  // Raw values from waveform data
+  inline double pulse_amplitude() const { return m_pulse_amplitude; }
+  inline double pulse_integral() const { return m_pulse_integral; }
+
+  // Bsaeline information
+  inline double baseline_mean() const { return m_baseline_mean; }
+  inline double baseline_rms()  const { return m_baseline_rms; }
+
+  private:
+
+  // Data members
+  unsigned int m_channel;
+
+  // Best values from fit
+  double m_localtime;
+  double m_amplitude;
+  double m_integral;
+
+  // Values from data
+  double m_pulse_amplitude;
+  double m_pulse_integral;
+
+  // Baseline information
+  double m_baseline_mean;
+  double m_baseline_rms;
+
+  // Fit informtaion
+};
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformHit &wfm);
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+inline WaveformHit* 
+WaveformHit::clone() const { 
+  return new WaveformHit(*this);  
+}
+
+CLASS_DEF( WaveformHit, 140632415, 1 )
+
+#endif // SCINTRECEVENT_WAVEFORMHIT_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
new file mode 100644
index 000000000..1304850a7
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
@@ -0,0 +1,24 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTRECEVENT_WAVEFORMHITCONTAINER_H
+#define SCINTRECEVENT_WAVEFORMHITCONTAINER_H
+
+#include "ScintRecEvent/WaveformHit.h"
+#include "AthContainers/DataVector.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+// Make this a class in case we need to add some functions
+class WaveformHitContainer : public DataVector<WaveformHit> {
+ public:
+  void print() const;
+};
+
+std::ostream 
+&operator<<(std::ostream &out, const WaveformHitContainer &container);
+
+CLASS_DEF(WaveformHitContainer, 1330197509, 1 )
+SG_BASE(WaveformHitContainer, DataVector<WaveformHit>);
+
+#endif // SCINTRECEVENT_WAVEFORMHITCONTAINER_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
new file mode 100644
index 000000000..378366a3a
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+  <class name="WaveformHitContainer" id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
+  <class name="DataVector<WaveformHit>" id="2943c109-26da-48df-b699-c9364d20896b" />
+  <class name="std::vector<WaveformHit*>" />
+  <class name="std::vector<const WaveformHit*>" />
+  <class name="WaveformHit" />
+</lcgdict>
diff --git a/Scintillator/ScintRecEvent/src/WaveformHit.cxx b/Scintillator/ScintRecEvent/src/WaveformHit.cxx
new file mode 100644
index 000000000..7df830fac
--- /dev/null
+++ b/Scintillator/ScintRecEvent/src/WaveformHit.cxx
@@ -0,0 +1,20 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintRecEvent/WaveformHit.h"
+
+// Default constructor
+WaveformHit::WaveformHit() {
+}
+
+std::ostream
+&operator<<( std::ostream& out, const WaveformHit &hit ) {
+  out << "WaveformHit - Time: " << hit.localtime() << ", Amplitude: " << hit.amplitude() << std::endl;
+  return out;
+}
+
+
+
+
+
diff --git a/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx b/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx
new file mode 100644
index 000000000..5e30f7a4e
--- /dev/null
+++ b/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx
@@ -0,0 +1,14 @@
+#include "ScintRecEvent/WaveformHitContainer.h"
+
+void
+WaveformHitContainer::print() const {
+  std::cout << "WaveformHit container with size=" << this->size() << std::endl;
+  for(auto wfm: *this) std::cout << *wfm;
+}
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformHitContainer& cont) {
+  out << "WaveformHit container with size=" << cont.size() << std::endl;
+  for(auto wfm: cont) out << *wfm;
+  return out;
+}
-- 
GitLab


From 35043ae199e11dffbda2611968e0d4d9096debb1 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 25 Feb 2021 00:24:09 -0800
Subject: [PATCH 24/47] Add baseline fit

---
 .../src/ScintWaveformDecoderTool.cxx          |  28 +++-
 .../ScintRawEvent/src/ScintWaveform.cxx       |  17 +-
 Scintillator/ScintRecAlgs/CMakeLists.txt      |   2 +-
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  |  52 ++++--
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    |  13 --
 Scintillator/ScintRecEvent/CMakeLists.txt     |  10 +-
 .../ScintRecEvent/WaveformBaselineData.h      |  39 ++---
 .../src/WaveformBaselineData.cxx              |  42 ++---
 Scintillator/ScintRecTools/CMakeLists.txt     |  12 +-
 .../IWaveformReconstructionTool.h             |   4 +-
 .../src/WaveformReconstructionTool.cxx        | 149 ++++++++++++++++++
 .../src/WaveformReconstructionTool.h          |  12 ++
 12 files changed, 286 insertions(+), 94 deletions(-)

diff --git a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
index de415ef29..55c9bd960 100644
--- a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
+++ b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
@@ -95,6 +95,7 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     ATH_MSG_DEBUG("Fragment:\n" << *frag);
 
     digitizer = new DigitizerDataFragment(frag->payload<const uint32_t*>(), frag->payload_size()); 
+
     break;
   }
 
@@ -103,7 +104,12 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     return StatusCode::FAILURE;
   }
 
-  // ATH_MSG_DEBUG("Digitizer Fragment:\n" << *digitizer);
+  // Check validity here
+  if (!digitizer->valid()) {
+    ATH_MSG_WARNING("Found invalid digitizer fragment:\n" << *digitizer);
+  } else {
+    ATH_MSG_DEBUG("Found valid digitizer fragment");
+  }
 
   std::vector<unsigned int>* channelList;
 
@@ -127,13 +133,18 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
   for (unsigned int channel: *channelList) {
     ATH_MSG_DEBUG("Converting channel "+std::to_string(channel)+" for "+key);
 
+    // Check if this has data
+    if (!digitizer->channel_has_data(channel)) {
+      ATH_MSG_INFO("Channel " << channel << " has no data - skipping!");
+      continue;
+    } 
+
     ScintWaveform* wfm = new ScintWaveform();
 
-    // Finally, set values in Waveform object from Digitizer fragment
     try {
       wfm->setWaveform( channel, digitizer->channel_adc_counts( channel ) );
     } catch ( DigitizerDataException& e ) {
-      ATH_MSG_INFO("ScintWaveformDecoderTool:\n"
+      ATH_MSG_WARNING("ScintWaveformDecoderTool:\n"
 		   <<e.what()
 		   << "\nChannel "
 		   << channel
@@ -151,12 +162,19 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     }
 
     container->push_back(wfm);    
+
+    // Sanity check
+    if (wfm->adc_counts().size() != wfm->n_samples()) {
+      ATH_MSG_WARNING("Created waveform channel" << channel << "with length " << wfm->adc_counts().size() << " but header reports n_samples = " << wfm->n_samples() << "!");
+      ATH_MSG_WARNING(*wfm);
+    }
+
   }
 
   // Don't spring a leak
   delete digitizer;
 
-ATH_MSG_DEBUG( "ScintWaveformDecoderTool created container " << key 
-<< " with size=" << container->size());
+  ATH_MSG_DEBUG( "ScintWaveformDecoderTool created container " << key 
+		 << " with size=" << container->size());
   return StatusCode::SUCCESS; 
 }
diff --git a/Scintillator/ScintRawEvent/src/ScintWaveform.cxx b/Scintillator/ScintRawEvent/src/ScintWaveform.cxx
index b525f2e0b..bc9f5eb91 100644
--- a/Scintillator/ScintRawEvent/src/ScintWaveform.cxx
+++ b/Scintillator/ScintRawEvent/src/ScintWaveform.cxx
@@ -52,14 +52,15 @@ ScintWaveform::setWaveform(unsigned int channel, const std::vector<uint16_t> wav
 
 std::ostream 
 &operator<<(std::ostream &out, const ScintWaveform &wfm) {
-  out << "Waveform data:" << std::endl
-  << std::setw(30) << " board_id:             "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.board_id()<<std::setfill(' ')<<std::endl
-  << std::setw(30) << " board_fail_flag:      "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.board_fail_flag()<<std::setfill(' ')<<std::endl
-  << std::setw(30) << " board_trig_options:   "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.pattern_trig_options()<<std::setfill(' ')<<std::endl
-  << std::setw(30) << " channel_mask:         "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.channel_mask()<<std::setfill(' ')<<std::endl
-  << std::setw(30) << " event_counter:        "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.event_counter()<<std::setfill(' ')<<std::endl
-  << std::setw(30) << " trigger_time_tag:     "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.trigger_time_tag()<<std::setfill(' ')<<std::endl
-      << std::setw(30) << " n_samples:            "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.n_samples()<<std::setfill(' ')<<std::endl;
+  out << "Waveform data channel:" << std::dec << wfm.channel() << std::endl;
+  out << std::setw(30) << " board_id:             "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.board_id()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " board_fail_flag:      "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.board_fail_flag()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " board_trig_options:   "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.pattern_trig_options()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " channel_mask:         "<<std::setfill(' ')<<std::setw(32)<<std::hex<<wfm.channel_mask()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " event_counter:        "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.event_counter()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " trigger_time_tag:     "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.trigger_time_tag()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " n_samples:            "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.n_samples()<<std::setfill(' ')<<std::endl;
+  out << std::setw(30) << " adc_counts.size():    "<<std::setfill(' ')<<std::setw(32)<<std::dec<<wfm.adc_counts().size()<<std::setfill(' ')<<std::endl;
 
   return out;
 }
diff --git a/Scintillator/ScintRecAlgs/CMakeLists.txt b/Scintillator/ScintRecAlgs/CMakeLists.txt
index b89582e2d..e4f81b4bb 100644
--- a/Scintillator/ScintRecAlgs/CMakeLists.txt
+++ b/Scintillator/ScintRecAlgs/CMakeLists.txt
@@ -9,7 +9,7 @@ atlas_subdir( ScintRecAlgs )
 atlas_add_component( ScintRecAlgs
                      src/*.cxx src/*.h
                      src/components/*.cxx
-                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecToolsLib) #ScintRecEvent )
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecEvent ScintRecToolsLib )
 
 #atlas_install_python_modules( python/*.py )
 
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index efd01a2cc..88ef5be6b 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -1,4 +1,5 @@
 #include "ScintWaveformRecAlg.h"
+#include "ScintRecEvent/WaveformBaselineData.h"
 
 ScintWaveformRecAlg::ScintWaveformRecAlg(const std::string& name, 
 					 ISvcLocator* pSvcLocator)
@@ -13,13 +14,7 @@ ScintWaveformRecAlg::initialize() {
   // Initalize tools
   ATH_CHECK( m_recoTool.retrieve() );
 
-  // Make sure we have something to work with
-  ATH_CHECK( m_inputWaveformKey.length() != 0);
-  ATH_MSG_INFO(name() << "Reading from " << m_inputWaveformKey );
-  ATH_MSG_INFO(name() << "Writing to   " << m_outputWaveformKey );
-
   // Set key to read waveform from
-  m_waveformContainer = m_inputWaveformKey;
   ATH_CHECK( m_waveformContainer.initialize() );
 
   return StatusCode::SUCCESS;
@@ -34,14 +29,53 @@ ScintWaveformRecAlg::finalize() {
 
 StatusCode 
 ScintWaveformRecAlg::execute(const EventContext& ctx) const {
-  ATH_MSG_INFO(name() << "::execute()");
+  ATH_MSG_INFO("Executing");
 
   ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() 
 		<< " Event: " << ctx.eventID().event_number());
 
+  // Find the waveform container
   SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainer, ctx);
-  ATH_MSG_INFO("Found ReadHandle for Waveforms");
-  ATH_MSG_INFO(*waveformHandle);
+
+  ATH_CHECK( waveformHandle.isValid() );
+  ATH_MSG_DEBUG("Found ReadHandle for Waveforms");
+
+  if (waveformHandle->size() == 0) {
+    ATH_MSG_INFO("Waveform container found with zero length!");
+    return StatusCode::SUCCESS;
+  }
+
+  // Reconstruct each waveform
+  for( const auto& wave : *waveformHandle) {
+
+    ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
+
+    // Make some sanity checks before going further
+    if (wave->adc_counts().size() == 0) {
+      ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
+		       << " with size " << wave->adc_counts().size() << "!");
+      // Create dummy hit here, or just skip?
+      continue;
+    }
+    
+    if (wave->adc_counts().size() != wave->n_samples()) {
+      ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
+		       << " with size " << wave->adc_counts().size() 
+		       << " not equal to number of samples " << wave->n_samples());
+      continue;
+    }
+
+    // Find the baseline (return as an object so we can pass it downstream)
+    WaveformBaselineData* baseline = m_recoTool->findBaseline(*wave);
+
+    // Write something out
+    ATH_MSG_INFO( "Channel " << wave->channel() << " baseline: " << *baseline );
+
+    // This is transient, so delete it here
+    delete baseline;
+  }
+  
+
 
   return StatusCode::SUCCESS;
 }
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
index 16e071bcb..19b5ad2d7 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -61,19 +61,6 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
   //  {this, "WaveformContainerKey", ""};
   //@}
 
-
-  /** @brief Key for the DetectorStore (jobOptions) 
-   * The input waveform will be read from this key.
-   */
-  StringProperty m_inputWaveformKey
-  { this, "inputKey", ""};
-
-  /** @brief Key for the DetectorStore (jobOptions) 
-   * The output data will be saved to this key.
-   */
-  StringProperty m_outputWaveformKey
-  { this, "outputKey", ""};
-
 };
 
 #endif // SCINTRECALGS_SCINTWAVEFORMRECALG_H
diff --git a/Scintillator/ScintRecEvent/CMakeLists.txt b/Scintillator/ScintRecEvent/CMakeLists.txt
index b560c284a..cddd115ed 100644
--- a/Scintillator/ScintRecEvent/CMakeLists.txt
+++ b/Scintillator/ScintRecEvent/CMakeLists.txt
@@ -6,10 +6,18 @@
 atlas_subdir( ScintRecEvent )
 
 # External dependencies:
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
 
 # Component(s) in the package:
 atlas_add_library( ScintRecEvent
                    src/*.cxx src/*.h
                    PUBLIC_HEADERS ScintRecEvent
-                   PRIVATE_LINK_LIBRARIES ScintRawEvent)
+		   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ScintRawEvent)
+
+atlas_add_dictionary( ScintRecEventDict
+		      ScintRecEvent/ScintRecEventDict.h
+		      ScintRecEvent/selection.xml
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} AthAllocators CxxUtils StoreGateLib ScintIdentifier ScintRecEvent )
 
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
index 5f7a25576..ef631805b 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
@@ -27,39 +27,34 @@ class WaveformBaselineData {
   /** Default constructor */
   WaveformBaselineData();
 
-  /**
-   * @name Parametrised constructors
-   */
-  //@{
+  // Set status directly
   WaveformBaselineData(bool valid);
-  WaveformBaselineData(double mean, double rms, int channel);    
-  //@}
 
-  /** Copy Constructor */
-  WaveformBaselineData(const WaveformBaselineData &) ;
+  // move assignment defaulted
+  WaveformBaselineData & operator= (WaveformBaselineData &&) = default;
+  //assignment defaulted
+  WaveformBaselineData & operator= (const WaveformBaselineData &) = default;
+  //copy c'tor defaulted
+  WaveformBaselineData(const WaveformBaselineData &) = default;
 
   /** Destructor */
   virtual ~WaveformBaselineData() = default;
 
-  /** Overloading Assignment Operator */
-  WaveformBaselineData &operator=(const WaveformBaselineData &);
-
   /** Clones */
   virtual WaveformBaselineData* clone() const ;       
             
-  // Access functions
-  inline double get_mean() const { return m_mean; }
-  inline double get_rms() const { return m_rms; }
-  inline int get_channel() const { return m_channel; }
-  inline double is_valid() const { return m_valid; }
+  // Data members
+  int channel;  // Channel number
+  bool valid;   // Overall valididty flag
 
-  private:
+  double mean;  // Best value for mean baseline
+  double rms;   // Best value for baseline RMS
+  int fit_status; // Return value from fit
+  double peak;  // Amplitude of baseline fit
+  double chi2n; // Reduced chi2/Ndof from gauss fit
 
-  // Data members
-  double m_mean;
-  double m_rms;
-  int m_channel;
-  bool m_valid;
+ private:
+  void clear();
 };
 
 std::ostream
diff --git a/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx b/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
index 7bc52ab94..5a48f1e9f 100644
--- a/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
+++ b/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
@@ -5,42 +5,28 @@
 #include "ScintRecEvent/WaveformBaselineData.h"
 
 WaveformBaselineData::WaveformBaselineData() {
+  clear();
 }
 
-WaveformBaselineData::WaveformBaselineData(const WaveformBaselineData &other) {
-  m_mean = other.get_mean();
-  m_rms = other.get_rms();
-  m_channel = other.get_channel();
-  m_valid = other.is_valid();
+WaveformBaselineData::WaveformBaselineData(bool isvalid) {
+  clear();
+  valid = isvalid;
 }
 
-WaveformBaselineData::WaveformBaselineData(double mean, double rms, int channel) {
-  m_mean = mean;
-  m_rms = rms;
-  m_channel = channel;
-  m_valid = true;
-}
-
-WaveformBaselineData::WaveformBaselineData(bool valid) {
-  m_mean = 0.;
-  m_rms = 0.;
-  m_channel = 0;
-  m_valid = valid;
-}
-
-// Assignment operator
-WaveformBaselineData& 
-WaveformBaselineData::operator=(const WaveformBaselineData& o) {
-  if (&o !=this) {
-    WaveformBaselineData::operator=(o);
-  }
-  return *this;
+void
+WaveformBaselineData::clear() {
+  channel = -1;
+  valid = false;
+  mean = 0.;
+  rms = 0.;
+  fit_status = -1;
+  peak = 0.;
+  chi2n = 0.;
 }
 
 std::ostream
 &operator<<( std::ostream& out, const WaveformBaselineData &base ) {
-  out << "WaveformBaselineData: " << std::endl;
-  out << " Mean: " << base.get_mean() << ", RMS: " << base.get_rms() << std::endl;
+  out << "WaveformBaselineData - Mean: " << base.mean << ", RMS: " << base.rms << std::endl;
   return out;
 }
 
diff --git a/Scintillator/ScintRecTools/CMakeLists.txt b/Scintillator/ScintRecTools/CMakeLists.txt
index 92d9c2594..7befc0e44 100644
--- a/Scintillator/ScintRecTools/CMakeLists.txt
+++ b/Scintillator/ScintRecTools/CMakeLists.txt
@@ -6,19 +6,19 @@
 atlas_subdir( ScintRecTools )
 
 # External dependencies:
-# find_package( Eigen )
+find_package( ROOT )
 
 # Component(s) in the package:
 atlas_add_library( ScintRecToolsLib
                    ScintRecTools/*.h src/*.cxx src/*.h
                    PUBLIC_HEADERS ScintRecTools
-                   # INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}
-                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent # ScintRecEvent
-                   # PRIVATE_LINK_LIBRARIES GaudiKernel TrackerIdentifier TrackerReadoutGeometry TrackerSpacePoint 
+                   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent ScintRecEvent
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES}
 		   )
 
 atlas_add_component( ScintRecTools
 		     src/components/*.cxx 
-		     # INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}
-                     LINK_LIBRARIES AthenaBaseComps GaudiKernel ScintRecToolsLib )
+		     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel ScintRecToolsLib )
 
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index a392443f7..96413c7f5 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -15,7 +15,7 @@
 // Base class
 #include "GaudiKernel/IAlgTool.h"
 #include "ScintRawEvent/ScintWaveform.h"
-// #include "ScintRecEvent/WaveformHitCollection.h"
+#include "ScintRecEvent/WaveformBaselineData.h"
 #include "GaudiKernel/ToolHandle.h"
 
 ///Interface for Waveform reco algorithms
@@ -28,6 +28,8 @@ class IWaveformReconstructionTool : virtual public IAlgTool
 
   virtual ~IWaveformReconstructionTool() = default;
 
+  virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const = 0;
+
   /** Reconstruct a single waveform into a list of hits
    * @param[in] @c RDOs the raw data objects
    */
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 3782bcc89..f4c281b5e 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -10,6 +10,11 @@
 
 #include "WaveformReconstructionTool.h"
 
+#include "TH1F.h"
+#include "TF1.h"
+#include "TFitResult.h"
+#include "TFitResultPtr.h"
+
 // Constructor
 WaveformReconstructionTool::WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
   base_class(type, name, parent)
@@ -21,6 +26,11 @@ StatusCode
 WaveformReconstructionTool::initialize() {
   ATH_MSG_INFO( name() << "::initalize()" );
 
+  if (m_useSimpleBaseline.value()) {
+    ATH_MSG_INFO("Will use simple baseline estimation");
+  } else {
+    ATH_MSG_INFO("Will use fit to determine baseline");
+  }
   return StatusCode::SUCCESS;
 }
 
@@ -30,3 +40,142 @@ WaveformHitCollection*
 WaveformReconstructionTool::reconstruct(const ScintWaveform& wave) const {
 }
 */
+
+WaveformBaselineData*
+WaveformReconstructionTool::findBaseline(const ScintWaveform& wave) const {
+
+  if (m_useSimpleBaseline.value())
+    return this->findSimpleBaseline(wave);
+
+  else
+    return this->findAdvancedBaseline(wave);
+}
+
+WaveformBaselineData*
+WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& wave) const {
+
+  ATH_MSG_DEBUG( "findSimpleBaseline called" );
+  ATH_MSG_DEBUG( wave );
+
+  // Calling algorithm checks for proper data
+  // Here we just check algorithm-specific issues
+  if (int(wave.n_samples()) < m_samplesForBaselineAverage.value()) {
+    ATH_MSG_WARNING( "Found waveform with " << wave.n_samples() << " samples, not enough to find baseline!" );
+    return new WaveformBaselineData(false);
+  }
+
+  const std::vector<unsigned int>& counts = wave.adc_counts();
+
+  double sumx = 0.;
+  double sumx2 = 0.;
+
+  // Look at first n values in the waveform
+  unsigned int nvalues = m_samplesForBaselineAverage.value();
+
+  for (unsigned int i=0; i< nvalues; i++) {
+    sumx  += counts[i];
+    sumx2 += (counts[i] * counts[i]);
+  }
+  double mean = sumx / nvalues;
+  double mean2 = sumx2 / nvalues;
+
+  double rms = std::sqrt(mean2 - mean*mean);
+
+  WaveformBaselineData* base = new WaveformBaselineData(true);
+  base->channel = wave.channel();
+  base->mean = mean;
+  base->rms = rms;
+  return base;
+}
+
+WaveformBaselineData*
+WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) const {
+
+  // First histogram to find most likely value
+  // Turn these into configurables once this works
+  int nbins = 320;
+  double xlo = 0.;
+  double xhi = 16000.;
+
+  TH1F h1("", "", nbins, xlo, xhi);
+
+  // Fill this histogram with the waveform
+  for (auto value : wave.adc_counts()) {
+    //ATH_MSG_DEBUG( "Found value " << value );
+    h1.Fill(value);
+  }
+
+  // Find max bin
+  int maxbin = h1.GetMaximumBin();
+  double maxbinval = h1.GetXaxis()->GetBinCenter(maxbin);
+  ATH_MSG_DEBUG( "Found max bin at " << maxbinval << " counts");
+
+  // Fill second histogram with integer resolution around the peak
+  nbins = 200;
+  xlo = int(maxbinval - 100.)-0.5;
+  xhi = xlo + nbins;
+  ATH_MSG_DEBUG( "Filling 2nd histogram from " << xlo << " to " << xhi);
+
+  TH1F h2("", "", nbins, xlo, xhi);
+  for (auto value : wave.adc_counts()) {
+    h2.Fill(value);
+  }
+
+  // Start with full histogram range
+  double mean = h2.GetMean();
+  double rms = h2.GetRMS();
+  double peak = h2.GetBinContent(h2.GetMaximumBin());
+
+  ATH_MSG_DEBUG( "Initial Mean: " << mean << " RMS: " << rms << " Peak: " << peak );
+
+  // Restrict range to +/- 2 sigma of mean
+  double window = 2.;  // Window range in sigma
+  h2.GetXaxis()->SetRangeUser(mean-window*rms, mean+window*rms);
+  mean = h2.GetMean();
+  rms = h2.GetRMS();
+  peak = h2.GetBinContent(h2.GetMaximumBin());
+
+  ATH_MSG_DEBUG( "2 Sigma Mean: " << mean << " RMS: " << rms << " Peak: " << peak);
+
+  // Finally, fit a Gaussian to the 2 sigma range
+  double fitlo = mean-window*rms;
+  double fithi = mean+window*rms;
+
+  // Define fit function and preset range
+  TF1 fitfunc("BaseFit", "gaus", fitlo, fithi);
+  fitfunc.SetParameters(peak, mean, rms);
+
+  // Fit Options:
+  // L - Likelihood fit
+  // Q - Quiet mode (V for verbose)
+  // N - Don't draw or store graphics
+  // S - Return fit results
+  // E - Better error estimation
+  // M - Use TMinuit IMPROVE to find a better minimum
+  // R - Use function range  
+  TFitResultPtr fit = h2.Fit(&fitfunc, "LQNSR", "");
+
+  int fitStatus = fit;
+  double chi2 = fit->Chi2();
+  unsigned int ndf = fit->Ndf();
+  if (ndf == 0) ndf = 1;
+
+  if (!fit->IsValid()) {
+    ATH_MSG_WARNING( " Baseline fit failed! ");
+  } else {
+    // Improve estimation with fit results
+    peak = fit->Parameter(0);
+    mean = fit->Parameter(1);
+    rms  = fit->Parameter(2);
+    ATH_MSG_DEBUG( "G Fit   Mean: " << mean << " RMS: " << rms << " Peak: " << peak << " Chi2/N: " << chi2/ndf);  
+  }
+
+  WaveformBaselineData* base = new WaveformBaselineData(true);
+  base->channel = wave.channel();
+  base->mean = mean;
+  base->rms = rms;
+  base->fit_status = fitStatus; 
+  base->peak = peak;
+  base->chi2n = chi2/ndf;
+  return base;
+}
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 84dcb2d48..3289c5ab0 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -12,6 +12,7 @@
 //Athena
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "ScintRecTools/IWaveformReconstructionTool.h"
+#include "ScintRecEvent/WaveformBaselineData.h"
 
 //Gaudi
 #include "GaudiKernel/ToolHandle.h"
@@ -30,11 +31,22 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
   /// Retrieve the necessary services in initialize
   StatusCode initialize();
 
+  /// Find baseline (return pointer to new baseline object)
+  virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const;
+
   /// Reconstruct hits from waveform
   //virtual WaveformHitCollection* reconstruct(const ScintWaveform& wave) const;
 
  private:
 
+  // Parameters
+  BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", true};
+  IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40};
+
+  // Baseline algorithms
+  WaveformBaselineData* findSimpleBaseline(const ScintWaveform& wave) const;
+  WaveformBaselineData* findAdvancedBaseline(const ScintWaveform& wave) const;
+
 };
 
 #endif // SCINTRECTOOLS_WAVEFORMRECONSTRUCTIONTOOL_H
-- 
GitLab


From 4437df8f48ad531de02d2fcf9a1471838c56e593 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 26 Feb 2021 23:51:01 -0800
Subject: [PATCH 25/47] Add CB fit to waveform tool

---
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  |   3 +
 .../IWaveformReconstructionTool.h             |  16 +-
 .../src/WaveformReconstructionTool.cxx        | 181 +++++++++++++++++-
 .../src/WaveformReconstructionTool.h          |  22 ++-
 4 files changed, 202 insertions(+), 20 deletions(-)

diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index 88ef5be6b..7a463d030 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -71,6 +71,9 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
     // Write something out
     ATH_MSG_INFO( "Channel " << wave->channel() << " baseline: " << *baseline );
 
+    // Reconstruct the hits
+    WaveformHitContainer* container = m_recoTool->reconstruct(*wave, *baseline);
+
     // This is transient, so delete it here
     delete baseline;
   }
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index 96413c7f5..df49ecceb 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -14,10 +14,14 @@
 
 // Base class
 #include "GaudiKernel/IAlgTool.h"
-#include "ScintRawEvent/ScintWaveform.h"
-#include "ScintRecEvent/WaveformBaselineData.h"
+//#include "ScintRawEvent/ScintWaveform.h"
+//#include "ScintRecEvent/WaveformBaselineData.h"
 #include "GaudiKernel/ToolHandle.h"
 
+class ScintWaveform;
+class WaveformBaselineData;
+class WaveformHitContainer;
+
 ///Interface for Waveform reco algorithms
 class IWaveformReconstructionTool : virtual public IAlgTool 
 {
@@ -28,12 +32,10 @@ class IWaveformReconstructionTool : virtual public IAlgTool
 
   virtual ~IWaveformReconstructionTool() = default;
 
+  // Find the baseline for a complete raw waveform
   virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const = 0;
-
-  /** Reconstruct a single waveform into a list of hits
-   * @param[in] @c RDOs the raw data objects
-   */
-  //virtual WaveformHitCollection* reconstruct(const ScintWaveform& wave) const = 0;
+  // Reconstruct all peaks in a raw waveform
+  virtual WaveformHitContainer* reconstruct(const ScintWaveform& wave, const WaveformBaselineData& baseline) const = 0;
 
 };
 
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index f4c281b5e..1796f6f19 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -14,6 +14,9 @@
 #include "TF1.h"
 #include "TFitResult.h"
 #include "TFitResultPtr.h"
+#include "TGraph.h"
+
+#include <vector>
 
 // Constructor
 WaveformReconstructionTool::WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
@@ -35,11 +38,167 @@ WaveformReconstructionTool::initialize() {
 }
 
 // Reconstruction step
-/*
-WaveformHitCollection*
-WaveformReconstructionTool::reconstruct(const ScintWaveform& wave) const {
+WaveformHitContainer*
+WaveformReconstructionTool::reconstruct(const ScintWaveform& rawWaveform, const WaveformBaselineData& baseline) const {
+
+  ATH_MSG_DEBUG(" reconstruct called ");
+
+  // Start out with empty WaveformHitContainer
+  WaveformHitContainer* container = new WaveformHitContainer();
+
+  // Create baseline-subtracted data array
+  std::vector<float> wave(rawWaveform.adc_counts().begin(), rawWaveform.adc_counts().end());
+  for (auto& element : wave)
+    element = baseline.mean - element;
+
+  // Define the fit functions here outside the loop
+  TF1 gfunc("gfunc", "gaus");
+  TF1 cbfunc("cbfunc", "crystalball");
+
+  // Now we iteratively find peaks and fit
+  while(true) {
+
+    // Find max value location in array
+    unsigned int imax = std::max_element(wave.begin(), wave.end()) - wave.begin();
+    float maxval = wave[imax];
+    ATH_MSG_DEBUG( "Found max value " << maxval << " at position " << imax );
+
+    // Check if this is over threshold
+    float pulseThreshold = 10.; // In baseline sigma
+    if (maxval < pulseThreshold*baseline.rms) {
+      ATH_MSG_DEBUG("Failed threshold");
+      break;
+    }
+
+    // Make a window around this peak, values are in bins, so units of 2ns
+    // Ensure our window is within the vector range
+    int lo_edge = (imax - 10) > 0 ? (imax - 10) : 0; 
+    int hi_edge = (imax + 40) < wave.size() ? (imax + 40) : wave.size();
+
+    ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge);
+    std::vector<float> window(wave.begin()+lo_edge, wave.begin()+hi_edge);
+
+    // Array of matching time values (in ns), find mean and rms of these data
+    std::vector<float> tvec(50, 0.);
+
+    double tot = 0.;
+    double sum = 0.;
+    double sum2 = 0.;
+    for (unsigned int i=0; i<tvec.size(); i++) {
+      tvec[i] = 2.*(lo_edge+i);
+      tot += window[i];
+      sum += tvec[i] * window[i];
+      sum2 += tvec[i] * tvec[i] * window[i];
+    }
+
+    // Initial parameters from window
+    double gmean = sum/tot;
+    double grms = std::sqrt(sum2/tot - gmean*gmean);
+    double gpeak = maxval;
+    ATH_MSG_DEBUG( "Initial Mean: " << gmean << " RMS: " << grms << " Peak: " << gpeak);  
+
+    // Start by creating a TGraph and fitting this with a Gaussian
+    // Must pass arrays to TGraph, use pointer to first vector element
+    TGraph tg(tvec.size(), &tvec[0], &window[0]);
+
+    // Define fit function and preset range
+    gfunc.SetParameters(gpeak, gmean, grms);
+    gfunc.SetParError(0, std::sqrt(gpeak));
+    gfunc.SetParError(1, grms);
+    gfunc.SetParError(2, 5.);
+    TFitResultPtr gfit = tg.Fit(&gfunc, "QNS", "");
+
+    //int gFitStatus = gfit;
+
+    if (!gfit->IsValid()) {
+      ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
+      break;
+    } else {
+      // Improve estimation with fit results
+      gpeak = gfit->Parameter(0);
+      gmean = gfit->Parameter(1);
+      grms  = gfit->Parameter(2);
+      ATH_MSG_DEBUG("G Fit   Mean: " << gmean << " RMS: " << grms << " Peak: " << gpeak);
+    }
+
+    // Check for overflow
+    bool overflow = (rawWaveform.adc_counts()[imax] == 0);
+
+    if (overflow) {
+      ATH_MSG_INFO("Found waveform overflow");
+
+      // Want to remove overflowing points so fit works better
+      // Find first and last overflow here
+      // max_element will find the first overflow (imax), find the last
+      unsigned int iover;
+      for (iover = imax; iover < rawWaveform.adc_counts().size(); iover++) {
+	if (rawWaveform.adc_counts()[iover] != 0) break;
+      }
+
+      // Find the limits in the windowed waveform
+      unsigned int cut_lo = imax - lo_edge;
+      unsigned int cut_hi = iover - lo_edge;
+      if (cut_hi > window.size()) cut_hi = window.size();  // Don't cut beyond window
+
+      // Remove these entries
+      ATH_MSG_DEBUG("Removing entries from " << cut_lo << " to " << cut_hi);
+      tvec.erase(tvec.begin()+cut_lo, tvec.begin()+cut_hi);
+      window.erase(window.begin()+cut_lo, window.begin()+cut_hi);
+      ATH_MSG_DEBUG("Vector length now " << tvec.size());
+
+    }
+
+    // Now do crystal ball fit
+    double cbpeak = gpeak;
+    double cbmean = gmean;
+    double cbrms = grms;
+    if (cbrms < 0.) cbrms = abs(cbrms);
+    if (cbrms > 20.) cbrms = 5.;
+
+    double alpha = -0.25; // Negative puts tail on RH side
+    double nval = 3.;
+    // Preset everything to improve results
+    cbfunc.SetParameter(0, cbpeak); // Peak height
+    cbfunc.SetParError(0, std::sqrt(cbpeak));
+    cbfunc.SetParameter(1, cbmean); // Mean
+    cbfunc.SetParError(1, cbrms);
+    cbfunc.SetParameter(2, cbrms);  // Width
+    cbfunc.SetParError(2, 5.);
+    cbfunc.SetParLimits(2, 0., 20.);
+    cbfunc.SetParameter(3, alpha); // Tail parameter (negative for high-side tail)
+    cbfunc.SetParError(3, 0.05);
+    cbfunc.SetParLimits(3, -10., 0.);
+    cbfunc.SetParameter(4, nval);  // Tail power
+    cbfunc.SetParError(4, 1.);
+    cbfunc.SetParLimits(4, 0., 1.E3);
+    //cbfunc.SetParameters(peak, mean, rms, alpha, nval);
+
+    TFitResultPtr cbfit = tg.Fit(&cbfunc, "QNS", "");
+
+    double chi2 = cbfit->Chi2();
+    unsigned int ndf = cbfit->Ndf();
+    if (ndf == 0) ndf = 1;
+    double chi2ndf = chi2/ndf;
+
+    if (!cbfit->IsValid()) {
+      ATH_MSG_WARNING(" CrystalBall waveform fit failed!");
+      break;
+    } else {
+      // Improve estimation with fit results
+      cbpeak  = cbfit->Parameter(0);
+      cbmean  = cbfit->Parameter(1);
+      cbrms   = cbfit->Parameter(2);
+      alpha = cbfit->Parameter(3);
+      nval  = cbfit->Parameter(4);
+      ATH_MSG_DEBUG("CB Fit  Mean: " << cbmean << " RMS: " << cbrms << " Peak: " << cbpeak << " N: " << nval << " Alpha: " << alpha << " Chi2/Ndf: " << chi2ndf);
+    }
+  
+    break;
+  }
+
+  return container;
 }
-*/
+
 
 WaveformBaselineData*
 WaveformReconstructionTool::findBaseline(const ScintWaveform& wave) const {
@@ -55,7 +214,7 @@ WaveformBaselineData*
 WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& wave) const {
 
   ATH_MSG_DEBUG( "findSimpleBaseline called" );
-  ATH_MSG_DEBUG( wave );
+  //ATH_MSG_DEBUG( wave );
 
   // Calling algorithm checks for proper data
   // Here we just check algorithm-specific issues
@@ -91,11 +250,13 @@ WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& wave) const
 WaveformBaselineData*
 WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) const {
 
+  ATH_MSG_DEBUG( "findAdvancedBaseline called" );
+
   // First histogram to find most likely value
   // Turn these into configurables once this works
-  int nbins = 320;
+  int nbins = m_baselineRangeBins;
   double xlo = 0.;
-  double xhi = 16000.;
+  double xhi = m_baselineRange;
 
   TH1F h1("", "", nbins, xlo, xhi);
 
@@ -111,8 +272,8 @@ WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) cons
   ATH_MSG_DEBUG( "Found max bin at " << maxbinval << " counts");
 
   // Fill second histogram with integer resolution around the peak
-  nbins = 200;
-  xlo = int(maxbinval - 100.)-0.5;
+  nbins = m_baselineFitRange;
+  xlo = int(maxbinval - nbins/2)-0.5;
   xhi = xlo + nbins;
   ATH_MSG_DEBUG( "Filling 2nd histogram from " << xlo << " to " << xhi);
 
@@ -129,7 +290,7 @@ WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) cons
   ATH_MSG_DEBUG( "Initial Mean: " << mean << " RMS: " << rms << " Peak: " << peak );
 
   // Restrict range to +/- 2 sigma of mean
-  double window = 2.;  // Window range in sigma
+  double window = m_baselineFitWindow;  // Window range in sigma
   h2.GetXaxis()->SetRangeUser(mean-window*rms, mean+window*rms);
   mean = h2.GetMean();
   rms = h2.GetRMS();
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 3289c5ab0..2448ecb6f 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -12,7 +12,10 @@
 //Athena
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "ScintRecTools/IWaveformReconstructionTool.h"
+
+#include "ScintRawEvent/ScintWaveform.h"
 #include "ScintRecEvent/WaveformBaselineData.h"
+#include "ScintRecEvent/WaveformHitContainer.h"
 
 //Gaudi
 #include "GaudiKernel/ToolHandle.h"
@@ -35,14 +38,27 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
   virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const;
 
   /// Reconstruct hits from waveform
-  //virtual WaveformHitCollection* reconstruct(const ScintWaveform& wave) const;
+  virtual WaveformHitContainer* reconstruct(const ScintWaveform& wave, const WaveformBaselineData& baseline) const;
 
  private:
 
-  // Parameters
-  BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", true};
+  // Baseline Estimation Parameters
+  BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", false};
   IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40};
 
+  //
+  // Parameters of initial histogram to find baseline max
+  // Range and bins to use, ratio should be an integer (bin width)
+  IntegerProperty m_baselineRange{this, "BaselineRange", 16000};
+  IntegerProperty m_baselineRangeBins{this, "BaselineRangeBins", 320};
+
+  // 
+  // Parameters for the Gaussian fit to the baseline peak (in counts)
+  // Range is total range to use to find truncated mean and width
+  IntegerProperty m_baselineFitRange{this, "BaselineFitRange", 200};
+  // Fit window is value (in sigma) of trucated width to use in final fit
+  FloatProperty m_baselineFitWindow{this, "BaselineFitWindow", 2.};
+
   // Baseline algorithms
   WaveformBaselineData* findSimpleBaseline(const ScintWaveform& wave) const;
   WaveformBaselineData* findAdvancedBaseline(const ScintWaveform& wave) const;
-- 
GitLab


From 19bb7f400d9e1a996c926131b33d70008f85fce8 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 5 Mar 2021 14:24:28 -0800
Subject: [PATCH 26/47] Functionally complete version of raw waveform
 reconstruction

---
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  |  15 +-
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    |   9 +-
 .../ScintRecEvent/ScintRecEventDict.h         |   2 +-
 .../ScintRecEvent/ScintRecEvent/WaveformHit.h |  61 ++-
 .../ScintRecEvent/WaveformHitCollection.h     |  27 +
 .../ScintRecEvent/WaveformHitContainer.h      |  24 -
 .../ScintRecEvent/ScintRecEvent/selection.xml |   2 +-
 .../ScintRecEvent/src/WaveformHit.cxx         |  31 ++
 .../src/WaveformHitCollection.cxx             |  14 +
 .../src/WaveformHitContainer.cxx              |  14 -
 .../IWaveformReconstructionTool.h             |   8 +-
 .../src/WaveformBaselineData.cxx              |   2 +-
 .../src}/WaveformBaselineData.h               |  11 +-
 .../ScintRecTools/src/WaveformFitResult.cxx   |  35 ++
 .../ScintRecTools/src/WaveformFitResult.h     |  73 +++
 .../src/WaveformReconstructionTool.cxx        | 501 ++++++++++++------
 .../src/WaveformReconstructionTool.h          |  69 ++-
 17 files changed, 645 insertions(+), 253 deletions(-)
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
 create mode 100644 Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
 delete mode 100644 Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx
 rename Scintillator/{ScintRecEvent => ScintRecTools}/src/WaveformBaselineData.cxx (92%)
 rename Scintillator/{ScintRecEvent/ScintRecEvent => ScintRecTools/src}/WaveformBaselineData.h (92%)
 create mode 100644 Scintillator/ScintRecTools/src/WaveformFitResult.cxx
 create mode 100644 Scintillator/ScintRecTools/src/WaveformFitResult.h

diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index 7a463d030..7dfa8a368 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -1,5 +1,4 @@
 #include "ScintWaveformRecAlg.h"
-#include "ScintRecEvent/WaveformBaselineData.h"
 
 ScintWaveformRecAlg::ScintWaveformRecAlg(const std::string& name, 
 					 ISvcLocator* pSvcLocator)
@@ -50,6 +49,8 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
 
     ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
 
+    WaveformHitCollection* collection = new WaveformHitCollection();
+
     // Make some sanity checks before going further
     if (wave->adc_counts().size() == 0) {
       ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
@@ -65,17 +66,11 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
       continue;
     }
 
-    // Find the baseline (return as an object so we can pass it downstream)
-    WaveformBaselineData* baseline = m_recoTool->findBaseline(*wave);
-
-    // Write something out
-    ATH_MSG_INFO( "Channel " << wave->channel() << " baseline: " << *baseline );
-
     // Reconstruct the hits
-    WaveformHitContainer* container = m_recoTool->reconstruct(*wave, *baseline);
+    CHECK( m_recoTool->reconstruct(*wave, collection) );
 
-    // This is transient, so delete it here
-    delete baseline;
+    // For now, this is transient
+    delete collection;
   }
   
 
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
index 19b5ad2d7..4867116e9 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -5,6 +5,9 @@
 #include "AthenaBaseComps/AthReentrantAlgorithm.h"
 
 #include "ScintRawEvent/ScintWaveformContainer.h"
+#include "ScintRecEvent/WaveformHitCollection.h"
+//#include "ScintRecEvent/WaveformHitContainer.h"
+
 #include "ScintRecTools/IWaveformReconstructionTool.h"
 
 #include "StoreGate/ReadHandleKey.h"
@@ -49,7 +52,7 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
    * @name Input data using SG::ReadHandleKey
    */
   //@{
-  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainer 
+  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainer
     {this, "WaveformContainerKey", ""};
   //@}
 
@@ -57,8 +60,8 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
    * @name Output data using SG::ReadHandleKey
    */
   //@{
-  //SG::WriteHandleKey<ScintWaveformContainer> m_waveformContainer 
-  //  {this, "WaveformContainerKey", ""};
+  //SG::WriteHandleKey<WaveformHitContainer> m_waveformHitContainer
+  //  {this, "WaveformHitContainerKey", ""};
   //@}
 
 };
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h b/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
index 653f7b730..9756e42b5 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
@@ -5,6 +5,6 @@
 #ifndef SCINTRECEVENT_SCINTRECEVENTDICT_H
 #define SCINTRECEVENT_SCINTRECEVENTDICT_H
 
-#include "ScintRecEvent/WaveformHitContainer.h"
+#include "ScintRecEvent/WaveformHitCollection.h"
 
 #endif
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
index 0785f7fd0..26301a933 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
@@ -46,35 +46,64 @@ class WaveformHit {
   inline int channel() const { return m_channel; }
 
   // Best results (from fit)
-  double localtime() const { return m_localtime; }
-  inline double amplitude() const { return m_amplitude; }
-  inline double integral() const { return m_integral; }
+  inline float localtime() const { return m_localtime; }
+  inline float amplitude() const { return m_amplitude; }
+  inline float width() const { return m_width; }
+  inline float integral() const { return m_integral; }
 
   // Raw values from waveform data
-  inline double pulse_amplitude() const { return m_pulse_amplitude; }
-  inline double pulse_integral() const { return m_pulse_integral; }
+  inline float raw_amplitude() const { return m_raw_amplitude; }
+  inline float raw_integral() const { return m_raw_integral; }
 
   // Bsaeline information
-  inline double baseline_mean() const { return m_baseline_mean; }
-  inline double baseline_rms()  const { return m_baseline_rms; }
+  inline float baseline_mean() const { return m_baseline_mean; }
+  inline float baseline_rms()  const { return m_baseline_rms; }
+
+  // Status informtaion
+  inline bool getStatus(unsigned int bit) const { return (m_status & (1 << bit)); }
+
+  // Set functions
+  void setChannel(unsigned int channel) {m_channel = channel;}
+  void setRawData(const std::vector<float>& time, 
+		  const std::vector<float>& wave);
+
+  void setBaseline(float mean, float rms) {m_baseline_mean = mean; m_baseline_rms = rms;}
+
+  void setRawResults(float peak, float mean, float width, float integral);
+  void setFitResults(float peak, float mean, float width, float integral);
+  void setCBResults(float alpha, float nval);
+
+  void setLocaltime(float time) { m_localtime = time; }
+  void setStatus(unsigned int bit) {m_status |= (1 << bit);}
 
   private:
 
   // Data members
   unsigned int m_channel;
+  unsigned int m_status;
 
-  // Best values from fit
-  double m_localtime;
-  double m_amplitude;
-  double m_integral;
+  // Raw values from waveform
+  float m_raw_amplitude;
+  float m_raw_mean;
+  float m_raw_width;
+  float m_raw_integral;
 
-  // Values from data
-  double m_pulse_amplitude;
-  double m_pulse_integral;
+  // Best values from fit
+  float m_localtime;
+  float m_amplitude;
+  float m_mean;
+  float m_width;
+  float m_integral;
+  float m_alpha;
+  float m_nval;
 
   // Baseline information
-  double m_baseline_mean;
-  double m_baseline_rms;
+  float m_baseline_mean;
+  float m_baseline_rms;
+
+  // Raw fit data
+  std::vector<float> m_timevec;
+  std::vector<float> m_wavevec;
 
   // Fit informtaion
 };
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
new file mode 100644
index 000000000..d947a9005
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
@@ -0,0 +1,27 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
+#define SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
+
+#include "ScintRecEvent/WaveformHit.h"
+#include "AthContainers/DataVector.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+// Make this a class in case we need to add some functions
+class WaveformHitCollection : public DataVector<WaveformHit> {
+ public:
+  unsigned int channel;
+  float baseline_mean;
+  float baseline_rms;
+  void print() const;
+};
+
+std::ostream 
+&operator<<(std::ostream &out, const WaveformHitCollection &collection);
+
+CLASS_DEF(WaveformHitCollection, 1228273893, 1 )
+SG_BASE(WaveformHitCollection, DataVector<WaveformHit>);
+
+#endif // SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
deleted file mode 100644
index 1304850a7..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef SCINTRECEVENT_WAVEFORMHITCONTAINER_H
-#define SCINTRECEVENT_WAVEFORMHITCONTAINER_H
-
-#include "ScintRecEvent/WaveformHit.h"
-#include "AthContainers/DataVector.h"
-#include "AthenaKernel/CLASS_DEF.h"
-
-// Make this a class in case we need to add some functions
-class WaveformHitContainer : public DataVector<WaveformHit> {
- public:
-  void print() const;
-};
-
-std::ostream 
-&operator<<(std::ostream &out, const WaveformHitContainer &container);
-
-CLASS_DEF(WaveformHitContainer, 1330197509, 1 )
-SG_BASE(WaveformHitContainer, DataVector<WaveformHit>);
-
-#endif // SCINTRECEVENT_WAVEFORMHITCONTAINER_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
index 378366a3a..709b6d649 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
@@ -1,5 +1,5 @@
 <lcgdict>
-  <class name="WaveformHitContainer" id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
+  <class name="WaveformHitCollection" id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
   <class name="DataVector<WaveformHit>" id="2943c109-26da-48df-b699-c9364d20896b" />
   <class name="std::vector<WaveformHit*>" />
   <class name="std::vector<const WaveformHit*>" />
diff --git a/Scintillator/ScintRecEvent/src/WaveformHit.cxx b/Scintillator/ScintRecEvent/src/WaveformHit.cxx
index 7df830fac..a0670f225 100644
--- a/Scintillator/ScintRecEvent/src/WaveformHit.cxx
+++ b/Scintillator/ScintRecEvent/src/WaveformHit.cxx
@@ -6,6 +6,37 @@
 
 // Default constructor
 WaveformHit::WaveformHit() {
+  m_timevec.clear();
+  m_wavevec.clear();
+}
+
+void 
+WaveformHit::setRawData(const std::vector<float>& time,
+			const std::vector<float>& wave) {
+  m_timevec = time;
+  m_wavevec = wave;
+}
+
+void
+WaveformHit::setRawResults(float peak, float mean, float width, float integral) {
+  m_raw_amplitude = peak;
+  m_raw_mean = mean;
+  m_raw_width = width;
+  m_raw_integral = integral;
+}
+
+void
+WaveformHit::setFitResults(float peak, float mean, float width, float integral) {
+  m_amplitude = peak;
+  m_mean = mean;
+  m_width = width;
+  m_integral = integral;
+}
+
+void
+WaveformHit::setCBResults(float alpha, float nval) {
+  m_alpha = alpha;
+  m_nval = nval;
 }
 
 std::ostream
diff --git a/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx b/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
new file mode 100644
index 000000000..8714f17f4
--- /dev/null
+++ b/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
@@ -0,0 +1,14 @@
+#include "ScintRecEvent/WaveformHitCollection.h"
+
+void
+WaveformHitCollection::print() const {
+  std::cout << "WaveformHit collection with size=" << this->size() << std::endl;
+  for(auto wfm: *this) std::cout << *wfm;
+}
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformHitCollection& cont) {
+  out << "WaveformHit collection with size=" << cont.size() << std::endl;
+  for(auto wfm: cont) out << *wfm;
+  return out;
+}
diff --git a/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx b/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx
deleted file mode 100644
index 5e30f7a4e..000000000
--- a/Scintillator/ScintRecEvent/src/WaveformHitContainer.cxx
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "ScintRecEvent/WaveformHitContainer.h"
-
-void
-WaveformHitContainer::print() const {
-  std::cout << "WaveformHit container with size=" << this->size() << std::endl;
-  for(auto wfm: *this) std::cout << *wfm;
-}
-
-std::ostream
-&operator<<(std::ostream &out, const WaveformHitContainer& cont) {
-  out << "WaveformHit container with size=" << cont.size() << std::endl;
-  for(auto wfm: cont) out << *wfm;
-  return out;
-}
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index df49ecceb..47a763562 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -19,8 +19,7 @@
 #include "GaudiKernel/ToolHandle.h"
 
 class ScintWaveform;
-class WaveformBaselineData;
-class WaveformHitContainer;
+class WaveformHitCollection;
 
 ///Interface for Waveform reco algorithms
 class IWaveformReconstructionTool : virtual public IAlgTool 
@@ -32,10 +31,9 @@ class IWaveformReconstructionTool : virtual public IAlgTool
 
   virtual ~IWaveformReconstructionTool() = default;
 
-  // Find the baseline for a complete raw waveform
-  virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const = 0;
   // Reconstruct all peaks in a raw waveform
-  virtual WaveformHitContainer* reconstruct(const ScintWaveform& wave, const WaveformBaselineData& baseline) const = 0;
+  virtual StatusCode reconstruct(const ScintWaveform& wave, 
+				 WaveformHitCollection* collection) const = 0;
 
 };
 
diff --git a/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx b/Scintillator/ScintRecTools/src/WaveformBaselineData.cxx
similarity index 92%
rename from Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
rename to Scintillator/ScintRecTools/src/WaveformBaselineData.cxx
index 5a48f1e9f..f2e92625c 100644
--- a/Scintillator/ScintRecEvent/src/WaveformBaselineData.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformBaselineData.cxx
@@ -2,7 +2,7 @@
   Copyright (C) 2021 CERN for the benefit of the FASER collaboration
 */
 
-#include "ScintRecEvent/WaveformBaselineData.h"
+#include "WaveformBaselineData.h"
 
 WaveformBaselineData::WaveformBaselineData() {
   clear();
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h b/Scintillator/ScintRecTools/src/WaveformBaselineData.h
similarity index 92%
rename from Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
rename to Scintillator/ScintRecTools/src/WaveformBaselineData.h
index ef631805b..13144a4f9 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformBaselineData.h
+++ b/Scintillator/ScintRecTools/src/WaveformBaselineData.h
@@ -10,8 +10,8 @@
 ///////////////////////////////////////////////////////////////////
 // Version 1.0   2/21/2021 Eric Torrence
 ///////////////////////////////////////////////////////////////////
-#ifndef SCINTRECEVENT_WAVEFORMBASELINEDATA_H
-#define SCINTRECEVENT_WAVEFORMBASELINEDATA_H
+#ifndef SCINTRECTOOLS_WAVEFORMBASELINEDATA_H
+#define SCINTRECTOOLS_WAVEFORMBASELINEDATA_H
 
 #include <iostream>
 
@@ -42,6 +42,9 @@ class WaveformBaselineData {
 
   /** Clones */
   virtual WaveformBaselineData* clone() const ;       
+
+  // Clear
+  void clear();
             
   // Data members
   int channel;  // Channel number
@@ -54,7 +57,7 @@ class WaveformBaselineData {
   double chi2n; // Reduced chi2/Ndof from gauss fit
 
  private:
-  void clear();
+
 };
 
 std::ostream
@@ -69,4 +72,4 @@ WaveformBaselineData::clone() const {
   return new WaveformBaselineData(*this);  
 }
 
-#endif // SCINTRECEVENT_WAVEFORMBASELINEDATA_H
+#endif // SCINTRECTOOLS_WAVEFORMBASELINEDATA_H
diff --git a/Scintillator/ScintRecTools/src/WaveformFitResult.cxx b/Scintillator/ScintRecTools/src/WaveformFitResult.cxx
new file mode 100644
index 000000000..45dcdae23
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/WaveformFitResult.cxx
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#include "WaveformFitResult.h"
+
+WaveformFitResult::WaveformFitResult() {
+  clear();
+}
+
+WaveformFitResult::WaveformFitResult(bool isvalid) {
+  clear();
+  valid = isvalid;
+}
+
+void
+WaveformFitResult::clear() {
+  valid = false;
+  peak = 0.;
+  mean = 0.;
+  sigma = 0.;
+  fit_status = -1;
+  chi2n = 0.;
+}
+
+std::ostream
+&operator<<( std::ostream& out, const WaveformFitResult &fit ) {
+  out << "WaveformFitResult - Mean: " << fit.mean << ", Sigma: " << fit.sigma << ", Peak: " << fit.peak << std::endl;
+  return out;
+}
+
+
+
+
+
diff --git a/Scintillator/ScintRecTools/src/WaveformFitResult.h b/Scintillator/ScintRecTools/src/WaveformFitResult.h
new file mode 100644
index 000000000..92ecf0fc6
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/WaveformFitResult.h
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// WaveformFitResult.h
+//   Header file for class WaveformFitResult
+///////////////////////////////////////////////////////////////////
+// Class to handle the fit output for a raw waveform
+///////////////////////////////////////////////////////////////////
+// Version 1.0   2/21/2021 Eric Torrence
+///////////////////////////////////////////////////////////////////
+#ifndef SCINTRECTOOLS_WAVEFORMFITRESULT_H
+#define SCINTRECTOOLS_WAVEFORMFITRESULT_H
+
+#include <iostream>
+
+/**
+ * @class WaveformFitResult
+ * The baseline is the estimate of the waveform reading for no signal.
+ */
+  
+class WaveformFitResult {
+      
+ public:
+      
+  /** Default constructor */
+  WaveformFitResult();
+
+  // Set status directly
+  WaveformFitResult(bool valid);
+
+  // move assignment defaulted
+  WaveformFitResult & operator= (WaveformFitResult &&) = default;
+  //assignment defaulted
+  WaveformFitResult & operator= (const WaveformFitResult &) = default;
+  //copy c'tor defaulted
+  WaveformFitResult(const WaveformFitResult &) = default;
+
+  /** Destructor */
+  virtual ~WaveformFitResult() = default;
+
+  // Clear
+  void clear();
+            
+  // Data members
+  bool valid;   // Overall valididty (from fit result == 0)
+
+  double peak;  // Best value for peak
+  double mean;  // Best value for mean
+  double sigma; // Best value for width
+  double alpha; // Crystal ball parameter
+  double nval;  // Crystal ball parameter
+  double chi2ndf; 
+  double integral;
+  double time;  // Time of leading edge of pulse
+
+  int fit_status; // Return value from fit
+
+  double chi2n; // Reduced chi2/Ndof from fit
+
+ private:
+
+};
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformFitResult &wfm);
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+#endif // SCINTRECTOOLS_WAVEFORMFITRESULT_H
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 1796f6f19..023d1749b 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -17,6 +17,7 @@
 #include "TGraph.h"
 
 #include <vector>
+#include <tuple>
 
 // Constructor
 WaveformReconstructionTool::WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
@@ -38,192 +39,204 @@ WaveformReconstructionTool::initialize() {
 }
 
 // Reconstruction step
-WaveformHitContainer*
-WaveformReconstructionTool::reconstruct(const ScintWaveform& rawWaveform, const WaveformBaselineData& baseline) const {
+StatusCode
+WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
+					WaveformHitCollection* collection) const {
 
   ATH_MSG_DEBUG(" reconstruct called ");
 
-  // Start out with empty WaveformHitContainer
-  WaveformHitContainer* container = new WaveformHitContainer();
+  // Check the collection
+  if (!collection) {
+    ATH_MSG_ERROR("WaveformHitCollection passed to reconstruct() is null!");
+    return StatusCode::FAILURE;
+  }
+  // Set channel
+  collection->channel = raw_wave.channel();
+
+  //
+  // Find baseline
+  WaveformBaselineData baseline;
+
+  if (m_useSimpleBaseline.value())
+    baseline = findSimpleBaseline(raw_wave);
+  else
+    baseline = findAdvancedBaseline(raw_wave);
+
+  if (!(baseline.valid)) {
+    ATH_MSG_WARNING("Failed to reconstruct baseline!");
+
+    // Store some default values
+    collection->baseline_mean = 0.;
+    collection->baseline_rms = -1.;
+
+    return StatusCode::SUCCESS;
+  }
+
+  // Save baseline to hit collection object
+  collection->baseline_mean = baseline.mean;
+  collection->baseline_rms = baseline.rms;
+
+  //
+  // Create baseline-subtracted data array for both time and signal
+  // Time in ns from start of readout
+  unsigned int size = raw_wave.adc_counts().size();
+  std::vector<float> time(size);  
+  for (unsigned int i=0; i<size; i++)
+    time[i] = 2.*i;
 
-  // Create baseline-subtracted data array
-  std::vector<float> wave(rawWaveform.adc_counts().begin(), rawWaveform.adc_counts().end());
+  // Baseline subtracted (and inverted) ADC waveform values
+  std::vector<float> wave(raw_wave.adc_counts().begin(), raw_wave.adc_counts().end());
   for (auto& element : wave)
     element = baseline.mean - element;
 
-  // Define the fit functions here outside the loop
-  TF1 gfunc("gfunc", "gaus");
-  TF1 cbfunc("cbfunc", "crystalball");
-
   // Now we iteratively find peaks and fit
   while(true) {
 
-    // Find max value location in array
-    unsigned int imax = std::max_element(wave.begin(), wave.end()) - wave.begin();
-    float maxval = wave[imax];
-    ATH_MSG_DEBUG( "Found max value " << maxval << " at position " << imax );
+    //
+    // Find peak in array and return time and value arrays
+    // This range of data is also *removed* from original arrays
+    std::vector<float> wtime;
+    std::vector<float> wwave;
+
+    // All done if we don't have any peaks above threshold
+    // If we do find a significant peak, fill the window
+    if (! findPeak(baseline, time, wave, wtime, wwave) ) break;
+
+    //
+    // Save windowed waveform to Hit object
+    WaveformHit* hit = new WaveformHit();
+    hit->setChannel(raw_wave.channel());
+    hit->setRawData(wtime, wwave);
+    hit->setBaseline(baseline.mean, baseline.rms);
+
+    //
+    // Find some raw values
+    WaveformFitResult raw = findRawHitValues(wtime, wwave);
+    hit->setRawResults(raw.peak, raw.mean, raw.sigma, raw.integral);
+    hit->setLocaltime(raw.time);
+
+    //
+    // Perform Gaussian fit to waveform
+    WaveformFitResult gfit = fitGaussian(raw, wtime, wwave);
+    if (! gfit.valid) {
+      ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
+      // hit->setStatus(GAUSS_FIT_FAILED);
+    } 
+    // Fit results (or raw if it failed
+    hit->setFitResults(gfit.peak, gfit.mean, gfit.sigma, gfit.integral);
+    hit->setLocaltime(gfit.time);
 
-    // Check if this is over threshold
-    float pulseThreshold = 10.; // In baseline sigma
-    if (maxval < pulseThreshold*baseline.rms) {
-      ATH_MSG_DEBUG("Failed threshold");
-      break;
+    //
+    // Check for overflow
+    if (m_removeOverflow && findOverflow(baseline, wtime, wwave)) {
+      ATH_MSG_INFO("Found waveform overflow");
+      // hit->setStatus(OVERFLOW);
     }
 
-    // Make a window around this peak, values are in bins, so units of 2ns
-    // Ensure our window is within the vector range
-    int lo_edge = (imax - 10) > 0 ? (imax - 10) : 0; 
-    int hi_edge = (imax + 40) < wave.size() ? (imax + 40) : wave.size();
-
-    ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge);
-    std::vector<float> window(wave.begin()+lo_edge, wave.begin()+hi_edge);
-
-    // Array of matching time values (in ns), find mean and rms of these data
-    std::vector<float> tvec(50, 0.);
-
-    double tot = 0.;
-    double sum = 0.;
-    double sum2 = 0.;
-    for (unsigned int i=0; i<tvec.size(); i++) {
-      tvec[i] = 2.*(lo_edge+i);
-      tot += window[i];
-      sum += tvec[i] * window[i];
-      sum2 += tvec[i] * tvec[i] * window[i];
+    //
+    // Perform CB fit
+    WaveformFitResult cbfit = fitCBall(gfit, wtime, wwave);
+    if (! cbfit.valid) {
+      ATH_MSG_WARNING("CrystalBall fit failed!");
+      // Still have gaussian parameters as an estimate
+      // hit->setStatus(CB_FIT_FAILED);
+    } else {
+      hit->setFitResults(cbfit.peak, cbfit.mean, cbfit.sigma, cbfit.integral);
+      hit->setCBResults(cbfit.alpha, cbfit.nval);
+      hit->setLocaltime(cbfit.time);
     }
 
-    // Initial parameters from window
-    double gmean = sum/tot;
-    double grms = std::sqrt(sum2/tot - gmean*gmean);
-    double gpeak = maxval;
-    ATH_MSG_DEBUG( "Initial Mean: " << gmean << " RMS: " << grms << " Peak: " << gpeak);  
-
-    // Start by creating a TGraph and fitting this with a Gaussian
-    // Must pass arrays to TGraph, use pointer to first vector element
-    TGraph tg(tvec.size(), &tvec[0], &window[0]);
+    collection->push_back(hit);
+  
+    if (! m_findMultipleHits) break;
 
-    // Define fit function and preset range
-    gfunc.SetParameters(gpeak, gmean, grms);
-    gfunc.SetParError(0, std::sqrt(gpeak));
-    gfunc.SetParError(1, grms);
-    gfunc.SetParError(2, 5.);
-    TFitResultPtr gfit = tg.Fit(&gfunc, "QNS", "");
+  } // End of loop over waveform data
 
-    //int gFitStatus = gfit;
+  ATH_MSG_DEBUG( "WaveformReconstructionTool created collection for channel " 
+		 << collection->channel << " with size= " << collection->size());
 
-    if (!gfit->IsValid()) {
-      ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
-      break;
-    } else {
-      // Improve estimation with fit results
-      gpeak = gfit->Parameter(0);
-      gmean = gfit->Parameter(1);
-      grms  = gfit->Parameter(2);
-      ATH_MSG_DEBUG("G Fit   Mean: " << gmean << " RMS: " << grms << " Peak: " << gpeak);
-    }
+  return StatusCode::SUCCESS;
+}
 
-    // Check for overflow
-    bool overflow = (rawWaveform.adc_counts()[imax] == 0);
+bool
+WaveformReconstructionTool::findPeak(WaveformBaselineData& baseline, 
+   std::vector<float>& time, std::vector<float>& wave,
+   std::vector<float>& windowed_time, std::vector<float>& windowed_wave) const {
 
-    if (overflow) {
-      ATH_MSG_INFO("Found waveform overflow");
+  ATH_MSG_DEBUG("findPeak called");
 
-      // Want to remove overflowing points so fit works better
-      // Find first and last overflow here
-      // max_element will find the first overflow (imax), find the last
-      unsigned int iover;
-      for (iover = imax; iover < rawWaveform.adc_counts().size(); iover++) {
-	if (rawWaveform.adc_counts()[iover] != 0) break;
-      }
-
-      // Find the limits in the windowed waveform
-      unsigned int cut_lo = imax - lo_edge;
-      unsigned int cut_hi = iover - lo_edge;
-      if (cut_hi > window.size()) cut_hi = window.size();  // Don't cut beyond window
-
-      // Remove these entries
-      ATH_MSG_DEBUG("Removing entries from " << cut_lo << " to " << cut_hi);
-      tvec.erase(tvec.begin()+cut_lo, tvec.begin()+cut_hi);
-      window.erase(window.begin()+cut_lo, window.begin()+cut_hi);
-      ATH_MSG_DEBUG("Vector length now " << tvec.size());
+  // Find max value location in array
+  unsigned int imax = std::max_element(wave.begin(), wave.end()) - wave.begin();
+  float maxval = wave[imax];
+  ATH_MSG_DEBUG( "Found peak value " << maxval << " at position " << imax );
 
-    }
-
-    // Now do crystal ball fit
-    double cbpeak = gpeak;
-    double cbmean = gmean;
-    double cbrms = grms;
-    if (cbrms < 0.) cbrms = abs(cbrms);
-    if (cbrms > 20.) cbrms = 5.;
-
-    double alpha = -0.25; // Negative puts tail on RH side
-    double nval = 3.;
-    // Preset everything to improve results
-    cbfunc.SetParameter(0, cbpeak); // Peak height
-    cbfunc.SetParError(0, std::sqrt(cbpeak));
-    cbfunc.SetParameter(1, cbmean); // Mean
-    cbfunc.SetParError(1, cbrms);
-    cbfunc.SetParameter(2, cbrms);  // Width
-    cbfunc.SetParError(2, 5.);
-    cbfunc.SetParLimits(2, 0., 20.);
-    cbfunc.SetParameter(3, alpha); // Tail parameter (negative for high-side tail)
-    cbfunc.SetParError(3, 0.05);
-    cbfunc.SetParLimits(3, -10., 0.);
-    cbfunc.SetParameter(4, nval);  // Tail power
-    cbfunc.SetParError(4, 1.);
-    cbfunc.SetParLimits(4, 0., 1.E3);
-    //cbfunc.SetParameters(peak, mean, rms, alpha, nval);
-
-    TFitResultPtr cbfit = tg.Fit(&cbfunc, "QNS", "");
-
-    double chi2 = cbfit->Chi2();
-    unsigned int ndf = cbfit->Ndf();
-    if (ndf == 0) ndf = 1;
-    double chi2ndf = chi2/ndf;
+  // Check if this is over threshold (in sigma)
+  if (maxval < m_peakThreshold*baseline.rms) {
+    ATH_MSG_DEBUG("Failed threshold");
+    return false;
+  }
 
-    if (!cbfit->IsValid()) {
-      ATH_MSG_WARNING(" CrystalBall waveform fit failed!");
-      break;
-    } else {
-      // Improve estimation with fit results
-      cbpeak  = cbfit->Parameter(0);
-      cbmean  = cbfit->Parameter(1);
-      cbrms   = cbfit->Parameter(2);
-      alpha = cbfit->Parameter(3);
-      nval  = cbfit->Parameter(4);
-      ATH_MSG_DEBUG("CB Fit  Mean: " << cbmean << " RMS: " << cbrms << " Peak: " << cbpeak << " N: " << nval << " Alpha: " << alpha << " Chi2/Ndf: " << chi2ndf);
-    }
+  // Make a window around this peak, values are in bins, so units of 2ns
+  // Ensure our window is within the vector range
+  int lo_edge = (imax + m_windowStart) > 0 ? (imax + m_windowStart) : 0; 
+  int hi_edge = (imax + m_windowStart + m_windowWidth) < wave.size() ? (imax + m_windowStart + m_windowWidth) : wave.size();
   
-    break;
-  }
+  ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge);
+  windowed_time = std::vector<float> (time.begin()+lo_edge, time.begin()+hi_edge);
+  windowed_wave = std::vector<float> (wave.begin()+lo_edge, wave.begin()+hi_edge);
 
-  return container;
+  // Remove these values from the original arrays so we can iterate
+  time.erase(time.begin()+lo_edge, time.begin()+hi_edge);
+  wave.erase(wave.begin()+lo_edge, wave.begin()+hi_edge);
+  
+  return true;
 }
 
+bool
+WaveformReconstructionTool::findOverflow(const WaveformBaselineData& base, 
+	      std::vector<float>& time, std::vector<float>& wave) const {
 
-WaveformBaselineData*
-WaveformReconstructionTool::findBaseline(const ScintWaveform& wave) const {
+  auto peakloc = std::max_element(wave.begin(), wave.end());
 
-  if (m_useSimpleBaseline.value())
-    return this->findSimpleBaseline(wave);
+  // If peak value is less than baseline, we have no overflow
+  if (*peakloc < int(base.mean)) return false;
 
-  else
-    return this->findAdvancedBaseline(wave);
+  ATH_MSG_DEBUG("Removing overflows from waveform with length " << wave.size());
+
+  // We have an overflow, remove all elements that are overflowing
+  unsigned int i = peakloc - wave.begin();
+  for (; i<wave.size(); i++) {
+    if (wave[i] < int(base.mean)) continue;
+
+    ATH_MSG_DEBUG("Removing position "<< i<< " with value " << wave[i] << " > " << int(base.mean));
+    // This is an overflow, remove elements
+    time.erase(time.begin() + i);
+    wave.erase(wave.begin() + i);
+    i--;  // Decrement so that loop itertaion points to next element
+  }
+
+  ATH_MSG_DEBUG("Removed overflows, length now " << wave.size());
+  return true;
 }
 
-WaveformBaselineData*
-WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& wave) const {
+WaveformBaselineData&
+WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& raw_wave) const {
 
   ATH_MSG_DEBUG( "findSimpleBaseline called" );
-  //ATH_MSG_DEBUG( wave );
+  //ATH_MSG_DEBUG( raw_wave );
+
+  // This must be static so we can return a reference
+  static WaveformBaselineData baseline;  
+  baseline.clear();
 
   // Calling algorithm checks for proper data
   // Here we just check algorithm-specific issues
-  if (int(wave.n_samples()) < m_samplesForBaselineAverage.value()) {
-    ATH_MSG_WARNING( "Found waveform with " << wave.n_samples() << " samples, not enough to find baseline!" );
-    return new WaveformBaselineData(false);
+  if (int(raw_wave.n_samples()) < m_samplesForBaselineAverage.value()) {
+    ATH_MSG_WARNING( "Found waveform with " << raw_wave.n_samples() << " samples, not enough to find baseline!" );
+    return baseline;
   }
 
-  const std::vector<unsigned int>& counts = wave.adc_counts();
+  const std::vector<unsigned int>& counts = raw_wave.adc_counts();
 
   double sumx = 0.;
   double sumx2 = 0.;
@@ -240,18 +253,22 @@ WaveformReconstructionTool::findSimpleBaseline(const ScintWaveform& wave) const
 
   double rms = std::sqrt(mean2 - mean*mean);
 
-  WaveformBaselineData* base = new WaveformBaselineData(true);
-  base->channel = wave.channel();
-  base->mean = mean;
-  base->rms = rms;
-  return base;
+  baseline.valid = true;
+  baseline.channel = raw_wave.channel();
+  baseline.mean = mean;
+  baseline.rms = rms;
+  return baseline;
 }
 
-WaveformBaselineData*
-WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) const {
+WaveformBaselineData&
+WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& raw_wave) const {
 
   ATH_MSG_DEBUG( "findAdvancedBaseline called" );
 
+  // This must be static so we can return a reference
+  static WaveformBaselineData baseline;  
+  baseline.clear();
+
   // First histogram to find most likely value
   // Turn these into configurables once this works
   int nbins = m_baselineRangeBins;
@@ -261,7 +278,7 @@ WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) cons
   TH1F h1("", "", nbins, xlo, xhi);
 
   // Fill this histogram with the waveform
-  for (auto value : wave.adc_counts()) {
+  for (auto value : raw_wave.adc_counts()) {
     //ATH_MSG_DEBUG( "Found value " << value );
     h1.Fill(value);
   }
@@ -278,7 +295,7 @@ WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) cons
   ATH_MSG_DEBUG( "Filling 2nd histogram from " << xlo << " to " << xhi);
 
   TH1F h2("", "", nbins, xlo, xhi);
-  for (auto value : wave.adc_counts()) {
+  for (auto value : raw_wave.adc_counts()) {
     h2.Fill(value);
   }
 
@@ -331,12 +348,168 @@ WaveformReconstructionTool::findAdvancedBaseline(const ScintWaveform& wave) cons
     ATH_MSG_DEBUG( "G Fit   Mean: " << mean << " RMS: " << rms << " Peak: " << peak << " Chi2/N: " << chi2/ndf);  
   }
 
-  WaveformBaselineData* base = new WaveformBaselineData(true);
-  base->channel = wave.channel();
-  base->mean = mean;
-  base->rms = rms;
-  base->fit_status = fitStatus; 
-  base->peak = peak;
-  base->chi2n = chi2/ndf;
-  return base;
+  baseline.valid = true;
+  baseline.channel = raw_wave.channel();
+  baseline.mean = mean;
+  baseline.rms = rms;
+  baseline.fit_status = fitStatus; 
+  baseline.peak = peak;
+  baseline.chi2n = chi2/ndf;
+  return baseline;
+}
+
+WaveformFitResult&
+WaveformReconstructionTool::findRawHitValues(const std::vector<float> time, const std::vector<float> wave) const {
+
+  ATH_MSG_DEBUG("findRawHitValues called");
+
+  // This must be static so we can return a reference
+  static WaveformFitResult rfit;
+  rfit.clear();
+
+  // First, estimate starting values from input waveform
+  // Will use this to pre-set fit values, but also as a backup in case fit fails
+  double tot = 0.;
+  double sum = 0.;
+  double sum2 = 0.;
+  for (unsigned int i=0; i<time.size(); i++) {
+    tot += wave[i];
+    sum += time[i] * wave[i];
+    sum2 += time[i] * time[i] * wave[i];
+  }
+
+  // Pointer to peak
+  auto peakloc = std::max_element(wave.begin(), wave.end());
+
+  // Initial parameters from waveform
+  rfit.mean = sum/tot;
+  rfit.sigma = std::sqrt(sum2/tot - rfit.mean*rfit.mean);
+  rfit.peak = *peakloc;
+  rfit.integral = tot;
+  rfit.time = rfit.mean;
+
+  ATH_MSG_DEBUG( "Initial Mean: " << rfit.mean << " RMS: " << rfit.sigma << " Peak: " << rfit.peak);  
+
+  return rfit;
+}
+
+WaveformFitResult&
+WaveformReconstructionTool::fitGaussian(const WaveformFitResult& raw, const std::vector<float> time, const std::vector<float> wave) const {
+
+  ATH_MSG_DEBUG("fitGaussian called");
+
+  // This must be static so we can return a reference
+  static WaveformFitResult gfit;
+  gfit.clear();
+
+  // Start with raw values by default
+  gfit = raw;
+
+  // Start by creating a TGraph and fitting this with a Gaussian
+  // Must pass arrays to TGraph, use pointer to first vector element
+  TGraph tg(time.size(), &time[0], &wave[0]);
+
+  // Define fit function and preset range
+  TF1 gfunc("gfunc", "gaus");
+  gfunc.SetParameters(raw.peak, raw.mean, raw.sigma);
+  gfunc.SetParError(0, std::sqrt(raw.peak));
+  gfunc.SetParError(1, raw.sigma);
+  gfunc.SetParError(2, raw.sigma / 10.);
+  gfunc.SetParLimits(2, 0., 20.);  // Constrain width
+
+  TFitResultPtr gfitptr = tg.Fit(&gfunc, "QNS", "");
+
+  gfit.fit_status = gfitptr;
+  gfit.valid = (gfit.fit_status == 0);
+
+  if (!gfitptr->IsValid()) {
+    ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
+  } else {
+    // Improve estimation with fit results
+    gfit.peak = gfitptr->Parameter(0);
+    gfit.mean = gfitptr->Parameter(1);
+    gfit.sigma = gfitptr->Parameter(2);
+    gfit.integral = gfunc.Integral(time.front(), time.back());
+
+    // Find time here
+    gfit.time = gfunc.GetX( gfit.peak * m_timingPeakFraction, time.front(), gfit.mean );
+
+    ATH_MSG_DEBUG("G Fit   Mean: " << gfit.mean << " RMS: " << gfit.sigma 
+		  << " Peak: " << gfit.peak << " Int: " << gfit.integral << " Time: " << gfit.time);
+  }
+
+  return gfit;
+}
+
+WaveformFitResult&
+WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit, 
+     const std::vector<float> time, const std::vector<float> wave) const {
+
+  ATH_MSG_DEBUG("fitCBall called");
+
+  // This must be static so we can return a reference
+  static WaveformFitResult cbfit;
+  cbfit.clear();
+
+  // Must pass arrays to TGraph, use pointer to first vector element
+  TGraph tg(time.size(), &time[0], &wave[0]);
+
+  // Values to preset CB fit
+  cbfit.peak = abs(gfit.peak);
+  cbfit.mean = gfit.mean;
+  cbfit.sigma = abs(gfit.sigma);
+  if (cbfit.sigma > 20.) cbfit.sigma = 5.;
+  cbfit.alpha = -0.25;  // Negative to get tail on high side
+  cbfit.nval = 3.;
+
+  // Define fit function and preset values
+  TF1 cbfunc("cbfunc", "crystalball");
+  cbfunc.SetParameter(0, cbfit.peak); // Peak height
+  cbfunc.SetParError(0, std::sqrt(cbfit.peak));
+  cbfunc.SetParameter(1, cbfit.mean); // Mean
+  cbfunc.SetParError(1, cbfit.sigma);
+  cbfunc.SetParameter(2, cbfit.sigma);  // Width
+  cbfunc.SetParError(2, cbfit.sigma/10.);
+  cbfunc.SetParLimits(2, 0., 20.);
+  cbfunc.SetParameter(3, cbfit.alpha); // Tail parameter (negative for high-side tail)
+  cbfunc.SetParError(3, -cbfit.alpha/10.);
+  cbfunc.SetParLimits(3, -10., 0.);
+  cbfunc.SetParameter(4, cbfit.nval);  // Tail power
+  cbfunc.SetParError(4, cbfit.nval/10.);
+  cbfunc.SetParLimits(4, 0., 1.E3);
+
+  TFitResultPtr cbfitptr = tg.Fit(&cbfunc, "QNS", "");
+
+  cbfit.fit_status = cbfitptr;
+  cbfit.valid = (cbfit.fit_status == 0);
+
+  if (!cbfitptr->IsValid()) {
+    ATH_MSG_WARNING( " Crystal Ball waveform fit failed! ");
+  } else {
+    // Improve estimation with fit results
+    cbfit.peak = cbfitptr->Parameter(0);
+    cbfit.mean = cbfitptr->Parameter(1);
+    cbfit.sigma = cbfitptr->Parameter(2);
+    cbfit.alpha = cbfitptr->Parameter(3);
+    cbfit.nval = cbfitptr->Parameter(4);
+
+    double chi2 = cbfitptr->Chi2();
+    unsigned int ndf = cbfitptr->Ndf();
+    if (ndf == 0) ndf = 1;
+    cbfit.chi2ndf = chi2/ndf;
+
+    cbfit.integral = cbfunc.Integral(time.front(), time.back());
+
+    // Find time here
+    cbfit.time = cbfunc.GetX( cbfit.peak * m_timingPeakFraction, time.front(), cbfit.mean );
+
+    ATH_MSG_DEBUG("CB Fit  Mean: " << cbfit.mean << " RMS: " << cbfit.sigma 
+		  << " Peak: " << cbfit.peak << " Int: " << cbfit.integral
+		  << " Time: " << cbfit.time 
+		  << " N: " << cbfit.nval << " Alpha: " << cbfit.alpha 
+		  << " Chi2/Ndf: " << cbfit.chi2ndf );
+
+  }
+
+  return cbfit;
 }
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 2448ecb6f..32407abf4 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -14,8 +14,10 @@
 #include "ScintRecTools/IWaveformReconstructionTool.h"
 
 #include "ScintRawEvent/ScintWaveform.h"
-#include "ScintRecEvent/WaveformBaselineData.h"
-#include "ScintRecEvent/WaveformHitContainer.h"
+#include "ScintRecEvent/WaveformHitCollection.h"
+
+#include "WaveformBaselineData.h"
+#include "WaveformFitResult.h"
 
 //Gaudi
 #include "GaudiKernel/ToolHandle.h"
@@ -24,24 +26,24 @@
 #include <string>
 #include <vector>
 
-
 class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstructionTool> {
  public:
 
   /// Normal constructor for an AlgTool; 'properties' are also declared here
-  WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent);
+  WaveformReconstructionTool(const std::string& type, 
+			     const std::string& name, const IInterface* parent);
 
   /// Retrieve the necessary services in initialize
   StatusCode initialize();
 
-  /// Find baseline (return pointer to new baseline object)
-  virtual WaveformBaselineData* findBaseline(const ScintWaveform& wave) const;
-
   /// Reconstruct hits from waveform
-  virtual WaveformHitContainer* reconstruct(const ScintWaveform& wave, const WaveformBaselineData& baseline) const;
+  
+  virtual StatusCode reconstruct(const ScintWaveform& wave,
+				 WaveformHitCollection* collection) const;
 
  private:
 
+  //
   // Baseline Estimation Parameters
   BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", false};
   IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40};
@@ -59,9 +61,56 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
   // Fit window is value (in sigma) of trucated width to use in final fit
   FloatProperty m_baselineFitWindow{this, "BaselineFitWindow", 2.};
 
+  //
+  // Peak threshold (in sigma of baseline RMS) to find a hit
+  FloatProperty m_peakThreshold{this, "PeakThreshold", 10.};
+ 
+  //
+  // Window to define fitting range, in samples (2ns/sample)
+  IntegerProperty m_windowStart{this, "FitWindowFromPeak", -10};
+  IntegerProperty m_windowWidth{this, "FitWindowWidth", 50};
+
+  //
+  // Remove overflow values from CB fit
+  BooleanProperty m_removeOverflow{this, "RemoveOverflow", true};
+
+  //
+  // Look for more than one hit in each channel
+  BooleanProperty m_findMultipleHits{this, "FindMultipleHits", false};
+
+  //
+  // Fraction of peak to set local hit time
+  FloatProperty m_timingPeakFraction{this, "TimingPeakFraction", 0.2};
+
   // Baseline algorithms
-  WaveformBaselineData* findSimpleBaseline(const ScintWaveform& wave) const;
-  WaveformBaselineData* findAdvancedBaseline(const ScintWaveform& wave) const;
+  WaveformBaselineData& findSimpleBaseline(const ScintWaveform& wave) const;
+  WaveformBaselineData& findAdvancedBaseline(const ScintWaveform& wave) const;
+
+  // Find peak in wave, return windowed region in windowed_time and windowed_wave
+  // Windowed region is removed from original vectors
+  // Returns true if peak found, false if not
+  bool findPeak(WaveformBaselineData& baseline,
+		std::vector<float>& time, std::vector<float>& wave,
+		std::vector<float>& windowed_time, std::vector<float>& windowed_wave) const;
+
+  // Get estimate from waveform data itself
+  WaveformFitResult& findRawHitValues(const std::vector<float> time, 
+				      const std::vector<float> wave) const;
+
+  // Fit windowed data to Gaussian (to get initial estimate of parameters
+  WaveformFitResult& fitGaussian(const WaveformFitResult& raw,
+				 const std::vector<float> time, 
+				 const std::vector<float> wave) const;
+
+  // Find overflows and remove points from arrays
+  bool findOverflow(const WaveformBaselineData& baseline, 
+		    std::vector<float>& time, std::vector<float>& wave) const;
+
+  // Fit windowed data to CrystalBall function
+  WaveformFitResult& fitCBall(const WaveformFitResult& gfit, 
+			      const std::vector<float> time, 
+			      const std::vector<float> wave) const;
+
 
 };
 
-- 
GitLab


From ece7dcdcb350c0267f8e63ad4c5fc1d6831a7b1a Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 5 Mar 2021 16:32:37 -0800
Subject: [PATCH 27/47] Save HitCollections in WaveformHitContainer

---
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  | 21 ++++++++++++++-----
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    | 10 ++++-----
 .../ScintRecEvent/WaveformHitContainer.h      | 17 +++++++++++++++
 .../ScintRecEvent/ScintRecEvent/selection.xml | 10 +++++----
 4 files changed, 44 insertions(+), 14 deletions(-)
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h

diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index 7dfa8a368..39e20990d 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -14,7 +14,10 @@ ScintWaveformRecAlg::initialize() {
   ATH_CHECK( m_recoTool.retrieve() );
 
   // Set key to read waveform from
-  ATH_CHECK( m_waveformContainer.initialize() );
+  ATH_CHECK( m_waveformContainerKey.initialize() );
+
+  // Set key to write container
+  ATH_CHECK( m_waveformHitContainerKey.initialize() );
 
   return StatusCode::SUCCESS;
 }
@@ -33,8 +36,8 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
   ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() 
 		<< " Event: " << ctx.eventID().event_number());
 
-  // Find the waveform container
-  SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainer, ctx);
+  // Find the input waveform container
+  SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainerKey, ctx);
 
   ATH_CHECK( waveformHandle.isValid() );
   ATH_MSG_DEBUG("Found ReadHandle for Waveforms");
@@ -44,6 +47,11 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
     return StatusCode::SUCCESS;
   }
 
+  // Find the output waveform container
+  SG::WriteHandle<WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx);
+  ATH_CHECK( hitContainerHandle.record( std::make_unique<WaveformHitContainer>() ) );
+  ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' initialized");
+
   // Reconstruct each waveform
   for( const auto& wave : *waveformHandle) {
 
@@ -69,11 +77,14 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
     // Reconstruct the hits
     CHECK( m_recoTool->reconstruct(*wave, collection) );
 
+    // Store collection in container
+    hitContainerHandle->push_back(collection);
+
     // For now, this is transient
-    delete collection;
+    // delete collection;
   }
-  
 
+  ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' filled with "<< hitContainerHandle->size() <<" collections");
 
   return StatusCode::SUCCESS;
 }
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
index 4867116e9..2794add30 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -6,7 +6,7 @@
 
 #include "ScintRawEvent/ScintWaveformContainer.h"
 #include "ScintRecEvent/WaveformHitCollection.h"
-//#include "ScintRecEvent/WaveformHitContainer.h"
+#include "ScintRecEvent/WaveformHitContainer.h"
 
 #include "ScintRecTools/IWaveformReconstructionTool.h"
 
@@ -52,16 +52,16 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
    * @name Input data using SG::ReadHandleKey
    */
   //@{
-  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainer
+  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainerKey
     {this, "WaveformContainerKey", ""};
   //@}
 
   /**
-   * @name Output data using SG::ReadHandleKey
+   * @name Output data using SG::WriteHandleKey
    */
   //@{
-  //SG::WriteHandleKey<WaveformHitContainer> m_waveformHitContainer
-  //  {this, "WaveformHitContainerKey", ""};
+  SG::WriteHandleKey<WaveformHitContainer> m_waveformHitContainerKey
+    {this, "WaveformHitContainerKey", ""};
   //@}
 
 };
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
new file mode 100644
index 000000000..e53eb3e1b
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
@@ -0,0 +1,17 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef SCINTRECEVENT_WAVEFORMHITCONTAINER_H
+#define SCINTRECEVENT_WAVEFORMHITCONTAINER_H
+
+#include "ScintRecEvent/WaveformHitCollection.h"
+#include "AthContainers/DataVector.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+//
+// Container will WaveformHitCollections from each detector element
+typedef DataVector<WaveformHitCollection> WaveformHitContainer;
+CLASS_DEF(WaveformHitContainer , 1330197509, 1 )
+
+#endif // SCINTRECEVENT_WAVEFORMHITCONTAINER_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
index 709b6d649..405b441b0 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
@@ -1,7 +1,9 @@
 <lcgdict>
-  <class name="WaveformHitCollection" id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
-  <class name="DataVector<WaveformHit>" id="2943c109-26da-48df-b699-c9364d20896b" />
-  <class name="std::vector<WaveformHit*>" />
-  <class name="std::vector<const WaveformHit*>" />
+  <class name="WaveformHitContainer"/>
+  <class name="DataVector<WaveformHitCollection>", id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
+  <class name="std::vector<WaveformHitCollection*>" />
+  <class name="std::vector<const WaveformHitCollection*>" />
+
+  <class name="WaveformHitCollection" />
   <class name="WaveformHit" />
 </lcgdict>
-- 
GitLab


From b13096c89ddea6589b5a3029e58586e3e9c9689a Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Mon, 8 Mar 2021 08:51:58 -0800
Subject: [PATCH 28/47] Add clock reconstruction

---
 .../ScintRecAlgs/src/ScintClockRecAlg.cxx     |  91 ++++++++++++
 .../ScintRecAlgs/src/ScintClockRecAlg.h       |  71 ++++++++++
 .../src/components/ScintRecAlgs_entries.cxx   |   2 +
 .../ScintRecEvent/WaveformClock.h             |  95 +++++++++++++
 .../ScintRecEvent/ScintRecEvent/selection.xml |   2 +
 .../ScintRecEvent/src/WaveformClock.cxx       |  42 ++++++
 .../ScintRecTools/IClockReconstructionTool.h  |  38 +++++
 .../IWaveformReconstructionTool.h             |   4 +-
 .../src/ClockReconstructionTool.cxx           | 134 ++++++++++++++++++
 .../src/ClockReconstructionTool.h             |  50 +++++++
 .../src/WaveformReconstructionTool.cxx        |   4 +-
 .../src/WaveformReconstructionTool.h          |   2 +-
 .../src/components/ScintRecTools_entries.cxx  |   2 +
 13 files changed, 531 insertions(+), 6 deletions(-)
 create mode 100644 Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
 create mode 100644 Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
 create mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
 create mode 100644 Scintillator/ScintRecEvent/src/WaveformClock.cxx
 create mode 100644 Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
 create mode 100644 Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
 create mode 100644 Scintillator/ScintRecTools/src/ClockReconstructionTool.h

diff --git a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
new file mode 100644
index 000000000..cbdb8521e
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
@@ -0,0 +1,91 @@
+#include "ScintClockRecAlg.h"
+
+ScintClockRecAlg::ScintClockRecAlg(const std::string& name, 
+				   ISvcLocator* pSvcLocator)
+  : AthReentrantAlgorithm(name, pSvcLocator) { 
+}
+
+StatusCode 
+ScintClockRecAlg::initialize() {
+  ATH_MSG_INFO(name() << "::initalize()" );
+
+  // Initalize tools
+  ATH_CHECK( m_recoTool.retrieve() );
+
+  // Set key to read waveform from
+  ATH_CHECK( m_waveformContainerKey.initialize() );
+
+  // Set key to write container
+  ATH_CHECK( m_waveformClockKey.initialize() );
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+ScintClockRecAlg::finalize() {
+  ATH_MSG_INFO(name() << "::finalize()");
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+ScintClockRecAlg::execute(const EventContext& ctx) const {
+  ATH_MSG_INFO("Executing");
+
+  ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() 
+		<< " Event: " << ctx.eventID().event_number());
+
+  // Find the input waveform container
+  SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainerKey, ctx);
+
+  ATH_CHECK( waveformHandle.isValid() );
+  ATH_MSG_DEBUG("Found ReadHandle for Waveforms");
+
+  if (waveformHandle->size() == 0) {
+    ATH_MSG_INFO("Waveform container found with zero length!");
+    return StatusCode::SUCCESS;
+  }
+
+  // Check length (should be one)
+  if (waveformHandle->size() != 1) {
+    ATH_MSG_WARNING("Found waveform container " << m_waveformContainerKey 
+		    << " with size " << waveformHandle->size() << "!");
+  }
+
+  // Create the output clock container
+  SG::WriteHandle<WaveformClock> clockHandle(m_waveformClockKey, ctx);
+  ATH_CHECK( clockHandle.record( std::make_unique<WaveformClock>() ) );
+  auto clock = clockHandle.ptr();
+
+  // Reconstruct first element
+  for(const auto& wave : *waveformHandle) {
+
+    ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
+
+    // Make some sanity checks before going further
+    if (wave->adc_counts().size() == 0) {
+      ATH_MSG_ERROR( "Found waveform for channel " << wave->channel() 
+		     << " with size " << wave->adc_counts().size() << "!");
+      // Create dummy hit here, or just skip?
+      return StatusCode::FAILURE;
+    }
+    
+    if (wave->adc_counts().size() != wave->n_samples()) {
+      ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
+		       << " with size " << wave->adc_counts().size() 
+		       << " not equal to number of samples " << wave->n_samples());
+      return StatusCode::SUCCESS;
+    }
+
+    // Reconstruct the hits
+    CHECK( m_recoTool->reconstruct(*wave, clock) );
+
+    // Only do one if there happen to be more
+    break;
+  }
+
+  ATH_MSG_DEBUG(waveformHandle.name() << " created");
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
new file mode 100644
index 000000000..ea0ac1db4
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
@@ -0,0 +1,71 @@
+#ifndef SCINTRECALGS_SCINTCLOCKRECALG_H
+#define SCINTRECALGS_SCINTCLOCKRECALG_H
+
+// Base class
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+
+// Input data
+#include "ScintRawEvent/ScintWaveformContainer.h"
+
+// Output data
+#include "ScintRecEvent/WaveformClock.h"
+
+#include "ScintRecTools/IClockReconstructionTool.h"
+
+#include "StoreGate/ReadHandleKey.h"
+
+// Gaudi
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ToolHandle.h"
+
+// STL
+#include <string>
+
+class ScintClockRecAlg : public AthReentrantAlgorithm {
+
+ public:
+  // Constructor
+  ScintClockRecAlg(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~ScintClockRecAlg() = default;
+
+  /** @name Usual algorithm methods */
+  //@{
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+  //@}
+
+ private:
+
+  /** @name Disallow default instantiation, copy, assignment */
+  //@{
+  ScintClockRecAlg() = delete;
+  ScintClockRecAlg(const ScintClockRecAlg&) = delete;
+  ScintClockRecAlg &operator=(const ScintClockRecAlg&) = delete;
+  //@}
+
+  /**
+   * @name Reconstruction tool
+   */
+  ToolHandle<IClockReconstructionTool> m_recoTool
+    {this, "ClockReconstructionTool", "ClockReconstructionTool"};
+
+  /**
+   * @name Input data using SG::ReadHandleKey
+   */
+  //@{
+  SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainerKey
+    {this, "WaveformContainerKey", "ClockWaveforms"};
+  //@}
+
+  /**
+   * @name Output data using SG::WriteHandleKey
+   */
+  //@{
+  SG::WriteHandleKey<WaveformClock> m_waveformClockKey
+    {this, "WaveformClockKey", "LHCClockData"};
+  //@}
+
+};
+
+#endif // SCINTRECALGS_SCINTCLOCKRECALG_H
diff --git a/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx b/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
index bd3d88daf..9634fc8f9 100644
--- a/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
+++ b/Scintillator/ScintRecAlgs/src/components/ScintRecAlgs_entries.cxx
@@ -1,3 +1,5 @@
 #include "../ScintWaveformRecAlg.h"
+#include "../ScintClockRecAlg.h"
 
 DECLARE_COMPONENT( ScintWaveformRecAlg )
+DECLARE_COMPONENT( ScintClockRecAlg )
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
new file mode 100644
index 000000000..6a670b6d0
--- /dev/null
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
@@ -0,0 +1,95 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// WaveformClock.h
+//   Header file for class WaveformClock
+///////////////////////////////////////////////////////////////////
+// Class to handle reconstructed peaks in waveform data
+///////////////////////////////////////////////////////////////////
+// Version 1.0   2/21/2021 Eric Torrence
+///////////////////////////////////////////////////////////////////
+#ifndef SCINTRECEVENT_WAVEFORMCLOCK_H
+#define SCINTRECEVENT_WAVEFORMCLOCK_H
+
+#include <iostream>
+
+#include "AthenaKernel/CLASS_DEF.h"
+#include "GaudiKernel/DataObject.h"
+
+/**
+ * @class WaveformClock
+ * Class containing reconstructed informtaion for the digitizer clock
+ */
+  
+class WaveformClock : public DataObject {
+      
+ public:
+      
+  /** Default constructor */
+  WaveformClock();
+
+  /** Destructor */
+  virtual ~WaveformClock() = default;
+
+  // move assignment defaulted
+  WaveformClock & operator= (WaveformClock &&) = default;
+  //assignment defaulted
+  WaveformClock & operator= (const WaveformClock &) = default;
+  //copy c'tor defaulted
+  WaveformClock(const WaveformClock &) = default;
+
+  /** Clones */
+  virtual WaveformClock* clone() const ;       
+            
+  // Access functions
+  inline double offset() const {return m_offset;}
+  inline double frequency() const {return m_frequency;}
+  inline double amplitude() const {return m_amplitude;}
+  inline double phase() const {return m_phase;}
+
+  inline double trigger_time() const {return m_trigger_time;}
+
+  // Set functions
+  void setParams(double avg, double freq, double amp, double phase);
+  void setTriggerTime(double time) {m_trigger_time = 2*time;}
+
+  // Time functions
+
+  // Time (in ns) of preceeding clock edge
+  double previousClock(double time) const;
+
+  // Time (in ns) of given time from preceeding clock
+  double timeFromClock(double time) const {return time-previousClock(time);}
+
+  private:
+
+  // Data members
+  // Average of waveform (frequency=0 magnitude) from FFT
+  double m_offset;
+  // Primary frequency
+  double m_frequency;
+  // Amplitude of primary frequency
+  double m_amplitude;
+  // Phase of primary frequency
+  double m_phase;
+  // From raw waveform (but in ns)
+  double m_trigger_time;
+};
+
+std::ostream
+&operator<<(std::ostream &out, const WaveformClock &wfm);
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+inline WaveformClock* 
+WaveformClock::clone() const { 
+  return new WaveformClock(*this);  
+}
+
+CLASS_DEF( WaveformClock, 174305800, 1 )
+
+#endif // SCINTRECEVENT_WAVEFORMCLOCK_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
index 405b441b0..45b5f9c68 100644
--- a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
+++ b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
@@ -6,4 +6,6 @@
 
   <class name="WaveformHitCollection" />
   <class name="WaveformHit" />
+
+  <class name="WaveformClock", id="4ca1c909-45ee-4e68-a4f8-8a02b66b7fa6"/>
 </lcgdict>
diff --git a/Scintillator/ScintRecEvent/src/WaveformClock.cxx b/Scintillator/ScintRecEvent/src/WaveformClock.cxx
new file mode 100644
index 000000000..8ec31fbe0
--- /dev/null
+++ b/Scintillator/ScintRecEvent/src/WaveformClock.cxx
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#include "ScintRecEvent/WaveformClock.h"
+
+#include <cmath>
+
+// Default constructor
+WaveformClock::WaveformClock() {
+}
+
+void
+WaveformClock::setParams(double offset, double freq, double amp, double phase) {
+  m_offset = offset;
+  m_frequency = freq;
+  m_amplitude = amp;
+  m_phase = phase;
+}
+
+double
+WaveformClock::previousClock(double time) const {
+
+  double freq = m_frequency / 1000; // Frequency in GHz
+  // 0.25 accounts for difference in phsae between cos (at top of cycle) and rising edge
+  double dphase = m_phase / (2 * M_PI) + 0.25;  
+  int n_cycle = freq*time + dphase;  
+  double dtime = time - (n_cycle - dphase)/freq;
+  return dtime;
+}
+
+std::ostream
+&operator<<( std::ostream& out, const WaveformClock &c ) {
+  out << "WaveformClock - Freq: " << c.frequency() << " Amp: " 
+      << c.amplitude() << " Phase: " << c.phase() << " DC offset: " << c.offset();
+  return out;
+}
+
+
+
+
+
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
new file mode 100644
index 000000000..4ed97e93e
--- /dev/null
+++ b/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+/**
+ * @file IClockReconstructionTool.h
+ * Header file for the IClockReconstructionTool class
+ * @author Eric Torrence, 2021
+ */
+
+
+#ifndef SCINTRECTOOLS_ICLOCKRECONSTRUCTIONTOOL_H
+#define SCINTRECTOOLS_ICLOCKRECONSTRUCTIONTOOL_H
+
+// Base class
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+
+class ScintWaveform;
+class WaveformClock;
+
+///Interface for Clock reco algorithms
+class IClockReconstructionTool : virtual public IAlgTool 
+{
+  public:
+
+  // InterfaceID
+  DeclareInterfaceID(IClockReconstructionTool, 1, 0);
+
+  virtual ~IClockReconstructionTool() = default;
+
+  // Reconstruct all peaks in a raw waveform
+  virtual StatusCode reconstruct(const ScintWaveform& wave, 
+				 WaveformClock* clockdata) const = 0;
+
+};
+
+#endif // SCINTRECTOOLS_ICLOCKRECONSTRUCTIONTOOL_H
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index 47a763562..871d600c6 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
 */
 
 /**
@@ -14,8 +14,6 @@
 
 // Base class
 #include "GaudiKernel/IAlgTool.h"
-//#include "ScintRawEvent/ScintWaveform.h"
-//#include "ScintRecEvent/WaveformBaselineData.h"
 #include "GaudiKernel/ToolHandle.h"
 
 class ScintWaveform;
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
new file mode 100644
index 000000000..9e9743d9e
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -0,0 +1,134 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+/**
+ * @file ClockReconstructionTool.cxx
+ * Implementation file for the ClockReconstructionTool.cxx
+ * @ author E. Torrence, 2021
+ **/
+
+#include "ClockReconstructionTool.h"
+
+#include "TVirtualFFT.h"
+
+#include <vector>
+
+// Constructor
+ClockReconstructionTool::ClockReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
+  base_class(type, name, parent)
+{
+}
+
+// Initialization
+StatusCode
+ClockReconstructionTool::initialize() {
+  ATH_MSG_INFO( name() << "::initalize()" );
+
+  return StatusCode::SUCCESS;
+}
+
+// Reconstruction step
+StatusCode
+ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
+				     WaveformClock* clockdata) const {
+
+  ATH_MSG_DEBUG("Clock reconstruct called ");
+
+  // Check the output object
+  if (!clockdata) {
+    ATH_MSG_ERROR("WaveformClock passed to reconstruct() is null!");
+    return StatusCode::FAILURE;
+  }
+
+  // Set the trigger time
+  clockdata->setTriggerTime(raw_wave.trigger_time_tag());
+  ATH_MSG_DEBUG("Trigger time: " << raw_wave.trigger_time_tag());
+
+  // Digitized clock data, sampled at 500 MHz (2 ns)
+  auto counts = raw_wave.adc_counts();
+
+  // Need a double array for FFT
+  int N = counts.size();
+  std::vector<double> wave(N);
+  wave.assign(counts.begin(), counts.end());
+
+  ATH_MSG_DEBUG("Created double array with length " << wave.size() );
+  ATH_MSG_DEBUG("First 20 elements:");
+  for (unsigned int i=0; i< 20; i++)
+    ATH_MSG_DEBUG(" " << i << " " << wave[i]);
+
+  // delta_nu = 1/T where T is the total waveform length
+  // Multiplying (freqmult * i) gives the frequency of point i in the FFT
+  double freqmult = 1./(0.002 * N); // 2ns per point, so this is in MHz
+
+  TVirtualFFT *fftr2c = TVirtualFFT::FFT(1, &N, "R2C");
+  fftr2c->SetPoints(&wave[0]);
+  fftr2c->Transform();
+
+  // Get the coefficients
+  std::vector<double> re_full(N);
+  std::vector<double> im_full(N);
+  std::vector<double> magnitude(N/2); 
+  fftr2c->GetPointsComplex(&re_full[0],&im_full[0]);
+
+  // Normalize the magnitude (just using the positive complex frequencies)
+  unsigned int i=0;
+  magnitude[i] = sqrt(pow(re_full[i], 2) + pow(im_full[i], 2))/N;
+  for(i=1; i<magnitude.size(); i++) 
+    magnitude[i] = 2*sqrt(pow(re_full[i], 2) + pow(im_full[i], 2))/N;
+
+  // First, look at the DC offset
+  ATH_MSG_DEBUG("DC offset: " << magnitude[0]);
+
+  // Second, find max value (should be primary line at 40 MHz
+  unsigned int imax = max_element(magnitude.begin()+1, magnitude.end()) - magnitude.begin();
+
+  if (((int(imax)-1) < 0) || ((imax+1) >= magnitude.size())) {
+    ATH_MSG_WARNING("Found maximum frequency amplitude at postion " << imax << "!");
+  } else {
+    ATH_MSG_DEBUG("Magnitude array at peak:");
+    for(i = imax-1; i <= imax+1; i++)
+      ATH_MSG_DEBUG("Index: " << i << " Freq: " << i*freqmult << " Mag: " << magnitude[i]);
+  }
+
+  // Store results
+  double avg = magnitude[0];
+  double freq = imax * freqmult;
+  double amp = magnitude[imax];
+  double phase = atan2(im_full[imax], re_full[imax]);
+  clockdata->setParams(avg, freq, amp, phase); 
+ 
+  ATH_MSG_DEBUG("Before correcting for finite resolution:");
+  ATH_MSG_DEBUG(*clockdata);
+
+  // Correct for the windowing to find the exact peak frequency
+  // Following: https://indico.cern.ch/event/132526/contributions/128902/attachments/99707/142376/Meeting1-06-11_FFT_corrections_for_tune_measurements.pdf
+
+  double dm;  // Fraction of integer frequency where real peak sits
+  if (magnitude[imax+1] >= magnitude[imax-1]) { // Past ipeak by dm
+    dm = magnitude[imax+1] / (magnitude[imax] + magnitude[imax + 1]);
+  } else { // Before ipeak by dm
+    dm = -magnitude[imax-1] / (magnitude[imax-1] + magnitude[imax]);
+  }
+
+  ATH_MSG_DEBUG("Found shift in frequency index: " << dm);
+
+  // Improved values
+  freq = (imax+dm) * freqmult;
+  phase = atan2(im_full[imax], re_full[imax]) - dm * M_PI;
+  // Fix any overflows
+  if (phase < M_PI) phase += (2*M_PI);
+  if (phase > M_PI) phase -= (2*M_PI);
+
+  amp = 2*M_PI*dm*magnitude[imax] / sin(M_PI * dm);
+  clockdata->setParams(avg, freq, amp, phase); 
+
+  ATH_MSG_DEBUG("After correcting for finite resolution:");
+  ATH_MSG_DEBUG(*clockdata);
+
+
+  delete fftr2c;
+
+  return StatusCode::SUCCESS;
+}
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
new file mode 100644
index 000000000..3d04d5ef2
--- /dev/null
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -0,0 +1,50 @@
+/*
+   Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+/** @file ClockReconstructionTool.h
+ *  Header file for ClockReconstructionTool.h
+ *
+ */
+#ifndef SCINTRECTOOLS_CLOCKRECONSTRUCTIONTOOL_H
+#define SCINTRECTOOLS_CLOCKRECONSTRUCTIONTOOL_H
+
+//Athena
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "ScintRecTools/IClockReconstructionTool.h"
+
+#include "ScintRawEvent/ScintWaveform.h"
+#include "ScintRecEvent/WaveformClock.h"
+
+//Gaudi
+#include "GaudiKernel/ToolHandle.h"
+
+//STL
+#include <string>
+#include <vector>
+
+class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTool> {
+ public:
+
+  /// Normal constructor for an AlgTool; 'properties' are also declared here
+  ClockReconstructionTool(const std::string& type, 
+			  const std::string& name, const IInterface* parent);
+
+  /// Retrieve the necessary services in initialize
+  StatusCode initialize();
+
+  /// Reconstruct hits from clock  
+  virtual StatusCode reconstruct(const ScintWaveform& wave,
+				 WaveformClock* clockdata) const;
+
+ private:
+
+  //
+  // Baseline Estimation Parameters
+  //BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", false};
+  //IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40};
+  //FloatProperty m_baselineFitWindow{this, "BaselineFitWindow", 2.};
+
+};
+
+#endif // SCINTRECTOOLS_CLOCKRECONSTRUCTIONTOOL_H
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 023d1749b..3a80dfe71 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -178,8 +178,8 @@ WaveformReconstructionTool::findPeak(WaveformBaselineData& baseline,
 
   // Make a window around this peak, values are in bins, so units of 2ns
   // Ensure our window is within the vector range
-  int lo_edge = (imax + m_windowStart) > 0 ? (imax + m_windowStart) : 0; 
-  int hi_edge = (imax + m_windowStart + m_windowWidth) < wave.size() ? (imax + m_windowStart + m_windowWidth) : wave.size();
+  int lo_edge = ((int(imax) + m_windowStart) >= 0 ? (imax + m_windowStart) : 0); 
+  int hi_edge = ((imax + m_windowStart + m_windowWidth) < wave.size() ? (imax + m_windowStart + m_windowWidth) : wave.size());
   
   ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge);
   windowed_time = std::vector<float> (time.begin()+lo_edge, time.begin()+hi_edge);
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 32407abf4..9cb526924 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -67,7 +67,7 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
  
   //
   // Window to define fitting range, in samples (2ns/sample)
-  IntegerProperty m_windowStart{this, "FitWindowFromPeak", -10};
+  IntegerProperty m_windowStart{this, "FitWindowStart", -10};
   IntegerProperty m_windowWidth{this, "FitWindowWidth", 50};
 
   //
diff --git a/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx b/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx
index a4318588f..a96a42c9b 100644
--- a/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx
+++ b/Scintillator/ScintRecTools/src/components/ScintRecTools_entries.cxx
@@ -1,3 +1,5 @@
+#include "../ClockReconstructionTool.h"
 #include "../WaveformReconstructionTool.h"
 
+DECLARE_COMPONENT( ClockReconstructionTool )
 DECLARE_COMPONENT( WaveformReconstructionTool )
-- 
GitLab


From ab296d42041aeb7a7c690655a81e743bd5ae6335 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 9 Mar 2021 14:40:50 -0800
Subject: [PATCH 29/47] Add waveform data types as xAOD

---
 xAOD/xAODFaserWaveform/CMakeLists.txt         | 26 +++++++++
 .../Root/WaveformClockAuxInfo_v1.cxx          | 18 ++++++
 .../Root/WaveformClock_v1.cxx                 | 35 ++++++++++++
 .../Root/WaveformHitAuxContainer_v1.cxx       | 19 +++++++
 .../xAODFaserWaveform/Root/WaveformHit_v1.cxx | 32 +++++++++++
 .../Root/xAODFaserWaveformCLIDs.cxx           | 10 ++++
 .../xAODFaserWaveform/WaveformClock.h         | 22 ++++++++
 .../xAODFaserWaveform/WaveformClockAuxInfo.h  | 22 ++++++++
 .../xAODFaserWaveform/WaveformHit.h           | 22 ++++++++
 .../WaveformHitAuxContainer.h                 | 22 ++++++++
 .../xAODFaserWaveform/WaveformHitContainer.h  | 22 ++++++++
 .../xAODFaserWaveform/selection.xml           | 24 ++++++++
 .../versions/WaveformClockAuxInfo_v1.h        | 45 +++++++++++++++
 .../versions/WaveformClock_v1.h               | 55 +++++++++++++++++++
 .../versions/WaveformHitAuxContainer_v1.h     | 43 +++++++++++++++
 .../versions/WaveformHitContainer_v1.h        | 26 +++++++++
 .../versions/WaveformHit_v1.h                 | 47 ++++++++++++++++
 .../xAODFaserWaveform/xAODFaserWaveformDict.h | 33 +++++++++++
 18 files changed, 523 insertions(+)
 create mode 100644 xAOD/xAODFaserWaveform/CMakeLists.txt
 create mode 100644 xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
 create mode 100644 xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
 create mode 100644 xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
 create mode 100644 xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
 create mode 100644 xAOD/xAODFaserWaveform/Root/xAODFaserWaveformCLIDs.cxx
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClock.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClockAuxInfo.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHit.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitAuxContainer.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitContainer.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/selection.xml
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitContainer_v1.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
 create mode 100644 xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h

diff --git a/xAOD/xAODFaserWaveform/CMakeLists.txt b/xAOD/xAODFaserWaveform/CMakeLists.txt
new file mode 100644
index 000000000..118525113
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+
+# Declare the package name.
+atlas_subdir( xAODFaserWaveform )
+
+# External dependencies.
+find_package( xAODUtilities )
+
+# Component(s) in the package.
+atlas_add_library( xAODFaserWaveform
+   xAODFaserWaveform/*.h xAODFaserWaveform/versions/*.h Root/*.cxx
+   PUBLIC_HEADERS xAODFaserWaveform
+   LINK_LIBRARIES xAODCore )
+
+atlas_add_xaod_smart_pointer_dicts(
+   INPUT xAODFaserWaveform/selection.xml
+   OUTPUT _selectionFile
+   OBJECTS "xAOD::WaveformClock_v1"
+   CONTAINERS "xAOD::WaveformHitContainer_v1")
+
+atlas_add_dictionary( xAODFaserWaveformDict
+   xAODFaserWaveform/xAODFaserWaveformDict.h
+   ${_selectionFile}
+   LINK_LIBRARIES xAODCore xAODFaserWaveform
+   EXTRA_FILES Root/dict/*.cxx )
+
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
new file mode 100644
index 000000000..c6be98a7b
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
@@ -0,0 +1,18 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h"
+
+namespace xAOD {
+
+  WaveformClockAuxInfo_v1::WaveformClockAuxInfo_v1()
+    : AuxInfoBase(), 
+      frequency(0), phase(0), offset(0), amplitude(0) {
+    AUX_VARIABLE( frequency );
+    AUX_VARIABLE( phase );
+    AUX_VARIABLE( offset );
+    AUX_VARIABLE( amplitude );
+  }
+} // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
new file mode 100644
index 000000000..6a3128d02
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// EDM include(s):
+#include "xAODCore/AuxStoreAccessorMacros.h"
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformClock_v1.h"
+
+namespace xAOD {
+
+  WaveformClock_v1::WaveformClock_v1() : SG::AuxElement() {
+  }
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, frequency, set_frequency )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, phase, set_phase )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, offset, set_offset )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, amplitude, set_amplitude )
+
+} // namespace xAOD
+
+namespace xAOD {
+
+  std::ostream& operator<<(std::ostream& s, const xAOD::WaveformClock_v1& clk) {
+    s << "xAODWaveformClock: frequency=" << clk.frequency()
+      << std::endl;
+
+    return s;
+  }
+
+} // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
new file mode 100644
index 000000000..300fa4d84
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
@@ -0,0 +1,19 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h"
+
+namespace xAOD {
+
+  WaveformHitAuxContainer_v1::WaveformHitAuxContainer_v1() 
+    : AuxContainerBase() {
+
+    AUX_VARIABLE(baseline_mean);
+    AUX_VARIABLE(baseline_rms);
+
+  }
+
+} // namespace xAOD
+
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
new file mode 100644
index 000000000..080946b0e
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// EDM include(s):
+#include "xAODCore/AuxStoreAccessorMacros.h"
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformHit_v1.h"
+
+namespace xAOD {
+
+  WaveformHit_v1::WaveformHit_v1() : SG::AuxElement() {
+  }
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, baseline_mean, set_baseline_mean )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, baseline_rms, set_baseline_rms )
+
+} // namespace xAOD
+
+namespace xAOD {
+
+  std::ostream& operator<<(std::ostream& s, const xAOD::WaveformHit_v1& hit) {
+    s << "xAODWaveformHit: baseline=" << hit.baseline_mean() 
+      << " rms=" << hit.baseline_rms()
+      << std::endl;
+
+    return s;
+  }
+
+} // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/xAODFaserWaveformCLIDs.cxx b/xAOD/xAODFaserWaveform/Root/xAODFaserWaveformCLIDs.cxx
new file mode 100644
index 000000000..acd57bce0
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/xAODFaserWaveformCLIDs.cxx
@@ -0,0 +1,10 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+//simple includes to force the CLASS_DEF etc to be encountered during compile
+
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+#include "xAODFaserWaveform/WaveformHitAuxContainer.h"
+#include "xAODFaserWaveform/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClockAuxInfo.h"
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClock.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClock.h
new file mode 100644
index 000000000..951d21a7a
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClock.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_WAVEFORMCLOCK_H
+#define XAODFASERWAVEFORM_WAVEFORMCLOCK_H
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformClock_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef WaveformClock_v1 WaveformClock;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::WaveformClock, 58376762, 1 )
+
+#endif // XAODFASERWAVEFORM_WAVEFORMCLOCK_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClockAuxInfo.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClockAuxInfo.h
new file mode 100644
index 000000000..5cdc5294f
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformClockAuxInfo.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_WAVEFORMCLOCKAUXINFO_H
+#define XAODFASERWAVEFORM_WAVEFORMCLOCKAUXINFO_H
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef WaveformClockAuxInfo_v1 WaveformClockAuxInfo;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::WaveformClockAuxInfo, 150155999, 1 )
+
+#endif // XAODFASERWAVEFORM_WAVEFORMCLOCKAUXINFO_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHit.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHit.h
new file mode 100644
index 000000000..6f01f4fc4
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHit.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_WAVEFORMHIT_H
+#define XAODFASERWAVEFORM_WAVEFORMHIT_H
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformHit_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef WaveformHit_v1 WaveformHit;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::WaveformHit, 131600577, 1 )
+
+#endif // XAODFASERWAVEFORM_WAVEFORMHIT_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitAuxContainer.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitAuxContainer.h
new file mode 100644
index 000000000..014da4c02
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitAuxContainer.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_WAVEFORMHITAUXCONTAINER_H
+#define XAODFASERWAVEFORM_WAVEFORMHITAUXCONTAINER_H
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef WaveformHitAuxContainer_v1 WaveformHitAuxContainer;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::WaveformHitAuxContainer, 1262669778, 1 )
+
+#endif // XAODFASERWAVEFORM_WAVEFORMHITAUXCONTAINER_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitContainer.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitContainer.h
new file mode 100644
index 000000000..41de79d21
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/WaveformHitContainer.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_WAVEFORMHITCONTAINER_H
+#define XAODFASERWAVEFORM_WAVEFORMHITCONTAINER_H
+
+// Local include(s):
+#include "xAODFaserWaveform/versions/WaveformHitContainer_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef WaveformHitContainer_v1 WaveformHitContainer;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::WaveformHitContainer, 1156844391, 1 )
+
+#endif // XAODFASERWAVEFORM_WAVEFORMHITCONTAINER_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/selection.xml b/xAOD/xAODFaserWaveform/xAODFaserWaveform/selection.xml
new file mode 100644
index 000000000..44146cd55
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/selection.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2020 CERN for the benefit of the FASER collaboration -->
+<lcgdict>
+
+  <class name="xAOD::WaveformHit_v1" />
+  <typedef name="xAOD::WaveformHit" />
+
+  <class name="xAOD::WaveformHitContainer_v1" 
+	 id="fb49e082-7130-462f-9500-de9a2aef8a24" />
+  <typedef name="xAOD::WaveformHitContainer" />
+
+  <class name="xAOD::WaveformHitAuxContainer_v1" 
+	 id="091007bd-f4ab-4862-b905-1a0ed96c962f" />
+  <typedef name="xAOD::WaveformHitAuxContainer" />
+
+  <class name="xAOD::WaveformClock_v1" 
+	 id="461aa5ca-6c72-46ee-b5d5-5bd6df4e2848" />
+  <typedef name="xAOD::WaveformClock" />
+
+  <class name="xAOD::WaveformClockAuxInfo_v1" 
+	 id="fe0600cc-f2f3-4be5-9723-257646dbb8f7" />
+  <typedef name="xAOD::WaveformClockAuxInfo" />
+
+
+</lcgdict>
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
new file mode 100644
index 000000000..74a98b62e
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
@@ -0,0 +1,45 @@
+// Dear emacs, this is -*- c++ -*- 
+
+/* 
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCKAUXINFO_V1_H
+#define XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCKAUXINFO_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// xAOD include(s):
+#include "xAODCore/AuxInfoBase.h"
+
+namespace xAOD {
+
+  /// Class holding the data handled by WaveformClock_v1
+
+  class WaveformClockAuxInfo_v1 : public AuxInfoBase {
+
+  public:
+    /// Default constructor
+    WaveformClockAuxInfo_v1();
+
+  private:
+    /// @name Basic variables
+    ///@ {
+    double frequency;
+    double phase;
+    double offset;
+    double amplitude;
+    ///@}
+
+  }; // class WaveformClockAuxInfo_v1
+
+} // namespace xAOD
+
+// Set up a CLID and StoreGate inheritance for the class:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::WaveformClockAuxInfo_v1, xAOD::AuxInfoBase );
+
+#endif // XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCKAUXINFO_V1_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
new file mode 100644
index 000000000..2d70b976d
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
@@ -0,0 +1,55 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCK_V1_H
+#define XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCK_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// Core EDM include(s):
+#include "AthContainers/AuxElement.h"
+
+namespace xAOD {
+
+  // Cllss describing pulses in the waveform digitizer
+  class WaveformClock_v1 : public SG::AuxElement {
+
+  public:
+    /// Defaullt constructor
+    WaveformClock_v1();
+
+    /// @name Access WaveformClock elements
+    /// @{
+
+    /// Clock Frequency (in MHz)
+    double frequency() const;
+    void set_frequency(double value);
+
+    /// Clock Phase (in Radians)
+    double phase() const;
+    void set_phase(double value);
+
+    /// DC Clock offset
+    double offset() const;
+    void set_offset(double value);
+
+    /// Amplitude of primary freq. component
+    double amplitude() const;
+    void set_amplitude(double value);
+    /// @}
+
+  }; // class WaveformClock_v1
+
+}
+
+// Declare the inheritance of the type:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::WaveformClock_v1, SG::AuxElement );
+
+#endif // XAODFASERWAVEFORM_VERSIONS_WAVEFORMCLOCK_V1_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
new file mode 100644
index 000000000..d4a28ac5f
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
@@ -0,0 +1,43 @@
+// Dear emacs, this is -*- c++ -*-                                              
+
+/*                                                                              
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration            
+*/
+
+#ifndef XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITAUXCONTAINER_V1_H
+#define XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITAUXCONTAINER_V1_H
+
+// STL include(s):
+#include <vector>
+
+// EDM include(s):
+#include "xAODCore/AuxContainerBase.h"
+
+namespace xAOD {
+
+  /// Auxiliary container for WaveformHit containers
+
+  class WaveformHitAuxContainer_v1 : public AuxContainerBase {
+
+  public:
+    /// Default constructor
+    WaveformHitAuxContainer_v1();
+    /// Destructor
+    ~WaveformHitAuxContainer_v1() {}
+
+  private:
+    /// @name Basic variables
+    ///@ {
+    std::vector<float> baseline_mean;
+    std::vector<float> baseline_rms;
+    ///@}
+
+  }; // class WaveformHitAuxContainer_v1
+
+} // namespace xAOD
+
+// Set up a CLID and StoreGate inheritance for the class:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::WaveformHitAuxContainer_v1, xAOD::AuxContainerBase );
+
+#endif // XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITAUXCONTAINER_V1_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitContainer_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitContainer_v1.h
new file mode 100644
index 000000000..180cf9719
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitContainer_v1.h
@@ -0,0 +1,26 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITCONTAINER_V1_H
+#define XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITCONTAINER_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// EDM include(s):
+#include "AthContainers/DataVector.h"
+
+// Local includes:
+#include "xAODFaserWaveform/versions/WaveformHit_v1.h"
+
+namespace xAOD {
+  // Define the container as a simple DataVector
+  typedef DataVector<WaveformHit_v1> WaveformHitContainer_v1;
+}
+
+#endif // XAODFASERWAVEFORM_VERSIONS_WAVEFORMHITCONTAINER_V1_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
new file mode 100644
index 000000000..355b5685b
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
@@ -0,0 +1,47 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_VERSIONS_WAVEFORMHIT_V1_H
+#define XAODFASERWAVEFORM_VERSIONS_WAVEFORMHIT_V1_H
+
+// System include(s):
+extern "C" {
+#   include "stdint.h"
+}
+
+// Core EDM include(s):
+#include "AthContainers/AuxElement.h"
+
+namespace xAOD {
+
+  // Cllss describing pulses in the waveform digitizer
+  class WaveformHit_v1 : public SG::AuxElement {
+
+  public:
+    /// Defaullt constructor
+    WaveformHit_v1();
+
+    /// @name Access WaveformHit elements
+    /// @{
+
+    /// Bsaeline mean
+    float baseline_mean() const;
+    void set_baseline_mean(float value);
+
+    /// Baseline rms
+    float baseline_rms() const;
+    void set_baseline_rms(float value);
+
+  }; // class WaveformHit_v1
+
+}
+
+// Declare the inheritance of the type:
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::WaveformHit_v1, SG::AuxElement );
+
+
+#endif // XAODFASERWAVEFORM_VERSIONS_WAVEFORMHIT_V1_H
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h
new file mode 100644
index 000000000..6ba4a1abd
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORM_XAODFASERWAVEFORMDICT_H
+#define XAODFASERWAVEFORM_XAODFASERWAVEFORMDICT_H
+
+// Local includes
+#include "xAODFaserWaveform/WaveformHit.h"
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+#include "xAODFaserWaveform/WaveformHitAuxContainer.h"
+
+#include "xAODFaserWaveform/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClockAuxInfo.h"
+
+#include "xAODFaserWaveform/versions/WaveformHit_v1.h"
+#include "xAODFaserWaveform/versions/WaveformHitContainer_v1.h"
+#include "xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h"
+
+#include "xAODFaserWaveform/versions/WaveformClock_v1.h"
+#include "xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h"
+
+// EDM include(s).
+#include "xAODCore/tools/DictHelpers.h"
+
+namespace {
+  struct GCCXML_DUMMY_INSTANTIATION_XAODFASERWAVEFORM {
+    XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, WaveformHitContainer_v1 );
+    XAOD_INSTANTIATE_NS_OBJECT_TYPES( xAOD, WaveformClock_v1 );
+  }
+}
+
+#endif // XAODFASERWAVEFORM_XAODFASERWAVEFORMDICT_H
-- 
GitLab


From b85b7fe84b67698ea4633867ae1fb3c74b01ce96 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 9 Mar 2021 16:28:37 -0800
Subject: [PATCH 30/47] Writing WaveformClock as xAOD object works

---
 Scintillator/ScintRecAlgs/CMakeLists.txt      |  2 +-
 .../ScintRecAlgs/src/ScintClockRecAlg.cxx     |  7 +++--
 .../ScintRecAlgs/src/ScintClockRecAlg.h       |  7 +++--
 Scintillator/ScintRecTools/CMakeLists.txt     |  2 +-
 .../ScintRecTools/IClockReconstructionTool.h  |  5 +--
 .../src/ClockReconstructionTool.cxx           | 31 +++++++++----------
 .../src/ClockReconstructionTool.h             |  5 +--
 .../Root/WaveformClock_v1.cxx                 |  3 ++
 .../versions/WaveformClock_v1.h               |  4 ++-
 .../xAODFaserWaveform/xAODFaserWaveformDict.h |  2 +-
 .../CMakeLists.txt                            | 14 +++++++++
 .../src/xAODWaveformClockAuxInfoCnv.cxx       |  5 +++
 .../src/xAODWaveformClockAuxInfoCnv.h         | 15 +++++++++
 .../src/xAODWaveformClockCnv.cxx              |  5 +++
 .../src/xAODWaveformClockCnv.h                | 15 +++++++++
 15 files changed, 93 insertions(+), 29 deletions(-)
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.h
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.h

diff --git a/Scintillator/ScintRecAlgs/CMakeLists.txt b/Scintillator/ScintRecAlgs/CMakeLists.txt
index e4f81b4bb..1cc6650e6 100644
--- a/Scintillator/ScintRecAlgs/CMakeLists.txt
+++ b/Scintillator/ScintRecAlgs/CMakeLists.txt
@@ -9,7 +9,7 @@ atlas_subdir( ScintRecAlgs )
 atlas_add_component( ScintRecAlgs
                      src/*.cxx src/*.h
                      src/components/*.cxx
-                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecEvent ScintRecToolsLib )
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecEvent xAODFaserWaveform ScintRecToolsLib )
 
 #atlas_install_python_modules( python/*.py )
 
diff --git a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
index cbdb8521e..45ceaa30b 100644
--- a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.cxx
@@ -53,8 +53,11 @@ ScintClockRecAlg::execute(const EventContext& ctx) const {
   }
 
   // Create the output clock container
-  SG::WriteHandle<WaveformClock> clockHandle(m_waveformClockKey, ctx);
-  ATH_CHECK( clockHandle.record( std::make_unique<WaveformClock>() ) );
+  SG::WriteHandle<xAOD::WaveformClock> clockHandle(m_waveformClockKey, ctx);
+  //ATH_CHECK( clockHandle.record( std::make_unique<WaveformClock>() ) );
+  ATH_CHECK( clockHandle.record( std::make_unique<xAOD::WaveformClock>(),
+				 std::make_unique<xAOD::WaveformClockAuxInfo>() ) );
+
   auto clock = clockHandle.ptr();
 
   // Reconstruct first element
diff --git a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
index ea0ac1db4..8fb355551 100644
--- a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
@@ -8,8 +8,9 @@
 #include "ScintRawEvent/ScintWaveformContainer.h"
 
 // Output data
-#include "ScintRecEvent/WaveformClock.h"
-
+// #include "ScintRecEvent/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClockAuxInfo.h"
 #include "ScintRecTools/IClockReconstructionTool.h"
 
 #include "StoreGate/ReadHandleKey.h"
@@ -62,7 +63,7 @@ class ScintClockRecAlg : public AthReentrantAlgorithm {
    * @name Output data using SG::WriteHandleKey
    */
   //@{
-  SG::WriteHandleKey<WaveformClock> m_waveformClockKey
+  SG::WriteHandleKey<xAOD::WaveformClock> m_waveformClockKey
     {this, "WaveformClockKey", "LHCClockData"};
   //@}
 
diff --git a/Scintillator/ScintRecTools/CMakeLists.txt b/Scintillator/ScintRecTools/CMakeLists.txt
index 7befc0e44..285298d61 100644
--- a/Scintillator/ScintRecTools/CMakeLists.txt
+++ b/Scintillator/ScintRecTools/CMakeLists.txt
@@ -13,7 +13,7 @@ atlas_add_library( ScintRecToolsLib
                    ScintRecTools/*.h src/*.cxx src/*.h
                    PUBLIC_HEADERS ScintRecTools
                    PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent ScintRecEvent
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent ScintRecEvent xAODFaserWaveform
                    PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES}
 		   )
 
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
index 4ed97e93e..46712a75c 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IClockReconstructionTool.h
@@ -16,8 +16,9 @@
 #include "GaudiKernel/IAlgTool.h"
 #include "GaudiKernel/ToolHandle.h"
 
+#include "xAODFaserWaveform/WaveformClock.h"
+
 class ScintWaveform;
-class WaveformClock;
 
 ///Interface for Clock reco algorithms
 class IClockReconstructionTool : virtual public IAlgTool 
@@ -31,7 +32,7 @@ class IClockReconstructionTool : virtual public IAlgTool
 
   // Reconstruct all peaks in a raw waveform
   virtual StatusCode reconstruct(const ScintWaveform& wave, 
-				 WaveformClock* clockdata) const = 0;
+				 xAOD::WaveformClock* clockdata) const = 0;
 
 };
 
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
index 9e9743d9e..4c065eff5 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -31,7 +31,7 @@ ClockReconstructionTool::initialize() {
 // Reconstruction step
 StatusCode
 ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
-				     WaveformClock* clockdata) const {
+				     xAOD::WaveformClock* clockdata) const {
 
   ATH_MSG_DEBUG("Clock reconstruct called ");
 
@@ -42,8 +42,8 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   }
 
   // Set the trigger time
-  clockdata->setTriggerTime(raw_wave.trigger_time_tag());
-  ATH_MSG_DEBUG("Trigger time: " << raw_wave.trigger_time_tag());
+  //clockdata->setTriggerTime(raw_wave.trigger_time_tag());
+  //ATH_MSG_DEBUG("Trigger time: " << raw_wave.trigger_time_tag());
 
   // Digitized clock data, sampled at 500 MHz (2 ns)
   auto counts = raw_wave.adc_counts();
@@ -54,8 +54,8 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   wave.assign(counts.begin(), counts.end());
 
   ATH_MSG_DEBUG("Created double array with length " << wave.size() );
-  ATH_MSG_DEBUG("First 20 elements:");
-  for (unsigned int i=0; i< 20; i++)
+  ATH_MSG_DEBUG("First 10 elements:");
+  for (unsigned int i=0; i< 10; i++)
     ATH_MSG_DEBUG(" " << i << " " << wave[i]);
 
   // delta_nu = 1/T where T is the total waveform length
@@ -93,12 +93,11 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   }
 
   // Store results
-  double avg = magnitude[0];
-  double freq = imax * freqmult;
-  double amp = magnitude[imax];
-  double phase = atan2(im_full[imax], re_full[imax]);
-  clockdata->setParams(avg, freq, amp, phase); 
- 
+  clockdata->set_offset(magnitude[0]);
+  clockdata->set_frequency(imax * freqmult);
+  clockdata->set_amplitude(magnitude[imax]);
+  clockdata->set_phase(atan2(im_full[imax], re_full[imax]));
+
   ATH_MSG_DEBUG("Before correcting for finite resolution:");
   ATH_MSG_DEBUG(*clockdata);
 
@@ -115,19 +114,19 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   ATH_MSG_DEBUG("Found shift in frequency index: " << dm);
 
   // Improved values
-  freq = (imax+dm) * freqmult;
-  phase = atan2(im_full[imax], re_full[imax]) - dm * M_PI;
+
+  double phase = atan2(im_full[imax], re_full[imax]) - dm * M_PI;
   // Fix any overflows
   if (phase < M_PI) phase += (2*M_PI);
   if (phase > M_PI) phase -= (2*M_PI);
 
-  amp = 2*M_PI*dm*magnitude[imax] / sin(M_PI * dm);
-  clockdata->setParams(avg, freq, amp, phase); 
+  clockdata->set_frequency( (imax+dm) * freqmult );
+  clockdata->set_phase (phase);
+  clockdata->set_amplitude( 2*M_PI*dm*magnitude[imax] / sin(M_PI * dm) );
 
   ATH_MSG_DEBUG("After correcting for finite resolution:");
   ATH_MSG_DEBUG(*clockdata);
 
-
   delete fftr2c;
 
   return StatusCode::SUCCESS;
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
index 3d04d5ef2..c0f667524 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -14,7 +14,8 @@
 #include "ScintRecTools/IClockReconstructionTool.h"
 
 #include "ScintRawEvent/ScintWaveform.h"
-#include "ScintRecEvent/WaveformClock.h"
+//#include "ScintRecEvent/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClock.h"
 
 //Gaudi
 #include "GaudiKernel/ToolHandle.h"
@@ -35,7 +36,7 @@ class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTo
 
   /// Reconstruct hits from clock  
   virtual StatusCode reconstruct(const ScintWaveform& wave,
-				 WaveformClock* clockdata) const;
+				 xAOD::WaveformClock* clockdata) const;
 
  private:
 
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
index 6a3128d02..b875b468f 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
@@ -27,6 +27,9 @@ namespace xAOD {
 
   std::ostream& operator<<(std::ostream& s, const xAOD::WaveformClock_v1& clk) {
     s << "xAODWaveformClock: frequency=" << clk.frequency()
+      << " phase=" << clk.phase()
+      << " amplitude=" << clk.amplitude()
+      << " offset=" << clk.offset()
       << std::endl;
 
     return s;
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
index 2d70b976d..3fffe41c1 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
@@ -46,7 +46,9 @@ namespace xAOD {
 
   }; // class WaveformClock_v1
 
-}
+  std::ostream& operator<<(std::ostream& s, const xAOD::WaveformClock_v1& clk);
+
+} // namespace xAOD
 
 // Declare the inheritance of the type:
 #include "xAODCore/BaseInfo.h"
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h
index 6ba4a1abd..5bb2eceb5 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/xAODFaserWaveformDict.h
@@ -27,7 +27,7 @@ namespace {
   struct GCCXML_DUMMY_INSTANTIATION_XAODFASERWAVEFORM {
     XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, WaveformHitContainer_v1 );
     XAOD_INSTANTIATE_NS_OBJECT_TYPES( xAOD, WaveformClock_v1 );
-  }
+  };
 }
 
 #endif // XAODFASERWAVEFORM_XAODFASERWAVEFORMDICT_H
diff --git a/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt b/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
new file mode 100644
index 000000000..3df3443af
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+
+# Declare the package name.
+atlas_subdir( xAODFaserWaveformAthenaPool )
+
+# Component(s) in the package:
+atlas_add_poolcnv_library( xAODFaserWaveformAthenaPoolPoolCnv
+   src/*.h src/*.cxx
+   FILES xAODFaserWaveform/WaveformClock.h xAODFaserWaveform/WaveformClockAuxInfo.h
+   TYPES_WITH_NAMESPACE xAOD::WaveformClock xAOD::WaveformClockAuxInfo
+   CNV_PFX xAOD
+   LINK_LIBRARIES AthenaPoolCnvSvcLib AthenaPoolUtilities xAODFaserWaveform )
+
+
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
new file mode 100644
index 000000000..2ae946703
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
@@ -0,0 +1,5 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.h b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.h
new file mode 100644
index 000000000..5ac8b4c0d
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.h
@@ -0,0 +1,15 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMCLOCKAUXINFOCNV_H
+#define XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMCLOCKAUXINFOCNV_H
+
+#include "xAODFaserWaveform/WaveformClockAuxInfo.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
+
+typedef T_AthenaPoolAuxContainerCnv<xAOD::WaveformClockAuxInfo> xAODWaveformClockAuxInfoCnv;
+
+#endif // XAODFASERWAVEFORMATHENAPOOL_XAODFASERWAVEFORMCLOCKAUXINFOCNV_H
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
new file mode 100644
index 000000000..2ae946703
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
@@ -0,0 +1,5 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.h b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.h
new file mode 100644
index 000000000..2f591d164
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.h
@@ -0,0 +1,15 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMCLOCKCNV_H
+#define XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMCLOCKCNV_H
+
+#include "xAODFaserWaveform/WaveformClock.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolxAODCnv.h"
+
+typedef T_AthenaPoolxAODCnv<xAOD::WaveformClock> xAODWaveformClockCnv;
+
+#endif // XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMCLOCKCNV_H
-- 
GitLab


From 4c68143c14a26d5260d4c4934c518b7d02e53229 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 10 Mar 2021 00:06:11 -0800
Subject: [PATCH 31/47] Move all reco waveform data to xAOD

---
 Scintillator/ScintRecAlgs/CMakeLists.txt      |   2 +-
 .../ScintRecAlgs/src/ScintClockRecAlg.h       |   2 +-
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  |  37 ++----
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    |  11 +-
 Scintillator/ScintRecEvent/CMakeLists.txt     |  23 ----
 .../ScintRecEvent/ScintRecEventDict.h         |  10 --
 .../ScintRecEvent/WaveformClock.h             |  95 -------------
 .../ScintRecEvent/ScintRecEvent/WaveformHit.h | 125 ------------------
 .../ScintRecEvent/WaveformHitCollection.h     |  27 ----
 .../ScintRecEvent/WaveformHitContainer.h      |  17 ---
 .../ScintRecEvent/ScintRecEvent/selection.xml |  11 --
 .../ScintRecEvent/src/WaveformClock.cxx       |  42 ------
 .../ScintRecEvent/src/WaveformHit.cxx         |  51 -------
 .../src/WaveformHitCollection.cxx             |  14 --
 Scintillator/ScintRecTools/CMakeLists.txt     |   2 +-
 .../IWaveformReconstructionTool.h             |   5 +-
 .../src/ClockReconstructionTool.cxx           |   2 +-
 .../src/WaveformReconstructionTool.cxx        | 110 +++++++++++----
 .../src/WaveformReconstructionTool.h          |   3 +-
 .../Root/WaveformClockAuxInfo_v1.cxx          |   4 +-
 .../Root/WaveformClock_v1.cxx                 |   4 +-
 .../Root/WaveformHitAuxContainer_v1.cxx       |  16 +++
 .../xAODFaserWaveform/Root/WaveformHit_v1.cxx |  34 ++++-
 .../versions/WaveformClockAuxInfo_v1.h        |   2 +-
 .../versions/WaveformClock_v1.h               |   4 +-
 .../versions/WaveformHitAuxContainer_v1.h     |  20 +++
 .../versions/WaveformHit_v1.h                 |  55 ++++++++
 .../CMakeLists.txt                            |   4 +-
 .../src/xAODWaveformClockAuxInfoCnv.cxx       |   1 +
 .../src/xAODWaveformClockCnv.cxx              |   1 +
 .../src/xAODWaveformHitAuxContainerCnv.cxx    |   6 +
 .../src/xAODWaveformHitAuxContainerCnv.h      |  15 +++
 .../src/xAODWaveformHitContainerCnv.cxx       |   6 +
 .../src/xAODWaveformHitContainerCnv.h         |  15 +++
 34 files changed, 283 insertions(+), 493 deletions(-)
 delete mode 100644 Scintillator/ScintRecEvent/CMakeLists.txt
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
 delete mode 100644 Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
 delete mode 100644 Scintillator/ScintRecEvent/src/WaveformClock.cxx
 delete mode 100644 Scintillator/ScintRecEvent/src/WaveformHit.cxx
 delete mode 100644 Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.cxx
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.h
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.cxx
 create mode 100644 xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.h

diff --git a/Scintillator/ScintRecAlgs/CMakeLists.txt b/Scintillator/ScintRecAlgs/CMakeLists.txt
index 1cc6650e6..c7d40ae00 100644
--- a/Scintillator/ScintRecAlgs/CMakeLists.txt
+++ b/Scintillator/ScintRecAlgs/CMakeLists.txt
@@ -9,7 +9,7 @@ atlas_subdir( ScintRecAlgs )
 atlas_add_component( ScintRecAlgs
                      src/*.cxx src/*.h
                      src/components/*.cxx
-                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent ScintRecEvent xAODFaserWaveform ScintRecToolsLib )
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent xAODFaserWaveform ScintRecToolsLib )
 
 #atlas_install_python_modules( python/*.py )
 
diff --git a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
index 8fb355551..3fde8295d 100644
--- a/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintClockRecAlg.h
@@ -64,7 +64,7 @@ class ScintClockRecAlg : public AthReentrantAlgorithm {
    */
   //@{
   SG::WriteHandleKey<xAOD::WaveformClock> m_waveformClockKey
-    {this, "WaveformClockKey", "LHCClockData"};
+    {this, "WaveformClockKey", "WaveformClock"};
   //@}
 
 };
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index 39e20990d..b592dc7d1 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -48,8 +48,10 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
   }
 
   // Find the output waveform container
-  SG::WriteHandle<WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx);
-  ATH_CHECK( hitContainerHandle.record( std::make_unique<WaveformHitContainer>() ) );
+  SG::WriteHandle<xAOD::WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx);
+  ATH_CHECK( hitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(),
+					std::make_unique<xAOD::WaveformHitAuxContainer>() ) );
+
   ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' initialized");
 
   // Reconstruct each waveform
@@ -57,34 +59,13 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
 
     ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
 
-    WaveformHitCollection* collection = new WaveformHitCollection();
-
-    // Make some sanity checks before going further
-    if (wave->adc_counts().size() == 0) {
-      ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
-		       << " with size " << wave->adc_counts().size() << "!");
-      // Create dummy hit here, or just skip?
-      continue;
-    }
-    
-    if (wave->adc_counts().size() != wave->n_samples()) {
-      ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() 
-		       << " with size " << wave->adc_counts().size() 
-		       << " not equal to number of samples " << wave->n_samples());
-      continue;
-    }
-
-    // Reconstruct the hits
-    CHECK( m_recoTool->reconstruct(*wave, collection) );
-
-    // Store collection in container
-    hitContainerHandle->push_back(collection);
-
-    // For now, this is transient
-    // delete collection;
+    // Reconstruct the hits, may be more than one, so pass container
+    CHECK( m_recoTool->reconstruct(*wave, hitContainerHandle.ptr()) );
+
+
   }
 
-  ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' filled with "<< hitContainerHandle->size() <<" collections");
+  ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' filled with "<< hitContainerHandle->size() <<" items");
 
   return StatusCode::SUCCESS;
 }
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
index 2794add30..9c95b084d 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -4,13 +4,18 @@
 // Base class
 #include "AthenaBaseComps/AthReentrantAlgorithm.h"
 
+// Data classes
 #include "ScintRawEvent/ScintWaveformContainer.h"
-#include "ScintRecEvent/WaveformHitCollection.h"
-#include "ScintRecEvent/WaveformHitContainer.h"
+#include "xAODFaserWaveform/WaveformHit.h"
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+#include "xAODFaserWaveform/WaveformHitAuxContainer.h"
 
+// Tool classes
 #include "ScintRecTools/IWaveformReconstructionTool.h"
 
+// Handles
 #include "StoreGate/ReadHandleKey.h"
+#include "StoreGate/WriteHandleKey.h"
 
 // Gaudi
 #include "GaudiKernel/ServiceHandle.h"
@@ -60,7 +65,7 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
    * @name Output data using SG::WriteHandleKey
    */
   //@{
-  SG::WriteHandleKey<WaveformHitContainer> m_waveformHitContainerKey
+  SG::WriteHandleKey<xAOD::WaveformHitContainer> m_waveformHitContainerKey
     {this, "WaveformHitContainerKey", ""};
   //@}
 
diff --git a/Scintillator/ScintRecEvent/CMakeLists.txt b/Scintillator/ScintRecEvent/CMakeLists.txt
deleted file mode 100644
index cddd115ed..000000000
--- a/Scintillator/ScintRecEvent/CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-################################################################################
-# Package: ScintRecEvent
-################################################################################
-
-# Declare the package name:
-atlas_subdir( ScintRecEvent )
-
-# External dependencies:
-find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
-
-# Component(s) in the package:
-atlas_add_library( ScintRecEvent
-                   src/*.cxx src/*.h
-                   PUBLIC_HEADERS ScintRecEvent
-		   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ScintRawEvent)
-
-atlas_add_dictionary( ScintRecEventDict
-		      ScintRecEvent/ScintRecEventDict.h
-		      ScintRecEvent/selection.xml
-                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                      LINK_LIBRARIES ${ROOT_LIBRARIES} AthAllocators CxxUtils StoreGateLib ScintIdentifier ScintRecEvent )
-
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h b/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
deleted file mode 100644
index 9756e42b5..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/ScintRecEventDict.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
-  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef SCINTRECEVENT_SCINTRECEVENTDICT_H
-#define SCINTRECEVENT_SCINTRECEVENTDICT_H
-
-#include "ScintRecEvent/WaveformHitCollection.h"
-
-#endif
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
deleted file mode 100644
index 6a670b6d0..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformClock.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-///////////////////////////////////////////////////////////////////
-// WaveformClock.h
-//   Header file for class WaveformClock
-///////////////////////////////////////////////////////////////////
-// Class to handle reconstructed peaks in waveform data
-///////////////////////////////////////////////////////////////////
-// Version 1.0   2/21/2021 Eric Torrence
-///////////////////////////////////////////////////////////////////
-#ifndef SCINTRECEVENT_WAVEFORMCLOCK_H
-#define SCINTRECEVENT_WAVEFORMCLOCK_H
-
-#include <iostream>
-
-#include "AthenaKernel/CLASS_DEF.h"
-#include "GaudiKernel/DataObject.h"
-
-/**
- * @class WaveformClock
- * Class containing reconstructed informtaion for the digitizer clock
- */
-  
-class WaveformClock : public DataObject {
-      
- public:
-      
-  /** Default constructor */
-  WaveformClock();
-
-  /** Destructor */
-  virtual ~WaveformClock() = default;
-
-  // move assignment defaulted
-  WaveformClock & operator= (WaveformClock &&) = default;
-  //assignment defaulted
-  WaveformClock & operator= (const WaveformClock &) = default;
-  //copy c'tor defaulted
-  WaveformClock(const WaveformClock &) = default;
-
-  /** Clones */
-  virtual WaveformClock* clone() const ;       
-            
-  // Access functions
-  inline double offset() const {return m_offset;}
-  inline double frequency() const {return m_frequency;}
-  inline double amplitude() const {return m_amplitude;}
-  inline double phase() const {return m_phase;}
-
-  inline double trigger_time() const {return m_trigger_time;}
-
-  // Set functions
-  void setParams(double avg, double freq, double amp, double phase);
-  void setTriggerTime(double time) {m_trigger_time = 2*time;}
-
-  // Time functions
-
-  // Time (in ns) of preceeding clock edge
-  double previousClock(double time) const;
-
-  // Time (in ns) of given time from preceeding clock
-  double timeFromClock(double time) const {return time-previousClock(time);}
-
-  private:
-
-  // Data members
-  // Average of waveform (frequency=0 magnitude) from FFT
-  double m_offset;
-  // Primary frequency
-  double m_frequency;
-  // Amplitude of primary frequency
-  double m_amplitude;
-  // Phase of primary frequency
-  double m_phase;
-  // From raw waveform (but in ns)
-  double m_trigger_time;
-};
-
-std::ostream
-&operator<<(std::ostream &out, const WaveformClock &wfm);
-
-///////////////////////////////////////////////////////////////////
-// Inline methods:
-///////////////////////////////////////////////////////////////////
-
-inline WaveformClock* 
-WaveformClock::clone() const { 
-  return new WaveformClock(*this);  
-}
-
-CLASS_DEF( WaveformClock, 174305800, 1 )
-
-#endif // SCINTRECEVENT_WAVEFORMCLOCK_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
deleted file mode 100644
index 26301a933..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHit.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-///////////////////////////////////////////////////////////////////
-// WaveformHit.h
-//   Header file for class WaveformHit
-///////////////////////////////////////////////////////////////////
-// Class to handle reconstructed peaks in waveform data
-///////////////////////////////////////////////////////////////////
-// Version 1.0   2/21/2021 Eric Torrence
-///////////////////////////////////////////////////////////////////
-#ifndef SCINTRECEVENT_WAVEFORMHIT_H
-#define SCINTRECEVENT_WAVEFORMHIT_H
-
-#include <iostream>
-
-#include "AthenaKernel/CLASS_DEF.h"
-
-/**
- * @class WaveformHit
- * Class containing reconstructed informtaion for one waveform hit
- */
-  
-class WaveformHit {
-      
- public:
-      
-  /** Default constructor */
-  WaveformHit();
-
-  /** Destructor */
-  virtual ~WaveformHit() = default;
-
-  // move assignment defaulted
-  WaveformHit & operator= (WaveformHit &&) = default;
-  //assignment defaulted
-  WaveformHit & operator= (const WaveformHit &) = default;
-  //copy c'tor defaulted
-  WaveformHit(const WaveformHit &) = default;
-
-  /** Clones */
-  virtual WaveformHit* clone() const ;       
-            
-  // Access functions
-  inline int channel() const { return m_channel; }
-
-  // Best results (from fit)
-  inline float localtime() const { return m_localtime; }
-  inline float amplitude() const { return m_amplitude; }
-  inline float width() const { return m_width; }
-  inline float integral() const { return m_integral; }
-
-  // Raw values from waveform data
-  inline float raw_amplitude() const { return m_raw_amplitude; }
-  inline float raw_integral() const { return m_raw_integral; }
-
-  // Bsaeline information
-  inline float baseline_mean() const { return m_baseline_mean; }
-  inline float baseline_rms()  const { return m_baseline_rms; }
-
-  // Status informtaion
-  inline bool getStatus(unsigned int bit) const { return (m_status & (1 << bit)); }
-
-  // Set functions
-  void setChannel(unsigned int channel) {m_channel = channel;}
-  void setRawData(const std::vector<float>& time, 
-		  const std::vector<float>& wave);
-
-  void setBaseline(float mean, float rms) {m_baseline_mean = mean; m_baseline_rms = rms;}
-
-  void setRawResults(float peak, float mean, float width, float integral);
-  void setFitResults(float peak, float mean, float width, float integral);
-  void setCBResults(float alpha, float nval);
-
-  void setLocaltime(float time) { m_localtime = time; }
-  void setStatus(unsigned int bit) {m_status |= (1 << bit);}
-
-  private:
-
-  // Data members
-  unsigned int m_channel;
-  unsigned int m_status;
-
-  // Raw values from waveform
-  float m_raw_amplitude;
-  float m_raw_mean;
-  float m_raw_width;
-  float m_raw_integral;
-
-  // Best values from fit
-  float m_localtime;
-  float m_amplitude;
-  float m_mean;
-  float m_width;
-  float m_integral;
-  float m_alpha;
-  float m_nval;
-
-  // Baseline information
-  float m_baseline_mean;
-  float m_baseline_rms;
-
-  // Raw fit data
-  std::vector<float> m_timevec;
-  std::vector<float> m_wavevec;
-
-  // Fit informtaion
-};
-
-std::ostream
-&operator<<(std::ostream &out, const WaveformHit &wfm);
-
-///////////////////////////////////////////////////////////////////
-// Inline methods:
-///////////////////////////////////////////////////////////////////
-
-inline WaveformHit* 
-WaveformHit::clone() const { 
-  return new WaveformHit(*this);  
-}
-
-CLASS_DEF( WaveformHit, 140632415, 1 )
-
-#endif // SCINTRECEVENT_WAVEFORMHIT_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
deleted file mode 100644
index d947a9005..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitCollection.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
-#define SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
-
-#include "ScintRecEvent/WaveformHit.h"
-#include "AthContainers/DataVector.h"
-#include "AthenaKernel/CLASS_DEF.h"
-
-// Make this a class in case we need to add some functions
-class WaveformHitCollection : public DataVector<WaveformHit> {
- public:
-  unsigned int channel;
-  float baseline_mean;
-  float baseline_rms;
-  void print() const;
-};
-
-std::ostream 
-&operator<<(std::ostream &out, const WaveformHitCollection &collection);
-
-CLASS_DEF(WaveformHitCollection, 1228273893, 1 )
-SG_BASE(WaveformHitCollection, DataVector<WaveformHit>);
-
-#endif // SCINTRECEVENT_WAVEFORMHITCOLLECTION_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h b/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
deleted file mode 100644
index e53eb3e1b..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/WaveformHitContainer.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef SCINTRECEVENT_WAVEFORMHITCONTAINER_H
-#define SCINTRECEVENT_WAVEFORMHITCONTAINER_H
-
-#include "ScintRecEvent/WaveformHitCollection.h"
-#include "AthContainers/DataVector.h"
-#include "AthenaKernel/CLASS_DEF.h"
-
-//
-// Container will WaveformHitCollections from each detector element
-typedef DataVector<WaveformHitCollection> WaveformHitContainer;
-CLASS_DEF(WaveformHitContainer , 1330197509, 1 )
-
-#endif // SCINTRECEVENT_WAVEFORMHITCONTAINER_H
diff --git a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml b/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
deleted file mode 100644
index 45b5f9c68..000000000
--- a/Scintillator/ScintRecEvent/ScintRecEvent/selection.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<lcgdict>
-  <class name="WaveformHitContainer"/>
-  <class name="DataVector<WaveformHitCollection>", id="860e5caa-2d26-4b6a-9c40-b4c196974faa" />
-  <class name="std::vector<WaveformHitCollection*>" />
-  <class name="std::vector<const WaveformHitCollection*>" />
-
-  <class name="WaveformHitCollection" />
-  <class name="WaveformHit" />
-
-  <class name="WaveformClock", id="4ca1c909-45ee-4e68-a4f8-8a02b66b7fa6"/>
-</lcgdict>
diff --git a/Scintillator/ScintRecEvent/src/WaveformClock.cxx b/Scintillator/ScintRecEvent/src/WaveformClock.cxx
deleted file mode 100644
index 8ec31fbe0..000000000
--- a/Scintillator/ScintRecEvent/src/WaveformClock.cxx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-#include "ScintRecEvent/WaveformClock.h"
-
-#include <cmath>
-
-// Default constructor
-WaveformClock::WaveformClock() {
-}
-
-void
-WaveformClock::setParams(double offset, double freq, double amp, double phase) {
-  m_offset = offset;
-  m_frequency = freq;
-  m_amplitude = amp;
-  m_phase = phase;
-}
-
-double
-WaveformClock::previousClock(double time) const {
-
-  double freq = m_frequency / 1000; // Frequency in GHz
-  // 0.25 accounts for difference in phsae between cos (at top of cycle) and rising edge
-  double dphase = m_phase / (2 * M_PI) + 0.25;  
-  int n_cycle = freq*time + dphase;  
-  double dtime = time - (n_cycle - dphase)/freq;
-  return dtime;
-}
-
-std::ostream
-&operator<<( std::ostream& out, const WaveformClock &c ) {
-  out << "WaveformClock - Freq: " << c.frequency() << " Amp: " 
-      << c.amplitude() << " Phase: " << c.phase() << " DC offset: " << c.offset();
-  return out;
-}
-
-
-
-
-
diff --git a/Scintillator/ScintRecEvent/src/WaveformHit.cxx b/Scintillator/ScintRecEvent/src/WaveformHit.cxx
deleted file mode 100644
index a0670f225..000000000
--- a/Scintillator/ScintRecEvent/src/WaveformHit.cxx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
-*/
-
-#include "ScintRecEvent/WaveformHit.h"
-
-// Default constructor
-WaveformHit::WaveformHit() {
-  m_timevec.clear();
-  m_wavevec.clear();
-}
-
-void 
-WaveformHit::setRawData(const std::vector<float>& time,
-			const std::vector<float>& wave) {
-  m_timevec = time;
-  m_wavevec = wave;
-}
-
-void
-WaveformHit::setRawResults(float peak, float mean, float width, float integral) {
-  m_raw_amplitude = peak;
-  m_raw_mean = mean;
-  m_raw_width = width;
-  m_raw_integral = integral;
-}
-
-void
-WaveformHit::setFitResults(float peak, float mean, float width, float integral) {
-  m_amplitude = peak;
-  m_mean = mean;
-  m_width = width;
-  m_integral = integral;
-}
-
-void
-WaveformHit::setCBResults(float alpha, float nval) {
-  m_alpha = alpha;
-  m_nval = nval;
-}
-
-std::ostream
-&operator<<( std::ostream& out, const WaveformHit &hit ) {
-  out << "WaveformHit - Time: " << hit.localtime() << ", Amplitude: " << hit.amplitude() << std::endl;
-  return out;
-}
-
-
-
-
-
diff --git a/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx b/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
deleted file mode 100644
index 8714f17f4..000000000
--- a/Scintillator/ScintRecEvent/src/WaveformHitCollection.cxx
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "ScintRecEvent/WaveformHitCollection.h"
-
-void
-WaveformHitCollection::print() const {
-  std::cout << "WaveformHit collection with size=" << this->size() << std::endl;
-  for(auto wfm: *this) std::cout << *wfm;
-}
-
-std::ostream
-&operator<<(std::ostream &out, const WaveformHitCollection& cont) {
-  out << "WaveformHit collection with size=" << cont.size() << std::endl;
-  for(auto wfm: cont) out << *wfm;
-  return out;
-}
diff --git a/Scintillator/ScintRecTools/CMakeLists.txt b/Scintillator/ScintRecTools/CMakeLists.txt
index 285298d61..174249e45 100644
--- a/Scintillator/ScintRecTools/CMakeLists.txt
+++ b/Scintillator/ScintRecTools/CMakeLists.txt
@@ -13,7 +13,7 @@ atlas_add_library( ScintRecToolsLib
                    ScintRecTools/*.h src/*.cxx src/*.h
                    PUBLIC_HEADERS ScintRecTools
                    PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent ScintRecEvent xAODFaserWaveform
+                   LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives ScintRawEvent xAODFaserWaveform
                    PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES}
 		   )
 
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index 871d600c6..bd81b6d04 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -16,8 +16,9 @@
 #include "GaudiKernel/IAlgTool.h"
 #include "GaudiKernel/ToolHandle.h"
 
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+
 class ScintWaveform;
-class WaveformHitCollection;
 
 ///Interface for Waveform reco algorithms
 class IWaveformReconstructionTool : virtual public IAlgTool 
@@ -31,7 +32,7 @@ class IWaveformReconstructionTool : virtual public IAlgTool
 
   // Reconstruct all peaks in a raw waveform
   virtual StatusCode reconstruct(const ScintWaveform& wave, 
-				 WaveformHitCollection* collection) const = 0;
+				 xAOD::WaveformHitContainer* container) const = 0;
 
 };
 
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
index 4c065eff5..92442bed4 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -93,7 +93,7 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   }
 
   // Store results
-  clockdata->set_offset(magnitude[0]);
+  clockdata->set_dc_offset(magnitude[0]);
   clockdata->set_frequency(imax * freqmult);
   clockdata->set_amplitude(magnitude[imax]);
   clockdata->set_phase(atan2(im_full[imax], re_full[imax]));
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 3a80dfe71..d8bdcb213 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -10,6 +10,8 @@
 
 #include "WaveformReconstructionTool.h"
 
+#include "xAODFaserWaveform/WaveformHit.h"
+
 #include "TH1F.h"
 #include "TF1.h"
 #include "TFitResult.h"
@@ -41,17 +43,45 @@ WaveformReconstructionTool::initialize() {
 // Reconstruction step
 StatusCode
 WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
-					WaveformHitCollection* collection) const {
+					xAOD::WaveformHitContainer* container) const {
 
   ATH_MSG_DEBUG(" reconstruct called ");
 
-  // Check the collection
-  if (!collection) {
+  // Check the container
+  if (!container) {
     ATH_MSG_ERROR("WaveformHitCollection passed to reconstruct() is null!");
     return StatusCode::FAILURE;
   }
+
+  //
+  // We always want to create at least one hit, so create it here
+  xAOD::WaveformHit* hit = new xAOD::WaveformHit();
+  container->push_back(hit);
+  hit->set_channel(raw_wave.channel());
+
+  //
+  // Make some sanity checks on the waveform data
+  if (raw_wave.adc_counts().size() == 0) {
+    ATH_MSG_WARNING( "Found waveform for channel " << raw_wave.channel() 
+		     << " with size " << raw_wave.adc_counts().size() << "!");
+
+    // Set flag here!!!!
+    // hit->set_status_bit(INVALID_WAVEFORM);
+    return StatusCode::SUCCESS;
+  }
+    
+  if (raw_wave.adc_counts().size() != raw_wave.n_samples()) {
+    ATH_MSG_WARNING( "Found waveform for channel " << raw_wave.channel() 
+		     << " with size " << raw_wave.adc_counts().size() 
+		     << " not equal to number of samples " << raw_wave.n_samples());
+
+    // Set flag here!!!!
+    // hit->set_status_bit(INVALID_WAVEFORM);
+    return StatusCode::SUCCESS;
+  }
+
   // Set channel
-  collection->channel = raw_wave.channel();
+  hit->set_channel(raw_wave.channel());
 
   //
   // Find baseline
@@ -65,16 +95,17 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   if (!(baseline.valid)) {
     ATH_MSG_WARNING("Failed to reconstruct baseline!");
 
-    // Store some default values
-    collection->baseline_mean = 0.;
-    collection->baseline_rms = -1.;
+    hit->set_baseline_mean(0.);
+    hit->set_baseline_rms(-1.);
+    // Set flag here!!!
+    // hit->set_status_bit(BASELINE_FAILED);
 
     return StatusCode::SUCCESS;
   }
 
   // Save baseline to hit collection object
-  collection->baseline_mean = baseline.mean;
-  collection->baseline_rms = baseline.rms;
+  hit->set_baseline_mean(baseline.mean);
+  hit->set_baseline_rms(baseline.rms);
 
   //
   // Create baseline-subtracted data array for both time and signal
@@ -89,6 +120,8 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
   for (auto& element : wave)
     element = baseline.mean - element;
 
+  bool first = true;
+
   // Now we iteratively find peaks and fit
   while(true) {
 
@@ -102,35 +135,53 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     // If we do find a significant peak, fill the window
     if (! findPeak(baseline, time, wave, wtime, wwave) ) break;
 
+    //
+    // Create new hit to fill
+    if (!first) {
+      hit = new xAOD::WaveformHit();
+      container->push_back(hit);
+    }
+    first = false;
+
     //
     // Save windowed waveform to Hit object
-    WaveformHit* hit = new WaveformHit();
-    hit->setChannel(raw_wave.channel());
-    hit->setRawData(wtime, wwave);
-    hit->setBaseline(baseline.mean, baseline.rms);
+    hit->set_channel(raw_wave.channel());
+    hit->set_baseline_mean(baseline.mean);
+    hit->set_baseline_rms(baseline.rms);
+    hit->set_time_vector(wtime);
+    hit->set_wave_vector(wave);
 
     //
     // Find some raw values
     WaveformFitResult raw = findRawHitValues(wtime, wwave);
-    hit->setRawResults(raw.peak, raw.mean, raw.sigma, raw.integral);
-    hit->setLocaltime(raw.time);
+    hit->set_peak(raw.peak);
+    hit->set_mean(raw.mean);
+    hit->set_width(raw.sigma);
+    hit->set_integral(raw.integral);
+    hit->set_localtime(raw.mean);
+    hit->set_raw_peak(raw.peak);
+    hit->set_raw_integral(raw.integral);
 
     //
     // Perform Gaussian fit to waveform
     WaveformFitResult gfit = fitGaussian(raw, wtime, wwave);
     if (! gfit.valid) {
       ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
-      // hit->setStatus(GAUSS_FIT_FAILED);
+      // hit->set_status_bit(GAUSS_FIT_FAILED);
     } 
-    // Fit results (or raw if it failed
-    hit->setFitResults(gfit.peak, gfit.mean, gfit.sigma, gfit.integral);
-    hit->setLocaltime(gfit.time);
+
+    // Fit results (or raw if it failed)
+    hit->set_peak(gfit.peak);
+    hit->set_mean(gfit.mean);
+    hit->set_width(gfit.sigma);
+    hit->set_integral(gfit.integral);
+    hit->set_localtime(gfit.time);
 
     //
     // Check for overflow
     if (m_removeOverflow && findOverflow(baseline, wtime, wwave)) {
       ATH_MSG_INFO("Found waveform overflow");
-      // hit->setStatus(OVERFLOW);
+      //hit->set_status_bit(OVERFLOW);
     }
 
     //
@@ -139,21 +190,24 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     if (! cbfit.valid) {
       ATH_MSG_WARNING("CrystalBall fit failed!");
       // Still have gaussian parameters as an estimate
-      // hit->setStatus(CB_FIT_FAILED);
+      // hit->set_status_bit(CBFIT_FAILED);
     } else {
-      hit->setFitResults(cbfit.peak, cbfit.mean, cbfit.sigma, cbfit.integral);
-      hit->setCBResults(cbfit.alpha, cbfit.nval);
-      hit->setLocaltime(cbfit.time);
+      hit->set_peak(cbfit.peak);
+      hit->set_mean(cbfit.mean);
+      hit->set_width(cbfit.sigma);
+      hit->set_integral(cbfit.integral);
+      hit->set_localtime(cbfit.time);
+
+      hit->set_alpha(cbfit.alpha);
+      hit->set_nval(cbfit.nval);
     }
 
-    collection->push_back(hit);
-  
     if (! m_findMultipleHits) break;
 
   } // End of loop over waveform data
 
-  ATH_MSG_DEBUG( "WaveformReconstructionTool created collection for channel " 
-		 << collection->channel << " with size= " << collection->size());
+  ATH_MSG_DEBUG( "WaveformReconstructionTool finished for channel " 
+		 << raw_wave.channel() << " container size= " << container->size());
 
   return StatusCode::SUCCESS;
 }
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 9cb526924..71db72582 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -14,7 +14,6 @@
 #include "ScintRecTools/IWaveformReconstructionTool.h"
 
 #include "ScintRawEvent/ScintWaveform.h"
-#include "ScintRecEvent/WaveformHitCollection.h"
 
 #include "WaveformBaselineData.h"
 #include "WaveformFitResult.h"
@@ -39,7 +38,7 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
   /// Reconstruct hits from waveform
   
   virtual StatusCode reconstruct(const ScintWaveform& wave,
-				 WaveformHitCollection* collection) const;
+				 xAOD::WaveformHitContainer* container) const;
 
  private:
 
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
index c6be98a7b..61d5dc8e8 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClockAuxInfo_v1.cxx
@@ -9,10 +9,10 @@ namespace xAOD {
 
   WaveformClockAuxInfo_v1::WaveformClockAuxInfo_v1()
     : AuxInfoBase(), 
-      frequency(0), phase(0), offset(0), amplitude(0) {
+      frequency(0), phase(0), dc_offset(0), amplitude(0) {
     AUX_VARIABLE( frequency );
     AUX_VARIABLE( phase );
-    AUX_VARIABLE( offset );
+    AUX_VARIABLE( dc_offset );
     AUX_VARIABLE( amplitude );
   }
 } // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
index b875b468f..4d4e7c3d0 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
@@ -17,7 +17,7 @@ namespace xAOD {
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, phase, set_phase )
 
-  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, offset, set_offset )
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, dc_offset, set_dc_offset )
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, amplitude, set_amplitude )
 
@@ -29,7 +29,7 @@ namespace xAOD {
     s << "xAODWaveformClock: frequency=" << clk.frequency()
       << " phase=" << clk.phase()
       << " amplitude=" << clk.amplitude()
-      << " offset=" << clk.offset()
+      << " offset=" << clk.dc_offset()
       << std::endl;
 
     return s;
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
index 300fa4d84..76aed5624 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx
@@ -10,9 +10,25 @@ namespace xAOD {
   WaveformHitAuxContainer_v1::WaveformHitAuxContainer_v1() 
     : AuxContainerBase() {
 
+    AUX_VARIABLE(channel);
+    AUX_VARIABLE(localtime);
+    AUX_VARIABLE(peak);
+    AUX_VARIABLE(width);
+    AUX_VARIABLE(integral);
+    AUX_VARIABLE(bcid_time);
+    AUX_VARIABLE(raw_peak);
+    AUX_VARIABLE(raw_integral);
+
     AUX_VARIABLE(baseline_mean);
     AUX_VARIABLE(baseline_rms);
 
+    AUX_VARIABLE(status);
+    AUX_VARIABLE(mean);
+    AUX_VARIABLE(alpha);
+    AUX_VARIABLE(nval);
+    AUX_VARIABLE(time_vector);
+    AUX_VARIABLE(wave_vector);
+
   }
 
 } // namespace xAOD
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
index 080946b0e..1b6b2ba92 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
@@ -13,17 +13,47 @@ namespace xAOD {
   WaveformHit_v1::WaveformHit_v1() : SG::AuxElement() {
   }
 
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, channel, set_channel )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, localtime, set_localtime )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, peak, set_peak )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, width, set_width )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, integral, set_integral )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, bcid_time, set_bcid_time )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, raw_peak, set_raw_peak )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, raw_integral, set_raw_integral )
+
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, baseline_mean, set_baseline_mean )
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, baseline_rms, set_baseline_rms )
 
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, status, set_status )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, mean, set_mean )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, alpha, set_alpha )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, nval, set_nval )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, std::vector<float>, time_vector, set_time_vector )
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, std::vector<float>, wave_vector, set_wave_vector )
+
+
 } // namespace xAOD
 
 namespace xAOD {
 
   std::ostream& operator<<(std::ostream& s, const xAOD::WaveformHit_v1& hit) {
-    s << "xAODWaveformHit: baseline=" << hit.baseline_mean() 
-      << " rms=" << hit.baseline_rms()
+    s << "xAODWaveformHit: channel=" << hit.channel()
+      << " local time=" << hit.localtime()
+      << " peak=" << hit.peak()
       << std::endl;
 
     return s;
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
index 74a98b62e..24741e247 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClockAuxInfo_v1.h
@@ -30,7 +30,7 @@ namespace xAOD {
     ///@ {
     double frequency;
     double phase;
-    double offset;
+    double dc_offset;
     double amplitude;
     ///@}
 
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
index 3fffe41c1..8e2f94ae5 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
@@ -36,8 +36,8 @@ namespace xAOD {
     void set_phase(double value);
 
     /// DC Clock offset
-    double offset() const;
-    void set_offset(double value);
+    double dc_offset() const;
+    void set_dc_offset(double value);
 
     /// Amplitude of primary freq. component
     double amplitude() const;
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
index d4a28ac5f..0ea61b39a 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h
@@ -28,8 +28,28 @@ namespace xAOD {
   private:
     /// @name Basic variables
     ///@ {
+    std::vector<unsigned int> channel;
+    std::vector<float> localtime;
+    std::vector<float> peak;
+    std::vector<float> width;
+    std::vector<float> integral;
+    std::vector<float> bcid_time;
+
+    std::vector<float> raw_peak;
+    std::vector<float> raw_integral;
+
     std::vector<float> baseline_mean;
     std::vector<float> baseline_rms;
+
+    std::vector<unsigned int> status;
+
+    std::vector<float> mean;
+    std::vector<float> alpha;
+    std::vector<float> nval;
+
+    std::vector<std::vector<float>> time_vector;
+    std::vector<std::vector<float>> wave_vector;
+
     ///@}
 
   }; // class WaveformHitAuxContainer_v1
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
index 355b5685b..71f692c65 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
@@ -12,6 +12,8 @@ extern "C" {
 #   include "stdint.h"
 }
 
+#include <vector>
+
 // Core EDM include(s):
 #include "AthContainers/AuxElement.h"
 
@@ -27,6 +29,34 @@ namespace xAOD {
     /// @name Access WaveformHit elements
     /// @{
 
+    /// Waveform channel
+    unsigned int channel() const;
+    void set_channel(unsigned int value);
+
+    /// Best results
+    float localtime() const;
+    void set_localtime(float value);
+
+    float peak() const;
+    void set_peak(float value);
+
+    float width() const;
+    void set_width(float value);
+
+    float integral() const;
+    void set_integral(float value);
+
+    /// Time from previous clock edge
+    float bcid_time() const;
+    void set_bcid_time(float value);
+
+    /// Raw values from waveform
+    float raw_peak() const;
+    void set_raw_peak(float value);
+
+    float raw_integral() const;
+    void set_raw_integral(float value);
+
     /// Bsaeline mean
     float baseline_mean() const;
     void set_baseline_mean(float value);
@@ -35,8 +65,33 @@ namespace xAOD {
     float baseline_rms() const;
     void set_baseline_rms(float value);
 
+    /// Status word
+    unsigned int status() const;
+    void set_status(unsigned int value);
+
+    /// Other fit results
+    float mean() const;
+    void set_mean(float value);
+
+    /// Crystal Ball fit parameters
+    float alpha() const;
+    void set_alpha(float value);
+
+    float nval() const;
+    void set_nval(float value);
+
+    /// Raw time and waveform data
+    std::vector<float> time_vector() const;
+    void set_time_vector(std::vector<float> value);
+
+    std::vector<float> wave_vector() const;
+    void set_wave_vector(std::vector<float> value);
+
+    /// @}
+
   }; // class WaveformHit_v1
 
+  std::ostream& operator<<(std::ostream& s, const xAOD::WaveformHit_v1& hit);
 }
 
 // Declare the inheritance of the type:
diff --git a/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt b/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
index 3df3443af..99f9ee00f 100644
--- a/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
+++ b/xAOD/xAODFaserWaveformAthenaPool/CMakeLists.txt
@@ -6,8 +6,8 @@ atlas_subdir( xAODFaserWaveformAthenaPool )
 # Component(s) in the package:
 atlas_add_poolcnv_library( xAODFaserWaveformAthenaPoolPoolCnv
    src/*.h src/*.cxx
-   FILES xAODFaserWaveform/WaveformClock.h xAODFaserWaveform/WaveformClockAuxInfo.h
-   TYPES_WITH_NAMESPACE xAOD::WaveformClock xAOD::WaveformClockAuxInfo
+   FILES xAODFaserWaveform/WaveformClock.h xAODFaserWaveform/WaveformClockAuxInfo.h xAODFaserWaveform/WaveformHitContainer.h xAODFaserWaveform/WaveformHitAuxContainer.h
+   TYPES_WITH_NAMESPACE xAOD::WaveformClock xAOD::WaveformClockAuxInfo xAOD::WaveformHitContainer xAOD::WaveformHitAuxContainer
    CNV_PFX xAOD
    LINK_LIBRARIES AthenaPoolCnvSvcLib AthenaPoolUtilities xAODFaserWaveform )
 
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
index 2ae946703..b5024b1ae 100644
--- a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockAuxInfoCnv.cxx
@@ -3,3 +3,4 @@
 */
 
 // Dummy source file so that cmake will know this is a custom converter.
+// xAODWaveformClockAuxInfoCnv.cxx
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
index 2ae946703..a175dccc7 100644
--- a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformClockCnv.cxx
@@ -3,3 +3,4 @@
 */
 
 // Dummy source file so that cmake will know this is a custom converter.
+// xAODWaveformClockCnv.cxx
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.cxx
new file mode 100644
index 000000000..31d86ebb8
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.cxx
@@ -0,0 +1,6 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
+// xAODWaveformHitAuxContainerCnv.cxx
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.h b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.h
new file mode 100644
index 000000000..bffe321a4
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitAuxContainerCnv.h
@@ -0,0 +1,15 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMHITAUXCONTAINERCNV_H
+#define XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMHITAUXCONTAINERCNV_H
+
+#include "xAODFaserWaveform/WaveformHitAuxContainer.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
+
+typedef T_AthenaPoolAuxContainerCnv<xAOD::WaveformHitAuxContainer> xAODWaveformHitAuxContainerCnv;
+
+#endif // XAODFASERWAVEFORMATHENAPOOL_XAODFASERWAVEFORMHITAUXCONTAINERCNV_H
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.cxx b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.cxx
new file mode 100644
index 000000000..2cd6731a4
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.cxx
@@ -0,0 +1,6 @@
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
+// xAODWaveformHitContainerCnv.cxx
diff --git a/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.h b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.h
new file mode 100644
index 000000000..770bb1625
--- /dev/null
+++ b/xAOD/xAODFaserWaveformAthenaPool/src/xAODWaveformHitContainerCnv.h
@@ -0,0 +1,15 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMHITCONTAINERCNV_H
+#define XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMHITCONTAINERCNV_H
+
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolxAODCnv.h"
+
+typedef T_AthenaPoolxAODCnv<xAOD::WaveformHitContainer> xAODWaveformHitContainerCnv;
+
+#endif // XAODFASERWAVEFORMATHENAPOOL_XAODWAVEFORMHITCONTAINERCNV_H
-- 
GitLab


From a29d0b6948127610be3c02c09b8d32582e7b1853 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 10 Mar 2021 20:26:39 -0800
Subject: [PATCH 32/47] First full working version of xAOD waveforms

---
 Scintillator/ScintRecAlgs/CMakeLists.txt      |  2 +-
 .../python/.#ScintRecAlgsConfig.py            |  1 +
 .../ScintRecAlgs/python/ScintRecAlgsConfig.py | 70 +++++++++++++++++++
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx  | 15 +++-
 .../ScintRecAlgs/src/ScintWaveformRecAlg.h    | 14 +++-
 Scintillator/ScintRecTools/CMakeLists.txt     |  1 +
 .../IWaveformReconstructionTool.h             |  2 +
 .../src/ClockReconstructionTool.h             |  1 -
 .../src/WaveformReconstructionTool.cxx        | 30 +++++---
 .../src/WaveformReconstructionTool.h          |  1 +
 .../Root/WaveformClock_v1.cxx                 |  9 +++
 .../xAODFaserWaveform/Root/WaveformHit_v1.cxx |  1 -
 .../versions/WaveformClock_v1.h               |  4 ++
 .../versions/WaveformHit_v1.h                 | 33 +++++++++
 14 files changed, 167 insertions(+), 17 deletions(-)
 create mode 120000 Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py
 create mode 100644 Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py

diff --git a/Scintillator/ScintRecAlgs/CMakeLists.txt b/Scintillator/ScintRecAlgs/CMakeLists.txt
index c7d40ae00..7ad177617 100644
--- a/Scintillator/ScintRecAlgs/CMakeLists.txt
+++ b/Scintillator/ScintRecAlgs/CMakeLists.txt
@@ -11,5 +11,5 @@ atlas_add_component( ScintRecAlgs
                      src/components/*.cxx
                      LINK_LIBRARIES AthenaBaseComps StoreGateLib ScintRawEvent xAODFaserWaveform ScintRecToolsLib )
 
-#atlas_install_python_modules( python/*.py )
+atlas_install_python_modules( python/*.py )
 
diff --git a/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py b/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py
new file mode 120000
index 000000000..16827f33c
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py
@@ -0,0 +1 @@
+torrence@hepatl34.uoregon.edu.3044685:1603878194
\ No newline at end of file
diff --git a/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
new file mode 100644
index 000000000..2d50faa8a
--- /dev/null
+++ b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
@@ -0,0 +1,70 @@
+""" Define methods used to instantiate configured Waveform reconstruction tools and algorithms
+
+Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+"""
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+
+WaveformReconstructionTool = CompFactory.WaveformReconstructionTool
+ClockReconstructionTool = CompFactory.ClockReconstructionTool
+
+# One stop shopping for normal FASER data
+def WaveformReconstructionCfg(flags):
+    """ Return all algorithms and tools for Waveform reconstruction """
+    acc = ComponentAccumulator()
+
+    acc.merge(WaveformClockRecCfg(flags, "ClockRecAlg"))
+
+    acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto"))
+    acc.merge(WaveformHitRecCfg(flags, "TimingWaveformRecAlg", "Trigger"))
+    acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower"))
+    acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo"))
+    return acc
+
+# Return configured WaveformClock reconstruction algorithm
+def WaveformClockRecCfg(flags, name="ClockRecAlg", **kwargs):
+
+    acc = ComponentAccumulator()
+
+    tool = ClockReconstructionTool(name="ClockReconstructionTool")
+
+    kwargs.setdefault("ClockReconstructionTool", tool)
+
+    recoAlg = CompFactory.ScintClockRecAlg(name, **kwargs)
+    recoAlg.ClockReconstructionTool = tool
+    acc.addEventAlgo(recoAlg)
+
+    return acc
+
+# Return configured WaveformHit reconstruction algorithm
+# Specify data source (Veto, Trigger, Preshower, Calo, Test)
+def WaveformHitRecCfg(flags, name="WaveformRecAlg", source="", **kwargs):
+
+    acc = ComponentAccumulator()
+
+    tool = WaveformReconstructionTool(name=source+"WaveformRecTool", **kwargs)
+    kwargs.setdefault("WaveformContainerKey", source+"Waveforms")
+    kwargs.setdefault("WaveformHitContainerKey", source+"WaveformHits")
+    kwargs.setdefault("WaveformReconstructionTool", tool)
+              
+    recoAlg = CompFactory.ScintWaveformRecAlg(name, **kwargs)
+    recoAlg.WaveformReconstructionTool = tool
+    acc.addEventAlgo(recoAlg)
+
+    return acc
+
+def WaveformReconstructionOutputCfg(flags, **kwargs):
+    """ Return ComponentAccumulator with output for Waveform Reco"""
+    acc = ComponentAccumulator()
+    ItemList = [
+        "xAOD::WaveformHitContainer#*"
+        , "xAOD::WaveformHitAuxContainer#*"
+        , "xAOD::WaveformClock#*"
+        , "xAOD::WaveformClockAuxInfo#*"
+    ]
+    acc.merge(OutputStreamCfg(flags, "RDO", ItemList))
+    ostream = acc.getEventAlgo("OutputStreamRDO")
+    # ostream.TakeItemsFromInput = True # Don't know what this does
+    return acc
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index b592dc7d1..e3d42247e 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -16,6 +16,9 @@ ScintWaveformRecAlg::initialize() {
   // Set key to read waveform from
   ATH_CHECK( m_waveformContainerKey.initialize() );
 
+  // Set key to read clock info
+  ATH_CHECK( m_clockKey.initialize() );
+
   // Set key to write container
   ATH_CHECK( m_waveformHitContainerKey.initialize() );
 
@@ -40,13 +43,19 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
   SG::ReadHandle<ScintWaveformContainer> waveformHandle(m_waveformContainerKey, ctx);
 
   ATH_CHECK( waveformHandle.isValid() );
-  ATH_MSG_DEBUG("Found ReadHandle for Waveforms");
+  ATH_MSG_DEBUG("Found ReadHandle for ScintWaveformContainer " << m_waveformContainerKey);
 
   if (waveformHandle->size() == 0) {
     ATH_MSG_INFO("Waveform container found with zero length!");
     return StatusCode::SUCCESS;
   }
 
+  // Also find the clock information
+  SG::ReadHandle<xAOD::WaveformClock> clockHandle(m_clockKey, ctx);
+
+  ATH_CHECK( clockHandle.isValid() );
+  ATH_MSG_DEBUG("Found ReadHandle for WaveformClock");
+
   // Find the output waveform container
   SG::WriteHandle<xAOD::WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx);
   ATH_CHECK( hitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(),
@@ -60,8 +69,8 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
     ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
 
     // Reconstruct the hits, may be more than one, so pass container
-    CHECK( m_recoTool->reconstruct(*wave, hitContainerHandle.ptr()) );
-
+    CHECK( m_recoTool->reconstruct(*wave, clockHandle.ptr(), 
+				   hitContainerHandle.ptr()) );
 
   }
 
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
index 9c95b084d..7d43e9752 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.h
@@ -6,6 +6,10 @@
 
 // Data classes
 #include "ScintRawEvent/ScintWaveformContainer.h"
+
+#include "xAODFaserWaveform/WaveformClock.h"
+#include "xAODFaserWaveform/WaveformClockAuxInfo.h"
+
 #include "xAODFaserWaveform/WaveformHit.h"
 #include "xAODFaserWaveform/WaveformHitContainer.h"
 #include "xAODFaserWaveform/WaveformHitAuxContainer.h"
@@ -54,13 +58,21 @@ class ScintWaveformRecAlg : public AthReentrantAlgorithm {
     {this, "WaveformReconstructionTool", "WaveformReconstructionTool"};
 
   /**
-   * @name Input data using SG::ReadHandleKey
+   * @name Input raw waveform data using SG::ReadHandleKey
    */
   //@{
   SG::ReadHandleKey<ScintWaveformContainer> m_waveformContainerKey
     {this, "WaveformContainerKey", ""};
   //@}
 
+  /**
+   * @name Input WaveformClock data using SG::ReadHandleKey
+   */
+  //@{
+  SG::ReadHandleKey<xAOD::WaveformClock> m_clockKey
+    {this, "WaveformClockKey", "WaveformClock"};
+  //@}
+
   /**
    * @name Output data using SG::WriteHandleKey
    */
diff --git a/Scintillator/ScintRecTools/CMakeLists.txt b/Scintillator/ScintRecTools/CMakeLists.txt
index 174249e45..a128a7384 100644
--- a/Scintillator/ScintRecTools/CMakeLists.txt
+++ b/Scintillator/ScintRecTools/CMakeLists.txt
@@ -22,3 +22,4 @@ atlas_add_component( ScintRecTools
 		     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
                      LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel ScintRecToolsLib )
 
+
diff --git a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
index bd81b6d04..00218de1c 100644
--- a/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/ScintRecTools/IWaveformReconstructionTool.h
@@ -17,6 +17,7 @@
 #include "GaudiKernel/ToolHandle.h"
 
 #include "xAODFaserWaveform/WaveformHitContainer.h"
+#include "xAODFaserWaveform/WaveformClock.h"
 
 class ScintWaveform;
 
@@ -32,6 +33,7 @@ class IWaveformReconstructionTool : virtual public IAlgTool
 
   // Reconstruct all peaks in a raw waveform
   virtual StatusCode reconstruct(const ScintWaveform& wave, 
+				 const xAOD::WaveformClock* clock, 
 				 xAOD::WaveformHitContainer* container) const = 0;
 
 };
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
index c0f667524..c7f76d6b6 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -14,7 +14,6 @@
 #include "ScintRecTools/IClockReconstructionTool.h"
 
 #include "ScintRawEvent/ScintWaveform.h"
-//#include "ScintRecEvent/WaveformClock.h"
 #include "xAODFaserWaveform/WaveformClock.h"
 
 //Gaudi
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index d8bdcb213..037cde512 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -43,6 +43,7 @@ WaveformReconstructionTool::initialize() {
 // Reconstruction step
 StatusCode
 WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
+					const xAOD::WaveformClock* clock, 
 					xAOD::WaveformHitContainer* container) const {
 
   ATH_MSG_DEBUG(" reconstruct called ");
@@ -65,8 +66,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     ATH_MSG_WARNING( "Found waveform for channel " << raw_wave.channel() 
 		     << " with size " << raw_wave.adc_counts().size() << "!");
 
-    // Set flag here!!!!
-    // hit->set_status_bit(INVALID_WAVEFORM);
+    hit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_MISSING);
     return StatusCode::SUCCESS;
   }
     
@@ -75,8 +75,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 		     << " with size " << raw_wave.adc_counts().size() 
 		     << " not equal to number of samples " << raw_wave.n_samples());
 
-    // Set flag here!!!!
-    // hit->set_status_bit(INVALID_WAVEFORM);
+    hit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID);
     return StatusCode::SUCCESS;
   }
 
@@ -97,8 +96,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
     hit->set_baseline_mean(0.);
     hit->set_baseline_rms(-1.);
-    // Set flag here!!!
-    // hit->set_status_bit(BASELINE_FAILED);
+    hit->set_status_bit(xAOD::WaveformStatus::BASELINE_FAILED);
 
     return StatusCode::SUCCESS;
   }
@@ -133,13 +131,17 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
     // All done if we don't have any peaks above threshold
     // If we do find a significant peak, fill the window
-    if (! findPeak(baseline, time, wave, wtime, wwave) ) break;
+    if (! findPeak(baseline, time, wave, wtime, wwave) ) {
+      if (first) hit->set_status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED);
+      break;
+    }
 
     //
     // Create new hit to fill
     if (!first) {
       hit = new xAOD::WaveformHit();
       container->push_back(hit);
+      hit->set_status_bit(xAOD::WaveformStatus::SECONDARY);
     }
     first = false;
 
@@ -167,7 +169,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     WaveformFitResult gfit = fitGaussian(raw, wtime, wwave);
     if (! gfit.valid) {
       ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
-      // hit->set_status_bit(GAUSS_FIT_FAILED);
+      hit->set_status_bit(xAOD::WaveformStatus::GFIT_FAILED);
     } 
 
     // Fit results (or raw if it failed)
@@ -181,7 +183,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     // Check for overflow
     if (m_removeOverflow && findOverflow(baseline, wtime, wwave)) {
       ATH_MSG_INFO("Found waveform overflow");
-      //hit->set_status_bit(OVERFLOW);
+      hit->set_status_bit(xAOD::WaveformStatus::WAVE_OVERFLOW);
     }
 
     //
@@ -190,7 +192,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     if (! cbfit.valid) {
       ATH_MSG_WARNING("CrystalBall fit failed!");
       // Still have gaussian parameters as an estimate
-      // hit->set_status_bit(CBFIT_FAILED);
+      hit->set_status_bit(xAOD::WaveformStatus::CBFIT_FAILED);
     } else {
       hit->set_peak(cbfit.peak);
       hit->set_mean(cbfit.mean);
@@ -202,6 +204,14 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
       hit->set_nval(cbfit.nval);
     }
 
+    //
+    // Find time from clock
+    if (!clock) {
+      hit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID);
+    } else {
+      hit->set_bcid_time(clock->time_from_clock(hit->localtime()));
+    }
+
     if (! m_findMultipleHits) break;
 
   } // End of loop over waveform data
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 71db72582..45a1e9c79 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -38,6 +38,7 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
   /// Reconstruct hits from waveform
   
   virtual StatusCode reconstruct(const ScintWaveform& wave,
+				 const xAOD::WaveformClock* clock,
 				 xAOD::WaveformHitContainer* container) const;
 
  private:
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
index 4d4e7c3d0..04498ccc8 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformClock_v1.cxx
@@ -21,6 +21,15 @@ namespace xAOD {
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformClock_v1, double, amplitude, set_amplitude )
 
+  float WaveformClock_v1::time_from_clock(float time) const {
+    // Figure out which integer cycle we are on, must add 1/4 of a cycle
+    // because FFT finds phase of cosine, which would be middle of 
+    // clock HI region.  frequency is in MHz, so convert here to GHz
+    int ncycle = int(time*frequency() / 1.E3 + phase() / (2*M_PI) + 0.25);
+    float dt = time - (ncycle - phase() / (2*M_PI) - 0.25) * 1.E3 / frequency();
+    return dt;
+  }
+
 } // namespace xAOD
 
 namespace xAOD {
diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
index 1b6b2ba92..4d4ce2789 100644
--- a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
+++ b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx
@@ -45,7 +45,6 @@ namespace xAOD {
 
   AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, std::vector<float>, wave_vector, set_wave_vector )
 
-
 } // namespace xAOD
 
 namespace xAOD {
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
index 8e2f94ae5..437b3ecab 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformClock_v1.h
@@ -42,6 +42,10 @@ namespace xAOD {
     /// Amplitude of primary freq. component
     double amplitude() const;
     void set_amplitude(double value);
+
+    /// Distance of time (in ns) from previous rising clock edge
+    float time_from_clock(float time) const;
+
     /// @}
 
   }; // class WaveformClock_v1
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
index 71f692c65..976c51512 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
@@ -19,6 +19,19 @@ extern "C" {
 
 namespace xAOD {
 
+  // Meaning of status bits
+  enum WaveformStatus {
+    THRESHOLD_FAILED=0,  // No hit found over threshold
+    SECONDARY,           // Second or more hit found in raw waveform
+    WAVE_OVERFLOW,       // Overflows removed from fit
+    BASELINE_FAILED,     // Baseline determination failed
+    GFIT_FAILED,         // Gaussian fit failed
+    CBFIT_FAILED,        // CrystalBall fit failed
+    CLOCK_INVALID,
+    WAVEFORM_MISSING,    // Input waveform data missing
+    WAVEFORM_INVALID     // Input waveform data length mismatch
+  };
+
   // Cllss describing pulses in the waveform digitizer
   class WaveformHit_v1 : public SG::AuxElement {
 
@@ -87,6 +100,26 @@ namespace xAOD {
     std::vector<float> wave_vector() const;
     void set_wave_vector(std::vector<float> value);
 
+    /// Status bit access functions
+    void set_status_bit(WaveformStatus bit) {
+      this->set_status(this->status() | (1<<bit));
+    }
+    bool status_bit(WaveformStatus bit) const {
+      return (this->status() | (1<<bit));
+    }
+
+    bool threshold() const {
+      return !(this->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED));
+    }
+
+    bool overflow() const {
+      return (this->status_bit(xAOD::WaveformStatus::WAVE_OVERFLOW));
+    }
+
+    bool secondary() const {
+      return this->status_bit(xAOD::WaveformStatus::SECONDARY);
+    }
+
     /// @}
 
   }; // class WaveformHit_v1
-- 
GitLab


From e211f7a42817b5438ef88d16685ee8615ff4ead3 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 10 Mar 2021 20:27:43 -0800
Subject: [PATCH 33/47] First full working version of xAOD waveforms

---
 Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py | 1 -
 1 file changed, 1 deletion(-)
 delete mode 120000 Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py

diff --git a/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py b/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py
deleted file mode 120000
index 16827f33c..000000000
--- a/Scintillator/ScintRecAlgs/python/.#ScintRecAlgsConfig.py
+++ /dev/null
@@ -1 +0,0 @@
-torrence@hepatl34.uoregon.edu.3044685:1603878194
\ No newline at end of file
-- 
GitLab


From 02f6b2442a1f03405e8023cdf774c843edb51cdf Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 10 Mar 2021 21:42:27 -0800
Subject: [PATCH 34/47] Forgot this

---
 xAOD/xAODFaserWaveform/Root/dict/ContainerProxies.cxx | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 xAOD/xAODFaserWaveform/Root/dict/ContainerProxies.cxx

diff --git a/xAOD/xAODFaserWaveform/Root/dict/ContainerProxies.cxx b/xAOD/xAODFaserWaveform/Root/dict/ContainerProxies.cxx
new file mode 100644
index 000000000..5ef691ac9
--- /dev/null
+++ b/xAOD/xAODFaserWaveform/Root/dict/ContainerProxies.cxx
@@ -0,0 +1,8 @@
+// EDM include(s):
+#include "xAODCore/AddDVProxy.h"
+
+// Local include(s):
+#include "xAODFaserWaveform/WaveformHitContainer.h"
+
+// Set up the collection proxies:
+ADD_NS_DV_PROXY( xAOD, WaveformHitContainer );
-- 
GitLab


From f5e2f7d92f97efaf94dc2b040d65aa60c96e550e Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 11 Mar 2021 14:33:28 -0800
Subject: [PATCH 35/47] Fix config for xAOD output

---
 Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
index 2d50faa8a..6319e9a01 100644
--- a/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
+++ b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
@@ -64,7 +64,7 @@ def WaveformReconstructionOutputCfg(flags, **kwargs):
         , "xAOD::WaveformClock#*"
         , "xAOD::WaveformClockAuxInfo#*"
     ]
-    acc.merge(OutputStreamCfg(flags, "RDO", ItemList))
-    ostream = acc.getEventAlgo("OutputStreamRDO")
+    acc.merge(OutputStreamCfg(flags, "xAOD", ItemList))
+    # ostream = acc.getEventAlgo("OutputStreamRDO")
     # ostream.TakeItemsFromInput = True # Don't know what this does
     return acc
-- 
GitLab


From 8b7193fab5f381af655f3f7b91ee2f70dd6bbd90 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 12 Mar 2021 13:07:11 -0800
Subject: [PATCH 36/47] Fix crashes with zero-length containers

---
 .../src/ScintWaveformDecoderTool.cxx               |  6 +++---
 .../src/ScintWaveformContainerCnv_p0.cxx           |  6 ++++++
 .../ScintRecAlgs/src/ScintWaveformRecAlg.cxx       | 14 ++++++++++----
 .../ScintRecTools/src/ClockReconstructionTool.cxx  | 13 +++++++++++--
 .../ScintRecTools/src/ClockReconstructionTool.h    |  8 ++++----
 .../src/WaveformReconstructionTool.cxx             |  3 ++-
 6 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
index 55c9bd960..d7012c138 100644
--- a/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
+++ b/Scintillator/ScintEventCnv/ScintByteStream/src/ScintWaveformDecoderTool.cxx
@@ -100,11 +100,11 @@ ScintWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
   }
 
   if (!digitizer) {
-    ATH_MSG_ERROR("Failed to find TLB fragment in raw event!");
-    return StatusCode::FAILURE;
+    ATH_MSG_WARNING("Failed to find digitizer fragment in raw event!");
+    return StatusCode::SUCCESS;
   }
 
-  // Check validity here
+  // Check validity here, try to continue, as perhaps not all channels are bad
   if (!digitizer->valid()) {
     ATH_MSG_WARNING("Found invalid digitizer fragment:\n" << *digitizer);
   } else {
diff --git a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
index 4312a0303..55ce336f6 100644
--- a/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
+++ b/Scintillator/ScintEventCnv/ScintEventAthenaPool/src/ScintWaveformContainerCnv_p0.cxx
@@ -39,6 +39,12 @@ ScintWaveformContainerCnv_p0::transToPers(const ScintWaveformContainer* transCon
 
   log << MSG::DEBUG << "ScintWaveformContainerCnv_p0::transToPers preparing " << transCont->size() << " waveforms" << endmsg;
 
+  // If trans container is empty, nothing else to do
+  if (!transCont->size()) {
+    log << MSG::DEBUG << "ScintWaveformContainerCnv_p0::transToPers found empty container, exiting!" << endmsg;
+    return;
+  }
+
   ScintWaveformCnv_p0 waveformCnv;
 
   typedef ScintWaveformContainer TRANS;
diff --git a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
index e3d42247e..36d05aa36 100644
--- a/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
+++ b/Scintillator/ScintRecAlgs/src/ScintWaveformRecAlg.cxx
@@ -52,9 +52,15 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
 
   // Also find the clock information
   SG::ReadHandle<xAOD::WaveformClock> clockHandle(m_clockKey, ctx);
-
-  ATH_CHECK( clockHandle.isValid() );
-  ATH_MSG_DEBUG("Found ReadHandle for WaveformClock");
+  const xAOD::WaveformClock* clockptr = NULL;
+
+  // Can survive without this, but make a note
+  if ( clockHandle.isValid() ) {
+    ATH_MSG_DEBUG("Found ReadHandle for WaveformClock");
+    clockptr = clockHandle.ptr();
+  } else {
+    ATH_MSG_WARNING("Didn't find ReadHandle for WaveformClock!");
+  }
 
   // Find the output waveform container
   SG::WriteHandle<xAOD::WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx);
@@ -69,7 +75,7 @@ ScintWaveformRecAlg::execute(const EventContext& ctx) const {
     ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel());
 
     // Reconstruct the hits, may be more than one, so pass container
-    CHECK( m_recoTool->reconstruct(*wave, clockHandle.ptr(), 
+    CHECK( m_recoTool->reconstruct(*wave, clockptr, 
 				   hitContainerHandle.ptr()) );
 
   }
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
index 92442bed4..15a3e5f3b 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -41,13 +41,22 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     return StatusCode::FAILURE;
   }
 
-  // Set the trigger time
+  // Invalid value until we know we are OK
+  clockdata->set_frequency(-1.);
+
+  // Can we determine the actual BCID we triggered in?
   //clockdata->setTriggerTime(raw_wave.trigger_time_tag());
   //ATH_MSG_DEBUG("Trigger time: " << raw_wave.trigger_time_tag());
 
   // Digitized clock data, sampled at 500 MHz (2 ns)
   auto counts = raw_wave.adc_counts();
 
+  // Check that we have some minimal amount of data to work with
+  if (int(counts.size()) <= m_minimumSamples.value()) {
+    ATH_MSG_WARNING("Found clock waveform with length " << counts.size() << "! Not enough data to continue!");
+    return StatusCode::SUCCESS;
+  }
+
   // Need a double array for FFT
   int N = counts.size();
   std::vector<double> wave(N);
@@ -55,7 +64,7 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
   ATH_MSG_DEBUG("Created double array with length " << wave.size() );
   ATH_MSG_DEBUG("First 10 elements:");
-  for (unsigned int i=0; i< 10; i++)
+  for (unsigned int i=0; i < std::min(10, N); i++)
     ATH_MSG_DEBUG(" " << i << " " << wave[i]);
 
   // delta_nu = 1/T where T is the total waveform length
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
index c7f76d6b6..0b52229e2 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -40,10 +40,10 @@ class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTo
  private:
 
   //
-  // Baseline Estimation Parameters
-  //BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", false};
-  //IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40};
-  //FloatProperty m_baselineFitWindow{this, "BaselineFitWindow", 2.};
+  // Parameters
+
+  /// Minimum samples in the input waveform array to try FFT
+  IntegerProperty m_minimumSamples{this, "MinimumSamples", 40};
 
 };
 
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 037cde512..657371165 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -206,8 +206,9 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
     //
     // Find time from clock
-    if (!clock) {
+    if (!clock || (clock->frequency() <= 0.)) {
       hit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID);
+      hit->set_bcid_time(-1.);
     } else {
       hit->set_bcid_time(clock->time_from_clock(hit->localtime()));
     }
-- 
GitLab


From a136d2611ac009f55405cf1aa53967e3bdfd32c8 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 16 Mar 2021 00:45:29 -0700
Subject: [PATCH 37/47] Add reading of xrootd files

---
 Event/FaserByteStreamPlugins/CMakeLists.txt   |  43 +++++
 .../FaserByteStreamPlugins/src/fReadDavix.cxx | 163 ++++++++++++++++++
 Event/FaserByteStreamPlugins/src/fReadDavix.h |  40 +++++
 .../src/fReadPlain.cxx                        |   0
 .../src/fReadPlain.h                          |   0
 .../src/fReadXRootD.cxx                       | 114 ++++++++++++
 .../FaserByteStreamPlugins/src/fReadXRootD.h  |  31 ++++
 Event/FaserEventStorage/CMakeLists.txt        |   9 +-
 .../src/pickFaserDataReader.cxx               |  24 +--
 9 files changed, 402 insertions(+), 22 deletions(-)
 create mode 100644 Event/FaserByteStreamPlugins/CMakeLists.txt
 create mode 100644 Event/FaserByteStreamPlugins/src/fReadDavix.cxx
 create mode 100644 Event/FaserByteStreamPlugins/src/fReadDavix.h
 rename Event/{FaserEventStorage => FaserByteStreamPlugins}/src/fReadPlain.cxx (100%)
 rename Event/{FaserEventStorage => FaserByteStreamPlugins}/src/fReadPlain.h (100%)
 create mode 100644 Event/FaserByteStreamPlugins/src/fReadXRootD.cxx
 create mode 100644 Event/FaserByteStreamPlugins/src/fReadXRootD.h

diff --git a/Event/FaserByteStreamPlugins/CMakeLists.txt b/Event/FaserByteStreamPlugins/CMakeLists.txt
new file mode 100644
index 000000000..a340d06c4
--- /dev/null
+++ b/Event/FaserByteStreamPlugins/CMakeLists.txt
@@ -0,0 +1,43 @@
+################################################################################
+# Package: FaserByteStreamPlugins
+################################################################################
+
+# Declare the package name:
+atlas_subdir( FaserByteStreamPlugins )
+
+# External dependencies:
+find_package( tdaq-common COMPONENTS ers EventStorage )
+find_package( Boost COMPONENTS system )
+find_package( Xrootd COMPONENTS Posix PosixPreload )
+find_package( Davix )
+
+# Make sure that libraries are linked correctly:
+atlas_disable_as_needed()
+
+atlas_add_library( fReadXRootD
+   src/fReadXRootD.h src/fReadXRootD.cxx
+   NO_PUBLIC_HEADERS
+   PRIVATE_INCLUDE_DIRS FaserEventStorage ${TDAQ-COMMON_INCLUDE_DIRS} 
+   ${XROOTD_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
+   PRIVATE_LINK_LIBRARIES FaserEventStorageLib ${TDAQ-COMMON_LIBRARIES} 
+   ${XROOTD_LIBRARIES} ${Boost_LIBRARIES}
+   PRIVATE_DEFINITIONS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+   -D_FILE_OFFSET_BITS=64 )
+
+atlas_add_library( fReadPlain 
+   src/fReadPlain.h src/fReadPlain.cxx 
+   NO_PUBLIC_HEADERS
+   PRIVATE_INCLUDE_DIRS FaserEventStorage ${TDAQ-COMMON_INCLUDE_DIRS} 
+   ${Boost_INCLUDE_DIRS}
+   PRIVATE_LINK_LIBRARIES FaserEventStorageLib ${TDAQ-COMMON_LIBRARIES} 
+   ${Boost_LIBRARIES})
+
+atlas_add_library( fReadDavix
+   src/fReadDavix.h src/fReadDavix.cxx
+   NO_PUBLIC_HEADERS
+   PRIVATE_INCLUDE_DIRS FaserEventStorage ${TDAQ-COMMON_INCLUDE_DIRS}
+   ${DAVIX_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
+   PRIVATE_LINK_LIBRARIES FaserEventStorageLib ${TDAQ-COMMON_LIBRARIES} 
+   ${DAVIX_LIBRARIES} ${Boost_LIBRARIES} )
+
+
diff --git a/Event/FaserByteStreamPlugins/src/fReadDavix.cxx b/Event/FaserByteStreamPlugins/src/fReadDavix.cxx
new file mode 100644
index 000000000..9d36e4780
--- /dev/null
+++ b/Event/FaserByteStreamPlugins/src/fReadDavix.cxx
@@ -0,0 +1,163 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "ers/ers.h"
+#include <fcntl.h>
+
+#include "fReadDavix.h"
+#include "EventStorage/EventStorageIssues.h"
+
+// http://dmc-docs.web.cern.ch/dmc-docs/docs/davix-epel/html/lib-examples.html
+// https://root.cern.ch/doc/master/TDavixFile_8cxx_source.html
+
+static int TDavixFile_http_authn_cert_X509(void *userdata, const Davix::SessionInfo &info, Davix::X509Credential *cert, Davix::DavixError **err) {
+
+  (void) userdata; // keep quiete compilation warnings
+  (void) info;
+  // user proxy
+  std::string ucert, ukey;
+  if ( std::getenv("X509_USER_PROXY")) {
+    ucert = ukey = std::getenv("X509_USER_PROXY");
+  }
+  
+  if (ucert.empty() || ukey.empty()) {
+    Davix::DavixError::setupError(err, "fReadDavix.cxx",
+				  Davix::StatusCode::AuthentificationError,
+				  "Could not set the user's proxy or certificate");
+    return -1;
+  }
+  return cert->loadFromFilePEM(ukey, ucert, "", err);
+}
+
+fReadDavix::fReadDavix()
+{
+  m_pfd = 0;
+  m_offset = 0;
+  m_fd = nullptr;
+
+  m_davixParam = new Davix::RequestParams();
+  m_err = NULL;
+  m_pos = new Davix::DavPosix(&m_c);
+  //m_pos = &m_c;
+
+
+  // enableGridMode
+  const char *env_var = NULL;
+  if( ( env_var = std::getenv("X509_CERT_DIR")) == NULL){
+    env_var = "/etc/grid-security/certificates/";
+  }
+  m_davixParam->addCertificateAuthorityPath(env_var);
+  m_davixParam->setTransparentRedirectionSupport(true);
+  m_cert = new Davix::X509Credential();
+  m_davixParam->setClientCertCallbackX509(&TDavixFile_http_authn_cert_X509, NULL);
+
+}
+
+fReadDavix::~fReadDavix()
+{
+  this->closeFile();
+}
+
+bool fReadDavix::isOpen()
+{
+  return m_pfd != 0;
+}
+
+bool fReadDavix::isEoF()
+{
+
+  return false;
+}
+
+bool fReadDavix::fileExists(std::string fName) const
+{
+  Davix::DavixError* err2 = NULL;
+  DAVIX_FD* pfd = m_pos->open(m_davixParam, fName.c_str(), O_RDONLY, &err2);
+  if(pfd == 0) return false;
+  m_pos->close(pfd, &err2);
+  return true;
+}
+
+void fReadDavix::openFile(std::string fName)
+{
+  if(this->isOpen()) this->closeFile();
+  m_fd = m_pos->open(m_davixParam, fName.c_str(), O_RDONLY, &m_err);
+  m_offset = 0;
+  m_pfd = 1;
+}
+
+void fReadDavix::closeFile()
+{
+  if(m_pfd != 0) m_pos->close(m_fd, &m_err);
+  m_pfd = 0;
+}
+
+void fReadDavix::readData(char *buffer, unsigned int sizeBytes)
+{
+  if (sizeBytes==0) return;
+  if(this->isOpen())
+    {
+      unsigned int totalRead=0,ntry=0;
+      while(sizeBytes > totalRead)
+	{
+	  ssize_t ret = m_pos->pread(m_fd, buffer, sizeBytes, m_offset, &m_err);
+	  if (ret < 0) {
+	    std::stringstream mystream;
+	    mystream << "fReadDavix::readData: can not read data with davix " << m_err->getErrMsg().c_str() << " "  << m_err->getStatus();
+	    Davix::DavixError::clearError(&m_err);
+	    EventStorage::ReadingIssue ci(ERS_HERE, mystream.str().c_str());
+	    ers::warning(ci);
+	    return;
+	  } else {
+	    m_offset += ret;
+	  }
+	  totalRead += ret; ++ntry;
+	  if(ntry>5) {
+	    std::stringstream mystream;
+	    mystream << "Problem reading from the data file. "
+                    <<"fReadDavix::readData asked to read "<<sizeBytes
+                    <<" bytes and managed to read only "<<totalRead
+                    <<" bytes.";
+        EventStorage::ReadingIssue ci(ERS_HERE, mystream.str().c_str());
+        ers::warning(ci);
+        return;
+      }
+    }
+  }
+}
+
+int64_t fReadDavix::getPosition()
+{
+  if(this->isOpen()) return m_offset;
+ 
+  return -1;
+}
+
+void fReadDavix::setPosition(int64_t p)
+{
+  if(this->isOpen()) m_offset = p;
+}
+
+void fReadDavix::setPositionFromEnd(int64_t p)
+{
+  dav_off_t ret;
+  if(this->isOpen()) {
+    ret = m_pos->lseek64(m_fd, p, SEEK_END, &m_err);
+    m_offset = ret;
+  }
+}
+
+fRead * fReadDavix::newReader() const
+{
+  fReadDavix * nfr = new fReadDavix();
+  return (fRead *)nfr;
+}
+
+extern "C" {
+  fRead * fReadFactory()
+  {
+    fReadDavix * nfr = new fReadDavix();
+    return (fRead *)nfr;
+  }
+}
diff --git a/Event/FaserByteStreamPlugins/src/fReadDavix.h b/Event/FaserByteStreamPlugins/src/fReadDavix.h
new file mode 100644
index 000000000..316d519ff
--- /dev/null
+++ b/Event/FaserByteStreamPlugins/src/fReadDavix.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FREADDAVIX_H
+#define FREADDAVIX_H
+
+#include "FaserEventStorage/fRead.h"
+#include "davix.hpp"
+
+class fReadDavix : public fRead
+{
+ public:
+  fReadDavix();
+  ~fReadDavix();
+
+  bool isOpen();
+  bool isEoF();
+  bool fileExists(std::string fName) const;
+  void openFile(std::string fName);
+  void closeFile();
+  void readData(char *buffer, unsigned int sizeBytes);
+  int64_t getPosition();
+  void setPosition(int64_t p);
+  void setPositionFromEnd(int64_t p);
+  fRead * newReader() const;
+
+ private:
+  int  m_pfd; // current file, used as bool to check if file is open
+  int64_t m_offset;
+  Davix::Context m_c;
+  Davix::RequestParams *m_davixParam;
+  Davix::DavixError* m_err;
+  Davix::DavPosix *m_pos;
+  Davix::X509Credential *m_cert;
+  DAVIX_FD* m_fd; // davix pointer to current file
+
+};
+
+#endif
diff --git a/Event/FaserEventStorage/src/fReadPlain.cxx b/Event/FaserByteStreamPlugins/src/fReadPlain.cxx
similarity index 100%
rename from Event/FaserEventStorage/src/fReadPlain.cxx
rename to Event/FaserByteStreamPlugins/src/fReadPlain.cxx
diff --git a/Event/FaserEventStorage/src/fReadPlain.h b/Event/FaserByteStreamPlugins/src/fReadPlain.h
similarity index 100%
rename from Event/FaserEventStorage/src/fReadPlain.h
rename to Event/FaserByteStreamPlugins/src/fReadPlain.h
diff --git a/Event/FaserByteStreamPlugins/src/fReadXRootD.cxx b/Event/FaserByteStreamPlugins/src/fReadXRootD.cxx
new file mode 100644
index 000000000..f0e646127
--- /dev/null
+++ b/Event/FaserByteStreamPlugins/src/fReadXRootD.cxx
@@ -0,0 +1,114 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "ers/ers.h"
+#include <fcntl.h>
+
+#include "fReadXRootD.h"
+#include "EventStorage/EventStorageIssues.h"
+
+// external XRootD functions from ROOT net/xrootd/src/xrootd/src/XrdPosix/XrdPosixXrootd.hh
+class XrdPosixCallBack;
+class XrdPosixXrootd {
+public:
+  static int Open(const char *path, int oflag, mode_t mode=0, XrdPosixCallBack *cbP=0);
+  static int Close(int fildes);
+  static size_t Read(int fildes, void *buf, size_t nbyte);
+  static off_t Lseek(int fildes, off_t offset, int whence);
+};
+
+fReadXRootD::fReadXRootD()
+{
+  m_pfd = 0;
+}
+
+fReadXRootD::~fReadXRootD()
+{
+  this->closeFile();
+}
+
+bool fReadXRootD::isOpen()
+{
+  return m_pfd != 0;
+}
+
+bool fReadXRootD::isEoF()
+{
+  //xrd eof??
+  return false;
+}
+
+bool fReadXRootD::fileExists(std::string fName) const
+{
+  int pfd = XrdPosixXrootd::Open(fName.c_str(), O_RDONLY);
+  if(pfd == 0) return false;
+  XrdPosixXrootd::Close(pfd);
+  return true;
+}
+
+void fReadXRootD::openFile(std::string fName)
+{
+  if(this->isOpen()) this->closeFile();
+  m_pfd = XrdPosixXrootd::Open(fName.c_str(), O_RDONLY);
+}
+
+void fReadXRootD::closeFile()
+{
+  if(m_pfd != 0) XrdPosixXrootd::Close(m_pfd);
+  m_pfd = 0;
+}
+
+void fReadXRootD::readData(char *buffer, unsigned int sizeBytes)
+{
+  if (sizeBytes==0) return;
+  if(this->isOpen())
+    {
+      unsigned int totalRead=0,ntry=0;
+      while(sizeBytes > totalRead)
+	{
+	  int ret = XrdPosixXrootd::Read(m_pfd,buffer,sizeBytes);
+	  totalRead += ret; ++ntry;
+	  if(ntry>5) {
+	    std::stringstream mystream;
+	    mystream << "Problem reading from the data file. "
+		     <<"fReadXRootD::readData asked to read "<<sizeBytes
+		     <<" bytes and managed to read only "<<totalRead
+		     <<" bytes.";
+	    EventStorage::ReadingIssue ci(ERS_HERE, mystream.str().c_str());
+	    ers::warning(ci);
+	    return;
+	  }
+	}
+    }
+}
+
+int64_t fReadXRootD::getPosition()
+{
+  if(this->isOpen()) return  XrdPosixXrootd::Lseek(m_pfd, 0, SEEK_CUR);
+  return -1;
+}
+
+void fReadXRootD::setPosition(int64_t p)
+{
+  if(this->isOpen()) XrdPosixXrootd::Lseek(m_pfd, (long long)p, SEEK_SET);
+}
+
+void fReadXRootD::setPositionFromEnd(int64_t p)
+{
+  if(this->isOpen()) XrdPosixXrootd::Lseek(m_pfd, (long long)p, SEEK_END);
+}
+
+fRead * fReadXRootD::newReader() const
+{
+  fReadXRootD * nfr = new fReadXRootD();
+  return (fRead *)nfr;
+}
+
+extern "C" {
+  fRead * fReadFactory()
+  {
+    fReadXRootD * nfr = new fReadXRootD();
+    return (fRead *)nfr;
+  }
+}
diff --git a/Event/FaserByteStreamPlugins/src/fReadXRootD.h b/Event/FaserByteStreamPlugins/src/fReadXRootD.h
new file mode 100644
index 000000000..4d17ab197
--- /dev/null
+++ b/Event/FaserByteStreamPlugins/src/fReadXRootD.h
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef FREADXROOTD_H
+#define FREADXROOTD_H
+
+#include "FaserEventStorage/fRead.h"
+
+class fReadXRootD : public fRead
+{
+ public:
+  fReadXRootD();
+  ~fReadXRootD();
+
+  bool isOpen();
+  bool isEoF();
+  bool fileExists(std::string fName) const;
+  void openFile(std::string fName);
+  void closeFile();
+  void readData(char *buffer, unsigned int sizeBytes);
+  int64_t getPosition();
+  void setPosition(int64_t p);
+  void setPositionFromEnd(int64_t p);
+  fRead * newReader() const;
+
+ private:
+  int  m_pfd; // current file
+};
+
+#endif
diff --git a/Event/FaserEventStorage/CMakeLists.txt b/Event/FaserEventStorage/CMakeLists.txt
index e2344ff42..f55d90c6e 100644
--- a/Event/FaserEventStorage/CMakeLists.txt
+++ b/Event/FaserEventStorage/CMakeLists.txt
@@ -16,11 +16,12 @@ atlas_add_library( FaserEventStorageLib
     LINK_LIBRARIES ${CMAKE_DL_LIBS} ${Boost_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} EventFormats )
 
 
+
 # atlas_add_library(fReadPlain 
-#     src/fReadPlain.h src/fReadPlain.cxx 
-#     PUBLIC_HEADERS src
-#     INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS}
-#     LINK_LIBRARIES ${Boost_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} -rdynamic)
+#      src/fReadPlain.h src/fReadPlain.cxx 
+#      NO_PUBLIC_HEADERS
+#      PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS}
+#      PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} -rdynamic)
 
 # Install files from the package:
 #atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
diff --git a/Event/FaserEventStorage/src/pickFaserDataReader.cxx b/Event/FaserEventStorage/src/pickFaserDataReader.cxx
index e800e22aa..72b95ec8b 100644
--- a/Event/FaserEventStorage/src/pickFaserDataReader.cxx
+++ b/Event/FaserEventStorage/src/pickFaserDataReader.cxx
@@ -10,40 +10,28 @@ DataReader * pickFaserDataReader(std::string fileName) {
   ERS_DEBUG(1,"pickFaserDataReader(file) with file name "<<fileName);
 
   std::vector<std::string> fReadLibs;
-  fReadLibs.push_back("fReadPlain");  // Just use plain
 
-  /*
   // Control plugins libraries via file name prefixes.
   // Take the prefixes away from the name, in most cases anyway.
-  if(fileName.find("rfio:")==0) {
-    fileName.erase(0,std::string("rfio:").size());
-    fReadLibs.push_back("fReadCastor");
-  } else if(fileName.find("dcache:")==0) {
-    fileName.erase(0,std::string("dcache:").size());
-    fReadLibs.push_back("fReaddCache");
-  } else if(fileName.find("dcap:")==0) {
-    // Leave the prefix in the file name in this case.
-    fReadLibs.push_back("fReaddCache");
-  } else if(fileName.find("root:")==0) {
+
+  if(fileName.find("root:")==0) {
     // Leave the prefix in the file name in this case.
     fReadLibs.push_back("fReadXRootD");
+  } else if(fileName.find("disk:")==0) {
+    fileName.erase(0,std::string("disk:").size()); 
+    fReadLibs.push_back("fReadPlain"); 
   } else if(fileName.find("https:")==0) {
     // Leave the prefix in the file name in this case.
     fReadLibs.push_back("fReadDavix");
   } else if(fileName.find("davs:")==0) {
     // Leave the prefix in the file name in this case.
     fReadLibs.push_back("fReadDavix");
-  } else if(fileName.find("disk:")==0) {
-    fileName.erase(0,std::string("disk:").size());
-    fReadLibs.push_back("fReadPlain");
   } else { // by defaul all will be tried
     fReadLibs.push_back("fReadPlain");
-    fReadLibs.push_back("fReadCastor");
     fReadLibs.push_back("fReadXRootD");
     fReadLibs.push_back("fReadDavix");
-    fReadLibs.push_back("fReaddCache");
   }
-  */
+
   ERS_DEBUG(2,"After parsing the file name is "<<fileName);
   ERS_DEBUG(2,"Number of fRead plugins to try is "<<fReadLibs.size());
 
-- 
GitLab


From f99e44e588621db9f5f13060a5d3c90cfa570faf Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 16 Mar 2021 09:42:07 -0700
Subject: [PATCH 38/47] Rename package to better match functionality

---
 .../CMakeLists.txt                                            | 4 ++--
 .../src/fReadDavix.cxx                                        | 0
 .../src/fReadDavix.h                                          | 0
 .../src/fReadPlain.cxx                                        | 0
 .../src/fReadPlain.h                                          | 0
 .../src/fReadXRootD.cxx                                       | 0
 .../src/fReadXRootD.h                                         | 0
 7 files changed, 2 insertions(+), 2 deletions(-)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/CMakeLists.txt (95%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadDavix.cxx (100%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadDavix.h (100%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadPlain.cxx (100%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadPlain.h (100%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadXRootD.cxx (100%)
 rename Event/{FaserByteStreamPlugins => FaserEventPlugins}/src/fReadXRootD.h (100%)

diff --git a/Event/FaserByteStreamPlugins/CMakeLists.txt b/Event/FaserEventPlugins/CMakeLists.txt
similarity index 95%
rename from Event/FaserByteStreamPlugins/CMakeLists.txt
rename to Event/FaserEventPlugins/CMakeLists.txt
index a340d06c4..377c12e15 100644
--- a/Event/FaserByteStreamPlugins/CMakeLists.txt
+++ b/Event/FaserEventPlugins/CMakeLists.txt
@@ -1,9 +1,9 @@
 ################################################################################
-# Package: FaserByteStreamPlugins
+# Package: FaserEventsPlugins
 ################################################################################
 
 # Declare the package name:
-atlas_subdir( FaserByteStreamPlugins )
+atlas_subdir( FaserEventsPlugins )
 
 # External dependencies:
 find_package( tdaq-common COMPONENTS ers EventStorage )
diff --git a/Event/FaserByteStreamPlugins/src/fReadDavix.cxx b/Event/FaserEventPlugins/src/fReadDavix.cxx
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadDavix.cxx
rename to Event/FaserEventPlugins/src/fReadDavix.cxx
diff --git a/Event/FaserByteStreamPlugins/src/fReadDavix.h b/Event/FaserEventPlugins/src/fReadDavix.h
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadDavix.h
rename to Event/FaserEventPlugins/src/fReadDavix.h
diff --git a/Event/FaserByteStreamPlugins/src/fReadPlain.cxx b/Event/FaserEventPlugins/src/fReadPlain.cxx
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadPlain.cxx
rename to Event/FaserEventPlugins/src/fReadPlain.cxx
diff --git a/Event/FaserByteStreamPlugins/src/fReadPlain.h b/Event/FaserEventPlugins/src/fReadPlain.h
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadPlain.h
rename to Event/FaserEventPlugins/src/fReadPlain.h
diff --git a/Event/FaserByteStreamPlugins/src/fReadXRootD.cxx b/Event/FaserEventPlugins/src/fReadXRootD.cxx
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadXRootD.cxx
rename to Event/FaserEventPlugins/src/fReadXRootD.cxx
diff --git a/Event/FaserByteStreamPlugins/src/fReadXRootD.h b/Event/FaserEventPlugins/src/fReadXRootD.h
similarity index 100%
rename from Event/FaserByteStreamPlugins/src/fReadXRootD.h
rename to Event/FaserEventPlugins/src/fReadXRootD.h
-- 
GitLab


From fbc1d4511f3f2d17b52e9a4427f93f17b4026f85 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 30 Mar 2021 23:34:13 -0700
Subject: [PATCH 39/47] Change name of trigger data Aux file

---
 .../python/TriggerDataAccessExampleConfig.py  |  2 +-
 .../python/FaserByteStreamCnvSvcConfig.py     |  2 +-
 .../share/jobOptions_faserBSToRDO.py          |  2 +-
 .../python/FaserByteStreamCnvSvcBaseConfig.py |  2 +-
 .../share/BSAddProvSvc_jobOptions.py          |  2 +-
 .../src/FaserTriggerByteStreamAuxCnv.cxx      | 10 ++++-----
 .../src/FaserTriggerByteStreamCnv.cxx         |  6 ++---
 .../src/FaserTriggerDecoderTool.cxx           |  2 +-
 xAOD/xAODFaserTrigger/CMakeLists.txt          |  4 ++--
 ...Info_v1.cxx => FaserTriggerDataAux_v1.cxx} |  4 ++--
 .../Root/xAODFaserTriggerCLIDs.cxx            |  2 +-
 .../xAODFaserTrigger/FaserTriggerDataAux.h    | 22 +++++++++++++++++++
 .../FaserTriggerDataAuxInfo.h                 | 22 -------------------
 .../xAODFaserTrigger/selection.xml            |  4 ++--
 ...aAuxInfo_v1.h => FaserTriggerDataAux_v1.h} | 12 +++++-----
 .../xAODFaserTrigger/xAODFaserTriggerDict.h   |  4 ++--
 .../xAODFaserTriggerAthenaPool/CMakeLists.txt |  4 ++--
 ...Cnv.cxx => xAODFaserTriggerDataAuxCnv.cxx} |  0
 .../src/xAODFaserTriggerDataAuxCnv.h          | 16 ++++++++++++++
 .../src/xAODFaserTriggerDataAuxInfoCnv.h      | 16 --------------
 20 files changed, 69 insertions(+), 69 deletions(-)
 rename xAOD/xAODFaserTrigger/Root/{FaserTriggerDataAuxInfo_v1.cxx => FaserTriggerDataAux_v1.cxx} (80%)
 create mode 100644 xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAux.h
 delete mode 100644 xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAuxInfo.h
 rename xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/{FaserTriggerDataAuxInfo_v1.h => FaserTriggerDataAux_v1.h} (72%)
 rename xAOD/xAODFaserTriggerAthenaPool/src/{xAODFaserTriggerDataAuxInfoCnv.cxx => xAODFaserTriggerDataAuxCnv.cxx} (100%)
 create mode 100644 xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.h
 delete mode 100644 xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.h

diff --git a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
index 5de3a3324..54ceea6ad 100644
--- a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
@@ -53,7 +53,7 @@ if __name__ == "__main__":
     itemList = [ "xAOD::EventInfo#*",
                  "xAOD::EventAuxInfo#*",
                  "xAOD::FaserTriggerData#*",
-                 "xAOD::FaserTriggerDataAuxInfo#*" ]
+                 "xAOD::FaserTriggerDataAux#*" ]
     acc.merge(OutputStreamCfg(ConfigFlags, "RDO", itemList))
     ostream = acc.getEventAlgo("OutputStreamRDO")
 
diff --git a/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py b/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py
index 26ad046e5..46b94723e 100644
--- a/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py
+++ b/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py
@@ -13,7 +13,7 @@ def FaserEventSelectorByteStreamCfg(configFlags, **kwargs):
 # Load ByteStreamCnvSvc
     byteSvc = CompFactory.FaserByteStreamCnvSvc
     byteSvcInstance = byteSvc(name = "FaserByteStreamCnvSvc")
-    byteSvcInstance.InitCnvs += [ "xAOD::FaserTriggerDataAuxInfo" , "xAOD::FaserTriggerData"  ]
+    byteSvcInstance.InitCnvs += [ "xAOD::FaserTriggerDataAux" , "xAOD::FaserTriggerData"  ]
     result.addService(byteSvcInstance)
 
 # Load EventSelectorByteStream
diff --git a/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py b/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
index 5bb3864df..5ce99e4b6 100644
--- a/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
+++ b/Event/FaserByteStreamCnvSvc/share/jobOptions_faserBSToRDO.py
@@ -71,7 +71,7 @@ xaodStream.AddItem( "xAOD::EventInfo#*" )
 xaodStream.AddItem( "xAOD::EventAuxInfo#*" )
 # Currently, this doesn't write the Aux data...
 xaodStream.AddItem( "xAOD::FaserTriggerData#*")
-xaodStream.AddItem( "xAOD::FaserTriggerDataAuxInfo#*")
+xaodStream.AddItem( "xAOD::FaserTriggerDataAux#*")
 # Tracker RDOs
 # xaodStream.AddItem( "FaserSCT_RDO_Container#*" )
 xaodStream.Print()
diff --git a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
index 3346c0fd6..af4766a10 100644
--- a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
+++ b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py
@@ -10,7 +10,7 @@ def FaserByteStreamCnvSvcBaseCfg(flags, **kwargs):
     result.addService(adxProvider)
 
     adxProvider.TypeNames += [ "xAOD::FaserTriggerData/FaserTriggerData",
-                               "xAOD::FaserTriggerDataAuxInfo/FaserTriggerDataAuxInfo." ]
+                               "xAOD::FaserTriggerDataAux/FaserTriggerDataAux." ]
 
     adxProvider.TypeNames += [
         "ScintWaveformContainer/CaloWaveforms",
diff --git a/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
index ac692d56f..3adf8709d 100644
--- a/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
+++ b/Event/FaserByteStreamCnvSvcBase/share/BSAddProvSvc_jobOptions.py
@@ -7,7 +7,7 @@ if not hasattr( svcMgr, "FaserByteStreamAddressProviderSvc" ):
 # Correnct syntax for non-containers
 svcMgr.FaserByteStreamAddressProviderSvc.TypeNames += [ 
     "xAOD::FaserTriggerData/FaserTriggerData",
-    "xAOD::FaserTriggerDataAuxInfo/FaserTriggerDataAuxInfo."
+    "xAOD::FaserTriggerDataAux/FaserTriggerDataAux."
 ]
 
 # Add the different Scintillator containers
diff --git a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamAuxCnv.cxx b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamAuxCnv.cxx
index 4d6c6a05c..942c0c700 100644
--- a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamAuxCnv.cxx
+++ b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamAuxCnv.cxx
@@ -16,7 +16,7 @@
 #include "GaudiKernel/IRegistry.h"
 
 #include "xAODFaserTrigger/FaserTriggerData.h"
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
 
 #include "StoreGate/StoreGateSvc.h"
 
@@ -36,7 +36,7 @@ FaserTriggerByteStreamAuxCnv::FaserTriggerByteStreamAuxCnv(ISvcLocator* svcloc)
 
 const CLID& FaserTriggerByteStreamAuxCnv::classID() 
 {
-  return ClassID_traits<xAOD::FaserTriggerDataAuxInfo>::ID();
+  return ClassID_traits<xAOD::FaserTriggerDataAux>::ID();
 }
 
 long FaserTriggerByteStreamAuxCnv::storageType() 
@@ -95,20 +95,20 @@ StatusCode FaserTriggerByteStreamAuxCnv::createObj(IOpaqueAddress* pAddr, DataOb
 
 
   xAOD::FaserTriggerData triggerData;
-  xAOD::FaserTriggerDataAuxInfo* pTriggerDataAux = new xAOD::FaserTriggerDataAuxInfo();
+  xAOD::FaserTriggerDataAux* pTriggerDataAux = new xAOD::FaserTriggerDataAux();
   triggerData.setStore(pTriggerDataAux);
 
   CHECK( m_tool->convert(re, &triggerData) );
 
   pObj = StoreGateSvc::asStorable(pTriggerDataAux);
 
-  ATH_MSG_DEBUG("Created xAOD::FaserTriggerDataAuxInfo for run/event =" << runNumber << " / " << eventNumber);
+  ATH_MSG_DEBUG("Created xAOD::FaserTriggerDataAux for run/event =" << runNumber << " / " << eventNumber);
   return StatusCode::SUCCESS;
 }
 
 StatusCode FaserTriggerByteStreamAuxCnv::createRep(DataObject* /*pObj*/, IOpaqueAddress*& /*pAddr*/) 
 {
-  ATH_MSG_DEBUG("Nothing to be done for xAOD::FaserTriggerDataAuxInfo createReps");
+  ATH_MSG_DEBUG("Nothing to be done for xAOD::FaserTriggerDataAux createReps");
   return StatusCode::SUCCESS;
 }
 
diff --git a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamCnv.cxx b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamCnv.cxx
index 353c6a14f..293992772 100644
--- a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamCnv.cxx
+++ b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerByteStreamCnv.cxx
@@ -6,7 +6,7 @@
 
 #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
 #include "xAODFaserTrigger/FaserTriggerData.h"
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
 #include "EventFormats/DAQFormats.hpp"
 
 #include "AthenaKernel/errorcheck.h"
@@ -61,10 +61,10 @@ StatusCode FaserTriggerByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObjec
   ATH_MSG_DEBUG("Creating Objects");
 
   const std::string nm = *(pRE_Addr->par());
-  const std::string nmAux = nm + "AuxInfo.";
+  const std::string nmAux = nm + "Aux.";
 
   xAOD::FaserTriggerData* pTriggerData = new xAOD::FaserTriggerData();
-  DataLink<xAOD::FaserTriggerDataAuxInfo> link(nmAux);
+  DataLink<xAOD::FaserTriggerDataAux> link(nmAux);
   pTriggerData->setStore(link);
   pObj = StoreGateSvc::asStorable(pTriggerData);
 
diff --git a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerDecoderTool.cxx b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerDecoderTool.cxx
index 96bb3a532..af639a5b9 100644
--- a/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerDecoderTool.cxx
+++ b/Trigger/FaserTrigEventCnv/FaserTriggerByteStream/src/FaserTriggerDecoderTool.cxx
@@ -6,7 +6,7 @@
 #include "AthenaBaseComps/AthAlgTool.h"
 
 #include "xAODFaserTrigger/FaserTriggerData.h"
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
 
 #include "EventFormats/TLBDataFragment.hpp"
 
diff --git a/xAOD/xAODFaserTrigger/CMakeLists.txt b/xAOD/xAODFaserTrigger/CMakeLists.txt
index bce466e88..83c514f64 100644
--- a/xAOD/xAODFaserTrigger/CMakeLists.txt
+++ b/xAOD/xAODFaserTrigger/CMakeLists.txt
@@ -16,7 +16,7 @@ atlas_add_library( xAODFaserTrigger
 atlas_add_xaod_smart_pointer_dicts(
    INPUT xAODFaserTrigger/selection.xml
    OUTPUT _selectionFile
-   OBJECTS "xAOD::FaserTriggerData_v1")
+   OBJECTS "xAOD::FaserTriggerData_v1" "xAOD::FaserTriggerDataAux_v1")
 
 atlas_add_dictionary( xAODFaserTriggerDict
    xAODFaserTrigger/xAODFaserTriggerDict.h
@@ -25,4 +25,4 @@ atlas_add_dictionary( xAODFaserTriggerDict
    EXTRA_FILES Root/dict/*.cxx )
 
 # Understand what this does...
-# atlas_generate_cliddb( xAODFaserTrigger )
+atlas_generate_cliddb( xAODFaserTrigger )
diff --git a/xAOD/xAODFaserTrigger/Root/FaserTriggerDataAuxInfo_v1.cxx b/xAOD/xAODFaserTrigger/Root/FaserTriggerDataAux_v1.cxx
similarity index 80%
rename from xAOD/xAODFaserTrigger/Root/FaserTriggerDataAuxInfo_v1.cxx
rename to xAOD/xAODFaserTrigger/Root/FaserTriggerDataAux_v1.cxx
index 9d3bb911d..cb9be1ef2 100644
--- a/xAOD/xAODFaserTrigger/Root/FaserTriggerDataAuxInfo_v1.cxx
+++ b/xAOD/xAODFaserTrigger/Root/FaserTriggerDataAux_v1.cxx
@@ -5,11 +5,11 @@
 // $Id: $
 
 // Local include(s):
-#include "xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h"
+#include "xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h"
 
 namespace xAOD {
 
-  FaserTriggerDataAuxInfo_v1::FaserTriggerDataAuxInfo_v1()
+  FaserTriggerDataAux_v1::FaserTriggerDataAux_v1()
     : AuxInfoBase(),
       header(0), eventId(0), orbitId(0), bcid(0), 
       inputBitsNextClk(0), inputBits(0), tbp(0), tap(0) {
diff --git a/xAOD/xAODFaserTrigger/Root/xAODFaserTriggerCLIDs.cxx b/xAOD/xAODFaserTrigger/Root/xAODFaserTriggerCLIDs.cxx
index 62efdd992..fa899af62 100644
--- a/xAOD/xAODFaserTrigger/Root/xAODFaserTriggerCLIDs.cxx
+++ b/xAOD/xAODFaserTrigger/Root/xAODFaserTriggerCLIDs.cxx
@@ -5,4 +5,4 @@
 //simple includes to force the CLASS_DEF etc to be encountered during compile
 
 #include "xAODFaserTrigger/FaserTriggerData.h"
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
diff --git a/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAux.h b/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAux.h
new file mode 100644
index 000000000..95305f789
--- /dev/null
+++ b/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAux.h
@@ -0,0 +1,22 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERTRIGGER_FASERTRIGGERDATAAUX_H
+#define XAODFASERTRIGGER_FASERTRIGGERDATAAUX_H
+
+// Local include(s):
+#include "xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h"
+
+namespace xAOD {
+  /// Declare the latest version of the class
+  typedef FaserTriggerDataAux_v1 FaserTriggerDataAux;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FaserTriggerDataAux, 155975504, 1 )
+
+#endif // XAODFASERTRIGGER_FASERTRIGGERDATAAUX_H
diff --git a/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAuxInfo.h b/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAuxInfo.h
deleted file mode 100644
index d557cf607..000000000
--- a/xAOD/xAODFaserTrigger/xAODFaserTrigger/FaserTriggerDataAuxInfo.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Dear emacs, this is -*- c++ -*-
-
-/*
-  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef XAODFASERTRIGGER_FASERTRIGGERDATAAUXINFO_H
-#define XAODFASERTRIGGER_FASERTRIGGERDATAAUXINFO_H
-
-// Local include(s):
-#include "xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h"
-
-namespace xAOD {
-  /// Declare the latest version of the class
-  typedef FaserTriggerDataAuxInfo_v1 FaserTriggerDataAuxInfo;
-}
-
-// Set up a CLID for the container:
-#include "xAODCore/CLASS_DEF.h"
-CLASS_DEF( xAOD::FaserTriggerDataAuxInfo, 82583928, 1 )
-
-#endif // XAODFASERTRIGGER_FASERTRIGGERDATAAUXINFO_H
diff --git a/xAOD/xAODFaserTrigger/xAODFaserTrigger/selection.xml b/xAOD/xAODFaserTrigger/xAODFaserTrigger/selection.xml
index f5b7e2144..e5861d92f 100644
--- a/xAOD/xAODFaserTrigger/xAODFaserTrigger/selection.xml
+++ b/xAOD/xAODFaserTrigger/xAODFaserTrigger/selection.xml
@@ -6,8 +6,8 @@
 	 id="965196C8-AC56-421C-9AC7-D7DB62E2AFFC"/>
   <typedef name="xAOD::FaserTriggerData" />
 
-  <class name="xAOD::FaserTriggerDataAuxInfo_v1" 
+  <class name="xAOD::FaserTriggerDataAux_v1" 
 	 id="5F26C42B-3BF1-44CA-A127-172ED5797936"/>
-  <typedef name="xAOD::FaserTriggerDataAuxInfo" />
+  <typedef name="xAOD::FaserTriggerDataAux" />
 
 </lcgdict>
diff --git a/xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h b/xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h
similarity index 72%
rename from xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h
rename to xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h
index 1ee880548..0601947ba 100644
--- a/xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h
+++ b/xAOD/xAODFaserTrigger/xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h
@@ -4,8 +4,8 @@
   Copyright (C) 2020 CERN for the benefit of the FASER collaboration
 */
 
-#ifndef XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUXINFO_V1_H
-#define XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUXINFO_V1_H
+#ifndef XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUX_V1_H
+#define XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUX_V1_H
 
 // System include(s):
 extern "C" {
@@ -26,11 +26,11 @@ namespace xAOD {
   /// $Revision:  $
   /// $Date: $
 
-  class FaserTriggerDataAuxInfo_v1 : public AuxInfoBase {
+  class FaserTriggerDataAux_v1 : public AuxInfoBase {
 
   public:
     /// Default constructor
-    FaserTriggerDataAuxInfo_v1();
+    FaserTriggerDataAux_v1();
 
   private:
     /// @name TriggerLogicBoard payload
@@ -51,8 +51,8 @@ namespace xAOD {
 
 // Set up the StoreGate inheritance of the class:
 #include "xAODCore/BaseInfo.h"
-SG_BASE( xAOD::FaserTriggerDataAuxInfo_v1, xAOD::AuxInfoBase );
+SG_BASE( xAOD::FaserTriggerDataAux_v1, xAOD::AuxInfoBase );
 
-#endif // XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUXINFO_V1_H
+#endif // XAODFASERTRIGGER_VERSIONS_FASERTRIGGERDATAAUX_V1_H
 
 
diff --git a/xAOD/xAODFaserTrigger/xAODFaserTrigger/xAODFaserTriggerDict.h b/xAOD/xAODFaserTrigger/xAODFaserTrigger/xAODFaserTriggerDict.h
index 494fcbc5c..8347119ce 100644
--- a/xAOD/xAODFaserTrigger/xAODFaserTrigger/xAODFaserTriggerDict.h
+++ b/xAOD/xAODFaserTrigger/xAODFaserTrigger/xAODFaserTriggerDict.h
@@ -7,9 +7,9 @@
 
 // Local include(s):
 #include "xAODFaserTrigger/FaserTriggerData.h"
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
 #include "xAODFaserTrigger/versions/FaserTriggerData_v1.h"
-#include "xAODFaserTrigger/versions/FaserTriggerDataAuxInfo_v1.h"
+#include "xAODFaserTrigger/versions/FaserTriggerDataAux_v1.h"
 
 // EDM include(s).
 #include "xAODCore/tools/DictHelpers.h"
diff --git a/xAOD/xAODFaserTriggerAthenaPool/CMakeLists.txt b/xAOD/xAODFaserTriggerAthenaPool/CMakeLists.txt
index 1d738c2ad..d02c9a19f 100644
--- a/xAOD/xAODFaserTriggerAthenaPool/CMakeLists.txt
+++ b/xAOD/xAODFaserTriggerAthenaPool/CMakeLists.txt
@@ -6,8 +6,8 @@ atlas_subdir( xAODFaserTriggerAthenaPool )
 # Component(s) in the package:
 atlas_add_poolcnv_library( xAODFaserTriggerAthenaPoolPoolCnv
    src/*.h src/*.cxx
-   FILES xAODFaserTrigger/FaserTriggerData.h xAODFaserTrigger/FaserTriggerDataAuxInfo.h
-   TYPES_WITH_NAMESPACE xAOD::FaserTriggerData xAOD::FaserTriggerDataAuxInfo
+   FILES xAODFaserTrigger/FaserTriggerData.h xAODFaserTrigger/FaserTriggerDataAux.h
+   TYPES_WITH_NAMESPACE xAOD::FaserTriggerData xAOD::FaserTriggerDataAux
    CNV_PFX xAOD
    LINK_LIBRARIES AthenaPoolCnvSvcLib AthenaPoolUtilities xAODFaserTrigger )
 
diff --git a/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.cxx b/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.cxx
similarity index 100%
rename from xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.cxx
rename to xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.cxx
diff --git a/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.h b/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.h
new file mode 100644
index 000000000..f0c8db9e5
--- /dev/null
+++ b/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxCnv.h
@@ -0,0 +1,16 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXCNV_H
+#define XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXCNV_H
+
+#include "xAODFaserTrigger/FaserTriggerDataAux.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
+
+typedef T_AthenaPoolAuxContainerCnv<xAOD::FaserTriggerDataAux> xAODFaserTriggerDataAuxCnv;
+
+
+#endif // XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXCNV_H
diff --git a/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.h b/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.h
deleted file mode 100644
index 71d0cb016..000000000
--- a/xAOD/xAODFaserTriggerAthenaPool/src/xAODFaserTriggerDataAuxInfoCnv.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Dear emacs, this is -*- c++ -*-
-
-/*
-  Copyright (C) 2020 CERN for the benefit of the FASER collaboration
-*/
-
-#ifndef XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXINFOCNV_H
-#define XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXINFOCNV_H
-
-#include "xAODFaserTrigger/FaserTriggerDataAuxInfo.h"
-#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
-
-typedef T_AthenaPoolAuxContainerCnv<xAOD::FaserTriggerDataAuxInfo> xAODFaserTriggerDataAuxInfoCnv;
-
-
-#endif // XAODFASERTRIGGERDATAATHENAPOOL_XAODFASERTRIGGERDATAAUXINFOCNV_H
-- 
GitLab


From 82421590184414f1bd7d60fe684880494c0dc7de Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 1 Apr 2021 23:21:37 -0700
Subject: [PATCH 40/47] Needed to read RDOs

---
 .../TrackerEventAthenaPool/FaserSCT_RawDataContainer_p4.h       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Tracker/TrackerEventCnv/TrackerEventAthenaPool/TrackerEventAthenaPool/FaserSCT_RawDataContainer_p4.h b/Tracker/TrackerEventCnv/TrackerEventAthenaPool/TrackerEventAthenaPool/FaserSCT_RawDataContainer_p4.h
index 73bb683c2..a5f93dbe6 100644
--- a/Tracker/TrackerEventCnv/TrackerEventAthenaPool/TrackerEventAthenaPool/FaserSCT_RawDataContainer_p4.h
+++ b/Tracker/TrackerEventCnv/TrackerEventAthenaPool/TrackerEventAthenaPool/FaserSCT_RawDataContainer_p4.h
@@ -26,7 +26,7 @@ class FaserSCT_RawDataContainer_p4
 /// Default constructor
   FaserSCT_RawDataContainer_p4();
   friend class FaserSCT_RawDataContainerCnv_p4;
- private:
+  //private:
   std::vector<TrackerRawDataCollection_p1>  m_collections;
   std::vector<TrackerRawData_p2>            m_rawdata;
   std::vector<FaserSCT3_RawData_p4>         m_sct3data;
-- 
GitLab


From eb38cede270d3f5aeca9492dc03439e876ad1df1 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 6 Apr 2021 22:16:22 -0700
Subject: [PATCH 41/47] Fix bug in stored waveform snippet

---
 Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 657371165..7b442b695 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -151,7 +151,7 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     hit->set_baseline_mean(baseline.mean);
     hit->set_baseline_rms(baseline.rms);
     hit->set_time_vector(wtime);
-    hit->set_wave_vector(wave);
+    hit->set_wave_vector(wwave);
 
     //
     // Find some raw values
@@ -253,7 +253,7 @@ WaveformReconstructionTool::findPeak(WaveformBaselineData& baseline,
   // Remove these values from the original arrays so we can iterate
   time.erase(time.begin()+lo_edge, time.begin()+hi_edge);
   wave.erase(wave.begin()+lo_edge, wave.begin()+hi_edge);
-  
+
   return true;
 }
 
-- 
GitLab


From 435959513481d7b400350d85f1127d8cb86902f5 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Tue, 6 Apr 2021 23:46:32 -0700
Subject: [PATCH 42/47] Fix bug in Dave's reco code

---
 .../TrackerClusterFit/src/ClusterFitAlg.cxx            | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Tracker/TrackerRecAlgs/TrackerClusterFit/src/ClusterFitAlg.cxx b/Tracker/TrackerRecAlgs/TrackerClusterFit/src/ClusterFitAlg.cxx
index 7dc182d8b..591c186f2 100644
--- a/Tracker/TrackerRecAlgs/TrackerClusterFit/src/ClusterFitAlg.cxx
+++ b/Tracker/TrackerRecAlgs/TrackerClusterFit/src/ClusterFitAlg.cxx
@@ -376,10 +376,10 @@ ClusterFitAlg::AddTrack(std::unique_ptr<TrackCollection>& tracks,
     // translate parameters to nominal fit point
     s->push_back( GetState(fitResult, fitCovariance, nullptr, station) );
 
-    // for (const clusterInfo* cInfo : fitClusters)
-    // {
-    //     s->push_back( GetState(fitResult, fitCovariance, cInfo->cluster, station) );
-    // }
+    for (const clusterInfo* cInfo : fitClusters)
+      {
+	s->push_back( GetState(fitResult, fitCovariance, cInfo->cluster, station) );
+      }
 
     // Create and store track
     tracks->push_back(new Trk::Track(i, s , q));
@@ -495,4 +495,4 @@ ClusterFitAlg::Residuals(std::vector<const clusterInfo*>& fitClusters) const
     }
 }
 
-}
\ No newline at end of file
+}
-- 
GitLab


From 50da8522bad26d80f4c32c26b646d0578dddbc57 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Fri, 9 Apr 2021 11:14:51 -0700
Subject: [PATCH 43/47] add some debug monitoring

---
 .../src/ClockReconstructionTool.cxx           | 27 ++++++++++++++++++-
 .../src/ClockReconstructionTool.h             |  6 +++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
index 15a3e5f3b..3b560c320 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -64,7 +64,8 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
   ATH_MSG_DEBUG("Created double array with length " << wave.size() );
   ATH_MSG_DEBUG("First 10 elements:");
-  for (unsigned int i=0; i < std::min(10, N); i++)
+
+  for (int i=0; i < std::min(10, N); i++)
     ATH_MSG_DEBUG(" " << i << " " << wave[i]);
 
   // delta_nu = 1/T where T is the total waveform length
@@ -138,5 +139,29 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
   delete fftr2c;
 
+  if (m_checkResult) checkResult(raw_wave, clockdata);
+
   return StatusCode::SUCCESS;
 }
+
+void
+ClockReconstructionTool::checkResult(const ScintWaveform& raw_wave,
+				     xAOD::WaveformClock* clockdata) const {
+
+  // Go through each element in raw_wave and make sure time in clockdata matches
+
+  float time;
+  for (unsigned int i=0; i<raw_wave.adc_counts().size(); i++) {
+    time = 2.*i; // Time in ns
+
+    float dt = clockdata->time_from_clock(time);
+
+    // Is raw_wave HI or LO?
+    bool hi = raw_wave.adc_counts()[i] > clockdata->dc_offset();
+
+    // Check for mismatch
+    if (((dt < 12.5) && !hi) || ((dt > 12.5) && hi) ) 
+      ATH_MSG_WARNING("Clock Time:" << time << " dt:" << dt << " found" << hi);
+  }
+
+}
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
index 0b52229e2..a503c0632 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -45,6 +45,12 @@ class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTo
   /// Minimum samples in the input waveform array to try FFT
   IntegerProperty m_minimumSamples{this, "MinimumSamples", 40};
 
+  /// Check reconstructed clock against waveform
+  BooleanProperty m_checkResult{this, "CheckResult", false};
+
+  void checkResult(const ScintWaveform& raw_wave,
+		   xAOD::WaveformClock* clockdata) const;
+
 };
 
 #endif // SCINTRECTOOLS_CLOCKRECONSTRUCTIONTOOL_H
-- 
GitLab


From 7aa2a2d5e1609f9fd2f095a64892bf87351e5963 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Sun, 11 Apr 2021 13:43:06 -0700
Subject: [PATCH 44/47] Bugfixes for waveform reco

---
 .../ScintRecAlgs/python/ScintRecAlgsConfig.py |  2 +-
 .../src/ClockReconstructionTool.cxx           |  9 +++-
 .../src/ClockReconstructionTool.h             |  5 +++
 .../src/WaveformReconstructionTool.cxx        | 43 ++++++++++++++-----
 .../src/WaveformReconstructionTool.h          |  2 +-
 .../versions/WaveformHit_v1.h                 |  2 +-
 6 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
index 6319e9a01..f96dbcaf2 100644
--- a/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
+++ b/Scintillator/ScintRecAlgs/python/ScintRecAlgsConfig.py
@@ -29,7 +29,7 @@ def WaveformClockRecCfg(flags, name="ClockRecAlg", **kwargs):
     acc = ComponentAccumulator()
 
     tool = ClockReconstructionTool(name="ClockReconstructionTool")
-
+    # tool.CheckResult = True
     kwargs.setdefault("ClockReconstructionTool", tool)
 
     recoAlg = CompFactory.ScintClockRecAlg(name, **kwargs)
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
index 3b560c320..c4d1bf68f 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.cxx
@@ -139,6 +139,11 @@ ClockReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
 
   delete fftr2c;
 
+  // Check the result for sanity
+  if (clockdata->amplitude() < m_amplitude_min || clockdata->frequency() < m_frequency_min || clockdata->frequency() > m_frequency_max) {
+    ATH_MSG_WARNING("Clock reconstructed with frequency = " << clockdata->frequency() << " amplitude = " << clockdata->amplitude() << "!");
+  }
+
   if (m_checkResult) checkResult(raw_wave, clockdata);
 
   return StatusCode::SUCCESS;
@@ -160,8 +165,8 @@ ClockReconstructionTool::checkResult(const ScintWaveform& raw_wave,
     bool hi = raw_wave.adc_counts()[i] > clockdata->dc_offset();
 
     // Check for mismatch
-    if (((dt < 12.5) && !hi) || ((dt > 12.5) && hi) ) 
-      ATH_MSG_WARNING("Clock Time:" << time << " dt:" << dt << " found" << hi);
+    if (((dt > 0.05) && (dt < 12.45) && !hi) || ((dt > 12.55) && (dt < 24.95) && hi) ) 
+      ATH_MSG_WARNING("Clock Time: " << time << " Time to edge: "  << dt << " found raw data: " << hi);
   }
 
 }
diff --git a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
index a503c0632..056d1a4e9 100644
--- a/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/ClockReconstructionTool.h
@@ -51,6 +51,11 @@ class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTo
   void checkResult(const ScintWaveform& raw_wave,
 		   xAOD::WaveformClock* clockdata) const;
 
+  // Limits to print warnings
+  FloatProperty m_amplitude_min{this, "AmplitudeMin", 1000.};
+  FloatProperty m_frequency_min{this, "FrequencyMin", 40.0};
+  FloatProperty m_frequency_max{this, "FrequencyMax", 40.1};
+
 };
 
 #endif // SCINTRECTOOLS_CLOCKRECONSTRUCTIONTOOL_H
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
index 7b442b695..e774f918d 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.cxx
@@ -20,6 +20,7 @@
 
 #include <vector>
 #include <tuple>
+#include <math.h>
 
 // Constructor
 WaveformReconstructionTool::WaveformReconstructionTool(const std::string& type, const std::string& name, const IInterface* parent) :
@@ -168,8 +169,13 @@ WaveformReconstructionTool::reconstruct(const ScintWaveform& raw_wave,
     // Perform Gaussian fit to waveform
     WaveformFitResult gfit = fitGaussian(raw, wtime, wwave);
     if (! gfit.valid) {
-      ATH_MSG_WARNING( " Gaussian waveform fit failed! ");
-      hit->set_status_bit(xAOD::WaveformStatus::GFIT_FAILED);
+      // Lets try again with a more restricted width
+      ATH_MSG_WARNING( " Gaussian waveform fit failed with width " << raw.sigma << " try reducing width to 1 " );
+      raw.sigma = 1.;
+      gfit = fitGaussian(raw, wtime, wwave);
+      if (!gfit.valid) {
+	hit->set_status_bit(xAOD::WaveformStatus::GFIT_FAILED);
+      }
     } 
 
     // Fit results (or raw if it failed)
@@ -455,6 +461,12 @@ WaveformReconstructionTool::findRawHitValues(const std::vector<float> time, cons
 
   ATH_MSG_DEBUG( "Initial Mean: " << rfit.mean << " RMS: " << rfit.sigma << " Peak: " << rfit.peak);  
 
+  // Fix bad values
+  if (isnan(rfit.sigma)) {
+    ATH_MSG_DEBUG("Found sigma: " << rfit.sigma << " Replace with 2.");
+    rfit.sigma = 2.;
+  }
+
   return rfit;
 }
 
@@ -479,7 +491,7 @@ WaveformReconstructionTool::fitGaussian(const WaveformFitResult& raw, const std:
   gfunc.SetParameters(raw.peak, raw.mean, raw.sigma);
   gfunc.SetParError(0, std::sqrt(raw.peak));
   gfunc.SetParError(1, raw.sigma);
-  gfunc.SetParError(2, raw.sigma / 10.);
+  gfunc.SetParError(2, raw.sigma / 5.);
   gfunc.SetParLimits(2, 0., 20.);  // Constrain width
 
   TFitResultPtr gfitptr = tg.Fit(&gfunc, "QNS", "");
@@ -523,9 +535,9 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit,
   cbfit.peak = abs(gfit.peak);
   cbfit.mean = gfit.mean;
   cbfit.sigma = abs(gfit.sigma);
-  if (cbfit.sigma > 20.) cbfit.sigma = 5.;
-  cbfit.alpha = -0.25;  // Negative to get tail on high side
-  cbfit.nval = 3.;
+  if (cbfit.sigma > 20.) cbfit.sigma = 2.;
+  cbfit.alpha = -0.5;  // Negative to get tail on high side
+  cbfit.nval = 2.;
 
   // Define fit function and preset values
   TF1 cbfunc("cbfunc", "crystalball");
@@ -534,16 +546,27 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit,
   cbfunc.SetParameter(1, cbfit.mean); // Mean
   cbfunc.SetParError(1, cbfit.sigma);
   cbfunc.SetParameter(2, cbfit.sigma);  // Width
-  cbfunc.SetParError(2, cbfit.sigma/10.);
+  cbfunc.SetParError(2, cbfit.sigma/5.);
   cbfunc.SetParLimits(2, 0., 20.);
   cbfunc.SetParameter(3, cbfit.alpha); // Tail parameter (negative for high-side tail)
-  cbfunc.SetParError(3, -cbfit.alpha/10.);
+  cbfunc.SetParError(3, -cbfit.alpha/5.);
   cbfunc.SetParLimits(3, -10., 0.);
+  // Try fixing the tail first
+  cbfunc.FixParameter(4, cbfit.nval);
+
+  TFitResultPtr cbfitptr = tg.Fit(&cbfunc, "QNS", "");
+
+  if (!cbfitptr->IsValid()) {
+    ATH_MSG_WARNING( " First Crystal Ball waveform fit failed! ");
+  }
+
+  // Now try releasing the tail parameter
+  cbfunc.ReleaseParameter(4);
   cbfunc.SetParameter(4, cbfit.nval);  // Tail power
-  cbfunc.SetParError(4, cbfit.nval/10.);
+  cbfunc.SetParError(4, cbfit.nval/5.);
   cbfunc.SetParLimits(4, 0., 1.E3);
 
-  TFitResultPtr cbfitptr = tg.Fit(&cbfunc, "QNS", "");
+  cbfitptr = tg.Fit(&cbfunc, "QNS", "");
 
   cbfit.fit_status = cbfitptr;
   cbfit.valid = (cbfit.fit_status == 0);
diff --git a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
index 45a1e9c79..e8b2abf93 100644
--- a/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
+++ b/Scintillator/ScintRecTools/src/WaveformReconstructionTool.h
@@ -80,7 +80,7 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc
 
   //
   // Fraction of peak to set local hit time
-  FloatProperty m_timingPeakFraction{this, "TimingPeakFraction", 0.2};
+  FloatProperty m_timingPeakFraction{this, "TimingPeakFraction", 0.45};
 
   // Baseline algorithms
   WaveformBaselineData& findSimpleBaseline(const ScintWaveform& wave) const;
diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
index 976c51512..8b69c776d 100644
--- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
+++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h
@@ -105,7 +105,7 @@ namespace xAOD {
       this->set_status(this->status() | (1<<bit));
     }
     bool status_bit(WaveformStatus bit) const {
-      return (this->status() | (1<<bit));
+      return (this->status() & (1<<bit));
     }
 
     bool threshold() const {
-- 
GitLab


From f3c859e29d8531fbd674aff0724dc7e85110e9e8 Mon Sep 17 00:00:00 2001
From: Deion Fellers <dfellers@uoregon.edu>
Date: Tue, 18 May 2021 00:31:11 -0700
Subject: [PATCH 45/47] add raw data reco tests to pipeline

---
 .../TrackerDataAccessExample/CMakeLists.txt    |   7 +++++++
 .../python/TrackerDataAccessExampleConfig.py   |   8 ++++++--
 .../TriggerDataAccessExample/CMakeLists.txt    |   6 ++++++
 .../python/TriggerDataAccessExampleConfig.py   |   8 ++++++--
 .../WaveformDataAccessExample/CMakeLists.txt   |   6 ++++++
 .../python/WaveformDataAccessExampleConfig.py  |   8 ++++++--
 .../rawdata/Faser-Physics-001920-filtered.raw  | Bin 0 -> 203852 bytes
 7 files changed, 37 insertions(+), 6 deletions(-)
 mode change 100644 => 100755 Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
 mode change 100644 => 100755 Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
 mode change 100644 => 100755 Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
 create mode 100644 Control/CalypsoExample/rawdata/Faser-Physics-001920-filtered.raw

diff --git a/Control/CalypsoExample/TrackerDataAccessExample/CMakeLists.txt b/Control/CalypsoExample/TrackerDataAccessExample/CMakeLists.txt
index 365f884fe..81fea4e21 100644
--- a/Control/CalypsoExample/TrackerDataAccessExample/CMakeLists.txt
+++ b/Control/CalypsoExample/TrackerDataAccessExample/CMakeLists.txt
@@ -11,3 +11,10 @@ atlas_add_component( TrackerDataAccessExample
                      LINK_LIBRARIES AthenaBaseComps TrackerRawData )
 
 atlas_install_python_modules( python/*.py )
+
+# Test(s) in the package:
+atlas_add_test( TrackerDataAccessTest
+   SCRIPT python/TrackerDataAccessExampleConfig.py ${CMAKE_CURRENT_SOURCE_DIR}
+   PROPERTIES TIMEOUT 300 )
+
+
diff --git a/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py b/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
old mode 100644
new mode 100755
index e4dcd1c1a..0a2d083a8
--- a/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
@@ -1,10 +1,14 @@
+#!/usr/bin/env python
+
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
-#!/usr/bin/env python
 import sys
 from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaCommon.Constants import VERBOSE, INFO
 
+Cmake_working_dir = sys.argv[1]
+print("Cmake_working_dir = ", Cmake_working_dir)
+
 def TrackerDataAccessExampleCfg(flags, name="TrackerDataAccessExampleAlg", **kwargs):
 
     from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
@@ -36,7 +40,7 @@ if __name__ == "__main__":
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # FASER geometry
     ConfigFlags.Input.ProjectName = "data20"                     # Needed to bypass autoconfig
     ConfigFlags.GeoModel.Align.Dynamic    = False
-    ConfigFlags.Input.Files = ["cosmics.raw"]
+    ConfigFlags.Input.Files = [f"{Cmake_working_dir}/../rawdata/Faser-Physics-001920-filtered.raw"] #path is set to test data for ctest
     ConfigFlags.Output.RDOFileName = "my.RDO.pool.root"
     ConfigFlags.lock()
 
diff --git a/Control/CalypsoExample/TriggerDataAccessExample/CMakeLists.txt b/Control/CalypsoExample/TriggerDataAccessExample/CMakeLists.txt
index 3f8b3f195..7d0275a89 100644
--- a/Control/CalypsoExample/TriggerDataAccessExample/CMakeLists.txt
+++ b/Control/CalypsoExample/TriggerDataAccessExample/CMakeLists.txt
@@ -11,3 +11,9 @@ atlas_add_component( TriggerDataAccessExample
                      LINK_LIBRARIES AthenaBaseComps xAODFaserTrigger )
 
 atlas_install_python_modules( python/*.py )
+
+# Test(s) in the package:
+atlas_add_test( TriggerDataAccessTest
+   SCRIPT python/TriggerDataAccessExampleConfig.py ${CMAKE_CURRENT_SOURCE_DIR}
+   PROPERTIES TIMEOUT 300 )
+
diff --git a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
old mode 100644
new mode 100755
index ffab4e9f9..737d03721
--- a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
@@ -1,10 +1,14 @@
+#!/usr/bin/env python
+
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
-#!/usr/bin/env python
 import sys
 from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaCommon.Constants import VERBOSE, INFO
 
+Cmake_working_dir = sys.argv[1]
+print("Cmake_working_dir = ", Cmake_working_dir)
+
 def TriggerDataAccessExampleCfg(flags, name="TriggerDataAccessExampleAlg", **kwargs):
 
     from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
@@ -36,7 +40,7 @@ if __name__ == "__main__":
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Input.ProjectName = "data20"
     ConfigFlags.GeoModel.Align.Dynamic    = False
-    ConfigFlags.Input.Files = ["cosmics.raw"]
+    ConfigFlags.Input.Files = [f"{Cmake_working_dir}/../rawdata/Faser-Physics-001920-filtered.raw"] #path is set to test data for ctest
     ConfigFlags.Output.RDOFileName = "trigger.RDO.pool.root"
     ConfigFlags.lock()
 
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/CMakeLists.txt b/Control/CalypsoExample/WaveformDataAccessExample/CMakeLists.txt
index 54626a0a2..69bfbf2e2 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/CMakeLists.txt
+++ b/Control/CalypsoExample/WaveformDataAccessExample/CMakeLists.txt
@@ -11,3 +11,9 @@ atlas_add_component( WaveformDataAccessExample
                      LINK_LIBRARIES AthenaBaseComps ScintRawEvent )
 
 atlas_install_python_modules( python/*.py )
+
+# Test(s) in the package:
+atlas_add_test( WaveformDataAccessTest
+   SCRIPT python/WaveformDataAccessExampleConfig.py ${CMAKE_CURRENT_SOURCE_DIR}
+   PROPERTIES TIMEOUT 300 )
+
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py b/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
old mode 100644
new mode 100755
index d46ef7491..5d0cfcdea
--- a/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
@@ -1,10 +1,14 @@
+#!/usr/bin/env python
+
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
-#!/usr/bin/env python
 import sys
 from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaCommon.Constants import VERBOSE, INFO
 
+Cmake_working_dir = sys.argv[1]
+print("Cmake_working_dir = ", Cmake_working_dir)
+
 def WaveformDataAccessExampleCfg(flags, name="WaveformDataAccessExampleAlg", **kwargs):
 
     from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
@@ -36,7 +40,7 @@ if __name__ == "__main__":
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Input.ProjectName = "data20"
     ConfigFlags.GeoModel.Align.Dynamic    = False
-    ConfigFlags.Input.Files = ["cosmics.raw"]
+    ConfigFlags.Input.Files = [f"{Cmake_working_dir}/../rawdata/Faser-Physics-001920-filtered.raw"] #path is set to test data for ctest
     ConfigFlags.Output.RDOFileName = "waveform.RDO.pool.root"
     ConfigFlags.lock()
 
diff --git a/Control/CalypsoExample/rawdata/Faser-Physics-001920-filtered.raw b/Control/CalypsoExample/rawdata/Faser-Physics-001920-filtered.raw
new file mode 100644
index 0000000000000000000000000000000000000000..eecc1b6dc76b0d430312eaf999d95429d63bc6c9
GIT binary patch
literal 203852
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
N>}J#Es;#$b{|~AJp)&vg

literal 0
HcmV?d00001

-- 
GitLab


From 90877f5a0a15437e3132c68a76bb273f68c70d54 Mon Sep 17 00:00:00 2001
From: Deion Fellers <dfellers@uoregon.edu>
Date: Tue, 1 Jun 2021 14:32:01 -0700
Subject: [PATCH 46/47] Made NoisyStripFinder package in order to create a
 noisy strip database from RAW data files

---
 .../NoisyStripFinder/CMakeLists.txt           |  21 +++
 .../python/NoisyStripFinderConfig.py          |  24 ++++
 .../NoisyStripFinder/python/__init__.py       |   0
 .../share/NoisyStripFinderHist_Analysis.py    |  83 +++++++++++
 .../NoisyStripFinder/src/NoisyStripFinder.cxx | 133 ++++++++++++++++++
 .../NoisyStripFinder/src/NoisyStripFinder.h   |  87 ++++++++++++
 .../components/NoisyStripFinder_entries.cxx   |   4 +
 7 files changed, 352 insertions(+)
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/python/__init__.py
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
 create mode 100644 Tracker/TrackerRecAlgs/NoisyStripFinder/src/components/NoisyStripFinder_entries.cxx

diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt b/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt
new file mode 100644
index 000000000..29e80551e
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt
@@ -0,0 +1,21 @@
+################################################################################
+# Package: NoisyStripFinder
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NoisyStripFinder )
+
+# Component(s) in the package:
+atlas_add_component( NoisyStripFinder
+                     src/*.cxx src/*.h
+                     src/components/*.cxx
+                     LINK_LIBRARIES AthenaBaseComps StoreGateLib SGtests Identifier GaudiKernel TrackerRawData TrackerPrepRawData FaserDetDescr TrackerIdentifier 
+                                    TrackerReadoutGeometry AthViews FaserSCT_ConditionsData xAODFaserTrigger )
+
+# Install files from the package:
+#atlas_install_headers( TrackerPrepRawDataFormation )
+
+atlas_install_python_modules( python/*.py )
+
+#atlas_install_scripts( test/*.py )
+
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
new file mode 100644
index 000000000..e0a6aa97d
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
@@ -0,0 +1,24 @@
+"""
+Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def NoisyStripFinderBasicCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    kwargs.setdefault("DataObjectName", "SCT_RDOs")
+    Tracker__NoisyStripFinder = CompFactory.Tracker.NoisyStripFinder
+    acc.addEventAlgo(Tracker__NoisyStripFinder(**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST1 DATAFILE='NoisyStripFinderHist.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+    return acc
+
+
+def NoisyStripFinderCfg(flags, **kwargs):
+    acc = NoisyStripFinderBasicCfg(flags, **kwargs)
+    return acc
+
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/__init__.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py
new file mode 100644
index 000000000..349316b31
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+
+# This script combines the strip occupancy histograms from NoisyStripFinderHist.root files then it generates a pdf with sumarry plots and an XML file with a list of noisy strips
+
+# Set up (Py)ROOT.
+import ROOT
+import xml.etree.ElementTree as ET
+
+ROOT.gStyle.SetOptStat(0) #take away option box in histograms
+ROOT.gStyle.SetOptTitle(1)
+#ROOT.gROOT.SetStyle("ATLAS")
+
+def GetKeyNames( self ): # gets a list of object names in a root file
+    return [key.GetName() for key in f.GetListOfKeys()]
+ROOT.TFile.GetKeyNames = GetKeyNames
+
+numEvents = 0
+nfiles = 0
+HistDict = {}
+
+ROOT.TH1.AddDirectory(0) # This is necessary in order to have the histogram data after closing the file
+
+for inputfile in ["./NoisyStripFinderHist.root"]:
+    print("opening root file ",inputfile)
+    f = ROOT.TFile.Open(inputfile, "r")
+    numEvents += f.Get("numEvents").GetVal()
+    if nfiles == 0:
+        trigger = f.Get("trigger").GetVal()
+    for rootkey in f.GetKeyNames():
+        if rootkey == 'numEvents' or rootkey == 'trigger':
+            continue # skip over the root objects TParameters that store the trigger and number of events data
+        if rootkey in HistDict: # if sensor histogram has already been stored, then add to it 
+            HistDict[rootkey].Add(f.Get(rootkey),1.0)
+        else: # if sensor histogram has not already been stored, then store this histogram
+            HistDict[rootkey] = f.Get(rootkey).Clone()
+
+    nfiles += 1
+
+    # Good to cleanup
+    f.Close()
+
+print("Total # of root files analyzed = ", nfiles)
+print("Trigger mask = ", trigger)
+print("Total number of events = ", numEvents)
+
+# Now make some plots
+filename = "NoisyStripFinderHist_Analysis.pdf"
+
+c = ROOT.TCanvas()
+c.Print(filename+'[')
+
+for dictkey in HistDict:
+    c = ROOT.TCanvas()
+    c.Divide(1,2)
+    c.cd(1)
+    tempHist = HistDict[dictkey].Clone()
+    tempHist.Draw("")
+    c.cd(2)
+    HistDict[dictkey].Scale(1.0/float(numEvents)) # Normalize histrograms by total event number in order to get occupancies
+    HistDict[dictkey].GetYaxis().SetTitle("Strip Occupancy")
+    HistDict[dictkey].Draw("")
+#    ROOT.gPad.SetLogy()
+    c.Print(filename)
+
+c.Print(filename+']') # Must close file at the end
+
+# Now make an XML file to store noisy strip data
+root = ET.Element('NoisyStripData')
+for dictkey in HistDict:
+    sensorhash = ET.SubElement(root, "Sensor_Hash")
+    sensorhash.text = dictkey
+    bini = 1
+    while bini <= 768:
+        if HistDict[dictkey].GetBinContent(bini) >= 0.1 :
+            strip = ET.SubElement(sensorhash, "Strip")
+            strip.text = str(bini - 1) # strip number is offset by histogram bin number by 1 because of underflow bin
+            occupancy = ET.SubElement(strip, "Occupancy")
+            occupancy.text = str(HistDict[dictkey].GetBinContent(bini))
+        bini += 1           
+ 
+tree = ET.ElementTree(root)
+tree.write("NoisyPixels.xml")
+
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
new file mode 100644
index 000000000..af12a923c
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
@@ -0,0 +1,133 @@
+/*
+   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+   */
+
+#include "NoisyStripFinder.h"
+
+#include "FaserDetDescr/FaserDetectorID.h"    
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerRawData/FaserSCT_RDO_Container.h"
+#include "TrackerRawData/FaserSCT_RDORawData.h"
+#include "StoreGate/WriteHandle.h"
+
+#include <sstream>
+#include <string.h>
+#include <TH1.h>
+#include <TFile.h>
+#include <TParameter.h>
+
+namespace Tracker
+{
+// Constructor with parameters:
+NoisyStripFinder::NoisyStripFinder(const std::string& name, ISvcLocator* pSvcLocator) :
+  AthReentrantAlgorithm(name, pSvcLocator),
+  m_idHelper{nullptr}
+{
+}
+
+// Initialize method:
+StatusCode NoisyStripFinder::initialize() {
+  ATH_MSG_INFO("NoisyStripFinder::initialize()!");
+
+  ATH_CHECK(m_rdoContainerKey.initialize());
+  ATH_CHECK(m_FaserTriggerData.initialize());
+
+  // Get the SCT ID helper
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+
+  return StatusCode::SUCCESS;
+}
+
+// Execute method:
+StatusCode NoisyStripFinder::execute(const EventContext& ctx) const {
+
+  SG::ReadHandle<xAOD::FaserTriggerData> xaod(m_FaserTriggerData, ctx);
+  int trig = xaod->tap();
+
+  ATH_MSG_INFO("Found FaserTriggerData");
+  ATH_MSG_INFO("trigger = " << trig);
+  ATH_MSG_INFO("mask = " << trigmask);
+
+//  if (xaod->tap() & mask){
+  if (trig == trigmask){
+    ATH_MSG_INFO("trigger passed mask");
+    ++m_numberOfEvents;                                                                
+
+    // First, we have to retrieve and access the container, not because we want to 
+    // use it, but in order to generate the proxies for the collections, if they 
+    // are being provided by a container converter.
+    SG::ReadHandle<FaserSCT_RDO_Container> rdoContainer{m_rdoContainerKey, ctx};
+    ATH_CHECK(rdoContainer.isValid());
+
+    // Anything to dereference the DataHandle will trigger the converter
+    FaserSCT_RDO_Container::const_iterator rdoCollections{rdoContainer->begin()};
+    FaserSCT_RDO_Container::const_iterator rdoCollectionsEnd{rdoContainer->end()};
+    for (; rdoCollections != rdoCollectionsEnd; ++rdoCollections) {
+      ++m_numberOfRDOCollection;
+      const TrackerRawDataCollection<FaserSCT_RDORawData>* rd{*rdoCollections};
+      ATH_MSG_DEBUG("RDO collection size=" << rd->size() << ", Hash=" << rd->identifyHash());
+      for (const FaserSCT_RDORawData* pRawData: *rd) {
+        ++m_numberOfRDO;
+        const Identifier      firstStripId(pRawData->identify());
+//        const unsigned int    nStrips(pRawData->getGroupSize());
+        const int             thisStrip(m_idHelper->strip(firstStripId));
+        ATH_MSG_DEBUG( "---------- new rdo ----------------------------- " );
+        ATH_MSG_DEBUG( "rd->identifyHash() = " << rd->identifyHash() );
+        ATH_MSG_DEBUG( "strip = " << thisStrip );
+
+        if ( NoisyStrip_histmap.count(rd->identifyHash()) == 0 ) { // map.count(key) returns 1 if the key exists and 0 if it does not
+          std::string histname_str = std::to_string(rd->identifyHash());
+          char const *histname = histname_str.c_str();
+          std::string station_num = std::to_string(m_idHelper->station(firstStripId));
+          std::string layer_num = std::to_string(m_idHelper->layer(firstStripId));
+          std::string phi_num = std::to_string(m_idHelper->phi_module(firstStripId));
+          std::string eta_num = std::to_string(m_idHelper->eta_module(firstStripId));
+          std::string side_num = std::to_string(m_idHelper->side(firstStripId));
+          std::string hist_title_str = "Station " + station_num + " | Layer " + layer_num + " | phi-module " + phi_num + " | eta-module " + eta_num + " | Side " + side_num + "; strip number; # of events";
+          char const *hist_title = hist_title_str.c_str();
+          NoisyStrip_histmap[rd->identifyHash()] = new TH1F(histname, hist_title, 768, -0.5, 767.5);
+        } 
+        NoisyStrip_histmap[rd->identifyHash()]->Fill(thisStrip); // increase the value by one so as to count the number of times the strip was active
+        
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+// Finalize method:
+StatusCode NoisyStripFinder::finalize() 
+{
+  ATH_MSG_INFO("NoisyStripFinder::finalize()");
+  ATH_MSG_INFO( m_numberOfEvents << " events processed" );
+  ATH_MSG_INFO( m_numberOfRDOCollection << " RDO collections processed" );
+  ATH_MSG_INFO( m_numberOfRDO<< " RawData" );
+
+  outputfile = new TFile("NoisyStripFinderHist.root","RECREATE");
+
+  TParameter("numEvents", m_numberOfEvents).Write();
+  TParameter("trigger", trigmask).Write();
+
+  std::map<int,TH1F*>::iterator it = NoisyStrip_histmap.begin();
+  // Iterate over the map using Iterator till end.
+  while (it != NoisyStrip_histmap.end()){
+    ATH_MSG_INFO( "" );
+    ATH_MSG_INFO( "Tracker Sensor hash = " << it->first );
+    ATH_MSG_INFO( "---------- hot strip occupancy >= 0.1 ----------" );
+    int i = 1;
+    while (i <= 768){
+      if ( it->second->GetBinContent(i)/(double)m_numberOfEvents >= 0.1 ){
+        ATH_MSG_INFO( "hot strip # = " << i-1 << ", hit occupancy = " << it->second->GetBinContent(i)/(double)m_numberOfEvents );
+      }
+      i++;
+    }
+    it->second->Write();
+    it++;
+  }
+
+  outputfile->Close();
+
+  return StatusCode::SUCCESS;
+}
+}
+
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
new file mode 100644
index 000000000..34b908e5e
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
@@ -0,0 +1,87 @@
+/*
+   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+   */
+
+#ifndef NoisyStripFinder_H
+#define NoisyStripFinder_H
+
+// Base class
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+
+////Next contains a typedef so cannot be fwd declared
+#include "TrackerRawData/FaserSCT_RDO_Container.h"
+#include "xAODFaserTrigger/FaserTriggerData.h"
+
+//Gaudi
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/ToolHandle.h"
+
+#include "StoreGate/ReadHandleKey.h"
+
+
+//STL
+#include <map>
+#include <TH1.h>
+#include <TFile.h>
+#include <TParameter.h>
+
+class FaserSCT_ID;
+class ISvcLocator;
+class StatusCode;
+
+namespace Tracker
+{
+
+/**
+ *    @class NoisyStripFinder
+ *    @brief Creates histograms with strip occupancy data from SCT Raw Data Objects
+ *    Creates histograms with strip occupancy data from SCT Raw Data Objects. Root files containing strip occupancy histograms can then be combined and analyzed (example pyROOT script in share folder) in order to make an XML database of noisy strips.
+ */
+class NoisyStripFinder : public AthReentrantAlgorithm {
+  public:
+    /// Constructor with parameters:
+    NoisyStripFinder(const std::string& name, ISvcLocator* pSvcLocator);
+
+    /**    @name Usual algorithm methods */
+    //@{
+    ///Retrieve the tools used and initialize variables
+    virtual StatusCode initialize() override;
+    ///Form clusters and record them in StoreGate (detector store)
+    virtual StatusCode execute(const EventContext& ctx) const override;
+    ///Clean up and release the collection containers
+    virtual StatusCode finalize() override;
+    //Make this algorithm clonable.
+    virtual bool isClonable() const override { return true; };
+    //@}
+
+  private:
+    /**    @name Disallow default instantiation, copy, assignment */
+    //@{
+    //NoisyStripFinder() = delete;
+    //NoisyStripFinder(const NoisyStripFinder&) = delete;
+    //NoisyStripFinder &operator=(const NoisyStripFinder&) = delete;
+    //@}
+
+    const FaserSCT_ID* m_idHelper;
+
+    SG::ReadHandleKey<FaserSCT_RDO_Container> m_rdoContainerKey{this, "DataObjectName", "FaserSCT_RDOs", "FaserSCT RDOs"};
+
+    SG::ReadHandleKey<xAOD::FaserTriggerData> m_FaserTriggerData{ this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"};
+
+//    mutable std::uint8_t mask;
+    mutable int trigmask = 4; // define the trig mask default
+
+    mutable int m_numberOfEvents{0};
+    mutable std::atomic<int> m_numberOfRDOCollection{0};
+    mutable std::atomic<int> m_numberOfRDO{0};
+
+    mutable std::map<int,TH1F*> NoisyStrip_histmap;
+
+    mutable TParameter<int> Nevents;
+
+    mutable TFile* outputfile;
+
+};
+}
+#endif // NoisyStripFinder_H
+
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/components/NoisyStripFinder_entries.cxx b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/components/NoisyStripFinder_entries.cxx
new file mode 100644
index 000000000..811dcec28
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/components/NoisyStripFinder_entries.cxx
@@ -0,0 +1,4 @@
+#include "../NoisyStripFinder.h"
+
+DECLARE_COMPONENT( Tracker::NoisyStripFinder )
+
-- 
GitLab


From 2f26f27bfdd79e7e6b1682942bfda880db458038 Mon Sep 17 00:00:00 2001
From: Deion Fellers <dfellers@uoregon.edu>
Date: Thu, 3 Jun 2021 15:34:55 -0700
Subject: [PATCH 47/47] updating NoisyStripFinder package to be cleaner and
 configurable

---
 .../python/NoisyStripFinderConfig.py          |   6 +-
 .../NoisyStripFinder/src/NoisyStripFinder.cxx | 118 ++++++++++--------
 .../NoisyStripFinder/src/NoisyStripFinder.h   |  16 ++-
 3 files changed, 73 insertions(+), 67 deletions(-)

diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
index e0a6aa97d..5e94a1fb0 100644
--- a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py
@@ -9,12 +9,10 @@ from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
 def NoisyStripFinderBasicCfg(flags, **kwargs):
     acc = FaserSCT_GeometryCfg(flags)
     kwargs.setdefault("DataObjectName", "SCT_RDOs")
+    kwargs.setdefault("OutputHistRootName", "NoisyStripFinderHist.root")
+    kwargs.setdefault("TriggerMask", 0x10)
     Tracker__NoisyStripFinder = CompFactory.Tracker.NoisyStripFinder
     acc.addEventAlgo(Tracker__NoisyStripFinder(**kwargs))
-
-    thistSvc = CompFactory.THistSvc()
-    thistSvc.Output += ["HIST1 DATAFILE='NoisyStripFinderHist.root' OPT='RECREATE'"]
-    acc.addService(thistSvc)
     return acc
 
 
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
index af12a923c..71598696b 100644
--- a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx
@@ -12,6 +12,7 @@
 
 #include <sstream>
 #include <string.h>
+#include <list>
 #include <TH1.h>
 #include <TFile.h>
 #include <TParameter.h>
@@ -42,54 +43,53 @@ StatusCode NoisyStripFinder::initialize() {
 StatusCode NoisyStripFinder::execute(const EventContext& ctx) const {
 
   SG::ReadHandle<xAOD::FaserTriggerData> xaod(m_FaserTriggerData, ctx);
-  int trig = xaod->tap();
-
-  ATH_MSG_INFO("Found FaserTriggerData");
-  ATH_MSG_INFO("trigger = " << trig);
-  ATH_MSG_INFO("mask = " << trigmask);
-
-//  if (xaod->tap() & mask){
-  if (trig == trigmask){
-    ATH_MSG_INFO("trigger passed mask");
-    ++m_numberOfEvents;                                                                
-
-    // First, we have to retrieve and access the container, not because we want to 
-    // use it, but in order to generate the proxies for the collections, if they 
-    // are being provided by a container converter.
-    SG::ReadHandle<FaserSCT_RDO_Container> rdoContainer{m_rdoContainerKey, ctx};
-    ATH_CHECK(rdoContainer.isValid());
-
-    // Anything to dereference the DataHandle will trigger the converter
-    FaserSCT_RDO_Container::const_iterator rdoCollections{rdoContainer->begin()};
-    FaserSCT_RDO_Container::const_iterator rdoCollectionsEnd{rdoContainer->end()};
-    for (; rdoCollections != rdoCollectionsEnd; ++rdoCollections) {
-      ++m_numberOfRDOCollection;
-      const TrackerRawDataCollection<FaserSCT_RDORawData>* rd{*rdoCollections};
-      ATH_MSG_DEBUG("RDO collection size=" << rd->size() << ", Hash=" << rd->identifyHash());
-      for (const FaserSCT_RDORawData* pRawData: *rd) {
-        ++m_numberOfRDO;
-        const Identifier      firstStripId(pRawData->identify());
-//        const unsigned int    nStrips(pRawData->getGroupSize());
-        const int             thisStrip(m_idHelper->strip(firstStripId));
-        ATH_MSG_DEBUG( "---------- new rdo ----------------------------- " );
-        ATH_MSG_DEBUG( "rd->identifyHash() = " << rd->identifyHash() );
-        ATH_MSG_DEBUG( "strip = " << thisStrip );
-
-        if ( NoisyStrip_histmap.count(rd->identifyHash()) == 0 ) { // map.count(key) returns 1 if the key exists and 0 if it does not
-          std::string histname_str = std::to_string(rd->identifyHash());
-          char const *histname = histname_str.c_str();
-          std::string station_num = std::to_string(m_idHelper->station(firstStripId));
-          std::string layer_num = std::to_string(m_idHelper->layer(firstStripId));
-          std::string phi_num = std::to_string(m_idHelper->phi_module(firstStripId));
-          std::string eta_num = std::to_string(m_idHelper->eta_module(firstStripId));
-          std::string side_num = std::to_string(m_idHelper->side(firstStripId));
-          std::string hist_title_str = "Station " + station_num + " | Layer " + layer_num + " | phi-module " + phi_num + " | eta-module " + eta_num + " | Side " + side_num + "; strip number; # of events";
-          char const *hist_title = hist_title_str.c_str();
-          NoisyStrip_histmap[rd->identifyHash()] = new TH1F(histname, hist_title, 768, -0.5, 767.5);
-        } 
-        NoisyStrip_histmap[rd->identifyHash()]->Fill(thisStrip); // increase the value by one so as to count the number of times the strip was active
-        
-      }
+
+  int trig_int = xaod->tap();
+  int trigmask_int = m_triggerMask.value();
+
+  ATH_MSG_DEBUG("Found FaserTriggerData");
+  ATH_MSG_DEBUG("trigger = " << trig_int);
+  ATH_MSG_DEBUG("mask = " << trigmask_int);
+
+  if (!(xaod->tap() & m_triggerMask.value())) return StatusCode::SUCCESS; // only process events that pass the trigger mask
+
+  ATH_MSG_INFO("trigger passed mask");
+  ++m_numberOfEvents;                                                                
+
+  // First, we have to retrieve and access the container, not because we want to 
+  // use it, but in order to generate the proxies for the collections, if they 
+  // are being provided by a container converter.
+  SG::ReadHandle<FaserSCT_RDO_Container> rdoContainer{m_rdoContainerKey, ctx};
+  ATH_CHECK(rdoContainer.isValid());
+
+  // Anything to dereference the DataHandle will trigger the converter
+  FaserSCT_RDO_Container::const_iterator rdoCollections{rdoContainer->begin()};
+  FaserSCT_RDO_Container::const_iterator rdoCollectionsEnd{rdoContainer->end()};
+  for (; rdoCollections != rdoCollectionsEnd; ++rdoCollections) {
+    ++m_numberOfRDOCollection;
+    const TrackerRawDataCollection<FaserSCT_RDORawData>* rd{*rdoCollections};
+    ATH_MSG_DEBUG("RDO collection size=" << rd->size() << ", Hash=" << rd->identifyHash());
+    for (const FaserSCT_RDORawData* pRawData: *rd) {
+      ++m_numberOfRDO;
+      const Identifier      firstStripId(pRawData->identify());
+      const int             thisStrip(m_idHelper->strip(firstStripId));
+      ATH_MSG_DEBUG( "---------- new rdo ----------------------------- " );
+      ATH_MSG_DEBUG( "rd->identifyHash() = " << rd->identifyHash() );
+      ATH_MSG_DEBUG( "strip = " << thisStrip );
+
+      if ( NoisyStrip_histmap.count(rd->identifyHash()) == 0 ) { // map.count(key) returns 1 if the key exists and 0 if it does not
+        std::string histname_str = std::to_string(rd->identifyHash());
+        char const *histname = histname_str.c_str();
+        std::string station_num = std::to_string(m_idHelper->station(firstStripId));
+        std::string layer_num = std::to_string(m_idHelper->layer(firstStripId));
+        std::string phi_num = std::to_string(m_idHelper->phi_module(firstStripId));
+        std::string eta_num = std::to_string(m_idHelper->eta_module(firstStripId));
+        std::string side_num = std::to_string(m_idHelper->side(firstStripId));
+        std::string hist_title_str = "Station " + station_num + " | Layer " + layer_num + " | phi-module " + phi_num + " | eta-module " + eta_num + " | Side " + side_num + "; strip number; # of events";
+        char const *hist_title = hist_title_str.c_str();
+        NoisyStrip_histmap[rd->identifyHash()] = new TH1D(histname, hist_title, 768, -0.5, 767.5);
+      } 
+      NoisyStrip_histmap[rd->identifyHash()]->Fill(thisStrip); // increase the value by one so as to count the number of times the strip was active    
     }
   }
   return StatusCode::SUCCESS;
@@ -102,22 +102,32 @@ StatusCode NoisyStripFinder::finalize()
   ATH_MSG_INFO( m_numberOfEvents << " events processed" );
   ATH_MSG_INFO( m_numberOfRDOCollection << " RDO collections processed" );
   ATH_MSG_INFO( m_numberOfRDO<< " RawData" );
+  ATH_MSG_INFO( "Number of sensors found = " << NoisyStrip_histmap.size() << " out of 144" );
+
+  for (int ihash = 0; ihash < 144; ++ihash){ // print out the sensors that are missing 
+    if ( NoisyStrip_histmap.count(ihash) == 0 ){
+      ATH_MSG_INFO("missing sensor # " << ihash);
+    }
+  }
+
+  const char *outputname = m_OutputRootName.value().c_str();
+
+  TFile* outputfile = new TFile(outputname,"RECREATE");
 
-  outputfile = new TFile("NoisyStripFinderHist.root","RECREATE");
+  int trigmask_int = m_triggerMask.value();
 
   TParameter("numEvents", m_numberOfEvents).Write();
-  TParameter("trigger", trigmask).Write();
+  TParameter("trigger", trigmask_int).Write();
 
-  std::map<int,TH1F*>::iterator it = NoisyStrip_histmap.begin();
+  std::map<int,TH1D*>::iterator it = NoisyStrip_histmap.begin();
   // Iterate over the map using Iterator till end.
   while (it != NoisyStrip_histmap.end()){
     ATH_MSG_INFO( "" );
-    ATH_MSG_INFO( "Tracker Sensor hash = " << it->first );
-    ATH_MSG_INFO( "---------- hot strip occupancy >= 0.1 ----------" );
+    ATH_MSG_INFO( "---------- hot strip occupancy >= 0.1 for Tracker Sensor hash = "<< it->first <<" ----------" );
     int i = 1;
     while (i <= 768){
       if ( it->second->GetBinContent(i)/(double)m_numberOfEvents >= 0.1 ){
-        ATH_MSG_INFO( "hot strip # = " << i-1 << ", hit occupancy = " << it->second->GetBinContent(i)/(double)m_numberOfEvents );
+        ATH_MSG_INFO( "hot strip # = " << i-1 << ", hit occupancy = " << it->second->GetBinContent(i)/(double)m_numberOfEvents ); // print out hot strips
       }
       i++;
     }
diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
index 34b908e5e..a1d977595 100644
--- a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
+++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h
@@ -25,6 +25,8 @@
 #include <TFile.h>
 #include <TParameter.h>
 
+#include <string>
+
 class FaserSCT_ID;
 class ISvcLocator;
 class StatusCode;
@@ -62,24 +64,20 @@ class NoisyStripFinder : public AthReentrantAlgorithm {
     //NoisyStripFinder &operator=(const NoisyStripFinder&) = delete;
     //@}
 
+    StringProperty m_OutputRootName{this, "OutputHistRootName", "NoisyStripFinderHist.root", "Name of output histogram root file for NoisyStripFinder"};
+
+    UnsignedIntegerProperty m_triggerMask{this, "TriggerMask", 0x10, "Trigger mask (0x10 = random trig)"};
+
     const FaserSCT_ID* m_idHelper;
 
     SG::ReadHandleKey<FaserSCT_RDO_Container> m_rdoContainerKey{this, "DataObjectName", "FaserSCT_RDOs", "FaserSCT RDOs"};
-
     SG::ReadHandleKey<xAOD::FaserTriggerData> m_FaserTriggerData{ this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"};
 
-//    mutable std::uint8_t mask;
-    mutable int trigmask = 4; // define the trig mask default
-
     mutable int m_numberOfEvents{0};
     mutable std::atomic<int> m_numberOfRDOCollection{0};
     mutable std::atomic<int> m_numberOfRDO{0};
 
-    mutable std::map<int,TH1F*> NoisyStrip_histmap;
-
-    mutable TParameter<int> Nevents;
-
-    mutable TFile* outputfile;
+    mutable std::map<int,TH1D*> NoisyStrip_histmap;
 
 };
 }
-- 
GitLab