diff --git a/Calorimeter/CaloDetDescr/EcalGeoModel/test/EcalGMConfig_test.py b/Calorimeter/CaloDetDescr/EcalGeoModel/test/EcalGMConfig_test.py
index 9df7d390796ae700181f0922c38e30b1bf33bd6e..18ac17cf213e582a9165c0b6475f5267b0e635b0 100644
--- a/Calorimeter/CaloDetDescr/EcalGeoModel/test/EcalGMConfig_test.py
+++ b/Calorimeter/CaloDetDescr/EcalGeoModel/test/EcalGMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.Detector.EnableEcal = True
     ConfigFlags.GeoModel.Align.Dynamic    = False
     ConfigFlags.lock()
diff --git a/Control/CalypsoCommon/python/GlobalFlags.py b/Control/CalypsoCommon/python/GlobalFlags.py
index d620bd8be430ee81aad8ed285bc6f73074c32bb0..0fe1ac4e4bc06982ee7e7e318d8657b8554a9bc6 100644
--- a/Control/CalypsoCommon/python/GlobalFlags.py
+++ b/Control/CalypsoCommon/python/GlobalFlags.py
@@ -67,7 +67,7 @@ class ConditionsTag(JobProperty):
      """
      statusOn=True
      allowedTypes=['str']
-     StoredValue='OFLCOND-XXXX-XXX-XX'
+     StoredValue='OFLCOND-FASER-01'
 
 #
 class DatabaseInstance(JobProperty):
diff --git a/Control/CalypsoConfiguration/python/DetectorConfigFlags.py b/Control/CalypsoConfiguration/python/DetectorConfigFlags.py
index fb0c315a7383e8c3888b2b7a9a6dcbce58af9941..5588000a509db94c0317d831ab1893a1461dde17 100644
--- a/Control/CalypsoConfiguration/python/DetectorConfigFlags.py
+++ b/Control/CalypsoConfiguration/python/DetectorConfigFlags.py
@@ -7,10 +7,11 @@ from CalypsoConfiguration.AutoConfigFlags import DetDescrInfo, getDefaultDetecto
 
 
 allDetectors = [
-    'Veto', 'Trigger', 'Preshower', 'FaserSCT', 'Ecal', 'Dipole', 
+    'Emulsion', 'Veto', 'Trigger', 'Preshower', 'FaserSCT', 'Ecal', 'Dipole', 
 ]
 
 allGroups = {
+    'Neutrino' : [ 'Emulsion' ],
     'Tracker' : ['SCT'],
     'Scintillator' : ['Veto', 'Trigger', 'Preshower'],
     'FaserCalo'  : ['Ecal'],
@@ -21,6 +22,10 @@ def createDetectorConfigFlags():
     dcf=AthConfigFlags()
 
     #Detector.Geometry - merger of the old geometry and detdescr tasks
+
+    dcf.addFlag('Detector.GeometryEmulsion',       False)
+    dcf.addFlag('Detector.GeometryNeutrino',       lambda prevFlags : (prevFlags.Detector.GeometryEmulsion))
+
     dcf.addFlag('Detector.GeometryDipole',          False)
     dcf.addFlag('Detector.GeometryMagnet',          lambda prevFlags : (prevFlags.Detector.GeometryDipole ))
     
@@ -54,6 +59,10 @@ def createDetectorConfigFlags():
     #                                                                     prevFlags.Detector.EnableCentralDipole or
     #                                                                     prevFlags.Detector.EnableDownstreamDipole))
     # dcf.addFlag('Detector.EnableDecayVolume', False)
+
+    dcf.addFlag('Detector.EnableEmulsion',   lambda prevFlags : 'Emulsion' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion))
+    dcf.addFlag('Detector.EnableNeutrino',   lambda prevFlags : (prevFlags.Detector.EnableEmulsion))
+
     dcf.addFlag('Detector.EnableVeto',        lambda prevFlags : 'Veto' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion))
     dcf.addFlag('Detector.EnableTrigger',     lambda prevFlags : 'Trigger' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion))
     dcf.addFlag('Detector.EnablePreshower',   lambda prevFlags : 'Preshower' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion))
@@ -70,6 +79,9 @@ def createDetectorConfigFlags():
     #                                                                 prevFlags.Detector.EnableFaserCalo))
 
     # Reco flags
+    dcf.addFlag('Detector.RecoEmulsion', False)
+    dcf.addFlag('Detector.RecoNeutrino', lambda prevFlags : (prevFlags.Detector.RecoEmulsion))
+
     dcf.addFlag('Detector.RecoVeto', False)
     dcf.addFlag('Detector.RecoTrigger', False)
     dcf.addFlag('Detector.RecoPreshower', False)
@@ -77,7 +89,7 @@ def createDetectorConfigFlags():
     dcf.addFlag('Detector.RecoWaveform', lambda prevFlags : (prevFlags.Detector.RecoVeto or prevFlags.Detector.RecoTrigger or 
                                                              prevFlags.Detector.RecoPreshower or prevFlags.Detector.RecoEcal))
     dcf.addFlag('Detector.RecoFaserSCT', False)
-    dcf.addFlag('Detector.RecoTracker', lambda prevFlags : (prevFlags.Detector.RecoSCT))
+    dcf.addFlag('Detector.RecoTracker', lambda prevFlags : (prevFlags.Detector.RecoFaserSCT))
 
     return dcf
 
diff --git a/Control/CalypsoExample/GenEventExample/python/GenEventReadExampleConfig.py b/Control/CalypsoExample/GenEventExample/python/GenEventReadExampleConfig.py
index 28073eb6912b68aa7844dd524d051082c03a62ff..1b84f6160a0b6adb417d4c4ff276b6146b9515ed 100644
--- a/Control/CalypsoExample/GenEventExample/python/GenEventReadExampleConfig.py
+++ b/Control/CalypsoExample/GenEventExample/python/GenEventReadExampleConfig.py
@@ -26,7 +26,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Detector.EnableFaserSCT = True
     ConfigFlags.Input.Files = ["my.cosmics.pool.root"]
diff --git a/Control/CalypsoExample/GeoModelTest/python/GeoModelTestConfig.py b/Control/CalypsoExample/GeoModelTest/python/GeoModelTestConfig.py
index e7f6feb7f9bcce18af1dccf3f0e57d403ea9844a..ad33f2cf97c66ba18a5d1902fdc1f9d8b58cb85f 100644
--- a/Control/CalypsoExample/GeoModelTest/python/GeoModelTestConfig.py
+++ b/Control/CalypsoExample/GeoModelTest/python/GeoModelTestConfig.py
@@ -30,7 +30,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.GeoModel.GeoExportFile    = "faserGeo.db"        # Writes out a GeoModel file with the full geometry tree (optional, comment out to skip)
     # ConfigFlags.Detector.EnableVeto     = True
diff --git a/Control/CalypsoExample/RDOReadExample/python/RDOReadExampleConfig.py b/Control/CalypsoExample/RDOReadExample/python/RDOReadExampleConfig.py
index fcaea799841a83b3ed152d8e139d931136e06968..7bffba5eef6cab66207ea2a28df9c2ab4512edd0 100644
--- a/Control/CalypsoExample/RDOReadExample/python/RDOReadExampleConfig.py
+++ b/Control/CalypsoExample/RDOReadExample/python/RDOReadExampleConfig.py
@@ -26,7 +26,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Detector.GeometryFaserSCT = True
     ConfigFlags.Input.Files = ["my.RDO.pool.root"]
diff --git a/Control/CalypsoExample/SimHitExample/CMakeLists.txt b/Control/CalypsoExample/SimHitExample/CMakeLists.txt
index 77084ea39ec8a8acdf4dae161c8abe0f6d175a94..19aa729b18603e2d40dd600d10b8d9ab3a645541 100644
--- a/Control/CalypsoExample/SimHitExample/CMakeLists.txt
+++ b/Control/CalypsoExample/SimHitExample/CMakeLists.txt
@@ -3,7 +3,7 @@ atlas_subdir( SimHitExample )
 atlas_add_component( SimHitExample
                     src/*.cxx
                     src/components/SimHitExample_entries.cxx
-                    LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent ScintSimEvent FaserCaloSimEvent
+                    LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent ScintSimEvent FaserCaloSimEvent NeutrinoSimEvent
         )
 
 atlas_install_joboptions( share/*.py )
\ No newline at end of file
diff --git a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx
index 86a1ecf5ac747a9a4bdc99a9cceeef8be0fdc2e1..100b0eeab94ffe94e8cb6f1119ca7ee39d5e5404 100644
--- a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx
+++ b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx
@@ -32,6 +32,8 @@ StatusCode SimHitAlg::initialize()
     ATH_CHECK( m_mcEventKey.initialize() );
     ATH_CHECK( m_faserSiHitKey.initialize() );
 
+    ATH_CHECK( m_emulsionHitKey.initialize() );
+
     ATH_CHECK( m_preshowerHitKey.initialize() );
     ATH_CHECK( m_triggerHitKey.initialize() );
     ATH_CHECK( m_vetoHitKey.initialize() );
@@ -41,9 +43,11 @@ StatusCode SimHitAlg::initialize()
     ATH_MSG_INFO( "Using GenEvent collection with key " << m_mcEventKey.key());
     ATH_MSG_INFO( "Using Faser SiHit collection with key " << m_faserSiHitKey.key());
 
-    ATH_MSG_INFO( "Using ScintHit collection with key " << m_preshowerHitKey.key());
-    ATH_MSG_INFO( "Using ScintHit collection with key " << m_triggerHitKey.key());
-    ATH_MSG_INFO( "Using ScintHit collection with key " << m_vetoHitKey.key());
+    ATH_MSG_INFO( "Using Emulsion NeutrinoHit collection with key " << m_emulsionHitKey.key() );
+
+    ATH_MSG_INFO( "Using Preshower ScintHit collection with key " << m_preshowerHitKey.key());
+    ATH_MSG_INFO( "Using Trigger ScintHit collection with key " << m_triggerHitKey.key());
+    ATH_MSG_INFO( "Using Veto ScintHit collection with key " << m_vetoHitKey.key());
 
     ATH_MSG_INFO( "Using CaloHit collection with key " << m_ecalHitKey.key());
     return StatusCode::SUCCESS;
@@ -61,6 +65,12 @@ StatusCode SimHitAlg::execute()
     SG::ReadHandle<FaserSiHitCollection> h_siHits(m_faserSiHitKey);
     ATH_MSG_INFO("Read FaserSiHitCollection with " << h_siHits->size() << " hits");
 
+    SG::ReadHandle<NeutrinoHitCollection> h_emulsionHits(m_emulsionHitKey);
+    if (h_emulsionHits.isValid())
+    {
+        ATH_MSG_INFO("Read NeutrinoHitCollection with " << h_emulsionHits->size() << " hits");
+    }
+
     SG::ReadHandle<ScintHitCollection> h_preshowerHits(m_preshowerHitKey);
     ATH_MSG_INFO("Read ScintHitCollection/Preshower with " << h_preshowerHits->size() << " hits");
     SG::ReadHandle<ScintHitCollection> h_triggerHits(m_triggerHitKey);
@@ -86,6 +96,15 @@ StatusCode SimHitAlg::execute()
         ePrimary = (*p)->momentum().e();
     }
 
+    if (h_emulsionHits.isValid() && h_emulsionHits->size()!=0)
+    {
+        //Loop over all hits; print
+        for (const NeutrinoHit& hit : *h_emulsionHits)
+        {
+            hit.print();
+        }
+    }
+
     // The hit container might be empty because particles missed the wafers
     //if (h_siHits->size() == 0) return StatusCode::SUCCESS;
 
diff --git a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h
index 3cf0fde82218a30756bfe344a3baf8dd862aceba..d7747bbfb9fc3c95920c99cbbe7ea0537bad0dca 100644
--- a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h
+++ b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h
@@ -1,6 +1,7 @@
 #include "AthenaBaseComps/AthHistogramAlgorithm.h"
 #include "GeneratorObjects/McEventCollection.h"
 #include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
 #include "ScintSimEvent/ScintHitCollection.h" 
 #include "FaserCaloSimEvent/CaloHitCollection.h"
 #include <TH1.h>
@@ -36,14 +37,20 @@ class SimHitAlg : public AthHistogramAlgorithm
     // Read handle keys for data containers
     // Any other event data can be accessed identically
     // Note the key names ("GEN_EVENT" or "SCT_Hits") are Gaudi properties and can be configured at run-time
+
+    // Truth information
     SG::ReadHandleKey<McEventCollection> m_mcEventKey       { this, "McEventCollection", "GEN_EVENT" };
+
+    // Tracker hits
     SG::ReadHandleKey<FaserSiHitCollection> m_faserSiHitKey { this, "FaserSiHitCollection", "SCT_Hits" };
 
+    // Emulsion hits
+    SG::ReadHandleKey<NeutrinoHitCollection> m_emulsionHitKey { this, "NeutrinoHitCollection", "EmulsionHits" };
+
     //PreshowerHits, TriggerHits, VetoHits Sav new stuff
-    SG::ReadHandleKey<ScintHitCollection> m_scintHitKey { this, "ScintHitCollection", "Scint_Hits" }; //template. remove later
-    SG::ReadHandleKey<ScintHitCollection> m_preshowerHitKey { this, "ScintHitCollection", "PreshowerHits" };
-    SG::ReadHandleKey<ScintHitCollection> m_triggerHitKey { this, "ScintHitCollection", "TriggerHits" };
-    SG::ReadHandleKey<ScintHitCollection> m_vetoHitKey { this, "ScintHitCollection", "VetoHits" };
+    SG::ReadHandleKey<ScintHitCollection> m_preshowerHitKey { this, "PreshowerHitCollection", "PreshowerHits" };
+    SG::ReadHandleKey<ScintHitCollection> m_triggerHitKey { this, "TriggerHitCollection", "TriggerHits" };
+    SG::ReadHandleKey<ScintHitCollection> m_vetoHitKey { this, "VetoHitCollection", "VetoHits" };
 
     //EcalHits
     SG::ReadHandleKey<CaloHitCollection> m_ecalHitKey { this, "CaloHitCollection", "EcalHits" };
diff --git a/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py b/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
index d420ec08310d6b653935826cd64b1d2d8ecc2463..e4dcd1c1abb13e44df6c8b538affed91ea107ca2 100644
--- a/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/TrackerDataAccessExample/python/TrackerDataAccessExampleConfig.py
@@ -31,7 +31,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # FASER geometry
     ConfigFlags.Input.ProjectName = "data20"                     # Needed to bypass autoconfig
diff --git a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
index 54ceea6ad1704a6f1b88bb124721a03d87100533..ffab4e9f96e55f559f92fc305de1a6c230ca224d 100644
--- a/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/TriggerDataAccessExample/python/TriggerDataAccessExampleConfig.py
@@ -31,7 +31,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Input.ProjectName = "data20"
diff --git a/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py b/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
index 096aacdd81ce9316862a5b1c5ff06ab16a476087..d46ef74914deec6275f1e477888328a536004b55 100644
--- a/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
+++ b/Control/CalypsoExample/WaveformDataAccessExample/python/WaveformDataAccessExampleConfig.py
@@ -31,7 +31,7 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.Input.ProjectName = "data20"
diff --git a/Control/CalypsoExample/WriteAlignment/CMakeLists.txt.disabled b/Control/CalypsoExample/WriteAlignment/CMakeLists.txt
similarity index 79%
rename from Control/CalypsoExample/WriteAlignment/CMakeLists.txt.disabled
rename to Control/CalypsoExample/WriteAlignment/CMakeLists.txt
index 751e8c0e7c95b3a213c73c673de53a0b88c8a2ce..0c167609117a1a14be6c24965148b782a0e0ffc9 100644
--- a/Control/CalypsoExample/WriteAlignment/CMakeLists.txt.disabled
+++ b/Control/CalypsoExample/WriteAlignment/CMakeLists.txt
@@ -15,10 +15,10 @@ atlas_add_component( WriteAlignment
                      INCLUDE_DIRS ${GEOMODELCORE_INCLUDE_DIRS}
                      LINK_LIBRARIES ${GEOMODELCORE_LIBRARIES} AthenaBaseComps GeoModelUtilities ScintReadoutGeometry TrackerReadoutGeometry TrackerAlignGenToolsLib )
 
-atlas_add_test( WriteAlignmentCheck
-                SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/python/WriteAlignmentConfig.py
-                PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-                PROPERTIES TIMEOUT 300 )
+# atlas_add_test( WriteAlignmentCheck
+#                 SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/python/WriteAlignmentConfig.py
+#                 PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+#                 PROPERTIES TIMEOUT 300 )
 
 # Install files from the package:
 #atlas_install_headers( WriteAlignment )
diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig.py
index 41fb9c9360add2307d3bb5bd001cff5506d9f029..de5a92acd49f221666e3d4ff053b1af43183526f 100644
--- a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig.py
+++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig.py
@@ -2,7 +2,7 @@
 
 #!/usr/bin/env python
 import sys
-from AthenaCommon.Constants import VERBOSE
+from AthenaCommon.Constants import VERBOSE, INFO
 from AthenaConfiguration.ComponentFactory import CompFactory
 
 def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs):
@@ -12,11 +12,11 @@ def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs):
     a = FaserGeometryCfg(flags)
 
     # This section is to allow alignment to be written to a conditions DB file
-    from IOVDbSvc.IOVDbSvcConfig import IOVDbSvcCfg
-    result = IOVDbSvcCfg(flags)
-    iovDbSvc = result.getPrimary()
-    iovDbSvc.dbConnection="sqlite://;schema=ALLP200.db;dbname=OFLP200"
-    a.merge(result)
+    # from IOVDbSvc.IOVDbSvcConfig import IOVDbSvcCfg
+    # result = IOVDbSvcCfg(flags)
+    # iovDbSvc = result.getPrimary()
+    # iovDbSvc.dbConnection="sqlite://;schema=ALLP200.db;dbname=OFLP200"
+    # a.merge(result)
 
     AthenaPoolCnvSvc=CompFactory.AthenaPoolCnvSvc
     apcs=AthenaPoolCnvSvc()
@@ -28,8 +28,11 @@ def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs):
 
     # Configure the algorithm itself
     WriteAlignmentAlg = CompFactory.WriteAlignmentAlg
-    outputTool = CompFactory.AthenaOutputStreamTool("DbStreamTool", OutputFile = "FaserSCT_AlignDb.pool.root")
-    kwargs.setdefault("AlignDbTool", CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool))
+    outputTool = CompFactory.AthenaOutputStreamTool("DbStreamTool", OutputFile = "FaserSCT_AlignDb.pool.root", 
+                                                                    PoolContainerPrefix="ConditionsContainer", 
+                                                                    TopLevelContainerName = "<type>",
+                                                                    SubLevelBranchName= "<key>" )
+    kwargs.setdefault("AlignDbTool", CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, OutputLevel=VERBOSE))
     a.addEventAlgo(WriteAlignmentAlg(name, **kwargs))
 
     return a
@@ -45,9 +48,10 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+    ConfigFlags.IOVDb.GlobalTag           = "OFLCOND-FASER-01"   # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.FaserVersion     = "FASER-01"           # Default FASER geometry
     ConfigFlags.GeoModel.GeoExportFile    = "faserGeo.db"        # Writes out a GeoModel file with the full geometry tree (optional, comment out to skip)
+    ConfigFlags.IOVDb.DBConnection        = "sqlite://;schema=ALLP200.db;dbname=OFLP200"
     ConfigFlags.lock()
 
 # Configure components
@@ -60,8 +64,8 @@ if __name__ == "__main__":
 # Configure verbosity    
     # ConfigFlags.dump()
     # logging.getLogger('forcomps').setLevel(VERBOSE)
-    # acc.foreach_component("*").OutputLevel = VERBOSE
-    # acc.foreach_component("*ClassID*").OutputLevel = INFO
+    acc.foreach_component("*").OutputLevel = VERBOSE
+    acc.foreach_component("*ClassID*").OutputLevel = INFO
     # log.setLevel(VERBOSE)
     
 # Execute and finish
diff --git a/Control/CalypsoExample/WriteAlignment/scripts/CopyAlignFolder.sh b/Control/CalypsoExample/WriteAlignment/scripts/CopyAlignFolder.sh
index 3e95b2313b2e18e1503960c41b5d5cd28ad1d00b..ce694ce4759a48ba872a9f1e57a6798b9601095c 100644
--- a/Control/CalypsoExample/WriteAlignment/scripts/CopyAlignFolder.sh
+++ b/Control/CalypsoExample/WriteAlignment/scripts/CopyAlignFolder.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
 
-AtlCoolCopy "sqlite://;schema=./ALLP200.db;dbname=OFLP200" "sqlite://;schema=data/ALLP200.db;dbname=OFLP200" -a -fnp -ot "OFLCOND-XXXX-XXX-XX"
+AtlCoolCopy "sqlite://;schema=./ALLP200.db;dbname=OFLP200" "sqlite://;schema=data/ALLP200.db;dbname=OFLP200" -a -fnp -ot "TRACKER-ALIGN-01"
 cp -n PoolFileCatalog.xml data/
 cp -n FaserSCT_AlignDb.pool.root data/
\ No newline at end of file
diff --git a/Control/CalypsoExample/WriteAlignment/src/WriteAlignmentAlg.cxx b/Control/CalypsoExample/WriteAlignment/src/WriteAlignmentAlg.cxx
index ed67d81aa6d269208efc836a43196b39ab8ce360..6efcb9b457f0e03096c1067059657b26fa8de4b5 100644
--- a/Control/CalypsoExample/WriteAlignment/src/WriteAlignmentAlg.cxx
+++ b/Control/CalypsoExample/WriteAlignment/src/WriteAlignmentAlg.cxx
@@ -33,42 +33,42 @@ StatusCode WriteAlignmentAlg::initialize()
 
 StatusCode WriteAlignmentAlg::execute(const EventContext&) const
 {   
-    GeoModelExperiment* theExpt = nullptr;
-    std::vector<std::string> listOfManagers;
-    ATH_CHECK(detStore()->retrieve(theExpt, "FASER"));
-    if (theExpt != nullptr)
-    {
-        ATH_MSG_ALWAYS("Retrieved top-level FASER experiment geometry from DetStore.");
-        listOfManagers = theExpt->getListOfManagers();
-        ATH_MSG_ALWAYS("Experiment has defined " << listOfManagers.size() << " detector managers:");
-        for (auto mgr : listOfManagers)
-        {
-            const GeoVDetectorManager* pMgr = nullptr;
-            pMgr = theExpt->getManager(mgr);
-            if (pMgr != nullptr)
-            {
-                ATH_MSG_ALWAYS("Retrieved (generic) manager " << mgr << " from top-level experiment.");
-            }
-            else
-            {
-                ATH_MSG_FATAL("Failed to retrieve manager " << mgr);
-                return StatusCode::FAILURE;
-            }
-        }
-    }
-    else
-    {
-        ATH_MSG_FATAL("Failed to retrieve top-level FASER experiment geometry from DetStore.");
-        return StatusCode::FAILURE;
-    }
+    // GeoModelExperiment* theExpt = nullptr;
+    // std::vector<std::string> listOfManagers;
+    // ATH_CHECK(detStore()->retrieve(theExpt, "FASER"));
+    // if (theExpt != nullptr)
+    // {
+    //     ATH_MSG_ALWAYS("Retrieved top-level FASER experiment geometry from DetStore.");
+    //     listOfManagers = theExpt->getListOfManagers();
+    //     ATH_MSG_ALWAYS("Experiment has defined " << listOfManagers.size() << " detector managers:");
+    //     for (auto mgr : listOfManagers)
+    //     {
+    //         const GeoVDetectorManager* pMgr = nullptr;
+    //         pMgr = theExpt->getManager(mgr);
+    //         if (pMgr != nullptr)
+    //         {
+    //             ATH_MSG_ALWAYS("Retrieved (generic) manager " << mgr << " from top-level experiment.");
+    //         }
+    //         else
+    //         {
+    //             ATH_MSG_FATAL("Failed to retrieve manager " << mgr);
+    //             return StatusCode::FAILURE;
+    //         }
+    //     }
+    // }
+    // else
+    // {
+    //     ATH_MSG_FATAL("Failed to retrieve top-level FASER experiment geometry from DetStore.");
+    //     return StatusCode::FAILURE;
+    // }
 
-    ATH_CHECK(testVeto());
+    // ATH_CHECK(testVeto());
 
-    ATH_CHECK(testTrigger());
+    // ATH_CHECK(testTrigger());
 
-    ATH_CHECK(testPreshower());
+    // ATH_CHECK(testPreshower());
 
-    ATH_CHECK(testSCT());
+    // ATH_CHECK(testSCT());
 
     ATH_CHECK(m_alignTool->createDB());
     ATH_CHECK(m_alignTool->sortTrans());
diff --git a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
index 4456994392b7c6d07ba43ea9ce3627ff2bfa190d..50884e7221086392e645855bd885e6f19ee821e0 100644
--- a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
+++ b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx
@@ -117,6 +117,8 @@ DetDescrCnvSvc::initialize()     {
     // IdHelpers
     status =  addToDetStore(125694213, "FaserID");
     if (status != StatusCode::SUCCESS) return status;
+    status =  addToDetStore(89852815,  "EmulsionID");
+    if (status != StatusCode::SUCCESS) return status;
     status =  addToDetStore(131395045, "VetoID");
     if (status != StatusCode::SUCCESS) return status;
     status =  addToDetStore(58382802, "TriggerID");
diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
index b17d61f7252e5fe254589babfa1744e62e3ae83c..3de4b6428fa65ae333a6bebe92aef8334f78a7b8 100644
--- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
+++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h
@@ -67,11 +67,18 @@ public:
     /// @name Detector system ids
     //@{
     /// Detector systems:
+    Identifier          neutrino        (void) const;
     Identifier          scint           (void) const;
     Identifier          tracker         (void) const;
     Identifier          calo            (void) const;
     //@}
 
+    /// @name Neutrino subsystem ids
+    //@{
+    Identifier          emulsion        (void) const;
+    //@}
+
+
     /// @name Scintillator subsystem ids
     //@{
     Identifier          veto            (void) const;
@@ -144,9 +151,11 @@ public:
 
     /// @name  Test of an Identifier to see if it belongs to a particular detector (sub)system:
     //@{
+    bool                is_neutrino     (Identifier id) const;
     bool                is_scint        (Identifier id) const;
     bool                is_tracker      (Identifier id) const;
     bool                is_calo         (Identifier id) const;
+    bool                is_emulsion     (Identifier id) const;
     bool                is_veto         (Identifier id) const;
     bool                is_trigger      (Identifier id) const;
     bool                is_preshower    (Identifier id) const;
@@ -157,9 +166,11 @@ public:
 
     /// @name  Test of an Identifier to see if it belongs to a particular detector (sub)system (using expanded ids):
     //@{
+    bool                is_neutrino     (const ExpandedIdentifier& id) const;
     bool                is_scint        (const ExpandedIdentifier& id) const;
     bool                is_tracker      (const ExpandedIdentifier& id) const;
     bool                is_calo         (const ExpandedIdentifier& id) const;
+    bool                is_emulsion     (const ExpandedIdentifier& id) const;
     bool                is_veto         (const ExpandedIdentifier& id) const;
     bool                is_trigger      (const ExpandedIdentifier& id) const;
     bool                is_preshower    (const ExpandedIdentifier& id) const;
@@ -209,10 +220,14 @@ protected:
     std::string         fix_barrel_ec   (const std::string& barrel_ec) const;
 
     /// Detector systems:
+    ExpandedIdentifier          neutrino_exp        (void) const;
     ExpandedIdentifier          scint_exp           (void) const;
     ExpandedIdentifier          tracker_exp         (void) const;
     ExpandedIdentifier          calo_exp            (void) const;
 
+    /// Neutrino:
+    ExpandedIdentifier          emulsion_exp        (void) const;
+
     /// Scintillator:
     ExpandedIdentifier          veto_exp            (void) const;
     ExpandedIdentifier          trigger_exp         (void) const;
@@ -226,9 +241,11 @@ protected:
 
     /// Provide efficient access to individual field values, for
     /// subclass idhelpers
+    int                 neutrino_field_value     () const;
     int                 scint_field_value        () const;     
     int                 tracker_field_value      () const;       
     int                 calo_field_value         () const;
+    int                 emulsion_field_value     () const;
     int                 veto_field_value         () const;     
     int                 trigger_field_value      () const;       
     int                 preshower_field_value    () const;       
@@ -283,9 +300,11 @@ private:
     bool                m_is_initialized_from_dict;
     size_type           m_DET_INDEX;
     size_type           m_SUBDET_INDEX;
+    int                 m_NEUTRINO_ID;     
     int                 m_SCINT_ID;     
     int                 m_TRACKER_ID;       
     int                 m_CALO_ID;
+    int                 m_EMULSION_ID;
     int                 m_VETO_ID;     
     int                 m_TRIGGER_ID;       
     int                 m_PRESHOWER_ID;       
@@ -296,11 +315,13 @@ private:
     bool                m_isSLHC;
 
     IdDictDictionary*   m_faser_dict;
+    IdDictDictionary*   m_neutrino_dict;
     IdDictDictionary*   m_scint_dict;
     IdDictDictionary*   m_tracker_dict;
     IdDictDictionary*   m_calo_dict;
     FaserDetectorIDHelper* m_helper;
     IdDictFieldImplementation m_det_impl;
+    IdDictFieldImplementation m_neutrino_part_impl;
     IdDictFieldImplementation m_scint_part_impl;
     IdDictFieldImplementation m_tracker_part_impl;
     IdDictFieldImplementation m_calo_part_impl;
@@ -318,6 +339,14 @@ CLASS_DEF(FaserDetectorID, 125694213 , 1)
 //<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
 /////////////////////////////////////////////////////////////////////////////
 
+inline ExpandedIdentifier          
+FaserDetectorID::neutrino_exp           (void) const
+{
+    ExpandedIdentifier result;
+    return (result << m_NEUTRINO_ID);
+}
+
+
 inline ExpandedIdentifier          
 FaserDetectorID::scint_exp           (void) const
 {
@@ -339,6 +368,13 @@ FaserDetectorID::calo_exp(void) const
     return (result << m_CALO_ID);
 }
 
+inline ExpandedIdentifier          
+FaserDetectorID::emulsion_exp           (void) const
+{
+    ExpandedIdentifier result(neutrino_exp());
+    return (result << m_EMULSION_ID);
+}
+
 inline ExpandedIdentifier          
 FaserDetectorID::veto_exp           (void) const
 {
@@ -374,6 +410,9 @@ FaserDetectorID::ecal_exp                (void) const
     return (result << m_ECAL_ID);  
 }
 
+inline int                 
+FaserDetectorID::neutrino_field_value     () const {return (m_NEUTRINO_ID);}     
+
 inline int                 
 FaserDetectorID::scint_field_value        () const {return (m_SCINT_ID);}     
 
@@ -383,6 +422,9 @@ FaserDetectorID::tracker_field_value      () const {return (m_TRACKER_ID);}
 inline int                 
 FaserDetectorID::calo_field_value         () const {return (m_CALO_ID);}
 
+inline int                 
+FaserDetectorID::emulsion_field_value     () const {return (m_EMULSION_ID);}     
+
 inline int                 
 FaserDetectorID::veto_field_value         () const {return (m_VETO_ID);}     
 
@@ -398,6 +440,12 @@ FaserDetectorID::sct_field_value          () const {return (m_SCT_ID);}
 inline int                 
 FaserDetectorID::ecal_field_value         () const {return (m_ECAL_ID);}       
 
+inline bool               
+FaserDetectorID::is_neutrino             (Identifier id) const
+{
+    return (m_det_impl.unpack(id) == m_NEUTRINO_ID);
+}
+
 inline bool               
 FaserDetectorID::is_scint                (Identifier id) const
 {
@@ -416,6 +464,16 @@ FaserDetectorID::is_calo                 (Identifier id) const
     return (m_det_impl.unpack(id) == m_CALO_ID);
 }
 
+inline bool               
+FaserDetectorID::is_emulsion     (Identifier id) const
+{
+    bool result = false;
+    if(is_neutrino(id)) {
+        result = (m_neutrino_part_impl.unpack(id) == m_EMULSION_ID);
+    }
+    return result;
+}
+
 inline bool               
 FaserDetectorID::is_veto       (Identifier id) const
 {
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
index 21f010378e163d6c6055dac5d9cd47140d0f3c0b..9e8dfbb0dcf18ea616c4e35725b28cbb27e8151a 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx
@@ -36,9 +36,11 @@ FaserDetectorID::FaserDetectorID()
         m_is_initialized_from_dict(false),
         m_DET_INDEX(999),
         m_SUBDET_INDEX(999),
+        m_NEUTRINO_ID(1),
         m_SCINT_ID(2),
         m_TRACKER_ID(3),
         m_CALO_ID(4),
+        m_EMULSION_ID(1),
         m_VETO_ID(1),
         m_TRIGGER_ID(2),
         m_PRESHOWER_ID(3),
@@ -46,6 +48,7 @@ FaserDetectorID::FaserDetectorID()
         m_ECAL_ID(1),
         m_isSLHC(false),
         m_faser_dict(0),
+        m_neutrino_dict(0),
         m_scint_dict(0),
         m_tracker_dict(0),
         m_calo_dict(0),
@@ -68,9 +71,11 @@ FaserDetectorID::FaserDetectorID(const FaserDetectorID& other)
         m_is_initialized_from_dict(other.m_is_initialized_from_dict),
         m_DET_INDEX               (other.m_DET_INDEX),
         m_SUBDET_INDEX            (other.m_SUBDET_INDEX),
+        m_NEUTRINO_ID             (other.m_NEUTRINO_ID),
         m_SCINT_ID                (other.m_SCINT_ID),
         m_TRACKER_ID              (other.m_TRACKER_ID),
         m_CALO_ID                 (other.m_CALO_ID),
+        m_EMULSION_ID             (other.m_EMULSION_ID),
         m_VETO_ID                 (other.m_VETO_ID),
         m_TRIGGER_ID              (other.m_TRIGGER_ID),
         m_PRESHOWER_ID            (other.m_PRESHOWER_ID),
@@ -78,11 +83,13 @@ FaserDetectorID::FaserDetectorID(const FaserDetectorID& other)
         m_ECAL_ID                 (other.m_ECAL_ID),
         m_isSLHC                  (other.m_isSLHC),
         m_faser_dict              (other.m_faser_dict),
+        m_neutrino_dict           (other.m_neutrino_dict),
         m_scint_dict              (other.m_scint_dict),
         m_tracker_dict            (other.m_tracker_dict),
         m_calo_dict               (other.m_calo_dict),
         m_helper                  (0),
         m_det_impl                (other.m_det_impl),
+        m_neutrino_part_impl      (other.m_neutrino_part_impl),
         m_scint_part_impl         (other.m_scint_part_impl),
         m_tracker_part_impl       (other.m_tracker_part_impl),
         m_calo_part_impl          (other.m_calo_part_impl)
@@ -107,19 +114,23 @@ FaserDetectorID::operator= (const FaserDetectorID& other)
         m_is_initialized_from_dict = other.m_is_initialized_from_dict;
         m_DET_INDEX             = other.m_DET_INDEX;
         m_SUBDET_INDEX          = other.m_SUBDET_INDEX;
+        m_NEUTRINO_ID           = other.m_NEUTRINO_ID;
         m_SCINT_ID              = other.m_SCINT_ID;
         m_TRACKER_ID            = other.m_TRACKER_ID;
         m_CALO_ID               = other.m_CALO_ID;
+        m_EMULSION_ID           = other.m_EMULSION_ID;
         m_VETO_ID               = other.m_VETO_ID;
         m_TRIGGER_ID            = other.m_TRIGGER_ID;
         m_PRESHOWER_ID          = other.m_PRESHOWER_ID;
         m_SCT_ID                = other.m_SCT_ID;
         m_ECAL_ID               = other.m_ECAL_ID;
         m_faser_dict            = other.m_faser_dict;
+        m_neutrino_dict         = other.m_neutrino_dict;
         m_scint_dict            = other.m_scint_dict;
         m_tracker_dict          = other.m_tracker_dict;
         m_calo_dict             = other.m_calo_dict;
         m_det_impl              = other.m_det_impl;
+        m_neutrino_part_impl    = other.m_neutrino_part_impl;
         m_scint_part_impl       = other.m_scint_part_impl;
         m_tracker_part_impl     = other.m_tracker_part_impl;
         m_calo_part_impl        = other.m_calo_part_impl;
@@ -135,6 +146,15 @@ FaserDetectorID::operator= (const FaserDetectorID& other)
     return (*this);
 }
 
+Identifier
+FaserDetectorID::neutrino     (void) const
+{
+
+    Identifier result((Identifier::value_type)0);
+    // Pack field
+    m_det_impl.pack    (neutrino_field_value(), result);
+    return (result);
+}
 
 Identifier
 FaserDetectorID::scint        (void) const
@@ -164,6 +184,15 @@ FaserDetectorID::calo(void) const
     return (result);
 }
 
+Identifier
+FaserDetectorID::emulsion        (void) const
+{
+    Identifier result((Identifier::value_type)0);
+    // Pack field
+    m_det_impl.pack       (neutrino_field_value(), result);
+    m_neutrino_part_impl.pack(m_EMULSION_ID, result);
+    return (result);
+}
 
 Identifier
 FaserDetectorID::veto        (void) const
@@ -355,6 +384,16 @@ FaserDetectorID::dictionaryVersion  (void) const
     return (m_dict_version);
 }
 
+bool
+FaserDetectorID::is_neutrino    (const ExpandedIdentifier& id) const
+{
+    bool result = false;
+    if ( id.fields() > 0 ){
+        if ( id[0] == m_NEUTRINO_ID) result = true;
+    }
+    return result;
+}
+
 bool
 FaserDetectorID::is_scint       (const ExpandedIdentifier& id) const
 {
@@ -385,6 +424,16 @@ FaserDetectorID::is_calo                (const ExpandedIdentifier& id) const
     return result;
 }
 
+bool
+FaserDetectorID::is_emulsion     (const ExpandedIdentifier& id) const
+{
+    bool result = false;
+    if ( is_neutrino(id) && id.fields() > 1 ){
+        if ( id[1] == m_EMULSION_ID ) result = true;
+    }
+    return result;
+}
+
 bool
 FaserDetectorID::is_veto       (const ExpandedIdentifier& id) const
 {
@@ -469,7 +518,11 @@ FaserDetectorID::show_to_string (Identifier id,
     ExpandedIdentifier prefix;  // default is null prefix
     Identifier compact = id;
 
-    if (is_scint(id)) {
+    if (is_neutrino(id))
+    {
+        dict = m_neutrino_dict;
+    }
+    else if (is_scint(id)) {
         dict = m_scint_dict;
     }
     else if (is_tracker(id)) {
@@ -541,7 +594,11 @@ FaserDetectorID::print_to_string        (Identifier id,
         ExpandedIdentifier prefix;  // default is null prefix
         Identifier compact = id;
 
-        if (is_scint(id)) {
+        if (is_neutrino(id))
+        {
+            dict = m_neutrino_dict;
+        }
+        else if (is_scint(id)) {
             dict = m_scint_dict;
         }
         else if (is_tracker(id)) {
@@ -664,9 +721,11 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
     // levels and id values
     m_DET_INDEX             = 999;
     m_SUBDET_INDEX          = 999;
+    m_NEUTRINO_ID           = -1;
     m_SCINT_ID              = -1;
     m_TRACKER_ID            = -1;
     m_CALO_ID               = -1;
+    m_EMULSION_ID           = -1;
     m_VETO_ID               = -1;
     m_TRIGGER_ID            = -1;
     m_PRESHOWER_ID          = -1;
@@ -678,7 +737,76 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
 
     // Get det ids
 
-    // Initialize ids for InDet subdet
+    // Initialize ids for Neutrino subdet
+
+    m_neutrino_dict = dict_mgr.find_dictionary ("Neutrino");
+    if(!m_neutrino_dict) {
+        if(m_msgSvc) {
+            MsgStream log(m_msgSvc, "FaserDetectorID" );
+            log << MSG::WARNING << "initLevelsFromDict - cannot access Neutrino dictionary" << endmsg;
+        }
+        else {
+            std::cout << " FaserDetectorID::initLevelsFromDict - Warning cannot access Neutrino dictionary "
+                      << std::endl;
+        }
+    }
+    else {
+
+        // Found Neutrino dict
+
+        top_dict = m_neutrino_dict;  // save as top_dict
+
+        // Check if this is SLHC layout
+        // m_isSLHC = (m_scint_dict->m_version=="SLHC");
+
+        // Get Neutrino subdets
+
+        field = m_neutrino_dict->find_field("part");
+        if (!field) {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorID" );
+                log << MSG::ERROR << "initLevelsFromDict - unable to find 'part' field for Neutrino dictionary" << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'part' field for Neutrino dictionary"
+                          << std::endl;
+            }
+            return (1);
+        }
+
+        label = field->find_label("Emulsion");
+        if (label) {
+            if (label->m_valued) {
+                m_EMULSION_ID = label->m_value;
+            }
+            else {
+                if(m_msgSvc) {
+                    MsgStream log(m_msgSvc, "FaserDetectorID" );
+                    log << MSG::ERROR << "initLevelsFromDict - label Emulsion does NOT have a value "
+                        << endmsg;
+                }
+                else {
+                    std::cout << "FaserDetectorID::initLevelsFromDict - label Emulsion does NOT have a value "
+                              << std::endl;
+                }
+                return (1);
+            }
+        }
+        else {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorID" );
+                log << MSG::ERROR << "initLevelsFromDict - unable to find 'Emulsion' label "
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'Emulsion' label "
+                          << std::endl;
+            }
+            return (1);
+        }
+    }
+
+    // Initialize ids for Scint subdet
     m_scint_dict = dict_mgr.find_dictionary ("Scintillator");
     if(!m_scint_dict) {
         if(m_msgSvc) {
@@ -956,6 +1084,38 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
             return (1);
         }
 
+        // Get neutrino id
+        label = field->find_label("Neutrino");
+        if (label) {
+            if (label->m_valued) {
+                m_NEUTRINO_ID = label->m_value;
+            }
+            else {
+                if(m_msgSvc) {
+                    MsgStream log(m_msgSvc, "FaserDetectorID" );
+                    log << MSG::ERROR << "initLevelsFromDict - label Neutrino does NOT have a value "
+                        << endmsg;
+                }
+                else {
+                    std::cout << "FaserDetectorID::initLevelsFromDict - label Neutrino does NOT have a value "
+                              << std::endl;
+                }
+                return (1);
+            }
+        }
+        else {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorID" );
+                log << MSG::ERROR << "initLevelsFromDict - unable to find 'Neutrino' label "
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'Neutrino' label "
+                          << std::endl;
+            }
+            return (1);
+        }
+
         // Get scint id
         label = field->find_label("Scintillator");
         if (label) {
@@ -1054,7 +1214,11 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
 
         // Get name of next level
         std::string name;
-        if (top_dict->m_name == "Scintillator") {
+        if (top_dict->m_name == "Neutrino")
+        {
+            name = "part";
+        }
+        else if (top_dict->m_name == "Scintillator") {
             name = "part";
         }
         else if (top_dict->m_name == "Calorimeter") {
@@ -1104,7 +1268,17 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr)
     // Set the field implementations
 
     const IdDictRegion* region = 0;
-    size_type region_index =  m_helper->veto_region_index();
+
+    size_type region_index =  m_helper->emulsion_region_index();
+    if (m_neutrino_dict && FaserDetectorIDHelper::UNDEFINED != region_index) {
+        region                 =  m_neutrino_dict->m_regions[region_index];
+        // Detector
+        m_det_impl             = region->m_implementation[m_DET_INDEX];
+        // InDet part
+        m_neutrino_part_impl      = region->m_implementation[m_SUBDET_INDEX];
+    }
+    
+    region_index =  m_helper->veto_region_index();
     if (m_scint_dict && FaserDetectorIDHelper::UNDEFINED != region_index) {
         region                 =  m_scint_dict->m_regions[region_index];
         // Detector
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
index 0a877bb96448dbf00a8313a1e93b1d49a5be882a..f192dcaff52bf68da5d9de6e815810b643963715 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.cxx
@@ -28,6 +28,7 @@
 FaserDetectorIDHelper::FaserDetectorIDHelper(void)
 	:
 	m_isSLHC(false),
+	m_emulsion_region_index(UNDEFINED),
 	m_veto_region_index(UNDEFINED),
 	m_trigger_region_index(UNDEFINED),
 	m_preshower_region_index(UNDEFINED),
@@ -51,7 +52,40 @@ FaserDetectorIDHelper::initialize_from_dictionary(const IdDictMgr& dict_mgr)
     FaserDetectorID faser_id;
     ExpandedIdentifier id;
 
-    const IdDictDictionary* 	dict = dict_mgr.find_dictionary ("Scintillator"); 
+    const IdDictDictionary* 	dict = dict_mgr.find_dictionary ("Neutrino"); 
+    if(!dict) {
+        if(m_msgSvc) {
+            MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+            log << MSG::WARNING << "initialize_from_dictionary - cannot access Neutrino dictionary "
+                << endmsg;
+        }
+        else {
+            std::cout << " FaserDetectorIDHelper::initialize_from_dictionary - Warning: cannot access Neutrino dictionary "
+                      << std::endl;
+        }
+    }
+    else {
+	// Check if this is SLHC layout
+	// m_isSLHC = (dict->m_version=="SLHC");
+
+	// Save index to a VETO region for unpacking
+	id = faser_id.emulsion_exp(); 
+	if (dict->find_region(id, m_emulsion_region_index)) {
+            if(m_msgSvc) {
+                MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
+                log << MSG::WARNING << "initialize_from_dictionary - unable to find emulsion region index: id, reg "  
+                    << (std::string)id << " " << m_emulsion_region_index
+                    << endmsg;
+            }
+            else {
+                std::cout << "FaserDetectorIDHelper::initialize_from_dictionary - Warning: unable to find emulsion region index: id, reg "  
+                          << (std::string)id << " " << m_emulsion_region_index
+                          << std::endl;
+            }
+	}
+    }
+
+    dict = dict_mgr.find_dictionary ("Scintillator"); 
     if(!dict) {
         if(m_msgSvc) {
             MsgStream log(m_msgSvc, "FaserDetectorIDHelper" );
diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
index 9836bb951238b57fab10e7a28be3b309c50d0fa4..ead07e481e66177d74b0ac9bf5f2ca71fc8de857 100644
--- a/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
+++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorIDHelper.h
@@ -45,6 +45,7 @@ public:
 
     ~FaserDetectorIDHelper(void);
     
+    size_type   emulsion_region_index();
     size_type   veto_region_index();
     size_type   trigger_region_index();
     size_type   preshower_region_index();
@@ -59,6 +60,7 @@ private:
 
     /// Flag for slhc layout:
     bool                m_isSLHC;
+    size_type   m_emulsion_region_index;
     size_type		m_veto_region_index;
     size_type		m_trigger_region_index;
     size_type		m_preshower_region_index;
@@ -74,6 +76,8 @@ private:
 
 //<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
 //<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::emulsion_region_index()
+{return (m_emulsion_region_index);}       
 
 inline FaserDetectorIDHelper::size_type   FaserDetectorIDHelper::veto_region_index()
 {return (m_veto_region_index);}       
diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/CMakeLists.txt b/DetectorDescription/GeoModel/FaserGeoAdaptors/CMakeLists.txt
index 5a09b1fef5249ed46824f8095776b45aca1eac42..649f30426498840566d5acc4650ae23bbf8628ff 100644
--- a/DetectorDescription/GeoModel/FaserGeoAdaptors/CMakeLists.txt
+++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/CMakeLists.txt
@@ -14,5 +14,8 @@ atlas_add_library( FaserGeoAdaptors
                    PUBLIC_HEADERS FaserGeoAdaptors
                    INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS}
                    DEFINITIONS ${CLHEP_DEFINITIONS}
-                   LINK_LIBRARIES ${CLHEP_LIBRARIES} Identifier FaserCaloIdentifier CaloReadoutGeometry FaserCaloSimEvent ScintIdentifier ScintReadoutGeometry ScintSimEvent TrackerIdentifier TrackerReadoutGeometry TrackerSimEvent StoreGateLib SGtests )
+                   LINK_LIBRARIES ${CLHEP_LIBRARIES} Identifier NeutrinoIdentifier NeutrinoReadoutGeometry NeutrinoSimEvent 
+                                                                FaserCaloIdentifier CaloReadoutGeometry FaserCaloSimEvent 
+                                                                ScintIdentifier ScintReadoutGeometry ScintSimEvent 
+                                                                TrackerIdentifier TrackerReadoutGeometry TrackerSimEvent StoreGateLib SGtests )
 
diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.h b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8ab78a4b244bbd2fd66ec091f6399367c418abf
--- /dev/null
+++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.h
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef GEOADAPTORS_GEONEUTRINOHIT_h
+#define GEOADAPTORS_GEONEUTRINOHIT_h
+//----------------------------------------------------------//
+//                                                          //
+// An adaptor for NeutrinoHits.                                //
+//                                                          //
+// Joe Boudreau Feb 04.                                     //
+//                                                          //
+// This adaptor class allows NeutrinoHits to behave            //
+// as if they knew which detector they were in.             //
+//                                                          //
+//                                                          //
+//----------------------------------------------------------//
+#include "CLHEP/Geometry/Point3D.h"
+class NeutrinoHit;
+class EmulsionID;
+namespace NeutrinoDD {
+  class EmulsionDetectorManager;
+}
+
+class GeoNeutrinoHit {
+
+ public:
+
+  // Constructor:
+  GeoNeutrinoHit(const NeutrinoHit & h);
+
+  // Get the absolute global position:
+  HepGeom::Point3D<double> getGlobalPosition() const;
+
+  // Underlying hit.
+  const NeutrinoHit &data() const { return *m_hit;}
+
+  // Is this hit ok?
+
+  operator bool () const { return s_emulsion; }
+
+ private:
+  
+  static void init();
+
+  const NeutrinoHit                                 *m_hit;
+  static const NeutrinoDD::EmulsionDetectorManager  *s_emulsion;
+  static const EmulsionID                           *s_nID;
+};
+
+#include "FaserGeoAdaptors/GeoNeutrinoHit.icc"
+
+#endif
diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.icc b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.icc
new file mode 100644
index 0000000000000000000000000000000000000000..83df3315ea52a7c34a7aadff1f44f0dc72e1e0fc
--- /dev/null
+++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoNeutrinoHit.icc
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "GeoPrimitives/CLHEPtoEigenConverter.h"
+
+inline void GeoNeutrinoHit::init() {
+
+  ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "GeoNeutrinoHit");
+  if (detStore.retrieve().isSuccess()) {
+    if(detStore->retrieve(s_emulsion,"Emulsion").isFailure())
+      s_emulsion = 0;
+    if(detStore->retrieve(s_nID,"EmulsionID").isFailure())
+      s_nID = 0;
+  }
+}
+
+inline GeoNeutrinoHit::GeoNeutrinoHit (const NeutrinoHit & h) {
+  m_hit = &h;
+  if (!s_emulsion) init();
+}
+
+inline HepGeom::Point3D<double> GeoNeutrinoHit::getGlobalPosition() const {
+
+  Identifier id;
+  const NeutrinoDD::NeutrinoDetectorElement *geoelement=NULL;
+  id = s_nID->film_id(m_hit->getModule(), m_hit->getBase(), m_hit->getFilm());
+  geoelement = s_emulsion->getDetectorElement(id);      
+  
+  if (geoelement) {
+
+    const HepGeom::Point3D<double> globalStartPos = Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_hit->localStartPosition());
+    const HepGeom::Point3D<double> globalEndPos   = Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_hit->localEndPosition());
+    
+    double x=(globalStartPos.x() + globalEndPos.x())/2;
+    double y=(globalStartPos.y() + globalEndPos.y())/2;
+    double z=(globalStartPos.z() + globalEndPos.z())/2;
+
+    return HepGeom::Point3D<double>(x,y,z);
+  }
+
+  return HepGeom::Point3D<double>(0.0,0.0,0.0);
+}
diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx b/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx
index 7c72a5103ec9b078504b041df625e5fc5b2257c4..ca6dd213cbe3a3782bbe5a45500b9a09e48eee09 100644
--- a/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx
+++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx
@@ -5,12 +5,15 @@
 #include "FaserGeoAdaptors/GeoScintHit.h"
 #include "FaserGeoAdaptors/GeoFaserSiHit.h"
 #include "FaserGeoAdaptors/GeoFaserCaloHit.h"
+#include "FaserGeoAdaptors/GeoNeutrinoHit.h"
 
+const NeutrinoDD::EmulsionDetectorManager *GeoNeutrinoHit::s_emulsion = 0;
 const ScintDD::VetoDetectorManager      *GeoScintHit::s_veto = 0;
 const ScintDD::TriggerDetectorManager   *GeoScintHit::s_trigger = 0;
 const ScintDD::PreshowerDetectorManager *GeoScintHit::s_preshower = 0;
 const TrackerDD::SCT_DetectorManager    *GeoFaserSiHit::s_sct;
 const CaloDD::EcalDetectorManager       *GeoFaserCaloHit::s_ecal = 0;
+const EmulsionID                        *GeoNeutrinoHit::s_nID = 0;
 const VetoID                            *GeoScintHit::s_vID = 0;
 const TriggerID                         *GeoScintHit::s_tID = 0;
 const PreshowerID                       *GeoScintHit::s_pID = 0;
diff --git a/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql b/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql
index a18d47bce2d9f0a9f68970b1cfa868fc602ccf20..edd02d7b67c730dfc55387e0123d9b53d858fa96 100644
--- a/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql
+++ b/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql
@@ -129,6 +129,58 @@ CREATE TABLE IF NOT EXISTS "EMULSIONTOPLEVEL_DATA2TAG" (
 	"EMULSIONTOPLEVEL_DATA_ID" SLONGLONG
 );
 --
+DROP TABLE IF EXISTS "EMULSIONGENERAL_DATA";
+CREATE TABLE IF NOT EXISTS "EMULSIONGENERAL_DATA" (
+	"EMULSIONGENERAL_DATA_ID" SLONGLONG UNIQUE,
+	"NMODULES" INT,
+	"NBASEPERMOD" INT,
+	"FIRSTBASEZ" DOUBLE,
+	"LASTBASEZ" DOUBLE
+);
+--
+DROP TABLE IF EXISTS "EMULSIONGENERAL_DATA2TAG";
+CREATE TABLE IF NOT EXISTS "EMULSIONGENERAL_DATA2TAG" (
+	"EMULSIONGENERAL_TAG_ID" SLONGLONG,
+	"EMULSIONGENERAL_DATA_ID" SLONGLONG
+);
+--
+DROP TABLE IF EXISTS "EMULSIONFILM_DATA";
+CREATE TABLE IF NOT EXISTS "EMULSIONFILM_DATA" (
+	"EMULSIONFILM_DATA_ID" SLONGLONG UNIQUE,
+	"BASEDX" DOUBLE,
+	"BASEDY" DOUBLE,
+	"BASEDZ" DOUBLE,
+	"BASEMAT" TEXT,
+	"FILMDX" DOUBLE,
+	"FILMDY" DOUBLE,
+	"FILMDZ" DOUBLE,
+	"FILMMAT" TEXT
+);
+--
+DROP TABLE IF EXISTS "EMULSIONFILM_DATA2TAG";
+CREATE TABLE IF NOT EXISTS "EMULSIONFILM_DATA2TAG" (
+	"EMULSIONFILM_TAG_ID" SLONGLONG,
+	"EMULSIONFILM_DATA_ID" SLONGLONG
+);
+--
+DROP TABLE IF EXISTS "EMULSIONPLATES_DATA";
+CREATE TABLE IF NOT EXISTS "EMULSIONPLATES_DATA" (
+	"EMULSIONPLATES_DATA_ID" SLONGLONG UNIQUE,
+	"DX" DOUBLE,
+	"DY" DOUBLE,
+	"DZ" DOUBLE,
+	"POSX" DOUBLE,
+	"POSY" DOUBLE,
+	"POSZ" DOUBLE,
+	"MATERIAL" TEXT
+);
+--
+DROP TABLE IF EXISTS "EMULSIONPLATES_DATA2TAG";
+CREATE TABLE IF NOT EXISTS "EMULSIONPLATES_DATA2TAG" (
+	"EMULSIONPLATES_TAG_ID" SLONGLONG,
+	"EMULSIONPLATES_DATA_ID" SLONGLONG
+);
+--
 -- Tables for describing Veto scintillator plates (and passive radiators)
 --
 DROP TABLE IF EXISTS "VETOTOPLEVEL_DATA";
@@ -166,6 +218,7 @@ CREATE TABLE IF NOT EXISTS "VETOSTATIONGENERAL_DATA2TAG" (
 	"VETOSTATIONGENERAL_TAG_ID" SLONGLONG,
 	"VETOSTATIONGENERAL_DATA_ID" SLONGLONG
 );
+--
 DROP TABLE IF EXISTS "VETOPLATEGENERAL_DATA";
 CREATE TABLE IF NOT EXISTS "VETOPLATEGENERAL_DATA" (
 	"VETOPLATEGENERAL_DATA_ID" SLONGLONG UNIQUE,
@@ -596,6 +649,9 @@ INSERT INTO "HVS_NODE" VALUES (1004, "NeutrinoMatComponents", 1, 0, NULL);
 INSERT INTO "HVS_NODE" VALUES (1005, "NeutrinoIdentifier", 1, 0, NULL);
 INSERT INTO "HVS_NODE" VALUES (11,   "Emulsion", 1, 1, NULL);
 INSERT INTO "HVS_NODE" VALUES (110,  "EmulsionTopLevel", 11, 0, NULL);
+INSERT INTO "HVS_NODE" VALUES (111,  "EmulsionGeneral", 11, 0, NULL);
+INSERT INTO "HVS_NODE" VALUES (112,  "EmulsionFilm", 11, 0, NULL);
+INSERT INTO "HVS_NODE" VALUES (113,  "EmulsionPlates", 11, 0, NULL);
 INSERT INTO "HVS_NODE" VALUES (114,  "EmulsionSwitches", 11, 0, NULL);
 INSERT INTO "HVS_NODE" VALUES (2,    "Scintillator", 0, 1, NULL);
 INSERT INTO "HVS_NODE" VALUES (2003, "ScintMaterials", 2, 0, NULL);
@@ -650,6 +706,8 @@ INSERT INTO "HVS_NODE" VALUES (4005, "CaloIdentifier", 4, 0, NULL);
 INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-00", 100000, NULL, 0, 0, 1549238400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-01", 100039, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-CR", 107784, NULL, 0, 0, 1598400000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-02", 107788, NULL, 0, 0, 1619222400000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASERNU-02", 107804, NULL, 0, 0, 1619308800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (90,   "FaserCommon-00", 100013, NULL, 0, 0, 1549324800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (9000, "Materials-00", 100005, NULL, 0, 0, 1549238400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (9001, "StdMaterials-00", 100006, NULL, 0, 0, 1549238400000000000, NULL, 22);
@@ -658,20 +716,28 @@ INSERT INTO "HVS_TAG2NODE" VALUES (9003, "Elements-00", 100008, NULL, 0, 0, 1549
 INSERT INTO "HVS_TAG2NODE" VALUES (1, "Neutrino-00", 100031, NULL, 0, 0, 1582416000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (11,"Emulsion-00", 100034, NULL, 0, 0, 1582416000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (110, "EmulsionTopLevel-00", 100035, NULL, 0, 0, 1582416000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (111, "EmulsionGeneral-00", 107805, NULL, 0, 0, 1619308800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (112, "EmulsionFilm-00", 107806, NULL, 0, 0, 1619308800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (113, "EmulsionPlates-00", 107807, NULL, 0, 0, 1619308800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (114, "EmulsionSwitches-00", 100036, NULL, 0, 0, 1582416000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-00", 100001, NULL, 0, 0, 1549238400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-01", 100042, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-02", 107789, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-00", 100002, NULL, 0, 0, 1549238400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-01", 100038, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-CR", 107783, NULL, 0, 0, 1598400000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-02", 107790, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-00", 100026, NULL, 0, 0, 1567987200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-01", 100037, NULL, 0, 0, 1159079680000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-CR", 107781, NULL, 0, 0, 1598400000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-02", 107791, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-00", 100027, NULL, 0, 0, 1568678400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-01", 100041, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-02", 107792, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-00", 106788, NULL, 0, 0, 1567987200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-01", 106790, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-CR", 107786, NULL, 0, 0, 1598400000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-02", 107793, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (311, "SctBarrelModule-00", 107003, NULL, 0, 0, 1567987200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (312, "SctBarrelSensor-00", 106730, NULL, 0, 0, 1567987200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (313, "SctFaserGeneral-00", 106789, NULL, 0, 0, 1567987200000000000, NULL, 22);
@@ -686,26 +752,33 @@ INSERT INTO "HVS_TAG2NODE" VALUES (3181,"SctFrameGeneral-00", 100054, NULL, 0, 0
 INSERT INTO "HVS_TAG2NODE" VALUES (3182,"SctFrameShape-00", 100055, NULL, 0, 0,   1591574400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-00", 100029, NULL, 0, 0, 1568678400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-01", 100040, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-02", 107794, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (321, "DipoleGeneral-00", 100004, NULL, 0, 0, 1568678400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (324, "DipoleSwitches-00", 100028, NULL, 0, 0, 1568678400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (4, "Calorimeter-00", 100003, NULL, 0, 0, 1549238400000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (4, "Calorimeter-02", 107795, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (41, "Ecal-00", 100056, NULL, 0, 0,    1593907200000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (41, "Ecal-02", 107796, NULL, 0, 0,    1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (410, "EcalTopLevel-00", 100058, NULL, 0, 0, 1599350400000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (410, "EcalTopLevel-02", 107797, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (411, "EcalRowGeneral-00", 100059, NULL, 0, 0, 1599350400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (414, "EcalSwitches-00", 100057, NULL, 0, 0, 1593907200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (210,  "VetoTopLevel-00", 100009, NULL, 0, 0, 1567123200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (210,  "VetoTopLevel-01", 100046, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (210,  "VetoTopLevel-02", 107798, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (211,  "VetoStationGeneral-00", 100010, NULL, 0, 0, 1567123200000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (212,  "VetoPlateGeneral-00", 100025, NULL, 0, 0, 1567209600000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (211,  "VetoStationGeneral-01", 100049, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (212,  "VetoPlateGeneral-01", 100050, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (220,  "TriggerTopLevel-00", 110009, NULL, 0, 0, 1581292800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (220,  "TriggerTopLevel-01", 100047, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (220,  "TriggerTopLevel-02", 107799, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (221,  "TriggerStationGeneral-00", 110010, NULL, 0, 0, 1581292800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (221,  "TriggerStationGeneral-01", 100051, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (222,  "TriggerPlateGeneral-00", 110025, NULL, 0, 0, 1581292800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (230,  "PreshowerTopLevel-00", 120009, NULL, 0, 0, 1581292800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (230,  "PreshowerTopLevel-01", 100048, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (230,  "PreshowerTopLevel-02", 107800, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (231,  "PreshowerStationGeneral-00", 120010, NULL, 0, 0, 1581292800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (231,  "PreshowerStationGeneral-01", 100052, NULL, 0, 0, 1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (232,  "PreshowerPlateGeneral-00", 120025, NULL, 0, 0, 1581292800000000000, NULL, 22);
@@ -726,119 +799,173 @@ INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-00", 100020, NULL, 0, 0, 15504
 INSERT INTO "HVS_TAG2NODE" VALUES (21, "Veto-01", 100043, NULL, 0, 0,      1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (22, "Trigger-01", 100044, NULL, 0, 0,   1590796800000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-01", 100045, NULL, 0, 0, 1590796800000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (21, "Veto-02", 107801, NULL, 0, 0, 1619222400000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (22, "Trigger-02", 107802, NULL, 0, 0, 1619222400000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-02", 107803, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (1005, "NeutrinoIdentifier-00", 100030, NULL, 0, 0, 1582416000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (2005, "ScintIdentifier-00", 100016, NULL, 0, 0, 1550448000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (3005, "TrackerIdentifier-00", 100017, NULL, 0, 0, 1550448000000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (3005, "TrackerIdentifier-CR", 107785, NULL, 0, 0, 1598400000000000000, NULL, 22);
+INSERT INTO "HVS_TAG2NODE" VALUES (3005, "TrackerIdentifier-02", 107787, NULL, 0, 0, 1619222400000000000, NULL, 22);
 INSERT INTO "HVS_TAG2NODE" VALUES (4005, "CaloIdentifier-00", 100018, NULL, 0, 0, 1550448000000000000, NULL, 22);
 -- Data for the HVS_LTAG2LTAG table
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107804, 1,    100031);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 2,    100001);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 2,    100042);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107784, 2,    100042);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107788, 2,    107789);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 3,    100002);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 3,    100038);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107784, 3,    107783);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107788, 3,    107790);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 4,    100003);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 4,    100003);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107784, 4,    100003);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (0,    100000, 9000,  100005);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (0,    100039, 9000,  100005);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (0,    107784, 9000,  100005);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107788, 4,    107795);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 90,   100013);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 90,   100013);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107788, 90,   100013);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 9000,  100005);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 9000,  100005);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107784, 9000,  100005);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   107788, 9000,  100005);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9001,  100006);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9002,  100007);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9003,  100008);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (1,   100031,  11,  100034);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (11,  100034, 110,  100035);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (11,  100034, 111,  107805);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (11,  100034, 112,  107806);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (11,  100034, 113,  107807);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (11,  100034, 114,  100036);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (1,   100031, 1003, 100032);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (1,   100031, 1004, 100033);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (1,   100031, 1005, 100030);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 21,   100015);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 22,   100019);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 23,   100020);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 21,   100043);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 22,   100044);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 23,   100045);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 21,   107801);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 22,   107802);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 23,   107803);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2003, 100011);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2004, 100012);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2005, 100016);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2003, 100011);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2004, 100012);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2005, 100016);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 2003, 100011);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 2004, 100012);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   107789, 2005, 100016);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 210,  100009);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100043, 210,  100046);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  107801, 210,  100046);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 211,  100010);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 212,  100025);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100043, 211,  100049);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  107801, 211,  100049);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 212,  100025);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100043, 212,  100050);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  107801, 212,  100050);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 214,  100014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100043, 214,  100014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  107801, 214,  100014);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100019, 220,  110009);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 220,  100047);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  107802, 220,  100047);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100019, 221,  110010);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 221,  100051);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  107802, 221,  100051);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100019, 222,  110025);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 221,  110010);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 222,  110025);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  107802, 222,  110025);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100019, 224,  110014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 224,  110014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  107802, 224,  110014);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100020, 230,  120009);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100045, 230,  120048);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  107803, 230,  120048);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100020, 231,  120010);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100045, 231,  100052);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  107803, 231,  100052);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100020, 232,  120025);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100045, 232,  120025);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2003, 100011);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2004, 100012);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2003, 100011);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2004, 100012);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3003, 100021);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3004, 100022);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3003, 100021);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3004, 100022);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  107803, 232,  120025);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100020, 234,  120014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100045, 234,  120014);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  107803, 234,  120014);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 31,   100026);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 31,   100037);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107783, 31,   107781);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107790, 31,   107791);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 32,   100027);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 32,   100041);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107790, 32,   107792);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3003, 100021);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3003, 100021);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107790, 3003, 100021);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3004, 100022);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3004, 100022);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107790, 3004, 100022);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3005, 100017);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3005, 100017);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107781, 3005, 107785);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107790, 3005, 107787);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 310,  106788);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 310,  106790);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100081, 310,  107786);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 310,  106790);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 311,  107003);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 312,  106730);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 313,  106789);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 314,  107782);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 315,  107777);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 316,  107778);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 317,  107779);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 318,  100053);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 311,  107003);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 311,  107003);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 312,  106730);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 312,  106730);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 312,  106730);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 313,  106789);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 313,  106791);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107781, 313,  107780);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 313,  106791);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 314,  107782);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 314,  107782);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 314,  107782);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 315,  107777);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 315,  107777);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 315,  107777);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 316,  107778);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 316,  107778);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 316,  107778);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 317,  107779);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 317,  107779);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 317,  107779);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100026, 318,  100053);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  100037, 318,  100053);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (31,  107791, 318,  100053);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (318, 100053, 3181, 100054);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (318, 100053, 3182, 100055);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 32,   100027);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 32,   100041);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100027, 320,  100029);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100027, 321,  100004);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100027, 324,  100028);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100041, 320,  100040);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  107792, 320,  107794);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100027, 321,  100004);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100041, 321,  100004);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  107792, 321,  100004);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100027, 324,  100028);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  100041, 324,  100028);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (32,  107792, 324,  100028);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   100003, 41,   100056);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 410,  100058);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 411,  100059);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 414,  100057);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   107795, 41,   107796);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   100003, 4003, 100023);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   100003, 4004, 100024);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100000, 90,   100013);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (0,   100039, 90,   100013);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 21,   100015);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 22,   100019);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 23,   100020);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 21,   100043);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 22,   100044);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 23,   100045);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100015, 214,  100014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (21,  100043, 214,  100014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100019, 224,  110014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (22,  100044, 224,  110014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100020, 234,  120014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (23,  100045, 234,  120014);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (1,   100031, 1005, 100030);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100001, 2005, 100016);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (2,   100042, 2005, 100016);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100002, 3005, 100017);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   100038, 3005, 100017);
-INSERT INTO "HVS_LTAG2LTAG" VALUES (3,   107781, 3005, 107785);
 INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   100003, 4005, 100018);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   107795, 4003, 100023);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   107795, 4004, 100024);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (4,   107795, 4005, 100018);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 410,  100058);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  107796, 410,  107797);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 411,  100059);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  100056, 414,  100057);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  107796, 411,  100059);
+INSERT INTO "HVS_LTAG2LTAG" VALUES (41,  107796, 414,  100057);
 -- Data for the HVS_TAGCACHE table
 INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-00", "FASER",              "FASER-00",                100000);
 INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-00", "FaserCommon",        "FaserCommon-00",          100013);
@@ -1020,6 +1147,128 @@ INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-CR", "NeutrinoIdentifier", "NeutrinoId
 INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-CR", "ScintIdentifier",    "ScintIdentifier-00",      100016);
 INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-CR", "TrackerIdentifier",  "TrackerIdentifier-CR",    107785);
 INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-CR", "CaloIdentifier",     "CaloIdentifier-00",       100018);
+
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "FASER",              "FASER-02",                107788);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "FaserCommon",        "FaserCommon-00",          100013);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Materials",          "Materials-00",            100005);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "StdMaterials",       "StdMaterials-00",         100006);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "StdMatComponents",   "StdMatComponents-00",     100007);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Elements",           "Elements-00",             100008);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Scintillator",       "Scintillator-02",         107789);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Tracker",            "Tracker-02",              107790);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SCT",                "SCT-02",                  107791);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctTopLevel",        "SCTTopLevel-02",          107793);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctBrlModule",       "SCTBrlModule-00",         107003);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctBrlSensor",       "SCTBrlSensor-00",         106730);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctFaserGeneral",    "SCTFaserGeneral-01",      106791);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctSwitches",        "SCTSwitches-00",          107782);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SCTMaterials",       "SCTMaterials-00",         107777);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SCTMatComponents",   "SCTMatComponents-00",     107778);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctConditions",      "SctConditions-00",        107779);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctFrame",           "SctFrame-00",             100053);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctFrameGeneral",    "SctFrameGeneral-00",      100054);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "SctFrameShape",      "SctFrameShape-00",        100055);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Dipole",             "Dipole-02",               107792);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "DipoleTopLevel",     "DipoleTopLevel-02",       107794);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "DipoleGeneral",      "DipoleGeneral-00",        100004);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "DipoleSwitches",     "DipoleSwitches-00",       100028);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Calorimeter",        "Calorimeter-02",          107795);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Ecal",               "Ecal-02",                 107796);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "EcalTopLevel",       "EcalTopLevel-02",         107797);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "EcalRowGeneral",     "EcalRowGeneral-00",       100059);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "EcalSwitches",       "EcalSwitches-00",         100057);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "VetoTopLevel",       "VetoTopLevel-02",         107798);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "VetoStationGeneral", "VetoStationGeneral-01",   100049);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "VetoPlateGeneral",   "VetoPlateGeneral-01",     100050);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TriggerTopLevel",       "TriggerTopLevel-02",         107799);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TriggerStationGeneral", "TriggerStationGeneral-01",   100051);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TriggerPlateGeneral",   "TriggerPlateGeneral-00",     110025);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "PreshowerTopLevel",     "PreshowerTopLevel-02",         107800);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "PreshowerStationGeneral", "PreshowerStationGeneral-01",   100052);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "PreshowerPlateGeneral",   "PreshowerPlateGeneral-00",     120025);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "NeutrinoMaterials",     "NeutrinoMaterials-00",       100032);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "NeutrinoMatComponents", "NeutrinoMatComponents-00",   100033);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "ScintMaterials",     "ScintMaterials-00",       100011);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "ScintMatComponents", "ScintMatComponents-00",   100012);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TrackerMaterials",     "TrackerMaterials-00",     100021);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TrackerMatComponents", "TrackerMatComponents-00", 100022);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "CaloMaterials",     "CaloMaterials-00",         100023);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "CaloMatComponents", "CaloMatComponents-00",     100024);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "VetoSwitches",       "VetoSwitches-00",         100014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TriggerSwitches",    "TriggerSwitches-00",      110014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "PreshowerSwitches",  "PreshowerSwitches-00",    120014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Veto",               "Veto-02",                 107801);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Trigger",            "Trigger-02",              107802);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "Preshower",          "Preshower-02",            107803);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "NeutrinoIdentifier", "NeutrinoIdentifier-00",   100030);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "ScintIdentifier",    "ScintIdentifier-00",      100016);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "TrackerIdentifier",  "TrackerIdentifier-02",     107787);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-02", "CaloIdentifier",     "CaloIdentifier-00",       100018);
+
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "FASER",              "FASERNU-02",              107804);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "FaserCommon",        "FaserCommon-00",          100013);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Materials",          "Materials-00",            100005);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "StdMaterials",       "StdMaterials-00",         100006);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "StdMatComponents",   "StdMatComponents-00",     100007);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Elements",           "Elements-00",             100008);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Neutrino",           "Neutrino-00",             100031);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Emulsion",           "Emulsion-00",             100034);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EmulsionTopLevel",   "EmulsionTopLevel-00",     100035);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EmulsionGeneral",    "EmulsionGeneral-00",      107805);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EmulsionFilm",       "EmulsionFilm-00",         107806);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EmulsionPlates",    "EmulsionPlates-00",        107807);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EmulsionSwitches",   "EmulsionSwitches-00",     100036);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Scintillator",       "Scintillator-02",         107789);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Tracker",            "Tracker-02",              107790);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SCT",                "SCT-02",                  107791);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctTopLevel",        "SCTTopLevel-02",          107793);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctBrlModule",       "SCTBrlModule-00",         107003);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctBrlSensor",       "SCTBrlSensor-00",         106730);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctFaserGeneral",    "SCTFaserGeneral-01",      106791);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctSwitches",        "SCTSwitches-00",          107782);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SCTMaterials",       "SCTMaterials-00",         107777);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SCTMatComponents",   "SCTMatComponents-00",     107778);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctConditions",      "SctConditions-00",        107779);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctFrame",           "SctFrame-00",             100053);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctFrameGeneral",    "SctFrameGeneral-00",      100054);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "SctFrameShape",      "SctFrameShape-00",        100055);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Dipole",             "Dipole-02",               107792);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "DipoleTopLevel",     "DipoleTopLevel-02",       107794);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "DipoleGeneral",      "DipoleGeneral-00",        100004);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "DipoleSwitches",     "DipoleSwitches-00",       100028);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Calorimeter",        "Calorimeter-02",          107795);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Ecal",               "Ecal-02",                 107796);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EcalTopLevel",       "EcalTopLevel-02",         107797);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EcalRowGeneral",     "EcalRowGeneral-00",       100059);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "EcalSwitches",       "EcalSwitches-00",         100057);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "VetoTopLevel",       "VetoTopLevel-02",         107798);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "VetoStationGeneral", "VetoStationGeneral-01",   100049);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "VetoPlateGeneral",   "VetoPlateGeneral-01",     100050);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TriggerTopLevel",       "TriggerTopLevel-02",         107799);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TriggerStationGeneral", "TriggerStationGeneral-01",   100051);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TriggerPlateGeneral",   "TriggerPlateGeneral-00",     110025);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "PreshowerTopLevel",     "PreshowerTopLevel-02",         107800);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "PreshowerStationGeneral", "PreshowerStationGeneral-01",   100052);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "PreshowerPlateGeneral",   "PreshowerPlateGeneral-00",     120025);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "NeutrinoMaterials",     "NeutrinoMaterials-00",       100032);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "NeutrinoMatComponents", "NeutrinoMatComponents-00",   100033);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "ScintMaterials",     "ScintMaterials-00",       100011);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "ScintMatComponents", "ScintMatComponents-00",   100012);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TrackerMaterials",     "TrackerMaterials-00",     100021);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TrackerMatComponents", "TrackerMatComponents-00", 100022);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "CaloMaterials",     "CaloMaterials-00",         100023);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "CaloMatComponents", "CaloMatComponents-00",     100024);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "VetoSwitches",       "VetoSwitches-00",         100014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TriggerSwitches",    "TriggerSwitches-00",      110014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "PreshowerSwitches",  "PreshowerSwitches-00",    120014);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Veto",               "Veto-02",                 107801);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Trigger",            "Trigger-02",              107802);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "Preshower",          "Preshower-02",            107803);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "NeutrinoIdentifier", "NeutrinoIdentifier-00",   100030);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "ScintIdentifier",    "ScintIdentifier-00",      100016);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "TrackerIdentifier",  "TrackerIdentifier-02",     107787);
+INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-02", "CaloIdentifier",     "CaloIdentifier-00",       100018);
+
 -- 
 --
 -- Part 2b: Content (Leaf node) data
@@ -1562,18 +1811,72 @@ INSERT INTO "ELEMENTS_DATA2TAG" VALUES (100008, 90);
 INSERT INTO "ELEMENTS_DATA2TAG" VALUES (100008, 91);
 --
 --
+INSERT INTO "EMULSIONTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, -2475.72, 0.0, 0.0, 0.0, 321, "Emulsion");
+INSERT INTO "EMULSIONTOPLEVEL_DATA" VALUES (1, 0.0, 0.0,     0.0, 0.0, 0.0, 0.0, 321, "StationA");
+INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (100035, 0);
+INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (100035, 1);
+--
+--
+INSERT INTO "EMULSIONGENERAL_DATA" VALUES (0, 35, 22, -524.275, 525.275);
+INSERT INTO "EMULSIONGENERAL_DATA2TAG" VALUES (107805, 0);
+--
+--
+INSERT INTO "EMULSIONFILM_DATA" VALUES (0, 250.0, 300.0, 0.210, "neutrino::Polystyrene", 250.0, 300.0, 0.070, "neutrino::Emulsion");
+INSERT INTO "EMULSIONFILM_DATA2TAG" VALUES (107806, 0);
+--
+--
+INSERT INTO "EMULSIONPLATES_DATA" VALUES (0, 250.0, 300.0, 1050.9, 0.0, 0.0, 0.0, "std::Wolfram");
+INSERT INTO "EMULSIONPLATES_DATA2TAG" VALUES (107807, 0);
+--
+--
+INSERT INTO "NEUTRINOMATERIALS_DATA" VALUES (0, "Polystyrene", 1.06);
+INSERT INTO "NEUTRINOMATERIALS_DATA" VALUES (1, "Emulsion", 3.58);
+INSERT INTO "NEUTRINOMATERIALS_DATA2TAG" VALUES (100032, 0);
+INSERT INTO "NEUTRINOMATERIALS_DATA2TAG" VALUES (100032, 1);
+--
+--
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(0, 0, "Hydrogen", 8.0);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(1, 0, "Carbon", 8.0);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(2, 1, "Hydrogen", 0.388171);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(3, 1, "Carbon",   0.184594);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(4, 1, "Nitrogen", 0.052763);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(5, 1, "Oxygen",   0.119373);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(6, 1, "Sodium",   0.002647);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(7, 1, "Sulfur",   0.001708);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(8, 1, "Bromine",  0.123103);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(9, 1, "Silver",   0.125381);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA" VALUES(10,1, "Iodine",   0.002261);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 0);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 1);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 2);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 3);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 4);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 5);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 6);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 7);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 8);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 9);
+INSERT INTO "NEUTRINOMATCOMPONENTS_DATA2TAG" VALUES (100033, 10);
+--
+--
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, -1725.0, 0.0, 0.0, 0.0, 321, "Veto");
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, -160.0, 0.0, 0.0, 0.0, 321, "StationA");
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (2, 0.0, 0.0,  160.0, 0.0, 0.0, 0.0, 321, "StationB");
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (3, 0.0, 0.0, -1709.0, 0.0, 0.0, 0.0, 321, "Veto");
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (4, 0.0, 0.0, -100.0, 0.0, 0.0, 0.0, 321, "StationA");
 INSERT INTO "VETOTOPLEVEL_DATA" VALUES (5, 0.0, 0.0,  100.0, 0.0, 0.0, 0.0, 321, "StationB");
+INSERT INTO "VETOTOPLEVEL_DATA" VALUES (6, 0.0, 0.0, -1694.65, 0.0, 0.0, 0.0, 321, "Veto");
+INSERT INTO "VETOTOPLEVEL_DATA" VALUES (7, 0.0, 0.0, -85.0, 0.0, 0.0, 2.6, 321, "StationA");
+INSERT INTO "VETOTOPLEVEL_DATA" VALUES (8, 0.0, 0.0,  85.0, 0.0, 0.0,-2.6, 321, "StationB");
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100009, 0);
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100009, 1);
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100009, 2);
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100046, 3);
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100046, 4);
 INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (100046, 5);
+INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (107798, 6);
+INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (107798, 7);
+INSERT INTO "VETOTOPLEVEL_DATA2TAG" VALUES (107798, 8);
 --
 --
 INSERT INTO "VETOSTATIONGENERAL_DATA" VALUES (0, 2, 100.0);
@@ -1590,10 +1893,13 @@ INSERT INTO "VETOPLATEGENERAL_DATA2TAG" VALUES (100050, 1);
 INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, 187.0, 0.0, 0.0, 0.0, 321, "Trigger");
 INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 321, "StationA");
 INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (2, 0.0, -5.0, -28.9, 0.0, 0.0, 0.0, 321, "Trigger");
+INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (3, 0.0, -5.0, -29.2, 0.0, 0.0, 0.0, 321, "Trigger");
 INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (110009, 0);
 INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (110009, 1);
 INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (100047, 1);
 INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (100047, 2);
+INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (107799, 3);
+INSERT INTO "TRIGGERTOPLEVEL_DATA2TAG" VALUES (107799, 1);
 --
 --
 INSERT INTO "TRIGGERSTATIONGENERAL_DATA" VALUES (0, 2, 195.0, 11.0);
@@ -1608,10 +1914,13 @@ INSERT INTO "TRIGGERPLATEGENERAL_DATA2TAG" VALUES (110025, 0);
 INSERT INTO "PRESHOWERTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, 2626.0, 0.0, 0.0, 0.0, 321, "Preshower");
 INSERT INTO "PRESHOWERTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 321, "StationA");
 INSERT INTO "PRESHOWERTOPLEVEL_DATA" VALUES (2, 0.0, 0.0, 2662.7, 0.0, 0.0, 0.0, 321, "Preshower");
+INSERT INTO "PRESHOWERTOPLEVEL_DATA" VALUES (3, 0.0, 0.0, 2662.35, 0.0, 0.0, 0.0, 321, "Preshower");
 INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (120009, 0);
 INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (120009, 1);
 INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (100048, 1);
 INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (100048, 2);
+INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (107800, 1);
+INSERT INTO "PRESHOWERTOPLEVEL_DATA2TAG" VALUES (107800, 3);
 --
 --
 INSERT INTO "PRESHOWERSTATIONGENERAL_DATA" VALUES (0, 2, 80.0);
@@ -1626,9 +1935,13 @@ INSERT INTO "PRESHOWERPLATEGENERAL_DATA2TAG" VALUES (120025, 0);
 INSERT INTO "ECALTOPLEVEL_DATA" VALUES (0, 0.0,   0.0, 3099.2, 0.0, 0.0, 0.0, 321, "Ecal");
 INSERT INTO "ECALTOPLEVEL_DATA" VALUES (1, 0.0, -71.6,    0.0, 0.0, 2.8, 0.0, 321, "BottomRow");
 INSERT INTO "ECALTOPLEVEL_DATA" VALUES (2, 0.0,  49.6,    0.0, 0.0, 2.8, 0.0, 321, "TopRow");
+INSERT INTO "ECALTOPLEVEL_DATA" VALUES (3, 0.0,   0.0, 3098.9, 0.0, 0.0, 0.0, 321, "Ecal");
 INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (100058, 0);
 INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (100058, 1);
 INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (100058, 2);
+INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (107797, 1);
+INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (107797, 2);
+INSERT INTO "ECALTOPLEVEL_DATA2TAG" VALUES (107797, 3);
 --
 --
 INSERT INTO "ECALROWGENERAL_DATA" VALUES (0, 2, 0.0, 2.8);
@@ -1649,6 +1962,10 @@ INSERT INTO "FASERCOMMON_DATA" VALUES (0, "RUN3", "TRACKER", "NONE");
 INSERT INTO "FASERCOMMON_DATA2TAG" VALUES (100013, 0);
 --
 --
+INSERT INTO "EMULSIONSWITCHES_DATA" VALUES  (0, "Emulsion", 1, 0, "GEO", "Development", "Baseline geometry");
+INSERT INTO "EMULSIONSWITCHES_DATA2TAG" VALUES (100036, 0);
+--
+--
 INSERT INTO "VETOSWITCHES_DATA" VALUES  (0, "Veto", 1, 0, "GEO", "Development", "Baseline geometry");
 INSERT INTO "VETOSWITCHES_DATA2TAG" VALUES (100014, 0);
 --
@@ -1675,8 +1992,10 @@ INSERT INTO "SCINTIDENTIFIER_DATA2TAG" VALUES (100016, 0);
 --
 INSERT INTO "TRACKERIDENTIFIER_DATA" VALUES (0, "Tracker", "TrackerIdDictFiles/IdDictTracker.xml", "Baseline layout");
 INSERT INTO "TRACKERIDENTIFIER_DATA" VALUES (1, "Tracker", "TrackerIdDictFiles/IdDictCosmic.xml", "Cosmic ray test stand");
+INSERT INTO "TRACKERIDENTIFIER_DATA" VALUES (2, "Tracker", "TrackerIdDictFiles/IdDictInterface.xml", "Tracker with interface detector");
 INSERT INTO "TRACKERIDENTIFIER_DATA2TAG" VALUES (100017, 0);
 INSERT INTO "TRACKERIDENTIFIER_DATA2TAG" VALUES (107785, 1);
+INSERT INTO "TRACKERIDENTIFIER_DATA2TAG" VALUES (107787, 2);
 --
 --
 INSERT INTO "CALOIDENTIFIER_DATA" VALUES (0, "Calorimeter", "CaloIdDictFiles/IdDictCalorimeter.xml", "Baseline layout");
@@ -1713,6 +2032,9 @@ INSERT INTO "SCTTOPLEVEL_DATA" VALUES(4,0.0,0.0,-1190.0,0.0,0.0,0.0,312,'Station
 INSERT INTO "SCTTOPLEVEL_DATA" VALUES(5,0.0,0.0,    0.0,0.0,0.0,0.0,312,'StationB');
 INSERT INTO "SCTTOPLEVEL_DATA" VALUES(6,0.0,0.0, 1190.0,0.0,0.0,0.0,312,'StationC');
 INSERT INTO "SCTTOPLEVEL_DATA" VALUES(7,0.0,0.0, 1237.7075,0.0,0.0,0.0,312,'SCT');
+INSERT INTO "SCTTOPLEVEL_DATA" VALUES(8,0.0,0.0, 1237.4   ,0.0,0.0,0.0,312,'SCT');
+INSERT INTO "SCTTOPLEVEL_DATA" VALUES(9,0.0,0.0,-3097.55  ,0.0,0.0,0.0,312,'Interface');
+
 
 DROP TABLE IF EXISTS "SCTTOPLEVEL_DATA2TAG";
 CREATE TABLE "SCTTOPLEVEL_DATA2TAG" ( "SCTTOPLEVEL_TAG_ID" SLONGLONG ,"SCTTOPLEVEL_DATA_ID" SLONGLONG  );
@@ -1726,6 +2048,11 @@ INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(106790,6);
 INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(106790,7);
 INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107786,5);
 INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107786,7);
+INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107793,4);
+INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107793,5);
+INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107793,6);
+INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107793,8);
+INSERT INTO "SCTTOPLEVEL_DATA2TAG" VALUES(107793,9);
 --
 --
 DROP TABLE IF EXISTS "SCTFASERGENERAL_DATA";
@@ -1844,6 +2171,10 @@ INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(3,0.0,0.0, 0.0,0.0,0.0,0.0,312,'Dipole'
 INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(4,0.0,0.0,-812.32,0.0,0.0,0.0,312,'UpstreamDipole');
 INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(5,0.0,0.0, 637.726,0.0,0.0,0.0,312,'CentralDipole');
 INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(6,0.0,0.0,1837.726,0.0,0.0,0.0,312,'DownstreamDipole');
+INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(7,0.0,0.0,-812.60,0.0,0.0,0.0,312,'UpstreamDipole');
+INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(8,0.0,0.0, 637.40,0.0,0.0,0.0,312,'CentralDipole');
+INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(9,0.0,0.0,1837.40,0.0,0.0,0.0,312,'DownstreamDipole');
+
 
 DROP TABLE IF EXISTS "DIPOLETOPLEVEL_DATA2TAG";
 CREATE TABLE "DIPOLETOPLEVEL_DATA2TAG" ( "DIPOLETOPLEVEL_TAG_ID" SLONGLONG ,"DIPOLETOPLEVEL_DATA_ID" SLONGLONG  );
@@ -1855,6 +2186,10 @@ INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(100040,3);
 INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(100040,4);
 INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(100040,5);
 INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(100040,6);
+INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,3);
+INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,7);
+INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,8);
+INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,9);
 --
 --
 DROP TABLE IF EXISTS "DIPOLEGENERAL_DATA";
diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py b/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py
index c75cbdbc6759af504b8d9baebf35dce8369e96ac..72e1d79a4266d82191dfef3141587dea7ac460d3 100644
--- a/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py
+++ b/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py
@@ -8,6 +8,9 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 def FaserGeometryCfg (flags):
     acc = ComponentAccumulator()
 
+    from EmulsionGeoModel.EmulsionGeoModelConfig import EmulsionGeometryCfg
+    acc.merge(EmulsionGeometryCfg(flags))
+
     from FaserGeoModel.ScintGMConfig import ScintGeometryCfg
     acc.merge(ScintGeometryCfg(flags))
 
diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py b/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py
index 7d9c16d9f7a66cc823b993919413bd992bbdb3f1..e645c94bc676149dd92ee6b4357f73f23b462f95 100644
--- a/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py
+++ b/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py
@@ -22,6 +22,10 @@ def _setupGeoModel():
 
     # Set up detector tools here
 
+    if not hasattr(svcMgr,'NeutrinoGeometryDBSvc'):
+        from GeometryDBSvc.GeometryDBSvcConf import GeometryDBSvc
+        svcMgr+=GeometryDBSvc("NeutrinoGeometryDBSvc")
+
     if not hasattr(svcMgr,'ScintGeometryDBSvc'):
         from GeometryDBSvc.GeometryDBSvcConf import GeometryDBSvc
         svcMgr+=GeometryDBSvc("ScintGeometryDBSvc")
@@ -35,6 +39,10 @@ def _setupGeoModel():
         svcMgr+=GeometryDBSvc("CaloGeometryDBSvc")
 
     # from AthenaCommon import CfgGetter
+    from EmulsionGeoModel.EmulsionGeoModelConf import EmulsionDetectorTool
+    emulsionDetectorTool = EmulsionDetectorTool(DetectorName = "Emulsion", Alignable = True, RDBAccessSvc = "RDBAccessSvc", GeometryDBSvc = "NeutrinoGeometryDBSvc", GeoDbTagSvc = "GeoDbTagSvc")
+    geoModelSvc.DetectorTools += [ emulsionDetectorTool ]
+
     from VetoGeoModel.VetoGeoModelConf import VetoDetectorTool
     vetoDetectorTool = VetoDetectorTool( DetectorName = "Veto",
                                          Alignable = True,
diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py b/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py
index 1c94db586d1ca1baec1fe7df455eaaff6f10bbef..93c42c057852c8b24ac4760ea70a612941c04855 100644
--- a/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py
+++ b/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py
@@ -35,7 +35,7 @@ if __name__ == "__main__":
   # from AthenaConfiguration.TestDefaults import defaultTestFiles
   # Provide MC input
   # ConfigFlags.Input.Files = defaultTestFiles.HITS
-  ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+  ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
   ConfigFlags.Detector.GeometryVeto   = True
   ConfigFlags.Detector.GeometryTrigger= True
   ConfigFlags.Detector.GeometryPreshower= True
diff --git a/DetectorDescription/GeoModel/FaserGeoModel/test/FaserGeometryConfig_EVNT_test.py b/DetectorDescription/GeoModel/FaserGeoModel/test/FaserGeometryConfig_EVNT_test.py
index eb0ced94e5731055600128fce56efe974a0b7d25..d96261d51b790ec7da566e36782a2172781da473 100644
--- a/DetectorDescription/GeoModel/FaserGeoModel/test/FaserGeometryConfig_EVNT_test.py
+++ b/DetectorDescription/GeoModel/FaserGeoModel/test/FaserGeometryConfig_EVNT_test.py
@@ -23,7 +23,7 @@ if __name__ == "__main__":
     ConfigFlags.Common.ProductionStep = ProductionStep.Simulation
     ConfigFlags.Input.Files = defaultTestFiles.EVNT
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic    = False
     ConfigFlags.lock()
 
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/CMakeLists.txt b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..71d3ffbd687e98865e625840fefcd786cbc45353
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/CMakeLists.txt
@@ -0,0 +1,28 @@
+################################################################################
+# Package: EmulsionGeoModel
+################################################################################
+
+# Declare the package name:
+atlas_subdir( EmulsionGeoModel )
+
+# External dependencies:
+find_package( Boost COMPONENTS filesystem thread system )
+find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess )
+find_package( Eigen )
+find_package( GeoModel )
+
+# Component(s) in the package:
+atlas_add_component( EmulsionGeoModel
+        		     src/*.cxx
+                     src/components/*.cxx
+                     INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} 
+                     LINK_LIBRARIES ${Boost_LIBRARIES} ${CORAL_LIBRARIES} ${GEOMODEL_LIBRARIES} AthenaKernel GeoModelFaserUtilities GaudiKernel SGTools StoreGateLib SGtests AthenaPoolUtilities DetDescrConditions FaserDetDescr NeutrinoGeoModelUtils NeutrinoReadoutGeometry NeutrinoIdentifier Identifier )
+
+atlas_add_test( EmulsionGMConfig_test
+                SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/test/EmulsionGMConfig_test.py
+                PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+                PROPERTIES TIMEOUT 300 )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+atlas_install_scripts( test/*.py )
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionDetectorTool.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionDetectorTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7eab489a28497149a298fc74fe9f8de8aee60fd
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionDetectorTool.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONDETECTORTOOL_H
+#define EMULSIONGEOMODEL_EMULSIONDETECTORTOOL_H
+
+#include "GeoModelFaserUtilities/GeoModelTool.h"
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h" 
+
+#include "GeometryDBSvc/IGeometryDBSvc.h"
+#include "GeoModelInterfaces/IGeoDbTagSvc.h"
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+
+#include "GaudiKernel/ServiceHandle.h"
+
+#include <string>
+
+namespace NeutrinoDD {
+  class EmulsionDetectorManager;
+}
+
+class EmulsionID;
+// class FaserDetectorID;
+
+class EmulsionDetectorTool : public GeoModelTool {
+
+public:
+  // Standard Constructor
+  EmulsionDetectorTool(const std::string& type, const std::string& name, const IInterface* parent);
+
+  virtual StatusCode create() override final;
+  virtual StatusCode clear() override final;
+
+  // Register callback function on ConDB object
+  virtual StatusCode registerCallback ATLAS_NOT_THREAD_SAFE () override final;
+
+  // Callback function itself
+  virtual StatusCode align(IOVSVC_CALLBACK_ARGS) override;
+
+private:
+  StringProperty m_detectorName{this, "DetectorName", "Emulsion"};
+  BooleanProperty m_alignable{this, "Alignable", true};
+  BooleanProperty m_useDynamicAlignFolders{this, "useDynamicAlignFolders", false};
+  bool m_cosmic;
+
+  const NeutrinoDD::EmulsionDetectorManager* m_manager;
+  
+  EmulsionGeoModelAthenaComps m_athenaComps;
+
+  ServiceHandle< IGeoDbTagSvc > m_geoDbTagSvc;
+  ServiceHandle< IRDBAccessSvc > m_rdbAccessSvc;
+  ServiceHandle< IGeometryDBSvc > m_geometryDBSvc;
+
+  StringProperty m_run1Folder{this,   "Run1Folder",   "/Neutrino/Align"};
+  StringProperty m_run2L1Folder{this, "Run2L1Folder", "/Neutrino/AlignL1/ID"};
+  StringProperty m_run2L2Folder{this, "Run2L2Folder", "/Neutrino/AlignL2/SCT"};
+  StringProperty m_run2L3Folder{this, "Run2L3Folder", "/Neutrino/AlignL3"};
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONDETECTORTOOL_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionGeoModelAthenaComps.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionGeoModelAthenaComps.h
new file mode 100644
index 0000000000000000000000000000000000000000..977e6d6144606fc0022bcd77aed9ed03aee0035e
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/EmulsionGeoModel/EmulsionGeoModelAthenaComps.h
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionGeoModelAthenaComps_H
+#define EmulsionGeoModel_EmulsionGeoModelAthenaComps_H 1
+
+#include "NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h"
+
+class EmulsionID;
+
+/// Class to hold various Athena components
+// template <class ID_HELPER>
+class EmulsionGeoModelAthenaComps : public NeutrinoDD::AthenaComps {
+
+public:
+
+  EmulsionGeoModelAthenaComps();
+
+  void setIdHelper(const EmulsionID* idHelper);
+
+  const EmulsionID* getIdHelper() const;
+
+private:
+  const EmulsionID* m_idHelper;
+
+};
+
+#endif // EmulsionGeoModel_EmulsionGeoModelAthenaComps_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/python/EmulsionGeoModelConfig.py b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/python/EmulsionGeoModelConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1465d18e845ac9fbee190968da24deca5017625
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/python/EmulsionGeoModelConfig.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+# from IOVDbSvc.IOVDbSvcConfig import addFoldersSplitOnline
+
+def EmulsionGeometryCfg( flags ):
+    from FaserGeoModel.GeoModelConfig import GeoModelCfg
+    acc = GeoModelCfg( flags )
+    geoModelSvc = acc.getPrimary()
+
+    if flags.Detector.GeometryEmulsion:
+        GeometryDBSvc = CompFactory.GeometryDBSvc
+        acc.addService(GeometryDBSvc("NeutrinoGeometryDBSvc"))
+
+        EmulsionDetectorTool = CompFactory.EmulsionDetectorTool
+        emulsionDetectorTool = EmulsionDetectorTool()
+
+        emulsionDetectorTool.useDynamicAlignFolders = flags.GeoModel.Align.Dynamic
+        geoModelSvc.DetectorTools += [ emulsionDetectorTool ]
+
+    return acc
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5f841889b2a2af73f8ce5d1d8ec10a1ddf0b179e
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.cxx
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionBase.h"
+
+#include "EmulsionGeometryManager.h"
+#include "EmulsionMaterialManager.h"
+
+#include "EmulsionFilmParameters.h"
+
+#include "GeoModelKernel/GeoBox.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoMaterial.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoVPhysVol.h"
+#include "GeoModelKernel/GeoNameTag.h"
+#include "GeoModelKernel/GeoIdentifierTag.h"
+#include "GeoModelKernel/GeoTransform.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+#include "GaudiKernel/SystemOfUnits.h"
+
+using namespace NeutrinoDD;
+
+EmulsionBase::EmulsionBase(const std::string & name,
+                     NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                     const EmulsionGeometryManager* geometryManager,
+                     EmulsionMaterialManager* materials)
+  : EmulsionUniqueComponentFactory(name, detectorManager, geometryManager, materials)
+{
+  getParameters();
+  m_logVolume = preBuild();
+}
+
+
+void
+EmulsionBase::getParameters()
+{
+  const EmulsionFilmParameters * parameters = m_geometryManager->filmParameters();
+  m_baseThickness = parameters->baseThickness();
+  m_baseHeight    = parameters->baseHeight();
+  m_baseWidth     = parameters->baseWidth();
+  m_filmThickness = parameters->filmThickness();
+  m_filmHeight    = parameters->filmHeight();
+  m_filmWidth     = parameters->filmWidth();
+  m_detectorManager->numerology().setNumFilmsPerBase(2);
+}
+
+const GeoLogVol * 
+EmulsionBase::preBuild()
+{
+  // Create child elements
+  m_baseboard = new EmulsionBaseboard("Baseboard", m_detectorManager, m_geometryManager, m_materials);
+  m_front = new EmulsionFilm("FrontFilm", m_detectorManager, m_geometryManager, m_materials);
+  m_back =  new EmulsionFilm("BackFilm", m_detectorManager, m_geometryManager, m_materials);
+
+  // Build a box to hold the base and two films
+  m_width = std::max(m_baseWidth, m_filmWidth);
+  m_height = std::max(m_baseHeight, m_filmHeight);
+  m_thickness = m_baseThickness + 2 * m_filmThickness;
+  const GeoBox* baseShape = new GeoBox(0.5*m_width, 0.5*m_height, 0.5*m_thickness);
+
+  GeoLogVol * baseLog = new GeoLogVol(getName(), baseShape, m_materials->gasMaterial());
+
+  m_baseboardPos = new GeoTrf::Translate3D(0.0, 0.0, 0.0);
+  m_frontPos     = new GeoTrf::Translate3D(0.0, 0.0, -(m_baseThickness + m_filmThickness)/2);
+  m_backPos     = new GeoTrf::Translate3D(0.0, 0.0, (m_baseThickness + m_filmThickness)/2);
+
+  return baseLog;
+}
+
+GeoVPhysVol * 
+EmulsionBase::build(EmulsionIdentifier id)
+{
+  GeoFullPhysVol * base = new GeoFullPhysVol(m_logVolume); 
+
+  // Add Baseboard
+  GeoTransform * baseboardTransform = new GeoTransform(*m_baseboardPos);
+  base->add(baseboardTransform);
+  base->add(m_baseboard->getVolume());
+
+  // Add front side
+  GeoAlignableTransform * frontTransform = new GeoAlignableTransform(*m_frontPos);
+  base->add(frontTransform);
+  int frontNumber = 0;
+  base->add(new GeoNameTag("Film#"+intToString(frontNumber))); // Identifier side=0
+  base->add(new GeoIdentifierTag(frontNumber));
+  id.setFilm(frontNumber);
+  Identifier frontId = id.getFilmId();
+  GeoVPhysVol * frontSide = m_front->build(id);
+  base->add(frontSide);  
+  // Store alignable transform
+  m_detectorManager->addAlignableTransform(0, frontId, frontTransform, frontSide);
+
+  // Add back side
+  GeoAlignableTransform * backTransform = new GeoAlignableTransform(*m_backPos);
+  base->add(backTransform);
+  int backNumber = 1;
+  base->add(new GeoNameTag("Film#"+intToString(backNumber))); // Identifier side=1
+  base->add(new GeoIdentifierTag(backNumber));
+  id.setFilm(backNumber);
+  Identifier backId = id.getFilmId();
+  GeoVPhysVol * backSide = m_back->build(id);
+  base->add(backSide);  
+  // Store alignable transform
+  m_detectorManager->addAlignableTransform(0, backId, backTransform, backSide);
+     
+  return base;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0df5dec8edd6106f1bee13879e3e67b955d11a8
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBase.h
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONBASE_H
+#define EMULSIONGEOMODEL_EMULSIONBASE_H
+
+#include "EmulsionComponentFactory.h"
+#include "EmulsionFilm.h"
+#include "EmulsionBaseboard.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+
+#include <atomic>
+#include <string>
+
+class GeoMaterial;
+class GeoVPhysVol;
+
+class EmulsionBase: public EmulsionUniqueComponentFactory
+{
+public:
+  EmulsionBase(const std::string & name,
+             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+             const EmulsionGeometryManager* geometryManager,
+             EmulsionMaterialManager* materials);
+
+public:
+  double thickness() const {return m_thickness;}
+  double width()     const {return m_width;}
+  double height()    const {return m_height;}
+
+  virtual GeoVPhysVol * build(EmulsionIdentifier id);
+  
+private:
+  void getParameters();
+  virtual const GeoLogVol * preBuild();
+ 
+  double m_thickness;
+  double m_width;
+  double m_height;
+  
+  double m_baseThickness;
+  double m_baseHeight;
+  double m_baseWidth;
+  double m_filmThickness;
+  double m_filmHeight;
+  double m_filmWidth;
+
+  EmulsionBaseboard* m_baseboard;
+  EmulsionFilm* m_front;
+  EmulsionFilm* m_back;
+
+  GeoTrf::Transform3D * m_frontPos;
+  GeoTrf::Transform3D * m_backPos;
+  GeoTrf::Translate3D * m_baseboardPos; 
+
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONBASE_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5cad5bd1907f660a15bd4b6684f610a34582b44d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.cxx
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionBaseboard.h"
+
+#include "EmulsionGeometryManager.h"
+#include "EmulsionMaterialManager.h"
+
+#include "EmulsionFilmParameters.h"
+
+#include "GeoModelKernel/GeoBox.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoMaterial.h"
+
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+#include "GaudiKernel/SystemOfUnits.h"
+
+using namespace NeutrinoDD;
+
+EmulsionBaseboard::EmulsionBaseboard(const std::string & name,
+                     NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                     const EmulsionGeometryManager* geometryManager,
+                     EmulsionMaterialManager* materials)
+  : EmulsionSharedComponentFactory(name, detectorManager, geometryManager, materials)
+{
+  getParameters();
+  m_physVolume = build();
+}
+
+
+void
+EmulsionBaseboard::getParameters()
+{
+  const EmulsionFilmParameters * parameters = m_geometryManager->filmParameters();
+  m_material  = m_materials->getMaterial(parameters->baseMaterial());
+  m_thickness = parameters->baseThickness();
+  m_height    = parameters->baseHeight();
+  m_width     = parameters->baseWidth();
+}
+
+GeoVPhysVol * 
+EmulsionBaseboard::build()
+{
+  const GeoBox* baseboardShape = new GeoBox(0.5*m_width, 0.5*m_height, 0.5*m_thickness);
+
+  GeoLogVol * baseboardLog = new GeoLogVol(getName(), baseboardShape, m_material);
+
+  GeoPhysVol * baseboard = new GeoPhysVol(baseboardLog); 
+  
+  return baseboard;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.h
new file mode 100644
index 0000000000000000000000000000000000000000..57123c8fa5b67c79b27887522c0a15e89098f520
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionBaseboard.h
@@ -0,0 +1,43 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONBASEBOARD_H
+#define EMULSIONGEOMODEL_EMULSIONBASEBOARD_H
+
+#include "EmulsionComponentFactory.h"
+
+#include <atomic>
+#include <string>
+
+class GeoMaterial;
+class GeoVPhysVol;
+namespace NeutrinoDD{class NeutrinoDetectorDesign;}
+
+class EmulsionBaseboard: public EmulsionSharedComponentFactory
+{
+public:
+  EmulsionBaseboard(const std::string & name,
+             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+             const EmulsionGeometryManager* geometryManager,
+             EmulsionMaterialManager* materials);
+
+public:
+  const GeoMaterial * material() const {return m_material;} 
+  double thickness() const {return m_thickness;}
+  double width()     const {return m_width;}
+  double height()    const {return m_height;}
+
+  virtual GeoVPhysVol * build();
+  
+private:
+  void getParameters();
+ 
+  const GeoMaterial * m_material;
+  double m_thickness;
+  double m_width;
+  double m_height;
+  
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONBASEBOARD_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f919d78e85dbf8224e810ec5773790b71fc75995
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.cxx
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionComponentFactory.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include <sstream>
+#include <string>
+
+using NeutrinoDD::EmulsionDetectorManager;
+
+const double EmulsionComponentFactory::s_epsilon = 1.0e-6 * Gaudi::Units::mm;
+
+EmulsionComponentFactory::EmulsionComponentFactory(const std::string & name,
+                                           NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                                           const EmulsionGeometryManager* geometryManager,
+                                           EmulsionMaterialManager* materials)
+  : m_detectorManager(detectorManager), 
+    m_geometryManager(geometryManager),
+    m_materials(materials),
+    m_name(name)
+{}
+
+EmulsionComponentFactory::~EmulsionComponentFactory() 
+{}
+
+std::string 
+EmulsionComponentFactory::intToString(int i) const
+{
+  std::ostringstream str;
+  str << i;
+  return str.str();
+}
+
+double
+EmulsionComponentFactory::epsilon() const
+{
+  return s_epsilon;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..2606dbb9aba6906a38c14ae1c8769ed73b1ff200
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionComponentFactory.h
@@ -0,0 +1,89 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONCOMPONENTFACTORY_H
+#define EMULSIONGEOMODEL_EMULSIONCOMPONENTFACTORY_H
+
+#include "EmulsionIdentifier.h"
+#include <string>
+
+namespace NeutrinoDD{class EmulsionDetectorManager;}
+class EmulsionGeometryManager;
+class EmulsionMaterialManager;
+
+class GeoLogVol;
+class GeoVPhysVol;
+
+
+class EmulsionComponentFactory
+{
+
+public:
+  EmulsionComponentFactory(const std::string & name,
+                       NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                       const EmulsionGeometryManager* geometryManager,
+                       EmulsionMaterialManager* materials);
+
+  const std::string & getName() const {return m_name;}
+
+  // utility function to covert int to string
+  std::string intToString(int i) const;
+
+protected: 
+  NeutrinoDD::EmulsionDetectorManager* m_detectorManager;
+  const EmulsionGeometryManager* m_geometryManager;
+  EmulsionMaterialManager* m_materials;
+
+  double epsilon() const;
+  virtual ~EmulsionComponentFactory();
+
+private:
+  std::string m_name;
+  static const double s_epsilon;
+
+};
+
+
+class EmulsionSharedComponentFactory : public EmulsionComponentFactory
+{
+
+public:
+  EmulsionSharedComponentFactory(const std::string & name,
+                             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                             const EmulsionGeometryManager* geometryManager,
+                             EmulsionMaterialManager* materials=nullptr) :
+    EmulsionComponentFactory(name, detectorManager, geometryManager, materials),
+    m_physVolume(nullptr)
+  {};
+  
+  GeoVPhysVol * getVolume() {return  m_physVolume;}
+
+protected:
+  GeoVPhysVol * m_physVolume;
+  virtual GeoVPhysVol * build() = 0;
+
+};
+
+class EmulsionUniqueComponentFactory : public EmulsionComponentFactory
+{
+
+public:
+  EmulsionUniqueComponentFactory(const std::string & name,
+                             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                             const EmulsionGeometryManager* geometryManager,
+                             EmulsionMaterialManager* materials=nullptr) :
+    EmulsionComponentFactory(name, detectorManager, geometryManager, materials),
+    m_logVolume{nullptr}
+  {};
+
+  virtual GeoVPhysVol * build(EmulsionIdentifier id) = 0;
+
+protected:
+  const GeoLogVol * m_logVolume;
+
+  virtual const GeoLogVol * preBuild() = 0;
+
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONCOMPONENTFACTORY_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..eae5fd1e07a8e70ec9bcec697d3deeb4da41d4d0
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx
@@ -0,0 +1,108 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionDataBase.h"
+
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+
+#include "GeoModelInterfaces/IGeoDbTagSvc.h"
+#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h"
+
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h"
+
+#include <iostream>
+
+EmulsionDataBase::EmulsionDataBase(const EmulsionGeoModelAthenaComps * athenaComps)
+{
+  m_athenaComps = athenaComps;
+
+  IGeoDbTagSvc * geoDbTag = m_athenaComps->geoDbTagSvc();
+
+  // Get version tag and node for Emulsion
+  DecodeFaserVersionKey versionKey(geoDbTag,"Emulsion");
+  std::string versionTag  = versionKey.tag();
+  std::string versionNode = versionKey.node();
+
+  // Get version tag and node for Neutrino.
+  DecodeFaserVersionKey neutrinoVersionKey(geoDbTag,"Neutrino");
+
+  // Access the RDB
+  IRDBAccessSvc* rdbSvc = m_athenaComps->rdbAccessSvc();
+
+  // Emulsion version tag
+  m_emulsionVersionTag = rdbSvc->getChildTag("Emulsion", versionKey.tag(), versionKey.node(), "FASERDD");
+
+
+/////////////////////////////////////////////////////////
+//
+// Gets the structures
+//
+/////////////////////////////////////////////////////////
+
+    msg(MSG::INFO) << "Retrieving Record Sets from database ..." << endmsg;
+    msg(MSG::DEBUG) << " Using version tag: " << versionTag << endmsg;
+    msg(MSG::DEBUG) << "           at node: " << versionNode << endmsg;
+    msg(MSG::DEBUG) << " Emulsion Version:       " << m_emulsionVersionTag << endmsg;
+
+  // ATLS - not sure I use it.
+  // General atlas parameters
+
+  //
+  // Emulsion General
+  //
+
+  // Emulsion TopLevel
+  m_topLevel = rdbSvc->getRecordsetPtr("EmulsionTopLevel", versionTag, versionNode, "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionTopLevel Fetched" << endmsg;
+
+  // Weight Table
+  m_weightTable = rdbSvc->getRecordsetPtr("EmulsionWeights", versionTag, versionNode, "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionWeights Fetched" << endmsg;
+
+  // Extra Scaling Table. This is used for extra material studies. For nominal material the table should be empty.
+  // NB this is at InnerDetector level node.
+  m_scalingTable = rdbSvc->getRecordsetPtr("EmulsionMatScaling", neutrinoVersionKey.tag(), neutrinoVersionKey.node(), "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionMatScaling Fetched" << endmsg;
+
+//   // Default conditions
+//   m_conditions = rdbSvc->getRecordsetPtr("EmulsionConditions", versionTag, versionNode, "FASERDD");
+//   msg(MSG::DEBUG) << "Table EmulsionConditions Fetched" << endmsg;
+
+  m_emulsionGeneral = rdbSvc->getRecordsetPtr("EmulsionGeneral", versionTag, versionNode, "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionGeneral Fetched" << endmsg;
+
+  m_emulsionFilm = rdbSvc->getRecordsetPtr("EmulsionFilm", versionTag, versionNode, "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionFilm Fetched" << endmsg;
+
+  m_emulsionPlates = rdbSvc->getRecordsetPtr("EmulsionPlates", versionTag, versionNode, "FASERDD");
+  msg(MSG::DEBUG) << "Table EmulsionPlates Fetched" << endmsg;
+
+}
+
+const EmulsionGeoModelAthenaComps* EmulsionDataBase::athenaComps() const { return m_athenaComps; }
+
+IRDBRecordset_ptr EmulsionDataBase::weightTable() const {return m_weightTable;}
+
+IRDBRecordset_ptr EmulsionDataBase::scalingTable() const {return m_scalingTable;}
+
+// //const IRDBRecord* EmulsionDataBase::atls() const {return *m_atls)[0];}  
+IRDBRecordset_ptr EmulsionDataBase::topLevelTable() const {return m_topLevel;}
+
+// IRDBRecordset_ptr EmulsionDataBase::conditionsTable() const {return m_conditions;}
+// const IRDBRecord* EmulsionDataBase::conditions() const {return (*m_conditions)[0];}
+
+const IRDBRecord* EmulsionDataBase::emulsionGeneral() const {return (*m_emulsionGeneral)[0];}
+const IRDBRecord* EmulsionDataBase::emulsionFilm() const {return (*m_emulsionFilm)[0];}
+const IRDBRecord* EmulsionDataBase::emulsionPlates() const {return (*m_emulsionPlates)[0];}
+
+const std::string & EmulsionDataBase::versionTag() const {
+  return m_emulsionVersionTag;
+}
+
+MsgStream&  EmulsionDataBase::msg (MSG::Level lvl) const 
+{ 
+  return m_athenaComps->msg(lvl); 
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..35bf120c7a04cfe5ecaa88effd524785642271a2
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionDataBase_H
+#define EmulsionGeoModel_EmulsionDataBase_H
+
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h"
+#include <string>
+
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+class IRDBRecord;
+
+
+class EmulsionDataBase
+{
+
+  
+public:
+
+  EmulsionDataBase(const EmulsionGeoModelAthenaComps* athenaComps);
+
+  const EmulsionGeoModelAthenaComps* athenaComps() const;
+
+  IRDBRecordset_ptr weightTable() const;
+  IRDBRecordset_ptr scalingTable() const;
+  IRDBRecordset_ptr topLevelTable() const;
+
+  const IRDBRecord* emulsionGeneral() const;
+  const IRDBRecord* emulsionFilm() const;
+  const IRDBRecord* emulsionPlates() const;
+
+  // Return the Emulsion version tag.
+  const std::string & versionTag() const;
+
+  MsgStream& msg (MSG::Level lvl) const;
+
+private:
+  
+  EmulsionDataBase(const EmulsionDataBase &);
+  EmulsionDataBase& operator= (const EmulsionDataBase &);
+
+private:
+
+  const EmulsionGeoModelAthenaComps* m_athenaComps;
+
+  std::string m_emulsionVersionTag;
+
+  IRDBRecordset_ptr m_weightTable;
+  IRDBRecordset_ptr m_scalingTable;
+  IRDBRecordset_ptr m_topLevel;
+  IRDBRecordset_ptr m_conditions;
+
+  IRDBRecordset_ptr m_emulsionGeneral;
+  IRDBRecordset_ptr m_emulsionFilm;
+  IRDBRecordset_ptr m_emulsionPlates;
+
+
+};
+
+#endif //EmulsionGeoModel_EmulsionDataBase_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..25fc89125f7974ef00f89ae2899a67a7b68d2551
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx
@@ -0,0 +1,229 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+//
+// EmulsionDetectorFactory: This is the top level node 
+//
+
+
+#include "EmulsionDetectorFactory.h" 
+
+#include "EmulsionDataBase.h"
+#include "EmulsionIdentifier.h"
+#include "EmulsionGeometryManager.h" 
+#include "EmulsionMaterialManager.h"
+#include "EmulsionGeneralParameters.h"
+#include "NeutrinoReadoutGeometry/Version.h" 
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h" 
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h" 
+
+#include "EmulsionBase.h"
+#include "EmulsionPlates.h"
+#include "EmulsionDataBase.h"
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h"
+
+//
+// GeoModel include files:
+//
+#include "GeoModelKernel/GeoMaterial.h"  
+#include "GeoModelKernel/GeoTube.h"  
+#include "GeoModelKernel/GeoLogVol.h"  
+#include "GeoModelKernel/GeoNameTag.h"  
+#include "GeoModelKernel/GeoIdentifierTag.h"  
+#include "GeoModelKernel/GeoPhysVol.h"  
+#include "GeoModelKernel/GeoVPhysVol.h"  
+#include "GeoModelKernel/GeoTransform.h"  
+#include "GeoModelKernel/GeoAlignableTransform.h"  
+#include "GeoModelKernel/GeoShape.h"
+#include "GeoModelKernel/GeoShapeUnion.h"
+#include "GeoModelKernel/GeoShapeShift.h"
+#include "GeoModelInterfaces/StoredMaterialManager.h"
+#include "GeoModelInterfaces/IGeoDbTagSvc.h"
+#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h"
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "DetDescrConditions/AlignableTransformContainer.h"
+#
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/ISvcLocator.h"
+
+#include "GeoModelKernel/GeoDefinitions.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+
+
+#include <iostream> 
+#include <iomanip> 
+#include <string>
+ 
+using NeutrinoDD::EmulsionDetectorManager; 
+using NeutrinoDD::NeutrinoCommonItems; 
+
+EmulsionDetectorFactory::EmulsionDetectorFactory(const EmulsionGeoModelAthenaComps * athenaComps,
+					                     const EmulsionOptions & options)
+  : NeutrinoDD::DetectorFactoryBase(athenaComps),
+    m_useDynamicAlignFolders(false)
+{ 
+  
+  // Create the detector manager
+  m_detectorManager = new EmulsionDetectorManager(detStore());
+  msg(MSG::DEBUG) << "Created EmulsionDetectorManager" << endmsg;
+
+  // Create the database
+  m_db = new EmulsionDataBase{athenaComps};
+  msg(MSG::DEBUG) << "Created EmulsionDataBase" << endmsg;
+
+  // Create the material manager
+  m_materials = new EmulsionMaterialManager{m_db};
+  msg(MSG::DEBUG) << "Created EmulsionMaterialManager" << endmsg;
+
+  // Create the geometry manager.
+  m_geometryManager = new EmulsionGeometryManager{m_db};
+  msg(MSG::DEBUG) << "Created EmulsionGeometryManager" << endmsg;
+  m_geometryManager->setOptions(options);
+  msg(MSG::DEBUG) << "Set options on EmulsionGeometryManager" << endmsg;
+
+  m_useDynamicAlignFolders = options.dynamicAlignFolders();
+ 
+  // Set Version information
+  // Get the geometry tag
+  DecodeFaserVersionKey versionKey(geoDbTagSvc(),"Emulsion");
+  IRDBRecordset_ptr switchSet
+    = rdbAccessSvc()->getRecordsetPtr("EmulsionSwitches", versionKey.tag(), versionKey.node(),"FASERDD");
+  const IRDBRecord    *switches   = (*switchSet)[0];
+  msg(MSG::DEBUG) << "Retrieved EmulsionSwitches" << endmsg;
+
+  std::string layout = "Final";
+  std::string description;
+  if (!switches->isFieldNull("LAYOUT")) {
+    layout = switches->getString("LAYOUT");
+  }
+  if (!switches->isFieldNull("DESCRIPTION")) {
+    description = switches->getString("DESCRIPTION");
+  }
+
+  std::string versionTag = rdbAccessSvc()->getChildTag("Emulsion", versionKey.tag(), versionKey.node(),"FASERDD");
+  std::string versionName = switches->getString("VERSIONNAME");
+  int versionMajorNumber = 1;
+  int versionMinorNumber = 0;
+  int versionPatchNumber = 0;
+  NeutrinoDD::Version version(versionTag,
+                           versionName, 
+                           layout, 
+                           description, 
+                           versionMajorNumber,
+                           versionMinorNumber,
+                           versionPatchNumber);
+  m_detectorManager->setVersion(version);
+} 
+ 
+ 
+EmulsionDetectorFactory::~EmulsionDetectorFactory() 
+{ 
+  // NB the detector manager (m_detectorManager)is stored in the detector store by the
+  // Tool and so we don't delete it.
+  delete m_db;
+  delete m_materials;
+  delete m_geometryManager;
+} 
+
+void EmulsionDetectorFactory::create(GeoPhysVol *world) 
+{ 
+
+  msg(MSG::INFO) << "Building Emulsion Detector." << endmsg;
+  msg(MSG::INFO) << " " << m_detectorManager->getVersion().fullDescription() << endmsg;
+
+  // Change precision.
+  int oldPrecision = std::cout.precision(6);
+
+  // The tree tops get added to world. We name it "neutrino" though.
+  GeoPhysVol *neutrino = world;
+
+  const EmulsionGeneralParameters * emulsionGeneral = m_geometryManager->generalParameters();
+
+  GeoTrf::Transform3D emulsionTransform = emulsionGeneral->partTransform("Emulsion");
+
+    std::string stationA_Label = "StationA";
+
+    bool stationA_Present = emulsionGeneral->partPresent(stationA_Label);
+
+  //
+  //  Plate is the same for all stations
+  //
+  // EmulsionBase base("Base", m_detectorManager, m_geometryManager, m_materials);
+  // msg(MSG::DEBUG) << "Created Emulsion base with dimensions (" << base.width() << "," << base.height() << "," << base.thickness() << ")" << endmsg;
+  //
+  // Station A
+  //
+  if (stationA_Present)
+  {
+    msg(MSG::DEBUG) << "Building the Emulsion Station A." << endmsg;
+
+    // // Create the station
+    EmulsionPlates stationA("EmulsionStationA", m_detectorManager, m_geometryManager, m_materials);
+    EmulsionIdentifier id{m_geometryManager->athenaComps()->getIdHelper()};
+
+    GeoVPhysVol* stationA_PV = stationA.build(id);
+    GeoAlignableTransform* stationA_Transform = new GeoAlignableTransform(emulsionTransform * emulsionGeneral->partTransform(stationA_Label));
+
+    GeoNameTag* topLevelNameTag = new GeoNameTag("Emulsion");
+    neutrino->add(topLevelNameTag);
+    neutrino->add(new GeoIdentifierTag(0));
+    neutrino->add(stationA_Transform);
+    neutrino->add(stationA_PV);
+    m_detectorManager->addTreeTop(stationA_PV);
+
+    // // Store alignable transform for station (level = 1)
+    m_detectorManager->addAlignableTransform(2, id.getFilmId(), stationA_Transform, stationA_PV);
+  }
+
+  // Set the neighbours
+  m_detectorManager->initNeighbours();
+
+  // Set number of pmts in numerology.
+  // const NeutrinoDD::NeutrinoDetectorDesign* design = m_detectorManager->getEmulsionDesign();
+  // if (design != nullptr)
+  // {
+  //   m_detectorManager->numerology().setNumFilmsPerBase(m_detectorManager->getEmulsionDesign()->cells());
+  // }
+  // else
+  // {
+  //   m_detectorManager->numerology().setNumPmtsPerPlate(0);
+  // }
+  
+
+  // Register the keys and the level corresponding to the key
+  // and whether it expects a global or local shift.
+  // level 0: sensor, level 1: module, level 2, layer/disc, level 3: whole barrel/enccap
+
+
+  if (!m_useDynamicAlignFolders){
+
+    m_detectorManager->addAlignFolderType(NeutrinoDD::static_run1);
+    // m_detectorManager->addFolder("/Neutrino/Align");
+  }
+  else {
+    m_detectorManager->addAlignFolderType(NeutrinoDD::timedependent_run2);
+    // m_detectorManager->addGlobalFolder("/Neutrino/AlignL1/Neutrino");
+    // m_detectorManager->addGlobalFolder("/Neutrino/AlignL2/Emulsion");
+    // m_detectorManager->addChannel("/Neutrino/AlignL1/Neutrino",3,NeutrinoDD::global);
+    // m_detectorManager->addChannel("/Neutrino/AlignL2/Emulsion",2,NeutrinoDD::global);
+    // m_detectorManager->addFolder("/Neutrino/AlignL3");
+  }
+
+  // Return precision to its original value
+  std::cout.precision(oldPrecision);
+
+} 
+ 
+
+const EmulsionDetectorManager * EmulsionDetectorFactory::getDetectorManager() const
+{
+  return m_detectorManager;
+}
+ 
+
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b53eadd21145a6b7817a7f860d40adae9a7ee4a
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOGEOMODEL_NEUTRINODETECTORFACTORY_H 
+#define NEUTRINOGEOMODEL_NEUTRINODETECTORFACTORY_H 
+ 
+#include "NeutrinoGeoModelUtils/DetectorFactoryBase.h" 
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+
+class GeoPhysVol;
+class EmulsionDataBase;
+class EmulsionGeometryManager;
+class EmulsionGeoModelAthenaComps;
+class EmulsionMaterialManager;
+class EmulsionOptions;
+
+class EmulsionDetectorFactory : public NeutrinoDD::DetectorFactoryBase  
+{ 
+  
+ public: 
+  // Constructor
+  EmulsionDetectorFactory(const EmulsionGeoModelAthenaComps * athenaComps, 
+		              const EmulsionOptions & options); 
+
+  // Destructor
+  virtual ~EmulsionDetectorFactory(); 
+
+  // Creation of geometry:
+  virtual void create(GeoPhysVol *world);   
+
+  // Access to the results: 
+  virtual const NeutrinoDD::EmulsionDetectorManager * getDetectorManager() const; 
+
+ private: 
+  // Copy and assignments operations illegal and so are made private
+  EmulsionDetectorFactory(const EmulsionDetectorFactory &right); 
+  const EmulsionDetectorFactory & operator=(const EmulsionDetectorFactory &right); 
+
+  NeutrinoDD::EmulsionDetectorManager *m_detectorManager;
+  EmulsionGeometryManager *m_geometryManager;
+  EmulsionDataBase* m_db;
+  EmulsionMaterialManager* m_materials;
+  bool m_useDynamicAlignFolders;
+
+}; 
+ 
+#endif 
+ 
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorTool.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ed7015b1f6734f3f5be7ba60b4594ea830896ea6
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorTool.cxx
@@ -0,0 +1,249 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionGeoModel/EmulsionDetectorTool.h"
+
+#include "EmulsionDetectorFactory.h" 
+#include "EmulsionDataBase.h" 
+// #include "EmulsionMaterialManager.h" 
+#include "EmulsionOptions.h" 
+
+// temporary
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h" 
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "DetDescrConditions/AlignableTransformContainer.h"
+
+#include "GeoModelFaserUtilities/GeoModelExperiment.h"
+#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h"
+#include "StoreGate/DataHandle.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+
+#include "AthenaKernel/ClassID_traits.h"
+#include "SGTools/DataProxy.h"
+
+using NeutrinoDD::EmulsionDetectorManager;
+using NeutrinoDD::NeutrinoDetectorManager;
+
+//
+// Constructor
+//
+EmulsionDetectorTool::EmulsionDetectorTool(const std::string& type,
+                                   const std::string& name, 
+                                   const IInterface* parent)
+  : GeoModelTool(type, name, parent),
+  m_cosmic{false},
+  m_manager{nullptr},
+  m_athenaComps{ },
+  m_geoDbTagSvc{"GeoDbTagSvc", name},
+  m_rdbAccessSvc{"RDBAccessSvc", name},
+  m_geometryDBSvc{"NeutrinoGeometryDBSvc", name}
+{
+  // Get parameter values from jobOptions file
+  declareProperty("GeoDbTagSvc", m_geoDbTagSvc);
+  declareProperty("RDBAccessSvc", m_rdbAccessSvc);
+  declareProperty("GeometryDBSvc", m_geometryDBSvc);
+}
+
+//
+// Create the Geometry via the factory corresponding to this tool
+//
+
+StatusCode
+EmulsionDetectorTool::create()
+{ 
+  // Get the detector configuration.
+  ATH_CHECK(m_geoDbTagSvc.retrieve());
+  
+  DecodeFaserVersionKey versionKey{&*m_geoDbTagSvc, "Emulsion"};
+  // Issue error if AUTO.
+  if (versionKey.tag() == "AUTO") {
+    ATH_MSG_ERROR("AUTO Faser version. Please select a version.");
+  }
+  ATH_MSG_INFO("Building Emulsion with Version Tag: " << versionKey.tag() << " at Node: " << versionKey.node());
+
+  ATH_CHECK(m_rdbAccessSvc.retrieve());
+  // Print the Emulsion version tag:
+  std::string emulsionVersionTag{m_rdbAccessSvc->getChildTag("Emulsion", versionKey.tag(), versionKey.node(), "FASERDD")};
+  ATH_MSG_INFO("Emulsion Version: " << emulsionVersionTag <<  "  Package Version: " << PACKAGE_VERSION);
+  // Check if version is empty. If so, then the Emulsion cannot be built. This may or may not be intentional. We
+  // just issue an INFO message. 
+  if (emulsionVersionTag.empty()) {
+    ATH_MSG_INFO("No Emulsion Version. Emulsion will not be built.");
+  } else {
+    std::string versionName;
+    if (versionKey.custom()) {
+      ATH_MSG_WARNING("EmulsionDetectorTool:  Detector Information coming from a custom configuration!!");
+    } else {
+      ATH_MSG_DEBUG("EmulsionDetectorTool:  Detector Information coming from the database and job options IGNORED.");
+      ATH_MSG_DEBUG("Keys for Emulsion Switches are "  << versionKey.tag()  << "  " << versionKey.node());
+
+      IRDBRecordset_ptr switchSet{m_rdbAccessSvc->getRecordsetPtr("EmulsionSwitches", versionKey.tag(), versionKey.node(), "FASERDD")};
+      const IRDBRecord* switches{(*switchSet)[0]};
+      m_detectorName.setValue(switches->getString("DETECTORNAME"));
+
+      if (not switches->isFieldNull("COSMICLAYOUT")) 
+      {
+        m_cosmic = switches->getInt("COSMICLAYOUT");
+      }
+      if (not switches->isFieldNull("VERSIONNAME")) 
+      {
+        versionName = switches->getString("VERSIONNAME");
+      } 
+    }
+
+    ATH_MSG_DEBUG("Creating the Emulsion");
+    ATH_MSG_DEBUG("Emulsion Geometry Options: ");
+    ATH_MSG_DEBUG(" Alignable:             " << (m_alignable.value() ? "true" : "false"));
+    ATH_MSG_DEBUG(" CosmicLayout:          " << (m_cosmic ? "true" : "false"));
+    ATH_MSG_DEBUG(" VersionName:           " << versionName);
+
+    EmulsionOptions options;
+    options.setAlignable(m_alignable.value());
+    options.setDynamicAlignFolders(m_useDynamicAlignFolders.value());
+    m_manager = nullptr;
+
+    // 
+    // Locate the top level experiment node 
+    // 
+    GeoModelExperiment* theExpt{nullptr};
+    ATH_CHECK(detStore()->retrieve(theExpt, "FASER"));
+      
+    // Retrieve the Geometry DB Interface
+    ATH_CHECK(m_geometryDBSvc.retrieve());
+
+    // Pass athena services to factory, etc
+    m_athenaComps.setDetStore(detStore().operator->());
+    m_athenaComps.setGeoDbTagSvc(&*m_geoDbTagSvc);
+    m_athenaComps.setGeometryDBSvc(&*m_geometryDBSvc);
+    m_athenaComps.setRDBAccessSvc(&*m_rdbAccessSvc);
+    const EmulsionID* idHelper{nullptr};
+    ATH_CHECK(detStore()->retrieve(idHelper, "EmulsionID"));
+    m_athenaComps.setIdHelper(idHelper);
+    idHelper->test_base_packing();
+    //
+    // This strange way of casting is to avoid an
+    // utterly brain damaged compiler warning.
+    //
+    GeoPhysVol* world{&*theExpt->getPhysVol()};
+    if (world != nullptr) ATH_MSG_INFO("Retrieved World PhysVol");
+
+    EmulsionDetectorFactory theEmulsion{&m_athenaComps, options};
+    ATH_MSG_INFO("Created instance of detector factory");
+    theEmulsion.create(world);
+    ATH_MSG_INFO("Called create method on factory");
+    m_manager = theEmulsion.getDetectorManager();
+    ATH_MSG_INFO("Attempted to retrieve detector manager");
+
+    if (m_manager==nullptr) {
+      ATH_MSG_FATAL("EmulsionDetectorManager not created");
+      return StatusCode::FAILURE;
+    }
+      
+    // Get the manager from the factory and store it in the detector store.
+    //   m_detector is non constant so I can not set it to a const pointer.
+    //   m_detector = theSCT.getDetectorManager();
+      
+    ATH_MSG_DEBUG("Registering EmulsionDetectorManager. ");
+    ATH_CHECK(detStore()->record(m_manager, m_manager->getName()));
+    theExpt->addManager(m_manager);
+    
+    // Create a symLink to the NeutrinoDetectorManager base class
+    const NeutrinoDetectorManager* neutrinoDetManager{m_manager};
+    ATH_CHECK(detStore()->symLink(m_manager, neutrinoDetManager));
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+EmulsionDetectorTool::clear()
+{
+  ATH_MSG_WARNING("Called untested EmulsionDetectorTool::clear()");
+  SG::DataProxy* proxy{detStore()->proxy(ClassID_traits<EmulsionDetectorManager>::ID(), m_manager->getName())};
+  if (proxy) {
+    proxy->reset();
+    m_manager = nullptr;
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode 
+EmulsionDetectorTool::registerCallback()
+{
+  StatusCode sc{StatusCode::FAILURE, true};
+  if (m_alignable.value()) {
+      ATH_MSG_WARNING("Called untested EmulsionDetectorTool::registerCallback()");
+    if (m_useDynamicAlignFolders.value()) {
+
+      if (detStore()->contains<CondAttrListCollection>(m_run2L1Folder.value())) {
+        ATH_MSG_DEBUG("Registering callback on global Container with folder " << m_run2L1Folder.value());
+        const DataHandle<CondAttrListCollection> calc;
+        ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), calc, m_run2L1Folder.value()));
+        sc = StatusCode::SUCCESS;
+      } else {
+        ATH_MSG_WARNING("Unable to register callback on global Container with folder " << m_run2L1Folder.value());
+        return StatusCode::FAILURE;
+      }
+    
+      if (detStore()->contains<CondAttrListCollection>(m_run2L2Folder.value())) {
+        ATH_MSG_DEBUG("Registering callback on global Container with folder " << m_run2L2Folder.value());
+        const DataHandle<CondAttrListCollection> calc;
+        ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), calc, m_run2L2Folder.value()));
+        sc = StatusCode::SUCCESS;
+      } else {
+        ATH_MSG_WARNING("Unable to register callback on global Container with folder " << m_run2L2Folder.value());
+        return StatusCode::FAILURE;
+      }
+    
+      if (detStore()->contains<AlignableTransformContainer>(m_run2L3Folder.value())) {
+        ATH_MSG_DEBUG("Registering callback on AlignableTransformContainer with folder " << m_run2L3Folder.value());
+        const DataHandle<AlignableTransformContainer> atc;
+        ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), atc, m_run2L3Folder.value()));
+        sc = StatusCode::SUCCESS;
+      } else {
+        ATH_MSG_WARNING("Unable to register callback on AlignableTransformContainer with folder " << m_run2L3Folder.value());
+        return StatusCode::FAILURE;
+      }
+     
+    } else {
+    
+      if (detStore()->contains<AlignableTransformContainer>(m_run1Folder.value())) {
+        ATH_MSG_DEBUG("Registering callback on AlignableTransformContainer with folder " << m_run1Folder.value());
+        const DataHandle<AlignableTransformContainer> atc;
+        ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), atc, m_run1Folder.value()));
+        sc = StatusCode::SUCCESS;
+      } else {
+        ATH_MSG_WARNING("Unable to register callback on AlignableTransformContainer with folder "
+                        << m_run1Folder.value() << ", Alignment disabled (only if no Run2 scheme is loaded)!");
+        return StatusCode::FAILURE;
+      }
+    }
+  } else {
+    ATH_MSG_INFO("Alignment disabled. No callback registered");
+    // We return failure otherwise it will try and register
+    // a GeoModelSvc callback associated with this callback. 
+    return StatusCode::FAILURE;
+  }
+  return sc;
+}
+  
+StatusCode 
+EmulsionDetectorTool::align(IOVSVC_CALLBACK_ARGS_P(I, keys))
+{
+  ATH_MSG_WARNING("Called untested EmulsionDetectorTool::align()");
+  void* i = &I;
+  void* k = &keys;
+  if (i == nullptr && k == nullptr) return StatusCode::SUCCESS; // suppress stupid warning
+  if (m_manager==nullptr) { 
+    ATH_MSG_FATAL("Manager does not exist");
+    return StatusCode::FAILURE;
+  }    
+  if (m_alignable.value()) {
+    return m_manager->align(I, keys);
+  } else {
+    ATH_MSG_DEBUG("Alignment disabled. No alignments applied");
+    return StatusCode::SUCCESS;
+  }
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e6c24e2b7579ee6fa983cfc68c98e79aca36a315
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.cxx
@@ -0,0 +1,98 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionFilm.h"
+
+#include "EmulsionGeometryManager.h"
+#include "EmulsionMaterialManager.h"
+
+#include "EmulsionFilmParameters.h"
+
+#include "GeoModelKernel/GeoBox.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoMaterial.h"
+
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+#include "GaudiKernel/SystemOfUnits.h"
+
+using namespace NeutrinoDD;
+
+EmulsionFilm::EmulsionFilm(const std::string & name,
+                     NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                     const EmulsionGeometryManager* geometryManager,
+                     EmulsionMaterialManager* materials)
+  : EmulsionUniqueComponentFactory(name, detectorManager, geometryManager, materials),
+    m_noElementWarning{true}
+{
+  getParameters();
+  m_logVolume = preBuild();
+}
+
+
+void
+EmulsionFilm::getParameters()
+{
+  const EmulsionFilmParameters * parameters = m_geometryManager->filmParameters();
+  m_material  = m_materials->getMaterial(parameters->filmMaterial());
+  m_thickness = parameters->filmThickness();
+  m_height    = parameters->filmHeight();
+  m_width     = parameters->filmWidth();
+}
+
+const GeoLogVol * 
+EmulsionFilm::preBuild()
+{
+  // Simple box
+  const GeoBox* filmShape = new GeoBox(0.5*m_width, 0.5*m_height, 0.5*m_thickness);
+
+  GeoLogVol * filmLog = new GeoLogVol(getName(), filmShape, m_material);
+  makeDesign();
+  return filmLog;
+}
+
+void
+EmulsionFilm::makeDesign()
+{
+    m_design = new NeutrinoDetectorDesign( m_width, m_height, m_thickness );
+}
+
+
+
+GeoVPhysVol * 
+EmulsionFilm::build(EmulsionIdentifier id)
+{
+  GeoFullPhysVol * film = new GeoFullPhysVol(m_logVolume); 
+  
+  // Make detector element and add to collection
+  // Only do so if we have a valid id helper.
+
+  //id.print(); // for debugging only
+
+  const NeutrinoCommonItems* commonItems =  m_geometryManager->commonItems();
+
+  if (commonItems->getIdHelper()) {
+
+    NeutrinoDetectorElement * detElement;
+
+    detElement =  new NeutrinoDetectorElement(id.getFilmId(), 
+                                              m_design, 
+                                              film,  
+                                              commonItems);
+    // Add the detector element.
+    m_detectorManager->addDetectorElement(detElement);
+
+  } else {
+    if (m_noElementWarning) {
+      std::cout << "WARNING!!!!: No Emulsion id helper and so no elements being produced." << std::endl;
+      m_noElementWarning = false;
+    }
+  }
+  return film;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3f25ccd27e02277dda881bfef1352319678e531
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilm.h
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONFILM_H
+#define EMULSIONGEOMODEL_EMULSIONFILM_H
+
+#include "EmulsionComponentFactory.h"
+
+#include <atomic>
+#include <string>
+
+class GeoMaterial;
+class GeoVPhysVol;
+namespace NeutrinoDD{class NeutrinoDetectorDesign;}
+
+class EmulsionFilm: public EmulsionUniqueComponentFactory
+{
+public:
+  EmulsionFilm(const std::string & name,
+             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+             const EmulsionGeometryManager* geometryManager,
+             EmulsionMaterialManager* materials);
+
+public:
+  const GeoMaterial * material() const {return m_material;} 
+  double thickness() const {return m_thickness;}
+  double width()     const {return m_width;}
+  double height()    const {return m_height;}
+
+  virtual GeoVPhysVol * build(EmulsionIdentifier id);
+  
+private:
+  void getParameters();
+  virtual const GeoLogVol * preBuild();
+  void makeDesign();
+ 
+  const GeoMaterial * m_material;
+  double m_thickness;
+  double m_width;
+  double m_height;
+  
+  NeutrinoDD::NeutrinoDetectorDesign* m_design;
+
+  mutable std::atomic_bool m_noElementWarning;
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONFILM_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0a1eef8ff95793a6f9dcf3297b2bd59cce335887
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.cxx
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionFilmParameters.h"
+#include "EmulsionGeometryManager.h"
+
+#include "EmulsionDataBase.h"
+
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include <cmath>
+
+
+EmulsionFilmParameters::EmulsionFilmParameters(EmulsionDataBase* rdb)
+{
+  m_rdb = rdb;
+}
+
+double 
+EmulsionFilmParameters::baseWidth() const
+{
+  return m_rdb->emulsionFilm()->getDouble("BASEDX") * Gaudi::Units::mm; 
+}
+
+double 
+EmulsionFilmParameters::baseHeight() const
+{
+  return m_rdb->emulsionFilm()->getDouble("BASEDY") * Gaudi::Units::mm; 
+}
+
+double 
+EmulsionFilmParameters::baseThickness() const
+{
+  return m_rdb->emulsionFilm()->getDouble("BASEDZ") * Gaudi::Units::mm; 
+}
+
+std::string EmulsionFilmParameters::baseMaterial() const
+{
+  return m_rdb->emulsionFilm()->getString("BASEMAT");
+}
+
+double 
+EmulsionFilmParameters::filmWidth() const
+{
+  return m_rdb->emulsionFilm()->getDouble("FILMDX") * Gaudi::Units::mm; 
+}
+
+double 
+EmulsionFilmParameters::filmHeight() const
+{
+  return m_rdb->emulsionFilm()->getDouble("FILMDY") * Gaudi::Units::mm; 
+}
+
+double 
+EmulsionFilmParameters::filmThickness() const
+{
+  return m_rdb->emulsionFilm()->getDouble("FILMDZ") * Gaudi::Units::mm; 
+}
+
+std::string EmulsionFilmParameters::filmMaterial() const
+{
+  return m_rdb->emulsionFilm()->getString("FILMMAT");
+}
+
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..a85ec246c820c36e5bbb9e4179ed453e77bad2cd
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionFilmParameters.h
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionFilmParameters_H
+#define EmulsionGeoModel_EmulsionFilmParameters_H
+
+#include <string>
+
+class EmulsionDataBase;
+
+class EmulsionFilmParameters {
+
+public:
+
+  // Constructor 
+  EmulsionFilmParameters(EmulsionDataBase* rdb);
+
+  double baseThickness() const;
+  double baseWidth() const;
+  double baseHeight() const;
+  double filmThickness() const;
+  double filmWidth() const;
+  double filmHeight() const;
+
+  std::string baseMaterial() const;
+  std::string filmMaterial() const;
+
+ private:
+  EmulsionDataBase * m_rdb;
+
+};
+
+
+#endif // EmulsionGeoModel_EmulsionFilmParameters_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d96379535d9415a145326a459439a45427e3b86d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.cxx
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionGeneralParameters.h"
+#include "EmulsionDataBase.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+#include "NeutrinoGeoModelUtils/TopLevelPlacements.h"
+
+const double EmulsionSAFETY = 0.01 * Gaudi::Units::mm; // Used in some places to make envelopes slightly larger to ensure
+                                     // no overlaps due to rounding errors.
+
+
+EmulsionGeneralParameters::EmulsionGeneralParameters(EmulsionDataBase* rdb)
+{
+  m_rdb = rdb;
+  m_placements = new TopLevelPlacements(m_rdb->topLevelTable());
+}
+
+
+EmulsionGeneralParameters::~EmulsionGeneralParameters()
+{
+  delete m_placements;
+}
+
+
+const GeoTrf::Transform3D & 
+EmulsionGeneralParameters::partTransform(const std::string & partName) const 
+{
+  return m_placements->transform(partName);
+}
+
+
+bool 
+EmulsionGeneralParameters::partPresent(const std::string & partName) const
+{
+  return m_placements->present(partName);
+}
+
+//
+// General
+//
+double 
+EmulsionGeneralParameters::safety() const
+{
+  return EmulsionSAFETY;
+}
+
+int
+EmulsionGeneralParameters::nModules() const
+{
+  return m_rdb->emulsionGeneral()->getInt("NMODULES");
+}
+
+int
+EmulsionGeneralParameters::nBasesPerModule() const
+{
+  return m_rdb->emulsionGeneral()->getInt("NBASEPERMOD");
+}
+
+double
+EmulsionGeneralParameters::firstBaseZ() const
+{
+  return m_rdb->emulsionGeneral()->getDouble("FIRSTBASEZ") * Gaudi::Units::mm;
+}
+
+double
+EmulsionGeneralParameters::lastBaseZ() const
+{
+  return m_rdb->emulsionGeneral()->getDouble("LASTBASEZ") * Gaudi::Units::mm;
+}
+
+// Default Conditions. Values should be come form conditions data base. These values provide
+// default vlaues if nothing from the conditions database is provided.
+
+
+// double 
+// EmulsionGeneralParameters::temperature() const
+// {
+//   if (m_rdb->conditionsTable()->size() == 0) {
+//     return 266.15 * Gaudi::Units::kelvin; // -7 C
+//   }
+//   return (m_rdb->conditions()->getDouble("TEMPERATURE") + 273.15) * Gaudi::Units::kelvin;
+// }
+
+
+// double 
+// SCT_GeneralParameters::biasVoltage() const
+// {
+//   if (m_rdb->conditionsTable()->size() == 0) {
+//     return 100 * Gaudi::Units::volt;
+//   }
+//   return m_rdb->conditions()->getDouble("BIASVOLT") * Gaudi::Units::volt;
+// }
+
+// double 
+// SCT_GeneralParameters::depletionVoltage() const
+// {
+//   if (m_rdb->conditionsTable()->size() == 0) {
+//     return 20 * Gaudi::Units::volt;
+//   }
+//   return m_rdb->conditions()->getDouble("DEPLETIONVOLT") * Gaudi::Units::volt;
+// }
+
+
+
+  
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..65d618ce65d68759588489006a0eb7be05679bff
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeneralParameters.h
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionGeneralParameters_H
+#define EmulsionGeoModel_EmulsionGeneralParameters_H
+
+#include "GeoModelKernel/GeoDefinitions.h"
+
+#include <map>
+#include <string>
+
+class EmulsionDataBase;
+class TopLevelPlacements;
+
+class EmulsionGeneralParameters {
+
+public:
+
+  EmulsionGeneralParameters(EmulsionDataBase* rdb);
+  ~EmulsionGeneralParameters();
+  //Explicitly disallow copy, assignment to appease coverity
+  EmulsionGeneralParameters(const EmulsionGeneralParameters &) = delete;
+  EmulsionGeneralParameters & operator=(const EmulsionGeneralParameters &) = delete;
+
+  // General
+  double safety() const;
+
+  const GeoTrf::Transform3D & partTransform(const std::string & partName) const; 
+  bool partPresent(const std::string & partName) const;
+
+  int nModules() const;
+  int nBasesPerModule() const;
+  double firstBaseZ() const;
+  double lastBaseZ() const;
+  
+private:
+
+  EmulsionDataBase * m_rdb;
+  TopLevelPlacements * m_placements;
+};
+
+
+#endif // EmulsionGeoModel_EmulsionGeneralParameters_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeoModelAthenaComps.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeoModelAthenaComps.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f6bf50fd79a9ccae19e645aa574b53374bf1ea38
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeoModelAthenaComps.cxx
@@ -0,0 +1,23 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h"
+
+EmulsionGeoModelAthenaComps::EmulsionGeoModelAthenaComps()
+  : NeutrinoDD::AthenaComps("EmulsionGeoModel"),
+    m_idHelper(0)
+{}
+ 
+void 
+EmulsionGeoModelAthenaComps::setIdHelper(const EmulsionID* idHelper)
+{
+  m_idHelper = idHelper;
+}
+
+const EmulsionID* 
+EmulsionGeoModelAthenaComps::getIdHelper() const
+{
+  return m_idHelper;
+}
+
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..679678fba793dddd06cb3b2e13169f57a08a1b0d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionGeometryManager.h"
+
+#include "NeutrinoGeoModelUtils/DistortedMaterialManager.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+#include "EmulsionFilmParameters.h"
+#include "EmulsionPlatesParameters.h"
+#include "EmulsionDataBase.h"
+#include "EmulsionGeneralParameters.h"
+#include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h"
+
+EmulsionGeometryManager::EmulsionGeometryManager(EmulsionDataBase* rdb)
+  : m_athenaComps{rdb->athenaComps()},
+    m_rdb{rdb}
+{
+  // This class uses reference counting. Should not be delete'd in destructor.
+  m_commonItems = new NeutrinoDD::NeutrinoCommonItems(m_athenaComps->getIdHelper());
+
+  m_filmParameters = std::make_unique<EmulsionFilmParameters>(m_rdb);
+  m_platesParameters = std::make_unique<EmulsionPlatesParameters>(m_rdb);
+  m_generalParameters = std::make_unique<EmulsionGeneralParameters>(m_rdb);
+  m_distortedMatManager = std::make_unique<NeutrinoDD::DistortedMaterialManager>();
+}
+
+EmulsionGeometryManager::~EmulsionGeometryManager()
+{
+}
+
+//
+// Access to run time options.
+//
+const EmulsionOptions & 
+EmulsionGeometryManager::options() const
+{
+  return m_options;
+}
+
+void
+EmulsionGeometryManager::setOptions(const EmulsionOptions & options)
+{
+  m_options = options;
+}
+
+const EmulsionGeoModelAthenaComps *
+EmulsionGeometryManager::athenaComps() const 
+{
+  return m_athenaComps;
+}
+  
+//
+// NeutrinoCommonItems which are passed to NeutrinoDetectorElements.
+//
+
+const NeutrinoDD::NeutrinoCommonItems *
+EmulsionGeometryManager::commonItems() const
+{
+  return m_commonItems;
+}
+
+const EmulsionFilmParameters * 
+EmulsionGeometryManager::filmParameters() const
+{    
+  return m_filmParameters.get();
+}
+
+const EmulsionPlatesParameters * 
+EmulsionGeometryManager::platesParameters() const
+{    
+  return m_platesParameters.get();
+}
+
+const EmulsionGeneralParameters * 
+EmulsionGeometryManager::generalParameters() const
+{    
+  return m_generalParameters.get();
+}
+
+const NeutrinoDD::DistortedMaterialManager * 
+EmulsionGeometryManager::distortedMatManager() const
+{    
+  return m_distortedMatManager.get();
+}
+
+EmulsionGeometryManager&
+EmulsionGeometryManager::operator=(const EmulsionGeometryManager& right) {
+  if (this != &right) {
+    m_options = right.m_options;
+    m_athenaComps = right.m_athenaComps;
+    m_commonItems = right.m_commonItems;
+    m_rdb = right.m_rdb;
+    m_filmParameters.reset(new EmulsionFilmParameters(m_rdb));
+    m_platesParameters.reset(new EmulsionPlatesParameters(m_rdb));
+    m_generalParameters.reset(new EmulsionGeneralParameters(m_rdb));
+    m_distortedMatManager.reset(new NeutrinoDD::DistortedMaterialManager());
+  }
+  return *this;
+}
+
+EmulsionGeometryManager::EmulsionGeometryManager(const EmulsionGeometryManager& right) {
+  m_options = right.m_options;
+  m_athenaComps = right.m_athenaComps;
+  m_commonItems = right.m_commonItems;
+  m_rdb = right.m_rdb;
+  m_filmParameters.reset(new EmulsionFilmParameters(m_rdb));
+  m_platesParameters.reset(new EmulsionPlatesParameters(m_rdb));
+  m_generalParameters.reset(new EmulsionGeneralParameters(m_rdb));
+  m_distortedMatManager.reset(new NeutrinoDD::DistortedMaterialManager());
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..a068602e658925ba5a363bd571d0486fa08a04ec
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionGeometryManager_H
+#define EmulsionGeoModel_EmulsionGeometryManager_H
+
+#include "EmulsionOptions.h"
+
+#include <memory>
+
+namespace NeutrinoDD {
+  class NeutrinoCommonItems;
+  class DistortedMaterialManager;
+}
+
+class EmulsionFilmParameters;
+class EmulsionPlatesParameters;
+class EmulsionDataBase;
+class EmulsionGeneralParameters;
+class EmulsionGeoModelAthenaComps;
+
+class EmulsionGeometryManager {
+
+public:
+
+  // Constructor 
+  EmulsionGeometryManager(EmulsionDataBase* rdb);
+
+  // Destructor 
+  ~EmulsionGeometryManager();
+
+  // Access to run time options
+  const EmulsionOptions & options() const;
+  void setOptions(const EmulsionOptions & options);
+
+  // Access to athena components
+  const EmulsionGeoModelAthenaComps * athenaComps() const;
+
+  // To be passed to detector element.
+  const NeutrinoDD::NeutrinoCommonItems * commonItems() const;
+
+  const EmulsionFilmParameters*               filmParameters() const;
+  const EmulsionPlatesParameters*             platesParameters() const;
+  const EmulsionGeneralParameters*            generalParameters() const;
+  const NeutrinoDD::DistortedMaterialManager* distortedMatManager() const;
+
+  EmulsionGeometryManager& operator=(const EmulsionGeometryManager& right);
+  EmulsionGeometryManager(const EmulsionGeometryManager& right);
+
+private:
+
+  EmulsionOptions m_options;
+  const EmulsionGeoModelAthenaComps * m_athenaComps;
+  NeutrinoDD::NeutrinoCommonItems * m_commonItems;
+  EmulsionDataBase* m_rdb;
+ 
+  std::unique_ptr<EmulsionFilmParameters> m_filmParameters;
+  std::unique_ptr<EmulsionPlatesParameters> m_platesParameters;
+  std::unique_ptr<EmulsionGeneralParameters> m_generalParameters;
+  std::unique_ptr<NeutrinoDD::DistortedMaterialManager> m_distortedMatManager;
+
+};
+
+
+#endif // EmulsionGeoModel_EmulsionGeometryManager_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..52bdf151712a78cdad29439ba775045373fe628f
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.cxx
@@ -0,0 +1,23 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionIdentifier.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "Identifier/Identifier.h"
+
+#include <cassert>
+#include <iostream>
+
+Identifier 
+EmulsionIdentifier::getFilmId() 
+{
+  assert (m_idHelper);
+  return m_idHelper->film_id(m_module, m_base, m_film);
+}
+
+void EmulsionIdentifier::print()
+{
+  std::cout << "1/1/" << m_module << "/" 
+            << m_base << "/" << m_film << std::endl;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.h
new file mode 100644
index 0000000000000000000000000000000000000000..f82ba9c18829850c7ec80001260f73be205a4ea1
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionIdentifier.h
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONIDENTIFIER_H
+#define EMULSIONGEOMODEL_EMULSIONIDENTIFIER_H
+
+class Identifier;
+class EmulsionID;
+
+class EmulsionIdentifier
+{
+public:
+
+  EmulsionIdentifier( const EmulsionID* idHelper,
+                      int module = 0,
+		                  int base = 0,
+                      int film = 0 )
+    : m_idHelper{idHelper},
+      m_module{module},
+      m_base{base},
+      m_film{film}
+  {};
+
+
+  void setModule(int i) {m_module = i;}
+  int  getModule() const {return m_module;}
+
+  void setBase(int i) {m_base = i;}
+  int  getBase() const {return m_base;}
+
+  void setFilm(int i) {m_film = i;}
+  int  getFilm() const {return m_film;}
+
+
+  Identifier getFilmId();
+
+  // For debugging purposes.
+  void print();
+
+private:
+  const EmulsionID* m_idHelper;
+  int m_module;
+  int m_base;
+  int m_film;
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONIDENTIFIER_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b7007072a8feaff3d81809abbfbb5a59ecf93e7a
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.cxx
@@ -0,0 +1,83 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionMaterialManager.h"
+#include "GeoModelKernel/GeoMaterial.h"
+#include "GeoModelKernel/GeoElement.h"
+#include "EmulsionDataBase.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/Bootstrap.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include <iostream>
+
+// Constructor 
+EmulsionMaterialManager::EmulsionMaterialManager(EmulsionDataBase* db)
+{
+  // Get my material manager.
+  ISvcLocator* svcLocator = Gaudi::svcLocator(); // from Bootstrap
+  StoreGateSvc* detStore;
+  StatusCode sc = svcLocator->service("DetectorStore", detStore );
+  if (sc.isFailure()) {
+    std::cout << "Could not locate DetectorStore" << std::endl;
+    return;
+  }
+
+  m_materialManager = std::make_unique<NeutrinoMaterialManager>("EmulsionMaterialManager", db->athenaComps());
+  m_materialManager->addWeightTable(db->weightTable(), "preshower");
+  m_materialManager->addScalingTable(db->scalingTable());
+
+  loadMaterials();
+
+  m_gasMaterial = m_materialManager->getMaterial("std::Air");
+}
+
+// Add materials not yet in the database 
+void
+EmulsionMaterialManager::loadMaterials()
+{
+}
+
+const GeoElement* 
+EmulsionMaterialManager::getElement(const std::string & elementName) const
+{
+  return m_materialManager->getElement(elementName);
+}
+
+const GeoMaterial* 
+EmulsionMaterialManager::getMaterial(const std::string & materialName) const
+{
+  return m_materialManager->getMaterial(materialName);
+}
+
+void
+EmulsionMaterialManager::addMaterial(GeoMaterial* material)
+{
+  return m_materialManager->addMaterial(material);
+}
+
+const GeoMaterial* 
+EmulsionMaterialManager::getMaterial(const std::string & originalMaterial, 
+                                 double density,  
+                                 const std::string & newName)
+{
+  
+  return m_materialManager->getMaterial(originalMaterial, density, newName);
+}
+
+const GeoMaterial *
+EmulsionMaterialManager::getMaterialForVolume(const std::string & materialName, double volume)
+{
+  return m_materialManager->getMaterialForVolume(materialName, volume);
+}
+
+
+
+const GeoMaterial* 
+EmulsionMaterialManager::gasMaterial() const
+{
+  return m_gasMaterial;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..900d63ec61ef45f3771c913eef86991886f60230
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionMaterialManager.h
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONMATERIALMANAGER_H
+#define EMULSIONMATERIALMANAGER_H
+
+// EmulsionMaterialManager. This provides an interface to the NeutrinoMaterialManager which in turn
+// is an interface to GeoModel Material Manager with some additional functionality.
+#include "NeutrinoGeoModelUtils/NeutrinoMaterialManager.h"
+
+#include <memory>
+#include <string>
+
+class GeoMaterial;
+class GeoElement;
+class NeutrinoMaterialManager;
+class EmulsionDataBase;
+
+class EmulsionMaterialManager
+{
+
+public:
+
+  EmulsionMaterialManager(EmulsionDataBase* db);
+
+  const GeoMaterial* getMaterial(const std::string & materialName) const;
+  const GeoElement* getElement(const std::string & elementName) const;
+
+  const GeoMaterial* getMaterial(const std::string & originalMaterial, 
+				 double density,  
+				 const std::string & newName = "");
+  const GeoMaterial *getMaterialForVolume(const std::string & materialName, double volume);
+
+  // Default gas material
+  const GeoMaterial* gasMaterial() const;
+
+private:
+  void loadMaterials();
+  void addMaterial(GeoMaterial* material);
+
+  std::unique_ptr<NeutrinoMaterialManager> m_materialManager;
+  const GeoMaterial* m_gasMaterial;
+
+};
+
+
+#endif // EMULSIONMATERIALMANAGER_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d8d6c893419f4b1463bfbe8ef688a30922b88d2e
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.cxx
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionOptions.h"
+
+EmulsionOptions::EmulsionOptions()
+  : m_alignable(true)
+//   , m_alignModule(true)
+  , m_dynAlignFolders(false)
+{}
+
+void 
+EmulsionOptions::setAlignable(bool flag)
+{
+  m_alignable = flag;
+}
+
+bool 
+EmulsionOptions::alignable() const
+{
+  return m_alignable;
+}
+
+// following may eventually become useful
+//
+// void 
+// SCT_Options::setAlignAtModuleLevel(bool flag)
+// {
+//   m_alignModule = flag;
+// }
+
+// bool 
+// SCT_Options::alignAtModuleLevel() const
+// {
+//   return m_alignModule;
+// }
+
+void EmulsionOptions::setDynamicAlignFolders(const bool flag)
+{
+  m_dynAlignFolders = flag;
+}
+
+bool EmulsionOptions::dynamicAlignFolders() const 
+{  
+  return m_dynAlignFolders;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..9854273f41e9155d7d402058e2bd438d95b505f1
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionOptions.h
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionOptions_H
+#define EmulsionGeoModel_EmulsionOptions_H
+
+// Class for any run time options.
+
+
+class EmulsionOptions
+{
+
+public:
+  EmulsionOptions();
+  bool alignable() const;
+//   bool alignAtModuleLevel() const;
+
+  void setAlignable(bool flag = true);
+//   void setAlignAtModuleLevel(bool flag = true);
+
+  //dynamic alignment folders
+  void setDynamicAlignFolders(const bool flag = true);
+  bool dynamicAlignFolders() const;
+
+private:
+
+  bool m_alignable;
+//   bool m_alignModule;
+  bool m_dynAlignFolders;   //controls which set of alignment folders is used
+
+};
+
+
+#endif // EmulsionGeoModel_EmulsionOptions_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7424987e17929d371002aa7f778e7a2a0ae08b06
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionPlates.h"
+
+#include "EmulsionGeometryManager.h"
+#include "EmulsionMaterialManager.h"
+#include "EmulsionGeneralParameters.h"
+#include "EmulsionPlatesParameters.h"
+
+#include "GeoModelKernel/GeoBox.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoMaterial.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoVPhysVol.h"
+#include "GeoModelKernel/GeoNameTag.h"
+#include "GeoModelKernel/GeoIdentifierTag.h"
+#include "GeoModelKernel/GeoTransform.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+#include "GaudiKernel/SystemOfUnits.h"
+
+using namespace NeutrinoDD;
+
+EmulsionPlates::EmulsionPlates(const std::string & name,
+                     NeutrinoDD::EmulsionDetectorManager* detectorManager,
+                     const EmulsionGeometryManager* geometryManager,
+                     EmulsionMaterialManager* materials)
+  : EmulsionUniqueComponentFactory(name, detectorManager, geometryManager, materials)
+{
+  getParameters();
+  m_logVolume = preBuild();
+}
+
+
+void
+EmulsionPlates::getParameters()
+{
+  const EmulsionGeneralParameters * generalParameters = m_geometryManager->generalParameters();
+  const EmulsionPlatesParameters *   platesParameters = m_geometryManager->platesParameters();
+
+  m_width = platesParameters->platesWidth();
+  m_height = platesParameters->platesHeight();
+  m_thickness = platesParameters->platesThickness();
+  m_material = m_materials->getMaterial(platesParameters->platesMaterial());
+
+  m_nBasesPerModule = generalParameters->nBasesPerModule();
+  m_nModules       = generalParameters->nModules();
+  m_firstBaseZ     = generalParameters->firstBaseZ();
+  m_lastBaseZ      = generalParameters->lastBaseZ();
+
+  m_detectorManager->numerology().setNumBasesPerModule(m_nBasesPerModule);
+}
+
+const GeoLogVol * 
+EmulsionPlates::preBuild()
+{
+  // create child element
+  m_base = new EmulsionBase("Base", m_detectorManager, m_geometryManager, m_materials);
+
+
+  // Build a box to hold everything
+  const GeoBox* platesShape = new GeoBox(0.5*m_width, 0.5*m_height, 0.5*m_thickness);
+
+  // GeoLogVol * platesLog = new GeoLogVol(getName(), platesShape, m_materials->gasMaterial());
+  GeoLogVol * platesLog = new GeoLogVol(getName(), platesShape, m_material);
+
+  // m_baseboardPos = new GeoTrf::Translate3D(0.0, 0.0, 0.0);
+  // m_frontPos     = new GeoTrf::Translate3D(0.0, 0.0, -(m_baseThickness + m_filmThickness)/2);
+  // m_backPos     = new GeoTrf::Translate3D(0.0, 0.0, (m_baseThickness + m_filmThickness)/2);
+
+  return platesLog;
+}
+
+GeoVPhysVol * 
+EmulsionPlates::build(EmulsionIdentifier id)
+{
+  GeoFullPhysVol * plates = new GeoFullPhysVol(m_logVolume); 
+  
+  int nBases = 0;
+  int nBasesTotal = m_nModules * m_nBasesPerModule;
+  // Loop over modules
+  for (int module = 0; module < m_nModules; module++)
+  {
+    id.setModule(module);
+    // plates->add(new GeoNameTag("Module#"+intToString(module)));
+    // plates->add(new GeoIdentifierTag(module));
+    // Loop over bases in a module
+    for (int base = 0; base < m_nBasesPerModule; base++)
+    {
+      id.setBase(base);
+      GeoAlignableTransform* theTransform = new GeoAlignableTransform( GeoTrf::Translate3D {0.0, 0.0, m_firstBaseZ + ((m_lastBaseZ - m_firstBaseZ)/(nBasesTotal-1))*nBases++} );
+      plates->add(theTransform);
+      plates->add(new GeoNameTag("Base#"+intToString(module*100 + base)));
+      plates->add(new GeoIdentifierTag(module*100 + base));
+      GeoVPhysVol* physBase = m_base->build(id);
+      plates->add(physBase);
+      m_detectorManager->addAlignableTransform(1, id.getFilmId(), theTransform, physBase);
+    }
+    m_detectorManager->numerology().useModule(module);
+  }
+
+  return plates;
+}
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h
new file mode 100644
index 0000000000000000000000000000000000000000..b827265b9f0753fd834f24d0d051eb02ba2a5675
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EMULSIONGEOMODEL_EMULSIONPLATES_H
+#define EMULSIONGEOMODEL_EMULSIONPLATES_H
+
+#include "EmulsionComponentFactory.h"
+#include "EmulsionBase.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+
+#include <atomic>
+#include <string>
+
+class GeoMaterial;
+class GeoVPhysVol;
+
+class EmulsionPlates: public EmulsionUniqueComponentFactory
+{
+public:
+  EmulsionPlates(const std::string & name,
+             NeutrinoDD::EmulsionDetectorManager* detectorManager,
+             const EmulsionGeometryManager* geometryManager,
+             EmulsionMaterialManager* materials);
+
+public:
+  double thickness() const {return m_thickness;}
+  double width()     const {return m_width;}
+  double height()    const {return m_height;}
+
+  virtual GeoVPhysVol * build(EmulsionIdentifier id);
+  
+private:
+  void getParameters();
+  virtual const GeoLogVol * preBuild();
+ 
+  double m_thickness;
+  double m_width;
+  double m_height;
+  const GeoMaterial * m_material;
+
+  int m_nModules;
+  int m_nBasesPerModule;
+  double m_firstBaseZ;
+  double m_lastBaseZ;
+
+  EmulsionBase* m_base;
+
+};
+
+#endif // EMULSIONGEOMODEL_EMULSIONPLATES_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..67af6b05830b97a9c1b355aa963f64d969cd6995
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.cxx
@@ -0,0 +1,61 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EmulsionPlatesParameters.h"
+#include "EmulsionGeometryManager.h"
+
+#include "EmulsionDataBase.h"
+
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include <cmath>
+
+
+EmulsionPlatesParameters::EmulsionPlatesParameters(EmulsionDataBase* rdb)
+{
+  m_rdb = rdb;
+}
+
+double 
+EmulsionPlatesParameters::platesWidth() const
+{
+  return m_rdb->emulsionPlates()->getDouble("DX");
+}
+
+double 
+EmulsionPlatesParameters::platesHeight() const
+{
+  return m_rdb->emulsionPlates()->getDouble("DY");
+}
+
+double 
+EmulsionPlatesParameters::platesThickness() const
+{
+  return m_rdb->emulsionPlates()->getDouble("DZ");
+}
+
+double 
+EmulsionPlatesParameters::platesX() const
+{
+  return m_rdb->emulsionPlates()->getDouble("POSX");
+}
+
+double 
+EmulsionPlatesParameters::platesY() const
+{
+  return m_rdb->emulsionPlates()->getDouble("POSY");
+}
+
+double 
+EmulsionPlatesParameters::platesZ() const
+{
+  return m_rdb->emulsionPlates()->getDouble("POSZ");
+}
+
+std::string 
+EmulsionPlatesParameters::platesMaterial() const
+{
+  return m_rdb->emulsionPlates()->getString("MATERIAL");
+}
\ No newline at end of file
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..71962b66cdd8f97825b3b177ec43ae959bbfdefa
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlatesParameters.h
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EmulsionGeoModel_EmulsionPlatesParameters_H
+#define EmulsionGeoModel_EmulsionPlatesParameters_H
+
+#include <string>
+
+class EmulsionDataBase;
+
+class EmulsionPlatesParameters {
+
+public:
+
+  // Constructor 
+  EmulsionPlatesParameters(EmulsionDataBase* rdb);
+
+
+  // General
+  double platesWidth() const;
+  double platesHeight() const;
+  double platesThickness() const;
+  double platesX() const;
+  double platesY() const;
+  double platesZ() const;
+  std::string platesMaterial() const;
+
+ private:
+  EmulsionDataBase * m_rdb;
+
+};
+
+
+#endif // EmulsionGeoModel_EmulsionPlatesParameters_H
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/components/EmulsionGeoModel_entries.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/components/EmulsionGeoModel_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..908a4adf4470f578e07ac3a16227caf482171672
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/components/EmulsionGeoModel_entries.cxx
@@ -0,0 +1,3 @@
+#include "EmulsionGeoModel/EmulsionDetectorTool.h"
+
+DECLARE_COMPONENT( EmulsionDetectorTool )
\ No newline at end of file
diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/test/EmulsionGMConfig_test.py b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/test/EmulsionGMConfig_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..f200fa848aed649c0bc1f104b3bfa8adf5abc3e8
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/test/EmulsionGMConfig_test.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Run tests on EmulsionGeoModel configuration
+
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+if __name__ == "__main__":
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior=1
+    from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+    from AthenaConfiguration.TestDefaults import defaultTestFiles
+
+    ConfigFlags.Input.Files = defaultTestFiles.HITS
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
+    ConfigFlags.GeoModel.Align.Dynamic    = False
+    ConfigFlags.lock()
+
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    from EmulsionGeoModel.EmulsionGeoModelConfig import EmulsionGeometryCfg
+    acc = EmulsionGeometryCfg(ConfigFlags)
+    f=open('EmulsionGeometryCfg.pkl','wb')
+    acc.store(f)
+    f.close()
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/CMakeLists.txt b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4b79c5b3d9e00246811905fc12b112c90887e9d8
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/CMakeLists.txt
@@ -0,0 +1,22 @@
+################################################################################
+# Package: NeutrinoGeoModelUtils
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoGeoModelUtils )
+
+# External dependencies:
+find_package( Boost COMPONENTS filesystem thread system )
+find_package( CLHEP )
+find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess )
+find_package( GeoModel )
+
+# Component(s) in the package:
+atlas_add_library( NeutrinoGeoModelUtils
+                   src/*.cxx
+                   PUBLIC_HEADERS NeutrinoGeoModelUtils
+                   INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                   DEFINITIONS ${CLHEP_DEFINITIONS}
+                   LINK_LIBRARIES ${Boost_LIBRARIES} ${CORAL_LIBRARIES} ${CLHEP_LIBRARIES} ${GEOMODEL_LIBRARIES} AthenaKernel GaudiKernel StoreGateLib SGtests GeoPrimitives GeometryDBSvcLib
+                   PRIVATE_LINK_LIBRARIES GeoModelFaserUtilities )
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DetectorFactoryBase.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DetectorFactoryBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..86f49a399af0bb077249b508334837b63a005bae
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DetectorFactoryBase.h
@@ -0,0 +1,51 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_DetectorFactoryBase_H
+#define NeutrinoGeoModelUtils_DetectorFactoryBase_H
+
+#include "AthenaKernel/MsgStreamMember.h"
+#include "GeoModelKernel/GeoVDetectorFactory.h" 
+#include "NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h"
+
+class StoreGateSvc;
+class IGeoDbTagSvc;
+class IRDBAccessSvc;
+
+namespace NeutrinoDD {
+
+class DetectorFactoryBase : public GeoVDetectorFactory  
+{ 
+
+public:
+  DetectorFactoryBase(const NeutrinoDD::AthenaComps * athenaComps)
+    : m_athenaComps(athenaComps)
+  {}
+
+  StoreGateSvc * detStore() const {return m_athenaComps->detStore();}
+
+  IGeoDbTagSvc * geoDbTagSvc() const {return m_athenaComps->geoDbTagSvc();}
+
+  IRDBAccessSvc * rdbAccessSvc() const {return m_athenaComps->rdbAccessSvc();}
+  
+  IGeometryDBSvc * geomDB() const {return m_athenaComps->geomDB();}
+
+ //Declaring the Message method for further use
+  MsgStream& msg (MSG::Level lvl) const { return m_athenaComps->msg(lvl); }
+
+  //Declaring the Method providing Verbosity Level
+  bool msgLvl (MSG::Level lvl) const { return m_athenaComps->msgLvl(lvl); }
+
+  const NeutrinoDD::AthenaComps *  getAthenaComps() {return m_athenaComps;}
+
+private:
+  
+  const NeutrinoDD::AthenaComps *  m_athenaComps;
+
+};
+
+} // end namespace
+
+#endif // NeutrinoGeoModelUtils_DetectorFactoryBase_H
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DistortedMaterialManager.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DistortedMaterialManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d9a4e5259ac0b9b1019ea77821e05c18d05c1a8
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/DistortedMaterialManager.h
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_DistortedMaterialManager_h
+#define NeutrinoGeoModelUtils_DistortedMaterialManager_h
+
+class AbsMaterialManager;
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+
+namespace NeutrinoDD {
+
+class DistortedMaterialManager
+{
+public:
+  DistortedMaterialManager();  
+  IRDBRecordset_ptr  extraMaterialTable() const {return  m_xMatTable;}
+  const AbsMaterialManager * materialManager() const {return  m_materialManager;}
+
+private:
+  const AbsMaterialManager * m_materialManager;
+  IRDBRecordset_ptr  m_xMatTable;
+};
+
+
+} // endnamespace
+
+#endif // NeutrinoGeoModelUtils_DistortedMaterialManager_h
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/ExtraMaterial.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/ExtraMaterial.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0cefb059347d0ddf911c6cf75a602a48bae6735
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/ExtraMaterial.h
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_ExtraMaterial
+#define NeutrinoGeoModelUtils_ExtraMaterial
+
+#include <cmath>
+#include <string>
+#include <sstream>
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+
+class GeoPhysVol;
+class GeoFullPhysVol;
+class AbsMaterialManager;
+
+namespace NeutrinoDD {
+
+class DistortedMaterialManager;
+
+class ExtraMaterial
+{
+public:
+  ExtraMaterial(IRDBRecordset_ptr xMatTable, const AbsMaterialManager * matManager);
+  ExtraMaterial(const NeutrinoDD::DistortedMaterialManager * manager);
+  void add(GeoPhysVol * parent, const std::string & parentName, double zPos = 0);
+  void add(GeoFullPhysVol * parent, const std::string & parentName, double zPos = 0);
+
+private:
+  void add(GeoPhysVol * parent, GeoFullPhysVol * fullparent, const std::string & parentName, double zPos);
+  IRDBRecordset_ptr  m_xMatTable;
+  const AbsMaterialManager * m_matManager;
+};
+
+} // end namespace
+
+#endif // NeutrinoGeoModelUtils_ExtraMaterial
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/GenericTubeMaker.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/GenericTubeMaker.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fa74a1a53d56981a64ba57697ff2402ac90438e
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/GenericTubeMaker.h
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_GenericTubeMaker_h
+#define NeutrinoGeoModelUtils_GenericTubeMaker_h
+
+#include "NeutrinoGeoModelUtils/TubeVolData.h"
+#include <string>
+
+class GeoVPhysVol;
+class GeoPhysVol;
+class GeoFullPhysVol;
+class GeoShape;
+class IRDBRecord;
+
+/// Helper class to make general tubes used mainly for services.
+/// Takes as input a DB table which has the following columns
+/// Handles numberouse cases
+/// Simple tubes: Rmin2, Rmax2 <=0.
+/// Cones: Uses Rmin2 and Rmax2.
+/// Tube and cone sectors: Uses phi start and phi delta.
+/// If RadialDiv > 0 then simulates the CLHEP::radial dependence of tubes/cables going outward CLHEP::radially.
+/// 
+
+namespace NeutrinoDD {
+
+class GenericTubeMaker 
+{
+public:
+  GenericTubeMaker(const IRDBRecord *);
+  const TubeVolData & volData() const {return m_volData;}
+  std::string name() const;
+  std::string materialName() const;
+  const GeoShape * buildShape();
+  void placeVolume(GeoPhysVol * parent, GeoVPhysVol * child, double zParent = 0);
+  void placeVolume(GeoFullPhysVol * fullparent, GeoVPhysVol * child, double zParent = 0);
+  void placeVolTwoSide(GeoPhysVol * parentPos, GeoPhysVol * parentNeg, GeoVPhysVol * child, double zParent = 0);
+  void placeVolTwoSide(GeoFullPhysVol * fullparentPos, GeoFullPhysVol * fullparentNeg, GeoVPhysVol * child, double zParent = 0);
+
+
+private:
+
+  void placeVolume(GeoPhysVol * parent, GeoFullPhysVol * fullparent, GeoVPhysVol * child, double zParent);
+  void placeVolTwoSide(GeoPhysVol * parentPos, GeoPhysVol * parentNeg, 
+		       GeoFullPhysVol * fullparentPos, GeoFullPhysVol * fullparentNeg, 
+		       GeoVPhysVol * child, double zParent);
+
+  const IRDBRecord * m_record;
+  TubeVolData m_volData;  
+};
+
+} // end namespace
+
+#endif // NeutrinoGeoModelUtils_GenericTubeMaker_h
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d1aad8a87df7db2c1cf6548c48229bfdeab095b
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_NeutrinoDDAthenaComps_H
+#define NeutrinoGeoModelUtils_NeutrinoDDAthenaComps_H
+
+// Message Stream Member
+#include "AthenaKernel/MsgStreamMember.h"
+class  StoreGateSvc;
+class  IGeoDbTagSvc;
+class  IRDBAccessSvc;
+class  IGeometryDBSvc; 
+
+#include <string>
+namespace NeutrinoDD {
+
+/// Class to hold various Athena components.
+class AthenaComps {
+
+public:
+
+  AthenaComps(const std::string & msgStreamName);
+
+  //Declaring the Message method for further use
+  MsgStream& msg (MSG::Level lvl) const { return m_msg << lvl; }
+
+  //Declaring the Method providing Verbosity Level
+  bool msgLvl (MSG::Level lvl) const { return m_msg.get().level() <= lvl; }
+
+  void setDetStore(StoreGateSvc *);
+  void setGeoDbTagSvc(IGeoDbTagSvc *);
+  void setRDBAccessSvc(IRDBAccessSvc *);
+  void setGeometryDBSvc(IGeometryDBSvc *);
+
+  StoreGateSvc * detStore() const;
+  IGeoDbTagSvc * geoDbTagSvc() const;
+  IRDBAccessSvc * rdbAccessSvc() const;
+  IGeometryDBSvc * geomDB() const;
+  
+private:
+  //Declaring private message stream member.
+  mutable Athena::MsgStreamMember m_msg;
+  
+  StoreGateSvc * m_detStore;
+  IGeoDbTagSvc * m_geoDbTagSvc;
+  IRDBAccessSvc * m_rdbAccessSvc;
+  IGeometryDBSvc * m_geometryDBSvc;
+
+};
+
+inline StoreGateSvc * AthenaComps::detStore() const
+{
+  return m_detStore;
+}
+
+inline IGeoDbTagSvc * AthenaComps::geoDbTagSvc() const
+{
+  return m_geoDbTagSvc;
+}
+
+inline IRDBAccessSvc * AthenaComps::rdbAccessSvc() const
+{
+  return m_rdbAccessSvc;
+}
+
+inline IGeometryDBSvc * AthenaComps::geomDB() const
+{
+  return m_geometryDBSvc;
+}
+
+} // endnamespace
+
+#endif // NeutrinoGeoModelUtils_NeutrinoDDAthenaComps_H
+
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoMaterialManager.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoMaterialManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb1c97741d0e128ada09e006a1ccb52d6fa11684
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/NeutrinoMaterialManager.h
@@ -0,0 +1,244 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef SCINTMATERIALMANAGER_H
+#define SCINTMATERIALMANAGER_H
+
+// Message Stream Member
+#include "AthenaKernel/MsgStreamMember.h"
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+
+class GeoMaterial;
+class GeoElement;
+class AbsMaterialManager;
+class StoreGateSvc;
+class IGeometryDBSvc;
+
+namespace NeutrinoDD
+{
+  class AthenaComps;
+}
+
+#include <string>
+#include <map>
+
+/// NeutrinoMaterialManager. This provides an interface to the GeoModel Material Manager
+/// as well as allowing additional materials to be defined or standard ones redefined.
+/// It also allows creating new materials based on existing ones but with a different 
+/// density. It is also possible to specify a weight table and this is used to create
+/// materials with a density such that the the total weight is correct.
+
+
+class NeutrinoMaterialManager 
+{
+
+public:
+
+  NeutrinoMaterialManager(const std::string & managerName, StoreGateSvc* detStore);
+  NeutrinoMaterialManager(const std::string & managerName, StoreGateSvc* detStore,
+		       IRDBRecordset_ptr weightTable,
+		       const std::string & space = "",
+		       bool extraFunctionality = false);
+  NeutrinoMaterialManager(const std::string & managerName, StoreGateSvc* detStore,
+		       IRDBRecordset_ptr weightTable,
+		       IRDBRecordset_ptr compositionTable,
+		       const std::string & space = "");
+  NeutrinoMaterialManager(const std::string & managerName, 
+		       const NeutrinoDD::AthenaComps *);
+  ~NeutrinoMaterialManager();
+
+  void addWeightTable(IRDBRecordset_ptr weightTable, const std::string & space = "");
+  void addWeightMaterial(std::string materialName, std::string materialBase, double weight, int linearWeightFlag);
+  void addCompositionTable(IRDBRecordset_ptr compositionTable, const std::string & space = "");
+  void addScalingTable(IRDBRecordset_ptr scalingTable);
+
+
+  bool hasMaterial(const std::string &materialName) const;
+
+  /// Get material. First looks for locally defined material and if not found looks in GeoModel material manager.
+  const GeoMaterial* getMaterial(const std::string & materialName);
+
+  /// Get element from GeoModel material manager
+  const GeoElement* getElement(const std::string & elementName) const;
+
+  /// Create and get material with a specified density based on an existing material.
+  /// If a newName is supplied it creates the new material even if the orginal material
+  /// has the same density. It however first checks if the material with NewName exists.
+  /// If no newName is supplied then it checks the density of
+  /// the existing material. If it is consistent it returns the material.
+  /// If it is different it creates a material with the string "Modified" added to the
+  /// name.
+  const GeoMaterial* getMaterial(const std::string & origMaterialName, 
+				 double density, 
+				 const std::string & newName = "");
+
+  // Creates a new material based on origMaterialName but with denisty scaled 
+  // by scaleFactor. If no newName then will add the string containing the scale 
+  // factor. Eg if scale 12.345678 "Silicon" -> "Silicon12_3456" 
+  // If the scale factor is 1 and there is no newName then it just returns the
+  // original material.
+  // scaleFactor must be between 0.001 and 1000.
+  const GeoMaterial* getMaterialScaled(const std::string & origMaterialName, 
+				       double scaleFactor, 
+				       const std::string & newName = "");
+
+  /// Create and get material with a density calculated to give weight in predefined weight table.
+  const GeoMaterial * getMaterialForVolume(const std::string & materialName, 
+					   double volume, 
+					   const std::string & newName = "");
+
+  // Similar to getMaterialForVolume but if weight table uses linear weight, then determine weight 
+  // using length. First looks in special table of material compositions which can specify several
+  // components and their count. 
+  const GeoMaterial * getMaterialForVolumeLength(const std::string & materialName, 
+						 double volume, 
+						 double length, 
+						 const std::string & newName = "");
+
+  // As above but rather than using the special table of material compositions, the compositions is specified
+  // in the arguments as a vector of materials and multiplictive factors.
+  const GeoMaterial * getMaterialForVolumeLength(const std::string & name,
+						 const std::vector<std::string> & materialComponents, 
+						 const std::vector<double> factors, 
+						 double volume, 
+						 double length);
+  
+  // As above but only one material making up the composition.
+  const GeoMaterial * getMaterialForVolumeLength(const std::string & name,
+						 const std::string & materialComponent, 
+						 double factor, 
+						 double volume, 
+						 double length);
+
+  // Define composite material : function used to create dynamically a new composite material by adding
+  //            a defined volume of glue/grease to an already existing material  (IBL stave)
+  const GeoMaterial * getCompositeMaterialForVolume(const std::string & newMatName,
+						    const double volumeTot,
+						    const double volume1, const std::string & matName1,
+						    const double volume2, const std::string & matName2
+						    );
+
+  // Define a new material composition.
+  const GeoMaterial * getMaterial(const std::string & name,
+				  const std::vector<std::string> & materialComponents, 
+				  const std::vector<double> & fractWeights, 
+				  double density);
+
+
+  /// Add material
+  void addMaterial(GeoMaterial *material);
+
+  //Declaring the Message method for further use
+  MsgStream& msg (MSG::Level lvl) const { return m_msg << lvl; }
+
+  //Declaring the Method providing Verbosity Level
+  bool msgLvl (MSG::Level lvl){ return m_msg.get().level() <= lvl; }
+
+
+private:
+
+  class MaterialByWeight  {
+  public:
+    MaterialByWeight() : weight(0), linearWeightFlag(false) {} 
+    MaterialByWeight(const std::string & name_in, double weight_in, bool linearWeightFlag_in) 
+      : name(name_in), weight(weight_in), linearWeightFlag(linearWeightFlag_in) {}
+    MaterialByWeight(double weight_in) 
+      : weight(weight_in), linearWeightFlag(false) {}
+    std::string name;
+    double weight;
+    bool linearWeightFlag;
+  };
+
+  class MaterialComponent {
+  public:
+    MaterialComponent() : factor(1), actualLength(-1) {}
+    MaterialComponent(const std::string & name_in, double factor_in = 1, bool actualLength_in = -1) 
+      :  name(name_in), factor(factor_in), actualLength(actualLength_in) {}
+    std::string name;
+    double factor;
+    double actualLength;
+  };
+
+  /// Class to hold information need to create a material
+  class MaterialDef {
+  public:
+    MaterialDef();
+    MaterialDef(const std::string & name, double density);
+    void addComponent(const std::string & compName, double fraction);
+    void setCreated() {m_created = true;}
+    unsigned int numComponents() const {return m_components.size();}
+    bool isCreated() const {return m_created;}
+    const std::string & name() const {return m_name;}
+    double density() const {return m_density;}
+    const std::string & compName(unsigned int i) const {return m_components[i];}
+    double fraction(unsigned int i) const {return m_fractions[i];}
+    double totalFraction() const;
+
+  private:
+    std::string m_name;
+    double m_density;
+    std::vector<std::string> m_components;
+    std::vector<double> m_fractions;
+    bool m_created;
+  };
+  
+  
+  const AbsMaterialManager * retrieveManager(StoreGateSvc* detStore);
+  const GeoMaterial* getAdditionalMaterial(const std::string & materialName) const; 
+  bool compareDensity(double d1, double d2) const;
+  void addWeightTableOld(IRDBRecordset_ptr weightTable, const std::string & space);
+
+  // Internal versions. The public versions allow materials to be have extra scaling.
+  const GeoMaterial* getMaterialInternal(const std::string & materialName) const;
+  const GeoMaterial* getMaterialInternal(const std::string & origMaterialName, 
+					 double density, 
+					 const std::string & newName = "");
+  const GeoMaterial* getMaterialScaledInternal(const std::string & origMaterialName, 
+					       double scaleFactor, 
+					       const std::string & newName = "");
+  const GeoMaterial * getMaterialInternal(const std::string & name,
+					  const std::vector<std::string> & materialComponents, 
+					  const std::vector<double> & fractWeights, 
+					  double density);
+
+  // Methods to return material with extra scaling.
+  const GeoMaterial * extraScaledMaterial(const std::string & materialName, 
+					  const std::string & newName, 
+					  const GeoMaterial * origMaterial);
+
+  const GeoMaterial * extraScaledMaterial(const std::string & materialName, 
+					  const GeoMaterial * origMaterial);
+
+  const IGeometryDBSvc * db();
+  void addTextFileMaterials();
+  void createMaterial(const MaterialDef & material);
+  double getExtraScaleFactor(const std::string & materialName);
+
+  const AbsMaterialManager *m_materialManager;
+  std::string m_managerName;
+
+  typedef std::map<std::string, const GeoMaterial *> MaterialStore;
+  MaterialStore m_store;
+
+  typedef std::map<std::string, MaterialByWeight > MaterialWeightMap;
+  MaterialWeightMap m_weightMap;
+
+  typedef std::map<std::string, MaterialComponent > MaterialCompositionMap;
+  MaterialCompositionMap m_matCompositionMap;
+
+  typedef std::map<std::string, double > ExtraScaleFactorMap;
+  ExtraScaleFactorMap m_scalingMap;
+
+  //Declaring private message stream member.
+  mutable Athena::MsgStreamMember m_msg;
+
+  // Has linear weight flag. 
+  bool m_extraFunctionality;
+
+  const NeutrinoDD::AthenaComps * m_athenaComps;
+
+};
+
+
+#endif // SCINTMATERIALMANAGER_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TopLevelPlacements.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TopLevelPlacements.h
new file mode 100644
index 0000000000000000000000000000000000000000..53d45c5b55a27c93997a7c6bad0ed3be071b24e7
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TopLevelPlacements.h
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef SCINTGEOMODELUTILS_TOPLEVELPLACEMENTS_H
+#define SCINTGEOMODELUTILS_TOPLEVELPLACEMENTS_H
+
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+
+#include <map>
+#include <string>
+
+class IRDBRecord;
+
+class TopLevelPlacements
+{
+  
+public:
+
+  TopLevelPlacements(IRDBRecordset_ptr topLevelTable);
+  ~TopLevelPlacements();
+
+  bool  present(const std::string & partName) const;
+  const GeoTrf::Transform3D & transform(const std::string & partName) const;
+  
+
+private:
+  
+  class Part {
+  public:
+    std::string label;
+    GeoTrf::Transform3D transform;
+  };
+
+  void fillPlacements(IRDBRecordset_ptr topLevelTable);
+  GeoTrf::Transform3D partTransform(const IRDBRecord* record) const;
+  Part * getPart(const std::string & partName) const;
+
+  std::map<std::string, Part *> m_parts;
+  bool m_noTopLevelTable;
+
+  static GeoTrf::Transform3D s_identityTransform;
+};
+
+#endif // SCINTGEOMODELUTILS_TOPLEVELPLACEMENTS_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TubeVolData.h b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TubeVolData.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d1f613e6a96c2c4a7b8ccab0a3adef81ca41138
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/NeutrinoGeoModelUtils/TubeVolData.h
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NeutrinoGeoModelUtils_TubeVolData_h
+#define NeutrinoGeoModelUtils_TubeVolData_h
+
+class IRDBRecord;
+#include <string>
+
+namespace NeutrinoDD {
+
+
+/// Helper class to read in generic TUBE, TUBS, CONS or PCON type volumes.
+
+class TubeVolData
+{
+ public:
+  enum VolShape {TUBE, TUBS, CONS, RADIAL};
+  
+  TubeVolData(const IRDBRecord *);
+  double rmin() const {return m_rmin1;}
+  double rmax() const {return m_rmax1;}
+  double rmin2() const {return m_rmin2;}
+  double rmax2() const {return m_rmax2;}
+  double length() const {return m_length;}
+  double zMid() const {return m_zMid;}
+  double phiStart() const {return m_phiStart;}
+  double phiDelta() const {return m_phiDelta;}
+  double phiStep() const {return m_phiStep;}
+  int nRepeat() const {return m_nRepeat;}
+  int radialDivisions() const {return m_radialDiv;}
+  bool bothZ() const {return m_bothZ;}
+
+  VolShape shape() const {return m_shape;}
+  std::string material() const;
+  
+  double maxRadius() const;
+
+ private:
+  const IRDBRecord * m_record;
+  bool m_bothZ;
+  int m_nRepeat;
+  int m_radialDiv;
+  double m_phiStart;
+  double m_phiDelta;
+  double m_phiStep;
+  double m_rmin1;
+  double m_rmin2;
+  double m_rmax1;
+  double m_rmax2;
+  double m_length;
+  double m_zMid;
+  VolShape m_shape{CONS};
+};
+
+} // end namespace
+
+#endif // NeutrinoGeoModelUtils_TubeVolData
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/DistortedMaterialManager.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/DistortedMaterialManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fbaae2a61caf49169c2318ae398c79b7cc92d4f1
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/DistortedMaterialManager.cxx
@@ -0,0 +1,46 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+
+#include "NeutrinoGeoModelUtils/DistortedMaterialManager.h"
+#include "GeoModelInterfaces/StoredMaterialManager.h"
+#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h"
+#include "AthenaKernel/MsgStreamMember.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "RDBAccessSvc/IRDBAccessSvc.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/Bootstrap.h"
+
+namespace NeutrinoDD {
+  DistortedMaterialManager::DistortedMaterialManager() {
+    ISvcLocator* svcLocator = Gaudi::svcLocator(); // from Bootstrap
+
+    Athena::MsgStreamMember log("ExtraMaterialManager");
+    log << MSG::DEBUG << "Initialized Neutrino Distorted Material Manager" << endmsg;
+
+    StoreGateSvc* detStore;
+    StatusCode sc;
+    sc = svcLocator->service("DetectorStore", detStore);
+    if (sc.isFailure()) log << MSG::FATAL << "Could not locate DetectorStore" << endmsg;
+
+    IRDBAccessSvc* rdbSvc;
+    sc = svcLocator->service("RDBAccessSvc", rdbSvc);
+    if (sc.isFailure()) log << MSG::FATAL << "Could not locate RDBAccessSvc" << endmsg;
+
+    // Get version tag and node for InDet.
+    DecodeFaserVersionKey versionKey("Neutrino");
+    std::string detectorKey = versionKey.tag();
+    std::string detectorNode = versionKey.node();
+
+    log << MSG::DEBUG << "Retrieving Record Sets from database ..." << endmsg;
+    log << MSG::DEBUG << "Key = " << detectorKey << " Node = " << detectorNode << endmsg;
+
+    m_xMatTable = rdbSvc->getRecordsetPtr("NeutrinoExtraMaterial", detectorKey, detectorNode, "FASERDD");
+
+    const StoredMaterialManager* theGeoMaterialManager = 0;
+    sc = detStore->retrieve(theGeoMaterialManager, "MATERIALS");
+    if (sc.isFailure()) log << MSG::FATAL << "Could not locate GeoModel Material manager" << endmsg;
+    m_materialManager = theGeoMaterialManager;
+  }
+} // end namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/ExtraMaterial.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/ExtraMaterial.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..315524c048217048ceab350303c4bd69923cd112
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/ExtraMaterial.cxx
@@ -0,0 +1,74 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/ExtraMaterial.h"
+#include "NeutrinoGeoModelUtils/GenericTubeMaker.h"
+#include "NeutrinoGeoModelUtils/TubeVolData.h"
+#include "NeutrinoGeoModelUtils/DistortedMaterialManager.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoTube.h"
+#include "GeoModelKernel/GeoTubs.h"
+#include "GeoModelKernel/GeoCons.h"
+#include "GeoModelKernel/GeoLogVol.h"
+#include "GeoModelKernel/GeoMaterial.h"
+
+#include "GeoModelInterfaces/AbsMaterialManager.h"
+
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace NeutrinoDD {
+  ExtraMaterial::ExtraMaterial(IRDBRecordset_ptr xMatTable, const AbsMaterialManager* matManager)
+    : m_xMatTable(xMatTable),
+    m_matManager(matManager)
+  {}
+
+  ExtraMaterial::ExtraMaterial(const DistortedMaterialManager* manager)
+    : m_xMatTable(manager->extraMaterialTable()),
+    m_matManager(manager->materialManager())
+  {}
+
+  void
+  ExtraMaterial::add(GeoPhysVol* parent, const std::string& region, double zParent) {
+    add(parent, 0, region, zParent);
+  }
+
+  void
+  ExtraMaterial::add(GeoFullPhysVol* parent, const std::string& region, double zParent) {
+    add(0, parent, region, zParent);
+  }
+
+  void
+  ExtraMaterial::add(GeoPhysVol* parent, GeoFullPhysVol* fullparent, const std::string& region, double zParent) {
+    //std::cout << "Adding Extra material for region: " << region << ", zParent = " << zParent << std::endl;
+
+    for (unsigned int i = 0; i < m_xMatTable->size(); i++) {
+      std::ostringstream volnamestr;
+      volnamestr << "ExtraMaterial" << i;
+
+      //std::cout << "In Extra material " << i << std::endl;
+
+      if ((*m_xMatTable)[i]->getString("REGION") == region) {
+        //std::cout << "Extra material Match " << i << std::endl;
+
+        GenericTubeMaker tubeHelper((*m_xMatTable)[i]);
+        const GeoMaterial* material = m_matManager->getMaterial(tubeHelper.volData().material());
+        const GeoShape* shape = tubeHelper.buildShape();
+        GeoLogVol* logVol = new GeoLogVol(volnamestr.str(), shape, material);
+        GeoPhysVol* physVol = new GeoPhysVol(logVol);
+
+        if (parent) {
+          tubeHelper.placeVolume(parent, physVol, zParent);
+        } else {
+          tubeHelper.placeVolume(fullparent, physVol, zParent);
+        }
+      }
+    }
+  }
+} // end namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/GenericTubeMaker.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/GenericTubeMaker.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5b7f54812e0e05d57041d9898d573be91dc65fed
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/GenericTubeMaker.cxx
@@ -0,0 +1,164 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/GenericTubeMaker.h"
+#include "NeutrinoGeoModelUtils/TubeVolData.h"
+
+#include "GeoModelKernel/GeoTube.h"
+#include "GeoModelKernel/GeoTubs.h"
+#include "GeoModelKernel/GeoCons.h"
+#include "GeoModelKernel/GeoPcon.h"
+#include "GeoModelKernel/GeoTransform.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include "RDBAccessSvc/IRDBRecord.h"
+
+namespace NeutrinoDD {
+  GenericTubeMaker::GenericTubeMaker(const IRDBRecord* record)
+    : m_record(record),
+    m_volData(record)
+  {}
+
+  std::string
+  GenericTubeMaker::materialName() const {
+    return m_record->getString("MATERIAL");
+  }
+
+  std::string
+  GenericTubeMaker::name() const {
+    return m_record->getString("NAME");
+  }
+
+  const GeoShape*
+  GenericTubeMaker::buildShape() {
+    const GeoShape* shape = 0;
+
+    switch (m_volData.shape()) {
+    case TubeVolData::TUBE:
+      shape = new GeoTube(m_volData.rmin(), m_volData.rmax(), 0.5 * m_volData.length());
+      break;
+
+    case TubeVolData::TUBS:
+      shape = new GeoTubs(m_volData.rmin(), m_volData.rmax(), 0.5 * m_volData.length(),
+                          m_volData.phiStart(), m_volData.phiDelta());
+      break;
+
+    case TubeVolData::CONS:
+      shape = new GeoCons(m_volData.rmin(), m_volData.rmin2(), m_volData.rmax(), m_volData.rmax2(),
+                          0.5 * m_volData.length(), m_volData.phiStart(), m_volData.phiDelta());
+      break;
+
+    case TubeVolData::RADIAL:
+      // This simulates the radial decrease in density.
+      double zstart = -0.5 * m_volData.length();
+      GeoPcon* shapeTmp = new GeoPcon(m_volData.phiStart(), m_volData.phiDelta());
+      shapeTmp->addPlane(zstart, m_volData.rmin(), m_volData.rmax());
+      double radialDelta = (m_volData.rmax() - m_volData.rmin()) / m_volData.radialDivisions();
+      for (int i = 0; i < m_volData.radialDivisions(); i++) {
+        double rIntermediate = m_volData.rmax() - i * radialDelta;
+        double reductionFactor = m_volData.rmin() / rIntermediate;
+        shapeTmp->addPlane(zstart + reductionFactor * m_volData.length(), m_volData.rmin(), rIntermediate);
+      }
+      shapeTmp->addPlane(zstart + m_volData.length(), m_volData.rmin(), m_volData.rmin());
+      shape = shapeTmp;
+      break;
+    }
+
+    return shape;
+  }
+
+  void
+  GenericTubeMaker::placeVolume(GeoPhysVol* parent, GeoVPhysVol* child, double zParent) {
+    placeVolume(parent, 0, child, zParent);
+  }
+
+  void
+  GenericTubeMaker::placeVolume(GeoFullPhysVol* fullparent, GeoVPhysVol* child, double zParent) {
+    placeVolume(0, fullparent, child, zParent);
+  }
+
+  void
+  GenericTubeMaker::placeVolTwoSide(GeoPhysVol* parentPos, GeoPhysVol* parentNeg, GeoVPhysVol* child, double zParent) {
+    placeVolTwoSide(parentPos, parentNeg, 0, 0, child, zParent);
+  }
+
+  void
+  GenericTubeMaker::placeVolTwoSide(GeoFullPhysVol* fullparentPos, GeoFullPhysVol* fullparentNeg, GeoVPhysVol* child,
+                                    double zParent) {
+    placeVolTwoSide(0, 0, fullparentPos, fullparentNeg, child, zParent);
+  }
+
+  void
+  GenericTubeMaker::placeVolume(GeoPhysVol* parent, GeoFullPhysVol* fullparent, GeoVPhysVol* child, double zParent) {
+    for (int iRepeat = 0; iRepeat < m_volData.nRepeat(); iRepeat++) {
+      double phi = m_volData.phiStep() * iRepeat;
+
+      GeoTransform* xform = 0;
+      double zOffset = m_volData.zMid() - zParent;
+      if (zOffset != 0 || iRepeat > 0) {
+        xform = new GeoTransform(GeoTrf::TranslateZ3D(zOffset) * GeoTrf::RotateZ3D(phi));
+      }
+
+      if (parent) {
+        if (xform) parent->add(xform);
+        parent->add(child);
+      } else {
+        if (xform) fullparent->add(xform);
+        fullparent->add(child);
+      }
+
+      // Place in negative z as well.
+      if (m_volData.bothZ()) {
+        GeoTransform* xformNeg = new GeoTransform(GeoTrf::RotateY3D(180 * Gaudi::Units::deg) * GeoTrf::TranslateZ3D(
+                                                    zOffset) * GeoTrf::RotateZ3D(phi));
+        if (parent) {
+          parent->add(xformNeg);
+          parent->add(child);
+        } else {
+          fullparent->add(xformNeg);
+          fullparent->add(child);
+        }
+      }
+    } // iRepeat loop
+  }
+
+  void
+  GenericTubeMaker::placeVolTwoSide(GeoPhysVol* parentPos, GeoPhysVol* parentNeg,
+                                    GeoFullPhysVol* fullparentPos, GeoFullPhysVol* fullparentNeg,
+                                    GeoVPhysVol* child, double zParent) {
+    for (int iRepeat = 0; iRepeat < m_volData.nRepeat(); iRepeat++) {
+      double phi = m_volData.phiStep() * iRepeat;
+      double zOffset = m_volData.zMid() - zParent;
+      const bool newXform((zOffset != 0)or(iRepeat > 0));
+
+      if (parentPos) {
+        if (newXform) {
+          parentPos->add(new GeoTransform(GeoTrf::TranslateZ3D(zOffset) * GeoTrf::RotateZ3D(phi)));
+        }
+        parentPos->add(child);
+      } else if (fullparentPos) {
+        if (newXform) {
+          fullparentPos->add(new GeoTransform(GeoTrf::TranslateZ3D(zOffset) * GeoTrf::RotateZ3D(phi)));
+        }
+        fullparentPos->add(child);
+      }
+
+      // Place in negative z as well.
+      if (m_volData.bothZ()) {
+        GeoTransform* xformNeg = new GeoTransform(GeoTrf::RotateY3D(180 * Gaudi::Units::deg) * GeoTrf::TranslateZ3D(
+                                                    zOffset) * GeoTrf::RotateZ3D(phi));
+        if (parentNeg) {
+          parentNeg->add(xformNeg);
+          parentNeg->add(child);
+        } else {
+          fullparentNeg->add(xformNeg);
+          fullparentNeg->add(child);
+        }
+      }
+    } // iRepeat loop
+  }
+}// end namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoDDAthenaComps.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoDDAthenaComps.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..40fdc37edc2825aec1afdd0c39b4ffc177b7960d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoDDAthenaComps.cxx
@@ -0,0 +1,35 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h"
+
+namespace NeutrinoDD {
+  AthenaComps::AthenaComps(const std::string& msgStreamName)
+    : m_msg(msgStreamName),
+    m_detStore(0),
+    m_geoDbTagSvc(0),
+    m_rdbAccessSvc(0),
+    m_geometryDBSvc(0)
+  {}
+
+  void
+  AthenaComps::setDetStore(StoreGateSvc* detStore) {
+    m_detStore = detStore;
+  }
+
+  void
+  AthenaComps::setGeoDbTagSvc(IGeoDbTagSvc* geoDbTagSvc) {
+    m_geoDbTagSvc = geoDbTagSvc;
+  }
+
+  void
+  AthenaComps::setRDBAccessSvc(IRDBAccessSvc* rdbAccessSvc) {
+    m_rdbAccessSvc = rdbAccessSvc;
+  }
+
+  void
+  AthenaComps::setGeometryDBSvc(IGeometryDBSvc* geometryDBSvc) {
+    m_geometryDBSvc = geometryDBSvc;
+  }
+}
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoMaterialManager.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoMaterialManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..475250a12eb0dafa33582344551f774cf9c3d44f
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/NeutrinoMaterialManager.cxx
@@ -0,0 +1,1042 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/NeutrinoMaterialManager.h"
+#include "NeutrinoGeoModelUtils/NeutrinoDDAthenaComps.h"
+#include "GeoModelInterfaces/AbsMaterialManager.h"
+#include "GeoModelInterfaces/StoredMaterialManager.h"
+#include "GeoModelKernel/GeoMaterial.h"
+#include "GeoModelKernel/GeoElement.h"
+#include "GeoModelKernel/Units.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "GeometryDBSvc/IGeometryDBSvc.h"
+#include "StoreGate/StoreGateSvc.h"
+
+#include <iostream>
+#include <iomanip>
+#include <cmath>
+#include <stdexcept>
+
+// Constructor
+NeutrinoMaterialManager::NeutrinoMaterialManager(const std::string& managerName,
+                                           StoreGateSvc* detStore)
+  : m_managerName(managerName),
+  m_msg(managerName),
+  m_extraFunctionality(false),
+  m_athenaComps(0) {
+  m_materialManager = retrieveManager(detStore);
+}
+
+// Constructor
+NeutrinoMaterialManager::NeutrinoMaterialManager(const std::string& managerName,
+                                           StoreGateSvc* detStore,
+                                           IRDBRecordset_ptr weightTable,
+                                           const std::string& space,
+                                           bool extraFunctionality)
+  : m_managerName(managerName),
+  m_msg(managerName),
+  m_extraFunctionality(extraFunctionality),
+  m_athenaComps(0) {
+  m_materialManager = retrieveManager(detStore);
+
+  if (weightTable) addWeightTable(weightTable, space);
+
+  // For testing we add a few materials.
+  //m_weightMap["veto::CoolingBlock"] = MaterialByWeight(2.418*CLHEP::gram);
+  //m_weightMap["veto::CoolingBlock"] = MaterialByWeight(2*CLHEP::gram);
+  //m_weightMap["veto::BrlHybrid"] = MaterialByWeight("veto::Hybrid", 8*CLHEP::gram);
+  //m_weightMap["veto::FwdHybrid"] = MaterialByWeight("std::Carbon", 7.662*CLHEP::gram);
+}
+
+NeutrinoMaterialManager::NeutrinoMaterialManager(const std::string& managerName, StoreGateSvc* detStore,
+                                           IRDBRecordset_ptr weightTable,
+                                           IRDBRecordset_ptr compositionTable,
+                                           const std::string& space)
+  : m_managerName(managerName),
+  m_msg(managerName),
+  m_extraFunctionality(true),
+  m_athenaComps(0) {
+  m_materialManager = retrieveManager(detStore);
+
+  if (weightTable) addWeightTable(weightTable, space);
+  if (compositionTable) addCompositionTable(compositionTable, space);
+}
+
+NeutrinoMaterialManager::NeutrinoMaterialManager(const std::string& managerName,
+                                           const NeutrinoDD::AthenaComps* athenaComps)
+  : m_managerName(managerName),
+  m_msg(managerName),
+  m_extraFunctionality(true),
+  m_athenaComps(athenaComps) {
+  m_materialManager = retrieveManager(athenaComps->detStore());
+  addTextFileMaterials();
+}
+
+NeutrinoMaterialManager::~NeutrinoMaterialManager() {
+  // Dereference the materials.
+  MaterialStore::const_iterator iter;
+  for (iter = m_store.begin(); iter != m_store.end(); ++iter) {
+    iter->second->unref();
+  }
+}
+
+const AbsMaterialManager*
+NeutrinoMaterialManager::retrieveManager(StoreGateSvc* detStore) {
+  const StoredMaterialManager* theGeoMaterialManager = nullptr;
+
+  if (StatusCode::SUCCESS != detStore->retrieve(theGeoMaterialManager, "MATERIALS")) {
+    msg(MSG::FATAL) << "Cannot locate Materials";
+  }
+
+  return theGeoMaterialManager;
+}
+
+const GeoElement*
+NeutrinoMaterialManager::getElement(const std::string& elementName) const {
+  return m_materialManager->getElement(elementName);
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterial(const std::string& materialName) {
+  return extraScaledMaterial(materialName, getMaterialInternal(materialName));
+}
+
+bool
+NeutrinoMaterialManager::hasMaterial(const std::string& materialName) const {
+  return m_store.find(materialName) != m_store.end();
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialInternal(const std::string& materialName) const {
+  // First check local store of materials. If not found then get it from the GeoModel
+  // manager.
+  const GeoMaterial* material = getAdditionalMaterial(materialName);
+
+  if (!material) {
+    // This prints error message if not found.
+    material = m_materialManager->getMaterial(materialName);
+  }
+  return material;
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getAdditionalMaterial(const std::string& materialName) const {
+  MaterialStore::const_iterator iter;
+  if ((iter = m_store.find(materialName)) != m_store.end()) {
+    return iter->second;
+  } else {
+    return 0;
+  }
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getCompositeMaterialForVolume(const std::string& newMatName,
+                                                    const double volumeTot,
+                                                    const double volume1, const std::string& matName1,
+                                                    const double volume2, const std::string& matName2
+                                                    ) {
+  std::vector<std::string> baseMaterials;
+  std::vector<double> fracWeight;
+  baseMaterials.reserve(2);
+  fracWeight.reserve(2);
+
+  msg(MSG::DEBUG) << "Composite material : " << volumeTot / Gaudi::Units::cm3 << " = " << volume1 / Gaudi::Units::cm3 << " + " <<
+    volume2 / Gaudi::Units::cm3 << endmsg;
+  msg(MSG::DEBUG) << "Composite material : " << matName1 << " " << matName2 << endmsg;
+
+  double density1, density2;
+
+  MaterialWeightMap::const_iterator iter;
+  if ((iter = m_weightMap.find(matName1)) != m_weightMap.end()) {
+    const GeoMaterial* mat1 = getMaterialForVolume(matName1, volume1);
+    density1 = mat1->getDensity();
+    msg(MSG::DEBUG) << "Composite material 1 - weight : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+  } else {
+    const GeoMaterial* mat1 = getMaterial(matName1);
+    density1 = mat1->getDensity();
+    msg(MSG::DEBUG) << "Composite material 1 - standard : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+  }
+
+  if ((iter = m_weightMap.find(matName2)) != m_weightMap.end()) {
+    const GeoMaterial* mat2 = getMaterialForVolume(matName2, volume2);
+    density2 = mat2->getDensity();
+    msg(MSG::DEBUG) << "Composite material 2 - weight : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+  } else {
+    const GeoMaterial* mat2 = getMaterial(matName2);
+    density2 = mat2->getDensity();
+    msg(MSG::DEBUG) << "Composite material 2 - standard : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+  }
+
+  double weight1 = density1 * volume1;
+  double weight2 = density2 * volume2;
+  double invWeightTot = 1.0 / (weight1 + weight2);
+
+  double density = (weight1 + weight2) / volumeTot;
+
+  double frac1 = weight1 / (weight1 + weight2);
+  double frac2 = weight2 / (weight1 + weight2);
+  double density_2 = 1.0 / (frac1 / density1 + frac2 / density2);
+  double density_3 = (weight1 + weight2) / (volume1 + volume2);
+  msg(MSG::DEBUG) << "-> weights : " << weight1 / (GeoModelKernelUnits::gram) << " " << weight2 / (GeoModelKernelUnits::gram) << endmsg;
+  msg(MSG::DEBUG) << "-> density : " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << "  " << density_2 /
+  (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << " " << density_3 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+
+
+  baseMaterials.push_back(matName1);
+  baseMaterials.push_back(matName2);
+  fracWeight.push_back(weight1 * invWeightTot);
+  fracWeight.push_back(weight2 * invWeightTot);
+
+  return getMaterial(newMatName, baseMaterials, fracWeight, density);
+}
+
+// This creates a new material with specified density.
+
+// If a newName is supplied it creates the new material even if the orginal material
+// has the same density. It however first checks if the material with NewName exists.
+
+// If no new name is supplied then it checks the density of
+// the existing material. If it is consistent it returns the material.
+// If it is different it creates a material with the string "Modified" added to the
+// name.
+
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterial(const std::string& origMaterialName,
+                                  double density,
+                                  const std::string& newName) {
+  return extraScaledMaterial(origMaterialName, newName,
+                             getMaterialInternal(origMaterialName, density, newName));
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialInternal(const std::string& origMaterialName,
+                                          double density,
+                                          const std::string& newName) {
+  std::string newName2 = newName;
+  bool newNameProvided = !newName2.empty();
+  if (!newNameProvided) {
+    newName2 = origMaterialName + "Modified";
+  }
+
+  const GeoMaterial* newMaterial = 0;
+
+  // First see if we already have the modified material
+  const GeoMaterial* material = getAdditionalMaterial(newName2);
+  if (material) {
+    if (!compareDensity(material->getDensity(), density)) {
+      msg(MSG::WARNING) << "Density is not consistent for material " << newName2
+                        << "  " << material->getDensity() / (GeoModelKernelUnits::gram / Gaudi::Units::cm3)
+                        << " / " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << endmsg;
+    }
+    newMaterial = material;
+  } else {
+    const GeoMaterial* origMaterial = getMaterialInternal(origMaterialName);
+    newMaterial = origMaterial;
+    if (origMaterial) {
+      // If no new name was provided we check if the density is compatible
+      // and if so we return the original material.
+      if (newNameProvided || !compareDensity(origMaterial->getDensity(), density)) {
+        // create new material
+        GeoMaterial* newMaterialTmp = new GeoMaterial(newName2, density);
+        newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), 1.);
+        addMaterial(newMaterialTmp);
+        newMaterial = newMaterialTmp;
+      }
+    }
+  }
+  return newMaterial;
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialScaled(const std::string& origMaterialName,
+                                        double scaleFactor,
+                                        const std::string& newName) {
+  return extraScaledMaterial(origMaterialName, newName,
+                             getMaterialScaledInternal(origMaterialName, scaleFactor, newName));
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialScaledInternal(const std::string& origMaterialName,
+                                                double scaleFactor,
+                                                const std::string& newName) {
+  // Don't allow large scale factors
+  if (scaleFactor > 1000 || scaleFactor < 0.001) {
+    msg(MSG::ERROR) << "Scale factor must be between 0.001 and 1000." << endmsg;
+    return 0;
+  }
+
+  const GeoMaterial* origMaterial = getMaterialInternal(origMaterialName);
+
+  // If scalefactor is 1 and no new name is requested
+  // then just return the orginal material
+  if (newName.empty() && scaleFactor == 1.) return origMaterial;
+
+  const GeoMaterial* newMaterial = 0;
+
+  if (origMaterial) {
+    double density = origMaterial->getDensity() * scaleFactor;
+    std::string newName2 = newName;
+    if (newName2.empty()) {
+      // Create name using the scale factor.
+      int scaleInt = static_cast<int>(scaleFactor * 10000);
+      int scale1 = scaleInt / 10000;
+      int scale2 = scaleInt % 10000;
+
+      std::ostringstream os;
+      os << origMaterialName << scale1 << "_" << std::setw(4) << std::setfill('0') << scale2;
+      newName2 = os.str();
+    }
+
+    newMaterial = getMaterialInternal(origMaterialName, density, newName2);
+  }
+
+  return newMaterial;
+}
+
+void
+NeutrinoMaterialManager::addMaterial(GeoMaterial* material) {
+  std::string name(material->getName());
+  if (m_store.find(name) != m_store.end()) {
+    msg(MSG::WARNING) << "Ignoring attempt to redefine an existing material: " << name << endmsg;
+    // Delete the material if it is not already ref counted.
+    material->ref();
+    material->unref();
+    //std::cout << m_store[name] << std::endl;
+  } else {
+    material->lock();
+    material->ref();
+    m_store[name] = material;
+
+    if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Created new material: " << name << ", " << material->getDensity() /
+      (Gaudi::Units::g / Gaudi::Units::cm3) << " g/cm3" << endmsg;
+  }
+}
+
+bool
+NeutrinoMaterialManager::compareDensity(double d1, double d2) const {
+  return(std::abs(d1 / d2 - 1.) < 1e-5);
+}
+
+void
+NeutrinoMaterialManager::addWeightTable(IRDBRecordset_ptr weightTable, const std::string& space) {
+  if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Reading in weight table: " << weightTable->nodeName() << endmsg;
+  // If not using geometryDBSvc revert to old version
+  if (!db()) {
+    if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "GeometryDBSvc not available. Using old version." << endmsg;
+    addWeightTableOld(weightTable, space);
+    return;
+  }
+  for (unsigned int i = 0; i < db()->getTableSize(weightTable); i++) {
+    std::string materialName = db()->getString(weightTable, "MATERIAL", i);
+    if (!space.empty()) {
+      materialName = space + "::" + materialName;
+    }
+    std::string materialBase;
+    if (db()->testField(weightTable, "BASEMATERIAL", i)) {
+      materialBase = db()->getString(weightTable, "BASEMATERIAL", i);
+    }
+    double weight = db()->getDouble(weightTable, "WEIGHT", i) * GeoModelKernelUnits::gram;
+    //std::cout << materialName << " " << materialBase << " " << weight/CLHEP::g <<  std::endl;
+
+    bool linearWeightFlag = false;
+    if (m_extraFunctionality && db()->testField(weightTable, "LINWEIGHTFLAG", i)) {
+      linearWeightFlag = db()->getInt(weightTable, "LINWEIGHTFLAG", i);
+    }
+
+    if (m_weightMap.find(materialName) != m_weightMap.end()) {
+      msg(MSG::WARNING) << "Material: " << materialName << " already exists in weight table" << endmsg;
+    } else {
+      msg(MSG::DEBUG) << "Adding " << materialName
+                      << " weight " << weight
+                      << " linearWeightFlag " << linearWeightFlag
+                      << " raw weight " << db()->getDouble(weightTable, "WEIGHT", i)
+                      << " m_extraFunctionality " << m_extraFunctionality
+                      << " to weight table" << endmsg;
+      m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
+    }
+  }
+}
+
+void
+NeutrinoMaterialManager::addWeightMaterial(std::string materialName, std::string materialBase, double weight,
+                                        int linearWeightFlag) {
+  // Weight in gr
+  weight = weight * GeoModelKernelUnits::gram;
+
+  if (m_weightMap.find(materialName) != m_weightMap.end()) {
+    msg(MSG::WARNING) << "Material: " << materialName << " already exists in weight table" << endmsg;
+  } else {
+    msg(MSG::DEBUG) << "Adding " << materialName
+                    << " weight " << weight
+                    << " linearWeightFlag " << linearWeightFlag
+                    << " to weight table" << endmsg;
+    m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
+  }
+}
+
+void
+NeutrinoMaterialManager::addWeightTableOld(IRDBRecordset_ptr weightTable, const std::string& space) {
+  for (unsigned int i = 0; i < weightTable->size(); i++) {
+    const IRDBRecord* record = (*weightTable)[i];
+    std::string materialName = record->getString("MATERIAL");
+    if (!space.empty()) {
+      materialName = space + "::" + materialName;
+    }
+    std::string materialBase;
+    if (!record->isFieldNull("BASEMATERIAL")) {
+      materialBase = record->getString("BASEMATERIAL");
+    }
+    double weight = record->getDouble("WEIGHT") * GeoModelKernelUnits::gram;
+    //std::cout << materialName << " " << materialBase << " " << weight/CLHEP::g <<  std::endl;
+
+    bool linearWeightFlag = false;
+    if (m_extraFunctionality) {
+      linearWeightFlag = record->getInt("LINWEIGHTFLAG");
+    }
+
+    if (m_weightMap.find(materialName) != m_weightMap.end()) {
+      msg(MSG::WARNING) << "Material: " << materialName << " already exists in weight table" << endmsg;
+    } else {
+      m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
+    }
+  }
+}
+
+void
+NeutrinoMaterialManager::addCompositionTable(IRDBRecordset_ptr compositionTable, const std::string& space) {
+  if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Reading in composition table: " << compositionTable->nodeName() << endmsg;
+
+  if (!db()) {
+    msg(MSG::ERROR) << "GeometryDBSvc not available. Unable to read in composition table." << endmsg;
+  }
+  for (unsigned int i = 0; i < db()->getTableSize(compositionTable); i++) {
+    std::string materialName = db()->getString(compositionTable, "MATERIAL", i);
+    if (!space.empty()) {
+      materialName = space + "::" + materialName;
+    }
+
+    std::string componentName = db()->getString(compositionTable, "COMPONENT", i);
+    int count = db()->getInt(compositionTable, "COUNT", i);
+    double factor = db()->getDouble(compositionTable, "FACTOR", i);
+    double actualLength = db()->getDouble(compositionTable, "ACTUALLENGTH", i);
+
+    m_matCompositionMap.insert(std::pair<std::string, MaterialComponent>(materialName,
+                                                                         MaterialComponent(componentName,
+                                                                                           count * factor,
+                                                                                           actualLength)));
+  }
+}
+
+void
+NeutrinoMaterialManager::addScalingTable(IRDBRecordset_ptr scalingTable) {
+  if (!scalingTable) return;
+
+  if (db()->getTableSize(scalingTable) == 0) return;
+
+  if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Reading in extra material scaling table: " << scalingTable->nodeName() <<
+    endmsg;
+  if (!db()) {
+    msg(MSG::ERROR) << "GeometryDBSvc not available. Unable to read in scaling table." << endmsg;
+  }
+  for (unsigned int i = 0; i < db()->getTableSize(scalingTable); i++) {
+    std::string materialName = db()->getString(scalingTable, "MATERIAL", i);
+    double scalingFactor = db()->getDouble(scalingTable, "FACTOR", i);
+
+    if (msgLvl(MSG::DEBUG)) {
+      if (scalingFactor >= 0 || scalingFactor == 1) {
+        msg(MSG::DEBUG) << "Material " << materialName << " will be scaled by: " << scalingFactor << endmsg;
+      } else {
+        // -ve or scalefactor = 1 means will not be scaled.
+        msg(MSG::DEBUG) << "Material " << materialName << " will be NOT be scaled." << endmsg;
+      }
+    }
+    if (m_scalingMap.find(materialName) != m_scalingMap.end()) {
+      msg(MSG::WARNING) << "Overriding material: " << materialName << " which already exists in scaling table" <<
+      endmsg;
+    }
+    m_scalingMap[materialName] = scalingFactor;
+  }
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialForVolume(const std::string& materialName, double volume, const std::string& newName) {
+  // Make sure we have a valid volume size.
+  if (volume <= 0) {
+    msg(MSG::ERROR) << "Invalid volume : " << volume << endmsg;
+    return 0;
+  }
+
+  // Find if material is in the weight table.
+  // If so we use the information to create a material with the
+  // density calculated from the volume and weight. If a base material
+  // is specified in the weight table, then a new material is made
+  // which is the same as the base material but with the new
+  // density. If no base material is specified then there should be a
+  // material already existing with that name. If the existing material already has the
+  // correct density it is used, otherwise a new material is created
+  // with the string "Modified" added to the material name.
+
+  MaterialWeightMap::const_iterator iter;
+  if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
+    const std::string& materialBase = iter->second.name;
+    double weight = iter->second.weight;
+    double density = weight / volume;
+    if (iter->second.linearWeightFlag) {
+      msg(MSG::ERROR) << "Material defined by linear weight cannot be created with getMaterialForVolume method: " <<
+      materialName << endmsg;
+    }
+
+    if (msgLvl(MSG::VERBOSE)) {
+      msg(MSG::VERBOSE)
+        <<
+      "Found material in weight table - name, base, weight(g), volume(cm3), density(g/cm3): "
+        << materialName << ", "
+        << materialBase << ", "
+        << weight / GeoModelKernelUnits::gram << ", "
+        << volume / Gaudi::Units::cm3 << ", "
+        << density / (Gaudi::Units::g / Gaudi::Units::cm3) << endmsg;
+    }
+
+    if (materialBase.empty()) {
+      return getMaterial(materialName, density, newName);
+    } else {
+      if (newName.empty()) {
+        return getMaterial(materialBase, density, materialName);
+      } else {
+        return getMaterial(materialBase, density, newName);
+      }
+    }
+  } else {
+    // If not in the weight table we just return the material.
+    // This is not an error.
+    if (msgLvl(MSG::VERBOSE))
+      msg(MSG::VERBOSE)
+        << "Material not in weight table, using standard material: "
+        << materialName
+        << ", volume(cm3) = " << volume / Gaudi::Units::cm3
+        << endmsg;
+    return getMaterial(materialName);
+  }
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialForVolumeLength(const std::string& materialName, double volume, double length,
+                                                 const std::string& newName) {
+  // In the case there is no material composition table (MaterialCompositionMap) and no linear weights are used this
+  // will
+  // behave the same way as getMaterialForVolume.
+  // If the material is in the MaterialCompositionMap it will build a material using the components
+  // from that table. If any components are defined as a linear weight the length is used to calculate the
+  // weight (ie linear weight * length).
+
+
+  std::string name;
+  if (newName.empty()) {
+    name = materialName;
+  } else {
+    name = newName;
+  }
+
+  // Make sure we have a valid volume size.
+  if (volume <= 0 || length <= 0) {
+    msg(MSG::ERROR) << "Invalid volume or length : " << volume << ", " << length << endmsg;
+    return 0;
+  }
+
+  // First look in the predefinded collections
+  std::pair<MaterialCompositionMap::const_iterator, MaterialCompositionMap::const_iterator> iterRange;
+  iterRange = m_matCompositionMap.equal_range(materialName);
+  if (iterRange.first != m_matCompositionMap.end()) {
+    if (msgLvl(MSG::VERBOSE)) {
+      msg(MSG::VERBOSE)
+        << "Found material in material composition table:" << materialName << endmsg;
+    }
+
+    std::vector<double> factors;
+    std::vector<std::string> components;
+    for (MaterialCompositionMap::const_iterator iter = iterRange.first; iter != iterRange.second; iter++) {
+      double factorTmp = iter->second.factor;
+      if (iter->second.actualLength > 0) factorTmp *= iter->second.actualLength / length;
+      factors.push_back(factorTmp);
+      components.push_back(iter->second.name);
+    }
+    return getMaterialForVolumeLength(name, components, factors, volume, length);
+  }
+
+  // Next look in weight table
+  MaterialWeightMap::const_iterator iter;
+  if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
+    const std::string& materialBase = iter->second.name;
+    double weight = iter->second.weight;
+    double density = weight / volume;
+    if (iter->second.linearWeightFlag) weight *= length;
+
+    if (materialBase.empty()) {
+      return getMaterial(materialName, density, newName);
+    } else {
+      return getMaterial(materialBase, density, name);
+    }
+  } else {
+    // Otherwise we just return the material.
+    // This is not an error.
+    if (msgLvl(MSG::VERBOSE))
+      msg(MSG::VERBOSE)
+        << "Material not in weight table, using standard material: "
+        << materialName
+        << ", volume(cm3) = " << volume / Gaudi::Units::cm3
+        << endmsg;
+    return getMaterial(materialName);
+  }
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialForVolumeLength(const std::string& name,
+                                                 const std::string& materialComponent,
+                                                 double factor,
+                                                 double volume,
+                                                 double length) {
+  std::vector<std::string> tmpMaterialComponents(1, materialComponent);
+  std::vector<double> tmpFactors(1, factor);
+  return getMaterialForVolumeLength(name, tmpMaterialComponents, tmpFactors, volume, length);
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialForVolumeLength(const std::string& name,
+                                                 const std::vector<std::string>& materialComponents,
+                                                 const std::vector<double> factors,
+                                                 double volume,
+                                                 double length) {
+  // Make sure we have a valid volume size.
+  if (volume <= 0 || length <= 0) {
+    msg(MSG::ERROR) << "Invalid volume or length : " << volume << ", " << length << endmsg;
+    return 0;
+  }
+
+  if (!factors.empty() && factors.size() < materialComponents.size()) {
+    msg(MSG::WARNING) << "getMaterialForVolumeLength: factor vector size too small. Setting remaining factors to 1." <<
+    endmsg;
+  }
+
+  std::vector<std::string> baseMaterials;
+  std::vector<double> fracWeight;
+  baseMaterials.reserve(materialComponents.size());
+  fracWeight.reserve(materialComponents.size());
+
+  double totWeight = 0;
+  for (unsigned int iComp = 0; iComp < materialComponents.size(); ++iComp) {
+    const std::string& materialName = materialComponents[iComp];
+
+    // First search in MaterialWeightMap
+    MaterialWeightMap::const_iterator iter;
+    if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
+      const std::string& materialBase = iter->second.name;
+      double weight = iter->second.weight;
+
+      if (iComp < factors.size()) {
+        weight *= factors[iComp];
+      }
+      msg(MSG::DEBUG) << "Material " << materialName
+                      << " found in weight table, weight " << iter->second.weight / GeoModelKernelUnits::gram
+                      << " factor " << factors[iComp]
+                      << " w*fac*len " << weight * length / GeoModelKernelUnits::gram
+                      << " basMat " << materialBase
+                      << " linear? " << iter->second.linearWeightFlag << endmsg;
+
+      if (iter->second.linearWeightFlag) weight *= length;
+      if (materialBase.empty()) {
+        // If no base material then name should refer to an already defined material
+        baseMaterials.push_back(materialName);
+      } else {
+        baseMaterials.push_back(materialBase);
+      }
+      fracWeight.push_back(weight); // Will be normalized later.
+      totWeight += weight;
+    } else {
+      // If not in the weight table we look for a regular material.
+      // I don't think this would normally be intentional so we give a warning message.
+      /*
+         if (msgLvl(MSG::WARNING))
+         msg(MSG::WARNING)
+         << "Component material not in weight table, using standard material: "
+         << materialName << " with weight= "
+         << factors.at(iComp) * length
+         << endmsg;
+         const GeoMaterial * material = getMaterialInternal(materialName);
+       */
+
+      // In this case the factor should correspond to the linear weight
+      double weight = factors.at(iComp) * length * GeoModelKernelUnits::gram;
+
+      // If material not found, will get error message when attempting to make the material. So carry on here.
+      baseMaterials.push_back(materialName);
+      fracWeight.push_back(weight);
+      totWeight += weight;
+    }
+  }
+
+  if (msgLvl(MSG::VERBOSE)) {
+    msg(MSG::VERBOSE) << "Creating material from multiple components: " << name << endmsg;
+    for (unsigned int i = 0; i < materialComponents.size(); ++i) {
+      msg(MSG::VERBOSE) << " Component " << i << ": Name = " << baseMaterials[i]
+                        << " Weight(g) = " << fracWeight[i] / Gaudi::Units::g << endmsg;
+    }
+  }
+
+  for (unsigned int i = 0; i < fracWeight.size(); ++i) {
+    fracWeight[i] /= totWeight;
+  }
+  double density = totWeight / volume;
+
+  return getMaterial(name, baseMaterials, fracWeight, density);
+}
+
+// Add materials assuming they simply occupy the same volume.
+/*
+   const GeoMaterial*
+   NeutrinoMaterialManager::getMaterial(const std::vector<const GeoMaterial *> & materialComponents,
+                  const std::string & newName)
+   {
+   const GeoMaterial * newMaterial = 0;
+   std::vector<double> fracWeight;
+   fracWeight.reserve(materialComponents.size());
+
+   for (unsigned int i = 0; i < materialComponents.size(); i++) {
+    const GeoMaterial * origMaterial = materialComponents[i];
+    double weight = origMaterial->getDensity();
+    fracWeight.push_back(weight);
+    totWeight += weight;
+   }
+   for (unsigned int i = 0; i < fracWeight.size(); ++i) {
+    fracWeight[i] /= totWeight;
+   }
+   return getMaterial(materialComponents, fracWeight, totWeight, newName);
+   }
+
+   const GeoMaterial*
+   NeutrinoMaterialManager::getMaterial(const std::vector<std::string> & materialComponents,
+                  const std::string & newName)
+   {
+   const GeoMaterial * newMaterial = 0;
+
+   // First see if we already have the modified material
+   const GeoMaterial* material = getAdditionalMaterial(newName);
+
+   for (unsigned int i = 0; i < materialComponents.size(); i++) {
+    const GeoMaterial * origMaterial = getMaterial(materialComponents[i]);
+    components.push_back(origMaterial);
+   }
+   return getMaterial(components,  newName);
+   }
+ */
+
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterial(const std::string& name,
+                                  const std::vector<std::string>& materialComponents,
+                                  const std::vector<double>& fracWeight,
+                                  double density) {
+  return extraScaledMaterial(name, getMaterialInternal(name, materialComponents, fracWeight, density));
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::getMaterialInternal(const std::string& name,
+                                          const std::vector<std::string>& materialComponents,
+                                          const std::vector<double>& fracWeight,
+                                          double density) {
+  const GeoMaterial* newMaterial = 0;
+
+  // First see if we already have the material
+  const GeoMaterial* material = getAdditionalMaterial(name);
+
+  if (material) {
+    if (!compareDensity(material->getDensity(), density)) {
+      msg(MSG::WARNING) << "Density is not consistent for material " << name << endmsg;
+    }
+    newMaterial = material;
+  } else {
+    GeoMaterial* newMaterialTmp = new GeoMaterial(name, density);
+    for (unsigned int i = 0; i < materialComponents.size(); i++) {
+      const GeoMaterial* origMaterial = getMaterialInternal(materialComponents[i]);
+      if (origMaterial) {
+        newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), fracWeight[i]);
+      } else {
+        msg(MSG::ERROR) << "Material component missing " << materialComponents[i] << endmsg;
+      }
+    }
+    addMaterial(newMaterialTmp);
+    newMaterial = newMaterialTmp;
+  }
+  return newMaterial;
+}
+
+const IGeometryDBSvc*
+NeutrinoMaterialManager::db() {
+  if (m_athenaComps) return m_athenaComps->geomDB();
+
+  return 0;
+}
+
+void
+NeutrinoMaterialManager::addTextFileMaterials() {
+  const std::string materialTable = "ExtraMaterials";
+  const std::string componentsTable = "ExtraMatComponents";
+
+  // Look for tables ExtraMaterials and ExtraMatComponents.
+  // These are text file only tables where extra materials are desired or
+  // one wants to override some database ones.
+  if (!db() || !db()->testField("", "TableSize:" + materialTable) || !db()->getTableSize(materialTable)
+      || !db()->testField("", "TableSize:" + componentsTable) || !db()->getTableSize(componentsTable)) return;
+
+
+  msg(MSG::INFO) << "Extra materials being read in from text file." << endmsg;
+
+  typedef std::map<std::string, MaterialDef> MatMap;
+  MatMap materials;
+
+  // read in material table
+  for (unsigned int iMat = 0; iMat < db()->getTableSize(materialTable); iMat++) {
+    std::string materialName = db()->getString(materialTable, "NAME", iMat);
+    double density = db()->getDouble(materialTable, "DENSITY", iMat) * Gaudi::Units::g / Gaudi::Units::cm3;
+    materials[materialName] = MaterialDef(materialName, density);
+  }
+
+  // read in material component table
+  for (unsigned int iComp = 0; iComp < db()->getTableSize(componentsTable); iComp++) {
+    std::string materialName = db()->getString(componentsTable, "NAME", iComp);
+    std::string compName = db()->getString(componentsTable, "COMPNAME", iComp);
+    double fracWeight = db()->getDouble(componentsTable, "FRACTION", iComp);
+    MatMap::iterator iter = materials.find(materialName);
+    if (iter != materials.end()) {
+      iter->second.addComponent(compName, fracWeight);
+    } else {
+      msg(MSG::ERROR) << "Attemp to add material component, " << compName << ", to non-existing material: " <<
+      materialName << endmsg;
+    }
+  }
+
+  //Now create the materials
+  int matCount = 0;
+  int matCountLast = -1;
+  bool someUndefined = true;
+  // While there are still undefined materials keep creating materials.
+  // Check also that the matCount had change to avoid endless loop due to cyclicly
+  // defined materials.
+  while (someUndefined && matCount != matCountLast) {
+    matCountLast = matCount;
+    someUndefined = false;
+    for (MatMap::iterator iter = materials.begin(); iter != materials.end(); ++iter) {
+      MaterialDef& tmpMat = iter->second;
+      if (!tmpMat.isCreated()) {
+        // Check if any components are materials in this table and if they are defined.
+        // If not flag that there are undefined materials and go to next material
+        bool compsDefined = true;
+        for (unsigned int iComp = 0; iComp < tmpMat.numComponents(); ++iComp) {
+          std::string compName = tmpMat.compName(iComp);
+          MatMap::iterator iter2 = materials.find(compName);
+          if (iter2 != materials.end()) {
+            if (!iter2->second.isCreated()) {
+              compsDefined = false;
+              break;
+            }
+          }
+        }
+        if (compsDefined) {
+          createMaterial(tmpMat);
+          tmpMat.setCreated();
+          matCount++;
+        } else {
+          someUndefined = true;
+        }
+      }
+    }
+  }
+
+
+  if (someUndefined) {
+    msg(MSG::ERROR) << "Not all materials could be defined due to cyclic definitions" << endmsg;
+  }
+}
+
+void
+NeutrinoMaterialManager::createMaterial(const MaterialDef& material) {
+  if (material.numComponents() == 0) {
+    msg(MSG::ERROR) << "Material has no components: " << material.name() << endmsg;
+    return;
+  }
+
+  // If total of fractions is greater than 1.1 then assume material is define by ratio of atoms.
+  double totWeight = material.totalFraction();
+  bool byAtomicRatio = false;
+  if (totWeight > 1.1) {
+    byAtomicRatio = true;
+    for (unsigned int i = 0; i < material.numComponents(); i++) {
+      if (material.compName(i).find("::") != std::string::npos) {
+        // If component name has "::" in it then its not an element.
+        msg(MSG::ERROR) << "Material, " << material.name()
+                        <<
+        ", is assumed to be defined by atomic ratio (due to total fraction > 1) but component is not an element: "
+                        << material.compName(i) << endmsg;
+        return;
+      }
+      const GeoElement* element = getElement(material.compName(i));
+      if (!element) {
+        msg(MSG::ERROR) << "Error making material " << material.name() << ". Element not found: " <<
+        material.compName(i) << endmsg;
+        return;
+      }
+      totWeight += material.fraction(i) * element->getA();
+    }
+  } else {
+    // Check if total fraction is close to 1.
+    if (std::abs(totWeight - 1) > 0.01) {
+      msg(MSG::WARNING) << "Total fractional weight does not sum to 1. Will renormalize. Total = " << totWeight <<
+      endmsg;
+    }
+  }
+  // Now build the material
+  GeoMaterial* newMaterial = new GeoMaterial(material.name(), material.density());
+  if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Creating material: " << material.name()
+                                          << " with density: " << material.density() / (Gaudi::Units::g / Gaudi::Units::cm3) <<
+    endmsg;
+  for (unsigned int i = 0; i < material.numComponents(); i++) {
+    double fracWeight = material.fraction(i) / totWeight;
+    if (material.compName(i).find("::") == std::string::npos) {
+      const GeoElement* element = getElement(material.compName(i));
+      if (!element) {
+        msg(MSG::ERROR) << "Error making material " << material.name() << ". Element not found: " <<
+        material.compName(i) << endmsg;
+        // delete the partially created material
+        newMaterial->ref();
+        newMaterial->unref();
+        return;
+      }
+      if (byAtomicRatio) {
+        fracWeight = material.fraction(i) * element->getA() / totWeight;
+      }
+      newMaterial->add(const_cast<GeoElement*>(element), fracWeight);
+      if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << " Component: " << material.compName(i) << " " << fracWeight << endmsg;
+    } else {
+      const GeoMaterial* materialTmp = getMaterialInternal(material.compName(i));
+      if (!materialTmp) {
+        msg(MSG::ERROR) << "Error making material " << material.name() << ". Component not found: " <<
+        material.compName(i) << endmsg;
+        // delete the partially created material
+        newMaterial->ref();
+        newMaterial->unref();
+        return;
+      }
+      if (byAtomicRatio) {
+        // Should not happen as already checked that all components were elements.
+        msg(MSG::ERROR) << "Unexpected Error" << endmsg;
+      }
+      newMaterial->add(const_cast<GeoMaterial*>(materialTmp), fracWeight);
+      if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << " Component: " << material.compName(i) << " " << fracWeight << endmsg;
+    }
+  }
+  newMaterial->lock();
+  addMaterial(newMaterial);
+}
+
+NeutrinoMaterialManager::MaterialDef::MaterialDef()
+  : m_density(0),
+  m_created(false)
+{}
+
+NeutrinoMaterialManager::MaterialDef::MaterialDef(const std::string& name, double density)
+  : m_name(name),
+  m_density(density),
+  m_created(false)
+{}
+
+void
+NeutrinoMaterialManager::MaterialDef::addComponent(const std::string& compName, double fraction) {
+  m_components.push_back(compName);
+  m_fractions.push_back(fraction);
+}
+
+double
+NeutrinoMaterialManager::MaterialDef::totalFraction() const {
+  double sum = 0;
+
+  for (unsigned int i = 0; i < m_fractions.size(); i++) {
+    sum += m_fractions[i];
+  }
+  return sum;
+}
+
+// We need the original name as the GeoMaterial from the standard
+// material manager has its namespace dropped.  We have two versions
+// of extraScaledMaterial. One where two names are provided. In this
+// version if newName is not empty that is used, otherwise
+// materialName is used.  The other just has one name and that is the
+// one that is used.
+
+const GeoMaterial*
+NeutrinoMaterialManager::extraScaledMaterial(const std::string& materialName,
+                                          const std::string& newName,
+                                          const GeoMaterial* origMaterial) {
+  if (newName.empty()) {
+    return extraScaledMaterial(materialName, origMaterial);
+  } else {
+    return extraScaledMaterial(newName, origMaterial);
+  }
+}
+
+const GeoMaterial*
+NeutrinoMaterialManager::extraScaledMaterial(const std::string& materialName, const GeoMaterial* origMaterial) {
+  if (!origMaterial) throw std::runtime_error(std::string("Invalid material: ") + materialName);
+
+  double scaleFactor = getExtraScaleFactor(materialName);
+  // -1 (or any -ve number) indicates material is not scaled. And if the scale factor
+  // is 1 then there is no need to create a new material.
+  if (scaleFactor < 0 || scaleFactor == 1 || materialName.find("Ether") != std::string::npos) return origMaterial;
+
+  if (scaleFactor == 0) return getMaterialInternal("std::Vacuum");
+
+  std::string newName = materialName + "_ExtraScaling";
+
+  // Check if it is already made.
+  const GeoMaterial* newMaterial = getAdditionalMaterial(newName);
+
+  // Already made so we return it.
+  if (newMaterial) return newMaterial;
+
+  // Otherwise we need to make it.
+  double density = origMaterial->getDensity() * scaleFactor;
+
+  // create new material
+  GeoMaterial* newMaterialTmp = new GeoMaterial(newName, density);
+  newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), 1.);
+  addMaterial(newMaterialTmp);
+  newMaterial = newMaterialTmp;
+
+  return newMaterial;
+}
+
+double
+NeutrinoMaterialManager::getExtraScaleFactor(const std::string& materialName) {
+  // If name is found in map we return the corresponding scale factor.
+  // The special name "ALL" indicates all materials are scaled.
+  // Individual materials can be excluded from scaling by giving either
+  // a -ve scaling factor or just specifying a scaling factor of 1.
+  // A scaling factor of 0 means the material will be replaced by vacuum.
+
+  ExtraScaleFactorMap::const_iterator iter = m_scalingMap.find(materialName);
+  if (iter != m_scalingMap.end()) {
+    return iter->second;
+  } else {
+    // Check for special names
+    // ALL means everything scaled. Do not scale air or vacuum (unless explicity requested)
+    iter = m_scalingMap.find("ALL");
+    if (iter != m_scalingMap.end() && materialName != "std::Air" && materialName != "std::Vacuum") {
+      return iter->second;
+    }
+  }
+
+  // If not found then return -1 to indicate material is not to be scaled.
+  return -1;
+}
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TopLevelPlacements.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TopLevelPlacements.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2d269f24ddf1f13574e456c576b7089ac3a80db2
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TopLevelPlacements.cxx
@@ -0,0 +1,145 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/TopLevelPlacements.h"
+#include "GaudiKernel/SystemOfUnits.h"
+#include "RDBAccessSvc/IRDBRecordset.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include <iostream>
+
+GeoTrf::Transform3D TopLevelPlacements::s_identityTransform = GeoTrf::Transform3D::Identity();
+
+TopLevelPlacements::TopLevelPlacements(IRDBRecordset_ptr topLevelTable)
+  : m_noTopLevelTable(true) {
+  fillPlacements(topLevelTable);
+}
+
+TopLevelPlacements::~TopLevelPlacements() {
+  std::map<std::string, Part*>::const_iterator iter;
+  for (iter = m_parts.begin(); iter != m_parts.end(); ++iter) delete iter->second;
+}
+
+const GeoTrf::Transform3D&
+TopLevelPlacements::transform(const std::string& partName) const {
+  Part* part = getPart(partName);
+
+  if (part) return part->transform;
+
+  return s_identityTransform;
+}
+
+bool
+TopLevelPlacements::present(const std::string& partName) const {
+  // If no table present assume everything is present.
+  if (m_noTopLevelTable) return true;
+
+  return(getPart(partName) != 0);
+}
+
+void
+TopLevelPlacements::fillPlacements(IRDBRecordset_ptr topLevelTable) {
+  if (topLevelTable.get() == 0) {
+    m_noTopLevelTable = true;
+    return;
+  }
+  m_noTopLevelTable = false;
+  int numParts = topLevelTable->size();
+  for (int i = 0; i < numParts; i++) {
+    const IRDBRecord* record = (*topLevelTable)[i];
+    std::string label = record->getString("LABEL");
+
+    Part* part = new Part;
+    part->label = label;
+    part->transform = partTransform(record);
+
+    m_parts[label] = part;
+  }
+}
+
+GeoTrf::Transform3D
+TopLevelPlacements::partTransform(const IRDBRecord* record) const {
+  double posX = record->getDouble("POSX") * Gaudi::Units::mm;
+  double posY = record->getDouble("POSY") * Gaudi::Units::mm;
+  double posZ = record->getDouble("POSZ") * Gaudi::Units::mm;
+  double rotX = record->getDouble("ROTX") * Gaudi::Units::degree;
+  double rotY = record->getDouble("ROTY") * Gaudi::Units::degree;
+  double rotZ = record->getDouble("ROTZ") * Gaudi::Units::degree;
+  int rotOrder = record->getInt("ROTORDER");
+
+  // Translation part
+  GeoTrf::Translate3D transform(posX, posY, posZ);
+
+  // If rotation is zero return translation
+  if (rotX == 0 && rotY == 0 && rotZ == 0) {
+    return transform;
+  }
+
+  // For rotation have to look at order.
+  // 123 means rotate around X, then Y , then Z.
+  // 312  means rotate around Z, then X , then Y.
+  // etc
+
+  int ixyz1 = rotOrder / 100 - 1;
+  int ixyz2 = (rotOrder % 100) / 10 - 1;
+  int ixyz3 = (rotOrder % 10) - 1;
+
+  if (ixyz1 < 0 || ixyz1 > 2 ||
+      ixyz2 < 0 || ixyz2 > 2 ||
+      ixyz3 < 0 || ixyz3 > 2) {
+    std::cout << "ERROR: Invalid rotation order:" << rotOrder << std::endl;
+    ixyz1 = 0;
+    ixyz2 = 1;
+    ixyz3 = 2;
+  }
+
+  GeoTrf::Transform3D rotation(GeoTrf::Translate3D::Identity());
+  std::vector<int> order { ixyz1 , ixyz2, ixyz3 };
+  for (int ixyz : order)
+  {
+    switch (ixyz)
+    {
+      case 0:
+        if (rotX != 0) rotation = GeoTrf::RotateX3D{rotX} * rotation;
+        break;
+      case 1:
+        if (rotY != 0) rotation = GeoTrf::RotateY3D{rotY} * rotation;
+        break;
+      case 2:
+        if (rotZ != 0) rotation = GeoTrf::RotateZ3D{rotZ} * rotation;
+        break;
+    }
+  }
+
+  // This segfaults at runtime when deleting the pointers, 
+  // I think because the base class of Transform3D 
+  // does not have a virtual destructor
+  //
+  // List of the three transforms
+  // GeoTrf::Transform3D* xformList[] = { nullptr, nullptr, nullptr };
+  // if (rotX != 0) xformList[0] = new GeoTrf::RotateX3D(rotX);
+  // if (rotY != 0) xformList[1] = new GeoTrf::RotateY3D(rotY);
+  // if (rotZ != 0) xformList[2] = new GeoTrf::RotateZ3D(rotZ);
+
+  // GeoTrf::Transform3D rotation(GeoTrf::Transform3D::Identity());
+  // if (xformList[ixyz1] != nullptr) rotation = *(xformList[ixyz1]) * rotation;
+  // if (xformList[ixyz2] != nullptr) rotation = *(xformList[ixyz2]) * rotation;
+  // if (xformList[ixyz3] != nullptr) rotation = *(xformList[ixyz3]) * rotation;
+  // if (xformList[0] != nullptr) 
+  //   delete xformList[0];
+  // if (xformList[1] != nullptr) 
+  //   delete xformList[1];
+  // if (xformList[2] != nullptr) 
+  //   delete xformList[2];
+
+  return transform * rotation;
+}
+
+TopLevelPlacements::Part*
+TopLevelPlacements::getPart(const std::string& partName) const {
+  std::map<std::string, Part*>::const_iterator iter;
+  iter = m_parts.find(partName);
+  if (iter == m_parts.end()) return 0;
+
+  return iter->second;
+}
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TubeVolData.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TubeVolData.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4059dc2283620aeac00da6d9ab652438b57b2f01
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoGeoModelUtils/src/TubeVolData.cxx
@@ -0,0 +1,101 @@
+/*
+   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+ */
+
+#include "NeutrinoGeoModelUtils/TubeVolData.h"
+#include "RDBAccessSvc/IRDBRecord.h"
+#include "GaudiKernel/SystemOfUnits.h"
+
+#include <cmath>
+#include <string>
+#include <iostream>
+
+namespace NeutrinoDD {
+  std::string
+  TubeVolData::material() const {
+    return m_record->getString("MATERIAL");
+  }
+
+  double
+  TubeVolData::maxRadius() const {
+    return std::max(m_rmax1, m_rmax2);
+  }
+
+  TubeVolData::TubeVolData(const IRDBRecord* record)
+    : m_record(record),
+    m_bothZ(false),
+    m_nRepeat(0),
+    m_radialDiv(0),
+    m_phiStart(0.),
+    m_phiDelta(0.),
+    m_phiStep(0.),
+    m_rmin1(0.),
+    m_rmin2(0.),
+    m_rmax1(0.),
+    m_rmax2(0.),
+    m_length(0.),
+    m_zMid(0.) {
+    // add an 2*epsilon gap between phi sectors.
+    const double phiepsilon = 0.001 * Gaudi::Units::degree;
+
+    bool fullPhiSector = false;
+
+
+    // Get the parameters which we need to do some preprocessing with.
+    // The rest are obtained directly from RDB.
+
+    if (m_record) {
+      m_phiStart = m_record->getDouble("PHISTART") * Gaudi::Units::degree;
+      m_phiDelta = m_record->getDouble("PHIDELTA") * Gaudi::Units::degree;
+      m_phiStep = m_record->getDouble("PHISTEP") * Gaudi::Units::degree;
+      m_nRepeat = m_record->getInt("NREPEAT");
+      m_rmin1 = m_record->getDouble("RMIN") * Gaudi::Units::mm;
+      m_rmax1 = m_record->getDouble("RMAX") * Gaudi::Units::mm;
+      m_rmin2 = m_record->getDouble("RMIN2") * Gaudi::Units::mm;
+      m_rmax2 = m_record->getDouble("RMAX2") * Gaudi::Units::mm;
+      m_radialDiv = 0;
+      if (!m_record->isFieldNull("RADIAL")) {
+        m_radialDiv = m_record->getInt("RADIAL");
+      }
+      m_bothZ = 0;
+      if (!m_record->isFieldNull("ZSYMM")) {
+        m_bothZ = m_record->getInt("ZSYMM");
+      }
+
+      double zmin = m_record->getDouble("ZMIN") * Gaudi::Units::mm;
+      double zmax = m_record->getDouble("ZMAX") * Gaudi::Units::mm;
+      m_length = std::abs(zmax - zmin);
+      m_zMid = 0.5 * (zmin + zmax);
+
+      if (m_phiDelta == 0 || m_phiDelta >= 359.9 * Gaudi::Units::degree) {
+        m_phiDelta = 360 * Gaudi::Units::degree;
+        fullPhiSector = true;
+      } else {
+        m_phiDelta -= 2 * phiepsilon;
+        m_phiStart += phiepsilon;
+      }
+
+      // Force nRepeat to be >= 1;
+      if (m_nRepeat <= 0) m_nRepeat = 1;
+      // if PHISTEP==0 then set it to be equi-distant steps filling up phi.
+      if (m_phiStep == 0) {
+        m_phiStep = 360 * Gaudi::Units::degree / m_nRepeat;
+      }
+
+      if (m_rmin2 <= 0) m_rmin2 = m_rmin1;
+      if (m_rmax2 <= 0) m_rmax2 = m_rmax1;
+
+      if (m_radialDiv > 0) {
+        m_shape = TubeVolData::RADIAL;
+      } else if (m_rmin1 == m_rmin2 && m_rmax1 == m_rmax2) {
+        if (fullPhiSector) {
+          m_shape = TubeVolData::TUBE;
+        } else {
+          m_shape = TubeVolData::TUBS;
+        }
+      } else {
+        m_shape = TubeVolData::CONS;
+      }
+    } else std::cout << "Unexpected ERROR in ExtraMaterial!" << std::endl;
+  }
+} // end namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdDictFiles/data/IdDictNeutrino.xml b/Neutrino/NeutrinoDetDescr/NeutrinoIdDictFiles/data/IdDictNeutrino.xml
index 9faa43cf04e34052e6ae08a55be6ce425b889357..45ef3be3ececee0b112b79ff949054b70c6fb2fd 100644
--- a/Neutrino/NeutrinoDetDescr/NeutrinoIdDictFiles/data/IdDictNeutrino.xml
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdDictFiles/data/IdDictNeutrino.xml
@@ -4,15 +4,16 @@
     <label name="Emulsion" value="1" />
   </field>
 
-  <field name="side">
+  <field name="film">
     <label name="Upstream" value="0" />
     <label name="Downstream" value="1" />
   </field>
 
   <region>
     <range field="part" value="Emulsion" />
-    <range field="film" minvalue="0" maxvalue="999" />
-    <range field="side" values="Upstream Downstream" />
+    <range field="module" minvalue="0" maxvalue="34" />
+    <range field="base" minvalue="0" maxvalue="21" />
+    <range field="film" values="Upstream Downstream" />
   </region>
 
 </IdDictionary>
\ No newline at end of file
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/CMakeLists.txt b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..804522b7d0e2e5d4270231d11b5bfdf1a16eae3d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/CMakeLists.txt
@@ -0,0 +1,24 @@
+################################################################################
+# Package: NeutrinoIdentifier
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoIdentifier )
+
+# External dependencies:
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_library( NeutrinoIdentifier
+                   src/EmulsionID.cxx
+                   PUBLIC_HEADERS NeutrinoIdentifier
+                   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                   LINK_LIBRARIES AthenaKernel FaserDetDescr IdDict Identifier
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} IdDictParser GaudiKernel )
+
+atlas_add_dictionary( NeutrinoIdentifierDict
+                      NeutrinoIdentifier/NeutrinoIdentifierDict.h
+                      NeutrinoIdentifier/selection.xml
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} FaserDetDescr IdDict Identifier IdDictParser GaudiKernel NeutrinoIdentifier )
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/EmulsionID.h b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/EmulsionID.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e396dd788940c30b3daaeb904134ecab7e04e88
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/EmulsionID.h
@@ -0,0 +1,573 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOIDENTIFIER_EMULSIONID_H
+#define NEUTRINOIDENTIFIER_EMULSIONID_H
+/**
+ * @file EmulsionID.h
+ *
+ * @brief This is an Identifier helper class for the Emulsion
+ *  subdetector. This class is a factory for creating compact
+ *  Identifier objects and IdentifierHash or hash ids. And it also
+ *  allows decoding of these ids.
+ *
+ */
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
+#include "Identifier/Range.h"
+#include "Identifier/IdHelper.h"
+#include "IdDict/IdDictFieldImplementation.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+#include <string>
+#include <assert.h>
+#include <algorithm>
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class IdDictDictionary;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+/**
+ **  @class EmulsionID
+ **  
+ **  @brief This is an Identifier helper class for the Emulsion
+ **  subdetector. This class is a factory for creating compact
+ **  Identifier objects and IdentifierHash or hash ids. And it also
+ **  allows decoding of these ids.
+ **
+ **  Definition and the range of values for the levels of the
+ **  identifier are:
+ **
+ ** @verbatim
+ **    element           range              meaning
+ **    -------           -----              -------
+ **
+ **    module           0 to 34             35 modules
+ **    base             0 to 21             22 bases per module
+ **    film side        0 to 1              2 films per base
+ **
+ ** @endverbatim
+ **
+ */
+class EmulsionID : public FaserDetectorID
+{
+public:
+        
+    /// @name public typedefs
+    //@{
+    typedef Identifier::size_type                       size_type; 
+    typedef std::vector<Identifier>::const_iterator     const_id_iterator;
+    typedef MultiRange::const_identifier_factory        const_expanded_id_iterator;
+    //@}
+
+    /// @name strutors
+    //@{
+    EmulsionID(void);
+    virtual ~EmulsionID(void) = default;
+    //@}
+        
+    /// @name Creators for base ids and side ids
+    //@{
+    /// For a single module
+    Identifier  module_id ( int module ) const;
+    Identifier  module_id ( int module,
+                             bool checks) const;
+
+    /// For a module from a base id
+    Identifier  module_id ( const Identifier& base_id ) const;
+
+    /// For a single base
+    Identifier  base_id ( int module, 
+                           int base ) const;
+    Identifier  base_id ( int module, 
+                           int base,
+                           bool checks) const;
+
+    /// For a single base from a film id
+    Identifier  base_id ( const Identifier& film_id ) const;
+
+    /// From hash - optimized
+    Identifier  base_id ( IdentifierHash base_hash ) const;
+    Identifier  film_id ( IdentifierHash film_hash ) const;
+
+    /// For an individual film
+    Identifier  film_id ( int module, 
+                         int base, 
+                         int film ) const; 
+
+    Identifier  film_id ( int module, 
+                         int base, 
+                         int film,
+                         bool check ) const; 
+
+    Identifier  film_id ( const Identifier& base_id, 
+                         int film ) const;
+
+    //@}
+
+
+    /// @name Hash table maximum sizes
+    //@{
+    size_type   base_hash_max          (void) const;
+    size_type   film_hash_max            (void) const;
+    //@}
+
+    /// @name Access to all ids
+    //@{
+    /// Iterators over full set of ids. Base iterator is sorted
+    const_id_iterator   base_begin                     (void) const;
+    const_id_iterator   base_end                       (void) const;
+    /// For film ids, only expanded id iterators are available. Use
+    /// following "film_id" method to obtain a compact identifier
+    const_expanded_id_iterator  film_begin             (void) const;  
+    const_expanded_id_iterator  film_end               (void) const;
+    //@}
+    
+
+    /// @name Optimized accessors  - ASSUMES id IS a veto id, i.e. NOT other
+    //@{
+    /// base hash from id - optimized
+    IdentifierHash      base_hash      (Identifier base_id) const;
+
+    IdentifierHash      film_hash      (Identifier film_id) const;
+
+    /// Values of different levels (failure returns 0)
+    int         module       (const Identifier& id) const;  
+    int         base         (const Identifier& id) const; 
+    int         film         (const Identifier& id) const; 
+
+    /// Max/Min values for each field (-999 == failure)
+    int         module_max  (const Identifier& id) const;
+    int         base_max    (const Identifier& id) const;
+    int         film_max    (const Identifier& id) const;
+    //@}
+
+    /// @name navigation
+    //@{
+        /// Previous base in z
+        int get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const;
+        /// Next base in z
+        int get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Previous wafer hash in phi (return == 0 for neighbor found)
+    // int         get_prev_in_phi (const IdentifierHash& id, IdentifierHash& prev) const;
+    // /// Next wafer hash in phi (return == 0 for neighbor found)
+    // int         get_next_in_phi (const IdentifierHash& id, IdentifierHash& next) const;
+    // /// Previous wafer hash in eta (return == 0 for neighbor found)
+    // int         get_prev_in_eta (const IdentifierHash& id, IdentifierHash& prev) const;
+    // /// Next wafer hash in eta (return == 0 for neighbor found)
+    // int         get_next_in_eta (const IdentifierHash& id, IdentifierHash& next) const;
+        /// Film hash on other side
+        int         get_other_side  (const IdentifierHash& id, IdentifierHash& other) const;
+    
+    // // To check for when phi wrap around may be needed, use
+    // bool        is_phi_module_max(const Identifier& id) const;
+    // /// For the barrel
+    // bool        is_eta_module_min(const Identifier& id) const;
+    // /// For the barrel
+    // bool        is_eta_module_max(const Identifier& id) const;
+    //@}
+
+    /// @name contexts to distinguish base id from film id
+    //@{
+    IdContext   base_context             (void) const;
+    IdContext   film_context             (void) const;
+    //@}
+
+    /// @name methods from abstract interface - slower than opt version
+    //@{
+    /// Create compact id from hash id (return == 0 for OK)
+    virtual int         get_id          (const IdentifierHash& hash_id,
+                                         Identifier& id,
+                                         const IdContext* context = 0) const;
+    
+    /// Create hash id from compact id (return == 0 for OK)
+    virtual int         get_hash        (const Identifier& id, 
+                                         IdentifierHash& hash_id,
+                                         const IdContext* context = 0) const;
+    //@}
+
+    /// Return the lowest bit position used in the channel id
+    int                 base_bit        (void) const;
+
+    /// Calculate a channel offset between the two identifiers.
+    Identifier::diff_type calc_offset(const Identifier& base,
+                                      const Identifier& target) const;
+
+    /// Create an identifier with a given base and channel offset
+    Identifier film_id_offset(const Identifier& base,
+                             Identifier::diff_type offset) const;
+
+    /// @name interaction with id dictionary
+    //@{
+    /// Create film Identifier from expanded id, which is returned by the
+    /// id_iterators
+    Identifier          film_id        (const ExpandedIdentifier& film_id) const;
+
+    /// Create expanded id from compact id (return == 0 for OK)
+    void                get_expanded_id (const Identifier& id,
+                                         ExpandedIdentifier& exp_id,
+                                         const IdContext* context = 0) const;
+
+    /// Initialization from the identifier dictionary
+    virtual int         initialize_from_dictionary(const IdDictMgr& dict_mgr);
+
+    /// Tests of packing
+    void        test_base_packing      (void) const;
+    //@}
+    
+private:
+        
+    enum {NOT_VALID_HASH        = 64000};
+
+    typedef std::vector<Identifier>     id_vec;
+    typedef id_vec::const_iterator      id_vec_it;
+    typedef std::vector<unsigned short> hash_vec;
+    typedef hash_vec::const_iterator    hash_vec_it;
+
+    void base_id_checks ( int module, 
+                          int base ) const; 
+
+    void film_id_checks ( int module, 
+                          int base, 
+                          int film ) const;
+
+
+    int         initLevelsFromDict(void);
+
+    int         init_hashes(void);
+
+    int         init_neighbors(void);
+
+    // Temporary method for adapting an identifier for the MultiRange
+    // check - MR is missing the InnerDetector level
+    // Identifier  idForCheck      (const Identifier& id) const;
+
+    size_type                   m_emulsion_region_index;
+    size_type                   m_NEUTRINO_INDEX;
+    size_type                   m_EMULSION_INDEX;
+    size_type                   m_MODULE_INDEX;
+    size_type                   m_BASE_INDEX;
+    size_type                   m_FILM_INDEX;
+
+    const IdDictDictionary*     m_dict;
+    MultiRange                  m_full_base_range;
+    MultiRange                  m_full_film_range;
+    size_type                   m_base_hash_max;
+    size_type                   m_film_hash_max;
+    // Range::field                m_barrel_field;
+    id_vec                      m_base_vec;
+    id_vec                      m_film_vec;
+    hash_vec                    m_prev_z_base_vec;
+    hash_vec                    m_next_z_base_vec;
+    // hash_vec                    m_prev_phi_wafer_vec;
+    // hash_vec                    m_next_phi_wafer_vec;
+    // hash_vec                    m_prev_eta_wafer_vec;
+    // hash_vec                    m_next_eta_wafer_vec;   
+    // bool 			m_hasRows	;
+
+    IdDictFieldImplementation   m_neutrino_impl	;
+    IdDictFieldImplementation   m_emulsion_impl	;
+    IdDictFieldImplementation   m_module_impl	;
+    IdDictFieldImplementation   m_base_impl	;
+    IdDictFieldImplementation   m_film_impl	;
+};
+    
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+
+/////////////////////////////////////////////////////////////////////////////
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+/////////////////////////////////////////////////////////////////////////////
+
+//using the macros below we can assign an identifier (and a version)
+//This is required and checked at compile time when you try to record/retrieve
+CLASS_DEF(EmulsionID, 89852815, 1)
+
+//----------------------------------------------------------------------------
+inline Identifier  
+EmulsionID::module_id ( int module, 
+                        bool checks) const
+{
+    
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_neutrino_impl.pack       (neutrino_field_value(),  result);
+    m_emulsion_impl.pack       (emulsion_field_value(),  result);
+    m_module_impl.pack         (module,                  result);
+    // Do checks
+    if(checks) 
+    {
+        base_id_checks ( module, 0 );
+    }
+
+    return result;
+}
+
+inline Identifier  
+EmulsionID::module_id ( int module ) const 
+{
+  return module_id (module, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+EmulsionID::module_id ( const Identifier& base_id ) const
+{
+    Identifier result(base_id);
+    //  Reset the base and film fields
+    m_base_impl.reset(result);
+    m_film_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+EmulsionID::base_id ( int module,  
+                      int base, 
+                      bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_neutrino_impl.pack   (neutrino_field_value(), result);
+    m_emulsion_impl.pack   (emulsion_field_value(),  result);
+    m_module_impl.pack     (module,             result);
+    m_base_impl.pack       (base,               result);
+
+    // Do checks
+    if(checks) 
+    {
+        base_id_checks ( module, base );
+    }
+    return result;
+}
+
+inline Identifier
+EmulsionID::base_id ( int module,  
+                      int base ) const
+{
+  return base_id (module, base, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+EmulsionID::base_id ( const Identifier& film_id ) const
+{
+    Identifier result(film_id);
+    // reset the film field
+    m_film_impl.reset(result);
+    return (result);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  EmulsionID::base_id ( IdentifierHash base_hash ) const
+{
+    return (m_base_vec[base_hash]);
+}
+
+inline Identifier  EmulsionID::film_id ( IdentifierHash film_hash ) const
+{
+    return (m_film_vec[film_hash]);
+}
+
+//----------------------------------------------------------------------------
+inline IdentifierHash      EmulsionID::base_hash      (Identifier base_id) const 
+{
+    // MsgStream log(m_msgSvc, "EmulsionID");
+    // log << MSG::VERBOSE << "m_plate_vec size: " << m_plate_vec.size() << endmsg;
+    // log << MSG::VERBOSE << "input id = " << plate_id << endmsg;
+    // for (size_t i = 0; i < m_plate_vec.size(); i++)
+    // {
+    //     log << MSG::VERBOSE << "Hash = " <<  i << " : ID = " << m_plate_vec[i] << endmsg;
+    // }
+    id_vec_it it = std::lower_bound(m_base_vec.begin(), 
+                                    m_base_vec.end(), 
+                                    base_id);
+    // Require that base_id matches the one in vector
+    if (it != m_base_vec.end() && base_id == (*it)) {
+        return (it - m_base_vec.begin());
+    }
+    IdentifierHash result;
+    return (result); // return hash in invalid state
+}
+
+inline IdentifierHash      EmulsionID::film_hash      (Identifier film_id) const 
+{
+    // MsgStream log(m_msgSvc, "EmulsionID");
+    // log << MSG::VERBOSE << "m_plate_vec size: " << m_plate_vec.size() << endmsg;
+    // log << MSG::VERBOSE << "input id = " << plate_id << endmsg;
+    // for (size_t i = 0; i < m_plate_vec.size(); i++)
+    // {
+    //     log << MSG::VERBOSE << "Hash = " <<  i << " : ID = " << m_plate_vec[i] << endmsg;
+    // }
+    id_vec_it it = std::lower_bound(m_film_vec.begin(), 
+                                    m_film_vec.end(), 
+                                    film_id);
+    // Require that base_id matches the one in vector
+    if (it != m_film_vec.end() && film_id == (*it)) {
+        return (it - m_film_vec.begin());
+    }
+    IdentifierHash result;
+    return (result); // return hash in invalid state
+}
+
+
+
+
+//----------------------------------------------------------------------------
+inline Identifier
+EmulsionID::film_id ( int module,  
+                 int base, 
+                 int film,
+                 bool checks) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_neutrino_impl.pack    (neutrino_field_value(), result);
+    m_emulsion_impl.pack    (emulsion_field_value(),  result);
+    m_module_impl.pack      (module,             result);
+    m_base_impl.pack        (base,               result);
+    m_film_impl.pack        (film,                 result);
+
+    // Do checks
+    if(checks) {
+        film_id_checks ( module, base, film );
+    }
+    return result;
+}
+
+inline Identifier
+EmulsionID::film_id ( int module,  
+                 int base, 
+                 int film ) const
+{
+  return film_id (module, base, film, do_checks());
+}
+
+//----------------------------------------------------------------------------
+inline Identifier               
+EmulsionID::film_id        (const ExpandedIdentifier& id) const
+{
+    // Build identifier
+    Identifier result((Identifier::value_type)0);
+
+    // Pack fields independently
+    m_neutrino_impl.pack    (neutrino_field_value(),    result);
+    m_emulsion_impl.pack    (emulsion_field_value(),     result);
+    m_module_impl.pack      (id[m_MODULE_INDEX],    result);
+    m_base_impl.pack        (id[m_BASE_INDEX],      result);
+    m_film_impl.pack        (id[m_FILM_INDEX],        result);
+
+    // Do checks
+    if(m_do_checks) 
+    {
+       	film_id_checks ( id[m_MODULE_INDEX],  
+                          id[m_BASE_INDEX], 
+                       	  id[m_FILM_INDEX]);    
+    }
+    return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier  
+EmulsionID::film_id ( const Identifier& base_id, int film ) const
+{
+	// Build identifier
+    Identifier result(base_id);
+  
+    // Reset strip and then add in value
+    m_film_impl.reset   (result);
+ 	m_film_impl.pack    (film, result);
+  
+    if(m_do_checks)
+    {          
+	    film_id_checks ( module(result), 
+		           		base(result), 
+                        film );
+	}
+	return result;
+}
+
+//----------------------------------------------------------------------------
+inline Identifier::diff_type
+EmulsionID::calc_offset(const Identifier& base, const Identifier& target) const
+{
+  Identifier::diff_type tval = static_cast<Identifier::diff_type>(target.get_compact() >> base_bit());
+  Identifier::diff_type bval = static_cast<Identifier::diff_type>(base.get_compact() >> base_bit());
+  return (tval - bval);
+}
+
+//----------------------------------------------------------------------------
+inline Identifier
+EmulsionID::film_id_offset(const Identifier& base,
+                        Identifier::diff_type offset) const
+{
+  Identifier::value_type bval = base.get_compact() >> base_bit();
+  return Identifier((bval + offset) << base_bit());
+}
+
+//----------------------------------------------------------------------------
+inline int
+EmulsionID::base_bit ( void ) const
+{
+  int base = static_cast<int>(m_film_impl.shift()); // lowest field base
+  return (base > 32) ? 32 : base;
+  // max base is 32 so we can still read old strip id's and differences
+  // from non-SLHC releases.
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+EmulsionID::base_context           (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_BASE_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline IdContext        
+EmulsionID::film_context   (void) const
+{
+    ExpandedIdentifier id;
+    return (IdContext(id, 0, m_FILM_INDEX));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+EmulsionID::module       (const Identifier& id) const
+{
+    return (m_module_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+EmulsionID::base     (const Identifier& id) const
+{
+    return (m_base_impl.unpack(id));
+}
+
+//----------------------------------------------------------------------------
+inline int 
+EmulsionID::film           (const Identifier& id) const
+{
+    return (m_film_impl.unpack(id));
+}
+
+
+#endif // NEUTRINOIDENTIFIER_EMULSIONID_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/NeutrinoIdentifierDict.h b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/NeutrinoIdentifierDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd6cea525acfc93121fe833948fa6e350abd3fa3
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/NeutrinoIdentifierDict.h
@@ -0,0 +1,17 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file NeutrinoIdentifierDict.h
+ *
+ * @brief This file includes the class for dictionary definitions
+ *
+ * $Id: $
+ */
+#ifndef NEUTRINOIDENTIFIER_NEUTRINOIDENTIFIERDICT_H
+#define NEUTRINOIDENTIFIER_NEUTRINOIDENTIFIERDICT_H 
+
+#include "NeutrinoIdentifier/EmulsionID.h"
+
+#endif // NEUTRINOIDENTIFIER_NEUTRINOIDENTIFIERDICT_H 
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/selection.xml b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..74a348f5cf3c3e2cedd5655d8a5ab2904b5bd62f
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/NeutrinoIdentifier/selection.xml
@@ -0,0 +1,3 @@
+<lcgdict>
+  <class name="EmulsionID" />
+</lcgdict>
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/src/EmulsionID.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/src/EmulsionID.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..39639714210ce7124b68ceade844fd233e0b3dec
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoIdentifier/src/EmulsionID.cxx
@@ -0,0 +1,1068 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Neutrino identifier package
+ -------------------------------------------
+***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+#include "GaudiKernel/MsgStream.h"
+
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "Identifier/IdentifierHash.h"
+#include "IdDict/IdDictDefs.h"  
+#include <set>
+#include <algorithm>
+#include <iostream>
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+
+EmulsionID::EmulsionID(void)
+        :
+        m_emulsion_region_index(0),
+        m_NEUTRINO_INDEX(0),
+        m_EMULSION_INDEX(1),
+        m_MODULE_INDEX(2),
+        m_BASE_INDEX(3),
+        m_FILM_INDEX(4),
+        m_dict(0),
+        m_base_hash_max(0),
+        m_film_hash_max(0)
+{
+}
+
+void
+EmulsionID::base_id_checks ( int module,  
+                          int base ) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << neutrino_field_value() << emulsion_field_value()
+       << module << base;
+
+    if (!m_full_base_range.match(id)) {  // module range check is sufficient
+        MsgStream log(m_msgSvc, "EmulsionID");
+        log << MSG::ERROR << " EmulsionID::base_id result is NOT ok. ID, range "
+            << (std::string)id <<  " " << (std::string)m_full_base_range << endmsg;
+    }
+}
+
+void
+EmulsionID::film_id_checks ( int module,  
+                        int base, 
+                        int film) const
+{
+
+    // Check that id is within allowed range
+
+    // Fill expanded id
+    ExpandedIdentifier id;
+    id << neutrino_field_value() << emulsion_field_value()
+       << module << base << film;
+
+    if (!m_full_film_range.match(id)) {  
+        MsgStream log(m_msgSvc, "EmulsionID");
+        log << MSG::ERROR << " EmulsionID::film_id result is NOT ok. ID, range "
+            << (std::string)id << " " << (std::string)m_full_film_range << std::endl;
+    }
+}
+
+int 
+EmulsionID::module_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext base_context1 = base_context();
+    get_expanded_id(id, expId, &base_context1);
+    for (unsigned int i = 0; i < m_full_base_range.size(); ++i) {
+        const Range& range = m_full_base_range[i];
+        if (range.match(expId)) {
+            const Range::field& module_field = range[m_MODULE_INDEX];
+            if (module_field.has_maximum()) {
+                return (module_field.get_maximum());
+            }
+        }
+    }
+    return (-999);  // default
+}
+
+int     
+EmulsionID::film_max       (const Identifier& id) const
+{
+    ExpandedIdentifier expId;
+    IdContext module_context(expId, 0, m_MODULE_INDEX);
+    get_expanded_id(id, expId, &module_context);
+    int result = -999;
+    for (unsigned int i = 0; i < m_full_film_range.size(); ++i) {
+        const Range& range = m_full_film_range[i];
+        if (range.match(expId)) {
+            const Range::field& film_field = range[m_FILM_INDEX];
+            if (film_field.has_maximum()) {
+                int film = film_field.get_maximum();
+                if (result < film) result = film;
+            }
+        }
+    }
+    return (result);
+}
+
+int 
+EmulsionID::base_max(const Identifier& id) const
+{
+    // get max from dictionary
+    ExpandedIdentifier expId;
+    IdContext base_context1 = base_context();
+    get_expanded_id(id, expId, &base_context1);
+    for (unsigned int i = 0; i < m_full_base_range.size(); ++i) {
+        const Range& range = m_full_base_range[i];
+        if (range.match(expId)) {
+            const Range::field& base_field = range[m_BASE_INDEX];
+            if (base_field.has_maximum()) {
+                return (base_field.get_maximum());
+            }
+        }
+    }
+    return -1;
+}
+
+int
+EmulsionID::initialize_from_dictionary(const IdDictMgr& dict_mgr)
+{
+    MsgStream log(m_msgSvc, "EmulsionID");
+    log << MSG::INFO << "Initialize from dictionary" << endmsg;
+  
+    // Check whether this helper should be reinitialized
+    if (!reinitialize(dict_mgr)) {
+        log << MSG::INFO << "Request to reinitialize not satisfied - tags have not changed" << endmsg;
+        return (0);
+    }
+    else {
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "(Re)initialize" << endmsg;
+        }
+        else {
+            std::cout  << " DEBUG (Re)initialize" << std::endl;
+        }
+    }
+
+    // init base object
+    if(FaserDetectorID::initialize_from_dictionary(dict_mgr)) return (1);
+
+    // Register version of InnerDetector dictionary 
+    if (register_dict_tag(dict_mgr, "Neutrino")) return(1);
+
+    m_dict = dict_mgr.find_dictionary ("Neutrino"); 
+    if(!m_dict) {
+        log << MSG::ERROR << " EmulsionID::initialize_from_dict - cannot access Neutrino dictionary " << endmsg;
+        return 1;
+    }
+
+    // Initialize the field indices
+    if(initLevelsFromDict()) return (1);
+
+    //
+    // Build multirange for the valid set of identifiers
+    //
+
+
+    // Find value for the field Neutrino
+    const IdDictDictionary* faserDict = dict_mgr.find_dictionary ("FASER"); 
+    int neutrinoField   = -1;
+    if (faserDict->get_label_value("subdet", "Neutrino", neutrinoField)) {
+        log << MSG::ERROR << "Could not get value for label 'Neutrino' of field 'subdet' in dictionary " 
+            << faserDict->m_name
+            << endmsg;
+        return (1);
+    }
+
+    // Find value for the field Emulsion
+    int emulsionField   = -1;
+    if (m_dict->get_label_value("part", "Emulsion", emulsionField)) {
+        log << MSG::ERROR << "Could not get value for label 'Emulsion' of field 'part' in dictionary " 
+            << m_dict->m_name
+            << endmsg;
+        return (1);
+    }
+    if (m_msgSvc) {
+        log << MSG::DEBUG << " EmulsionID::initialize_from_dict " 
+            << "Found field values: Emulsion "  
+            << emulsionField
+            << std::endl;
+    }
+    else {
+        std::cout << " DEBUG EmulsionID::initialize_from_dict " 
+                  << "Found field values: Emulsion "  
+                  << emulsionField
+                  << std::endl;
+    }
+    
+    // Set up id for region and range prefix
+    ExpandedIdentifier region_id;
+    region_id.add(neutrinoField);
+    region_id.add(emulsionField);
+    Range prefix;
+    m_full_base_range = m_dict->build_multirange(region_id, prefix, "base");
+    m_full_film_range = m_dict->build_multirange(region_id, prefix);
+
+    // Setup the hash tables
+    if(init_hashes()) return (1);
+
+    // Setup hash tables for finding neighbors
+    if(init_neighbors()) return (1);
+    
+    if (m_msgSvc) {
+        log << MSG::INFO << " EmulsionID::initialize_from_dict "  << endmsg;
+        log << MSG::DEBUG  
+            << "Base range -> " << (std::string)m_full_base_range
+            <<   endmsg;
+        log << MSG::DEBUG
+            << "Film range -> " << (std::string)m_full_film_range
+            << endmsg;
+    }
+    else {
+        std::cout << " INFO EmulsionID::initialize_from_dict "  << std::endl;
+        std::cout << " DEBUG  Base range -> " << (std::string)m_full_base_range
+                  <<   std::endl;
+        std::cout << " DEBUG Film range -> " << (std::string)m_full_film_range
+                  << std::endl;
+    }
+    
+    return 0;
+}
+
+int
+EmulsionID::init_hashes(void)
+{
+
+    //
+    // create a vector(s) to retrieve the hashes for compact ids. For
+    // the moment, we implement a hash for bases but NOT for films
+    //
+    MsgStream log(m_msgSvc, "EmulsionID");
+    // base hash
+    m_base_hash_max = m_full_base_range.cardinality();
+    m_base_vec.resize(m_base_hash_max);
+    unsigned int nids = 0;
+    std::set<Identifier> ids;
+    for (unsigned int i = 0; i < m_full_base_range.size(); ++i) {
+        const Range& range = m_full_base_range[i];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first) {
+            const ExpandedIdentifier& exp_id = (*first);
+            Identifier id = base_id(exp_id[m_MODULE_INDEX],
+                                     exp_id[m_BASE_INDEX]); 
+            if(!(ids.insert(id)).second) {
+                log << MSG::ERROR << " EmulsionID::init_hashes "
+                    << " Error: duplicated id for base id. nid " << nids
+                    << " compact id " << id.getString()
+                    << " id " << (std::string)exp_id << endmsg;
+                return (1);
+            }
+            nids++;
+        }
+    }
+    if(ids.size() != m_base_hash_max) {
+        log << MSG::ERROR << " EmulsionID::init_hashes "
+            << " Error: set size NOT EQUAL to hash max. size " << ids.size()
+            << " hash max " << m_base_hash_max 
+            << endmsg;
+        return (1);
+    }
+
+    nids = 0;
+    std::set<Identifier>::const_iterator first = ids.begin();
+    std::set<Identifier>::const_iterator last  = ids.end();
+    for (; first != last && nids < m_base_vec.size(); ++first) {
+        m_base_vec[nids] = (*first);
+        nids++;
+    }
+
+    // film hash - we do not keep a vec for the films
+    m_film_hash_max = m_full_film_range.cardinality();
+    m_film_vec.resize(m_film_hash_max);
+    nids = 0;
+    ids.clear();
+    for (unsigned int i = 0; i < m_full_film_range.size(); ++i) {
+        const Range& range = m_full_film_range[i];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first) {
+            const ExpandedIdentifier& exp_id = (*first);
+            Identifier id = film_id(exp_id[m_MODULE_INDEX],
+                                     exp_id[m_BASE_INDEX],
+                                     exp_id[m_FILM_INDEX]); 
+            if(!(ids.insert(id)).second) {
+                log << MSG::ERROR << " EmulsionID::init_hashes "
+                    << " Error: duplicated id for film id. nid " << nids
+                    << " compact id " << id.getString()
+                    << " id " << (std::string)exp_id << endmsg;
+                return (1);
+            }
+            nids++;
+        }
+    }
+    if(ids.size() != m_film_hash_max) {
+        log << MSG::ERROR << " EmulsionID::init_hashes "
+            << " Error: set size for films NOT EQUAL to hash max. size " << ids.size()
+            << " hash max " << m_base_hash_max 
+            << endmsg;
+        return (1);
+    }
+
+    nids = 0;
+    first = ids.begin();
+    last  = ids.end();
+    for (; first != last && nids < m_film_vec.size(); ++first) {
+        m_film_vec[nids] = (*first);
+        nids++;
+    }
+
+
+    return (0);
+}
+
+    int
+    EmulsionID::get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const
+    {
+        unsigned short index = id;
+        if (index < m_prev_z_base_vec.size())
+        {
+            if (m_prev_z_base_vec[index] == NOT_VALID_HASH) return (1);
+            prev = m_prev_z_base_vec[index];
+            return (0);
+        }
+        return (1);
+    }
+
+    int
+    EmulsionID::get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const
+    {
+        unsigned short index = id;
+        if (index < m_next_z_base_vec.size())
+        {
+            if (m_next_z_base_vec[index] == NOT_VALID_HASH) return (1);
+            next = m_next_z_base_vec[index];
+            return (0);
+        }
+        return (1);
+    }
+
+// int             
+// EmulsionID::get_prev_in_phi(const IdentifierHash& id, IdentifierHash& prev) const
+// {
+//     unsigned short index = id;
+//     if (index < m_prev_phi_wafer_vec.size()) {
+//         if (m_prev_phi_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         prev =  m_prev_phi_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int             
+// EmulsionID::get_next_in_phi(const IdentifierHash& id, IdentifierHash& next) const
+// {
+//     unsigned short index = id;
+//     if (index < m_next_phi_wafer_vec.size()) {
+//         if (m_next_phi_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         next =  m_next_phi_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int             
+// EmulsionID::get_prev_in_eta(const IdentifierHash& id, IdentifierHash& prev) const
+// {
+//     unsigned short index = id;
+//     if (index < m_prev_eta_wafer_vec.size()) {
+//         if (m_prev_eta_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         prev =  m_prev_eta_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+// int
+// EmulsionID::get_next_in_eta(const IdentifierHash& id, IdentifierHash& next) const
+// {
+//     unsigned short index = id;
+//     if (index < m_next_eta_wafer_vec.size()) {
+//         if (m_next_eta_wafer_vec[index] == NOT_VALID_HASH) return (1);
+//         next =  m_next_eta_wafer_vec[index];
+//         return (0);
+//     }
+//     return (1);
+// }
+
+int
+EmulsionID::get_other_side  (const IdentifierHash& hashId, IdentifierHash& other) const
+{
+    if (m_dict) {
+        // get max from dictionary
+        Identifier id;
+        IdContext film_context1 = film_context();
+        if(!get_id(hashId, id, &film_context1)) {
+            other = film(id) ? hashId - 1 : hashId + 1;
+            return (0);
+        }
+    }
+    return (1);
+}
+
+int
+EmulsionID::init_neighbors(void)
+{
+    //
+    // create a vector(s) to retrieve the hashes for compact ids for
+    // base neighbors.
+    //
+    MsgStream log(m_msgSvc, "EmulsionID");
+
+    m_prev_z_base_vec.resize(m_base_hash_max, NOT_VALID_HASH);
+    m_next_z_base_vec.resize(m_base_hash_max, NOT_VALID_HASH);
+    for (unsigned int i = 0; i < m_full_base_range.size(); i++)
+    {
+        const Range& range = m_full_base_range[i];
+        const Range::field& module_field = range[m_MODULE_INDEX];
+        const Range::field& base_field   = range[m_BASE_INDEX];
+        Range::const_identifier_factory first = range.factory_begin();
+        Range::const_identifier_factory last  = range.factory_end();
+        for (; first != last; ++first)
+        {
+            const ExpandedIdentifier& exp_id = (*first);
+            ExpandedIdentifier::element_type previous_base;
+            ExpandedIdentifier::element_type next_base;
+            ExpandedIdentifier::element_type previous_module;
+            ExpandedIdentifier::element_type next_module;
+            bool pbase = base_field.get_previous(exp_id[m_BASE_INDEX], previous_base);
+            bool nbase = base_field.get_next    (exp_id[m_BASE_INDEX], next_base);
+            bool pmodule = module_field.get_previous(exp_id[m_MODULE_INDEX], previous_module);
+            bool nmodule = module_field.get_next    (exp_id[m_MODULE_INDEX], next_module);
+
+            IdContext  pcontext = base_context();
+
+            IdentifierHash hash_id;
+            Identifier originalId = base_id(exp_id[m_MODULE_INDEX],
+                                             exp_id[m_BASE_INDEX]);
+
+            if (get_hash(originalId, hash_id, &pcontext)) 
+            {
+                log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get hash, exp/compact "
+                    << show_to_string(originalId, &pcontext)
+                    << " " << (std::string)m_full_base_range << endmsg;
+                return (1);
+            }
+
+            // index for the subsequent arrays
+            unsigned short index = hash_id;
+            assert (hash_id < m_prev_z_base_vec.size());
+            assert (hash_id < m_next_z_base_vec.size());
+            
+            if (pbase) {
+                // Get previous base hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_BASE_INDEX] = previous_base;
+                Identifier id = base_id(expId[m_MODULE_INDEX],
+                                         expId[m_BASE_INDEX]);
+
+                if (get_hash(id, hash_id, &pcontext)) {
+                    log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get previous base hash, exp/compact " << id.getString() << " " 
+                        << endmsg;
+                    return (1);
+                }
+                m_prev_z_base_vec[index] = hash_id;
+            }
+            else if (pmodule)
+            {
+                ExpandedIdentifier expId = exp_id;
+                expId[m_MODULE_INDEX] = previous_module;
+                ExpandedIdentifier moduleId;
+                moduleId.add(expId[m_NEUTRINO_INDEX]);
+                moduleId.add(expId[m_EMULSION_INDEX]);
+                moduleId.add(previous_module);
+                Range prefix;
+                MultiRange moduleBaseRange = m_dict->build_multirange(moduleId, prefix, "base");
+                const Range::field& upstream_base_field = range[m_BASE_INDEX];
+                if (upstream_base_field.has_maximum())
+                {
+                    expId[m_BASE_INDEX] = upstream_base_field.get_maximum();
+                    Identifier id = base_id(expId[m_MODULE_INDEX],
+                                             expId[m_BASE_INDEX]);
+                    if (get_hash(id, hash_id, &pcontext)) {
+                        log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get last base hash from previous module, exp/compact " << id.getString() << " " 
+                            << endmsg;
+                        return (1);
+                    }
+                    m_prev_z_base_vec[index] = hash_id;
+                }
+                else
+                {
+                    log << MSG::ERROR << "EmulsionID::init_neighbors - unable to get base_max for previous module, exp/compact " << originalId.getString() << " "
+                    << endmsg;
+                    return (1);
+                }
+            }
+
+            if (nbase) {
+                // Get next base hash id
+                ExpandedIdentifier expId = exp_id;
+                expId[m_BASE_INDEX] = next_base;
+                Identifier id = base_id(expId[m_MODULE_INDEX],
+                                         expId[m_BASE_INDEX]);
+
+                if (get_hash(id, hash_id, &pcontext)) {
+                    log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get next base hash, exp/compact " << id.getString() << " " 
+                        << endmsg;
+                    return (1);
+                }
+                m_next_z_base_vec[index] = hash_id;
+            }
+            else if (nmodule)
+            {
+                ExpandedIdentifier expId = exp_id;
+                expId[m_MODULE_INDEX] = next_module;
+                ExpandedIdentifier moduleId;
+                moduleId.add(expId[m_NEUTRINO_INDEX]);
+                moduleId.add(expId[m_EMULSION_INDEX]);
+                moduleId.add(next_module);
+                Range prefix;
+                MultiRange moduleBaseRange = m_dict->build_multirange(moduleId, prefix, "base");
+                const Range::field& downstream_base_field = range[m_BASE_INDEX];
+                if (downstream_base_field.has_minimum())
+                {
+                    expId[m_BASE_INDEX] = downstream_base_field.get_minimum();
+                    Identifier id = base_id(expId[m_MODULE_INDEX],
+                                             expId[m_BASE_INDEX]);
+                    if (get_hash(id, hash_id, &pcontext)) {
+                        log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get previous base hash from next module, exp/compact " << id.getString() << " " 
+                            << endmsg;
+                        return (1);
+                    }
+                    m_next_z_base_vec[index] = hash_id;
+                }
+                else
+                {
+                    log << MSG::ERROR << "EmulsionID::init_neighbors - unable to get base_min for next module, exp/compact " << originalId.getString() << " "
+                    << endmsg;
+                    return (1);
+                }
+            }
+
+        }
+    }
+
+    // m_prev_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_next_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_prev_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+    // m_next_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH);
+
+    // for (unsigned int i = 0; i < m_full_wafer_range.size(); ++i) {
+    //     const Range& range = m_full_wafer_range[i];
+    //     const Range::field& phi_field = range[m_PHI_MODULE_INDEX];
+    //     const Range::field& eta_field = range[m_ETA_MODULE_INDEX];
+    //     Range::const_identifier_factory first = range.factory_begin();
+    //     Range::const_identifier_factory last  = range.factory_end();
+    //     for (; first != last; ++first) {
+    //         const ExpandedIdentifier& exp_id = (*first);
+    //         ExpandedIdentifier::element_type previous_phi;
+    //         ExpandedIdentifier::element_type next_phi;
+    //         ExpandedIdentifier::element_type previous_eta;
+    //         ExpandedIdentifier::element_type next_eta;
+    //         bool pphi = phi_field.get_previous(exp_id[m_PHI_MODULE_INDEX], previous_phi);
+    //         bool nphi = phi_field.get_next    (exp_id[m_PHI_MODULE_INDEX], next_phi);
+    //         bool peta = eta_field.get_previous(exp_id[m_ETA_MODULE_INDEX], previous_eta);
+    //         bool neta = eta_field.get_next    (exp_id[m_ETA_MODULE_INDEX], next_eta);
+
+    //         IdContext      wcontext = wafer_context();
+            
+    //         // First get primary hash id
+    //         IdentifierHash hash_id;
+    //         Identifier id = wafer_id(exp_id[m_BARREL_EC_INDEX],
+    //                                  exp_id[m_LAYER_DISK_INDEX], 
+    //                                  exp_id[m_PHI_MODULE_INDEX],
+    //                                  exp_id[m_ETA_MODULE_INDEX],
+    //                                  exp_id[m_SIDE_INDEX]);
+    //         if (get_hash(id, hash_id, &wcontext)) {
+    //             log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get hash, exp/compact "
+    //                 << show_to_string(id, &wcontext)
+    //                 << " " << (std::string)m_full_wafer_range << endmsg;
+    //             return (1);
+    //         }
+
+    //         // index for the subsequent arrays
+    //         unsigned short index = hash_id;
+    //         assert (hash_id < m_prev_phi_wafer_vec.size());
+    //         assert (hash_id < m_next_phi_wafer_vec.size());
+    //         assert (hash_id < m_prev_eta_wafer_vec.size());
+    //         assert (hash_id < m_next_eta_wafer_vec.size());
+            
+    //         if (pphi) {
+    //             // Get previous phi hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_PHI_MODULE_INDEX] = previous_phi;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get previous phi hash, exp/compact " << id.getString() << " " 
+    //                     << endmsg;
+    //                 return (1);
+    //             }
+    //             m_prev_phi_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (nphi) {
+    //             // Get next phi hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_PHI_MODULE_INDEX] = next_phi;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get next phi hash, exp/compact " << id.getString() << 
+    //                     " " << MSG::hex << id.getString() << MSG::dec << endmsg;
+    //                 return (1);
+    //             }
+    //             m_next_phi_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (peta) {
+    //             // Get previous eta hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_ETA_MODULE_INDEX] = previous_eta;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get previous eta hash, exp/compact " << id.getString() 
+    //                     << " " << std::endl;
+    //                 return (1);
+    //             }
+    //             m_prev_eta_wafer_vec[index] = hash_id;
+    //         }
+            
+    //         if (neta) {
+    //             // Get next eta hash id
+    //             ExpandedIdentifier expId = exp_id;
+    //             expId[m_ETA_MODULE_INDEX] = next_eta;
+    //             Identifier id = wafer_id(expId[m_BARREL_EC_INDEX],
+    //                                      expId[m_LAYER_DISK_INDEX], 
+    //                                      expId[m_PHI_MODULE_INDEX],
+    //                                      expId[m_ETA_MODULE_INDEX],
+    //                                      expId[m_SIDE_INDEX]);
+    //             if (get_hash(id, hash_id, &wcontext)) {
+    //                 log << MSG::ERROR << " EmulsionID::init_neighbors - unable to get next eta hash, exp/compact " << id.getString() 
+    //                     << " " << endmsg;
+    //                 return (1);
+    //             }
+    //             m_next_eta_wafer_vec[index] = hash_id;
+    //         }
+            
+
+//          std::cout << " EmulsionID::init_neighbors "
+//                    << " phi, previous, next " << id[m_PHI_MODULE_INDEX]
+//                    << " " << pphi
+//                    << " " << previous_phi
+//                    << " " << nphi
+//                    << " " << next_phi
+//                    << " eta, previous, next " << id[m_ETA_MODULE_INDEX]
+//                    << " " << peta
+//                    << " " << previous_eta
+//                    << " " << neta
+//                    << " " << next_eta
+//                    << " id " << (std::string)(*first) 
+//                    << std::endl;
+    //     }
+    // }
+    return (0);
+}
+
+
+
+int     
+EmulsionID::initLevelsFromDict()
+{
+
+
+    MsgStream log(m_msgSvc, "EmulsionID");
+    if(!m_dict) {
+        log << MSG::ERROR << " EmulsionID::initLevelsFromDict - dictionary NOT initialized " << endmsg;
+        return (1);
+    }
+    
+    // Find out which identifier field corresponds to each level. Use
+    // names to find each field/leve.
+
+    m_NEUTRINO_INDEX               = 999;
+    m_EMULSION_INDEX                = 999;
+    m_MODULE_INDEX             = 999;
+    m_BASE_INDEX               = 999;
+    m_FILM_INDEX                 = 999;    
+
+    // Save index to a Emulsion region for unpacking
+    ExpandedIdentifier id; 
+    id << neutrino_field_value() << emulsion_field_value();
+    if (m_dict->find_region(id, m_emulsion_region_index)) {
+        log << MSG::ERROR << "EmulsionID::initLevelsFromDict - unable to find emulsion region index: id, reg "  
+            << (std::string)id << " " << m_emulsion_region_index
+            << endmsg;
+        return (1);
+    }
+
+    // Find a Emulsion region
+    IdDictField* field = m_dict->find_field("subdet");
+    if (field) {
+        m_NEUTRINO_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "EmulsionID::initLevelsFromDict - unable to find 'subdet' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("part");
+    if (field) {
+        m_EMULSION_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "EmulsionID::initLevelsFromDict - unable to find 'part' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("module");
+    if (field) {
+        m_MODULE_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "EmulsionID::initLevelsFromDict - unable to find 'module' field "   << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("base");
+    if (field) {
+        m_BASE_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR<< "EmulsionID::initLevelsFromDict - unable to find 'base' field "  << endmsg;
+        return (1);
+    }
+    field = m_dict->find_field("film");
+    if (field) {
+        m_FILM_INDEX = field->m_index;
+    }
+    else {
+        log << MSG::ERROR << "EmulsionID::initLevelsFromDict - unable to find 'film' field " << endmsg;    
+        return (1);
+    }
+    
+    // Set the field implementations
+
+    const IdDictRegion& region = *m_dict->m_regions[m_emulsion_region_index];
+
+    m_neutrino_impl      = region.m_implementation[m_NEUTRINO_INDEX]; 
+    m_emulsion_impl       = region.m_implementation[m_EMULSION_INDEX]; 
+    m_module_impl    = region.m_implementation[m_MODULE_INDEX]; 
+    m_base_impl      = region.m_implementation[m_BASE_INDEX];
+    m_film_impl        = region.m_implementation[m_FILM_INDEX]; 
+
+    if (m_msgSvc) {
+        log << MSG::DEBUG << "decode index and bit fields for each level: " << endmsg;
+        log << MSG::DEBUG << "neutrino    "  << m_neutrino_impl.show_to_string() << endmsg;
+        log << MSG::DEBUG << "emulsion     "  << m_emulsion_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "module  "  << m_module_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "base    "  << m_base_impl.show_to_string() << endmsg; 
+        log << MSG::DEBUG << "film      "  << m_film_impl.show_to_string() << endmsg; 
+    }
+    else {
+        std::cout << " DEBUG decode index and bit fields for each level: " << std::endl;
+        std::cout << " DEBUG neutrino    "  << m_neutrino_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG emulsion     "  << m_emulsion_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG module  "  << m_module_impl.show_to_string() << std::endl; 
+        std::cout << " DEBUG base    "  << m_base_impl.show_to_string() << std::endl;
+        std::cout << " DEBUG film      "  << m_film_impl.show_to_string() << std::endl; 
+    }
+    
+    std::cout << "neutrino "  << m_neutrino_impl.decode_index() << " " 
+              <<   (std::string)m_neutrino_impl.ored_field() << " " 
+              << std::hex    << m_neutrino_impl.mask() << " " 
+              << m_neutrino_impl.zeroing_mask() << " " 
+              << std::dec    << m_neutrino_impl.shift() << " "
+              << m_neutrino_impl.bits() << " "
+              << m_neutrino_impl.bits_offset()
+              << std::endl;
+    std::cout << "emulsion"     << m_emulsion_impl.decode_index() << " " 
+              <<   (std::string)m_emulsion_impl.ored_field() << " " 
+              << std::hex    << m_emulsion_impl.mask() << " " 
+              << m_emulsion_impl.zeroing_mask() << " " 
+              << std::dec    << m_emulsion_impl.shift() << " "
+              << m_emulsion_impl.bits() << " "
+              << m_emulsion_impl.bits_offset()
+              << std::endl;
+    std::cout << "module"<< m_module_impl.decode_index() << " " 
+              <<   (std::string)m_module_impl.ored_field() << " " 
+              << std::hex    << m_module_impl.mask() << " " 
+              << m_module_impl.zeroing_mask() << " " 
+              << std::dec    << m_module_impl.shift() << " "
+              << m_module_impl.bits() << " "
+              << m_module_impl.bits_offset()
+              << std::endl;
+    std::cout << "base"    << m_base_impl.decode_index() << " " 
+              <<   (std::string)m_base_impl.ored_field() << " " 
+              << std::hex    << m_base_impl.mask() << " " 
+              << m_base_impl.zeroing_mask() << " " 
+              << std::dec    << m_base_impl.shift() << " "
+              << m_base_impl.bits() << " "
+              << m_base_impl.bits_offset()
+              << std::endl;
+    std::cout << "film"   << m_film_impl.decode_index() << " " 
+              <<   (std::string)m_film_impl.ored_field() << " " 
+              << std::hex    << m_film_impl.mask() << " " 
+              << m_film_impl.zeroing_mask() << " " 
+              << std::dec    << m_film_impl.shift() << " "
+              << m_film_impl.bits() << " "
+              << m_film_impl.bits_offset()
+              << std::endl;
+
+    return (0);
+}
+
+EmulsionID::size_type       
+EmulsionID::base_hash_max (void) const
+{
+    return m_base_hash_max;
+}
+
+EmulsionID::size_type       
+EmulsionID::film_hash_max (void) const
+{
+    return m_film_hash_max;
+}
+
+EmulsionID::const_id_iterator       EmulsionID::base_begin             (void) const
+{
+    return (m_base_vec.begin());
+}
+
+EmulsionID::const_id_iterator       EmulsionID::base_end               (void) const
+{
+    return (m_base_vec.end());
+}
+
+EmulsionID::const_expanded_id_iterator      EmulsionID::film_begin     (void) const
+{
+    return (m_full_film_range.factory_begin());
+}
+
+EmulsionID::const_expanded_id_iterator      EmulsionID::film_end       (void) const
+{
+    return (m_full_film_range.factory_end());
+}
+
+// From hash get Identifier
+int     
+EmulsionID::get_id          (const IdentifierHash& hash_id,
+                         Identifier& id,
+                         const IdContext* context) const
+{
+
+    int result = 1;
+    id.clear();
+
+    size_t begin = (context) ? context->begin_index(): 0;
+    // cannot get hash if end is 0:
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) { 
+        // No hashes yet for ids with prefixes
+        if (m_BASE_INDEX == end) {
+            if (hash_id < (unsigned int)(m_base_vec.end() - m_base_vec.begin())) {
+                id = m_base_vec[hash_id];
+                result = 0;
+            }
+        }
+        else if (m_FILM_INDEX == end) {
+            // Do not know how to calculate strip id from hash yet!!
+            std::cout << "Do not know how to calculate film id from hash yet!!" << std::endl;
+        }
+    }
+    return (result);
+}
+
+void
+EmulsionID::get_expanded_id (const Identifier& id,
+                         ExpandedIdentifier& exp_id,
+                         const IdContext* context) const
+{
+    exp_id.clear();
+    exp_id << neutrino_field_value()
+           << emulsion_field_value()
+           << module(id)
+           << base(id);
+    if(!context || context->end_index() == m_FILM_INDEX) 
+    {
+       	exp_id << film(id);
+    }
+}
+
+int     
+EmulsionID::get_hash        (const Identifier& id, 
+                         IdentifierHash& hash_id,
+                         const IdContext* context) const
+{
+
+    // Get the hash code from either a vec (for base) or calculate
+    // it (films). For the former, we convert to compact and call
+    // get_hash again. For the latter, we calculate the hash from the
+    // Identifier.
+
+    int result = 1;
+    hash_id = 0;
+    size_t begin = (context) ? context->begin_index(): 0;
+    size_t end   = (context) ? context->end_index()  : 0; 
+    if (0 == begin) {
+        // No hashes yet for ids with prefixes
+        if (m_BASE_INDEX  == end) {
+            hash_id = base_hash(id);
+            if (hash_id.is_valid()) result = 0;
+        }
+        else if (context && context->end_index() == m_FILM_INDEX) {
+            // Must calculate for strip hash
+            ExpandedIdentifier new_id;
+            get_expanded_id(id, new_id);
+            hash_id =  m_full_film_range.cardinalityUpTo(new_id);
+            result = 0;
+        }
+    }
+    return (result);
+}
+
+
+void    
+EmulsionID::test_base_packing      (void) const
+{
+    MsgStream log(m_msgSvc, "EmulsionID");
+
+    if (m_dict) {
+        
+        int nids = 0;
+        int nerr = 0;
+        IdContext context = base_context();
+        const_id_iterator first = m_base_vec.begin();
+        const_id_iterator last  = m_base_vec.end();
+        for (; first != last; ++first, ++nids) {
+            Identifier id = (*first);
+            ExpandedIdentifier exp_id;
+            get_expanded_id(id, exp_id, &context);
+            Identifier new_id = base_id(exp_id[m_MODULE_INDEX],
+                                         exp_id[m_BASE_INDEX]);
+            if (id != new_id) {
+                log << MSG::ERROR << "EmulsionID::test_base_packing: new and old compacts not equal. New/old/expanded ids " 
+                    << MSG::hex << show_to_string(id) << " " << show_to_string(new_id) << " " << MSG::dec 
+                    << (std::string)exp_id << endmsg;
+                nerr++;
+                continue;
+            }
+            // check module id
+            if (!exp_id[m_BASE_INDEX]) {
+                
+                Identifier new_id1 = module_id(exp_id[m_MODULE_INDEX]);
+                if (id != new_id1) {
+                    log << MSG::ERROR << "EmulsionID::test_base_packing: new and old module ids not equal. New/old/expanded ids " 
+                        << MSG::hex << show_to_string(id) << " " << show_to_string(new_id1) << " " << MSG::dec 
+                        << (std::string)exp_id << endmsg;
+                    nerr++;
+                    continue;
+                }
+            }
+        }
+
+        if (m_msgSvc) { 
+            log << MSG::DEBUG << "EmulsionID::test_base_packing: tested base and module ids. nids, errors " 
+                << nids << " " << nerr << endmsg;
+        }
+        else {
+            std::cout << " DEBUG EmulsionID::test_base_packing: tested base and module ids. nids, errors " 
+                      << nids << " " << nerr << std::endl;
+        }
+        
+        nids = 0;
+        context = film_context();
+        const_expanded_id_iterator      first_emulsion = film_begin();  
+        const_expanded_id_iterator      last_emulsion  = film_end();
+        for (; first_emulsion != last_emulsion; ++first_emulsion, ++nids) {
+            // if (nids%10000 != 1) continue;
+            const ExpandedIdentifier& exp_id = *first_emulsion;
+            ExpandedIdentifier new_exp_id;
+
+            Identifier id = base_id(exp_id[m_MODULE_INDEX],
+                                     exp_id[m_BASE_INDEX]);
+            get_expanded_id(id, new_exp_id, &context);
+            if (exp_id[0] != new_exp_id[0] ||
+                exp_id[1] != new_exp_id[1] ||
+                exp_id[2] != new_exp_id[2] ||
+                exp_id[3] != new_exp_id[3])
+            {
+                log << MSG::ERROR << "EmulsionID::test_base_packing: new and old ids not equal. New/old/compact ids "
+                    << (std::string)new_exp_id << " " << (std::string)exp_id
+                    << " " << show_to_string(id) << endmsg;
+                continue;
+            }
+
+            Identifier filmid	;
+	        Identifier filmid1	;
+           	filmid = film_id ( 
+                       exp_id[m_MODULE_INDEX],
+					   exp_id[m_BASE_INDEX],
+					   exp_id[m_FILM_INDEX]);
+
+    	   	filmid1 = film_id (	    
+                        module(filmid),
+                        base(filmid),
+                        film(filmid));
+
+            if (filmid != filmid1) {
+                log << MSG::ERROR << "EmulsionID::test_base_packing: new and old pixel ids not equal. New/old ids "
+                    << " " << show_to_string(filmid1) << " " 
+                    << show_to_string(filmid) << endmsg;
+            }
+        }
+
+        if (m_msgSvc) {
+            log << MSG::DEBUG << "EmulsionID::test_base_packing: Successful tested " 
+                << nids << " ids. " 
+                << endmsg;
+        }
+        else {
+            std::cout << " DEBUG EmulsionID::test_base_packing: Successful tested " 
+                      << nids << " ids. " 
+                      << std::endl;
+        }
+    }
+    else {
+        log << MSG::ERROR << "EmulsionID::test_base_packing: Unable to test base packing - no dictionary has been defined. " 
+            << endmsg;
+    }
+}
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/CMakeLists.txt b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..744ed53ce735f0e7493a6aff8ecb9a86305bdc0d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/CMakeLists.txt
@@ -0,0 +1,21 @@
+################################################################################
+# Package: NeutrinoReadoutGeometry
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoReadoutGeometry )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( Eigen )
+find_package( GeoModel )
+
+# Component(s) in the package:
+atlas_add_library( NeutrinoReadoutGeometry
+                   src/*.cxx
+                   PUBLIC_HEADERS NeutrinoReadoutGeometry
+                   INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS}
+                   DEFINITIONS ${CLHEP_DEFINITIONS}
+                   LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${GEOMODEL_LIBRARIES} AthenaKernel CxxUtils FaserDetDescr GeoModelFaserUtilities GeoPrimitives Identifier GaudiKernel NeutrinoIdentifier TrkDetElementBase TrkSurfaces TrkEventPrimitives StoreGateLib SGtests AthenaBaseComps DetDescrConditions
+                   PRIVATE_LINK_LIBRARIES AthenaPoolUtilities IdDictDetDescr )
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/EmulsionDetectorManager.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/EmulsionDetectorManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..29be29e1bae0b55c0a56d10c8d6d16725e0ca699
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/EmulsionDetectorManager.h
@@ -0,0 +1,163 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// EmulsionDetectorManager.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_EMULSIONDETECTORMANAGER_H
+#define NEUTRINOREADOUTGEOMETRY_EMULSIONDETECTORMANAGER_H
+
+#include "GeoPrimitives/GeoPrimitives.h"
+
+#include "GeoModelKernel/GeoVPhysVol.h"
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+
+#include "NeutrinoIdentifier/EmulsionID.h"
+  
+class StoreGateSvc;
+class Identifier; 
+class IdentifierHash;
+class GeoAlignableTransform;
+class GeoVFullPhysVol;
+class GeoVPhysVol;
+class GeoVAlignmentStore;
+class CondAttrListCollection;
+
+namespace NeutrinoDD {
+
+  class NeutrinoDetectorElement;
+  class ExtendedAlignableTransform;
+  class EmulsionDetectorDesign;
+
+  /** @class EmulsionDetectorManager
+  
+      Dedicated detector manager extending the functionality of the NeutrinoDetectorManager
+      with dedicated Emulsion information, access.
+      
+      @author: Grant Gorfine
+      - modified and maintained by Nick Styles & Andreas Salzburger
+      - modified for FASER by D. Casper
+      */
+      
+  class EmulsionDetectorManager : public NeutrinoDetectorManager  {
+
+    public:
+    
+      // Constructor
+      EmulsionDetectorManager( StoreGateSvc* detStore );
+     
+      // Destructor
+      virtual ~EmulsionDetectorManager();
+     
+      /** Access Raw Geometry */
+      virtual unsigned int getNumTreeTops()           const override;
+      virtual PVConstLink  getTreeTop(unsigned int i) const override;
+      /** Add tree top */
+      void addTreeTop(PVLink); 
+    
+    
+      //
+      // Access Readout Elements
+      //
+    
+      /** access to individual elements via Identifier */
+      virtual NeutrinoDetectorElement * getDetectorElement(const Identifier &id) const override;
+
+      /** access to individual elements via IdentifierHash */
+      virtual NeutrinoDetectorElement * getDetectorElement(const IdentifierHash &idHash) const override;
+      
+      /** access to individual elements via module numbering schema */
+      NeutrinoDetectorElement * getDetectorElement(int module, int base, int film) const;
+    
+      /** access to whole collectiom via iterators */
+      virtual const NeutrinoDetectorElementCollection * getDetectorElementCollection() const override;
+      virtual NeutrinoDetectorElementCollection::const_iterator getDetectorElementBegin() const override;
+      virtual NeutrinoDetectorElementCollection::const_iterator getDetectorElementEnd() const override;
+    
+      /** Add elememts during construction */
+      virtual void addDetectorElement(NeutrinoDetectorElement * element) override;
+    
+      /** Add alignable transforms. No access to these, they will be changed by manager: */
+      virtual void addAlignableTransform (int level,
+    				                      const Identifier &id, 
+    				                      GeoAlignableTransform *xf,
+    				                      const GeoVFullPhysVol * child);
+      
+      /**  As above but does a dynamic_cast to GeoVFullPhysVol */
+      virtual void addAlignableTransform (int level,
+    				                      const Identifier &id, 
+    				                      GeoAlignableTransform *xf,
+    				                      const GeoVPhysVol * child); 
+    
+      /** Initialize the neighbours. This can only be done when all elements are built. */
+      virtual void initNeighbours() override;
+
+      /** Check identifier is for this detector */
+      virtual bool identifierBelongs(const Identifier & id) const override;
+    
+      /** Access to module design, casts to EmulsionDetectorDesign */
+      const NeutrinoDetectorDesign * getEmulsionDesign() const;
+
+      /** Process new global DB folders for L1 and L2 **/
+      virtual
+      bool processGlobalAlignment(const std::string &, int level, FrameType frame,
+                                  const CondAttrListCollection* obj,
+                                  GeoVAlignmentStore* alignStore) const override;
+
+      // comply with NeutrinoDetectorManager interface
+      bool processSpecialAlignment(const std::string & key,
+                                   NeutrinoDD::AlignFolderType alignfolder) const override;
+
+      bool processSpecialAlignment(const std::string& key,
+                                   const CondAttrListCollection* obj=nullptr,
+                                   GeoVAlignmentStore* alignStore=nullptr) const override;
+
+
+    private:
+      /** implements the main alignment update for delta transforms in different frames,
+          it translates into the LocalDelta or GlobalDelta function of NeutrinoDetectorManager
+      */
+      virtual bool setAlignableTransformDelta(int level, 
+                                              const Identifier & id, 
+                                              const Amg::Transform3D & delta,
+                                              FrameType frame,
+                                              GeoVAlignmentStore* alignStore) const override;
+      
+      /** Prevent copy and assignment */
+      const EmulsionDetectorManager & operator=(const EmulsionDetectorManager &right);
+      EmulsionDetectorManager(const EmulsionDetectorManager &right); 
+    
+      virtual const EmulsionID* getIdHelper() const override;
+       
+      // Private member data
+      std::vector<PVLink>                                           m_volume;  
+      NeutrinoDetectorElementCollection                                m_elementCollection;
+      typedef std::map<Identifier, ExtendedAlignableTransform *>    AlignableTransformMap;
+      std::vector< AlignableTransformMap >                          m_higherAlignableTransforms;
+      std::vector< ExtendedAlignableTransform *>                    m_alignableTransforms; 
+      const EmulsionID*                                                 m_idHelper;
+      
+      /** This variable switches the how the local alignment corrections are applied
+          If true they will be calcualted on top  of all of other corrections but in the default reference frame
+          If false they will be calcualted  on top  of all of other corrections but in the globally aligned reference frame    
+      */
+      bool                                                          m_isLogical;      
+      
+      
+    };
+
+} // namespace NeutrinoDD
+
+#ifndef GAUDI_NEUTRAL
+#include "AthenaKernel/CLASS_DEF.h" 
+CLASS_DEF(NeutrinoDD::EmulsionDetectorManager, 196479620, 1) 
+#endif
+
+#endif // NEUTRINOREADOUTGEOMETRY_EMULSIONDETECTORMANAGER_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/ExtendedAlignableTransform.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/ExtendedAlignableTransform.h
new file mode 100644
index 0000000000000000000000000000000000000000..95b8ef11aaebf1b3786935b7a46d438bd0ce538a
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/ExtendedAlignableTransform.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// ExtendedAlignableTransform.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef SCINTREADOUTGEOMETRY_EXTENDEDALIGNABLETRANSFORM_H
+#define SCINTREADOUTGEOMETRY_EXTENDEDALIGNABLETRANSFORM_H
+
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+#include "GeoModelKernel/GeoVFullPhysVol.h"
+
+namespace NeutrinoDD {
+
+    /** @class ExtendedAlignableTransform 
+    
+    Class to hold alignable transform plus a pointer to the child volume and
+    optionally a frame volume.
+
+    @author: Grant Gorfine
+    - modified & maintained: Nick Styles & Andreas Salzburger 
+    */
+    
+    class ExtendedAlignableTransform
+    {
+    
+    public:
+    
+      ExtendedAlignableTransform(GeoAlignableTransform * alignableTransform, 
+    			     const GeoVFullPhysVol * child,
+    			     const GeoVFullPhysVol * frame = 0)
+        : m_alignableTransform(alignableTransform),
+          m_child(child),
+          m_frame(frame)
+      {};
+    
+      GeoAlignableTransform * alignableTransform() {return m_alignableTransform;}
+      const GeoVFullPhysVol * child()  {return m_child;}
+      const GeoVFullPhysVol * frame()  {return m_frame;}
+    
+    private:
+      
+      GeoAlignableTransform * m_alignableTransform;
+      const GeoVFullPhysVol * m_child;
+      const GeoVFullPhysVol * m_frame;
+    
+    };
+
+
+} // end namespace 
+
+#endif // SCINTREADOUTGEOMETRY_EXTENDEDALIGNABLETRANSFORM_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoCommonItems.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoCommonItems.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef57e62d08e57ceba755034b883b0c1159eec95d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoCommonItems.h
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoCommonItems.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINOCOMMONITEMS_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINOCOMMONITEMS_H
+
+class FaserDetectorID;
+
+// Message Stream Member
+#include "AthenaKernel/MsgStreamMember.h"
+#include "CxxUtils/checker_macros.h"
+// #include "InDetCondTools/ISiLorentzAngleTool.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/RCBase.h"
+
+
+#include "GaudiKernel/ServiceHandle.h"
+#include "CLHEP/Geometry/Transform3D.h"
+
+#include <mutex>
+
+// mutable Athena::MsgStreamMember issues warnings.
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;
+
+namespace NeutrinoDD {
+
+    /** @class NeutrinoCommonItems
+    
+        Helper class to concentrate common items, such as the pointer to the IdHelper,
+        
+        To be used for Emulsion
+        
+        @author: Grant Gorfine
+        mondified & maintained: Nick Styles, Andreas Salzburger
+        modified: Dave Casper
+        */
+
+    class NeutrinoCommonItems: public RCBase 
+    {
+    
+        public:
+        
+          NeutrinoCommonItems(const FaserDetectorID* const idHelper);
+          
+          const FaserDetectorID* getIdHelper() const;
+        //   const HepGeom::Transform3D & solenoidFrame() const;
+        //   void setSolenoidFrame(const HepGeom::Transform3D & transform) const; 
+
+          //Declaring the Message method for further use
+          MsgStream& msg (MSG::Level lvl) const { return m_msg.get() << lvl; }
+        
+          //Declaring the Method providing Verbosity Level
+          bool msgLvl (MSG::Level lvl) const { return m_msg.get().level() <= lvl; }
+        
+        private:
+        
+          //Declaring private message stream member.
+          mutable Athena::MsgStreamMember m_msg;
+          
+          const FaserDetectorID* m_idHelper; 
+        //   mutable HepGeom::Transform3D m_solenoidFrame ATLAS_THREAD_SAFE; // Guarded by m_mutex
+
+          mutable std::mutex m_mutex;
+    };
+    
+    
+    inline const FaserDetectorID* NeutrinoCommonItems::getIdHelper() const
+    {
+      return m_idHelper;
+    }
+    
+    
+    // inline const HepGeom::Transform3D & SiCommonItems::solenoidFrame() const
+    // {
+    //   std::lock_guard<std::mutex> lock{m_mutex};
+    //   return m_solenoidFrame;
+    //   // This reference might be changed by setSolenoidFrame.
+    //   // However, it occurrs very rarely.
+    // }
+    
+    
+
+} // End namespace ScintDD
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINOCOMMONITEMSS_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDD_Defs.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDD_Defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..3953b3f0a34902b7fc09c57755149bc772f724c2
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDD_Defs.h
@@ -0,0 +1,22 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDD_Defs.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODD_Defs_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODD_Defs_H
+
+
+namespace NeutrinoDD {
+  enum FrameType {local, global, other};
+//   enum CarrierType {holes, electrons};
+  // new enumerator to select given align-folder structure
+  enum AlignFolderType {none = -1, static_run1 = 0, timedependent_run2 = 1};
+}
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODD_DEFS_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h
new file mode 100644
index 0000000000000000000000000000000000000000..a44bb7d6d2aa992e982dfa96b2a24fe5b76b7a2e
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h
@@ -0,0 +1,171 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDetectorDesign.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORDESIGN_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORDESIGN_H
+
+// Input/output classes
+#include "CLHEP/Geometry/Point3D.h"
+#include "CLHEP/Geometry/Vector3D.h"
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/RCBase.h"
+#include "NeutrinoDD_Defs.h"
+
+#include <list>
+#include <vector>
+
+
+class Identifier;
+
+namespace Trk {
+class SurfaceBounds;
+class RectangleBounds;
+}
+
+namespace NeutrinoDD {
+// class SiReadoutCellId;
+// class SiCellId;
+// class SiDiode;
+// class SiReadoutCell;
+class NeutrinoLocalPosition;
+class NeutrinoIntersect;
+
+enum DetectorShape {
+  Box=0, Other
+};
+
+/** @class NeutrinoDetectorDesign
+
+   Base class for the detector design classes for Emulsion.
+   These hold the local description of the detector elements which are
+   shared by a number of detector elements.
+
+    @author A. Calvet, Grant Gorfine
+ */
+
+class NeutrinoDetectorDesign: public RCBase {
+public:
+    enum Axis {
+        xAxis = 0, yAxis, zAxis
+    };
+
+    ///////////////////////////////////////////////////////////////////
+    // Public methods:
+    ///////////////////////////////////////////////////////////////////
+public:
+    /** Constructor
+     */
+
+    NeutrinoDetectorDesign( const double width,
+                            const double height,
+                            const double thickness );
+
+    /** Destructor: */
+    virtual ~NeutrinoDetectorDesign();
+
+    ///////////////////////////////////////////////////////////////////
+    // Const methods:
+    ///////////////////////////////////////////////////////////////////
+
+    /** Test if point is in the active part of the detector with specified tolerances */
+    NeutrinoIntersect inDetector(const NeutrinoLocalPosition &localPosition, double xTol,
+                              double yTol) const;
+
+    /** which axis in hit frame is horizontal */
+    /** phi corresponds to "width" */
+    NeutrinoDetectorDesign::Axis phiAxis() const;
+
+    /** which axis in hit frame is vertical */
+    /** eta corresponds to "length" */
+    NeutrinoDetectorDesign::Axis etaAxis() const;
+
+    /** which axis in hit frame is thickness/beam direction */
+    NeutrinoDetectorDesign::Axis depthAxis() const;
+
+    ///////////////////////////////////////////////////////////////////
+    // Pure virtual methods:
+    ///////////////////////////////////////////////////////////////////
+
+    /** Returns distance to nearest detector active edge
+       +ve = inside
+       -ve = outside */
+    virtual void distanceToDetectorEdge(const NeutrinoLocalPosition &localPosition,
+                                        double &xDist, double &yDist) const;
+
+    /** Method to calculate height of a module */
+    virtual double height() const;
+
+    /** Method to calculate average width of a module */
+    virtual double width() const;
+
+    /** Method which returns thickness of the silicon wafer */
+    double thickness() const;
+
+    // /** Shape of element */
+    virtual DetectorShape shape() const;
+
+    /**  Element boundary */
+    virtual const Trk::SurfaceBounds &bounds() const;
+
+    ///////////////////////////////////////////////////////////////////
+    // Private methods:
+    ///////////////////////////////////////////////////////////////////
+private:
+    NeutrinoDetectorDesign();
+
+    ///////////////////////////////////////////////////////////////////
+    // Private data:
+    ///////////////////////////////////////////////////////////////////
+private:
+    double m_thickness; // !< thickness of plate
+    double m_width;     // !< dimension in "phi" direction 
+    double m_height;    // !< dimnesion in "eta" direction
+
+    NeutrinoDetectorDesign::Axis m_phiAxis;  // which axis in hit frame is horizontal ("width" axis)
+    NeutrinoDetectorDesign::Axis m_etaAxis;  // which axis in hit frame is vertical ("length" axis)
+    NeutrinoDetectorDesign::Axis m_depthAxis; // which axis in hit frame is depth/beam?
+
+    const Trk::RectangleBounds* m_bounds;
+
+    // Disallow Copy and assignment;
+    NeutrinoDetectorDesign(const NeutrinoDetectorDesign &design);
+    NeutrinoDetectorDesign &operator = (const NeutrinoDetectorDesign &design);
+};
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+inline double NeutrinoDetectorDesign::thickness() const {
+    return m_thickness;
+}
+
+inline double NeutrinoDetectorDesign::width() const {
+    return m_width;
+}
+
+inline double NeutrinoDetectorDesign::height() const {
+    return m_height;
+}
+
+inline NeutrinoDetectorDesign::Axis NeutrinoDetectorDesign::phiAxis() const {
+    return m_phiAxis;
+}
+
+inline NeutrinoDetectorDesign::Axis NeutrinoDetectorDesign::etaAxis() const {
+    return m_etaAxis;
+}
+
+inline NeutrinoDetectorDesign::Axis NeutrinoDetectorDesign::depthAxis() const {
+    return m_depthAxis;
+}
+
+}  // namespace NeutrinoDD
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORDESIGN_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElement.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElement.h
new file mode 100644
index 0000000000000000000000000000000000000000..14641723e8d8d81878772e3d4cba75c2b5158f3d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElement.h
@@ -0,0 +1,687 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file NeutrinoDetectorElement.h
+**/
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENT_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENT_H
+
+// Base class.
+#include "TrkDetElementBase/TrkDetElementBase.h"
+
+// Data member classes
+#include "CxxUtils/CachedUniquePtr.h"
+#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoLocalPosition.h"
+#include "TrkEventPrimitives/ParamDefs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoIntersect.h"
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "GeoPrimitives/CLHEPtoEigenConverter.h"
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GeoModelKernel/GeoDefinitions.h"
+
+#include "CLHEP/Geometry/Point3D.h"
+
+#include <atomic>
+#include <mutex>
+
+class FaserDetectorID;
+class GeoVFullPhysVol;
+class GeoAlignmentStore;
+
+namespace Trk{
+ class Surface;
+ class SurfaceBounds;
+}
+
+namespace NeutrinoDD {
+
+  /**
+  
+   @class NeutrinoDetectorElement
+  
+   Class to hold geometrical description of a neutrino detector element. 
+   A detector element is a single emulsion film.
+    
+   @par Coordinate Frames.
+  
+   The following coordinate frames are used in these elements.
+  
+    - Global frame:\n
+         Currently global frame in G4/GeoModel. Probably eventually
+         will be global frame most suitable for reconstruction 
+         (eg solenoid axis).
+  
+    - Local hit frame:\n 
+         Local frame for hits. It is the same as local frame in G4 and GeoModel. 
+         I also refer to this as the local simulation frame. 
+         In FASER:
+            - hitDepth = local z = global z (always beam direction)
+            - hitEta   = local y = global y (always vertical up)
+            - hitPhi   = local x (right-handed wrt y cross z, hence same as global x; left of beam direction)
+          (hitPhi, hitEta, hitDepth) is right-handed
+         In ATLAS (retained for reference):
+         By convention elements are orientated such that:
+            - hitDepth = local x
+            - hitPhi   = local y
+            - hitEta   = local z
+         Directions of these correspond to the physical wafer. Consequently hitDepth and hitPhi axes go in 
+         different directions depending on the orientation of the module.
+         The readout side is determined from design()->readoutSide(). 
+  
+   - Local reconstruction frame:\n 
+            - distPhi  = local x (= global x in FASER)
+            - distEta  = local y (= global y in FASER)
+            - distDepth = local z (= global z in FASER)
+            .
+         (In ATLAS:)
+         The directions of the axes are defined as
+            - distPhi in direction of increasing phi
+            - distEta in direction of increasing z in barrel and increasing r in endcap.
+            - distDepth (normal) choosen to give right-handed coordinate. 
+               =>  away from intersection point for barrel, decreasing z for endcap
+     
+   @par Overview of Methods 
+  
+   Methods are grouped into the the following categories
+  
+      -  Identification
+      -  Navigation
+      -  Transformation/Orientation
+      -  Module Frame
+      -  Element Extent
+      -  Design methods
+      -  Intersection Tests
+      -  Lorentz Correction
+      -  Readout cell id
+      -  Miscellaneous
+      -  Cache handling.
+  
+  
+   @author Grant Gorfine
+   - modified & maintained: Nick Styles, Andreas Salzburger
+   - modified Nigel Hessey: get directions from the design instead of hard-wiring them   
+   - modified for Faser: Dave Casper
+
+  */  
+
+  class NeutrinoDetectorElement : public Trk::TrkDetElementBase {
+
+      ///////////////////////////////////////////////////////////////////
+      // Public methods:
+      ///////////////////////////////////////////////////////////////////
+    public:
+    
+    
+      /// Constructor:
+      NeutrinoDetectorElement(const Identifier &id, 
+                           const NeutrinoDetectorDesign *design,
+                           const GeoVFullPhysVol *geophysvol,
+                           const NeutrinoCommonItems * commonItems,
+                           const GeoAlignmentStore* geoAlignStore=nullptr);
+    
+      /// Destructor:
+      virtual ~NeutrinoDetectorElement();
+    
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Identification
+      /// Methods to identify the element and identifier manipulation.
+      // 
+      ///////////////////////////////////////////////////////////////////
+    
+      //@{
+    
+      /// identifier of this detector element:
+      Identifier identify() const;
+    
+      /// identifier hash
+      IdentifierHash identifyHash() const;
+    
+      /// Returns the id helper
+      const FaserDetectorID* getIdHelper() const;
+    
+      bool isEmulsion() const;
+
+      // Identifier <-> pmt 
+    
+      /// Identifier from pmt 
+      Identifier identifierFromCellId(const int& cellId) const;
+    
+      /// pmt from Identifier
+      int   cellIdFromIdentifier(const Identifier & identifier) const;
+      
+      //@}
+    
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Navigation
+      /// Methods to access neighbours. 
+      //
+      ///////////////////////////////////////////////////////////////////
+    
+      //@{
+        const NeutrinoDetectorElement* nextInZ() const;
+        const NeutrinoDetectorElement* prevInZ() const;
+      //@}
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Transformation/Orientation
+      //
+      ///////////////////////////////////////////////////////////////////
+    
+      //@{
+      // Position 
+      /// Local (simulation/hit frame) to global transform
+      virtual const GeoTrf::Transform3D & transformHit() const;
+      /// Local (reconstruction frame) to global transform
+      const Amg::Transform3D & transform() const;
+      /// Default Local (reconstruction frame) to global transform
+      /// ie with no misalignment. 
+      const HepGeom::Transform3D defTransformCLHEP() const;
+      const Amg::Transform3D defTransform() const;
+      /// Center in global coordinates
+      const Amg::Vector3D & center() const;
+    
+      const HepGeom::Transform3D & transformCLHEP() const;
+    
+      /// Simulation/Hit local frame to reconstruction local frame. 2D.
+      //  TODO: Will change order of parameters at some point.
+      Amg::Vector2D hitLocalToLocal(double xEta, double xPhi) const;
+      /// Same as previuos method but 3D.
+      HepGeom::Point3D<double> hitLocalToLocal3D(const HepGeom::Point3D<double> & hitPosition) const;
+    
+      /// Transform to go from local reconstruction frame to local hit frame.
+      const HepGeom::Transform3D recoToHitTransform() const;
+    
+      /// Directions of hit depth,phi,eta axes relative to reconstruction local position
+      /// axes (LocalPosition). Returns +/-1.
+      double hitDepthDirection() const;
+      /// See previous method.
+      double hitPhiDirection() const;
+      /// See previous method.
+      double hitEtaDirection() const;
+    
+      // To determine if readout direction between online and offline needs swapping, see methods
+      // swapPhiReadoutDirection() and swapEtaReadoutDirection() below in "Readout Cell id" section
+    
+      // Orientation. 
+      // Directions.
+      //  phiAxis - in same direction as increasing phi and identifier phi_index/strip. 
+      //            NB. This requires some flipping of axes with repsect to the hits.  
+      //  etaAxis - in direction of increasing z in the barrel and increasing r in the endcap. 
+      //  normal  - choosen to give right-handed coordinate frame (x=normal,y=phiAxis,z=etaAxis)
+      //            NB. This requires some flipping of axes with repsect to the hits.  
+      
+      /// Get reconstruction local x axes in global frame. 
+      const Amg::Vector3D & phiAxis() const;
+      const HepGeom::Vector3D<double> & phiAxisCLHEP() const;
+      /// Get reconstruction local y axes in global frame. 
+      const Amg::Vector3D & etaAxis() const;
+      const HepGeom::Vector3D<double> & etaAxisCLHEP() const;
+      /// Get reconstruction local normal axes in global frame. Choosen to give right-handed coordinate frame.
+      const Amg::Vector3D & normal() const;
+     
+      /// transform a hit local position into a global position:
+      HepGeom::Point3D<double> globalPositionHit(const HepGeom::Point3D<double> &simulationLocalPos) const;
+      Amg::Vector3D globalPositionHit(const Amg::Vector3D &simulationLocalPos) const;
+      
+      /// transform a reconstruction local position into a global position:
+      HepGeom::Point3D<double> globalPosition(const HepGeom::Point3D<double> &localPos) const;
+      Amg::Vector3D globalPosition(const Amg::Vector3D &localPos) const;
+
+      /// as in previous method but for 2D local position
+      HepGeom::Point3D<double> globalPositionCLHEP(const Amg::Vector2D &localPos) const;
+      
+      Amg::Vector3D globalPosition(const Amg::Vector2D &localPos) const;
+    
+      /// transform a global position into a 2D local position (reconstruction frame)
+      Amg::Vector2D localPosition(const HepGeom::Point3D<double> & globalPosition) const;
+
+      Amg::Vector2D localPosition(const Amg::Vector3D& globalPosition) const;
+     
+      /// Element Surface
+      virtual Trk::Surface & surface();
+      virtual const Trk::Surface & surface() const;
+    
+      //@}
+
+      /** Returns the full list of surfaces associated to this detector element */
+      virtual const std::vector<const Trk::Surface*>& surfaces() const;
+
+      /**
+      
+      @name Base Frame 
+      Methods to help work with the film frame. 
+      */
+      
+      //@{
+    
+      /// Film to global frame transform. 
+      /// Includes misalignment. 
+      //const HepGeom::Transform3D & moduleTransform() const;
+      const Amg::Transform3D & filmTransform() const;
+    
+      /// Default film to global frame transform, ie with no misalignment. 
+      Amg::Transform3D defFilmTransform() const;
+
+      /// Take a transform of the local element frame and return its equivalent in the base frame.
+      //HepGeom::Transform3D localToModuleFrame(const HepGeom::Transform3D & localTransform) const;
+      Amg::Transform3D localToBaseFrame(const Amg::Transform3D & localTransform) const;
+    
+
+      /// Transformation from local element to base frame.  This can be
+      /// used to take a local position in the element frame and transform
+      /// it to a position in the base frame. If one is already in the
+      /// base frame it will return the Identity transform.
+      //HepGeom::Transform3D localToModuleTransform() const;
+      Amg::Transform3D localToBaseTransform() const;
+
+
+      //@}
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Element Extent
+      /// Methods to get extent of element in x, y and z.  
+      ///////////////////////////////////////////////////////////////////
+    
+      //@{
+      // Extent in x,y and z
+      double xMin() const;
+      double xMax() const;
+      double yMin() const;
+      double yMax() const;
+      double zMin() const;
+      double zMax() const;
+    
+      //@}
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Design methods
+      //
+      ///////////////////////////////////////////////////////////////////
+      //@{
+    
+      /// access to the local description:
+      const NeutrinoDetectorDesign &design() const;
+    
+      // Methods from design
+      double width() const; // Width in x direction.
+      double height() const; // Length in y direction 
+      double thickness() const; // Thickness in z direction
+    
+      virtual const Trk::SurfaceBounds & bounds() const;
+    
+      // Test that it is in the active region
+      // Intersect has 3 states
+      // bool SiIntersect::in() const // definitely in
+      // bool SiIntersect::out() const // definitely out
+      // bool SiIntersect::nearBoundary() const // near a boundary within the tolerances 
+      // bool SiIntersect::mayIntersect() const // in() OR nearBoundary()
+      NeutrinoIntersect inDetector(const Amg::Vector2D & localPosition, double phiTol, double etaTol) const;
+      NeutrinoIntersect inDetector(const HepGeom::Point3D<double> & globalPosition, double phiTol, double etaTol) const;
+
+      //@}
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Cache handling.
+      //
+      ///////////////////////////////////////////////////////////////////
+      //@{.
+      //   - Methods to handle invalidating and updating caches. The cached values include values that are affected by alignment
+      //     Surface are only created on demand.  The method updateAllCaches also creates the surfaces as well as calling updateCache.
+      //     Conditions cache contains Lorentz angle related quantities.
+     
+      /// Signal that cached values are no longer valid.
+      /// Invalidate general cache
+      // void invalidate ATLAS_NOT_THREAD_SAFE () const;
+      void invalidate();
+    
+      ///Set/calculate cache values 
+      void setCache(){
+        updateCache();
+      } 
+     ///Set/calculate all cache values including  surfaces.  
+      void setAllCaches(){
+        updateAllCaches();
+      } 
+      //@}
+    
+      ///////////////////////////////////////////////////////////////////
+      //
+      /// @name Methods to satisfy TrkDetElementBase interface
+      //
+      ///////////////////////////////////////////////////////////////////
+      //{@
+      virtual const Amg::Transform3D & transform(const Identifier&) const {return transform();}
+      virtual const Trk::Surface& surface (const Identifier&) const {return surface();}
+      virtual const Amg::Vector3D& center (const Identifier&) const {return center();}
+      virtual const Amg::Vector3D& normal (const Identifier&) const {return normal();}
+      virtual const Trk::SurfaceBounds & bounds(const Identifier&) const {return bounds();}
+      //@}
+    
+      //////////////////////////////////////////////////////////////////////////////////////
+
+      void setNextInZ(const NeutrinoDetectorElement* element);
+      void setPrevInZ(const NeutrinoDetectorElement* element);
+
+      //////////////////////////////////////////////////////////////////////////////////////
+    
+    public:
+    
+      const NeutrinoCommonItems* getCommonItems() const;
+    
+      ///////////////////////////////////////////////////////////////////
+      // Private methods:
+      ///////////////////////////////////////////////////////////////////
+    
+    private:
+      /// Recalculate  cached values. 
+      void updateCache() const;
+   
+      /// Update all caches including surfaces.
+      void updateAllCaches() const;
+    
+
+      // Common code for constructors.
+      void commonConstructor();
+    
+      // Calculate extent in x, y and z. The values are cached and there
+      // are xMin(), xMax etc methods.
+      void getExtent(double &xMin, double &xMax,
+                     double &yMin, double &yMax,
+                     double &zMin, double &zMax) const;
+    
+      // Return the four corners of an element in local coordinates.
+      // Pass it an array of length 4.
+      // This function is used by getEtaPhiRegion()
+      void getCorners(HepGeom::Point3D<double> *corners) const;
+    
+      //Declaring the Message method for further use
+      MsgStream& msg (MSG::Level lvl) const { return m_commonItems->msg(lvl);}
+    
+      //Declaring the Method providing Verbosity Level
+      bool msgLvl (MSG::Level lvl) const { return m_commonItems->msgLvl(lvl);}
+    
+    
+      ///////////////////////////////////////////////////////////////////
+      // Private methods:
+      ///////////////////////////////////////////////////////////////////
+    private:
+      // Don't allow copying.
+      NeutrinoDetectorElement();
+      NeutrinoDetectorElement(const NeutrinoDetectorElement&);
+      NeutrinoDetectorElement &operator=(const NeutrinoDetectorElement&);
+
+      ///////////////////////////////////////////////////////////////////
+      // Protected data:
+      ///////////////////////////////////////////////////////////////////
+    protected:
+      Identifier m_id; // identifier of this detector element
+      IdentifierHash m_idHash; // hash id
+      const NeutrinoDetectorDesign *m_design; // local description of this detector element
+      const NeutrinoCommonItems * m_commonItems;
+    
+      const NeutrinoDetectorElement* m_prevInZ;
+      const NeutrinoDetectorElement* m_nextInZ;
+
+      //
+      // Cached values.
+      //
+      // Axes
+      NeutrinoDetectorDesign::Axis m_hitEta;
+      NeutrinoDetectorDesign::Axis m_hitPhi;
+      NeutrinoDetectorDesign::Axis m_hitDepth;
+
+      // Directions of axes. These are true if the hit/simulation and reconstruction local frames are
+      // in the same direction and false if they are opposite.
+      mutable bool m_depthDirection ATLAS_THREAD_SAFE; // Guarded by m_mutex // Direction of depth axis. 
+                             // Also direction of readout implant (n+ for pixel, p+ for SCT).
+      mutable bool m_phiDirection ATLAS_THREAD_SAFE;     //
+      mutable bool m_etaDirection ATLAS_THREAD_SAFE;     //
+
+      mutable std::atomic_bool m_cacheValid; // Alignment associated quatities.
+      mutable std::atomic_bool m_firstTime;
+
+      mutable bool m_isEmulsion;
+
+      mutable std::recursive_mutex m_mutex;
+
+      mutable Amg::Transform3D m_transform ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable HepGeom::Transform3D m_transformCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex
+
+      mutable Amg::Vector3D m_normal ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable Amg::Vector3D m_etaAxis ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable HepGeom::Vector3D<double> m_etaAxisCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable Amg::Vector3D m_phiAxis ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable HepGeom::Vector3D<double> m_phiAxisCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable Amg::Vector3D m_center ATLAS_THREAD_SAFE; // Guarded by m_mutex
+      mutable HepGeom::Vector3D<double> m_centerCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex
+
+      mutable double m_minX   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+      mutable double m_maxX   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+      mutable double m_minY   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+      mutable double m_maxY   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+      mutable double m_minZ   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+      mutable double m_maxZ   ATLAS_THREAD_SAFE;// Guarded by m_mutex
+
+      CxxUtils::CachedUniquePtrT<Trk::Surface> m_surface;
+      mutable std::vector<const Trk::Surface*> m_surfaces ATLAS_THREAD_SAFE; // Guarded by m_mutex
+
+      const GeoAlignmentStore* m_geoAlignStore{};
+    };
+    
+    ///////////////////////////////////////////////////////////////////
+    // Inline methods:
+    ///////////////////////////////////////////////////////////////////
+
+    inline HepGeom::Point3D<double> NeutrinoDetectorElement::globalPositionHit(const HepGeom::Point3D<double> &localPos) const
+    {
+      return Amg::EigenTransformToCLHEP(transformHit())*localPos;
+    }
+    
+    inline Amg::Vector3D NeutrinoDetectorElement::globalPosition(const Amg::Vector2D &localPos) const
+    {
+      if (!m_cacheValid) {
+        std::lock_guard<std::recursive_mutex> lock(m_mutex);
+        if (!m_cacheValid) updateCache();
+      }
+      return m_center + localPos[Trk::distEta] * m_etaAxis + localPos[Trk::distPhi] * m_phiAxis;
+    }
+
+    inline Amg::Vector3D NeutrinoDetectorElement::globalPositionHit(const Amg::Vector3D &localPos) const
+    {
+      return transformHit() * localPos;
+    }
+    
+     inline HepGeom::Point3D<double> NeutrinoDetectorElement::globalPositionCLHEP(const Amg::Vector2D &localPos) const
+    {
+      if (!m_cacheValid) {
+        std::lock_guard<std::recursive_mutex> lock(m_mutex);
+        if (!m_cacheValid) updateCache();
+      }
+      return m_centerCLHEP + localPos[Trk::distEta] * m_etaAxisCLHEP + localPos[Trk::distPhi] * m_phiAxisCLHEP;
+    }
+     //here
+     inline Amg::Vector3D NeutrinoDetectorElement::globalPosition(const Amg::Vector3D &localPos) const
+    {
+      return transform() * localPos;
+    }
+    
+     inline HepGeom::Point3D<double> NeutrinoDetectorElement::globalPosition(const HepGeom::Point3D<double> &localPos) const
+    {
+      return transformCLHEP() * localPos;
+    }
+    
+    inline Amg::Vector2D NeutrinoDetectorElement::localPosition(const HepGeom::Point3D<double> & globalPosition) const
+    {
+      if (!m_cacheValid){
+        std::lock_guard<std::recursive_mutex> lock(m_mutex);
+        if (!m_cacheValid) updateCache();
+      }
+      HepGeom::Vector3D<double> relativePos = globalPosition - m_centerCLHEP;
+      return Amg::Vector2D(relativePos.dot(m_phiAxisCLHEP), relativePos.dot(m_etaAxisCLHEP));
+    }
+
+    inline Amg::Vector2D NeutrinoDetectorElement::localPosition(const Amg::Vector3D & globalPosition) const
+    {
+      if (!m_cacheValid){
+        std::lock_guard<std::recursive_mutex> lock(m_mutex);
+        if (!m_cacheValid) updateCache();
+      }
+      Amg::Vector3D relativePos = globalPosition - m_center;
+      return Amg::Vector2D(relativePos.dot(m_phiAxis), relativePos.dot(m_etaAxis));
+    }
+
+    inline const NeutrinoDetectorDesign &NeutrinoDetectorElement::design() const
+    {
+      return *m_design;
+    }
+    
+    inline const FaserDetectorID* NeutrinoDetectorElement::getIdHelper() const
+    {
+      return m_commonItems->getIdHelper();
+    }
+    
+    inline Identifier NeutrinoDetectorElement::identify() const
+    {
+      return m_id;
+    }
+    
+    inline IdentifierHash NeutrinoDetectorElement::identifyHash() const
+    {
+      return m_idHash;
+    }
+    
+    inline double NeutrinoDetectorElement::hitDepthDirection() const
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return (m_depthDirection) ? 1. : -1.;
+    }
+    
+    inline double NeutrinoDetectorElement::hitPhiDirection() const
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return (m_phiDirection) ? 1. : -1.;
+    }
+    
+    inline double NeutrinoDetectorElement::hitEtaDirection() const
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return (m_etaDirection) ? 1. : -1.;
+    }
+       
+    inline void NeutrinoDetectorElement::invalidate()
+    {
+      m_cacheValid = false;
+    }
+
+    inline void NeutrinoDetectorElement::updateAllCaches() const
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      if (not m_surface) surface();
+    }
+    
+    
+    inline double NeutrinoDetectorElement::xMin() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_minX;
+    }
+    
+    inline double NeutrinoDetectorElement::xMax() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_maxX;
+    }
+    
+    inline double NeutrinoDetectorElement::yMin() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_minY;
+    }
+    
+    inline double NeutrinoDetectorElement::yMax() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_maxY;
+    }
+    
+    inline double NeutrinoDetectorElement::zMin() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_minZ;
+    }
+    
+    inline double NeutrinoDetectorElement::zMax() const 
+    {
+      std::lock_guard<std::recursive_mutex> lock(m_mutex);
+      if (!m_cacheValid) updateCache();
+      return m_maxZ;
+    }
+    
+    inline double NeutrinoDetectorElement::width() const
+    {
+      return m_design->width();
+    }
+       
+    inline double NeutrinoDetectorElement::height() const
+    {
+      return m_design->height();
+    }
+    
+    inline double NeutrinoDetectorElement::thickness() const
+    {
+      return m_design->thickness();
+    }
+    
+    inline const NeutrinoCommonItems* NeutrinoDetectorElement::getCommonItems() const
+    {
+      return m_commonItems;
+    }
+
+    inline const NeutrinoDetectorElement* NeutrinoDetectorElement::prevInZ() const
+    {
+      return m_prevInZ;
+    }
+
+    inline const NeutrinoDetectorElement* NeutrinoDetectorElement::nextInZ() const
+    {
+      return m_nextInZ;
+    }
+
+    inline void NeutrinoDetectorElement::setPrevInZ(const NeutrinoDetectorElement* element)
+    {
+      m_prevInZ = element;
+    }
+
+    inline void NeutrinoDetectorElement::setNextInZ(const NeutrinoDetectorElement* element)
+    {
+      m_nextInZ = element;
+    }
+        
+} // namespace NeutrinoDD
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENT_H
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h
new file mode 100644
index 0000000000000000000000000000000000000000..32d13f488f89acc5567ad130f99c5f2bd56d87d8
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDetectorElementCollection.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENTCOLLECTION_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENTCOLLECTION_H
+
+#include <vector>
+
+class IdentifierHash;
+
+namespace NeutrinoDD {
+
+    class NeutrinoDetectorElement;
+
+    /** @class NeutrinoDetectorElementCollection
+      
+       Class to hold the NeutrinoDetectorElement objects to be put in the detector store
+
+       @author Grant Gorfine
+       @author Dave Casper
+    */
+
+    class NeutrinoDetectorElementCollection : public std::vector<NeutrinoDetectorElement *> {
+     public:
+      ~NeutrinoDetectorElementCollection();
+      const NeutrinoDetectorElement* getDetectorElement(const IdentifierHash& hash) const;
+    };
+
+} // namespace NeutrinoDD
+
+#include "AthenaKernel/CLASS_DEF.h"
+CLASS_DEF( NeutrinoDD::NeutrinoDetectorElementCollection , 1277872151 , 1 )
+#include "AthenaKernel/CondCont.h"
+CONDCONT_DEF( NeutrinoDD::NeutrinoDetectorElementCollection, 1081260291 );
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORELEMENTCOLLECTION_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManager.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..b760d726a886c0298775dd44391e38d3821a2cfa
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManager.h
@@ -0,0 +1,147 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDetectorManager.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGER_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGER_H
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorManagerBase.h"
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/NeutrinoNumerology.h"
+
+// Amg stuff
+#include "GeoPrimitives/GeoPrimitives.h"
+
+#include "CLHEP/Geometry/Transform3D.h"
+
+#include <string>
+#include <map>
+  
+class StoreGateSvc;
+class Identifier; 
+class IdentifierHash;
+class FaserDetectorID;
+class GeoAlignableTransform;
+class GeoVAlignmentStore;
+
+namespace NeutrinoDD {
+
+class NeutrinoDetectorElement;
+class NeutrinoDetectorDesign;
+class ExtendedAlignableTransform;
+class NeutrinoNumerology;
+
+  /** @class NeutrinoDetectorManager
+  
+        Base class for Neutrino Detector managers.
+        
+        The Detector manager has methods to retrieve the Identifier
+        helper and methods to retrieve the detector elements.  It also
+        manages the alignment with methods to register the call backs
+        and infrastructure to associate the alignment transforms with
+        the appropriate alignable transform in GeoModel.
+  
+       @author: Grant Gorfine
+       - modified and maintained by Nick Styles & Andreas Salzburger 
+       */
+
+    class NeutrinoDetectorManager : public NeutrinoDetectorManagerBase  {
+    
+    
+    public:
+    
+      // Constructor
+      NeutrinoDetectorManager(StoreGateSvc * detStore, const std::string & name);
+     
+      // Destructor
+      virtual ~NeutrinoDetectorManager() {};
+    
+    
+      //
+      // Access Readout Elements
+      //
+    
+      /** access to individual elements using Identifier or IdentiferHash */
+      virtual NeutrinoDetectorElement * getDetectorElement(const Identifier &id) const = 0;
+      virtual NeutrinoDetectorElement * getDetectorElement(const IdentifierHash &idHash) const = 0;
+    
+      /** access to whole collectiom */
+      virtual const NeutrinoDetectorElementCollection * getDetectorElementCollection() const = 0;
+      virtual NeutrinoDetectorElementCollection::const_iterator getDetectorElementBegin() const = 0;
+      virtual NeutrinoDetectorElementCollection::const_iterator getDetectorElementEnd() const = 0;
+    
+    
+      /** Add elememts */
+      virtual void addDetectorElement(NeutrinoDetectorElement * element) = 0;
+    
+      /** Initialize the neighbours. This can only be done when all elements are built */
+      virtual void initNeighbours() = 0;
+    
+      /** Get tag used in dictionary */
+      const std::string & tag() const; 
+    
+      /** Invalidate cache for all detector elements */
+      virtual void invalidateAll() const;
+    
+      /** Update all caches */
+      virtual void updateAll() const;
+    
+      
+      /** Helper method to set delta transform from a global delta - Amg interface*/
+      bool setAlignableTransformGlobalDelta(ExtendedAlignableTransform * extXF, 
+                                            const Amg::Transform3D & delta,
+                                            GeoVAlignmentStore* alignStore=nullptr) const;
+    
+      /** Helper method to set delta transform from a local delta - Amg interface */
+      bool setAlignableTransformLocalDelta(ExtendedAlignableTransform * extXF, 
+                                           const Amg::Transform3D & localToGlobalXF,
+                                           const Amg::Transform3D & delta,
+                                           GeoVAlignmentStore* alignStore=nullptr) const;
+    
+      /** Access to module design */
+    
+      void setDesign(const NeutrinoDetectorDesign*);
+      const NeutrinoDetectorDesign* getDesign() const;
+
+      /** Access Numerology */
+      const NeutrinoNumerology & numerology() const {return m_numerology;}
+      NeutrinoNumerology & numerology() {return m_numerology;}
+    
+    private:
+      //** Prevent copy and assignment */
+      const NeutrinoDetectorManager & operator=(const NeutrinoDetectorManager &right);
+      NeutrinoDetectorManager(const NeutrinoDetectorManager &right); 
+    
+      /** This method is called by the NeutrinoDetectorManagerBase */
+      virtual bool setAlignableTransformDelta(int level, 
+                                              const Identifier & id, 
+                                              const Amg::Transform3D & delta,
+                                              FrameType frame,
+                                              GeoVAlignmentStore* alignStore) const = 0;
+    
+    
+    
+      std::string                               m_tag;
+      NeutrinoNumerology                           m_numerology;
+      const NeutrinoDetectorDesign *               m_design;
+    
+    };
+
+
+} // namespace NeutrinoDD
+
+#ifndef GAUDI_NEUTRAL
+#include "AthenaKernel/CLASS_DEF.h"
+
+CLASS_DEF(NeutrinoDD::NeutrinoDetectorManager, 203251628, 1)
+#endif
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGER_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManagerBase.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManagerBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..8bce2c0e5e69c1381a11b21f2b36427366a6c81f
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoDetectorManagerBase.h
@@ -0,0 +1,204 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDectorManagerBase.h (was InDetDetectorManager.h)
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGERBASE_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGERBASE_H
+
+// Amg
+#include "GeoPrimitives/GeoPrimitives.h"
+// GeoModel stuff
+#include "GeoModelKernel/GeoVDetectorManager.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h"
+#include "NeutrinoReadoutGeometry/Version.h"
+#include "CLHEP/Geometry/Transform3D.h"
+// Message Stream Member
+#include "AthenaKernel/MsgStreamMember.h"
+
+// IOV SVC for alignment:
+#include "AthenaKernel/IIOVSvc.h"
+
+#include "DetDescrConditions/AlignableTransformContainer.h"
+
+#include "CxxUtils/checker_macros.h"
+
+#include <atomic>
+#include <string>
+#include <map>
+#include <set>
+#include <list>
+
+class StoreGateSvc;
+class AlignableTransform;
+class Identifier; 
+class FaserDetectorID;
+class GeoVAlignmentStore;
+class CondAttrListCollection;
+
+// mutable Athena::MsgStreamMember issues warnings.
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;
+
+namespace NeutrinoDD {
+
+  typedef std::map<std::string, const void*> RawAlignmentObjects;
+
+    /** @class NeutrinoDetectorManagerBase
+    
+        Virtual base class for all neutrino detector managers.
+        
+        It implements the processKey() method for alingment
+        which calls the setAlignableTransformDelta() method which
+        is specified in the extended classes. This method supports both,
+        local and global delta's in the frame and translates it to the 
+        underlying GeoModel transform. As GeoModel (CLHEP) and tracking
+        (Amg) use different geo libraries, these are the methods that
+        act as the CLHEP <--> Amg interface
+        
+        @author: Grant Gorfine
+        - modified & maintained: Nick Styles & Andreas Salzburger 
+    */
+    class NeutrinoDetectorManagerBase : public GeoVDetectorManager  {
+    
+    public:
+    
+      // Constructor
+      NeutrinoDetectorManagerBase(StoreGateSvc * detStore, const std::string & name);
+     
+      // Destructor
+      virtual ~NeutrinoDetectorManagerBase();
+    
+      
+      /** Get version information */
+      const Version & getVersion() const; 
+      const std::string & getLayout() const; // eg Initial, Final, TestBeam 
+      void setVersion(const Version & version); 
+    
+      /** Alignment access */
+      void addChannel(const std::string & key, int level, FrameType frame);
+      void addFolder(const std::string & key);
+      void addSpecialFolder(const std::string & key);
+      void addGlobalFolder(const std::string & key); 
+      void addAlignFolderType(const AlignFolderType alignfolder);
+
+      StatusCode align( IOVSVC_CALLBACK_ARGS ) const;
+
+      StatusCode align(const RawAlignmentObjects& alignObjects, GeoVAlignmentStore* alignStore) const;
+    
+      /** Invalidate cache for all detector elements */
+      virtual void invalidateAll() const = 0;
+    
+      /** Update all caches */
+      virtual void updateAll() const = 0;
+    
+      /** Check identifier is for this detector */
+      virtual bool identifierBelongs(const Identifier & id) const = 0;
+    
+      /** Declaring the Message method for further use */
+      MsgStream& msg (MSG::Level lvl) const { return m_msg.get() << lvl; }
+
+      /** Declaring the Method providing Verbosity Level */
+      bool msgLvl (MSG::Level lvl) const { return m_msg.get().level() <= lvl; }
+
+      AlignFolderType                           m_alignfoldertype;
+    
+    protected:
+      StoreGateSvc * m_detStore;
+    
+    private:
+      /** @class LevelInfo
+         Private helper class definition.
+         */
+      class LevelInfo {
+
+        private:
+          int m_level;
+          FrameType m_type;
+        
+        public:
+          LevelInfo(): m_level(-1), m_type(NeutrinoDD::global) {};
+          LevelInfo(int level, FrameType frame): m_level(level), m_type(frame) {};
+        
+          int level() const {return m_level;}
+          FrameType frame() const {return m_type;} 
+          bool isGlobalDelta() const {return m_type == NeutrinoDD::global;}
+          bool isLocalDelta() const {return m_type == NeutrinoDD::local;} 
+          bool isValid() const {return (m_level >= 0);}
+        
+      };
+
+      class AlignInfo {
+
+        private:
+        AlignFolderType m_aligntype;
+
+        public:
+          AlignInfo(): m_aligntype(NeutrinoDD::none) {};
+          AlignInfo(AlignFolderType alignfolder): m_aligntype(alignfolder) {};
+          AlignFolderType AlignFolder() const {return m_aligntype;}
+          bool isValidAlign() const {return (m_aligntype != NeutrinoDD::none);}
+
+      };
+
+    
+      /** Retrieve level information */
+      const LevelInfo & getLevel(const std::string & key) const;
+
+      /** return align folder string to use **/
+      //      NeutrinoDD::AlignFolderType getAlignInfo();
+
+      /** Process the alignment container, calls processKey */
+      bool processAlignmentContainer(const std::string & key) const;
+      bool processAlignmentContainer(const AlignableTransformContainer* container, GeoVAlignmentStore* alignStore) const;
+
+      /** Called by processAlignmentContainer, 
+          applies only one key on the transform Collections */
+      bool processKey(const std::string key, 
+                      const AlignableTransform* transformCollection,
+                      GeoVAlignmentStore* alignStore=nullptr) const;
+    
+      /** Set method applying the delta transform (in global or local frame)
+          onto the geoModel transform : CLHEP <--> Amg interface */
+      virtual bool setAlignableTransformDelta(int level, 
+                                              const Identifier & id, 
+                                              const Amg::Transform3D & delta,
+                                              FrameType frame,
+                                              GeoVAlignmentStore* alignStore=nullptr) const = 0;
+
+      virtual bool processSpecialAlignment(const std::string & key,
+                                           NeutrinoDD::AlignFolderType alignfolder) const = 0;
+
+      virtual bool processSpecialAlignment(const std::string& key,
+                                           const CondAttrListCollection* obj=nullptr,
+                                           GeoVAlignmentStore* alignStore=nullptr) const = 0;
+
+      bool processGlobalAlignmentContainer(const std::string & key,
+                                           const CondAttrListCollection* obj=nullptr,
+                                           GeoVAlignmentStore* alignStore=nullptr) const;
+
+      virtual bool processGlobalAlignment(const std::string & key, int level, FrameType frame,
+                                          const CondAttrListCollection* obj=nullptr,
+                                          GeoVAlignmentStore* alignStore=nullptr) const;
+      
+      virtual const FaserDetectorID* getIdHelper() const = 0;
+    
+      //Declaring private message stream member.
+      mutable Athena::MsgStreamMember           m_msg;
+      
+      Version                                   m_version;
+      std::map<std::string, LevelInfo>          m_keys;
+      std::set<std::string>                     m_folders;
+      std::set<std::string>                     m_specialFolders;
+      std::set<std::string>                     m_globalFolders; // new time-dependent global folders
+
+      static const LevelInfo s_invalidLevel;
+    };
+
+} // namespace NeutrinoDD
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINODETECTORMANAGERBASE_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoIntersect.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoIntersect.h
new file mode 100644
index 0000000000000000000000000000000000000000..6716572f96852b7a5d3a8054ed5fcae8feab9434
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoIntersect.h
@@ -0,0 +1,94 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+//   NeutrinoIntersect.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINOINTERSECT_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINOINTERSECT_H
+
+namespace NeutrinoDD {
+
+  /** @class NeutrinoIntersect
+ 
+      class to run intersection tests
+
+      @author Grant Gorfine
+  */
+
+  class NeutrinoIntersect {
+
+    public:
+
+      enum IntersectState {OUT = 0, BOUNDARY = 1, IN = 2};
+
+      NeutrinoIntersect(IntersectState state = OUT);
+
+      bool in() const; // Definitely in
+      bool out() const; // Definitely out
+      bool nearBoundary() const; // Near boundary within tolerences
+      bool mayIntersect() const; // in() || nearBoundary()
+      operator bool() const; // Equivalent to mayIntersect().
+
+      void setIn();
+      void setOut();
+      void setNearBoundary();
+
+    private:
+      IntersectState m_state;
+
+  };
+
+inline NeutrinoIntersect::NeutrinoIntersect(IntersectState state) 
+  : m_state(state)
+{}
+
+inline bool NeutrinoIntersect::in() const 
+{
+  return (m_state == IN);
+}
+
+inline bool NeutrinoIntersect::out() const 
+{
+  return (m_state == OUT);
+}
+
+inline bool NeutrinoIntersect::nearBoundary() const 
+{
+  return (m_state == BOUNDARY);
+}
+
+
+inline bool NeutrinoIntersect::mayIntersect() const 
+{
+  return (m_state == BOUNDARY || m_state == IN);
+}
+
+inline NeutrinoIntersect::operator bool() const 
+{
+  return mayIntersect();
+}
+
+inline void NeutrinoIntersect::setIn()
+{
+  m_state = IN;
+}
+
+inline void NeutrinoIntersect::setOut()
+{
+  m_state = OUT;
+}
+
+inline void NeutrinoIntersect::setNearBoundary()
+{
+  m_state = BOUNDARY;
+}
+
+} // namespace NeutrinoDD
+
+#endif  //NEUTRINOREADOUTGEOMETRY_NEUTRINOINTERSECT_H
+
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoLocalPosition.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoLocalPosition.h
new file mode 100644
index 0000000000000000000000000000000000000000..06f3decb9e75f6c56a5149fe2efa4d309e298434
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoLocalPosition.h
@@ -0,0 +1,173 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoLocalPosition.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINOLOCALPOSITION_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINOLOCALPOSITION_H
+
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "TrkEventPrimitives/ParamDefs.h"
+#include <cmath>
+
+namespace NeutrinoDD {
+  enum ExtraLocalPosParam {distDepth = 2}; // These will be defined in Trk soon.
+}
+
+namespace NeutrinoDD {
+
+    /** @class NeutrinoLocalPosition
+    Class to represent a position in the natural frame of an emulsion sensor
+    */
+
+  class NeutrinoLocalPosition {
+
+
+    ///////////////////////////////////////////////////////////////////
+    // Public methods:
+    ///////////////////////////////////////////////////////////////////
+  public:
+
+    /** Default constructor: */
+    NeutrinoLocalPosition();
+    
+    /** Copy constructor: */
+    NeutrinoLocalPosition(const NeutrinoLocalPosition &position) =  default;
+
+    /** This allows one to pass a Amg::Vector2D  to a NeutrinoLocalPosition */
+    NeutrinoLocalPosition(const Amg::Vector2D &position);
+
+    /** Constructor with parameters:
+        position along eta direction
+        position along phi direction
+        position along depth direction (default is 0) */
+    NeutrinoLocalPosition(const double eta,const double phi,
+  		  const double xDepth=0);
+
+    /** Destructor: */
+    ~NeutrinoLocalPosition();
+
+    /** Assignment operator: */
+    NeutrinoLocalPosition &operator=(const NeutrinoLocalPosition &) = default;
+    
+    /** Move assignment **/
+    NeutrinoLocalPosition &operator=(NeutrinoLocalPosition &&) = default;
+
+    ///////////////////////////////////////////////////////////////////
+    // Const methods:
+    ///////////////////////////////////////////////////////////////////
+
+    /** position along local eta direction:*/
+    double xEta() const;
+
+    /** position along local phi direction:*/
+    double xPhi() const;
+
+    /** Cylindrical coordinate r:*/
+    double r() const;
+
+    /** Cylindrical coordinate phi:*/
+    double phi() const;
+
+    /** position along depth direction: */
+    double xDepth() const;
+
+    ///////////////////////////////////////////////////////////////////
+    // Non-const methods:
+    ///////////////////////////////////////////////////////////////////
+
+    void xEta(const double eta);
+
+    void xPhi(const double phi);
+
+    void xDepth(const double xDepth);
+
+    // addition of positions:
+    NeutrinoLocalPosition &operator+=(const NeutrinoLocalPosition &position);
+  
+    // so we can go from NeutrinoLocalPosition to Trk::LocalPosition
+    operator Amg::Vector2D(void) const;
+
+    // scaling:
+    NeutrinoLocalPosition &operator*=(const double factor);
+    NeutrinoLocalPosition &operator/=(const double factor);
+
+    ///////////////////////////////////////////////////////////////////
+    // Private data:
+    ///////////////////////////////////////////////////////////////////
+
+  private:
+    double m_eta; //!< position along eta direction
+    double m_phi; //!< position along phi direction
+    double m_xDepth; //!< position along depth direction
+  };
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+inline NeutrinoLocalPosition::~NeutrinoLocalPosition()
+{}
+
+inline double NeutrinoLocalPosition::xEta() const
+{
+  return m_eta;
+}
+
+inline double NeutrinoLocalPosition::xPhi() const
+{
+  return m_phi;
+}
+
+inline double NeutrinoLocalPosition::xDepth() const
+{
+  return m_xDepth;
+}
+
+inline double NeutrinoLocalPosition::r() const
+{
+  return std::sqrt(m_eta * m_eta + m_phi * m_phi);
+}
+
+inline double NeutrinoLocalPosition::phi() const
+{
+  return std::atan2(m_phi, m_eta);
+}
+
+inline void NeutrinoLocalPosition::xEta(const double x)
+{
+  m_eta=x;
+}
+
+inline void NeutrinoLocalPosition::xPhi(const double y)
+{
+  m_phi=y;
+}
+
+inline void NeutrinoLocalPosition::xDepth(const double xDepth)
+{
+  m_xDepth=xDepth;
+}
+
+///////////////////////////////////////////////////////////////////
+// Binary operators:
+///////////////////////////////////////////////////////////////////
+NeutrinoLocalPosition operator+(const NeutrinoLocalPosition &position1,
+			  const NeutrinoLocalPosition &position2);
+
+NeutrinoLocalPosition operator*(const NeutrinoLocalPosition &position,const double factor);
+
+inline NeutrinoLocalPosition operator*(const double factor,const NeutrinoLocalPosition &position)
+{
+  return position*factor;
+}
+
+NeutrinoLocalPosition operator/(const NeutrinoLocalPosition &position,const double factor);
+
+} // namespace NeutrinoDD
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINOLOCALPOSITION_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.h
new file mode 100644
index 0000000000000000000000000000000000000000..333a0202d7c9a4202e62ddbc3a295efc2774aa97
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.h
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+//   NeutrinoNumerology.h
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+
+
+#ifndef NEUTRINOREADOUTGEOMETRY_NEUTRINONUMEROLOGY_H
+#define NEUTRINOREADOUTGEOMETRY_NEUTRINONUMEROLOGY_H
+
+#include <set>
+
+namespace NeutrinoDD {
+
+  /** @class NeutrinoNumerology
+  
+     Class to extract numerology for emulsion. For example number of modules, bases, films, etc.
+
+     @author Grant Gorfine
+   */
+
+  class NeutrinoNumerology {
+
+
+    public:
+    
+      /** Constructor: */
+      NeutrinoNumerology();
+      
+      // Accessors:
+      
+      /** Number of modules */
+      int numModules() const;
+
+      /** Number of bases in a module */
+      int numBasesPerModule() const;
+
+      /** Number of films per base */
+      int numFilmsPerBase() const;
+
+      const std::set<int>& moduleIds() const;
+
+      // Check presence of station
+      /** Check if station exists */
+      bool useModule(int module) const;
+      
+           
+      // Modifiers:
+      void addModule(int id);
+      void setNumBasesPerModule(int bases);
+      void setNumFilmsPerBase(int films);
+
+    private:
+      
+      int m_numBasesPerModule;
+      int m_numFilmsPerBase;
+      std::set<int> m_moduleIds;
+  };
+  
+}// End namespace
+
+#include "NeutrinoNumerology.icc"
+
+#endif // NEUTRINOREADOUTGEOMETRY_NEUTRINONUMEROLOGY_H
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.icc b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.icc
new file mode 100644
index 0000000000000000000000000000000000000000..d0647996afe0ccf7136e7811a4a8a8420092ce06
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/NeutrinoNumerology.icc
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+namespace NeutrinoDD {
+
+
+inline int NeutrinoNumerology::numModules() const
+{
+  return m_moduleIds.size();
+}
+
+inline int NeutrinoNumerology::numBasesPerModule() const
+{
+  return m_numBasesPerModule;
+}
+
+inline int NeutrinoNumerology::numFilmsPerBase() const
+{
+  return m_numFilmsPerBase;
+}
+
+inline bool NeutrinoNumerology::useModule(int module) const
+{
+  return (m_moduleIds.count(module) > 0);
+}
+
+inline const std::set<int>& NeutrinoNumerology::moduleIds() const
+{
+  return m_moduleIds;
+}
+
+} // End namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/Version.h b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/Version.h
new file mode 100644
index 0000000000000000000000000000000000000000..85ba12e474bbe2be3c8c6465b15b4e165c0364f7
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/NeutrinoReadoutGeometry/Version.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+////////////////////////////////////////////////////////////
+// Version.h
+////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOREADOUTGEOMETRY_VERSION 
+#define NEUTRINOREADOUTGEOMETRY_VERSION 
+
+#include <string>
+
+namespace NeutrinoDD {
+
+  /** @class Version
+
+    Class to hold version information consisting of tag, name layout and description as strings,
+    such as their integer regpresentation in the major-minor-tag scheme 
+    */
+
+  class Version {
+
+    public:
+
+      /** Constructor.  */
+      Version(const std::string & tag, 
+	  const std::string & name, 
+	  const std::string & layout, 
+	  const std::string & description, 
+	  int major,
+	  int minor,
+	  int patch);
+
+     /** Constructor. DEPRECATED */
+      Version(const std::string & name, 
+	  const std::string & layout, 
+	  const std::string & description, 
+	  int major,
+	  int minor,
+	  int patch);
+
+      /** Empty Constructor  */
+      Version();
+
+      /** Version tag */
+      const std::string & tag() const;
+
+      /** Version label */
+      const std::string & name() const;
+  
+      /** Layout (eg Initial, Final, TestBeam) */
+      const std::string & layout() const;
+
+      /** Description or comment. */
+      const std::string & description() const;
+
+      /** Major version number */
+      int majorNum() const;
+  
+      /** Minor version number */
+      int minorNum() const;
+
+      /** Patch version number  */
+      int patchNum() const;
+
+      /** Print out version number (eg. 2.00.00) */
+      std::string versionNumber() const;
+  
+      /** Full Description 
+          For example,
+          Version: SCT-DC1-00, Name: DC1, Layout: Final, Code Version: 2.00.00, Description: DC1 Geometry */
+      std::string fullDescription() const;
+
+  
+   private:
+ 
+      std::string m_tag;
+      std::string m_name;
+      std::string m_layout;
+      std::string m_description;
+      int m_major;
+      int m_minor;
+      int m_patch;
+  };
+
+} //  namespace  NeutrinoDD
+
+#endif // NEUTRINOREADOUTGEOMETRY_VERSION 
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/EmulsionDetectorManager.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/EmulsionDetectorManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b5009b6dad402bce026a9d3d02a2dbf47bec879c
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/EmulsionDetectorManager.cxx
@@ -0,0 +1,350 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "GeoPrimitives/CLHEPtoEigenConverter.h"
+#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/ExtendedAlignableTransform.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "StoreGate/StoreGateSvc.h"
+
+#include <iostream>
+
+namespace NeutrinoDD {
+
+  const int FIRST_HIGHER_LEVEL = 1;
+
+  EmulsionDetectorManager::EmulsionDetectorManager( StoreGateSvc* detStore )
+    : NeutrinoDetectorManager(detStore, "Emulsion"),
+      m_idHelper(0),
+      m_isLogical(false) // Change to true to change the definition of local module corrections
+  {
+    //  
+    // Initialized the Identifier helper.
+    //
+    StatusCode sc = detStore->retrieve(m_idHelper, "EmulsionID");  
+    if (sc.isFailure()) {
+      ATH_MSG_ERROR("Could not retrieve Emulsion id helper");
+    }
+    // Initialize the collections.
+    if (m_idHelper) {
+      m_elementCollection.resize(m_idHelper->film_hash_max());
+      m_alignableTransforms.resize(m_idHelper->film_hash_max());
+      // m_moduleAlignableTransforms.resize(m_idHelper->film_hash_max());
+    } 
+  }
+
+
+
+  EmulsionDetectorManager::~EmulsionDetectorManager()
+  {
+    // Clean up
+    for (size_t i=0; i < m_volume.size(); i++) {
+      m_volume[i]->unref();
+    }
+
+    for (size_t j=0; j < m_higherAlignableTransforms.size(); j++){
+      AlignableTransformMap::iterator iterMap;  
+      for (iterMap = m_higherAlignableTransforms[j].begin(); 
+           iterMap != m_higherAlignableTransforms[j].end();
+           ++iterMap) {
+        delete iterMap->second;
+      }
+    }
+
+    for (size_t k=0; k < m_alignableTransforms.size(); k++){
+      delete m_alignableTransforms[k];
+    }
+
+    // for (size_t l=0; l < m_moduleAlignableTransforms.size(); l++){
+    //   delete m_moduleAlignableTransforms[l];
+    // }
+  }
+
+  unsigned int EmulsionDetectorManager::getNumTreeTops() const
+  {
+    return m_volume.size(); 
+  }
+
+  PVConstLink EmulsionDetectorManager::getTreeTop(unsigned int i) const
+  {
+    return m_volume[i];
+  }
+
+  void EmulsionDetectorManager::addTreeTop(PVLink vol){
+    vol->ref();
+    m_volume.push_back(vol);
+  }
+
+
+  NeutrinoDetectorElement* EmulsionDetectorManager::getDetectorElement(const Identifier & id) const
+  {  
+    // NB the id helpers implementation for getting a hash is not optimal.
+    // Essentially does a binary search.
+    // Make sure it is a wafer Id
+    // Identifier waferId =  m_idHelper->film_id(id);
+    Identifier filmId =  id;
+    IdentifierHash idHash = m_idHelper->film_hash(filmId);
+    if (idHash.is_valid()) {
+      return m_elementCollection[idHash];
+    } else {
+      return 0;
+    }
+  }
+
+  NeutrinoDetectorElement* EmulsionDetectorManager::getDetectorElement(const IdentifierHash & idHash) const
+  {
+    return m_elementCollection[idHash];
+  }
+
+  NeutrinoDetectorElement* EmulsionDetectorManager::getDetectorElement(int module, int base, int film) const
+  {
+    return getDetectorElement(m_idHelper->film_id(module, base, film));
+  }
+
+  const NeutrinoDetectorElementCollection* EmulsionDetectorManager::getDetectorElementCollection() const
+  { 
+    return &m_elementCollection;
+  }
+
+  NeutrinoDetectorElementCollection::const_iterator EmulsionDetectorManager::getDetectorElementBegin() const
+  {
+    return m_elementCollection.begin();
+  }
+
+  NeutrinoDetectorElementCollection::const_iterator EmulsionDetectorManager::getDetectorElementEnd() const
+  {
+    return m_elementCollection.end();
+  }
+
+
+  void EmulsionDetectorManager::addDetectorElement(NeutrinoDetectorElement * element)
+  {
+    IdentifierHash idHash = element->identifyHash();
+    if (idHash >=  m_elementCollection.size())
+      throw std::runtime_error("EmulsionDetectorManager: Error adding detector element.");
+    m_elementCollection[idHash] = element;
+  }
+
+  void EmulsionDetectorManager::initNeighbours()
+  {
+    NeutrinoDetectorElementCollection::iterator iter;
+
+    // Loop over all elements and set the neighbours
+    for (iter = m_elementCollection.begin(); iter != m_elementCollection.end(); ++iter){
+
+      NeutrinoDetectorElement * element = *iter;
+      if (element) {
+
+        IdentifierHash idHash = element->identifyHash();
+        IdentifierHash idHashOther;
+
+        int result;
+        // If no neighbour, result != 0 in which case we leave neighbour as null
+        result = m_idHelper->get_next_in_z(idHash, idHashOther);
+        if (result==0) element->setNextInZ(m_elementCollection[idHashOther]);
+
+        result = m_idHelper->get_prev_in_z(idHash, idHashOther);
+        if (result==0) element->setPrevInZ(m_elementCollection[idHashOther]);
+      }
+    }
+  }
+
+  const EmulsionID* EmulsionDetectorManager::getIdHelper() const
+  {
+    return m_idHelper;
+  }
+
+
+  bool EmulsionDetectorManager::setAlignableTransformDelta(int level, 
+                                                       const Identifier & id, 
+                                                       const Amg::Transform3D & delta,
+                                                       FrameType frame,
+                                                       GeoVAlignmentStore* alignStore) const
+  {
+
+    if (level == 0) { // 0 - At the element level
+
+      // We retrieve it via a hashId.
+      IdentifierHash idHash = m_idHelper->film_hash(id);
+      if (!idHash.is_valid()) return false;
+
+      if (frame == NeutrinoDD::global) { // global shift
+        // Its a global transform
+        return setAlignableTransformGlobalDelta(m_alignableTransforms[idHash], delta, alignStore);
+
+      } else if (frame == NeutrinoDD::local) { // local shift
+
+        NeutrinoDetectorElement * element =  m_elementCollection[idHash];
+        if (!element) return false;
+
+
+        // Its a local transform
+        //See header file for definition of m_isLogical          
+        if( m_isLogical ){
+          //Ensure cache is up to date and use the alignment corrected local to global transform
+          element->setCache();
+          return setAlignableTransformLocalDelta(m_alignableTransforms[idHash], element->transform(), delta, alignStore);
+        } else 
+          //Use default local to global transform
+          return setAlignableTransformLocalDelta(m_alignableTransforms[idHash], element->defTransform(), delta, alignStore);
+
+      } else {   
+        // other not supported
+        ATH_MSG_WARNING("Frames other than global or local are not supported.");
+        return false;
+      }
+    } else { // higher level
+      if (frame != NeutrinoDD::global) {
+        ATH_MSG_WARNING("Non global shift at higher levels is not supported.");
+        return false;
+      }
+
+      int index = level - FIRST_HIGHER_LEVEL; // level 0 is treated separately.
+      if (index  >=  static_cast<int>(m_higherAlignableTransforms.size())) return false;
+
+      // We retrieve it from a map. 
+      AlignableTransformMap::const_iterator iter;    
+      iter = m_higherAlignableTransforms[index].find(id);
+      if (iter == m_higherAlignableTransforms[index].end()) return false;      
+
+      // Its a global transform
+      return setAlignableTransformGlobalDelta(iter->second, delta, alignStore);
+    }
+  }
+
+  void EmulsionDetectorManager::addAlignableTransform (int level, 
+                                                   const Identifier & id, 
+                                                   GeoAlignableTransform *transform,
+                                                   const GeoVPhysVol * child)
+  {
+    if (m_idHelper) {
+
+      const GeoVFullPhysVol * childFPV = dynamic_cast<const GeoVFullPhysVol *>(child);
+      if (!childFPV) { 
+        ATH_MSG_ERROR("Child of alignable transform is not a full physical volume");
+      } else {
+        addAlignableTransform (level, id, transform, childFPV);
+      }
+    }
+  }
+
+  void EmulsionDetectorManager::addAlignableTransform (int level, 
+                                                   const Identifier & id, 
+                                                   GeoAlignableTransform *transform,
+                                                   const GeoVFullPhysVol * child)
+  { 
+    if (m_idHelper) {
+      if (level == 0) { 
+        // Element
+        IdentifierHash idHash = m_idHelper->film_hash(id);
+        if (idHash.is_valid()) {
+          m_alignableTransforms[idHash]= new ExtendedAlignableTransform(transform, child);
+        } 
+      } else {
+        // Higher levels are saved in a map. NB level=0 is treated above.   
+        int index = level - FIRST_HIGHER_LEVEL; // level 0 is treated separately.
+        if (index >= static_cast<int>(m_higherAlignableTransforms.size())) m_higherAlignableTransforms.resize(index+1); 
+        m_higherAlignableTransforms[index][id] = new ExtendedAlignableTransform(transform, child);
+      }  
+    }
+  }
+
+  bool
+  EmulsionDetectorManager::identifierBelongs(const Identifier & id) const
+  {
+    return getIdHelper()->is_emulsion(id);
+  }
+
+
+  const NeutrinoDetectorDesign* EmulsionDetectorManager::getEmulsionDesign() const
+  {
+    return dynamic_cast<const NeutrinoDetectorDesign *>(getDesign());
+  }
+
+  // New global alignment folders
+  bool EmulsionDetectorManager::processGlobalAlignment(const std::string & key, int level, FrameType frame,
+                                                   const CondAttrListCollection* obj, GeoVAlignmentStore* alignStore) const
+  {
+    ATH_MSG_INFO("Processing new global alignment containers with key " << key << " in the " << frame << " frame at level ");
+
+    const CondAttrListCollection* atrlistcol=obj;
+    if(atrlistcol==nullptr and m_detStore->retrieve(atrlistcol,key)!=StatusCode::SUCCESS) {
+      ATH_MSG_INFO("Cannot find new global align Container for key "
+                   << key << " - no new global alignment ");
+      return false;
+    }
+
+    bool alignmentChange = false;
+    Identifier ident=Identifier();
+
+    // loop over objects in collection
+    for (CondAttrListCollection::const_iterator citr=atrlistcol->begin(); citr!=atrlistcol->end();++citr) {
+      const coral::AttributeList& atrlist=citr->second;
+      // SCT manager, therefore ignore all that is not a SCT Identifier
+      //   if (atrlist["det"].data<int>()!=2) continue;
+      ATH_MSG_FATAL("Using invalid alignment data for Emulsion detector (correct treatment not yet implemented");
+      ident = getIdHelper()->film_id(atrlist["module"].data<int>(),
+                                      atrlist["base"].data<int>(),
+                                      atrlist["film"].data<int>()); // The last is the module side which is at this ident-level always the 0-side
+
+      // construct new transform
+      // Order of rotations is defined as around z, then y, then x.
+      Amg::Translation3D  newtranslation(atrlist["Tx"].data<float>(),atrlist["Ty"].data<float>(),atrlist["Tz"].data<float>());
+      Amg::Transform3D newtrans = newtranslation * Amg::RotationMatrix3D::Identity();
+      newtrans *= Amg::AngleAxis3D(atrlist["Rz"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,0.,1.));
+      newtrans *= Amg::AngleAxis3D(atrlist["Ry"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,1.,0.));
+      newtrans *= Amg::AngleAxis3D(atrlist["Rx"].data<float>()*CLHEP::mrad, Amg::Vector3D(1.,0.,0.));
+
+      ATH_MSG_DEBUG("New global DB -- channel: " << citr->first
+                    << " ,det: "    << atrlist["det"].data<int>()
+                    << " ,bec: "    << atrlist["bec"].data<int>()
+                    << " ,layer: "  << atrlist["layer"].data<int>()
+                    << " ,ring: "   << atrlist["ring"].data<int>()
+                    << " ,sector: " << atrlist["sector"].data<int>()
+                    << " ,Tx: "     << atrlist["Tx"].data<float>()
+                    << " ,Ty: "     << atrlist["Ty"].data<float>()
+                    << " ,Tz: "     << atrlist["Tz"].data<float>()
+                    << " ,Rx: "     << atrlist["Rx"].data<float>()
+                    << " ,Ry: "     << atrlist["Ry"].data<float>()
+                    << " ,Rz: "     << atrlist["Rz"].data<float>());
+
+      // Set the new transform; Will replace existing one with updated transform
+      bool status = setAlignableTransformDelta(level,
+                                               ident,
+                                               newtrans,
+                                               frame,
+                                               alignStore);
+
+      if (!status) {
+        ATH_MSG_DEBUG("Cannot set AlignableTransform for identifier."
+                      << getIdHelper()->show_to_string(ident)
+                      << " at level " << level << " for new global DB ");
+      }
+
+      alignmentChange = (alignmentChange || status);
+    }
+    return alignmentChange;
+  }
+
+bool EmulsionDetectorManager::processSpecialAlignment(
+    const std::string &, NeutrinoDD::AlignFolderType) const {
+  return false;
+}
+
+bool EmulsionDetectorManager::processSpecialAlignment(const std::string& /*key*/,
+                                                  const CondAttrListCollection* /*obj*/,
+                                                  GeoVAlignmentStore* /*alignStore*/) const {
+  return false;
+
+}
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoCommonItems.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoCommonItems.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..87ec9c5b1e18e00cc5b92c665ca019edfdfae664
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoCommonItems.cxx
@@ -0,0 +1,22 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+namespace NeutrinoDD {
+
+NeutrinoCommonItems::NeutrinoCommonItems(const FaserDetectorID* const idHelper)
+  :  m_msg("NeutrinoDetectorElement"),
+     m_idHelper(idHelper), 
+     m_mutex{}
+{}
+
+// void   
+// SiCommonItems::setSolenoidFrame(const HepGeom::Transform3D & transform) const
+// {
+//   std::lock_guard<std::mutex> lock{m_mutex};
+//   m_solenoidFrame = transform;
+// }
+
+} // End namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorDesign.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorDesign.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8461f494e2415c1163c66afc9bf7b08cb7a26613
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorDesign.cxx
@@ -0,0 +1,99 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoDetectorDesign.cxx
+//   Implementation file for class NeutrinoDetectorDesign
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+// Version 3.0 05/05/2001 David Calvet
+// Modified: Grant Gorfine
+// Modified: Dave Casper
+///////////////////////////////////////////////////////////////////
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+#include "NeutrinoReadoutGeometry/NeutrinoIntersect.h"
+#include "NeutrinoReadoutGeometry/NeutrinoLocalPosition.h"
+#include "TrkSurfaces/RectangleBounds.h"
+
+namespace NeutrinoDD {
+// Constructor:
+NeutrinoDetectorDesign::NeutrinoDetectorDesign( const double width,
+                                          const double height,
+                                          const double thickness ) :
+    m_thickness(thickness),
+    m_width{width},
+    m_height{height},
+    m_phiAxis(Axis::xAxis),
+    m_etaAxis(Axis::yAxis),  
+    m_depthAxis(Axis::zAxis)
+{
+    m_bounds = new Trk::RectangleBounds(0.5*width, 0.5*height);
+}
+
+
+// Destructor:
+NeutrinoDetectorDesign::~NeutrinoDetectorDesign() {
+    if (m_bounds != nullptr) delete m_bounds;
+}
+
+NeutrinoIntersect NeutrinoDetectorDesign::inDetector(const NeutrinoLocalPosition &localPosition,
+                                               double xTol, double yTol) const {
+    double xDist = 0;
+    double yDist = 0;
+
+    distanceToDetectorEdge(localPosition, xDist, yDist);
+
+    NeutrinoIntersect state;
+
+    if (xDist < -xTol || yDist < -yTol) {
+        state.setOut();
+        return state;
+    }
+
+    if (xDist > xTol && yDist > yTol) {
+        state.setIn();
+        return state;
+    }
+
+    // Near boundary.
+    state.setNearBoundary();
+    return state;
+}
+
+DetectorShape NeutrinoDetectorDesign::shape() const {
+    // Default is Box.
+    return NeutrinoDD::Box;
+}
+
+const Trk::SurfaceBounds & 
+NeutrinoDetectorDesign::bounds() const
+{
+  return *m_bounds;
+}
+
+// Returns distance to nearest detector edge 
+// +ve = inside
+// -ve = outside
+void
+NeutrinoDetectorDesign::distanceToDetectorEdge(const NeutrinoLocalPosition & localPosition,
+						   double & etaDist, double & phiDist) const
+{ 
+  // As the calculation is symmetric around 0,0 we only have to test it for one side.
+  double xEta = abs(localPosition.xEta());
+  double xPhi = abs(localPosition.xPhi());
+
+  double xEtaEdge = 0.5 * height();
+  double xPhiEdge = 0.5 * width();
+
+  // Distance to top/bottom
+  etaDist = xEtaEdge - xEta;
+  
+  // Distance to right/left edge
+  phiDist = xPhiEdge - xPhi;
+
+}
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElement.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElement.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8588ea2398b623a9a8786145024a877dc1266d7a
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElement.cxx
@@ -0,0 +1,930 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file NeutrinoDetectorElement.cxx
+ * Implementation file for class NeutrinoDetectorElement
+ * @author Grant Gorfine
+ * Based on version developed by David Calvet.
+**/
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+
+#include "NeutrinoIdentifier/EmulsionID.h"
+
+#include "GeoModelKernel/GeoVFullPhysVol.h"
+#include "GeoModelFaserUtilities/GeoAlignmentStore.h"
+#include "FaserDetDescr/FaserDetectorID.h"
+
+#include "CLHEP/Geometry/Point3D.h"
+#include "CLHEP/Geometry/Vector3D.h"
+#include "CLHEP/Vector/ThreeVector.h"
+#include "CLHEP/Units/PhysicalConstants.h" // for M_PI
+#include "CLHEP/Units/SystemOfUnits.h"
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorDesign.h"
+
+
+#include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h"
+
+#include "TrkSurfaces/PlaneSurface.h"
+#include "TrkSurfaces/SurfaceBounds.h"
+
+#include <cmath>
+#include <cassert>
+#include <limits>
+
+namespace NeutrinoDD {
+using Trk::distEta;
+using Trk::distPhi;
+// using Trk::distDepth;
+
+// Constructor with parameters:
+NeutrinoDetectorElement::NeutrinoDetectorElement(const Identifier &id,
+                                     const NeutrinoDetectorDesign *design,
+                                     const GeoVFullPhysVol *geophysvol,
+                                     const NeutrinoCommonItems * commonItems,
+                                     const GeoAlignmentStore* geoAlignStore) :
+  TrkDetElementBase(geophysvol),
+  m_id(id),
+  m_idHash(64000),
+  m_design(design),
+  m_commonItems(commonItems),
+  m_prevInZ(nullptr),
+  m_nextInZ(nullptr),
+  m_cacheValid(false),
+  m_firstTime(true),
+  m_isEmulsion(true),
+  m_mutex(),
+  m_surface{},
+  m_surfaces{},
+  m_geoAlignStore(geoAlignStore)
+{
+  //The following are fixes for coverity bug 11955, uninitialized scalars:
+  const bool boolDefault(true);
+  m_depthDirection=boolDefault;
+  m_phiDirection=boolDefault;
+  m_etaDirection=boolDefault;
+  const double defaultMin(std::numeric_limits<double>::max());
+  const double defaultMax(std::numeric_limits<double>::lowest());
+  m_minX=defaultMin;
+  m_maxX=defaultMax;
+  m_minY=defaultMin;
+  m_maxY=defaultMax;
+  m_minZ=defaultMin;
+  m_maxZ=defaultMax;
+  m_hitEta = m_design->etaAxis();
+  m_hitPhi = m_design->phiAxis();
+  m_hitDepth = m_design->depthAxis();
+  ///
+  
+ commonConstructor();
+}
+
+void
+NeutrinoDetectorElement::commonConstructor() 
+{
+  if (!m_id.is_valid()) throw std::runtime_error("NeutrinoDetectorElement: Invalid identifier");
+
+  // Set booleans for wether we are veto/trigger/preshower
+  m_isEmulsion = getIdHelper()->is_emulsion(m_id);
+  if (!m_isEmulsion)
+  {
+    if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id is not for emulsion" << endmsg;
+  }
+  
+  // // Set IdHash.
+  const EmulsionID* emulsionId = dynamic_cast<const EmulsionID* >(getIdHelper());
+  m_idHash = emulsionId->film_hash(m_id);
+  
+  if (!m_idHash.is_valid()) throw std::runtime_error("NeutrinoDetectorElement: Unable to set IdentifierHash");
+
+  // Increase the reference count of the NeutrinoDetectorDesign objects.
+  m_design->ref();
+
+  // Increase the reference count of the NeutrinoCommonItems objects.
+  m_commonItems->ref();
+
+  // Should we reference count the geophysvol as well?
+
+}
+
+
+// Destructor:
+NeutrinoDetectorElement::~NeutrinoDetectorElement()
+{
+  // The design is reference counted so that it will not be deleted until the last element is deleted.
+  m_design->unref();
+
+  m_commonItems->unref();
+}
+
+bool NeutrinoDetectorElement::isEmulsion() const
+{
+  return m_isEmulsion;
+}
+
+
+void 
+NeutrinoDetectorElement::updateCache() const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+  bool firstTimeTmp = m_firstTime;
+  m_firstTime = false;
+  m_cacheValid = true;
+  
+  const GeoTrf::Transform3D & geoTransform = transformHit();
+     
+  HepGeom::Point3D<double> centerGeoModel(0., 0., 0.);
+  m_centerCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * centerGeoModel;
+  m_center = Amg::Vector3D(m_centerCLHEP[0],m_centerCLHEP[1],m_centerCLHEP[2]);
+  
+  // (In ATLAS:)
+  // Determine directions depth, eta and phi axis in reconstruction local frame
+  // ie depth away from interaction point
+  //    phi in direction of increasing phi
+  //    eta in direction of increasing z in barrel, and increasing r in endcap
+  //
+  // depthAxis, phiAxis, and etaAxis are defined to be x,y,z respectively for all detectors for hit local frame.
+  // depthAxis, phiAxis, and etaAxis are defined to be z,x,y respectively for all detectors for reco local frame.
+  //
+  // In FASER:
+  // depthAxis, phiAxis and etaAxis are defined to be z,x,y respectively for all detectors in hit local AND reco local frames
+  // This is accomplished simply by the fixed initialization of m_hitEta, m_hitPhi and m_hitDepth in NeutrinoDetectorDesign
+  //
+
+  static const HepGeom::Vector3D<double> localAxes[3] = {
+    HepGeom::Vector3D<double>(1,0,0),
+    HepGeom::Vector3D<double>(0,1,0),
+    HepGeom::Vector3D<double>(0,0,1)
+  };
+  
+  static const HepGeom::Vector3D<double> & localRecoPhiAxis = localAxes[distPhi];     // Defined to be same as x axis
+  static const HepGeom::Vector3D<double> & localRecoEtaAxis = localAxes[distEta];     // Defined to be same as y axis
+  static const HepGeom::Vector3D<double> & localRecoDepthAxis = localAxes[distDepth]; // Defined to be same as z axis
+  
+  // We only need to calculate the rough orientation once.
+  //For it to change would require extreme unrealistic misalignment changes.
+  if (firstTimeTmp) {
+    // Determine the unit vectors in global frame
+        
+    const HepGeom::Vector3D<double> &geoModelPhiAxis = localAxes[m_hitPhi];
+    const HepGeom::Vector3D<double> &geoModelEtaAxis = localAxes[m_hitEta];
+    const HepGeom::Vector3D<double> &geoModelDepthAxis = localAxes[m_hitDepth];
+
+    HepGeom::Vector3D<double> globalDepthAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelDepthAxis);
+    HepGeom::Vector3D<double> globalPhiAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelPhiAxis);
+    HepGeom::Vector3D<double> globalEtaAxis(Amg::EigenTransformToCLHEP(geoTransform) * geoModelEtaAxis);
+
+    // unit radial vector
+    // HepGeom::Vector3D<double> unitR(m_center.x(), m_center.y(), 0.);
+     
+    // unitR.setMag(1.);
+
+    // HepGeom::Vector3D<double> nominalEta;
+    // HepGeom::Vector3D<double> nominalNormal;
+    // HepGeom::Vector3D<double> nominalPhi(-unitR.y(), unitR.x(), 0);
+  
+    // In Barrel like geometry, the etaAxis is along increasing z, and normal is in increasing radial direction.
+    // In Endcap like geometry, the etaAxis is along increasing r, and normal is in decreasing z direction,
+    // We base whether it is barrel like or endcap like by the orientation of the local z axis of the 
+    // the element. This allows the use of endcap identifiers in a TB setup. A warning message is issued however if
+    // the orientation and identifier are not consistent (ie a barrel like orientation with an endcap identifier).
+
+    // bool barrelLike = true;
+    // nominalEta.setZ(1);
+    // if (std::abs(globalEtaAxis.dot(nominalEta)) < 0.5) { // Check that it is in roughly the right direction.
+      // barrelLike = false;
+    // }   
+
+    // if (isBarrel() && !barrelLike) {      
+    //   if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element has endcap like orientation with barrel identifier."
+    //                                               << endmsg;
+    // } else if (!isBarrel() && barrelLike) {
+    //   if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element has barrel like orientation with endcap identifier."
+    //                                               << endmsg;
+    // }
+    
+    // if (barrelLike) {
+    //   nominalEta.setZ(1);
+    //   nominalNormal =  unitR;
+    // } else { // endcap like
+      // nominalNormal.setZ(-1);
+      // nominalEta = unitR;
+    // }
+
+    // Determine if axes are to have their directions swapped.
+
+    //
+    // Depth axis.
+    //
+    // double depthDir = globalDepthAxis.dot(nominalNormal);
+    // m_depthDirection = true;
+    // if (depthDir < 0) {
+      // if (m_design->depthSymmetric()) {
+        // m_depthDirection = false;
+      // } else {
+      //   if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Unable to swap local depth axis." << endmsg;
+      // }
+    // }
+    // if (std::abs(depthDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local depth axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local depth axis does not follow correct convention.");
+    //   m_depthDirection = true; // Don't swap.
+    // }
+    
+    //
+    // Phi axis (unclear how to handle for FASER - never swap for now)
+    //
+    // double phiDir = globalPhiAxis.dot(nominalPhi);
+    // m_phiDirection = true;
+    // if (phiDir < 0) {
+    //   if (m_design->phiSymmetric()) {
+    //     m_phiDirection = false;
+    //   } else {
+    //     if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Unable to swap local xPhi axis." << endmsg;
+    //   }
+    // }
+    
+    // if (std::abs(phiDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local xPhi axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local xPhi axis does not follow correct convention.");
+    //   m_phiDirection = true; // Don't swap.
+    // }
+    
+    //
+    // Eta axis (unclear how to handle for FASER - never swap for now)
+    //
+    // double etaDir = globalEtaAxis.dot(nominalEta);
+    // m_etaDirection = true;
+    // if (etaDir < 0) {
+    //   if (m_design->etaSymmetric()) {
+    //     m_etaDirection = false;
+    //   } else {
+    //     if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Unable to swap local xEta axis." << endmsg;
+    //   }
+    // }
+    // if (std::abs(etaDir) < 0.5) { // Check that it is in roughly the right direction.
+    //   msg(MSG::ERROR) << "Orientation of local xEta axis does not follow correct convention." << endmsg;
+    //   // throw std::runtime_error("Orientation of local xEta axis does not follow correct convention.");
+    //   m_etaDirection = true; // Don't swap
+    // }   
+
+  } // end if (firstTimeTmp)
+  
+
+
+  m_transformCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * recoToHitTransform();
+  //m_transform = m_commonItems->solenoidFrame() * geoTransform * recoToHitTransform();
+  m_transform = Amg::CLHEPTransformToEigen(m_transformCLHEP);
+  
+  // Check that local frame is right-handed. (ie transform has no reflection)
+  // This can be done by checking that the determinant is >0.
+  // if (firstTimeTmp) { // Only need to check this once.
+  //   HepGeom::Transform3D & t = m_transformCLHEP;
+  //   double det = t(0,0) * (t(1,1)*t(2,2) - t(1,2)*t(2,1)) -
+  //                t(0,1) * (t(1,0)*t(2,2) - t(1,2)*t(2,0)) +
+  //                t(0,2) * (t(1,0)*t(2,1) - t(1,1)*t(2,0));
+  //   if (det < 0) {
+    //   if (m_design->depthSymmetric()) {
+        // if (msgLvl(MSG::DEBUG))
+        //   msg(MSG::DEBUG) << "Local frame is left-handed, Swapping depth axis to make it right handed."
+        //                   << endmsg;
+        // m_depthDirection = !m_depthDirection;
+        // m_transformCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * recoToHitTransform();
+        // m_transform = Amg::CLHEPTransformToEigen(m_transformCLHEP);
+        //m_transform = m_commonItems->solenoidFrame() * geoTransform * recoToHitTransform();
+    //    } else {
+    //    if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Local frame is left-handed." << endmsg;
+    //   }
+    // }
+  // }
+  
+  
+  // Initialize various cached members
+  // The unit vectors
+  HepGeom::Vector3D<double> normalCLHEP = m_transformCLHEP * localRecoDepthAxis;
+  m_normal = Amg::Vector3D( normalCLHEP[0], normalCLHEP[1], normalCLHEP[2]);
+  
+
+  m_phiAxisCLHEP = m_transformCLHEP * localRecoPhiAxis;
+  m_etaAxisCLHEP = m_transformCLHEP * localRecoEtaAxis;
+
+  m_phiAxis = Amg::Vector3D(m_phiAxisCLHEP[0],m_phiAxisCLHEP[1],m_phiAxisCLHEP[2]);
+  m_etaAxis = Amg::Vector3D(m_etaAxisCLHEP[0],m_etaAxisCLHEP[1],m_etaAxisCLHEP[2]);
+
+  getExtent(m_minX, m_maxX, m_minY, m_maxY, m_minZ, m_maxZ);
+
+
+  // Determin isStereo
+//   if (firstTimeTmp) {
+//     if (isSCT() && m_otherSide) {
+//       double sinStereoThis = std::abs(sinStereo());
+//       double sinStereoOther = std::abs(m_otherSide->sinStereo());
+//       if (sinStereoThis == sinStereoOther) {
+//         // If they happend to be equal then set side0 as axial and side1 as stereo.
+//         const SCT_ID* sctId = dynamic_cast<const SCT_ID *>(getIdHelper());
+//         if (sctId) {
+//           int side = sctId->side(m_id);
+//           m_isStereo = (side == 1);
+//         }
+//       } else {
+//         // set the stereo side as the one with largest absolute sinStereo.
+//         m_isStereo = (sinStereoThis > sinStereoOther);
+//       }
+//     } else {
+//       m_isStereo = false;
+//     }
+//   }    
+}
+
+
+const GeoTrf::Transform3D &
+NeutrinoDetectorElement::transformHit() const
+{
+  if (m_geoAlignStore) {
+    const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getAbsPosition(getMaterialGeom());
+    if (ptrXf) return *ptrXf;
+  }
+  return getMaterialGeom()->getAbsoluteTransform();
+}
+
+const Amg::Transform3D &
+NeutrinoDetectorElement::transform() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_transform;
+}
+
+const HepGeom::Transform3D &
+NeutrinoDetectorElement::transformCLHEP() const
+{
+  //stuff to get the CLHEP version of the local to global transform.
+   if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }   
+  return m_transformCLHEP;
+}
+
+const HepGeom::Transform3D 
+NeutrinoDetectorElement::defTransformCLHEP() const
+{
+  if (m_geoAlignStore) {
+    const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getDefAbsPosition(getMaterialGeom());
+    if (ptrXf) return Amg::EigenTransformToCLHEP(*ptrXf) * recoToHitTransform();
+  }
+  return Amg::EigenTransformToCLHEP(getMaterialGeom()->getDefAbsoluteTransform()) * recoToHitTransform();
+}  
+   
+const Amg::Transform3D 
+NeutrinoDetectorElement::defTransform() const
+{
+  HepGeom::Transform3D tmpTransform = defTransformCLHEP();
+  return Amg::CLHEPTransformToEigen(tmpTransform);
+}
+
+const HepGeom::Transform3D 
+NeutrinoDetectorElement::recoToHitTransform() const
+{
+
+  // Determine the reconstruction local (LocalPosition) to global transform.
+
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (m_firstTime) updateCache();
+
+  // global = transform * recoLocal
+  //        = transformHit * hitLocal
+  //        = transformHit * recoToHitTransform * recoLocal
+  //
+  // (In ATLAS:) recoToHitTransform takes recoLocal to hitLocal
+  // x,y,z -> y,z,x 
+  // equiv to a rotation around Y of 90 deg followed by a rotation around X of 90deg
+  // 
+  // recoToHit is static as it needs to be calculated once only.
+  // We use the HepGeom::Transform3D constructor which takes one coordinates system to another where the
+  // coordinate system is defined by it center and two axes.
+  // distPhi, distEta are the reco local axes and hitPhi and hitEta are the hit local axes.
+  // It assume phi, eta, depth makes a right handed system which is the case.
+  static const HepGeom::Vector3D<double> localAxes[3] = {
+    HepGeom::Vector3D<double>(1,0,0),
+    HepGeom::Vector3D<double>(0,1,0),
+    HepGeom::Vector3D<double>(0,0,1)
+  };
+  //static 
+    
+  const HepGeom::Transform3D recoToHit(HepGeom::Point3D<double>(0,0,0),localAxes[distPhi],localAxes[distEta],
+                                       HepGeom::Point3D<double>(0,0,0),localAxes[m_hitPhi],localAxes[m_hitEta]);
+  
+  // Swap direction of axis as appropriate
+  CLHEP::Hep3Vector scale(1,1,1);
+  if (!m_phiDirection)   scale[distPhi]   = -1;
+  if (!m_etaDirection)   scale[distEta]   = -1;
+  if (!m_depthDirection) scale[distDepth] = -1;
+  return recoToHit * HepGeom::Scale3D(scale[0],scale[1],scale[2]);
+}
+
+const Amg::Transform3D &
+NeutrinoDetectorElement::filmTransform() const
+{
+  return transform();
+  // return  (isModuleFrame()) ?  transform() : m_otherSide->transform();
+}
+
+  Amg::Transform3D
+  NeutrinoDetectorElement::defFilmTransform() const
+{
+  return defTransform();
+//  return  (isModuleFrame()) ? defTransform() : m_otherSide->defTransform();
+}  
+
+
+// Take a transform in the local reconstruction and return it in the module frame
+// For a given transform l in frame A. The equivalent transform in frame B is
+//  B.inverse() * A * l * A.inverse() * B
+// Here A is the local to global transform of the element and B is the local to global
+// transform of the module.
+// If we are already in the module frame then there is nothing to do, we just return the
+// transform that is input. Otherwise we use the above formula.
+Amg::Transform3D 
+NeutrinoDetectorElement::localToBaseFrame(const Amg::Transform3D & localTransform) const
+{
+  // if (isModuleFrame()) {
+    return localTransform;
+  // } else {
+  //   return m_otherSide->transform().inverse() * transform() * localTransform * transform().inverse() *  m_otherSide->transform();
+  // }
+}
+
+Amg::Transform3D 
+NeutrinoDetectorElement::localToBaseTransform() const
+{
+  // if (isModuleFrame()) {
+    return Amg::Transform3D(); // Identity
+  // } else {
+  //   return  m_otherSide->transform().inverse() * transform();
+  // }
+}
+      
+
+// bool 
+// NeutrinoDetectorElement::isModuleFrame() const
+// {
+//   // The module frame is the axial side.
+//   // NB isStereo returns false for the pixel and so
+//   // isModuleFrame is always true for the pixel.
+
+//   return !isStereo();
+// }
+
+
+const Amg::Vector3D & 
+NeutrinoDetectorElement::center() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_center;
+}
+
+const Amg::Vector3D & 
+NeutrinoDetectorElement::normal() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_normal;
+}
+
+const HepGeom::Vector3D<double> & 
+NeutrinoDetectorElement::etaAxisCLHEP() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_etaAxisCLHEP;
+}
+
+const HepGeom::Vector3D<double> & 
+NeutrinoDetectorElement::phiAxisCLHEP() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_phiAxisCLHEP;
+}
+
+const Amg::Vector3D & 
+NeutrinoDetectorElement::etaAxis() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_etaAxis;
+}
+
+const Amg::Vector3D & 
+NeutrinoDetectorElement::phiAxis() const
+{
+  if (!m_cacheValid){                                                                                               
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);                                                            
+    if (!m_cacheValid) updateCache();                                                                               
+  }  
+  return m_phiAxis;
+}
+
+Amg::Vector2D
+NeutrinoDetectorElement::hitLocalToLocal(double xEta, double xPhi) const  // Will change order to phi,eta
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  if (!m_etaDirection) xEta = -xEta;
+  if (!m_phiDirection) xPhi = -xPhi;
+  return Amg::Vector2D(xPhi, xEta);
+}
+
+HepGeom::Point3D<double>
+NeutrinoDetectorElement::hitLocalToLocal3D(const HepGeom::Point3D<double> & hitPosition) const
+{
+  // Equiv to transform().inverse * transformHit() * hitPosition
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+  double xDepth = hitPosition[m_hitDepth];
+  double xPhi = hitPosition[m_hitPhi];
+  double xEta = hitPosition[m_hitEta];
+  if (!m_depthDirection) xDepth = -xDepth;
+  if (!m_phiDirection) xPhi = -xPhi;
+  if (!m_etaDirection) xEta = -xEta;
+  return HepGeom::Point3D<double>(xPhi, xEta, xDepth);
+}
+
+Trk::Surface & 
+NeutrinoDetectorElement::surface()
+{
+  if (not m_surface) m_surface.set(std::make_unique<Trk::PlaneSurface>(*this));
+  return *m_surface;
+}
+  
+const Trk::Surface & 
+NeutrinoDetectorElement::surface() const
+{
+  if (not m_surface) m_surface.set(std::make_unique<Trk::PlaneSurface>(*this));
+  return *m_surface;
+}
+  
+const std::vector<const Trk::Surface*>& NeutrinoDetectorElement::surfaces() const 
+{
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+    if (!m_surfaces.size()) {
+        // get this surface
+        m_surfaces.push_back(&surface());
+        // get the other side surface
+        // if (otherSide()) {
+        //     m_surfaces.push_back(&(otherSide()->surface()));
+        // }
+    }
+    // return the surfaces
+    return m_surfaces;
+}  
+  
+const Trk::SurfaceBounds & 
+NeutrinoDetectorElement::bounds() const
+{
+  return m_design->bounds();
+}
+  
+// Get min/max or r, z,and phi
+void NeutrinoDetectorElement::getExtent(double &xMin, double &xMax, 
+                                  double &yMin, double &yMax,
+                                  double &zMin, double &zMax) const
+{
+
+  HepGeom::Point3D<double> corners[4];
+  getCorners(corners);
+
+  bool first = true;
+
+  // double phiOffset = 0.;
+
+  double radialShift = 0.;
+  const HepGeom::Transform3D rShift = HepGeom::TranslateX3D(radialShift);//in local frame, radius is x
+
+  for (int i = 0; i < 4; i++) {
+
+    // if (testDesign) corners[i].transform(rShift);
+
+    HepGeom::Point3D<double> globalPoint = globalPosition(corners[i]);
+
+    // double rPoint = globalPoint.perp();
+    double xPoint = globalPoint.x();
+    double yPoint = globalPoint.y();
+    double zPoint = globalPoint.z();
+    // double phiPoint = globalPoint.phi();
+    
+    // Use first point to initializa min/max values.
+    if (first) {
+
+      // // Put phi in a range so that we are not near -180/+180 division.
+      // // Do this by adding an offset if phi > 90 CLHEP::deg or < -90 CLHEP::deg. 
+      // // This offset is later removed.
+      // if (phiPoint < -0.5 * M_PI) {
+      //   phiOffset = -0.5 * M_PI;
+      // } else if  (phiPoint > 0.5 * M_PI) {
+      //   phiOffset = 0.5 * M_PI;
+      // }
+      // phiMin = phiMax = phiPoint - phiOffset;
+      // rMin = rMax = rPoint;
+      xMin = xMax = xPoint;
+      yMin = yMax = yPoint;
+      zMin = zMax = zPoint;
+
+    } else {
+      // phiPoint -= phiOffset;
+      // // put phi back in -M_PI < phi < +M_PI range
+      // if (phiPoint < -M_PI) phiPoint += 2. * M_PI;
+      // if (phiPoint > M_PI)  phiPoint -= 2. * M_PI;
+      // phiMin = std::min(phiMin, phiPoint);
+      // phiMax = std::max(phiMax, phiPoint);
+      // rMin = std::min(rMin, rPoint);
+      // rMax = std::max(rMax, rPoint);
+      xMin = std::min(xMin, xPoint);
+      xMax = std::max(xMax, xPoint);
+      yMin = std::min(yMin, yPoint);
+      yMax = std::max(yMax, yPoint);      
+      zMin = std::min(zMin, zPoint);
+      zMax = std::max(zMax, zPoint);
+    }
+    first = false;
+  }
+
+  // // put phi back in -M_PI < phi < +M_PI range
+  // phiMin += phiOffset;
+  // phiMax += phiOffset;
+  // if (phiMin < -M_PI) phiMin += 2. * M_PI;
+  // if (phiMin > M_PI)  phiMin -= 2. * M_PI;
+  // if (phiMax < -M_PI) phiMax += 2. * M_PI;
+  // if (phiMax > M_PI)  phiMax -= 2. * M_PI;
+
+}
+
+
+
+// Get eta/phi extent. Returns min/max eta and phi and r (for barrel)
+// or z (for endcap) Takes as input the vertex spread in z (+-deltaZ).
+// Gets 4 corners of the sensor and calculates eta phi for each corner
+// for both +/- vertex spread.  The returned phi is between -M_PI and M_PI
+// with the direction minPhi to maxPhi always in the positive sense,
+// so if the element extends across the -180/180 boundary then minPhi will
+// be greater than maxPhi.
+// void NeutrinoDetectorElement::getEtaPhiRegion(double deltaZ, double &etaMin, double &etaMax, double &phiMin, 
+//                                         double &phiMax, double &rz) const
+// {
+//   std::lock_guard<std::recursive_mutex> lock(m_mutex);
+//   if (!m_cacheValid) updateCache();
+
+//   HepGeom::Point3D<double> corners[4];
+//   getCorners(corners);
+
+//   bool first = true;
+
+//   double phiOffset = 0.;
+
+//   for (int i = 0; i < 4; i++) {
+//     double etaMinPoint;
+//     double etaMaxPoint;
+//     double phiPoint;
+
+//     // Get the eta phi value for this corner.
+//     getEtaPhiPoint(corners[i], deltaZ, etaMinPoint, etaMaxPoint, phiPoint);
+
+//     if (first) { // Use the first point to initialize the min/max values.
+
+//       // Put phi in a range so that we are not near -180/+180 division.
+//       // Do this by adding an offset if phi > 90 CLHEP::deg or < -90 CLHEP::deg. 
+//       // This offset is later removed.
+//       if (phiPoint < -0.5 * M_PI) {
+//         phiOffset = -0.5 * M_PI;
+//       } else if  (phiPoint > 0.5 * M_PI) {
+//         phiOffset = 0.5 * M_PI;
+//       }
+//       phiMin = phiMax = phiPoint - phiOffset;
+//       etaMin = etaMinPoint;
+//       etaMax = etaMaxPoint;
+//     } else {
+//       phiPoint -= phiOffset;
+//       // put phi back in -M_PI < phi < +M_PI range
+//       if (phiPoint < -M_PI) phiPoint += 2. * M_PI;
+//       if (phiPoint > M_PI)  phiPoint -= 2. * M_PI;
+//       phiMin = std::min(phiMin, phiPoint);
+//       phiMax = std::max(phiMax, phiPoint);
+//       etaMin = std::min(etaMin, etaMinPoint);
+//       etaMax = std::max(etaMax, etaMaxPoint);
+//     }
+//     first = false;
+//   }
+
+//   // put phi back in -M_PI < phi < +M_PI range
+//   phiMin += phiOffset;
+//   phiMax += phiOffset;
+//   if (phiMin < -M_PI) phiMin += 2. * M_PI;
+//   if (phiMin > M_PI)  phiMin -= 2. * M_PI;
+//   if (phiMax < -M_PI) phiMax += 2. * M_PI;
+//   if (phiMax > M_PI)  phiMax -= 2. * M_PI;
+
+//   // Calculate rz = r (barrel) or z (endcap)
+//   // Use center of sensor ((0,0,0) in local coordinates) for determining this.
+//   //  HepGeom::Point3D<double> globalCenter = globalPosition(HepGeom::Point3D<double>(0,0,0));
+//   if (isBarrel()) {
+//     rz = center().perp(); // r
+//   } else {
+//     rz = center().z();  // z
+//   }
+
+// }
+
+// Gets eta phi for a point given in local coordinates. deltaZ is specified to
+// account for the vertex spread. phi is independent of this vertex
+// spread. etaMax will correspond to zMin (-deltaZ) and etaMin will
+// correspond to zMax (+deltaZ).
+// void NeutrinoDetectorElement::getEtaPhiPoint(const HepGeom::Point3D<double> & point, double deltaZ, 
+//                                        double &etaMin, double &etaMax, double &phi) const
+// {
+//   // Get the point in global coordinates.
+//   HepGeom::Point3D<double> globalPoint = globalPosition(point);
+
+//   double r = globalPoint.perp();
+//   double z = globalPoint.z();
+  
+//   double thetaMin = atan2(r,(z + deltaZ));
+//   etaMax = -log(tan(0.5 * thetaMin));
+//   double thetaMax = atan2(r,(z - deltaZ));
+//   etaMin = -log(tan(0.5 * thetaMax));
+  
+//   phi = globalPoint.phi();
+// }
+
+void NeutrinoDetectorElement::getCorners(HepGeom::Point3D<double> *corners) const
+{
+  std::lock_guard<std::recursive_mutex> lock(m_mutex);
+  if (!m_cacheValid) updateCache();
+
+  // This makes the assumption that the forward SCT detectors are orientated such that 
+  // the positive etaAxis corresponds to the top of the detector where the width is largest.
+  // This is currently always the case.
+  // For the SCT barrel and pixel detectors minWidth and maxWidth are the same and so should 
+  // work for all orientations.
+
+  // double minWidth = m_design->minWidth();
+  // double maxWidth = m_design->maxWidth();
+  double width    = m_design->width();
+  double height   = m_design->height();
+  
+  // Lower left
+  corners[0][distPhi] = -0.5 * width;
+  corners[0][distEta] = -0.5 * height;
+  corners[0][distDepth] = 0.;
+
+  // Lower right
+  corners[1][distPhi] =  0.5 * width;
+  corners[1][distEta] = -0.5 * height;
+  corners[1][distDepth] = 0.;
+
+  // Upper Right
+  corners[2][distPhi] = 0.5 * width;
+  corners[2][distEta] = 0.5 * height;
+  corners[2][distDepth] = 0.;
+
+  // Upper left
+  corners[3][distPhi] = -0.5 * width;
+  corners[3][distEta] =  0.5 * height;
+  corners[3][distDepth] = 0.;
+}
+
+NeutrinoIntersect
+NeutrinoDetectorElement::inDetector(const Amg::Vector2D & localPosition, 
+                              double phiTol, double etaTol) const
+{
+  return m_design->inDetector(localPosition, phiTol, etaTol);
+}
+
+  
+NeutrinoIntersect 
+NeutrinoDetectorElement::inDetector(const HepGeom::Point3D<double> & globalPosition, double phiTol, double etaTol) const
+{
+  return m_design->inDetector(localPosition(globalPosition), phiTol, etaTol);
+}
+
+// bool 
+// NeutrinoDetectorElement::nearBondGap(Amg::Vector2D localPosition, double etaTol) const
+// {
+//   return m_design->nearBondGap(localPosition, etaTol);
+// }
+
+// bool
+// NeutrinoDetectorElement::nearBondGap(HepGeom::Point3D<double> globalPosition, double etaTol) const
+// {
+//   return m_design->nearBondGap(localPosition(globalPosition), etaTol);
+// }  
+
+// Amg::Vector2D
+// NeutrinoDetectorElement::rawLocalPositionOfCell(const SiCellId &cellId) const
+// {
+//   return m_design->localPositionOfCell(cellId);
+// }
+
+// Amg::Vector2D
+// NeutrinoDetectorElement::rawLocalPositionOfCell(const Identifier & id) const
+// {
+//   SiCellId cellId = cellIdFromIdentifier(id);
+//   return m_design->localPositionOfCell(cellId);
+// }
+
+// int 
+// NeutrinoDetectorElement::numberOfConnectedCells(const SiCellId cellId) const
+// {
+//   SiReadoutCellId readoutId = m_design->readoutIdOfCell(cellId);
+//   return m_design->numberOfConnectedCells(readoutId);
+// }
+
+// SiCellId 
+// NeutrinoDetectorElement::connectedCell(const SiCellId cellId, int number) const
+// {
+//   SiReadoutCellId readoutId = m_design->readoutIdOfCell(cellId);
+//   return m_design->connectedCell(readoutId, number);
+// }
+
+
+// SiCellId 
+// NeutrinoDetectorElement::cellIdOfPosition(const Amg::Vector2D &localPosition) const
+// {
+//   return m_design->cellIdOfPosition(localPosition);
+// }
+
+// Identifier
+// NeutrinoDetectorElement::identifierOfPosition(const Amg::Vector2D &localPosition) const
+// {
+//   SiCellId cellId = m_design->cellIdOfPosition(localPosition);
+//   return identifierFromCellId(cellId);
+// }
+
+// Identifier 
+// NeutrinoDetectorElement::identifierFromCellId(const SiCellId & cellId) const
+// {
+//   Identifier id; // Will be initialized in an invalid state.
+
+//   // If something fails it returns the id in an invalid state.
+
+//   if (cellId.isValid()) {
+
+//     if (isPixel()) {
+//       const PixelID * pixelIdHelper = static_cast<const PixelID *>(getIdHelper());
+//       if (pixelIdHelper) {
+//         id = pixelIdHelper->pixel_id(m_id, cellId.phiIndex(), cellId.etaIndex());
+//       }
+//     } else {
+//       const SCT_ID * sctIdHelper = static_cast<const SCT_ID *>(getIdHelper());
+//       if (sctIdHelper) {
+//         id = sctIdHelper->strip_id(m_id, cellId.strip());
+//       }
+//     }
+//   }
+
+//   return id;
+// }
+
+// SiCellId   
+// NeutrinoDetectorElement::cellIdFromIdentifier(const Identifier & identifier) const
+// {
+//   SiCellId cellId; // Initialized in invalid state.
+
+//   // If something fails it returns the cellId in an invalid state.
+
+//   if (identifier.is_valid()) {
+  
+//     if (isPixel()) {
+//       const PixelID * pixelIdHelper = static_cast<const PixelID *>(getIdHelper());
+//       if (pixelIdHelper) {
+//         cellId = SiCellId(pixelIdHelper->phi_index(identifier), pixelIdHelper->eta_index(identifier));
+//       }
+//     } else {
+//       const SCT_ID * sctIdHelper = static_cast<const SCT_ID *>(getIdHelper());
+//       if (sctIdHelper) {
+//         cellId =  SiCellId(sctIdHelper->strip(identifier));
+//       }
+//     }
+//   }
+  
+//   return cellId;
+// }
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElementCollection.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElementCollection.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..318ea304fbfe69178bee8e30dc34b2ad6f72e212
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorElementCollection.cxx
@@ -0,0 +1,19 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h"
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "Identifier/IdentifierHash.h"
+
+NeutrinoDD::NeutrinoDetectorElementCollection::~NeutrinoDetectorElementCollection() {
+  for (NeutrinoDD::NeutrinoDetectorElement* ele: *this) delete ele;
+}
+
+const NeutrinoDD::NeutrinoDetectorElement*
+NeutrinoDD::NeutrinoDetectorElementCollection::getDetectorElement(const IdentifierHash& hash) const {
+  const unsigned int value{hash.value()};
+  if (this->size()<=value) return nullptr;
+  return this->at(value);  
+}
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManager.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a3b335d4f177e62ae9e04d712c215e4db4634b28
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManager.cxx
@@ -0,0 +1,144 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "GeoPrimitives/CLHEPtoEigenConverter.h"
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorManager.h"
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "IdDictDetDescr/IdDictManager.h"
+#include "StoreGate/StoreGateSvc.h"
+
+#include "GeoModelKernel/GeoXF.h"
+#include "GeoGenericFunctions/Variable.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+#include "DetDescrConditions/AlignableTransformContainer.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElementCollection.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/ExtendedAlignableTransform.h"
+
+#include <iostream>
+
+namespace NeutrinoDD
+{
+
+    NeutrinoDetectorManager::NeutrinoDetectorManager(StoreGateSvc * detStore, const std::string & name)
+        : NeutrinoDetectorManagerBase(detStore, name),
+        m_design {nullptr}
+    {
+  // Add default folder
+        // addFolder("/Neutrino/Align");
+    }
+
+    const std::string& NeutrinoDetectorManager::tag() const
+    {
+        return m_tag;
+    }
+
+    void NeutrinoDetectorManager::invalidateAll() const
+    {
+        for (NeutrinoDetectorElementCollection::const_iterator element_iter = getDetectorElementBegin();
+        element_iter != getDetectorElementEnd();
+        ++element_iter) {
+
+            if (*element_iter) {
+                (*element_iter)->invalidate();
+            }
+        }
+    }
+
+    void NeutrinoDetectorManager::updateAll() const
+    {
+        for (NeutrinoDetectorElementCollection::const_iterator element_iter = getDetectorElementBegin();
+        element_iter != getDetectorElementEnd();
+        ++element_iter) {
+            if (*element_iter) {
+                (*element_iter)->setAllCaches();
+            }
+        }
+    }
+
+    bool NeutrinoDetectorManager::setAlignableTransformLocalDelta(ExtendedAlignableTransform * extXF, 
+                                                            const Amg::Transform3D & localToGlobalXF,
+                                                            const Amg::Transform3D & delta,
+                                                            GeoVAlignmentStore* alignStore) const
+    {
+        // ATTENTION -------------------------------------------------------- (A.S.)
+        // CLHEP < -- > AMG interface method
+        
+        // Sets the alignable transform delta when the supplied delta is in the local
+        // reconstruction frame
+        
+        // If the default transform to the local recostruction frame is
+        // T = A*B*C*D*E
+        // and the alignable transform is C with delta c and the delat in the local frame is l, then
+        // A*B*C*c*D*E = A*B*C*D*E*l
+        //  c = (D*E) * l * (D*E).inverse()
+        //  c = (A*B*C).inverse * T * l * T.inverse() * (A*B*C) 
+        
+        // To get default transform up and including the alignable transform,
+        // we assume the next volume down is a fullphys volume and so its
+        // transform is the transform we want (ie A*B*C in the above example).
+
+        if (!extXF) return false;
+
+        const GeoVFullPhysVol* child = extXF->child();
+        if (child && extXF->alignableTransform()) {
+            // the definitiv absolut transform is in CLHEP -> do the calculation in CLHEP
+            const GeoTrf::Transform3D& transform = child->getDefAbsoluteTransform(alignStore);
+            // calucluate the corrected delta according to the formula above
+            GeoTrf::Transform3D correctedDelta = transform.inverse()*localToGlobalXF      // (A*B*C).inverse() * T
+	                                         * delta                                  // l
+                                                 * localToGlobalXF.inverse() * transform; // T.inverse() * (A*B*C)
+            extXF->alignableTransform()->setDelta(correctedDelta, alignStore);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool NeutrinoDetectorManager::setAlignableTransformGlobalDelta(ExtendedAlignableTransform * extXF, 
+                                                             const Amg::Transform3D& delta,
+                                                             GeoVAlignmentStore* alignStore) const {
+        // ATTENTION -------------------------------------------------------- (A.S.)
+        // CLHEP < -- > AMG interface method
+        
+        // Sets the alignable transform delta when the supplied delta is in the global frame.
+        
+        // If the default transform down to the alignable transform is
+        // T = A*B*C
+        // and the alignable transform is C with delta c and the delta in the global frame is g, then
+        // A*B*C*c = g*A*B*C
+        // T*c = g*T
+        //  c = T.inverse() * g * T
+        
+        // To get default transform up and including the alignable transform,
+        // we assume the next volume down is a fullphys volume and so its
+        // transform is the transform we want (ie T=A*B*C in the above example).
+
+
+        if (!extXF) return false;
+
+        const GeoVFullPhysVol * child = extXF->child();
+        if (child && extXF->alignableTransform()) {
+            // do the calculation in CLHEP  
+            const GeoTrf::Transform3D& transform = child->getDefAbsoluteTransform(alignStore);
+            extXF->alignableTransform()->setDelta(transform.inverse() * delta * transform, alignStore);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    void NeutrinoDetectorManager::setDesign(const NeutrinoDetectorDesign * design)
+    {
+        m_design = design;
+    }
+
+    const NeutrinoDetectorDesign* NeutrinoDetectorManager::getDesign() const
+    {
+        return m_design;
+    }
+
+}// namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManagerBase.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManagerBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5048b84221263eeb55ee8edc6cf253e991594e7c
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoDetectorManagerBase.cxx
@@ -0,0 +1,424 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorManagerBase.h"
+
+#include "StoreGate/StoreGateSvc.h"
+#include "DetDescrConditions/AlignableTransform.h"
+#include "FaserDetDescr/FaserDetectorID.h"
+#include "GeoPrimitives/CLHEPtoEigenConverter.h" 
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "AthenaBaseComps/AthMsgStreamMacros.h"
+
+#include <map>
+
+namespace NeutrinoDD 
+{
+
+    NeutrinoDetectorManagerBase::NeutrinoDetectorManagerBase(StoreGateSvc * detStore, const std::string & name)
+        : m_alignfoldertype{none},m_detStore(detStore), 
+        m_msg(name+"DetectorManager")
+    {
+        setName(name);
+    }
+
+  // Destructor
+    NeutrinoDetectorManagerBase::~NeutrinoDetectorManagerBase() 
+        {}
+
+
+    const Version& NeutrinoDetectorManagerBase::getVersion() const
+    {
+        return m_version;
+    }
+
+    const std::string& NeutrinoDetectorManagerBase::getLayout() const
+    {
+        return m_version.layout();
+    }
+
+    void NeutrinoDetectorManagerBase::setVersion(const Version & version)
+    {
+        m_version = version;
+    }
+
+    void NeutrinoDetectorManagerBase::addChannel(const std::string & key, int level, FrameType frame)
+    {
+        std::string frameStr = "other";
+        if (frame == NeutrinoDD::global) frameStr = "global";
+        if (frame == NeutrinoDD::local) frameStr  = "local";
+        ATH_MSG_INFO("Registering alignment channel with key " << key << ", level " << level 
+                     << ", with frame " << frameStr << ".");
+        m_keys[key] = LevelInfo(level, frame); 
+    }
+
+    void NeutrinoDetectorManagerBase::addFolder(const std::string & key)
+    {
+        m_folders.insert(key);
+    }
+
+    void NeutrinoDetectorManagerBase::addSpecialFolder(const std::string & key)
+    {
+        m_specialFolders.insert(key);
+    }
+
+    void NeutrinoDetectorManagerBase::addGlobalFolder(const std::string & key)
+    {
+        m_globalFolders.insert(key);
+    }
+
+    void NeutrinoDetectorManagerBase::addAlignFolderType(const AlignFolderType  alignfolder)
+    {
+        m_alignfoldertype = alignfolder;
+    }
+
+  // Return the level in the hierarchy (user defined) corresponding to the key.
+    const NeutrinoDetectorManagerBase::LevelInfo& NeutrinoDetectorManagerBase::getLevel(const std::string & key) const 
+    {
+        std::map<std::string, LevelInfo>::const_iterator iter;
+        iter = m_keys.find(key);
+        if (iter == m_keys.end()) return s_invalidLevel;
+        return iter->second;
+    }
+
+    StatusCode NeutrinoDetectorManagerBase::align( IOVSVC_CALLBACK_ARGS_P(I,keys) ) const
+    {
+
+        (void) I; // avoid warning about unused parameter 
+
+        ATH_MSG_DEBUG("AlignmentCallback called ");
+
+        if (!getIdHelper()) return StatusCode::SUCCESS;
+
+        bool alignmentChange = false;
+        const AlignInfo &aligninfo = AlignInfo(m_alignfoldertype);
+
+        // If dummy arguments
+        if (keys.empty()) {
+
+
+            // New global aligment folders should be processed first
+            for (std::set<std::string>::const_iterator iterFolders = m_globalFolders.begin();
+            iterFolders != m_globalFolders.end();
+            ++iterFolders) {
+
+                try {
+                    bool status = processGlobalAlignmentContainer(*iterFolders);
+                    alignmentChange = (alignmentChange || status);
+                } catch(std::runtime_error& err) {
+                    // keys are empty when running simualtion. It is normal for detector specific aligments not to exist.
+                  ATH_MSG_FATAL(err.what());
+                  return StatusCode::FAILURE;
+                }
+            }
+
+            // Regular alignments. Loop through folder keys. Normally only one.
+            for (std::set<std::string>::const_iterator iterFolders = m_folders.begin();
+            iterFolders != m_folders.end();
+            ++iterFolders) {
+
+                try {
+                    bool status = processAlignmentContainer(*iterFolders);
+                    alignmentChange = (alignmentChange || status);
+                }
+                catch(std::runtime_error& err) {
+                    // alignments should always exist so we return fatal if we could not process the alignment for this key
+                    ATH_MSG_FATAL(err.what());
+                    return StatusCode::FAILURE;
+                }
+            }  
+            // Detector specific aligments
+            for (std::set<std::string>::const_iterator iterFolders = m_specialFolders.begin();
+            iterFolders != m_specialFolders.end();
+            ++iterFolders) {
+                try {
+                    bool status = processSpecialAlignment(*iterFolders, aligninfo.AlignFolder());
+                    alignmentChange = (alignmentChange || status);
+                } catch(std::runtime_error& err) {
+                    // keys are empty when running simualtion. It is normal for detector specific aligments not to exist.
+                    ATH_MSG_INFO(err.what());
+                    // We continue as detector specific aligments don't always exist.
+                }
+            }
+
+        } else {
+            // Loop over all the keys.
+            for (std::list<std::string>::const_iterator itr=keys.begin(); itr!=keys.end(); ++itr) {
+
+                const std::string & key = *itr;
+
+                ATH_MSG_DEBUG(" Processing call back key  " << key);
+
+                if ( m_globalFolders.find(key) != m_globalFolders.end() ) { 
+
+                    try {
+                        // New global alignemnts
+                        bool status = processGlobalAlignmentContainer(key);
+                        alignmentChange = (alignmentChange || status);
+                    } catch(std::runtime_error& err) {
+                        // alignments should always exist so we return fatal if we could not process the alignment for this key
+                        ATH_MSG_FATAL(err.what());
+                        return StatusCode::FAILURE;
+                    }
+
+                } else if ( m_folders.find(key) != m_folders.end() ) { 
+
+                    try {
+                        // Regular alignemnts
+                        bool status = processAlignmentContainer(key);
+                        alignmentChange = (alignmentChange || status);
+                    } catch(std::runtime_error& err) {
+                        // alignments should always exist so we return fatal if we could not process the alignment for this key
+                        ATH_MSG_FATAL(err.what());
+                        return StatusCode::FAILURE;
+                    }
+
+                } else if ( m_specialFolders.find(key) !=  m_specialFolders.end() ) {
+                    try {
+                        // Detector specific alignments
+                        bool status = processSpecialAlignment(key, aligninfo.AlignFolder());
+                        alignmentChange = (alignmentChange || status);
+                    } 
+                    catch(std::runtime_error& err) {
+                        // Should always exist if the folder was requested so we return fatal if we could not process the alignment for this key
+                        ATH_MSG_FATAL(err.what());
+                        return StatusCode::FAILURE;
+                    }
+                } else {
+                    // Should not be any other keys specified in call back.
+                    ATH_MSG_ERROR("Unrecognized key in call back.");
+                    return  StatusCode::RECOVERABLE;
+                }
+            }
+        }
+
+    // We invalidate all the elements if at least one alignment changed.
+        if (alignmentChange) {
+            invalidateAll();
+        }    
+
+        return StatusCode::SUCCESS;
+    }
+
+    StatusCode NeutrinoDetectorManagerBase::align(const RawAlignmentObjects& alignObjects, GeoVAlignmentStore* alignStore) const
+    {
+
+        ATH_MSG_DEBUG("align() called from an alignment CondAlg");
+        if (!getIdHelper()) return StatusCode::SUCCESS; // To Do: is it really a success?
+
+        bool alignmentChange = false;
+        //      const AlignInfo &aligninfo = AlignInfo(m_alignfoldertype);
+      
+        for(const auto& alignObj : alignObjects) {
+            const std::string& key = alignObj.first;
+
+            ATH_MSG_DEBUG(" Processing folder  " << key);
+
+            if(m_globalFolders.find(key)!=m_globalFolders.end()) {  
+                try {
+                    // New global alignemnts
+                    const CondAttrListCollection* obj = static_cast<const CondAttrListCollection*>(alignObj.second);
+                    bool status = processGlobalAlignmentContainer(key,obj,alignStore);
+                    alignmentChange = (alignmentChange || status);
+                } catch(std::runtime_error& err) {
+                    // alignments should always exist so we return fatal if we could not process the alignment for this key
+                    ATH_MSG_FATAL(err.what());
+                    return StatusCode::FAILURE;
+                }
+            } 
+            else if(m_folders.find(key)!=m_folders.end()) { 
+                try {
+                    // Regular alignemnts
+                    const AlignableTransformContainer* container = static_cast<const AlignableTransformContainer*>(alignObj.second);
+                    bool status = processAlignmentContainer(container,alignStore);
+                    alignmentChange = (alignmentChange || status);
+                } catch(std::runtime_error& err) {
+                    // alignments should always exist so we return fatal if we could not process the alignment for this key
+                    ATH_MSG_FATAL(err.what());
+                    return StatusCode::FAILURE;
+                }
+            } 
+            else if(m_specialFolders.find(key)!=m_specialFolders.end()) {
+                try {
+                  // Detector specific alignments
+                  const CondAttrListCollection *obj =
+                    static_cast<const CondAttrListCollection*>(alignObj.second);
+                  bool status = processSpecialAlignment(key, obj, alignStore);
+                  alignmentChange = (alignmentChange || status);
+                }
+                catch(std::runtime_error& err) {
+                  // Should always exist if the folder was requested so we return fatal if
+                  // we could not process the alignment for this key
+                  ATH_MSG_FATAL(err.what());
+                  return StatusCode::FAILURE;
+                }
+            } 
+            else {
+                // Should not be any other keys specified in raw alignment object.
+                ATH_MSG_ERROR("Unrecognized folder name.");
+                return StatusCode::RECOVERABLE;
+            }
+        }
+        // To Do: custom caching is not going to work in MT
+        /*
+          if(alignmentChange) invalidateAll(); 
+        */
+
+        return StatusCode::SUCCESS;      
+    }
+
+    bool NeutrinoDetectorManagerBase::processAlignmentContainer(const std::string & key) const
+    {
+        bool alignmentChange = false;
+
+        ATH_MSG_DEBUG("Dealing with key as container");
+        const AlignableTransformContainer* container;
+        if (StatusCode::SUCCESS!=m_detStore->retrieve(container, key)) {        
+            ATH_MSG_ERROR("Cannot find AlignableTransformContainer for key " 
+                          << key << " - no misalignment");
+            // This should not occur in normal situations so we force job to abort.
+            throw std::runtime_error("Unable to apply Neutrino alignments");
+        }
+        // Check if container is empty - this can occur if it is an invalid IOV.
+        if (container->empty()) {
+            ATH_MSG_ERROR("AlignableTransformContainer for key " 
+                          << key << " is empty. Probably due to out of range IOV");
+            // This should not occur in normal situations so we force job to abort.
+            throw std::runtime_error("Unable to apply Neutrino alignments.");
+        }
+        // loop over all the AlignableTransform objects in the collection
+        for (DataVector<AlignableTransform>::const_iterator pat=container->begin();
+        pat!=container->end();++pat) {
+
+            bool status = processKey((*pat)->tag(),*pat);
+            alignmentChange = (alignmentChange || status);
+        }
+        return alignmentChange;
+    } 
+
+    bool NeutrinoDetectorManagerBase::processAlignmentContainer(const AlignableTransformContainer* container, GeoVAlignmentStore* alignStore) const
+    {
+        bool alignmentChange = false;
+
+        // Check if container is empty - this can occur if it is an invalid IOV.
+        if (container->empty()) {
+            ATH_MSG_ERROR("AlignableTransformContainer " 
+                          << " is empty. Probably due to out of range IOV"); // To Do: add key to this printout for making it more informative
+            // This should not occur in normal situations so we force job to abort.
+            throw std::runtime_error("Unable to apply Neutrino alignments.");
+        }
+        // loop over all the AlignableTransform objects in the collection
+        // use only the last ones.
+        std::map<const std::string, const AlignableTransform*> stringToTransform;
+        for (DataVector<AlignableTransform>::const_iterator pat=container->begin();
+             pat!=container->end();++pat) {
+            stringToTransform[(*pat)->tag()] = *pat;
+        }
+        for (std::pair<const std::string, const AlignableTransform*> value: stringToTransform) {
+            bool status = processKey(value.first, value.second, alignStore);
+            alignmentChange = (alignmentChange || status);
+        }
+        return alignmentChange;
+    }
+
+    bool NeutrinoDetectorManagerBase::processKey(const std::string key,
+                                          const AlignableTransform* transformCollection,
+                                          GeoVAlignmentStore* alignStore) const 
+    {  
+        bool alignmentChange = false;
+
+        // From the key determine what level in hierarchy we are dealing with.
+        // returns -1 if unrecognized.  
+        const LevelInfo & levelInfo = getLevel(key);
+        if (levelInfo.isValid()) {
+            ATH_MSG_VERBOSE("Processing channel: " << key);
+        } else {
+            ATH_MSG_DEBUG("Channel " << key << " not registered in this manager");
+        }
+        // return silently if unrecognised - this can happen in container mode
+        // when a single container holds transforms for both pixel and SCT
+        if (!levelInfo.isValid() ) return false;
+
+        //Loop over the effected nodes.
+        for (AlignableTransform::AlignTransMem_citr trans_iter = transformCollection->begin(); 
+             trans_iter != transformCollection->end(); 
+             ++trans_iter) {
+            ATH_MSG_DEBUG( "Get alignment for identifier " 
+                           << getIdHelper()->show_to_string(trans_iter->identify())  
+                           << " at level " << levelInfo.level());
+
+            // The delta in the conditions DB is not necessarily the same as what is needed in the
+            // alignable transform. At the moment we support global frame, local frame or an alternative frame
+            // The setAlignableTransformDelta method takes care of this correction - this is CLHEP <--> Amg interfaced
+            bool status = setAlignableTransformDelta(levelInfo.level(), 
+                                                     trans_iter->identify(),
+                                                     Amg::CLHEPTransformToEigen(trans_iter->transform()),
+                                                     levelInfo.frame(),
+                                                     alignStore);
+
+            alignmentChange = (alignmentChange || status);
+
+            if (!status) {
+                if (!identifierBelongs(trans_iter->identify())) {
+                    ATH_MSG_DEBUG("Cannot set AlignableTransform for identifier."
+                                  << getIdHelper()->show_to_string(trans_iter->identify())  
+                                  << " at level " << levelInfo.level());
+                } else {
+                    ATH_MSG_WARNING("Cannot set AlignableTransform for identifier  " 
+                                    << getIdHelper()->show_to_string(trans_iter->identify())  
+                                    << " at level " << levelInfo.level());
+                    ATH_MSG_WARNING("Subsequent WARNINGS will be printed at DEBUG level.");
+                }
+            }  
+        }
+        return alignmentChange;
+    }
+
+  // We provide a default implementation of any detector specific alignment.
+    bool NeutrinoDetectorManagerBase::processGlobalAlignmentContainer(const std::string & key,
+                                                               const CondAttrListCollection* obj,
+                                                               GeoVAlignmentStore* alignStore) const
+    {
+      bool alignmentChange = false;
+
+      ATH_MSG_DEBUG("processing GlobalAlignmentContainer with key:  " << key);
+      // From the key determine what level in hierarchy we are dealing with.                                                                                   
+      // returns -1 if unrecognized.                                                                                                                           
+      const LevelInfo & levelInfo = getLevel(key);
+      if (levelInfo.isValid()) {
+          ATH_MSG_VERBOSE("Processing channel: " << key);
+      } else {
+          ATH_MSG_DEBUG("Channel " << key << " not registered in this manager");
+      }
+      // return silently if unrecognised - this can happen in container mode                                                                                   
+      // when a single container holds transforms for both pixel and SCT                                                                                       
+      if (!levelInfo.isValid() ) return false;
+        
+      // Within detector specific code
+      bool status = processGlobalAlignment(key, levelInfo.level(), levelInfo.frame(), obj, alignStore);
+      
+      alignmentChange = (alignmentChange || status);
+
+      return alignmentChange;
+
+    }
+  
+  // We provide a default implementation of any detector specific alignment.                                                                                 
+    bool NeutrinoDetectorManagerBase::processGlobalAlignment(const std::string &, int /*level*/, FrameType /*frame*/,
+                                                      const CondAttrListCollection* /*obj*/, GeoVAlignmentStore* /*alignStore*/) const
+    {
+        return false;
+    }
+
+
+  // We provide a default implementation of any detector specific alignment.
+    bool NeutrinoDetectorManagerBase::processSpecialAlignment(const std::string &, NeutrinoDD::AlignFolderType) const
+    {
+        return false;
+    }
+
+    const NeutrinoDetectorManagerBase::LevelInfo NeutrinoDetectorManagerBase::s_invalidLevel;
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoLocalPosition.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoLocalPosition.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c2dc61f78040c8c842570d449e326690adccaaed
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoLocalPosition.cxx
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoLocalPosition.cxx
+//   Implementation file for class NeutrinoLocalPosition
+///////////////////////////////////////////////////////////////////
+// (c) ATLAS Detector software
+///////////////////////////////////////////////////////////////////
+// Version 2.1 01/08/2001 David Calvet
+///////////////////////////////////////////////////////////////////
+
+#include "NeutrinoReadoutGeometry/NeutrinoLocalPosition.h"
+
+namespace NeutrinoDD {
+
+// Default constructor:
+NeutrinoLocalPosition::NeutrinoLocalPosition() :
+  m_eta(0),
+  m_phi(0),
+  m_xDepth(0)
+{}
+
+
+
+// Constructor with parameters:
+NeutrinoLocalPosition::NeutrinoLocalPosition(const double x,const double y,
+				 const double xDepth) :
+  m_eta(x),
+  m_phi(y),
+  m_xDepth(xDepth)
+{}
+
+NeutrinoLocalPosition::NeutrinoLocalPosition(const Amg::Vector2D &position)
+  : m_eta(position[Trk::distEta]),
+    m_phi(position[Trk::distPhi]),
+    m_xDepth(0)
+{}
+  
+
+NeutrinoLocalPosition::operator Amg::Vector2D(void) const
+{
+  return Amg::Vector2D(m_phi, m_eta);
+}
+
+
+
+// addition of positions:
+NeutrinoLocalPosition &NeutrinoLocalPosition::operator+=(const NeutrinoLocalPosition &position)
+{
+  m_eta+=position.m_eta;
+  m_phi+=position.m_phi;
+  m_xDepth+=position.m_xDepth;  
+  return *this;
+}
+
+// scaling:
+NeutrinoLocalPosition &NeutrinoLocalPosition::operator*=(const double factor)
+{
+  m_eta*=factor;
+  m_phi*=factor;
+  m_xDepth*=factor;
+  return *this;
+}
+
+// scaling:
+NeutrinoLocalPosition &NeutrinoLocalPosition::operator/=(const double factor)
+{
+  if (0!=factor) {
+    m_eta/=factor;
+    m_phi/=factor;
+    m_xDepth/=factor;
+  } else {}
+  return *this;
+}
+
+NeutrinoLocalPosition operator+(const NeutrinoLocalPosition &position1,
+			  const NeutrinoLocalPosition &position2)
+{
+  NeutrinoLocalPosition result(position1);
+  result+=position2;
+  return result;
+}
+
+NeutrinoLocalPosition operator*(const NeutrinoLocalPosition &position,const double factor)
+{
+  NeutrinoLocalPosition result(position);
+  result*=factor;
+  return result;
+}
+
+NeutrinoLocalPosition operator/(const NeutrinoLocalPosition &position,const double factor)
+{
+  NeutrinoLocalPosition result(position);
+  result/=factor;
+  return result;
+}
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoNumerology.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoNumerology.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f8ea063ffd688c7bbb6fefd746b58be015745e4f
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/NeutrinoNumerology.cxx
@@ -0,0 +1,31 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoReadoutGeometry/NeutrinoNumerology.h"
+
+
+namespace NeutrinoDD {
+
+NeutrinoNumerology::NeutrinoNumerology()
+  : m_numBasesPerModule(0),
+    m_numFilmsPerBase(0)
+{}
+  
+void NeutrinoNumerology::addModule(int id)
+{
+  m_moduleIds.insert(id);
+}
+
+void NeutrinoNumerology::setNumBasesPerModule(int nBases)
+{ 
+  m_numBasesPerModule = nBases;
+}
+
+void NeutrinoNumerology::setNumFilmsPerBase(int nFilms)
+{
+  m_numFilmsPerBase = nFilms;
+}
+
+	
+}  // End namespace
diff --git a/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/Version.cxx b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/Version.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..418315a4f6a7278abd9b67a652fc2c207ab656da
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescr/NeutrinoReadoutGeometry/src/Version.cxx
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoReadoutGeometry/Version.h"
+
+#include <sstream>
+#include <string>
+#include <iomanip>
+
+namespace NeutrinoDD {
+
+Version::Version(const std::string & tag, 
+		 const std::string & name, 
+		 const std::string & layout, 
+		 const std::string & description, 
+		 int major,
+		 int minor,
+		 int patch)
+  : m_tag(tag),
+    m_name(name),
+    m_layout(layout),
+    m_description(description),
+    m_major(major),
+    m_minor(minor),
+    m_patch(patch)
+{}
+
+// For backward compatibility
+Version::Version(const std::string & name, 
+		 const std::string & layout, 
+		 const std::string & description, 
+		 int major,
+		 int minor,
+		 int patch)
+  : m_tag("-"),
+    m_name(name),
+    m_layout(layout),
+    m_description(description),
+    m_major(major),
+    m_minor(minor),
+    m_patch(patch)
+{}
+
+
+
+Version::Version()
+  : m_major(0),
+    m_minor(0),
+    m_patch(0)
+{}
+
+const std::string & 
+Version::tag() const 
+{
+  return m_tag;
+}
+
+const std::string & 
+Version::name() const 
+{
+  return m_name;
+}
+
+const std::string & 
+Version::layout() const 
+{
+  return m_layout;
+}
+
+const std::string & 
+Version::description() const 
+{
+  return m_description;
+}
+
+int 
+Version::majorNum() const 
+{
+  return m_major;
+}
+
+int 
+Version::minorNum() const 
+{
+  return m_minor;
+}
+
+int 
+Version::patchNum() const 
+{
+  return m_patch;
+}
+
+std::string 
+Version::versionNumber() const
+{
+  std::ostringstream ostr;
+  ostr << m_major 
+       << "." << std::setfill('0') << std::setw(2) << m_minor 
+       << "." << std::setfill('0') << std::setw(2) << m_patch;
+  return ostr.str();
+}
+
+std::string  
+Version::fullDescription() const 
+{
+
+  //  Output of the form
+  //  Version: SCT-DC1-00, Name: DC1, Layout: Final, Code Version: 02.01.01, Description: DC1 Geometry
+
+  std::ostringstream ostr;
+  ostr << "Version: " << m_tag << ", Name: " << m_name << ", Layout: " << m_layout 
+       << ", Code Version: " << versionNumber();
+  if (!m_description.empty()) { 
+    ostr << ", Description: " << m_description;
+  }
+  return ostr.str();
+}
+
+} // namespace NeutrinoDD
diff --git a/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/CMakeLists.txt b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fe777075bdc5107cb34b47c67fcec9e1de895482
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/CMakeLists.txt
@@ -0,0 +1,15 @@
+################################################################################
+# Package: NeutrinoIdCnv
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoIdCnv )
+
+# Component(s) in the package:
+atlas_add_component( NeutrinoIdCnv
+                     src/*.cxx
+                     LINK_LIBRARIES StoreGateLib SGtests DetDescrCnvSvcLib IdDictDetDescr GaudiKernel NeutrinoIdentifier )
+
+# Install files from the package:
+atlas_install_joboptions( share/*.py )
+
diff --git a/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/share/NeutrinoIdCnv_jobOptions.py b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/share/NeutrinoIdCnv_jobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..611694cf5447815f9eed8758f195abf3fc292f3d
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/share/NeutrinoIdCnv_jobOptions.py
@@ -0,0 +1,6 @@
+#
+#  Joboptions for the loading of the of NeutrinoIdCnv
+#
+
+# DLLs 
+theApp.Dlls += [ "NeutrinoIdCnv" ]
diff --git a/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.cxx b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fc8cde7bd24f255492857b9014fab544cdaf4871
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.cxx
@@ -0,0 +1,239 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Neutrino DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "EmulsionIDDetDescrCnv.h"
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+#include "DetDescrCnvSvc/DetDescrAddress.h"
+#include "GaudiKernel/MsgStream.h"
+#include "StoreGate/StoreGateSvc.h" 
+
+#include "IdDictDetDescr/IdDictManager.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+
+
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+//--------------------------------------------------------------------
+
+long int   
+EmulsionIDDetDescrCnv::repSvcType() const
+{
+  return (storageType());
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+EmulsionIDDetDescrCnv::initialize()
+{
+    // First call parent init
+    StatusCode sc = DetDescrConverter::initialize();
+    MsgStream log(msgSvc(), "EmulsionIDDetDescrCnv");
+    log << MSG::DEBUG << "in initialize" << endmsg;
+
+    if (sc.isFailure()) {
+        log << MSG::ERROR << "DetDescrConverter::initialize failed" << endmsg;
+	return sc;
+    }
+    
+    // The following is an attempt to "bootstrap" the loading of a
+    // proxy for EmulsionID into the detector store. However,
+    // EmulsionIDDetDescrCnv::initialize is NOT called by the conversion
+    // service.  So for the moment, this cannot be use. Instead the
+    // DetDescrCnvSvc must do the bootstrap from a parameter list.
+
+
+//      // Add Neutrino_DetDescrManager proxy as entry point to the detector store
+//      // - this is ONLY needed for the manager of each system
+//      sc = addToDetStore(classID(), "EmulsionID");
+//      if (sc.isFailure()) {
+//  	log << MSG::FATAL << "Unable to add proxy for EmulsionID to the Detector Store!" << endmsg;
+//  	return StatusCode::FAILURE;
+//      } else {}
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode 
+EmulsionIDDetDescrCnv::finalize()
+{
+    MsgStream log(msgSvc(), "EmulsionIDDetDescrCnv");
+    log << MSG::DEBUG << "in finalize" << endmsg;
+
+    return StatusCode::SUCCESS; 
+}
+
+//--------------------------------------------------------------------
+
+StatusCode
+EmulsionIDDetDescrCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) 
+{
+    //StatusCode sc = StatusCode::SUCCESS;
+    MsgStream log(msgSvc(), "EmulsionIDDetDescrCnv");
+    log << MSG::INFO << "in createObj: creating a EmulsionID helper object in the detector store" << endmsg;
+
+    // Create a new EmulsionID
+
+    DetDescrAddress* ddAddr;
+    ddAddr = dynamic_cast<DetDescrAddress*> (pAddr);
+    if(!ddAddr) {
+	log << MSG::FATAL << "Could not cast to DetDescrAddress." << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // Get the StoreGate key of this container.
+    std::string helperKey  = *( ddAddr->par() );
+    if ("" == helperKey) {
+	log << MSG::DEBUG << "No Helper key " << endmsg;
+    }
+    else {
+	log << MSG::DEBUG << "Helper key is " << helperKey << endmsg;
+    }
+    
+
+    // get DetectorStore service
+    StoreGateSvc * detStore;
+    StatusCode status = serviceLocator()->service("DetectorStore", detStore);
+    if (status.isFailure()) {
+	log << MSG::FATAL << "DetectorStore service not found !" << endmsg;
+	return StatusCode::FAILURE;
+    } else {}
+ 
+    // Get the dictionary manager from the detector store
+    const DataHandle<IdDictManager> idDictMgr;
+    status = detStore->retrieve(idDictMgr, "IdDict");
+    if (status.isFailure()) {
+	log << MSG::FATAL << "Could not get IdDictManager !" << endmsg;
+	return StatusCode::FAILURE;
+    } 
+    else {
+	log << MSG::DEBUG << " Found the IdDictManager. " << endmsg;
+    }
+
+    // Only create new helper if it is the first pass or if there is a
+    // change in the the file or tag
+    bool initHelper               = false;
+
+    const IdDictMgr* mgr          = idDictMgr->manager();
+
+    // Internal Neutrino id tag
+    std::string   neutrinoIDTag      = mgr->tag();
+
+    // DoChecks flag
+    bool doChecks                 = mgr->do_checks();
+
+    IdDictDictionary* dict = mgr->find_dictionary("Neutrino");  
+    if (!dict) {
+	log << MSG::ERROR 
+	    << "unable to find idDict for Neutrino" 
+	    << endmsg;
+	return StatusCode::FAILURE;
+    }
+
+    // File to be read for Neutrino ids
+    std::string   neutrinoIDFileName = dict->file_name();
+
+    // Tag of RDB record for Neutrino ids
+    std::string   neutrinoIdDictTag  = dict->dict_tag();
+
+
+    if (m_emulsionId) {
+
+	// Emulsion id helper already exists - second pass. Check for a
+	// change 
+	if (neutrinoIDTag != m_neutrinoIDTag) { 
+	    // Internal Neutrino id tag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed internal Neutrino id tag: " 
+		<< neutrinoIDTag << endmsg;
+	}
+	if (neutrinoIDFileName != m_neutrinoIDFileName) {
+	    // File to be read for Neutrino ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed NeutrinoFileName:" 
+		<< neutrinoIDFileName << endmsg;
+	}
+	if (neutrinoIdDictTag != m_neutrinoIdDictTag) {
+	    // Tag of RDB record for Neutrino ids
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed NeutrinoIdDictTag: "
+		<< neutrinoIdDictTag 
+		<< endmsg;
+	}
+	if (doChecks != m_doChecks) {
+	    // DoChecks flag
+	    initHelper = true;
+	    log << MSG::DEBUG << " Changed doChecks flag: "
+		<< doChecks
+		<< endmsg;
+        }
+    }
+    else {
+	// create the helper
+	m_emulsionId = new EmulsionID;
+	initHelper = true;
+        // add in message service for printout
+        m_emulsionId->setMessageSvc(msgSvc());
+    }
+    
+    if (initHelper) {
+	if (idDictMgr->initializeHelper(*m_emulsionId)) {
+	    log << MSG::ERROR << "Unable to initialize EmulsionID" << endmsg;
+	    return StatusCode::FAILURE;
+	} 
+	// Save state:
+	m_neutrinoIDTag      = neutrinoIDTag;
+	m_neutrinoIDFileName = neutrinoIDFileName;
+	m_neutrinoIdDictTag  = neutrinoIdDictTag;
+	m_doChecks        = doChecks;
+    }
+
+    // Pass a pointer to the container to the Persistency service by reference.
+    pObj = StoreGateSvc::asStorable(m_emulsionId);
+
+    return StatusCode::SUCCESS; 
+
+}
+
+//--------------------------------------------------------------------
+
+long
+EmulsionIDDetDescrCnv::storageType()
+{
+    return DetDescr_StorageType;
+}
+
+//--------------------------------------------------------------------
+const CLID& 
+EmulsionIDDetDescrCnv::classID() { 
+    return ClassID_traits<EmulsionID>::ID(); 
+}
+
+//--------------------------------------------------------------------
+EmulsionIDDetDescrCnv::EmulsionIDDetDescrCnv(ISvcLocator* svcloc) 
+    :
+    DetDescrConverter(ClassID_traits<EmulsionID>::ID(), svcloc),
+    m_emulsionId(0),
+    m_doChecks(false)
+
+{}
+
diff --git a/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.h b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..717e4c4b26a828f789b6573d72b5acf7630d99e1
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/EmulsionIDDetDescrCnv.h
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/***************************************************************************
+ Neutrino DetDescrCnv package
+ -----------------------------------------
+ ***************************************************************************/
+
+#ifndef NEUTRINOIDCNV_EMULSIONIDDETDESCRCNV_H
+#define NEUTRINOIDCNV_EMULSIONIDDETDESCRCNV_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "DetDescrCnvSvc/DetDescrConverter.h"
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+
+class EmulsionID;
+
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+
+/**
+ **  This class is a converter for the EmulsionID an IdHelper which is
+ **  stored in the detector store. This class derives from
+ **  DetDescrConverter which is a converter of the DetDescrCnvSvc.
+ **
+ **/
+
+class EmulsionIDDetDescrCnv: public DetDescrConverter {
+
+public:
+    virtual long int   repSvcType() const;
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj);
+
+    // Storage type and class ID (used by CnvFactory)
+    static long storageType();
+    static const CLID& classID();
+
+    EmulsionIDDetDescrCnv(ISvcLocator* svcloc);
+
+private:
+    /// The helper - only will create it once
+    EmulsionID*       m_emulsionId;
+
+    /// File to be read for Neutrino ids
+    std::string   m_neutrinoIDFileName;
+
+    /// Tag of RDB record for Neutrino ids
+    std::string   m_neutrinoIdDictTag;
+
+    /// Internal Neutrino id tag
+    std::string   m_neutrinoIDTag;
+
+    /// Whether or not 
+    bool          m_doChecks;
+
+};
+
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+#endif // NEUTRINOIDCNV_EMULSIONIDDETDESCRCNV_H
diff --git a/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/NeutrinoIdCnv_entries.cxx b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/NeutrinoIdCnv_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b3dfd90127792916047107df911d9605c7efd14b
--- /dev/null
+++ b/Neutrino/NeutrinoDetDescrCnv/NeutrinoIdCnv/src/NeutrinoIdCnv_entries.cxx
@@ -0,0 +1,3 @@
+#include "EmulsionIDDetDescrCnv.h"
+
+DECLARE_CONVERTER(EmulsionIDDetDescrCnv)
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/CMakeLists.txt b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ecaa1b03b499ec9cc9e9029867f9d34f326c1d58
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/CMakeLists.txt
@@ -0,0 +1,27 @@
+################################################################################
+# Package: NeutrinoSimEventAthenaPool
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoSimEventAthenaPool )
+
+# External dependencies:
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_poolcnv_library( NeutrinoSimEventAthenaPoolPoolCnv
+                           src/*.cxx
+                           FILES NeutrinoSimEvent/NeutrinoHitCollection.h 
+                           INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                           LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaPoolCnvSvcLib AthenaPoolUtilities AtlasSealCLHEP GaudiKernel NeutrinoSimEventTPCnv NeutrinoSimEvent )
+
+atlas_add_dictionary( NeutrinoSimEventAthenaPoolCnvDict
+                      NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPoolCnvDict.h
+                      NeutrinoSimEventAthenaPool/selection.xml
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaPoolCnvSvcLib AthenaPoolUtilities AtlasSealCLHEP GaudiKernel NeutrinoSimEventTPCnv NeutrinoSimEvent )
+
+# Install files from the package:
+atlas_install_headers( NeutrinoSimEventAthenaPool )
+#atlas_install_joboptions( share/*.py )
+
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimDataCollection_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimDataCollection_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..2298acdeb1092567af4e6b0e3d194a7184f22b62
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimDataCollection_p1.h
@@ -0,0 +1,4 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimData_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimData_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..2298acdeb1092567af4e6b0e3d194a7184f22b62
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimData_p1.h
@@ -0,0 +1,4 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPoolCnvDict.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPoolCnvDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..de99042fe4b71c99fa0a0cae19d092b420764fd2
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPoolCnvDict.h
@@ -0,0 +1,9 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOSIMEVENTATHENAPOOLDICT_H
+#define NEUTRINOSIMEVENTATHENAPOOLDICT_H
+
+
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/selection.xml b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2eff49dff6688999d781e8922c8138fc7a36b1e8
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/NeutrinoSimEventAthenaPool/selection.xml
@@ -0,0 +1,2 @@
+<lcgdict>
+</lcgdict>
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..36ff6569e3c56cd9551bae75145d1c3d5a610f2e
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h"
+#include "NeutrinoHitCollectionCnv.h"
+
+
+NeutrinoHitCollection_PERS* NeutrinoHitCollectionCnv::createPersistent(NeutrinoHitCollection* transCont) {
+  MsgStream mlog(msgSvc(), "NeutrinoHitCollectionConverter" );
+  NeutrinoHitCollectionCnv_PERS converter;
+  NeutrinoHitCollection_PERS *persObj = converter.createPersistent( transCont, mlog );
+  return persObj;
+}
+
+
+NeutrinoHitCollection* NeutrinoHitCollectionCnv::createTransient() {
+    MsgStream mlog(msgSvc(), "NeutrinoHitCollectionConverter" );
+    NeutrinoHitCollectionCnv_p1   converter_p1;
+
+    static const pool::Guid   p1_guid("2CA7AF71-1494-4378-BED4-AFB5C54398AA");
+    // static const pool::Guid   p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779");
+
+    NeutrinoHitCollection       *trans_cont(0);
+    if( this->compareClassGuid(p1_guid)) {
+      std::unique_ptr< NeutrinoHitCollection_p1 >   col_vect( this->poolReadObject< NeutrinoHitCollection_p1 >() );
+      trans_cont = converter_p1.createTransient( col_vect.get(), mlog );
+    }  else {
+      throw std::runtime_error("Unsupported persistent version of Data container");
+    }
+    return trans_cont;
+}
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ccd3e1bb8675b5f5542032781af7d737aa1a378
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h
@@ -0,0 +1,29 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOHITCOLLECTIONCNV
+#define NEUTRINOHITCOLLECTIONCNV
+
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h"
+// Gaudi
+#include "GaudiKernel/MsgStream.h"
+// typedef to the latest persistent version
+typedef NeutrinoHitCollection_p1     NeutrinoHitCollection_PERS;
+typedef NeutrinoHitCollectionCnv_p1  NeutrinoHitCollectionCnv_PERS;
+
+class NeutrinoHitCollectionCnv  : public T_AthenaPoolCustomCnv<NeutrinoHitCollection, NeutrinoHitCollection_PERS > {
+  friend class CnvFactory<NeutrinoHitCollectionCnv>;
+public:
+  NeutrinoHitCollectionCnv(ISvcLocator* svcloc) :
+        T_AthenaPoolCustomCnv<NeutrinoHitCollection, NeutrinoHitCollection_PERS >( svcloc) {}
+protected:
+  NeutrinoHitCollection_PERS*  createPersistent(NeutrinoHitCollection* transCont);
+  NeutrinoHitCollection*       createTransient ();
+};
+
+
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..defef98b76adfaf00e4b4c1da37c685cee6e2d7c
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt
@@ -0,0 +1,26 @@
+###############################################################################
+# Package: NeutrinoSimEventTPCnv
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoSimEventTPCnv )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_library( NeutrinoSimEventTPCnv
+                   src/NeutrinoHits/*.cxx
+                   PUBLIC_HEADERS NeutrinoSimEventTPCnv
+                   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                   PRIVATE_DEFINITIONS ${CLHEP_DEFINITIONS}
+                   LINK_LIBRARIES GaudiKernel GeneratorObjectsTPCnv NeutrinoSimEvent AthenaPoolCnvSvcLib StoreGateLib SGtests
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} TestTools Identifier )
+
+atlas_add_dictionary( NeutrinoSimEventTPCnvDict
+                      NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h
+                      NeutrinoSimEventTPCnv/selection.xml
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv NeutrinoSimEvent TestTools StoreGateLib SGtests Identifier NeutrinoSimEventTPCnv )
+
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..c33946cf5e76626d2281d180bf78fc6d6ea98375
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOHITCNV_P1_H
+#define NEUTRINOHITCNV_P1_H
+
+/*
+Transient/Persistent converter for NeutrinoHit class
+Author: Davide Costanzo
+*/
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "NeutrinoHit_p1.h"
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h"
+
+class MsgStream;
+
+
+class NeutrinoHitCnv_p1  : public T_AthenaPoolTPCnvBase<NeutrinoHit, NeutrinoHit_p1>
+{
+public:
+
+  NeutrinoHitCnv_p1() {}
+
+  virtual void          persToTrans(const NeutrinoHit_p1* persObj, NeutrinoHit*
+transObj, MsgStream &log);
+  virtual void          transToPers(const NeutrinoHit* transObj, NeutrinoHit_p1*
+persObj, MsgStream &log);
+};
+
+
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..4adb5b4623de40845eb7b55877e255a689fc349b
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOHITCOLLECTIONCNV_P1_H
+#define NEUTRINOHITCOLLECTIONCNV_P1_H
+
+// NeutrinoHitCollectionCnv_p1, T/P separation of Neutrino Hits
+// author D.Costanzo <davide.costanzo@cern.ch>
+// author O.Arnaez <olivier.arnaez@cern.ch>
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h"
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+#include "NeutrinoHitCollection_p1.h"
+
+
+class NeutrinoHitCollectionCnv_p1 : public T_AthenaPoolTPCnvBase<NeutrinoHitCollection, NeutrinoHitCollection_p1>
+{
+ public:
+
+  NeutrinoHitCollectionCnv_p1()  {};
+
+  virtual NeutrinoHitCollection* createTransient(const NeutrinoHitCollection_p1* persObj, MsgStream &log);
+
+  virtual void	persToTrans(const NeutrinoHitCollection_p1* persCont,
+                            NeutrinoHitCollection* transCont,
+                            MsgStream &log) ;
+  virtual void	transToPers(const NeutrinoHitCollection* transCont,
+                            NeutrinoHitCollection_p1* persCont,
+                            MsgStream &log) ;
+
+ private:
+
+  static const double m_persEneUnit;
+  static const double m_persLenUnit;
+  static const double m_persAngUnit;
+  static const double m_2bHalfMaximum;
+  static const int m_2bMaximum;
+};
+
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..631fab9d84dbb1b866713f7c016ea7f372a89308
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOHITCOLLECTION_P1_H
+#define NEUTRINOHITCOLLECTION_P1_H
+
+/*
+
+Authors: Davide Costanzo Rob Duxfield
+
+*/
+
+#include <vector>
+#include <string>
+
+class NeutrinoHitCollection_p1
+{
+ public:
+/// Default constructor
+  NeutrinoHitCollection_p1 ();
+  //private:
+
+  std::vector<float>          m_hit1_meanTime;   //  1 element per string
+  std::vector<float>          m_hit1_x0;         //
+  std::vector<float>          m_hit1_y0;         //
+  std::vector<float>          m_hit1_z0;         //
+  std::vector<float>          m_hit1_theta;      //
+  std::vector<float>          m_hit1_phi;        //
+  std::vector<unsigned short> m_nHits;           //
+
+  std::vector<unsigned short> m_hitEne_2b;       //  1 element per hit
+  std::vector<unsigned short> m_hitLength_2b;    //
+
+  std::vector<unsigned short> m_dTheta;          //  1 element per hit except for first hit in string
+  std::vector<unsigned short> m_dPhi;            //
+
+  std::vector<float>          m_hitEne_4b;       //  1 element per hit with  m_hitEne_2b[i] == 2**16
+
+  std::vector<float>          m_hitLength_4b;    //  1 element per hit with  m_hitLength_2b[i] == 2**16
+
+  std::vector<unsigned long>  m_barcode;
+  std::vector<unsigned short> m_mcEvtIndex;
+  std::vector<char>           m_evtColl;
+  std::vector<unsigned short> m_nBC;
+
+  std::vector<unsigned long>  m_id;
+  std::vector<unsigned short> m_nId;
+};
+
+
+// inlines
+
+inline
+NeutrinoHitCollection_p1::NeutrinoHitCollection_p1 () {}
+
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e2bd215ea8142dc5ceae7d9a237a53f25d3f6f2
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h
@@ -0,0 +1,19 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOHIT_P1_H
+#define NEUTRINOHIT_P1_H
+
+#include "GeneratorObjectsTPCnv/HepMcParticleLink_p2.h"
+
+class NeutrinoHit_p1 {
+ public:
+  float m_stX, m_stY, m_stZ;
+  float m_enX, m_enY, m_enZ;
+  float m_energyLoss; // deposited energy
+  float m_meanTime; // time of energy deposition
+  HepMcParticleLink_p2 m_partLink;
+  unsigned int m_ID;
+};
+#endif
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..064ad71ac526d7f0a0d826df691f65f1ae648f98
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h
@@ -0,0 +1,20 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOEVENTTPCNV_NEUTRINOSIMEVENTTPCNVDICT_H
+#define NEUTRINOEVENTTPCNV_NEUTRINOSIMEVENTTPCNVDICT_H
+
+//-----------------------------------------------------------------------------
+//
+// file:   NeutrinoSimEventTPCnvDict_p1.h
+//
+//-----------------------------------------------------------------------------
+
+
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h"
+
+#endif // NEUTRINOEVENTTPCNV_NEUTRINOSIMEVENTTPCNVDICT_H
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6808c217a9a651ba26b4147a58409380ea0cc49b
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+    <!-- NeutrinoHits -->
+    <class name="NeutrinoHit_p1" />
+    <class name="std::vector<NeutrinoHit_p1>" />
+    <class name="NeutrinoHitCollection_p1" id="2CA7AF71-1494-4378-BED4-AFB5C54398AA" />
+</lcgdict>
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCnv_p1.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCnv_p1.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2732569782357b349c8095adf25df981dac2921e
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCnv_p1.cxx
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "Identifier/Identifier.h"
+#include "GeneratorObjectsTPCnv/HepMcParticleLinkCnv_p2.h"
+
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h"
+
+
+void
+NeutrinoHitCnv_p1::persToTrans(const NeutrinoHit_p1* persObj, NeutrinoHit* transObj, MsgStream &log)
+{
+  HepMcParticleLinkCnv_p2 HepMcPLCnv;
+  HepMcParticleLink link;
+  HepMcPLCnv.persToTrans(&(persObj->m_partLink),&link, log);
+
+   *transObj = NeutrinoHit (HepGeom::Point3D<double> (persObj->m_stX,
+                                                   persObj->m_stY,
+                                                   persObj->m_stZ),
+                         HepGeom::Point3D<double> (persObj->m_enX,
+                                                   persObj->m_enY,
+                                                   persObj->m_enZ),
+                         persObj->m_energyLoss,
+                         persObj->m_meanTime,
+                         link,
+                         persObj->m_ID
+                      );
+}
+
+
+void
+NeutrinoHitCnv_p1::transToPers(const NeutrinoHit* transObj, NeutrinoHit_p1* persObj, MsgStream &log)
+{
+//     if (log.level() <= MSG::DEBUG) log << MSG::DEBUG << "NeutrinoHitCnv_p1::transToPers called " << endmsg;
+   HepMcParticleLinkCnv_p2 HepMcPLCnv;
+
+   HepGeom::Point3D<double> st = transObj->localStartPosition();
+   persObj->m_stX         = st.x();
+   persObj->m_stY         = st.y();
+   persObj->m_stZ         = st.z();
+
+   HepGeom::Point3D<double> en = transObj->localEndPosition();
+   persObj->m_enX         = en.x();
+   persObj->m_enY         = en.y();
+   persObj->m_enZ         = en.z();
+
+   persObj->m_energyLoss  = transObj->energyLoss();
+   persObj->m_meanTime    = transObj->meanTime();
+   persObj->m_ID          = transObj->identify();
+   HepMcPLCnv.transToPers(&(transObj->particleLink()),&(persObj->m_partLink), log);
+}
diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3b85676a61cd4235918207a9deb82659ed1bc5bc
--- /dev/null
+++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx
@@ -0,0 +1,312 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h"
+#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h"
+#include "GeneratorObjects/HepMcParticleLink.h"
+
+#include <cmath>
+
+//CLHEP
+#include "CLHEP/Geometry/Point3D.h"
+// Gaudi
+#include "GaudiKernel/MsgStream.h"
+// Athena
+#include "StoreGate/StoreGateSvc.h"
+
+//  * * *  stolen from eflowRec  * * *  //
+inline double phicorr(double a)
+{
+  if (a <= -M_PI)
+    {
+      return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI)));
+    }
+  else if (a > M_PI)
+    {
+      return a-(2*M_PI*floor((a+M_PI)/(2*M_PI)));
+    }
+  else
+    {
+      return a;
+    }
+}
+
+//  * * *  stolen from eflowRec  * * *  //
+inline double cycle(double a, double b)
+{
+  double del = b-a;
+  if (del > M_PI)
+    {
+      return a+2.0*M_PI;
+    }
+  else if (del < -M_PI)
+    {
+      return a-2.0*M_PI;
+    }
+  else
+    {
+      return a;
+    }
+}
+
+
+const double NeutrinoHitCollectionCnv_p1::m_persEneUnit = 1.0e-5;
+const double NeutrinoHitCollectionCnv_p1::m_persLenUnit = 1.0e-5;
+const double NeutrinoHitCollectionCnv_p1::m_persAngUnit = 1.0e-5;
+const double NeutrinoHitCollectionCnv_p1::m_2bHalfMaximum = pow(2.0, 15.0);
+const int NeutrinoHitCollectionCnv_p1::m_2bMaximum = (unsigned short)(-1);
+
+
+void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* transCont, NeutrinoHitCollection_p1* persCont, MsgStream &/*log*/)
+{
+  // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and
+  // persistifies the end point of each hit plus the start point of the first hit in each string.
+  //
+  // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of
+  // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and
+  // used to specify the hit direction. All hit lengths are stored as 2 byte numbers.
+  //
+  // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean
+  // time of the first hit per string.
+  //
+  // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info.
+
+  static const double dRcut = 1.0e-7;
+  static const double dTcut = 1.0;
+
+  const HepMcParticleLink * lastLink=nullptr;
+  int lastId = -1;
+  double stringFirstTheta = 0.0;
+  double stringFirstPhi = 0.0;
+  double lastT = 0.0;
+  double persSumE = 0.0;
+  double transSumE = 0.0;
+  unsigned int idx = 0;
+  unsigned int endBC = 0;
+  unsigned int endId = 0;
+  unsigned int endHit = 0;
+  HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0);
+  HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0);
+
+  for (NeutrinoHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) {
+
+    NeutrinoHitCollection::const_iterator siHit = it;
+
+
+    if ( !lastLink || (siHit->particleLink() != *lastLink) ) {
+
+      // store barcode once for set of consecutive hits with same barcode
+
+      lastLink = &(siHit->particleLink());
+      persCont->m_barcode.push_back(lastLink->barcode());
+      persCont->m_mcEvtIndex.push_back(lastLink->eventIndex());
+      persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar());
+
+      if (idx > 0) {
+        persCont->m_nBC.push_back(idx - endBC);
+        endBC = idx;
+      }
+    }
+
+    if ( (int)siHit->identify() != lastId ) {
+
+      // store id once for set of consecutive hits with same barcode
+
+      lastId = siHit->identify();
+      persCont->m_id.push_back(lastId);
+
+      if (idx > 0) {
+        persCont->m_nId.push_back(idx - endId);
+        endId = idx;
+      }
+    }
+
+    HepGeom::Point3D<double> st = siHit->localStartPosition();
+    HepGeom::Point3D<double> en = siHit->localEndPosition();
+
+    const double dx = st.x() - lastTransEnd.x();
+    const double dy = st.y() - lastTransEnd.y();
+    const double dz = st.z() - lastTransEnd.z();
+    const double t = siHit->meanTime();
+
+    const double dRLast = sqrt(dx * dx + dy * dy + dz * dz);  // dR between end of previous hit and start of current one
+    const double dTLast = fabs(t - lastT);
+
+    CLHEP::Hep3Vector direction(0.0, 0.0, 0.0);
+    double theta = 0.0;
+    double phi = 0.0;
+    bool startNewString = false;
+
+    if (dRLast < dRcut && dTLast < dTcut) {
+
+      // hit is part of existing string
+
+      direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() );
+
+      theta = direction.theta();
+      phi = phicorr( direction.phi() );
+
+      const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 );
+      const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 );
+
+      if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) {
+        persCont->m_dTheta.push_back(dTheta_2b);
+        persCont->m_dPhi.push_back(dPhi_2b);
+        theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit;
+        phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit;
+        phi = phicorr(phi);
+      }
+      else {
+        startNewString = true;
+      }
+    }
+
+    if (startNewString || dRLast >= dRcut || dTLast >= dTcut) {
+
+      // begin new hit string
+
+      direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() );
+
+      theta = direction.theta();
+      phi = phicorr( direction.phi() );
+
+      persCont->m_hit1_meanTime.push_back(t);
+      persCont->m_hit1_x0.push_back(st.x());
+      persCont->m_hit1_y0.push_back(st.y());
+      persCont->m_hit1_z0.push_back(st.z());
+      persCont->m_hit1_theta.push_back(theta);
+      persCont->m_hit1_phi.push_back(phi);
+
+      lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z());
+
+      stringFirstTheta = theta;
+      stringFirstPhi = phi;
+
+      if (idx > 0) {
+        persCont->m_nHits.push_back(idx - endHit);
+        endHit = idx;
+      }
+    }
+
+    lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z());
+    transSumE += siHit->energyLoss();
+
+    const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5);  // calculated to allow recovery sum over
+                                                                                 // whole hit string to chosen precision
+
+    const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5);  // calculated to give the correct position to
+                                                                            // the chosen precision, NOT the length of the
+                                                                            // hit (small difference in practice).
+    double eneLoss = 0.0;
+
+    if (eneLoss_2b >= m_2bMaximum) {
+      eneLoss = siHit->energyLoss();
+      persCont->m_hitEne_2b.push_back(m_2bMaximum);
+      persCont->m_hitEne_4b.push_back(eneLoss);
+    }
+    else {
+      eneLoss = eneLoss_2b * m_persEneUnit;
+      persCont->m_hitEne_2b.push_back(eneLoss_2b);
+    }
+
+    double length = 0.0;
+
+    if (hitLength_2b >= m_2bMaximum) {
+      length = direction.mag();
+      persCont->m_hitLength_2b.push_back(m_2bMaximum);
+      persCont->m_hitLength_4b.push_back(direction.mag());
+    }
+    else {
+      length = hitLength_2b * m_persLenUnit;
+      persCont->m_hitLength_2b.push_back(hitLength_2b);
+    }
+
+    CLHEP::Hep3Vector persDir(length, 0.0, 0.0);
+    persDir.setTheta(theta);
+    persDir.setPhi(phi);
+
+    lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir;
+    persSumE += eneLoss;
+    lastT = t;
+
+    ++idx;
+  }
+
+  persCont->m_nBC.push_back(idx - endBC);
+  persCont->m_nId.push_back(idx - endId);
+  persCont->m_nHits.push_back(idx - endHit);
+}
+
+
+NeutrinoHitCollection* NeutrinoHitCollectionCnv_p1::createTransient(const NeutrinoHitCollection_p1* persObj, MsgStream &log) {
+  std::unique_ptr<NeutrinoHitCollection> trans(std::make_unique<NeutrinoHitCollection>("DefaultCollectionName",persObj->m_nHits.size()));
+  persToTrans(persObj, trans.get(), log);
+  return(trans.release());
+}
+
+
+void NeutrinoHitCollectionCnv_p1::persToTrans(const NeutrinoHitCollection_p1* persCont, NeutrinoHitCollection* transCont, MsgStream &/*log*/)
+{
+  unsigned int hitCount = 0;
+  unsigned int angleCount = 0;
+  unsigned int idxBC = 0;
+  unsigned int idxId = 0;
+  unsigned int idxEne4b = 0;
+  unsigned int idxLen4b = 0;
+  unsigned int endHit = 0;
+  unsigned int endBC = 0;
+  unsigned int endId = 0;
+
+  for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) {
+
+    if (persCont->m_nHits[i]) {
+
+      const unsigned int start = endHit;
+      endHit += persCont->m_nHits[i];
+
+      const double t0 = persCont->m_hit1_meanTime[i];
+      const double theta0 = persCont->m_hit1_theta[i];
+      const double phi0 = persCont->m_hit1_phi[i];
+      HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]);
+
+      for (unsigned int j = start; j < endHit; j++) {
+
+        if (j >= endBC + persCont->m_nBC[idxBC])
+          endBC += persCont->m_nBC[idxBC++];
+
+        if (j >= endId + persCont->m_nId[idxId])
+          endId += persCont->m_nId[idxId++];
+
+        const double eneLoss_2b = persCont->m_hitEne_2b[hitCount];
+        const double hitLength_2b = persCont->m_hitLength_2b[hitCount];
+
+        const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++];
+        const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++];
+
+        const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0;
+        const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0;
+
+        const double meanTime = t0;
+        const double theta = theta0 + dTheta;
+        const double phi = phicorr(phi0 + dPhi);
+
+        CLHEP::Hep3Vector r(length, 0.0, 0.0);
+        r.setTheta(theta);
+        r.setPhi(phi);
+
+        HepGeom::Point3D<double> endThis( endLast + r );
+
+        HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), HepMcParticleLink::IS_INDEX );
+        transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]);
+
+        endLast = endThis;
+
+        ++hitCount;
+        if (j > start) ++angleCount;
+      }
+    }
+  }
+}
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/CMakeLists.txt b/Neutrino/NeutrinoG4/EmulsionG4_SD/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5ce584bd562a18d4f61f970fdcabb498245e6145
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/CMakeLists.txt
@@ -0,0 +1,22 @@
+################################################################################
+# Package: EmulsionG4_SD
+################################################################################
+
+# Declare the package name:
+atlas_subdir( EmulsionG4_SD )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( Geant4 )
+find_package( XercesC )
+
+# Component(s) in the package:
+atlas_add_component( EmulsionG4_SD
+                     src/*.cxx
+                     src/components/*.cxx
+                     INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} StoreGateLib SGtests GaudiKernel NeutrinoSimEvent G4AtlasToolsLib FaserMCTruth )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py b/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..391e572abaef8cc7df72ec56a692c694aab32d74
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+EmulsionSensorSDTool=CompFactory.EmulsionSensorSDTool
+
+def EmulsionSensorSDCfg(ConfigFlags, name="EmulsionSensorSD", **kwargs):
+
+    result = ComponentAccumulator()
+    bare_collection_name = "EmulsionHits"
+    # mergeable_collection_suffix = "_G4"
+    # merger_input_property = "PreshowerHits"
+
+    # acc, hits_collection_name = CollectionMergerCfg(ConfigFlags, bare_collection_name, mergeable_collection_suffix, merger_input_property, "SCINT")
+    # kwargs.setdefault("OutputCollectionNames", [hits_collection_name])
+    kwargs.setdefault("LogicalVolumeNames", ["Emulsion::FrontFilm", "Emulsion::BackFilm"])
+    kwargs.setdefault("OutputCollectionNames", [bare_collection_name])
+
+    # result.merge(acc)
+    return result, EmulsionSensorSDTool(name, **kwargs)
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.cxx b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1f0fb78f228fa5d6f817dc3c2d72f3611af7d364
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.cxx
@@ -0,0 +1,119 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+//
+// Emulsion Sensitive Detector.
+// The Hits are processed here. For every hit I get the position and
+// an information on the sensor in which the interaction happened
+//
+
+// class headers
+#include "EmulsionSensorSD.h"
+
+// athena includes
+#include "FaserMCTruth/FaserTrackHelper.h"
+
+// Geant4 includes
+#include "G4Step.hh"
+#include "G4ThreeVector.hh"
+#include "G4SDManager.hh"
+#include "G4Geantino.hh"
+#include "G4ChargedGeantino.hh"
+
+// CLHEP transform
+#include "CLHEP/Geometry/Transform3D.h"
+
+#include <memory> // For make unique
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+EmulsionSensorSD::EmulsionSensorSD( const std::string& name, const std::string& hitCollectionName )
+  : G4VSensitiveDetector( name )
+  , m_HitColl( hitCollectionName )
+{
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+void EmulsionSensorSD::Initialize(G4HCofThisEvent *)
+{
+  if (!m_HitColl.isValid()) m_HitColl = std::make_unique<NeutrinoHitCollection>();
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+G4bool EmulsionSensorSD::ProcessHits(G4Step* aStep, G4TouchableHistory* /*ROhist*/)
+{
+  double edep = aStep->GetTotalEnergyDeposit();
+  if(edep==0.) {
+    if(aStep->GetTrack()->GetDefinition()!=G4Geantino::GeantinoDefinition() &&
+       aStep->GetTrack()->GetDefinition()!=G4ChargedGeantino::ChargedGeantinoDefinition())
+      return false;
+  }
+  edep *= CLHEP::MeV;
+
+  //
+  // Get the Touchable History:
+  //
+  const G4TouchableHistory *myTouch = dynamic_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable());
+  //
+  // Get the hit coordinates. Start and End Point
+  //
+  G4ThreeVector coord1 = aStep->GetPreStepPoint()->GetPosition();
+  G4ThreeVector coord2 = aStep->GetPostStepPoint()->GetPosition();
+  //
+  // Calculate the local step begin and end position.
+  // From a G4 FAQ:
+  // http://geant4-hn.slac.stanford.edu:5090/HyperNews/public/get/geometry/17/1.html
+  //
+  const G4AffineTransform transformation = myTouch->GetHistory()->GetTopTransform();
+
+  G4ThreeVector localPosition1 = transformation.TransformPoint(coord1);
+  G4ThreeVector localPosition2 = transformation.TransformPoint(coord2);
+  //
+  // Get it into a vector in local coords and with the right units:
+  //
+  HepGeom::Point3D<double> lP1,lP2;
+ 
+  // No funny business with coordinates like ATLAS...
+  lP1[2] = localPosition1[2]*CLHEP::mm;
+  lP1[1] = localPosition1[1]*CLHEP::mm;
+  lP1[0] = localPosition1[0]*CLHEP::mm;
+
+  lP2[2] = localPosition2[2]*CLHEP::mm;
+  lP2[1] = localPosition2[1]*CLHEP::mm;
+  lP2[0] = localPosition2[0]*CLHEP::mm;
+
+  // Now Navigate the history to know in what detector the step is:
+  // and finally set the ID of det element in which the hit is.
+  //
+  //G4int History;
+  //
+  // Get station and plate
+  //
+  int module = 0;
+  int base = 0;
+  int film = 0;
+  this->indexMethod(myTouch, module, base, film);
+  // get the HepMcParticleLink from the TrackHelper
+  FaserTrackHelper trHelp(aStep->GetTrack());
+  m_HitColl->Emplace(lP1,
+                     lP2,
+                     edep,
+                     aStep->GetPreStepPoint()->GetGlobalTime(),//use the global time. i.e. the time from the beginning of the event
+                     trHelp.GetParticleLink(),
+                     module,base,film);
+  return true;
+}
+
+void EmulsionSensorSD::indexMethod(const G4TouchableHistory *myTouch, 
+                              int &module, int &base, int &film) {
+
+  film = myTouch->GetVolume()->GetCopyNo();
+  G4int moduleAndBase = myTouch->GetVolume(1)->GetCopyNo();
+  base = moduleAndBase%100;
+  module = moduleAndBase/100;
+  // std::cout << "Emulsion hit at " << module << " / " << base << " / " << film << std::endl;
+  return;
+}
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.h b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f344194ad4c8ba8be4187463910dd66330cd91c
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSD.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+/****************************************************************
+   Emulsion Sensitive Detector class
+****************************************************************/
+
+#ifndef EMULSIONG4_SD_EMULSIONSENSORSD_H
+#define EMULSIONG4_SD_EMULSIONSENSORSD_H
+
+// Base class
+#include "G4VSensitiveDetector.hh"
+
+// For the hits
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+#include "StoreGate/WriteHandle.h"
+
+// G4 needed classes
+class G4Step;
+class G4TouchableHistory;
+
+// G4 needed classes
+#include "Geant4/G4EnergyLossTables.hh"
+#include "Geant4/G4Material.hh"
+#include "Geant4/G4MaterialCutsCouple.hh"
+
+class EmulsionSensorSD : public G4VSensitiveDetector
+{
+public:
+  // Constructor
+  EmulsionSensorSD(const std::string& name, const std::string& hitCollectionName);
+
+  // Destructor
+  ~EmulsionSensorSD() { /* If all goes well we do not own myHitColl here */ }
+
+  // Deal with each G4 hit
+  G4bool ProcessHits(G4Step*, G4TouchableHistory*) override;
+
+  // For setting up the hit collection
+  void Initialize(G4HCofThisEvent*) override final;
+
+  /** Templated method to stuff a single hit into the sensitive detector class.  This
+      could get rather tricky, but the idea is to allow fast simulations to use the very
+      same SD classes as the standard simulation. */
+  template <class... Args> void AddHit(Args&&... args){ m_HitColl->Emplace( args... ); }
+
+private:
+  void indexMethod(const G4TouchableHistory *myTouch, int &module, int &base, int &film);
+
+protected:
+  // The hits collection
+  SG::WriteHandle<NeutrinoHitCollection> m_HitColl;
+  
+};
+
+#endif //EMULSIONG4_SD_EMULSIONSENSORSD_H
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.cxx b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bea30a8ccdfdf05402ab089696fd76aa66dc5ee8
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.cxx
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Emulsion Sensitive Detector Tool.
+//
+
+// class header
+#include "EmulsionSensorSDTool.h"
+
+// package includes
+#include "EmulsionSensorSD.h"
+
+// STL includes
+#include <exception>
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+EmulsionSensorSDTool::EmulsionSensorSDTool(const std::string& type, const std::string& name, const IInterface* parent)
+  : SensitiveDetectorBase( type , name , parent )
+{
+
+}
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
+
+G4VSensitiveDetector* EmulsionSensorSDTool::makeSD() const
+{
+  ATH_MSG_DEBUG( "Creating Emulsion SD: " << name() );
+
+  EmulsionSensorSD* ecsd = new EmulsionSensorSD(name(), m_outputCollectionNames[0]);
+
+  return ecsd;
+}
+
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.h b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce68d061b23a478581355b252ffbb13b9837a56d
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/EmulsionSensorSDTool.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/****************************************************************
+   Emulsion Sensitive Detector Tool
+ ****************************************************************/
+
+#ifndef EMULSIONG4_SD_EMULSIONSENSORSDTOOL_H
+#define EMULSIONG4_SD_EMULSIONSENSORSDTOOL_H
+
+// Base class
+#include "G4AtlasTools/SensitiveDetectorBase.h"
+
+// STL headers
+#include <string>
+
+class G4VSensitiveDetector;
+
+//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
+
+class EmulsionSensorSDTool : public SensitiveDetectorBase
+{
+
+public:
+  // Constructor
+  EmulsionSensorSDTool(const std::string& type, const std::string& name, const IInterface *parent);
+
+  // Destructor
+  ~EmulsionSensorSDTool() { /* If all goes well we do not own myHitColl here */ }
+
+protected:
+  // Make me an SD!
+  G4VSensitiveDetector* makeSD() const override final;
+
+private:
+
+};
+
+#endif //EMULSIONG4_SD_EMULSIONSENSORSDTOOL_H
diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/src/components/EmulsionG4_SD_entries.cxx b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/components/EmulsionG4_SD_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4fda433cbaa23a960a135a3690416bfa18cfed90
--- /dev/null
+++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/src/components/EmulsionG4_SD_entries.cxx
@@ -0,0 +1,3 @@
+#include "../EmulsionSensorSDTool.h"
+
+DECLARE_COMPONENT( EmulsionSensorSDTool )
diff --git a/Neutrino/NeutrinoSimEvent/CMakeLists.txt b/Neutrino/NeutrinoSimEvent/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bedc06bd17e9a5ae5fab09c044578660248b344a
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/CMakeLists.txt
@@ -0,0 +1,28 @@
+################################################################################
+# Package: NeutrinoSimEvent
+################################################################################
+
+# Declare the package name:
+atlas_subdir( NeutrinoSimEvent )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( Geant4 )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_library( NeutrinoSimEvent
+                   src/*.cxx
+                   PUBLIC_HEADERS NeutrinoSimEvent
+                   INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS}
+                   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS}
+                   DEFINITIONS ${CLHEP_DEFINITIONS}
+                   LINK_LIBRARIES ${CLHEP_LIBRARIES} AthAllocators AthenaKernel CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} NeutrinoIdentifier )
+
+atlas_add_dictionary( NeutrinoSimEventDict
+                      NeutrinoSimEvent/NeutrinoSimEventDict.h
+                      NeutrinoSimEvent/selection.xml
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthAllocators CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests NeutrinoIdentifier NeutrinoSimEvent )
+
diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d28bd3eab46c2d8cc82be856f3fde2aac51f8a3
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+///////////////////////////////////////////////////////////////////
+// NeutrinoHit.h
+//   Header file for class NeutrinoHit
+///////////////////////////////////////////////////////////////////
+// Class for Emulsion hits
+///////////////////////////////////////////////////////////////////
+
+#ifndef NEUTRINOSIMEVENT_NEUTRINOHIT_H
+#define NEUTRINOSIMEVENT_NEUTRINOHIT_H
+
+// Data members classes
+#include "CLHEP/Geometry/Point3D.h"
+#include "GeneratorObjects/HepMcParticleLink.h"
+
+class NeutrinoHit  {
+
+  ///////////////////////////////////////////////////////////////////
+  // Public methods:
+  ///////////////////////////////////////////////////////////////////
+public:
+
+  // Constructor with parameters:
+  //   local start position of the energy deposit
+  //   local end position of the energy deposit
+  //   deposited energy
+  //   time of energy deposition
+  //   number of track which released this energy
+  //
+  NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+           const HepGeom::Point3D<double> &localEndPosition,
+           const double energyLoss,
+           const double meanTime,
+           const int trackNumber,
+           const unsigned int id);
+
+  NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+           const HepGeom::Point3D<double> &localEndPosition,
+           const double energyLoss,
+           const double meanTime,
+           const int trackNumber,
+           const int, const int, const int);
+  // Constructor with parameters:
+  //   local start position of the energy deposit
+  //   local end position of the energy deposit
+  //   deposited energy
+  //   time of energy deposition
+  //   link to particle which released this energy
+  //
+  NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+           const HepGeom::Point3D<double> &localEndPosition,
+           const double energyLoss,
+           const double meanTime,
+           const HepMcParticleLink &track,
+           const unsigned int id);
+
+  NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+           const HepGeom::Point3D<double> &localEndPosition,
+           const double energyLoss,
+           const double meanTime,
+           const HepMcParticleLink &track,
+           const int, const int, const int);
+  // needed by athenaRoot
+  NeutrinoHit();
+
+  // Destructor:
+  virtual ~NeutrinoHit(); 
+  
+  //move assignment defaulted
+  NeutrinoHit & operator = (NeutrinoHit &&) = default;
+  //assignment defaulted
+  NeutrinoHit & operator = (const NeutrinoHit &) = default;
+  //copy c'tor defaulted
+  NeutrinoHit(const NeutrinoHit &) = default;
+
+  ///////////////////////////////////////////////////////////////////
+  // Const methods:
+  ///////////////////////////////////////////////////////////////////
+
+  unsigned int identify() const;
+
+  // local start position of the energy deposit:
+  HepGeom::Point3D<double> localStartPosition() const;
+
+  HepGeom::Point3D<double> localEndPosition() const;
+
+  // deposited energy:
+  double energyLoss() const;
+
+  // time of energy deposition: FIXME name!
+  double meanTime() const;
+
+  // Set the time of energy deposition: FIXME name!
+  void setMeanTime(float meanTime);
+
+  // number of track which released this energy:
+  int trackNumber() const;
+
+  // link to the particle generating the hit
+  const HepMcParticleLink& particleLink() const;
+
+  // Film
+  int getFilm() const;
+
+  // Base
+  int getBase() const;
+
+  // Module
+  int getModule() const;
+
+  // some print-out:
+  void print() const;
+
+  bool operator < (const NeutrinoHit& rhs) const
+  {return m_ID < rhs.m_ID;}
+
+  ///////////////////////////////////////////////////////////////////
+  // Non-const methods:
+  ///////////////////////////////////////////////////////////////////
+  // Scale the length, used to go from cm to mm, of whatever we like.
+  void ScaleLength(double);
+
+  ///////////////////////////////////////////////////////////////////
+  // Private data:
+  ///////////////////////////////////////////////////////////////////
+private:
+
+  float m_stX, m_stY, m_stZ;
+  float m_enX, m_enY, m_enZ;
+  float m_energyLoss; // deposited energy
+  float m_meanTime; // time of energy deposition
+  HepMcParticleLink m_partLink;
+  unsigned int m_ID;
+public:
+  // enum
+  //   { xDep = 2, xPhi = 0, xEta = 1};
+};
+
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+inline unsigned int NeutrinoHit::identify() const
+{
+  return m_ID;
+}
+
+inline double NeutrinoHit::energyLoss() const
+{
+  return (double) m_energyLoss;
+}
+
+inline double NeutrinoHit::meanTime() const
+{
+  return (double) m_meanTime;
+}
+
+inline void NeutrinoHit::setMeanTime(float meanTime)
+{
+  m_meanTime=meanTime;
+}
+
+inline const HepMcParticleLink& NeutrinoHit::particleLink() const
+{
+  return m_partLink;
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+// open functions:
+///////////////////////////////////////////////////////////////////
+
+inline float hitTime(const NeutrinoHit& hit)
+{
+  return (float) hit.meanTime();
+}
+
+#endif // CALOSIMEVENT_CALOHIT_H
diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitCollection.h b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitCollection.h
new file mode 100644
index 0000000000000000000000000000000000000000..68461270526ee38a84e6387b57b41518cb4d151c
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitCollection.h
@@ -0,0 +1,20 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOSIMEVENT_NEUTRINOHITCOLLECTION_H
+#define NEUTRINOSIMEVENT_NEUTRINOHITCOLLECTION_H
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "HitManagement/AtlasHitsVector.h"
+#include "AthenaKernel/CLASS_DEF.h"
+
+typedef AtlasHitsVector<NeutrinoHit> NeutrinoHitCollection;
+typedef AtlasHitsVector<NeutrinoHit>::iterator NeutrinoHitIterator;
+typedef AtlasHitsVector<NeutrinoHit>::const_iterator NeutrinoHitConstIterator;
+
+#ifndef __CINT__
+  CLASS_DEF(NeutrinoHitCollection, 1232962600, 1 )
+#endif
+
+#endif // NEUTRINOSIMEVENT_NEUTRINOHITCOLLECTION_H
diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitIdHelper.h b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitIdHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..afa362e63104e428e4c5e98dddb4add3a2ed5cc9
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHitIdHelper.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOSIMEVENT_NEUTRINOHITIDHELPER
+#define NEUTRINOSIMEVENT_NEUTRINOHITIDHELPER
+
+//
+// This is a helper class to build an identifing integer used by
+// the simulation. It inherits from HitIdHelper, in order to get
+// all the packing and shifting for free.
+// The class is a singleton and a static GetHelper() is provided
+// the constructor calls the Initialize() method which sets all the
+// field dimensions
+// Methods are provided to get access to the Geometry
+// description
+//
+
+
+//
+// Base Class
+#include "HitManagement/HitIdHelper.h"
+
+// This class is singleton and static method and variable are used.
+#include "CxxUtils/checker_macros.h"
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;
+
+class NeutrinoHitIdHelper : HitIdHelper {
+ public:
+  //
+  // Access to the helper
+  static NeutrinoHitIdHelper* GetHelper();
+  //
+
+  // Front or back
+  int getFilm(const int& hid) const;
+
+  // Which base
+  int getBase(const int& hid) const;
+
+  // Which module
+  int getModule(const int& hid) const;
+
+  //
+  // Info packing:
+  int buildHitId(const int module, const int base, const int film) const;
+
+ private:
+  //
+  // private constructor to have a singleton
+  NeutrinoHitIdHelper();
+  //
+  // Initialize the helper, only called by the constructor
+  void Initialize();
+};
+
+#endif // NEUTRINOSIMEVENT_NEUTRINOHITIDHELPER
diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoSimEventDict.h b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoSimEventDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f47010aebd7c6e556ac0bee0e88c66492a1c6ab
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoSimEventDict.h
@@ -0,0 +1,10 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef NEUTRINOSIMEVENT_NEUTRINOSIMEVENTDICT_H
+#define NEUTRINOSIMEVENT_NEUTRINOSIMEVENTDICT_H
+
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+
+#endif
\ No newline at end of file
diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/selection.xml b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fd37526859c1f733d22fb478c8ea2c22055e64cb
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/selection.xml
@@ -0,0 +1,5 @@
+<lcgdict>
+  <class name="AtlasHitsVector<NeutrinoHit>" />
+  <class name="std::vector<NeutrinoHit>" />
+  <class name="NeutrinoHit" />
+</lcgdict>
diff --git a/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx b/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0101b412737265fff81b6c1c3fbf467c163fdc96
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx
@@ -0,0 +1,159 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "NeutrinoSimEvent/NeutrinoHitIdHelper.h"
+
+// Default consdtructor needed by athenaroot
+//
+NeutrinoHit::NeutrinoHit( ) :
+  m_stX(0.),
+  m_stY(0.),
+  m_stZ(0.),
+  m_enX(0.),
+  m_enY(0.),
+  m_enZ(0.),
+  m_energyLoss(0.),
+  m_meanTime(0.),
+  m_partLink(),
+  m_ID(0xffff)
+{
+
+}
+
+NeutrinoHit::~NeutrinoHit() {}
+
+
+// Constructor
+NeutrinoHit::NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+                   const HepGeom::Point3D<double> &localEndPosition,
+                   const double energyLoss,
+                   const double meanTime,
+                   const int trackNumber,
+                   const unsigned int id) :
+  m_stX( (float) localStartPosition.x() ),
+  m_stY( (float) localStartPosition.y() ),
+  m_stZ( (float) localStartPosition.z() ),
+  m_enX( (float) localEndPosition.x() ),
+  m_enY( (float) localEndPosition.y() ),
+  m_enZ( (float) localEndPosition.z() ),
+  m_energyLoss(energyLoss),
+  m_meanTime(meanTime),
+  m_partLink(trackNumber),
+  m_ID(id)
+{
+}
+
+// Constructor
+NeutrinoHit::NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+                   const HepGeom::Point3D<double> &localEndPosition,
+                   const double energyLoss,
+                   const double meanTime,
+                   const int trackNumber,
+                  //  const int veto_trigger_preshower, 
+                   const int module, 
+                   const int base,
+                   const int film) :
+  m_stX( (float) localStartPosition.x() ),
+  m_stY( (float) localStartPosition.y() ),
+  m_stZ( (float) localStartPosition.z() ),
+  m_enX( (float) localEndPosition.x() ),
+  m_enY( (float) localEndPosition.y() ),
+  m_enZ( (float) localEndPosition.z() ),
+  m_energyLoss(energyLoss),
+  m_meanTime(meanTime),
+  m_partLink(trackNumber),
+  m_ID(0)
+{
+  // Compress the location info into the integer:
+  m_ID =  NeutrinoHitIdHelper::GetHelper()->buildHitId( module, base, film);
+}
+
+// Constructor
+NeutrinoHit::NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+                   const HepGeom::Point3D<double> &localEndPosition,
+                   const double energyLoss,
+                   const double meanTime,
+                   const HepMcParticleLink &track,
+                   const unsigned int id) :
+  m_stX( (float) localStartPosition.x() ),
+  m_stY( (float) localStartPosition.y() ),
+  m_stZ( (float) localStartPosition.z() ),
+  m_enX( (float) localEndPosition.x() ),
+  m_enY( (float) localEndPosition.y() ),
+  m_enZ( (float) localEndPosition.z() ),
+  m_energyLoss(energyLoss),
+  m_meanTime(meanTime),
+  m_partLink(track),
+  m_ID(id)
+{
+}
+
+// Constructor
+NeutrinoHit::NeutrinoHit(const HepGeom::Point3D<double> &localStartPosition,
+                   const HepGeom::Point3D<double> &localEndPosition,
+                   const double energyLoss,
+                   const double meanTime,
+                   const HepMcParticleLink &track,
+                  //  const int veto_trigger_preshower, 
+                   const int module,
+                   const int base,
+                   const int film) : 
+  m_stX( (float) localStartPosition.x() ),
+  m_stY( (float) localStartPosition.y() ),
+  m_stZ( (float) localStartPosition.z() ),
+  m_enX( (float) localEndPosition.x() ),
+  m_enY( (float) localEndPosition.y() ),
+  m_enZ( (float) localEndPosition.z() ),
+  m_energyLoss(energyLoss),
+  m_meanTime(meanTime),
+  m_partLink(track),
+  m_ID(0)
+{
+  // Compress the location info into the integer:
+  m_ID =  NeutrinoHitIdHelper::GetHelper()->buildHitId( module, base, film);
+}
+
+void NeutrinoHit::ScaleLength(double sfactor) {
+  m_stX *=  (float) sfactor;
+  m_stY *=  (float) sfactor;
+  m_stZ *=  (float) sfactor;
+  m_enX *=  (float) sfactor;
+  m_enY *=  (float) sfactor;
+  m_enZ *=  (float) sfactor;
+}
+
+HepGeom::Point3D<double> NeutrinoHit::localStartPosition() const
+{
+  return HepGeom::Point3D<double>((double) m_stX, (double) m_stY, (double) m_stZ);
+}
+
+HepGeom::Point3D<double> NeutrinoHit::localEndPosition() const
+{
+  return HepGeom::Point3D<double>((double) m_enX, (double) m_enY, (double) m_enZ);
+}
+
+int NeutrinoHit::getFilm() const {
+  return  NeutrinoHitIdHelper::GetHelper()->getFilm(m_ID);
+}
+
+int NeutrinoHit::getBase() const {
+  return  NeutrinoHitIdHelper::GetHelper()->getBase(m_ID);
+}
+
+int NeutrinoHit::getModule() const {
+  return  NeutrinoHitIdHelper::GetHelper()->getModule(m_ID);
+}
+
+void NeutrinoHit::print() const {
+  std::cout << "*** Neutrino Hit" << std::endl;
+  std::cout << "          Module Number " << getModule() << std::endl;
+  std::cout << "          Base Number "   << getBase() << std::endl;
+  std::cout << "          Film Number   " << getFilm() << std::endl;
+}
+
+int NeutrinoHit::trackNumber() const
+{
+  return m_partLink.barcode();
+}
diff --git a/Neutrino/NeutrinoSimEvent/src/NeutrinoHitIdHelper.cxx b/Neutrino/NeutrinoSimEvent/src/NeutrinoHitIdHelper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8b60d732871df6fb37eef94d305640622a93d0ae
--- /dev/null
+++ b/Neutrino/NeutrinoSimEvent/src/NeutrinoHitIdHelper.cxx
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include <mutex>
+
+#include "NeutrinoSimEvent/NeutrinoHitIdHelper.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+
+#include "G4Types.hh"
+#ifdef G4MULTITHREADED
+#  include "GaudiKernel/ContextSpecificPtr.h"
+#endif
+
+static std::mutex sgMutex;
+
+// This class is singleton and static method and variable are used.
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;
+
+//
+// private constructor
+NeutrinoHitIdHelper::NeutrinoHitIdHelper() :HitIdHelper() {
+  Initialize();
+}
+
+NeutrinoHitIdHelper* NeutrinoHitIdHelper::GetHelper() {
+#ifdef G4MULTITHREADED
+  // Context-specific singleton
+  static Gaudi::Hive::ContextSpecificPtr<NeutrinoHitIdHelper> helperPtr;
+  if(!helperPtr) helperPtr = new NeutrinoHitIdHelper();
+  return helperPtr.get();
+#else
+  static NeutrinoHitIdHelper helper;
+  return &helper;
+#endif
+}
+
+void NeutrinoHitIdHelper::Initialize() {
+
+  // determine whether hits were created with an SLHC dictionary
+  // in which case eta module field is expanded.
+  // Need to lock this thread-unsafe retrieval
+  const EmulsionID* pix;
+  ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "NeutrinoHitIdHelper");
+  if (detStore.retrieve().isSuccess()) {
+    if (detStore->retrieve(pix, "EmulsionID").isFailure()) { pix = 0; }
+  }
+
+  InitializeField("Module", 0, 34);
+  InitializeField("Base", 0, 21);
+  InitializeField("Film", 0, 1);
+}
+
+// Module
+int NeutrinoHitIdHelper::getModule(const int& hid) const
+{
+  return this->GetFieldValue("Module", hid);
+}
+
+// Base
+int NeutrinoHitIdHelper::getBase(const int& hid) const
+{
+  return this->GetFieldValue("Base", hid);
+}
+
+// Film
+int NeutrinoHitIdHelper::getFilm(const int& hid) const
+{
+  return this->GetFieldValue("Film", hid);
+}
+
+//
+// Info packing:
+int NeutrinoHitIdHelper::buildHitId( const int module, 
+                                     const int base,
+                                     const int film) const
+{
+  int theID(0);
+  this->SetFieldValue("Module",  module,    theID);
+  this->SetFieldValue("Base",    base,      theID);
+  this->SetFieldValue("Film",    film,      theID);
+  return theID;
+}
diff --git a/README.md b/README.md
index 5e46f46f515c1e9dfd29ec6fc1b0e59930680bb3..00cfe12e7f430130237cb366a8b761cde37e5568 100644
--- a/README.md
+++ b/README.md
@@ -20,12 +20,27 @@ cd build
 cmake -DCMAKE_INSTALL_PREFIX=../run ../calypso ; make ; make install
 ```
 
+Before running anything, it is MANDATORY to do:
+
+```
+cd ../run
+source ./setup.sh
+```
+
+Don't omit the dot in the `source ./setup.sh` command! 
+
 It can be convenient to alias the "asetup --input=calypso/asetup.faser" to something like "fsetup"
 
 ## Known issues:
 
-* The "WriteAlignment" example program does not compile, and is disabled.  The example will be replaced eventually.
+* It is now essential to use the tags `ConfigFlags.GeoModel.FaserVersion` and `ConfigFlags.IOVDb.GlobalTag` in a consistent way.  If nothing is specified the first option (baseline) should be chosen by default.
+
+** `ConfigFlags.GeoModel.FaserVersion = "FASER-01"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-01` enables the baseline TI-12 detector
+
+** `ConfigFlags.GeoModel.FaserVersion = "FASER-02"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the interface tracker and repositioned Veto
+
+** `ConfigFlags.GeoModel.FaserVersion = "FASERNU-02"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the full FaserNu (IFT + emulsion) setup
 
 * The "FaserActsKalmanFilter" package is temporarily disabled.
 
-* The command `lsetup "lcgenv -p LCG_98python3_ATLAS_8 x86_64-centos7-gcc8-opt sqlite` may be necessary to avoid errors when generating a database
+* The command `lsetup "lcgenv -p LCG_98python3_ATLAS_8 x86_64-centos7-gcc8-opt sqlite"` may be necessary to avoid errors when generating a database
diff --git a/Scintillator/ScintDetDescr/PreshowerGeoModel/test/PreshowerGMConfig_test.py b/Scintillator/ScintDetDescr/PreshowerGeoModel/test/PreshowerGMConfig_test.py
index 2c2501267f993a31c25765208fef41575fa0e22f..fd3709543d5a2256e31d7e9e3d8c2e583f3d8686 100644
--- a/Scintillator/ScintDetDescr/PreshowerGeoModel/test/PreshowerGMConfig_test.py
+++ b/Scintillator/ScintDetDescr/PreshowerGeoModel/test/PreshowerGMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic    = False
     ConfigFlags.lock()
 
diff --git a/Scintillator/ScintDetDescr/TriggerGeoModel/test/TriggerGMConfig_test.py b/Scintillator/ScintDetDescr/TriggerGeoModel/test/TriggerGMConfig_test.py
index 4c88d31efe75a0a0f7b8dbfef8ad1e73101ce4e8..3752d03baadffc7a6e41f66f981419557c0c4f87 100644
--- a/Scintillator/ScintDetDescr/TriggerGeoModel/test/TriggerGMConfig_test.py
+++ b/Scintillator/ScintDetDescr/TriggerGeoModel/test/TriggerGMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic    = False
     ConfigFlags.lock()
 
diff --git a/Scintillator/ScintDetDescr/VetoGeoModel/test/VetoGMConfig_test.py b/Scintillator/ScintDetDescr/VetoGeoModel/test/VetoGMConfig_test.py
index b38d833dd48371e3ce4ae49be0b2c0d108ed6982..ba3f59f3254a76661d12294c9cc5ba5b96210c35 100644
--- a/Scintillator/ScintDetDescr/VetoGeoModel/test/VetoGMConfig_test.py
+++ b/Scintillator/ScintDetDescr/VetoGeoModel/test/VetoGMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic    = False
     ConfigFlags.lock()
 
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runEcal.py b/Simulation/G4Faser/G4FaserAlg/test/runEcal.py
index cbae412c90dd7776fdf1bb6fe50975de7076dfaf..eaef5c20150c9ffc1b0e2a59d6b8004a7dbf0310 100755
--- a/Simulation/G4Faser/G4FaserAlg/test/runEcal.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runEcal.py
@@ -43,7 +43,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runG4.py b/Simulation/G4Faser/G4FaserAlg/test/runG4.py
index 5054684724bedcb0c5595b423747b8ae4512170a..9538edac50589c38fbfc3a54bb0f512359232861 100644
--- a/Simulation/G4Faser/G4FaserAlg/test/runG4.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runG4.py
@@ -43,7 +43,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runG4Cosmics.py b/Simulation/G4Faser/G4FaserAlg/test/runG4Cosmics.py
index 2479a9d1178d1ca543d57c36f7e22c1dff1472b5..56618f6cebcdac90c40570797e1c17953653200e 100644
--- a/Simulation/G4Faser/G4FaserAlg/test/runG4Cosmics.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runG4Cosmics.py
@@ -44,7 +44,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py b/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py
index d33533819fd706e5f0c08ac52e0a0e4915980107..8110c6eeaaec03ef1ea21569f1d1bcd94b8fa0d9 100644
--- a/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py
@@ -44,7 +44,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runG4FaserNu.py b/Simulation/G4Faser/G4FaserAlg/test/runG4FaserNu.py
new file mode 100644
index 0000000000000000000000000000000000000000..486b628c43b2e6dc5f37dbfefe39cd8a239b46f2
--- /dev/null
+++ b/Simulation/G4Faser/G4FaserAlg/test/runG4FaserNu.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+if __name__ == "__main__":
+    import os
+    import sys
+    import GaudiPython
+    import ParticleGun as PG
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    from AthenaConfiguration.ComponentFactory import CompFactory
+    from AthenaCommon.AppMgr import *
+    from AthenaCommon.Logging import log, logging
+    from AthenaCommon.SystemOfUnits import TeV
+    from AthenaCommon.PhysicalConstants import pi
+    from AthenaCommon.Constants import VERBOSE, INFO
+    from AthenaCommon.Configurable import Configurable
+    from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+    from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+    from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+    from McEventSelector.McEventSelectorConfig import McEventSelectorCfg
+    from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+    from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+    from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg
+    from G4FaserServices.G4FaserServicesConfigNew import G4GeometryNotifierSvcCfg
+#
+# Set up logging and new style config
+#
+    log.setLevel(VERBOSE)
+    Configurable.configurableRun3Behavior = True
+#
+# Input settings (Generator file)
+#
+#   from AthenaConfiguration.TestDefaults import defaultTestFiles
+#   ConfigFlags.Input.Files = defaultTestFiles.EVNT
+#
+# Alternatively, these must ALL be explicitly set to run without an input file
+# (if missing, it will try to read metadata from a non-existent file and crash)
+#
+    ConfigFlags.Input.Files = [""]
+    ConfigFlags.Input.isMC = True
+    ConfigFlags.Input.RunNumber = 12345
+    ConfigFlags.Input.Collections = [""]
+    ConfigFlags.Input.ProjectName = "mc19"
+    ConfigFlags.Common.isOnline = False
+    ConfigFlags.Beam.Type = "collisions"
+    ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
+    ConfigFlags.GeoModel.FaserVersion = "FASERNU-02"             # Always needed
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"             # Always needed; must match FaserVersion
+# Workaround for bug/missing flag; unimportant otherwise 
+    ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
+# Workaround to avoid problematic ISF code
+    ConfigFlags.GeoModel.Layout = "Development"
+#
+# Output settings
+#
+    ConfigFlags.Output.HITSFileName = "myFaserNu.HITS.pool.root"
+    ConfigFlags.GeoModel.GeoExportFile = "faserGeo.db" # Optional dump of geometry for browsing in vp1light
+#
+# Geometry-related settings
+# Do not change!
+#
+    detectors = ['Emulsion', 'Veto', 'Trigger', 'Preshower', 'FaserSCT', 'Dipole', 'Ecal']
+    from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList
+    setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True)
+    ConfigFlags.GeoModel.Align.Dynamic  = False
+    ConfigFlags.Sim.ReleaseGeoModel     = False
+#
+# Physics list
+#
+    ConfigFlags.Sim.PhysicsList = "FTFP_BERT"
+#
+# All flags should be set before calling lock
+#
+    ConfigFlags.lock()
+#
+# Construct ComponentAccumulator
+#
+    acc = MainServicesCfg(ConfigFlags)
+#
+# Particle Gun generator (comment out to read generator file)
+# Raw energies (without units given) are interpreted as MeV
+#
+    pg = PG.ParticleGun()
+    pg.McEventKey = "GEN_EVENT"
+    pg.randomSeed = 123456
+    pg.sampler.pid = -13
+    pg.sampler.mom = PG.EThetaMPhiSampler(energy=1*TeV, theta=[0, pi/20], phi=[0, 2*pi], mass=105.71)
+    pg.sampler.pos = PG.PosSampler(x=[-5, 5], y=[-5, 5], z=-3750.0, t=0.0)
+    acc.addEventAlgo(pg, "AthBeginSeq") # to run *before* G4
+#
+# Only one of these two should be used in a given job
+# (MCEventSelectorCfg for generating events with no input file,
+#  PoolReadCfg when reading generator data from an input file)
+#    
+    acc.merge(McEventSelectorCfg(ConfigFlags))
+    # acc.merge(PoolReadCfg(ConfigFlags))
+#
+#  Output stream configuration
+#
+    acc.merge(OutputStreamCfg(ConfigFlags, 
+                              "HITS", 
+                             ["EventInfo#*",
+                              "McEventCollection#TruthEvent",
+                              "McEventCollection#GEN_EVENT",
+                              "NeutrinoHitCollection#*",
+                              "ScintHitCollection#*",
+                              "FaserSiHitCollection#*",
+                              "CaloHitCollection#*"
+                            ], disableEventTag=True))
+    acc.getEventAlgo("OutputStreamHITS").AcceptAlgs = ["G4FaserAlg"]               # optional
+    acc.getEventAlgo("OutputStreamHITS").WritingTool.ProcessingTag = "StreamHITS"  # required
+#
+#  Here is the configuration of the Geant4 pieces
+#    
+    acc.merge(FaserGeometryCfg(ConfigFlags))
+    acc.merge(G4FaserAlgCfg(ConfigFlags))
+    acc.addService(G4GeometryNotifierSvcCfg(ConfigFlags, ActivateLVNotifier=True))
+#
+# Verbosity
+#
+#    ConfigFlags.dump()
+#    logging.getLogger('forcomps').setLevel(VERBOSE)
+#    acc.foreach_component("*").OutputLevel = VERBOSE
+#    acc.foreach_component("*ClassID*").OutputLevel = INFO
+#    acc.getService("StoreGateSvc").Dump=True
+#    acc.getService("ConditionStore").Dump=True
+#    acc.printConfig()
+    f=open('FaserG4AppCfg_EVNT.pkl','wb')
+    acc.store(f)
+    f.close()
+#
+# Execute and finish
+#
+    sys.exit(int(acc.run(maxEvents=50).isFailure()))
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py
index 249968dfbaa320b99dc70b6a955ce3234dd2412b..99c94f3cd0b4a528bf67abf855162dee9b27970f 100644
--- a/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py
@@ -44,7 +44,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserAlg/test/runGen.py b/Simulation/G4Faser/G4FaserAlg/test/runGen.py
index a53f8aabe62609c3753c609f0b45dcb7a43c7204..216688162a91f3ed561ef60566ea5d0c58ce6e28 100755
--- a/Simulation/G4Faser/G4FaserAlg/test/runGen.py
+++ b/Simulation/G4Faser/G4FaserAlg/test/runGen.py
@@ -43,7 +43,7 @@ if __name__ == "__main__":
     ConfigFlags.Beam.Type = "collisions"
     ConfigFlags.Beam.Energy = 7*TeV                              # Informational, does not affect simulation
     ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Always needed; only the OFLCOND part matters
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 # Workaround for bug/missing flag; unimportant otherwise 
     ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
 # Workaround to avoid problematic ISF code
diff --git a/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py b/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py
index c9d461ceb0edfd01a20732c0c3c686d94bc3e911..21357a02dc4298dc734f0dcbbc70d38f8b52b45b 100644
--- a/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py
+++ b/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py
@@ -7,7 +7,7 @@ DetectorGeometrySvc, G4AtlasSvc, G4GeometryNotifierSvc, PhysicsListSvc=CompFacto
 #
 #  Physics region tools
 #
-from G4FaserTools.G4PhysicsRegionConfigNew import ScintillatorPhysicsRegionToolCfg, TrackerPhysicsRegionToolCfg, EcalPhysicsRegionToolCfg
+from G4FaserTools.G4PhysicsRegionConfigNew import NeutrinoPhysicsRegionToolCfg, ScintillatorPhysicsRegionToolCfg, TrackerPhysicsRegionToolCfg, EcalPhysicsRegionToolCfg
 #
 #  Geometry tools
 #
@@ -15,7 +15,7 @@ from G4FaserTools.G4GeometryToolConfig import MaterialDescriptionToolCfg, G4Atla
 #
 #  Magnetic field tools - start simple
 #
-from G4FaserTools.G4FieldConfigNew import FASERFieldManagerToolCfg, VetoFieldManagerToolCfg, TriggerFieldManagerToolCfg, PreshowerFieldManagerToolCfg
+from G4FaserTools.G4FieldConfigNew import FASERFieldManagerToolCfg, EmulsionFieldManagerToolCfg, VetoFieldManagerToolCfg, TriggerFieldManagerToolCfg, PreshowerFieldManagerToolCfg
 #
 #  Future field managers (?)
 #
@@ -32,6 +32,9 @@ def getFASER_RegionCreatorList(ConfigFlags):
     # if ConfigFlags.Beam.Type == 'cosmics' or ConfigFlags.Sim.CavernBG != 'Signal':
     #     regionCreatorList += [SX1PhysicsRegionToolCfg(ConfigFlags), BedrockPhysicsRegionToolCfg(ConfigFlags), CavernShaftsConcretePhysicsRegionToolCfg(ConfigFlags)]
 
+    if ConfigFlags.Detector.EnableNeutrino:
+        regionCreatorList += [NeutrinoPhysicsRegionToolCfg(ConfigFlags)]
+
     if ConfigFlags.Detector.EnableScintillator:
         regionCreatorList += [ScintillatorPhysicsRegionToolCfg(ConfigFlags)]
 
@@ -56,6 +59,10 @@ def FASER_FieldMgrListCfg(ConfigFlags):
         acc = DipoleFieldManagerToolCfg(ConfigFlags)
         tool  = result.popToolsAndMerge(acc)
         fieldMgrList += [tool]    
+    if ConfigFlags.Detector.GeometryEmulsion:
+        acc = EmulsionFieldManagerToolCfg(ConfigFlags)
+        tool  = result.popToolsAndMerge(acc)
+        fieldMgrList += [tool]
     if ConfigFlags.Detector.GeometryVeto:
         acc = VetoFieldManagerToolCfg(ConfigFlags)
         tool  = result.popToolsAndMerge(acc)
diff --git a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py
index 6f091f84426c8d0f31a128c1ab18d0eaf0fcc9a4..6f3d50a2b91d255fa6ad1af6b9e73ad61ddb12ab 100644
--- a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py
+++ b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py
@@ -7,12 +7,25 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaCommon import CfgMgr
 SensitiveDetectorMasterTool=CompFactory.SensitiveDetectorMasterTool
 
+from EmulsionG4_SD.EmulsionG4_SDToolConfig import EmulsionSensorSDCfg
 from VetoG4_SD.VetoG4_SDToolConfig import VetoSensorSDCfg
 from TriggerG4_SD.TriggerG4_SDToolConfig import TriggerSensorSDCfg
 from PreshowerG4_SD.PreshowerG4_SDToolConfig import PreshowerSensorSDCfg
 from FaserSCT_G4_SD.FaserSCT_G4_SDToolConfig import SctSensorSDCfg
 from EcalG4_SD.EcalG4_SDToolConfig import EcalSensorSDCfg
 
+def generateNeutrinoSensitiveDetectorList(ConfigFlags):
+
+    result = ComponentAccumulator()
+    SensitiveDetectorList=[]
+
+    if ConfigFlags.Detector.EnableEmulsion:
+        accEmulsion,toolEmulsion = EmulsionSensorSDCfg(ConfigFlags)
+        SensitiveDetectorList += [ toolEmulsion ]
+        result.merge(accEmulsion)
+    
+    return result, SensitiveDetectorList #List of tools here now! (CALL IT TOOL LIST?)
+
 def generateScintSensitiveDetectorList(ConfigFlags):
 
     result = ComponentAccumulator()
@@ -70,6 +83,9 @@ def generateSensitiveDetectorList(ConfigFlags):
     SensitiveDetectorList=[]
     # SensitiveDetectorList += generateEnvelopeSensitiveDetectorList(ConfigFlags) # to update
 
+    acc_NeutrinoSensitiveDetector, NeutrinoSensitiveDetectorList = generateNeutrinoSensitiveDetectorList(ConfigFlags)
+    SensitiveDetectorList += NeutrinoSensitiveDetectorList
+
     acc_ScintSensitiveDetector, ScintSensitiveDetectorList = generateScintSensitiveDetectorList(ConfigFlags)
     SensitiveDetectorList += ScintSensitiveDetectorList
 
@@ -79,6 +95,7 @@ def generateSensitiveDetectorList(ConfigFlags):
     acc_CaloSensitiveDetector, CaloSensitiveDetectorList = generateCaloSensitiveDetectorList(ConfigFlags)
     SensitiveDetectorList += CaloSensitiveDetectorList
 
+    result.merge(acc_NeutrinoSensitiveDetector)
     result.merge(acc_ScintSensitiveDetector)
     result.merge(acc_TrackerSensitiveDetector)
     result.merge(acc_CaloSensitiveDetector)
diff --git a/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py
index 81b780f323ab50d28218df68db5c64c68c9efada..33d34f728c6e0b0d7f6b451b5e81464ecf9c5f5b 100644
--- a/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py
+++ b/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py
@@ -52,6 +52,16 @@ def BasicDetectorConstantFieldManagerToolCfg(ConfigFlags, name='BasicDetectorCon
 #
 #  Same numerical values as ATLAS Inner Detector
 #
+
+def EmulsionFieldManagerToolCfg(ConfigFlags, name='EmulsionFieldManager', **kwargs):
+    kwargs.setdefault("LogicalVolumes", ['Emulsion::Emulsion'])
+    #kwargs.setdefault('DeltaChord',         0.00001)
+    kwargs.setdefault('DeltaIntersection',  0.00001)
+    kwargs.setdefault('DeltaOneStep',       0.0001)
+    kwargs.setdefault('MaximumEpsilonStep', 0.001)
+    kwargs.setdefault('MinimumEpsilonStep', 0.00001)
+    return BasicDetectorFieldManagerToolCfg(ConfigFlags, name, **kwargs)
+
 def VetoFieldManagerToolCfg(ConfigFlags, name='VetoFieldManager', **kwargs):
     kwargs.setdefault("LogicalVolumes", ['Veto::Veto'])
     #kwargs.setdefault('DeltaChord',         0.00001)
diff --git a/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py b/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py
index d08fd6f405c3a81b8eaada00cf8e7e01417c4f4a..85b372fa30ee6bdb1b3b5015b7901d5db8792fe6 100644
--- a/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py
+++ b/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py
@@ -1,5 +1,4 @@
 # Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
-from __future__ import print_function
 
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
@@ -9,6 +8,7 @@ GeoDetectorTool=CompFactory.GeoDetectorTool
 BoxEnvelope,MaterialDescriptionTool,G4AtlasDetectorConstructionTool=CompFactory.getComps("BoxEnvelope","MaterialDescriptionTool","G4AtlasDetectorConstructionTool",)
 
 from AthenaCommon.SystemOfUnits import mm
+from EmulsionGeoModel.EmulsionGeoModelConfig import EmulsionGeometryCfg
 from VetoGeoModel.VetoGeoModelConfig import VetoGeometryCfg
 from TriggerGeoModel.TriggerGeoModelConfig import TriggerGeometryCfg
 from PreshowerGeoModel.PreshowerGeoModelConfig import PreshowerGeometryCfg
@@ -21,6 +21,12 @@ from EcalGeoModel.EcalGeoModelConfig import EcalGeometryCfg
 #to still migrate: getCavernWorld, getCavernInfraGeoDetectorTool
 #from ForwardRegionProperties.ForwardRegionPropertiesToolConfig import ForwardRegionPropertiesCfg
 
+def EmulsionGeoDetectorToolCfg(ConfigFlags, name='Emulsion', **kwargs):
+    #set up geometry
+    result=EmulsionGeometryCfg(ConfigFlags)
+    kwargs.setdefault("DetectorName", "Emulsion")
+    return result, GeoDetectorTool(name, **kwargs)
+
 def VetoGeoDetectorToolCfg(ConfigFlags, name='Veto', **kwargs):
     #set up geometry
     result=VetoGeometryCfg(ConfigFlags)
@@ -61,6 +67,11 @@ def generateSubDetectorList(ConfigFlags):
     result = ComponentAccumulator()
     SubDetectorList=[]
 
+    if ConfigFlags.Detector.GeometryEmulsion:
+        accEmulsion, toolEmulsion = EmulsionGeoDetectorToolCfg(ConfigFlags)
+        SubDetectorList += [ toolEmulsion ]
+        result.merge(accEmulsion)
+
     if ConfigFlags.Detector.GeometryVeto:
         accVeto, toolVeto = VetoGeoDetectorToolCfg(ConfigFlags)
         SubDetectorList += [ toolVeto ]
diff --git a/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py
index 15750a0c55b0cca3b4ab2acb6c9b13133b5083b7..c910e2b8003df305b801f437257b0b44cbf937ec 100644
--- a/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py
+++ b/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py
@@ -63,6 +63,16 @@ RegionCreator=CompFactory.RegionCreator
 #     return RegionCreator(name, **kwargs)
 
 #  Values identical to ATLAS SCT
+
+def NeutrinoPhysicsRegionToolCfg(ConfigFlags, name="NeutrinoPhysicsRegionTool", **kwargs):
+    kwargs.setdefault("RegionName", "Neutrino")
+    volumeList = ['Emulsion::FrontFilm', 'Emulsion::BackFilm', 'Emulsion::Baseboard', 'Emulsion::EmulsionStationA']
+    kwargs.setdefault("VolumeList", volumeList)
+    kwargs.setdefault("ElectronCut", 0.01)
+    kwargs.setdefault("PositronCut", 0.01)
+    kwargs.setdefault("GammaCut",    0.01)
+    return RegionCreator(name, **kwargs)
+
 def ScintillatorPhysicsRegionToolCfg(ConfigFlags, name='ScintillatorPhysicsRegionTool', **kwargs):
     kwargs.setdefault("RegionName", 'Scintillator')
     volumeList = ['Veto::Plate' , 'Trigger::Plate', 'Preshower::Plate']
diff --git a/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py b/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py
index 4fe1606af6b15406fef44cfa252db7ea3eb9a6cd..a49c04991034dd011d9066b5b9116d317a1cd042 100644
--- a/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py
+++ b/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py
@@ -156,17 +156,16 @@ def FaserParticleGenericFilterCfg(ConfigFlags, name="ISF_FaserGenericFilter", **
 def FaserDipoleTruthStrategyCfg(ConfigFlags, name="ISF_FaserDipoleTruthStrategy", **kwargs):
     result = ComponentAccumulator()
 
-    import PyUtils.RootUtils as rootUtils
-    ROOT = rootUtils.import_root()
-    import cppyy
+    import ROOT, cppyy
     cppyy.load_library('FaserDetDescrDict')
-    from ROOT.FaserDetDescr import FaserRegion
+    FaserRegion = ROOT.FaserDetDescr.FaserRegion
     #
     # Save truth in Dipole region
     #
-    kwargs.setdefault('Regions', [FaserRegion.fFaserDipole])
-    kwargs.setdefault('ParentMinEkin', 5.0*MeV)
-    kwargs.setdefault('ChildMinEkin', 5.0*MeV)
+    kwargs.setdefault('Regions', [FaserRegion.fFaserDipole,
+                                  FaserRegion.fFaserNeutrino])
+    kwargs.setdefault('ParentMinEkin', 1000.0*MeV)
+    kwargs.setdefault('ChildMinEkin', 1000.0*MeV)
     result.setPrivateTools(ISF__FaserTruthStrategy(name, **kwargs))
     return result
 
@@ -174,16 +173,14 @@ def FaserDipoleTruthStrategyCfg(ConfigFlags, name="ISF_FaserDipoleTruthStrategy"
 def FaserTruthStrategyCfg(ConfigFlags, name="ISF_FaserTruthStrategy", **kwargs):
     result = ComponentAccumulator()
 
-    import PyUtils.RootUtils as rootUtils
-    ROOT = rootUtils.import_root()
-
-    import cppyy
+    import ROOT, cppyy
     cppyy.load_library('FaserDetDescrDict')
-    from ROOT.FaserDetDescr import FaserRegion
+    FaserRegion = ROOT.FaserDetDescr.FaserRegion
     #
     # Save truth in all regions except Dipole
     #
-    kwargs.setdefault('Regions', [FaserRegion.fFaserNeutrino,
+    kwargs.setdefault('Regions', [
+                                #   FaserRegion.fFaserNeutrino,
                                   FaserRegion.fFaserScintillator,
                                   FaserRegion.fFaserTracker,
                                 #   FaserRegion.fFaserDipole,
diff --git a/Simulation/README.md b/Simulation/README.md
index 9ad2f25f5f726371c740554bf2c66d79e16623d2..350d7ab9beb3eb94d7683c94d210d2e11d1fa90c 100644
--- a/Simulation/README.md
+++ b/Simulation/README.md
@@ -8,3 +8,8 @@ To generate Calypso MC data from an installation (run) directory:
 3) runG4.py
 
 (setup.sh will put the script in your path)
+
+To generate events with the emulsion detector, use
+
+3a) runG4FaserNu.py
+
diff --git a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
index 8ab67fbffbae4d7d363d952bce9ee27166a00136..a92e78dc3d2c3aa62464256aaeab5c38caa0072a 100644
--- a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
+++ b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
@@ -99,6 +99,7 @@ StatusCode TrackerAlignDBTool::initialize()
 
     for (int i=0;i<3;++i) chan[i]=100*i;
 
+    int minStation = 3;
     std::string man_name;
     for (const TrackerDD::SiDetectorElement* element : *(m_sctman->getDetectorElementCollection())) 
     {
@@ -111,6 +112,7 @@ StatusCode TrackerAlignDBTool::initialize()
               std::string level[3];
               for (int i=TransfLevel_low; i<3; ++i) 
               {  
+                minStation = std::min(station, minStation);
                 level[i]=dirkey(station, layer, 1+i, phi);
                 // add this to list if not seen already
                 std::vector<std::string>::const_iterator ix =
@@ -129,7 +131,7 @@ StatusCode TrackerAlignDBTool::initialize()
           }
         }
       }
-
+    m_ift =(minStation == 0);
     ATH_CHECK(m_outputTool.retrieve());
 
   if (msgLvl(MSG::DEBUG)) 
@@ -244,6 +246,12 @@ StatusCode TrackerAlignDBTool::createDB() const
     {
         Amg::Transform3D globshift;
         globshift.setIdentity();
+        // Tracker interface
+        if (m_ift)
+        {
+            ident1 = m_sctid->wafer_id(0, 0, 0, 0, 0);
+            pat->add(ident1, Amg::EigenTransformToCLHEP(globshift));
+        }
         // Tracker upstream
         ident1 = m_sctid->wafer_id(1, 0, 0, 0, 0);
         pat->add(ident1, Amg::EigenTransformToCLHEP(globshift));
@@ -651,7 +659,7 @@ StatusCode TrackerAlignDBTool::outputObjs() const {
   ATH_CHECK(m_outputTool->streamObjects(typekeys));
 
   // commit output
-  ATH_CHECK(m_outputTool->commitOutput());
+  ATH_CHECK(m_outputTool->commitOutput(true));
   ATH_MSG_DEBUG( "Written " << typekeys.size() << " objects to stream " << m_outputTool);
   return StatusCode::SUCCESS;
 }
diff --git a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h
index 47d7e8ee96ce38bae26ea21daa6209449dd5a000..9ff680075934e2702c4bb8a3aa3902eeaf030a65 100644
--- a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h
+++ b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h
@@ -185,6 +185,7 @@ class TrackerAlignDBTool: virtual public ITrackerAlignDBTool, public AthAlgTool
   const AlignableTransform* cgetTransPtr(const std::string key) const;
   bool m_dynamicDB;
   bool m_forceUserDBConfig;
+  bool m_ift {false};
 
   mutable  ToolHandle<IAthenaOutputStreamTool> m_outputTool { this, "OutputTool", "AthenaOutputStreamTool/CondStream1"} ;
 
diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/SCT_Conditions.py b/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/SCT_Conditions.py
index 7e4a9dca06ba7ddecc1e682e72d884f75810e673..899f0037a6acca662e5c640946e504bdafaacec2 100644
--- a/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/SCT_Conditions.py
+++ b/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/SCT_Conditions.py
@@ -9,7 +9,19 @@ sctChannels = [
        '2348810240', '2350907392', '2353004544', '2355101696', '2357198848', '2359296000', '2361393152', '2363490304', '2365587456', '2367684608', '2369781760', '2371878912', '2373976064', '2376073216', '2378170368', '2380267520', '2415919104', '2418016256', '2420113408', '2422210560',
        '2424307712', '2426404864', '2428502016', '2430599168', '2432696320', '2434793472', '2436890624', '2438987776', '2441084928', '2443182080', '2445279232', '2447376384', '2449473536', '2451570688', '2453667840', '2455764992', '2457862144', '2459959296', '2462056448', '2464153600',
        '2466250752', '2468347904', '2470445056', '2472542208', '2474639360', '2476736512', '2478833664', '2480930816', '2483027968', '2485125120', '2487222272', '2489319424', '2491416576', '2493513728', '2495610880', '2497708032', '2499805184', '2501902336', '2503999488', '2506096640',
-       '2508193792', '2510290944', '2512388096', '2514485248']
+       '2508193792', '2510290944', '2512388096', '2514485248' ]
+
+iftChannels = [
+       '2147483648', '2149580800', '2151677952', '2153775104', '2155872256', '2157969408', '2160066560', '2162163712', '2164260864', '2166358016', '2168455168', '2170552320', '2172649472', '2174746624', '2176843776', '2178940928', '2181038080', '2183135232', '2185232384', '2187329536',
+       '2189426688', '2191523840', '2193620992', '2195718144', '2197815296', '2199912448', '2202009600', '2204106752', '2206203904', '2208301056', '2210398208', '2212495360', '2214592512', '2216689664', '2218786816', '2220883968', '2222981120', '2225078272', '2227175424', '2229272576',
+       '2231369728', '2233466880', '2235564032', '2237661184', '2239758336', '2241855488', '2243952640', '2246049792', '2281701376', '2283798528', '2285895680', '2287992832', '2290089984', '2292187136', '2294284288', '2296381440', '2298478592', '2300575744', '2302672896', '2304770048',
+       '2306867200', '2308964352', '2311061504', '2313158656', '2315255808', '2317352960', '2319450112', '2321547264', '2323644416', '2325741568', '2327838720', '2329935872', '2332033024', '2334130176', '2336227328', '2338324480', '2340421632', '2342518784', '2344615936', '2346713088',
+       '2348810240', '2350907392', '2353004544', '2355101696', '2357198848', '2359296000', '2361393152', '2363490304', '2365587456', '2367684608', '2369781760', '2371878912', '2373976064', '2376073216', '2378170368', '2380267520', '2415919104', '2418016256', '2420113408', '2422210560',
+       '2424307712', '2426404864', '2428502016', '2430599168', '2432696320', '2434793472', '2436890624', '2438987776', '2441084928', '2443182080', '2445279232', '2447376384', '2449473536', '2451570688', '2453667840', '2455764992', '2457862144', '2459959296', '2462056448', '2464153600',
+       '2466250752', '2468347904', '2470445056', '2472542208', '2474639360', '2476736512', '2478833664', '2480930816', '2483027968', '2485125120', '2487222272', '2489319424', '2491416576', '2493513728', '2495610880', '2497708032', '2499805184', '2501902336', '2503999488', '2506096640',
+       '2508193792', '2510290944', '2512388096', '2514485248', '2550136832', '2552233984', '2554331136', '2556428288', '2558525440', '2560622592', '2562719744', '2564816896', '2566914048', '2569011200', '2571108352', '2573205504', '2575302656', '2577399808', '2579496960', '2581594112',
+       '2583691264', '2585788416', '2587885568', '2589982720', '2592079872', '2594177024', '2596274176', '2598371328', '2600468480', '2602565632', '2604662784', '2606759936', '2608857088', '2610954240', '2613051392', '2615148544', '2617245696', '2619342848', '2621440000', '2623537152',
+       '2625634304', '2627731456', '2629828608', '2631925760', '2634022912', '2636120064', '2638217216', '2640314368', '2642411520', '2644508672', '2646605824', '2648702976' ]
 
 
 description = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>'
@@ -25,6 +37,37 @@ print('recreating database')
 dbSvc.dropDatabase( connectString )
 db = dbSvc.createDatabase( connectString )
 
+tracker = db.createFolderSet("/Tracker")
+# tracker_align = db.createFolderSet("/Tracker/Align")
+sct = db.createFolderSet("/SCT")
+sct_dcs = db.createFolderSet("/SCT/DCS")
+sct_daq = db.createFolderSet("/SCT/DAQ")
+sct_daq_calibration = db.createFolderSet("/SCT/DAQ/Calibration")
+
+# tracker_align.createTagRelation("TRACKER-01", "TRACKER-ALIGN-01")
+tracker.createTagRelation("OFLCOND-FASER-01","TRACKER-01")
+sct_daq_calibration.createTagRelation("SCT-DAQ-01", "SCT-DAQ-Calibration-01")
+sct_daq.createTagRelation("SCT-01", "SCT-DAQ-01")
+sct_dcs.createTagRelation("SCT-01", "SCT-DCS-01")
+sct.createTagRelation("OFLCOND-FASER-01", "SCT-01")
+
+# tracker_align.createTagRelation("TRACKER-02", "TRACKER-ALIGN-02")
+tracker.createTagRelation("OFLCOND-FASER-02","TRACKER-02")
+sct_daq_calibration.createTagRelation("SCT-DAQ-02", "SCT-DAQ-Calibration-02")
+sct_daq.createTagRelation("SCT-02", "SCT-DAQ-02")
+sct_dcs.createTagRelation("SCT-02", "SCT-DCS-02")
+sct.createTagRelation("OFLCOND-FASER-02", "SCT-02")
+
+glob = db.createFolderSet("/GLOBAL")
+glob_bfield = db.createFolderSet("/GLOBAL/BField")
+
+glob_bfield.createTagRelation("GLOBAL-01", "GLOBAL-BField-01")
+glob.createTagRelation("OFLCOND-FASER-01", "GLOBAL-01")
+
+glob_bfield.createTagRelation("GLOBAL-02", "GLOBAL-BField-02")
+glob.createTagRelation("OFLCOND-FASER-02", "GLOBAL-02")
+
+
 gainSpec = cool.RecordSpecification()
 gainSpec.extend( 'serialNumber'          , cool.StorageType.UInt63 )
 gainSpec.extend( 'runNumber'             , cool.StorageType.UInt32 )
@@ -47,11 +90,12 @@ gainRecord[ 'offsetRMSByChip' ] = '1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75
 gainRecord[ 'noiseByChip'     ] = '1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0'
 gainRecord[ 'noiseRMSByChip'  ] = '45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0'
 
-gainFolderSpec = cool.FolderSpecification(gainSpec)
+gainFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, gainSpec)
 gainFolder = db.createFolder('/SCT/DAQ/Calibration/ChipGain', gainFolderSpec, description, True)
 
 for channel in sctChannels:
-    gainFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, gainRecord, int(channel) )
+    gainFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, gainRecord, int(channel), "SCT-DAQ-Calibration-ChipGain-01", True )
+gainFolder.createTagRelation("SCT-DAQ-Calibration-01", "SCT-DAQ-Calibration-ChipGain-01")
 
 noiseSpec = cool.RecordSpecification()
 noiseSpec.extend( 'serialNumber'          , cool.StorageType.UInt63 )
@@ -70,11 +114,12 @@ noiseRecord[ 'offsetByChip'       ] = '60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0 6
 noiseRecord[ 'occupancyByChip'    ] = '3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05'
 noiseRecord[ 'occupancyRMSByChip' ] = '2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05'
 
-noiseFolderSpec = cool.FolderSpecification(noiseSpec)
-noiseFolder = db.createFolder('/SCT/DAQ/Calibration/ChipNoise', noiseFolderSpec, description, True)
+noiseFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, noiseSpec)
+noiseFolder = db.createFolder('/SCT/DAQ/Calibration/ChipNoise', noiseFolderSpec, description, True )
 
 for channel in sctChannels:
-    noiseFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, noiseRecord, int(channel) )
+    noiseFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, noiseRecord, int(channel), "SCT-DAQ-Calibration-Noise-01", True )
+noiseFolder.createTagRelation("SCT-DAQ-Calibration-01", "SCT-DAQ-Calibration-Noise-01")
 
 chanstatSpec = cool.RecordSpecification()
 chanstatSpec.extend( 'LVCHSTAT_RECV' , cool.StorageType.Int32 )
@@ -84,11 +129,12 @@ chanstatRecord = cool.Record(chanstatSpec)
 chanstatRecord[ 'LVCHSTAT_RECV' ] = 209
 chanstatRecord[ 'STATE' ] = 17
 
-chanstatFolderSpec = cool.FolderSpecification(chanstatSpec)
-chanstatFolder = db.createFolder('/SCT/DCS/CHANSTAT', chanstatFolderSpec, descriptionDCS, True)
+chanstatFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, chanstatSpec)
+chanstatFolder = db.createFolder('/SCT/DCS/CHANSTAT', chanstatFolderSpec, descriptionDCS, True )
 
 for channel in sctChannels:
-    chanstatFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, chanstatRecord, int(channel) )
+    chanstatFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, chanstatRecord, int(channel), "SCT-DCS-Status-01", True )
+chanstatFolder.createTagRelation("SCT-DCS-01", "SCT-DCS-Status-01")
 
 hvSpec = cool.RecordSpecification()
 hvSpec.extend( 'HVCHVOLT_RECV' , cool.StorageType.Float )
@@ -98,11 +144,12 @@ hvRecord = cool.Record(hvSpec)
 hvRecord[ 'HVCHVOLT_RECV' ] = 150.0
 hvRecord[ 'HVCHCURR_RECV' ] = 10.0
 
-hvFolderSpec = cool.FolderSpecification(hvSpec)
-hvFolder = db.createFolder('/SCT/DCS/HV', hvFolderSpec, descriptionDCS, True)
+hvFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, hvSpec)
+hvFolder = db.createFolder('/SCT/DCS/HV', hvFolderSpec, descriptionDCS, True )
 
 for channel in sctChannels:
-    hvFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, hvRecord, int(channel) )
+    hvFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, hvRecord, int(channel), "SCT-DCS-HV-01", True )
+hvFolder.createTagRelation("SCT-DCS-01", "SCT-DCS-HV-01")
 
 modtempSpec = cool.RecordSpecification()
 modtempSpec.extend( 'MOCH_TM0_RECV' , cool.StorageType.Float )
@@ -112,11 +159,13 @@ modtempRecord = cool.Record(modtempSpec)
 modtempRecord[ 'MOCH_TM0_RECV' ] = 7.0
 modtempRecord[ 'MOCH_TM1_RECV' ] = 7.0
 
-modtempFolderSpec = cool.FolderSpecification(modtempSpec)
-modtempFolder = db.createFolder('/SCT/DCS/MODTEMP', modtempFolderSpec, descriptionDCS, True)
+modtempFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, modtempSpec)
+modtempFolder = db.createFolder('/SCT/DCS/MODTEMP', modtempFolderSpec, descriptionDCS, True )
 
 for channel in sctChannels:
-    modtempFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, modtempRecord, int(channel) )
+    modtempFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, modtempRecord, int(channel), "SCT-DCS-Temp-01", True )
+modtempFolder.createTagRelation("SCT-DCS-01", "SCT-DCS-Temp-01")
+
 
 mapSpec = cool.RecordSpecification()
 mapSpec.extend( 'FieldType', cool.StorageType.String4k )
@@ -126,10 +175,12 @@ mapRecord = cool.Record(mapSpec)
 mapRecord['FieldType'] = "GlobalMap"
 mapRecord['MapFileName'] = "file:MagneticFieldMaps/FaserFieldTable.root"
 
-mapFolderSpec = cool.FolderSpecification(mapSpec)
-mapFolder = db.createFolder('/GLOBAL/BField/Maps', mapFolderSpec, descriptionDCS, True)
+mapFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, mapSpec)
+mapFolder = db.createFolder('/GLOBAL/BField/Maps', mapFolderSpec, descriptionDCS, True )
+
+mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1, "GLOBAL-BField-Maps-01", True )
+mapFolder.createTagRelation("GLOBAL-BField-01", "GLOBAL-BField-Maps-01")
 
-mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1 )
 
 scaleSpec = cool.RecordSpecification()
 scaleSpec.extend( 'value', cool.StorageType.Float )
@@ -137,11 +188,141 @@ scaleSpec.extend( 'value', cool.StorageType.Float )
 scaleRecord = cool.Record(scaleSpec)
 scaleRecord['value'] = 1.0
 
-scaleFolderSpec = cool.FolderSpecification(scaleSpec)
-scaleFolder = db.createFolder('/GLOBAL/BField/Scales', scaleFolderSpec, descriptionDCS, True)
+scaleFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, scaleSpec)
+scaleFolder = db.createFolder('/GLOBAL/BField/Scales', scaleFolderSpec, descriptionDCS, True )
 
 # Channel names don't seem to be handled properly by Athena
 scaleFolder.createChannel( 1, "Dipole_Scale" )
-scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1 )
+scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1, "GLOBAL-BField-Scale-01", True )
+scaleFolder.createTagRelation("GLOBAL-BField-01", "GLOBAL-BField-Scale-01")
+
+# Start of IFT
+
+gainSpec = cool.RecordSpecification()
+gainSpec.extend( 'serialNumber'          , cool.StorageType.UInt63 )
+gainSpec.extend( 'runNumber'             , cool.StorageType.UInt32 )
+gainSpec.extend( 'scanNumber'            , cool.StorageType.UInt32 )
+gainSpec.extend( 'gainByChip'            , cool.StorageType.String4k )
+gainSpec.extend( 'gainRMSByChip'         , cool.StorageType.String4k )
+gainSpec.extend( 'offsetByChip'          , cool.StorageType.String4k )
+gainSpec.extend( 'offsetRMSByChip'       , cool.StorageType.String4k )
+gainSpec.extend( 'noiseByChip'           , cool.StorageType.String4k )
+gainSpec.extend( 'noiseRMSByChip'        , cool.StorageType.String4k )
+
+gainRecord = cool.Record(gainSpec)
+gainRecord[ 'serialNumber'    ] = 0
+gainRecord[ 'runNumber'       ] = 0
+gainRecord[ 'scanNumber'      ] = 0
+gainRecord[ 'gainByChip'      ] = '52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0'
+gainRecord[ 'gainRMSByChip'   ] = '1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25'
+gainRecord[ 'offsetByChip'    ] = '45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0'
+gainRecord[ 'offsetRMSByChip' ] = '1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75 1.75'
+gainRecord[ 'noiseByChip'     ] = '1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0 1600.0'
+gainRecord[ 'noiseRMSByChip'  ] = '45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0 45.0'
+
+# gainFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, gainSpec)
+# gainFolder = db.createFolder('/SCT/DAQ/Calibration/ChipGain', gainFolderSpec, description, True)
+
+for channel in iftChannels:
+    gainFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, gainRecord, int(channel), "SCT-DAQ-Calibration-ChipGain-02", True )
+gainFolder.createTagRelation("SCT-DAQ-Calibration-02", "SCT-DAQ-Calibration-ChipGain-02")
+
+noiseSpec = cool.RecordSpecification()
+noiseSpec.extend( 'serialNumber'          , cool.StorageType.UInt63 )
+noiseSpec.extend( 'runNumber'             , cool.StorageType.UInt32 )
+noiseSpec.extend( 'scanNumber'            , cool.StorageType.UInt32 )
+noiseSpec.extend( 'offsetByChip'          , cool.StorageType.String4k )
+noiseSpec.extend( 'occupancyByChip'       , cool.StorageType.String4k )
+noiseSpec.extend( 'occupancyRMSByChip'    , cool.StorageType.String4k )
+noiseSpec.extend( 'noiseByChip'           , cool.StorageType.String4k )
+
+noiseRecord = cool.Record(noiseSpec)
+noiseRecord[ 'serialNumber'       ] = 0
+noiseRecord[ 'runNumber'          ] = 0
+noiseRecord[ 'scanNumber'         ] = 0
+noiseRecord[ 'offsetByChip'       ] = '60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0 60.0'
+noiseRecord[ 'occupancyByChip'    ] = '3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05 3.50e-05'
+noiseRecord[ 'occupancyRMSByChip' ] = '2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05 2.50e-05'
+
+# noiseFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, noiseSpec)
+# noiseFolder = db.createFolder('/SCT/DAQ/Calibration/ChipNoise', noiseFolderSpec, description, True )
+
+for channel in iftChannels:
+    noiseFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, noiseRecord, int(channel), "SCT-DAQ-Calibration-Noise-02", True )
+noiseFolder.createTagRelation("SCT-DAQ-Calibration-02", "SCT-DAQ-Calibration-Noise-02")
+
+chanstatSpec = cool.RecordSpecification()
+chanstatSpec.extend( 'LVCHSTAT_RECV' , cool.StorageType.Int32 )
+chanstatSpec.extend( 'STATE'         , cool.StorageType.UInt32 )
+
+chanstatRecord = cool.Record(chanstatSpec)
+chanstatRecord[ 'LVCHSTAT_RECV' ] = 209
+chanstatRecord[ 'STATE' ] = 17
+
+# chanstatFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, chanstatSpec)
+# chanstatFolder = db.createFolder('/SCT/DCS/CHANSTAT', chanstatFolderSpec, descriptionDCS, True )
+
+for channel in iftChannels:
+    chanstatFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, chanstatRecord, int(channel), "SCT-DCS-Status-02", True )
+chanstatFolder.createTagRelation("SCT-DCS-02", "SCT-DCS-Status-02")
+
+hvSpec = cool.RecordSpecification()
+hvSpec.extend( 'HVCHVOLT_RECV' , cool.StorageType.Float )
+hvSpec.extend( 'HVCHCURR_RECV' , cool.StorageType.Float )
+
+hvRecord = cool.Record(hvSpec)
+hvRecord[ 'HVCHVOLT_RECV' ] = 150.0
+hvRecord[ 'HVCHCURR_RECV' ] = 10.0
+
+# hvFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, hvSpec)
+# hvFolder = db.createFolder('/SCT/DCS/HV', hvFolderSpec, descriptionDCS, True )
+
+for channel in iftChannels:
+    hvFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, hvRecord, int(channel), "SCT-DCS-HV-02", True )
+hvFolder.createTagRelation("SCT-DCS-02", "SCT-DCS-HV-02")
+
+modtempSpec = cool.RecordSpecification()
+modtempSpec.extend( 'MOCH_TM0_RECV' , cool.StorageType.Float )
+modtempSpec.extend( 'MOCH_TM1_RECV' , cool.StorageType.Float )
+
+modtempRecord = cool.Record(modtempSpec)
+modtempRecord[ 'MOCH_TM0_RECV' ] = 7.0
+modtempRecord[ 'MOCH_TM1_RECV' ] = 7.0
+
+# modtempFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, modtempSpec)
+# modtempFolder = db.createFolder('/SCT/DCS/MODTEMP', modtempFolderSpec, descriptionDCS, True )
+
+for channel in iftChannels:
+    modtempFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, modtempRecord, int(channel), "SCT-DCS-Temp-02", True )
+modtempFolder.createTagRelation("SCT-DCS-02", "SCT-DCS-Temp-02")
+
+
+mapSpec = cool.RecordSpecification()
+mapSpec.extend( 'FieldType', cool.StorageType.String4k )
+mapSpec.extend( 'MapFileName', cool.StorageType.String4k )
+
+mapRecord = cool.Record(mapSpec)
+mapRecord['FieldType'] = "GlobalMap"
+mapRecord['MapFileName'] = "file:MagneticFieldMaps/FaserFieldTable.root"
+
+# mapFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, mapSpec)
+# mapFolder = db.createFolder('/GLOBAL/BField/Maps', mapFolderSpec, descriptionDCS, True )
+
+mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1, "GLOBAL-BField-Maps-02", True )
+mapFolder.createTagRelation("GLOBAL-BField-02", "GLOBAL-BField-Maps-02")
+
+scaleSpec = cool.RecordSpecification()
+scaleSpec.extend( 'value', cool.StorageType.Float )
+
+scaleRecord = cool.Record(scaleSpec)
+scaleRecord['value'] = 1.0
+
+# scaleFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, scaleSpec)
+# scaleFolder = db.createFolder('/GLOBAL/BField/Scales', scaleFolderSpec, descriptionDCS, True )
+
+# Channel names don't seem to be handled properly by Athena
+# scaleFolder.createChannel( 1, "Dipole_Scale" )
+scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1, "GLOBAL-BField-Scale-02", True )
+scaleFolder.createTagRelation("GLOBAL-BField-02", "GLOBAL-BField-Scale-02")
 
 db.closeDatabase()
diff --git a/Tracker/TrackerDetDescr/DipoleGeoModel/test/DipoleGMConfig_test.py b/Tracker/TrackerDetDescr/DipoleGeoModel/test/DipoleGMConfig_test.py
index e9b1cf75813c29ae1fde82433c067df18510b27e..f893af721a7c3878f920bd329e070de09d6fc714 100755
--- a/Tracker/TrackerDetDescr/DipoleGeoModel/test/DipoleGMConfig_test.py
+++ b/Tracker/TrackerDetDescr/DipoleGeoModel/test/DipoleGMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag         = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic  = False
     ConfigFlags.lock()
 
diff --git a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/test/FaserSCT_GMConfig_test.py b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/test/FaserSCT_GMConfig_test.py
index 9349cdf70ea06476605c181ceb471fc725abad4d..75eb5c42190897a29e73a01ebd87499bb3bc3af4 100755
--- a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/test/FaserSCT_GMConfig_test.py
+++ b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/test/FaserSCT_GMConfig_test.py
@@ -10,7 +10,7 @@ if __name__ == "__main__":
     from AthenaConfiguration.TestDefaults import defaultTestFiles
 
     ConfigFlags.Input.Files = defaultTestFiles.HITS
-    ConfigFlags.IOVDb.GlobalTag         = "OFLCOND-XXXX-XXX-XX"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
     ConfigFlags.GeoModel.Align.Dynamic  = False
     ConfigFlags.lock()
 
diff --git a/Tracker/TrackerDetDescr/TrackerIdDictFiles/data/IdDictTracker_Interface.xml b/Tracker/TrackerDetDescr/TrackerIdDictFiles/data/IdDictInterface.xml
similarity index 100%
rename from Tracker/TrackerDetDescr/TrackerIdDictFiles/data/IdDictTracker_Interface.xml
rename to Tracker/TrackerDetDescr/TrackerIdDictFiles/data/IdDictInterface.xml
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/test/FaserSCT_DigitizationDbg.py b/Tracker/TrackerDigitization/FaserSCT_Digitization/test/FaserSCT_DigitizationDbg.py
index 33389e158e45283bf2813dd6752547a570e0d7ed..801349de0f4acc1b3494dccd8b3e509cc826168c 100644
--- a/Tracker/TrackerDigitization/FaserSCT_Digitization/test/FaserSCT_DigitizationDbg.py
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/test/FaserSCT_DigitizationDbg.py
@@ -24,7 +24,8 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.HITS.pool.root']
 ConfigFlags.Output.RDOFileName = "my.RDO.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.Beam.NumberOfCollisions = 0.
 
diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/test/SCT_DigitizationConfigNew_test.py b/Tracker/TrackerDigitization/FaserSCT_Digitization/test/SCT_DigitizationConfigNew_test.py
index b880cc0700601b2e9e95eb8e584c9250e1138856..36bcd84dab476ada60845222e6ffc1790692ccb5 100644
--- a/Tracker/TrackerDigitization/FaserSCT_Digitization/test/SCT_DigitizationConfigNew_test.py
+++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/test/SCT_DigitizationConfigNew_test.py
@@ -19,7 +19,7 @@ log.setLevel(DEBUG)
 Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = defaultTestFiles.HITS
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.lock()
 # Construct our accumulator to run
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
index 1859efa6cb0a1ee5e1057149ade0bcbfae9851d2..48197207d0c1b321e658b74ddb2d40d74ee244dd 100644
--- a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
@@ -50,7 +50,7 @@ if __name__ == "__main__":
   # Configure
   ConfigFlags.Input.Files = ['my.RDO.pool.root']
   ConfigFlags.Output.ESDFileName = "mySeeds.ESD.pool.root"
-  ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+  ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
   ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
   ConfigFlags.Input.ProjectName = "data20"                     # Needed to bypass autoconfig
   ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
diff --git a/Tracker/TrackerRecAlgs/TrackerClusterFit/test/TrackerClusterFitDbg.py b/Tracker/TrackerRecAlgs/TrackerClusterFit/test/TrackerClusterFitDbg.py
index 0f9c27faf83191276126e18859cf8177de9f096c..308b5ff3015435a4671d7410f5b97fae54be7dd5 100644
--- a/Tracker/TrackerRecAlgs/TrackerClusterFit/test/TrackerClusterFitDbg.py
+++ b/Tracker/TrackerRecAlgs/TrackerClusterFit/test/TrackerClusterFitDbg.py
@@ -93,7 +93,7 @@ ConfigFlags.Input.Files = [
 ]
 #ConfigFlags.Output.ESDFileName = "run608.ESD.pool.root"
 ConfigFlags.Output.ESDFileName = "run001332.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
 ConfigFlags.Input.ProjectName = "data21"                     # Needed to bypass autoconfig
 ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
diff --git a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbg.py b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbg.py
index ee9db620035f63681467eee2bed03ec27a45d734..26f6dfc5b1709c135fa61dab1ac619c0eb98ee0d 100644
--- a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbg.py
+++ b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbg.py
@@ -24,7 +24,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "myClusters.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.Beam.NumberOfCollisions = 0.
 
diff --git a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbgCosmics.py b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbgCosmics.py
index cbc4beec7a8e8729d102642080e4751f913e5da1..3cf2d8573ddd0b7dd72a0406d19825f9593a6ccd 100644
--- a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbgCosmics.py
+++ b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/test/FaserSCT_ClusterizationDbgCosmics.py
@@ -24,7 +24,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "myClusters.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"          # Needed to bypass autoconfig, only the "OFLCOND" matters at the moment
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
 ConfigFlags.Input.ProjectName = "data20"                     # Needed to bypass autoconfig
 ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
diff --git a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/StatisticsDbg.py b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/StatisticsDbg.py
index 1fb37bb3965ae740a7adc18dee808aa961d1418d..55d4ee20812ac529068a8f233524a18a035ab3c8 100644
--- a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/StatisticsDbg.py
+++ b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/StatisticsDbg.py
@@ -25,7 +25,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "mySpacePoints.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.Beam.NumberOfCollisions = 0.
 
diff --git a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbg.py b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbg.py
index b7ac51e000975692b8a1453979f9c8e5d5564f84..a3d520eed74ad922e48bf91b618b57c1e495ffba 100644
--- a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbg.py
+++ b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbg.py
@@ -25,7 +25,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "mySpacePoints.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.Beam.NumberOfCollisions = 0.
 
diff --git a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbgCosmics.py b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbgCosmics.py
index a02500c2788c607ce15777ed8c39a121e5dbeb2d..a197c227f2885c6b42721cc78a522941fcb317d1 100644
--- a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbgCosmics.py
+++ b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/test/TrackerSpacePointFormationDbgCosmics.py
@@ -25,7 +25,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "mySpacePoints.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
 ConfigFlags.Input.ProjectName = "data20"                     # Needed to bypass autoconfig
 ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
diff --git a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/test/TruthSeededTrackFinderDbg.py b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/test/TruthSeededTrackFinderDbg.py
index cd284784bddc75d12d48b795c34ab8e2947437a2..9eea2476dec0e8e1bca68463d41a3cecc878a3df 100644
--- a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/test/TruthSeededTrackFinderDbg.py
+++ b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/test/TruthSeededTrackFinderDbg.py
@@ -26,7 +26,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "mySeeds.ESD.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 #ConfigFlags.Concurrency.NumThreads = 1
 ConfigFlags.Beam.NumberOfCollisions = 0.
diff --git a/Tracker/TrackerSimEvent/src/FaserSiHitIdHelper.cxx b/Tracker/TrackerSimEvent/src/FaserSiHitIdHelper.cxx
index 149466cf711df123da973a8f4876892df306fbee..204399b88800b00fef75d91fc8d6f7b37c52af54 100644
--- a/Tracker/TrackerSimEvent/src/FaserSiHitIdHelper.cxx
+++ b/Tracker/TrackerSimEvent/src/FaserSiHitIdHelper.cxx
@@ -46,8 +46,8 @@ void FaserSiHitIdHelper::Initialize() {
     if (detStore->retrieve(pix, "FaserSCT_ID").isFailure()) { pix = 0; }
   }
 
-  InitializeField("Station", 1, 3);
-  InitializeField("Plane", 0, 3);
+  InitializeField("Station", 0, 3);
+  InitializeField("Plane", 0, 2);
   InitializeField("Row", 0, 4);
   InitializeField("Module", -1, 1);
   InitializeField("Sensor", 0, 1);
diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py
index 40e7eb6922fd60597c2f42d4d73ce9555dce2ae6..23270e4e9eeec0f6ddac95645749d3de1bf714c0 100644
--- a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py
+++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py
@@ -61,7 +61,7 @@ if "__main__" == __name__:
   ConfigFlags.Input.isMC             = True
   ConfigFlags.Beam.Type = "collisions" 
   ConfigFlags.GeoModel.FaserVersion  = "FASER-01"
-  ConfigFlags.IOVDb.GlobalTag        = "OFLCOND-XXXX-XXX-XX"
+  ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
   ConfigFlags.TrackingGeometry.MaterialSource = "geometry-maps.json"
   ConfigFlags.Concurrency.NumThreads = 1
   ConfigFlags.Concurrency.NumConcurrentEvents = 1
diff --git a/Tracking/Acts/FaserActsGeometry/test/FaserActsExtrapolationAlg.py b/Tracking/Acts/FaserActsGeometry/test/FaserActsExtrapolationAlg.py
index 71be0017e3473e5ba7778b1a1a2c243bf50552ad..de8c40acb735dea94e0b159366ec7c2fc1238c4f 100644
--- a/Tracking/Acts/FaserActsGeometry/test/FaserActsExtrapolationAlg.py
+++ b/Tracking/Acts/FaserActsGeometry/test/FaserActsExtrapolationAlg.py
@@ -20,7 +20,7 @@ Configurable.configurableRun3Behavior = True
 #ConfigFlags.Input.Files = ["/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/esd/100evts10lumiblocks.ESD.root"]
 #ConfigFlags.Output.RDOFileName = "myRDO_sp.pool.root"
 ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
 # Workaround for bug/missing flag; unimportant otherwise 
 ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
diff --git a/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py b/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py
index 1124fd8f2695ae9a388676e9ce5bb688c2462cf5..899134b324e2975bb78e33361b6ea974a5aa68f7 100644
--- a/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py
+++ b/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py
@@ -19,7 +19,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ["/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/esd/100evts10lumiblocks.ESD.root"]
 #ConfigFlags.Output.RDOFileName = "myRDO_sp.pool.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.FaserVersion = "FASER-01"               # Always needed
 # Workaround for bug/missing flag; unimportant otherwise 
 ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py b/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py
index a0f8db8f57a01fb5d5f3cfe12ad42da4ab6d5cfa..06975170f670f0fe8dec65b9a2d608aea6fc4c36 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py
@@ -22,7 +22,7 @@ Configurable.configurableRun3Behavior = True
 # Configure
 ConfigFlags.Input.Files = ['my.RDO.pool.root']
 ConfigFlags.Output.ESDFileName = "tmp.root"
-ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"             # Always needed; must match FaserVersion
 ConfigFlags.GeoModel.Align.Dynamic = False
 ConfigFlags.Beam.NumberOfCollisions = 0.
 #ConfigFlags.Concurrency.NumThreads = 1
diff --git a/Tracking/TrkEventCnv/TrkEventCnvTools/TrkEventCnvTools/ATLAS_CHECK_THREAD_SAFETY b/Tracking/TrkEventCnv/TrkEventCnvTools/TrkEventCnvTools/ATLAS_CHECK_THREAD_SAFETY
index c57ea6eb810387a34ccabde5cdf48e8fa532f5ce..7155ed9419ae05cccc81f78e499a688530e1f89a 100644
--- a/Tracking/TrkEventCnv/TrkEventCnvTools/TrkEventCnvTools/ATLAS_CHECK_THREAD_SAFETY
+++ b/Tracking/TrkEventCnv/TrkEventCnvTools/TrkEventCnvTools/ATLAS_CHECK_THREAD_SAFETY
@@ -1,3 +1,2 @@
-
 Tracking/TrkEventCnv/TrkEventCnvTools
 
diff --git a/graphics/VTI12/README.md b/graphics/VTI12/README.md
index 91f52743e6dca9ab9887413a7251894b18d24eeb..47e64e0abd2bc3e01bd66f6c3bde193ca894ab32 100644
--- a/graphics/VTI12/README.md
+++ b/graphics/VTI12/README.md
@@ -8,10 +8,6 @@ To run on Calypso MC data (from an installation (run) directory):
 
 Note that VP1PLUGINPATH can be ninja-changed by asetup, and if it does not include the Calypso installation library folder, nothing will work
 
-To run on cosmic ray data (RDO output from the TrackerDataAccess example programs), with the correct geometry, do the following commands instead:
+You can also give the -detdescr="FASER-01" or -detdescr="FASER-02" and -globcond="OFLCOND-FASER-01" or -globcond="OFLCOND-FASER-02" flags to specify the detector geometry and conditions.  
 
-% source ./setup.sh
-
-% export VP1PLUGINPATH=./lib
-
-% vti12 -noautoconf -nosortdbreplicas -detdescr='FASER-CR' &lt;input RDO file&gt;
\ No newline at end of file
+The event display has no way to determine the right values for these settings (it defaults to FASER-01 and OFLCOND-FASER-01).
\ No newline at end of file
diff --git a/graphics/VTI12/VTI12Algs/share/vti12.py b/graphics/VTI12/VTI12Algs/share/vti12.py
index d05dcb15eb1f2183e9068e7c0758bf27940fec57..3878899db88d845cd247602b91faf6a1204cee7b 100644
--- a/graphics/VTI12/VTI12Algs/share/vti12.py
+++ b/graphics/VTI12/VTI12Algs/share/vti12.py
@@ -91,11 +91,11 @@ if (vp1InputFiles == []):
     # Set geometry version
     if (not "DetDescrVersion" in dir()):
             DetDescrVersion = "FASER-01"
-            globalflags.DetDescrVersion = DetDescrVersion
+    globalflags.DetDescrVersion = DetDescrVersion
     
     # Set conditions tag
     if not 'vp1GlobCond' in dir():
-        vp1GlobCond="OFLCOND-XXXX-XXX-XX"
+        vp1GlobCond="OFLCOND-FASER-01"
     from IOVDbSvc.CondDB import conddb
     conddb.setGlobalTag(vp1GlobCond)
 
@@ -145,7 +145,7 @@ else:
         # Set conditions tag
         if not 'vp1GlobCond' in dir():
             if (vp1Mc):
-                vp1GlobCond="OFLCOND-XXXX-XXX-XX"
+                vp1GlobCond="OFLCOND-FASER-01"
             else:
                 vp1GlobCond="COMCOND-BLKPST-004-01"
 
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h
index 6d26dc45e00ecb7a6ea80b674d6bb48346aac685..a50cf0d19605f3bbd922459105c416271968d1d7 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h
@@ -26,14 +26,15 @@ public:
   enum SubSystemFlag { // 32-bits hexadecimal bitmask
     
     None                    = 0x00000000,
-    Veto                    = 0x00000001,
-    Trigger                 = 0x00000002,
-    Preshower               = 0x00000004,
+    Emulsion                = 0x00000001,
+    Veto                    = 0x00000002,
+    Trigger                 = 0x00000004,
+    Preshower               = 0x00000008,
 
-    SCT                     = 0x00000008,
-    Dipole                  = 0x00000010,
+    SCT                     = 0x00000010,
+    Dipole                  = 0x00000020,
 
-    Ecal                    = 0x00000020,
+    Ecal                    = 0x00000040,
     // Pixel                   = 0x00000001, // bit 0
     // SCT                     = 0x00000002, // 1
     // TRT                     = 0x00000004, // 2
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx
index 10a5411504f90663c3eba8bd10cb0ae6277f4049..e6325f8f2ff62915d13dc462bd87e626b23c9227 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx
@@ -146,6 +146,9 @@ GeoSysController::GeoSysController(IVP1System * sys)
 
   setLastSelectedVolume(0);
 
+  // Neutrino
+  m_d->subSysCheckBoxMap[VP1GeoFlags::Emulsion] = m_d->ui.checkBox_Emulsion;
+
   // SCINTILLATOR
   m_d->subSysCheckBoxMap[VP1GeoFlags::Veto] = m_d->ui.checkBox_Veto;
   m_d->subSysCheckBoxMap[VP1GeoFlags::Trigger] = m_d->ui.checkBox_Trigger;
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx
index 31252be92ee66a900cf4c9209633432249b63409..8e4b61921f3d849bdd127f00f5c0c4ca1b868aa2 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx
@@ -328,6 +328,7 @@ QWidget * VP1GeometrySystem::buildController()
                           const QString& grandchildrenregexp="", // the regex for granchildren of the main sub-detector
                           bool negategrandchildrenregexp = false // wheter we want to negate teh granchildren regex
    */
+    m_d->addSubSystem( VP1GeoFlags::Emulsion, "Emulsion");
     m_d->addSubSystem( VP1GeoFlags::Veto,     "Veto");
     m_d->addSubSystem( VP1GeoFlags::Trigger,  "Trigger");
     m_d->addSubSystem( VP1GeoFlags::Preshower,"Preshower");
@@ -1096,6 +1097,12 @@ void VP1GeometrySystem::Imp::applyTopVolStates(const QMap<quint32,QByteArray>&to
 void VP1GeometrySystem::Imp::createPathExtras(const VolumeHandle* volhandle, QString& prefix, QStack<QString>& entries)
 {
   switch(volhandle->subsystem()){
+    case VP1GeoFlags::Emulsion:{
+      prefix = QString("Emulsion::");
+      entries.push("NEUTRINO::NEUTRINO");
+      entries.push("Emulsion::Emulsion");
+      return;
+    }
     case VP1GeoFlags::Veto:{
       prefix = QString("Veto::");
       entries.push("SCINT::SCINT");
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx
index 44621c5f4bce1ec72301bf43fd8a96e34b25524d..e1df8c9ac21df05d3728942d5bdf0b4f07bbc816 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx
@@ -143,6 +143,15 @@ void VisAttributes::overrideTransparencies(float transpfact)
 //////////////////////////////// Attributes for detectors ////////////////////////////////
 
 DetVisAttributes::DetVisAttributes() {
+  {
+    SoMaterial *material = new SoMaterial;
+    material->ambientColor.setValue(.187004, .157811, 0);
+    material->diffuseColor.setValue(.748016, .631244, 0);
+    material->specularColor.setValue(.915152, .915152, .915152);
+    material->shininess.setValue(0.642424);
+    add("Emulsion",material);
+  }
+
 
   {
     SoMaterial *material = new SoMaterial;
@@ -363,7 +372,24 @@ MatVisAttributes::MatVisAttributes() {
     add("Ether",m);
   }
   */
- 
+  { 
+    SoMaterial *material = new SoMaterial;
+    material->ambientColor.setValue(.187004*1.2, .157811*1.2, 0);
+    material->diffuseColor.setValue(.748016*1.2, .631244*1.2, 0);
+    material->specularColor.setValue(.915152, .915152, .915152);
+    material->shininess.setValue(0.642424);
+    add("Emulsion",material);
+  }
+
+  { 
+    SoMaterial *material = new SoMaterial;
+    material->ambientColor.setValue(.187004/1.2, .157811/1.2, 0);
+    material->diffuseColor.setValue(.748016/1.2, .631244/1.2, 0);
+    material->specularColor.setValue(.915152, .915152, .915152);
+    material->shininess.setValue(0.642424);
+    add("Polystyrene",material);
+  }
+
 
   {
     // C02:
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx
index 5ad7fca0825f66147beebd2be9df04f8e6cdafce..b1aff16c0a2c354c77428af96bf7fb8b7c1d2dc6 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx
@@ -31,7 +31,7 @@
 class VolumeTreeModel::Imp {
 public:
   //Static definitions of sections and which subsystems goes in which sections:
-  enum SECTION { UNKNOWN, SCINT, TRACKER, CALO, MISC };
+  enum SECTION { UNKNOWN, NEUTRINO, SCINT, TRACKER, CALO, MISC };
   static std::map<SECTION,QString> section2string;
   static std::map<VP1GeoFlags::SubSystemFlag,SECTION> subsysflag2section;
   static std::map<VP1GeoFlags::SubSystemFlag,QString> subsysflag2string;
@@ -104,6 +104,7 @@ VolumeTreeModel::VolumeTreeModel( QObject * parent )
 {
   if (Imp::section2string.empty()) {
     Imp::section2string[Imp::UNKNOWN] = "Unknown";
+    Imp::section2string[Imp::NEUTRINO] = "Neutrino";
     Imp::section2string[Imp::SCINT] = "Scintillators";
     Imp::section2string[Imp::TRACKER] = "Tracker";
     Imp::section2string[Imp::CALO] = "Calorimeter";
@@ -111,6 +112,8 @@ VolumeTreeModel::VolumeTreeModel( QObject * parent )
   }
   if (Imp::subsysflag2section.empty()) {
     Imp::defineSubSystem(VP1GeoFlags::None,"None",Imp::UNKNOWN);
+    // Neutrino
+    Imp::defineSubSystem(VP1GeoFlags::Emulsion,  "Emulsion",  Imp::NEUTRINO);
     // Scintillator
     Imp::defineSubSystem(VP1GeoFlags::Veto,      "Veto",      Imp::SCINT);
     Imp::defineSubSystem(VP1GeoFlags::Trigger,   "Trigger",   Imp::SCINT);
diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui
index 57805e11d209d90fe64d69c872b2d765a33909f5..be9ac807d6b5d2511d214a4a6265064f0bd7ef26 100644
--- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui
+++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui
@@ -150,6 +150,54 @@
         <number>4</number>
        </property>
        <item>
+        <widget class="QGroupBox" name="groupBox_neutrino">
+         <property name="title">
+          <string>FaserNu</string>
+         </property>
+         <layout class="QVBoxLayout" name="_12">
+          <property name="spacing">
+           <number>0</number>
+          </property>
+          <property name="leftMargin">
+           <number>4</number>
+          </property>
+          <property name="topMargin">
+           <number>4</number>
+          </property>
+          <property name="rightMargin">
+           <number>4</number>
+          </property>
+          <property name="bottomMargin">
+           <number>4</number>
+          </property>
+          <item>
+           <layout class="QHBoxLayout" name="_14">
+            <item>
+             <widget class="QCheckBox" name="checkBox_Emulsion">
+              <property name="text">
+               <string>Emulsion</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer>
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>1</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>       
         <widget class="QGroupBox" name="groupBox_scintillator">
          <property name="title">
           <string>Scintillator</string>
diff --git a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/CMakeLists.txt b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/CMakeLists.txt
index bcb9cacd1fcd55200b78edde0f2399d024642248..0451aa18d2544723a12b4f6a9757b2ef696d8d14 100644
--- a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/CMakeLists.txt
+++ b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/CMakeLists.txt
@@ -24,5 +24,5 @@ atlas_add_library( VTI12SimHitSystems VTI12SimHitSystems/*.h src/*.h src/*.cxx s
                    PUBLIC_HEADERS VTI12SimHitSystems
                    PRIVATE_INCLUDE_DIRS ${COIN3D_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS}
                    LINK_LIBRARIES VP1Base Qt5::Core Qt5::Widgets GL StoreGateLib SGtests
-                   PRIVATE_LINK_LIBRARIES ${COIN3D_LIBRARIES} ${EIGEN_LIBRARIES} FaserGeoAdaptors GeoPrimitives ScintSimEvent FaserCaloSimEvent TrackerSimEvent VTI12Utils )
+                   PRIVATE_LINK_LIBRARIES ${COIN3D_LIBRARIES} ${EIGEN_LIBRARIES} FaserGeoAdaptors GeoPrimitives NeutrinoSimEvent ScintSimEvent FaserCaloSimEvent TrackerSimEvent VTI12Utils )
 
diff --git a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx
index 60a7cda9735e87ec9f62eca4bbc7839c541206df..19634a20a2b55431ade9a88704a8b9ca6cf06ba4 100755
--- a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx
@@ -22,6 +22,8 @@
 #include "FaserCaloSimEvent/CaloHitCollection.h"
 #include "ScintSimEvent/ScintHitCollection.h"
 #include "FaserGeoAdaptors/GeoScintHit.h"
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
+#include "FaserGeoAdaptors/GeoNeutrinoHit.h"
 #include "TrackerSimEvent/FaserSiHitCollection.h"
 #include "FaserGeoAdaptors/GeoFaserSiHit.h"
 #include "FaserGeoAdaptors/GeoFaserCaloHit.h"
@@ -61,6 +63,7 @@ QWidget* VP1SimHitSystem::buildController()
   ui.setupUi(controller);
 
   // Populate Check Box Names Map
+  m_clockwork->checkBoxNamesMap.insert(ui.chbxEmulsionHits,"Emulsion");
   m_clockwork->checkBoxNamesMap.insert(ui.chbxVetoHits,"Veto");
   m_clockwork->checkBoxNamesMap.insert(ui.chbxTriggerHits,"Trigger");
   m_clockwork->checkBoxNamesMap.insert(ui.chbxPreshowerHits,"Preshower");
@@ -80,6 +83,7 @@ QWidget* VP1SimHitSystem::buildController()
 void VP1SimHitSystem::systemcreate(StoreGateSvc* /*detstore*/)
 {
   // Populate Color Map
+  m_clockwork->colorMap.insert("Emulsion",SbColor(1,0,1));
   m_clockwork->colorMap.insert("Veto",SbColor(0,0,1));
   m_clockwork->colorMap.insert("Trigger",SbColor(1,1,1));
   m_clockwork->colorMap.insert("Preshower",SbColor(1,0,0));
@@ -185,7 +189,26 @@ void VP1SimHitSystem::buildHitTree(const QString& detector)
   sw->addChild(material);
 
   // Take hits from SG
-  if(detector=="Veto")
+  if(detector=="Emulsion")
+  {
+    //
+    // Emulsion:
+    //
+    const NeutrinoHitCollection* p_collection = nullptr;
+    if(sg->retrieve(p_collection, "EmulsionHits")==StatusCode::SUCCESS)
+    {
+      for(NeutrinoHitConstIterator i_hit=p_collection->begin(); i_hit!=p_collection->end(); ++i_hit)
+      {
+        GeoNeutrinoHit ghit(*i_hit);
+        if(!ghit) continue;
+        HepGeom::Point3D<double> u = ghit.getGlobalPosition();
+        hitVtxProperty->vertex.set1Value(hitCount++,u.x(),u.y(),u.z());
+      }
+    }
+    else
+      message("Unable to retrieve Emulsion Hits");
+  }
+  else if(detector=="Veto")
   {
     //
     // Veto:
diff --git a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui
index b12880a8110247861b1d9b7c5bd48b730dab22ae..67f62d51f9450ac5416d1452f106c37633f25809 100755
--- a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui
+++ b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui
@@ -84,6 +84,22 @@
            </property>
           </layout>
          </item>
+        <item>
+        <widget class="QGroupBox" name="groupBox_Nu">
+        <property name="title">
+            <string>Neutrino</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+            <item>
+            <widget class="QCheckBox" name="chbxEmulsionHits">
+            <property name="text">
+            <string>Emulsion Hits</string>
+            </property>
+            </widget>
+            </item>
+        </layout>
+        </widget>
+        </item>         
          <item>
           <widget class="QGroupBox" name="groupBox">
            <property name="title">
@@ -114,6 +130,22 @@
            </layout>
           </widget>
          </item>
+
+
+         <item>
+          <layout class="QVBoxLayout">
+           <property name="spacing">
+            <number>6</number>
+           </property>
+           <property name="margin">
+            <number>0</number>
+           </property>
+          </layout>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
          <item>
           <spacer>
            <property name="orientation">
@@ -143,20 +175,7 @@
            </layout>
           </widget>
          </item>
-         <item>
-          <layout class="QVBoxLayout">
-           <property name="spacing">
-            <number>6</number>
-           </property>
-           <property name="margin">
-            <number>0</number>
-           </property>
-          </layout>
-         </item>
-        </layout>
-       </item>
-      </layout>
-     </item>
+
      <item>
       <widget class="QGroupBox" name="groupBox_3">
        <property name="title">
diff --git a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/CMakeLists.txt b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/CMakeLists.txt
index 8c6fd2c60e1c9893fb2e7ed17e52f8c7c4f335f9..a93fb1a1f3cac4e08a829987eb0533bac47b785f 100644
--- a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/CMakeLists.txt
+++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/CMakeLists.txt
@@ -30,6 +30,7 @@ atlas_add_library( VTI12TrackSystems VTI12TrackSystems/*.h src/*.cxx
    Qt5::Core Qt5::Gui TrackRecordLib
    PRIVATE_LINK_LIBRARIES ${COIN3D_LIBRARIES} ${CLHEP_LIBRARIES}
    AtlasHepMCLib AthContainers FaserDetDescr EventPrimitives
+   NeutrinoIdentifier NeutrinoSimEvent NeutrinoReadoutGeometry
    ScintIdentifier ScintSimEvent ScintReadoutGeometry
    TrackerIdentifier TrackerReadoutGeometry TrackerSimEvent
    FaserCaloIdentifier CaloReadoutGeometry FaserCaloSimEvent
diff --git a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/SimHitHandle_NeutrinoHit.h b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/SimHitHandle_NeutrinoHit.h
new file mode 100644
index 0000000000000000000000000000000000000000..91e2d6fa37c86da549142110bb63475fd08ae709
--- /dev/null
+++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/SimHitHandle_NeutrinoHit.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+////////////////////////////////////////////////////////////////
+//                                                            //
+//  Header file for class SimHitHandle_NeutrinoHit                  //
+//                                                            //
+//  Description: Handle for NeutrinoHit's                           //
+//                                                            //
+//  Author: Thomas H. Kittelmann (Thomas.Kittelmann@cern.ch)  //
+//  Initial version: March 2008                               //
+//                                                            //
+////////////////////////////////////////////////////////////////
+
+#ifndef SIMHITHANDLE_NEUTRINOHIT_H
+#define SIMHITHANDLE_NEUTRINOHIT_H
+
+#include "VTI12TrackSystems/SimHitHandleBase.h"
+
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "TrkParameters/TrackParameters.h"
+
+class NeutrinoHit;
+class SimHitHandle_NeutrinoHit : public SimHitHandleBase {
+public:
+
+  SimHitHandle_NeutrinoHit( const NeutrinoHit * );
+  virtual ~SimHitHandle_NeutrinoHit();
+
+  QString type() const { return "NeutrinoHit"; };
+
+  Amg::Vector3D momentumDirection() const;
+  Amg::Vector3D posStart() const;
+  Amg::Vector3D posEnd() const;
+  double hitTime() const;
+
+  const HepMcParticleLink& particleLink() const;
+
+  Trk::TrackParameters * createTrackParameters() const;
+
+private:
+
+  class Imp;
+  Imp * m_d;
+
+};
+
+#endif
diff --git a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/SimHitHandle_NeutrinoHit.cxx b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/SimHitHandle_NeutrinoHit.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9a2077068919324cc6c977d0cb5d8a39229afa9d
--- /dev/null
+++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/SimHitHandle_NeutrinoHit.cxx
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+////////////////////////////////////////////////////////////////
+//                                                            //
+//  Implementation of class SimHitHandle_NeutrinoHit             //
+//                                                            //
+//  Author: Thomas H. Kittelmann (Thomas.Kittelmann@cern.ch)  //
+//  Initial version: March 2008                               //
+//                                                            //
+////////////////////////////////////////////////////////////////
+
+#include "VTI12TrackSystems/SimHitHandle_NeutrinoHit.h"
+#include "VP1Base/VP1Msg.h"
+#include "VTI12Utils/VP1DetInfo.h"
+#include "VTI12Utils/VP1ParticleData.h"
+
+#include "NeutrinoSimEvent/NeutrinoHit.h"
+#include "NeutrinoReadoutGeometry/NeutrinoDetectorElement.h"
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+#include "NeutrinoIdentifier/EmulsionID.h"
+#include "VTI12TrackSystems/VP1TrackSanity.h"
+
+//____________________________________________________________________
+class SimHitHandle_NeutrinoHit::Imp {
+public:
+  Imp( const NeutrinoHit * h ) : thehit(h),detelem(0) {}
+  const NeutrinoHit * thehit;
+  mutable const NeutrinoDD::NeutrinoDetectorElement * detelem;
+  bool ensureDetElemInit() const;
+  Amg::Vector3D localToGlobal(const HepGeom::Point3D<double>&) const;
+};
+
+
+//____________________________________________________________________
+SimHitHandle_NeutrinoHit::SimHitHandle_NeutrinoHit(const NeutrinoHit * h)
+  : SimHitHandleBase(), m_d(new Imp(h))
+{
+  if (!h)
+    VP1Msg::message("SimHitHandle_NeutrinoHit constructor ERROR: Received null hit pointer");
+}
+
+//____________________________________________________________________
+SimHitHandle_NeutrinoHit::~SimHitHandle_NeutrinoHit()
+{
+  delete m_d;
+}
+
+//____________________________________________________________________
+bool SimHitHandle_NeutrinoHit::Imp::ensureDetElemInit() const
+{
+  if (detelem)
+    return true;
+  int module = thehit->getModule();
+  int base   = thehit->getBase();
+  int film   = thehit->getFilm();
+
+  Identifier id = VP1DetInfo::emulsionIDHelper()->film_id( module, base, film);
+    //fixme: id is_valid ?
+  detelem = VP1DetInfo::emulsionDetMgr()->getDetectorElement(id);
+  //Fixme : Handle case where detelem can not be found gracefully. And check pointers from VP1DetInfo!!
+  if (!detelem)
+    VP1Msg::messageDebug("SimHitHandle_NeutrinoHit ERROR: Could not get detector element for hit!");
+  return detelem!=0;
+}
+
+//____________________________________________________________________
+Amg::Vector3D SimHitHandle_NeutrinoHit::momentumDirection() const
+{
+  if (VP1Msg::verbose()&&m_d->thehit->localEndPosition()==m_d->thehit->localStartPosition())
+    VP1Msg::messageVerbose("SimHitHandle_NeutrinoHit::momentumDirection() ERROR: posStart()==posEnd()");
+  return (posEnd()-posStart()).unit();
+}
+
+//____________________________________________________________________
+Amg::Vector3D SimHitHandle_NeutrinoHit::Imp::localToGlobal( const HepGeom::Point3D<double>& local ) const
+{
+  if (!ensureDetElemInit())
+    return Amg::Vector3D(0,0,0);
+  return Amg::Vector3D(Amg::EigenTransformToCLHEP(detelem->transformHit()) * local);
+}
+
+//____________________________________________________________________
+Amg::Vector3D SimHitHandle_NeutrinoHit::posStart() const
+{
+  return m_d->localToGlobal(m_d->thehit->localStartPosition());
+}
+
+//____________________________________________________________________
+Amg::Vector3D SimHitHandle_NeutrinoHit::posEnd() const
+{
+  return m_d->localToGlobal(m_d->thehit->localEndPosition());
+}
+
+//____________________________________________________________________
+double SimHitHandle_NeutrinoHit::hitTime() const
+{
+  return m_d->thehit->meanTime();
+}
+
+//____________________________________________________________________
+const HepMcParticleLink& SimHitHandle_NeutrinoHit::particleLink() const
+{
+  return m_d->thehit->particleLink();
+}
+
+//____________________________________________________________________
+Trk::TrackParameters * SimHitHandle_NeutrinoHit::createTrackParameters() const
+{
+  //Find charge and magnitude of momentum:
+  double c;
+  if ( !hasCharge() ) {
+    bool ok;
+    c = VP1ParticleData::particleCharge(pdg(),ok);
+    if (!ok) {
+      VP1Msg::message("SimHitHandle_NeutrinoHit::createTrackParameters ERROR: Could not find particle charge (pdg="
+		      +QString::number(pdg())+"). Assuming charge=+1.");
+      c = +1.0;
+    } else {
+      if (VP1Msg::verbose())
+        VP1Msg::messageVerbose("Looked up particle charge for scintillator simhit with pdg code "+VP1Msg::str(pdg())+": "+VP1Msg::str(c));
+    }
+    const_cast<SimHitHandle_NeutrinoHit*>(this)->setCharge(c);
+  } else {
+    c = charge();
+  }
+
+  double mom = momentum();
+  if (mom<=0) {
+    VP1Msg::message("SimHitHandle_NeutrinoHit::createTrackParameters ERROR: Unknown momentum. Using 1 GeV");
+    mom = 1*CLHEP::GeV;
+  }
+
+  ////We could in principle get a surface like this:
+  //   if (!m_d->ensureDetElemInit()) {
+  //     VP1Msg::messageDebug("SimHitHandle_NeutrinoHit WARNING: Could not get detector element!");
+  //     return 0;
+  //   }
+  //   const Trk::PlaneSurface * surf
+  //     = dynamic_cast<const Trk::PlaneSurface *>( &(m_d->detelem->surface()));
+  //   if (!surf) {
+  //     VP1Msg::message("SimHitHandle_NeutrinoHit::createTrackParameters ERROR: could not get Trk::PlaneSurface");
+  //     return 0;
+  //   }
+  ////And then proceed to construct a new AtaPlane parameter with that
+  ////surface. However, that gives some problems, so instead we simply
+  ////create a perigee:
+
+  const Amg::Vector3D globpos = posStart();
+
+//  const Trk::GlobalMomentum u(momentumDirection());
+  const Amg::Vector3D u(momentumDirection());
+
+  return new Trk::Perigee(0, 0, u.phi(), u.theta(), c/mom, globpos);
+}
diff --git a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx
index 05c3f75b3b7ffa76bfb55539930a8331507469ed..ef731fa9549323d72b6b4f7d516fb7989b4182b3 100644
--- a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx
+++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx
@@ -16,6 +16,7 @@
 #include "VTI12TrackSystems/TrackHandle_TruthTrack.h"
 #include "VTI12TrackSystems/SimHitHandleBase.h"
 #include "VTI12TrackSystems/SimHitHandle_TrackRecord.h"
+#include "VTI12TrackSystems/SimHitHandle_NeutrinoHit.h"
 #include "VTI12TrackSystems/SimHitHandle_ScintHit.h"
 #include "VTI12TrackSystems/SimHitHandle_FaserSiHit.h"
 #include "VTI12TrackSystems/SimHitHandle_CaloHit.h"
@@ -39,6 +40,7 @@
 #include "ScintSimEvent/ScintHitCollection.h"
 #include "TrackerSimEvent/FaserSiHitCollection.h"
 #include "FaserCaloSimEvent/CaloHitCollection.h"
+#include "NeutrinoSimEvent/NeutrinoHitCollection.h"
 
 #include "CLHEP/Units/PhysicalConstants.h"
 
@@ -67,6 +69,7 @@ public:
 
 //  static SimHitHandleBase * createHitHandle( const TrackRecord * h ) { return new SimHitHandle_TrackRecord(h); }
   static SimHitHandleBase * createHitHandle( const TrackRecord& h ) { return new SimHitHandle_TrackRecord(&h); }
+  static SimHitHandleBase * createHitHandle( const NeutrinoHit& h ) { return new SimHitHandle_NeutrinoHit(&h); }
   static SimHitHandleBase * createHitHandle( const ScintHit& h ) { return new SimHitHandle_ScintHit(&h); }
   static SimHitHandleBase * createHitHandle( const FaserSiHit& h ) { return new SimHitHandle_FaserSiHit(&h); }
   static SimHitHandleBase * createHitHandle( const CaloHit& h) { return new SimHitHandle_CaloHit(&h); }
@@ -117,7 +120,10 @@ QStringList TrackCollHandle_TruthTracks::availableCollections( IVP1System*sys )
   QStringList mcevent_keys = sgcont.getKeys<McEventCollection>();
   QStringList trackrecord_keys = sgcont.getKeys<TrackRecordCollection>();
 
-  QStringList keys_siliconhits,keys_scintillatorhits,keys_calorimeterhits;
+  QStringList keys_neutrinohits, keys_siliconhits,keys_scintillatorhits,keys_calorimeterhits;
+
+  if (VP1JobConfigInfo::hasEmulsionGeometry())
+    keys_neutrinohits = sgcont.getKeys<NeutrinoHitCollection>();//"EmulsionHits"
 
   if (VP1JobConfigInfo::hasVetoGeometry() ||
       VP1JobConfigInfo::hasTriggerGeometry() ||
@@ -128,7 +134,8 @@ QStringList TrackCollHandle_TruthTracks::availableCollections( IVP1System*sys )
   if (VP1JobConfigInfo::hasEcalGeometry())
     keys_calorimeterhits = sgcont.getKeys<CaloHitCollection>();
 
-  bool extrainfo = ! ( keys_scintillatorhits.empty() && 
+  bool extrainfo = ! ( keys_neutrinohits.empty() &&
+                       keys_scintillatorhits.empty() && 
                        keys_siliconhits.empty() &&
                        trackrecord_keys.empty() );
 
@@ -254,7 +261,8 @@ bool TrackCollHandle_TruthTracks::Imp::loadHitLists(std::map<SimBarCode,SimHitLi
   addHitCollections<TrackRecordCollection>(hitLists);
 
   //Important that collections which inherently contains pdg codes are loaded first!
-
+   if (VP1JobConfigInfo::hasEmulsionGeometry())
+     addHitCollections<NeutrinoHitCollection>(hitLists);
    if (VP1JobConfigInfo::hasVetoGeometry() || 
       VP1JobConfigInfo::hasTriggerGeometry() || 
       VP1JobConfigInfo::hasPreshowerGeometry())
diff --git a/graphics/VTI12/VTI12Utils/CMakeLists.txt b/graphics/VTI12/VTI12Utils/CMakeLists.txt
index ae7736791d02deefd6b896ce785b595765dac2d2..beff2bb1d9f48a29be206bdb158206805300504d 100644
--- a/graphics/VTI12/VTI12Utils/CMakeLists.txt
+++ b/graphics/VTI12/VTI12Utils/CMakeLists.txt
@@ -35,5 +35,6 @@ atlas_add_library( VTI12Utils VTI12Utils/*.h src/*.cxx src/*.cpp
    ScintIdentifier ScintReadoutGeometry
    TrackerIdentifier TrackerReadoutGeometry
    FaserCaloIdentifier CaloReadoutGeometry
+   NeutrinoIdentifier NeutrinoReadoutGeometry
    #InDetRIO_OnTrack 
    TrkSurfaces TrkRIO_OnTrack VP1HEPVis )
diff --git a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h
index 1adebf82ae7687211cd24cdd0cfaceb6b50f492d..ff521e608e83558942909b2af4eb7f5f3d227f8d 100644
--- a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h
+++ b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h
@@ -20,6 +20,7 @@
 
 class IVP1System;
 class StoreGateSvc;
+namespace NeutrinoDD { class EmulsionDetectorManager; }
 namespace TrackerDD { class SCT_DetectorManager; }
 namespace ScintDD { class VetoDetectorManager; }
 namespace ScintDD { class TriggerDetectorManager; }
@@ -27,12 +28,14 @@ namespace ScintDD { class PreshowerDetectorManager; }
 namespace CaloDD  { class EcalDetectorManager; }
 
 class FaserDetectorID;
+class EmulsionDetectorID;
 class ScintDetectorID;
 class VetoID;
 class TriggerID;
 class PreshowerID;
 class FaserSCT_ID;
 class EcalID;
+class EmulsionID;
 
 class Identifier;
 
@@ -45,6 +48,8 @@ public:
   //return null. And it is never allowed to delete any of the returned
   //pointers!
 
+  static const NeutrinoDD::EmulsionDetectorManager * emulsionDetMgr();
+
   static const ScintDD::VetoDetectorManager * vetoDetMgr();
   static const ScintDD::TriggerDetectorManager * triggerDetMgr();
   static const ScintDD::PreshowerDetectorManager * preshowerDetMgr();
@@ -58,6 +63,8 @@ public:
 
   //Common specialised identifier helpers:
 
+   static const EmulsionID * emulsionIDHelper();
+
    static const VetoID * vetoIDHelper();
    static const TriggerID * triggerIDHelper();
    static const PreshowerID * preshowerIDHelper();
diff --git a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h
index d9ad784cc3b3d46c3a6e38ee3195ddb3a66c0cfd..a90910903a46ee80f207ee10a8e5d2295602fe33 100644
--- a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h
+++ b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h
@@ -32,6 +32,8 @@ public:
   //These next methods tells us what geomodel parts are initialised:
   static bool hasGeoModelExperiment();//If GeoModelExperiment/"FASER" can be retrieved
 
+  static bool hasEmulsionGeometry();
+
   static bool hasVetoGeometry();
   static bool hasTriggerGeometry();
   static bool hasPreshowerGeometry();
diff --git a/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx b/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx
index 6f5a72e9c193b18c2a8306a9f734aeb2afd0d5fe..ba2ecb3fb349040c013933feb8d81474ddc2f5a8 100644
--- a/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx
+++ b/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx
@@ -22,6 +22,8 @@
 
 #include "GeoModelKernel/GeoPVConstLink.h"
 
+#include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h"
+
 #include "ScintReadoutGeometry/VetoDetectorManager.h"
 #include "ScintReadoutGeometry/TriggerDetectorManager.h"
 #include "ScintReadoutGeometry/PreshowerDetectorManager.h"
@@ -32,6 +34,8 @@
 
 #include "FaserDetDescr/FaserDetectorID.h"
 
+#include "NeutrinoIdentifier/EmulsionID.h"
+
 #include "ScintIdentifier/VetoID.h"
 #include "ScintIdentifier/TriggerID.h"
 #include "ScintIdentifier/PreshowerID.h"
@@ -51,6 +55,8 @@ public:
   static bool m_initialised;
   static const char m_badInitFlag;//Address of this means bad initialisation.
 
+  static const NeutrinoDD::EmulsionDetectorManager * m_emulsionDetMgr;
+
   static const ScintDD::VetoDetectorManager * m_vetoDetMgr;
   static const ScintDD::TriggerDetectorManager * m_triggerDetMgr;
   static const ScintDD::PreshowerDetectorManager * m_preshowerDetMgr;
@@ -61,6 +67,8 @@ public:
 
   static const FaserDetectorID * m_faserIDHelper;
 
+  static const EmulsionID *   m_emulsionIDHelper;
+
   static const VetoID *       m_vetoIDHelper;
   static const TriggerID *    m_triggerIDHelper;
   static const PreshowerID *  m_preshowerIDHelper;
@@ -73,6 +81,8 @@ public:
 bool VP1DetInfo::Imp::m_initialised = false;
 const char VP1DetInfo::Imp::m_badInitFlag = ' ';
 
+const NeutrinoDD::EmulsionDetectorManager * VP1DetInfo::Imp::m_emulsionDetMgr = 0;
+
 const ScintDD::VetoDetectorManager * VP1DetInfo::Imp::m_vetoDetMgr = 0;
 const ScintDD::TriggerDetectorManager * VP1DetInfo::Imp::m_triggerDetMgr = 0;
 const ScintDD::PreshowerDetectorManager * VP1DetInfo::Imp::m_preshowerDetMgr = 0;
@@ -83,6 +93,8 @@ const CaloDD::EcalDetectorManager * VP1DetInfo::Imp::m_ecalDetMgr = 0;
 
 const FaserDetectorID * VP1DetInfo::Imp::m_faserIDHelper = 0;
 
+const EmulsionID * VP1DetInfo::Imp::m_emulsionIDHelper = 0;
+
 const VetoID * VP1DetInfo::Imp::m_vetoIDHelper = 0;
 const TriggerID * VP1DetInfo::Imp::m_triggerIDHelper = 0;
 const PreshowerID * VP1DetInfo::Imp::m_preshowerIDHelper = 0;
@@ -129,6 +141,8 @@ const T * VP1DetInfo::Imp::cachedRetrieve(const T*& cachedPtr, const char* prefe
 
 }
 
+const NeutrinoDD::EmulsionDetectorManager * VP1DetInfo::emulsionDetMgr() { return Imp::cachedRetrieve(Imp::m_emulsionDetMgr,"Emulsion",VP1JobConfigInfo::hasEmulsionGeometry()); }
+
 const ScintDD::VetoDetectorManager * VP1DetInfo::vetoDetMgr() { return Imp::cachedRetrieve(Imp::m_vetoDetMgr,"Veto",VP1JobConfigInfo::hasVetoGeometry()); }
 const ScintDD::TriggerDetectorManager * VP1DetInfo::triggerDetMgr() { return Imp::cachedRetrieve(Imp::m_triggerDetMgr,"Trigger",VP1JobConfigInfo::hasTriggerGeometry()); }
 const ScintDD::PreshowerDetectorManager * VP1DetInfo::preshowerDetMgr() { return Imp::cachedRetrieve(Imp::m_preshowerDetMgr,"Preshower",VP1JobConfigInfo::hasPreshowerGeometry()); }
@@ -139,6 +153,8 @@ const CaloDD::EcalDetectorManager * VP1DetInfo::ecalDetMgr() { return Imp::cache
 
 const FaserDetectorID * VP1DetInfo::faserIDHelper() { return Imp::cachedRetrieve(Imp::m_faserIDHelper,"FaserID",true); }
 
+const EmulsionID * VP1DetInfo::emulsionIDHelper() { return Imp::cachedRetrieve(Imp::m_emulsionIDHelper,"EmulsionID",VP1JobConfigInfo::hasEmulsionGeometry()); }
+
 const VetoID * VP1DetInfo::vetoIDHelper() { return Imp::cachedRetrieve(Imp::m_vetoIDHelper,"VetoID",VP1JobConfigInfo::hasVetoGeometry()); }
 const TriggerID * VP1DetInfo::triggerIDHelper() { return Imp::cachedRetrieve(Imp::m_triggerIDHelper,"TriggerID",VP1JobConfigInfo::hasTriggerGeometry()); }
 const PreshowerID * VP1DetInfo::preshowerIDHelper() { return Imp::cachedRetrieve(Imp::m_preshowerIDHelper,"PreshowerID",VP1JobConfigInfo::hasPreshowerGeometry()); }
@@ -154,6 +170,12 @@ bool VP1DetInfo::isUnsafe( const Identifier& id ) {
   if ( !idhelper || !id.is_valid() )
     return true;
 
+  if (idhelper->is_neutrino(id))
+  {
+    if (!VP1JobConfigInfo::hasEmulsionGeometry() && idhelper->is_emulsion(id))
+      return true;
+  }
+
   if (idhelper->is_scint(id)) {
     if (!VP1JobConfigInfo::hasVetoGeometry() && idhelper->is_veto(id))
       return true;
diff --git a/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx b/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx
index 0449af3927f264f14afdfebf5dd42c88f7710237..03a305c6851e984faa31a33eec57e41f11297177 100644
--- a/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx
+++ b/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx
@@ -35,6 +35,7 @@ public:
 
   static GeoPVConstLink geoModelWorld;
   static bool hasGeoModelExperiment;
+  static bool hasEmulsionGeometry;
   static bool hasVetoGeometry;
   static bool hasTriggerGeometry;
   static bool hasPreshowerGeometry;
@@ -49,6 +50,7 @@ GeoPVConstLink VP1JobConfigInfo::Imp::geoModelWorld;
 // init default values
 bool VP1JobConfigInfo::Imp::initialised = false;
 bool VP1JobConfigInfo::Imp::hasGeoModelExperiment = false;
+bool VP1JobConfigInfo::Imp::hasEmulsionGeometry = false;
 bool VP1JobConfigInfo::Imp::hasVetoGeometry = false;
 bool VP1JobConfigInfo::Imp::hasTriggerGeometry = false;
 bool VP1JobConfigInfo::Imp::hasPreshowerGeometry = false;
@@ -60,6 +62,7 @@ bool VP1JobConfigInfo::Imp::hasCavernInfraGeometry = false;
 void VP1JobConfigInfo::Imp::turnOffAll()
 {
   hasGeoModelExperiment = false;
+  hasEmulsionGeometry = false;
   hasVetoGeometry = false;
   hasTriggerGeometry = false;
   hasPreshowerGeometry = false;
@@ -84,6 +87,7 @@ void VP1JobConfigInfo::Imp::ensureInit()
   if (VP1Msg::verbose()) {
     VP1Msg::messageVerbose("VTI12JobConfigInfo => Found job configuration:");
     VP1Msg::messageVerbose("VTI12JobConfigInfo => hasGeoModelExperiment = "+QString(hasGeoModelExperiment?"On":"Off"));
+    VP1Msg::messageVerbose("VTI12JobConfigInfo => hasEmulsionGeometry = "+QString(hasEmulsionGeometry?"On":"Off"));
     VP1Msg::messageVerbose("VTI12JobConfigInfo => hasVetoGeometry = "+QString(hasVetoGeometry?"On":"Off"));
     VP1Msg::messageVerbose("VTI12JobConfigInfo => hasTriggerGeometry = "+QString(hasTriggerGeometry?"On":"Off"));
     VP1Msg::messageVerbose("VTI12JobConfigInfo => hasPreshowerGeometry = "+QString(hasPreshowerGeometry?"On":"Off"));
@@ -97,6 +101,7 @@ void VP1JobConfigInfo::Imp::ensureInit()
 
 //____________________________________________________________________
 bool VP1JobConfigInfo::hasGeoModelExperiment() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasGeoModelExperiment; }
+bool VP1JobConfigInfo::hasEmulsionGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasEmulsionGeometry; }
 bool VP1JobConfigInfo::hasVetoGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasVetoGeometry; }
 bool VP1JobConfigInfo::hasTriggerGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasTriggerGeometry; }
 bool VP1JobConfigInfo::hasPreshowerGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasPreshowerGeometry; }
@@ -152,6 +157,7 @@ bool VP1JobConfigInfo::Imp::actualInit( StoreGateSvc* detStore )
   while (!av.atEnd()) {
     std::string name = av.getName();
     VP1Msg::message( QString { name.c_str() } );
+    if ( !hasEmulsionGeometry && name=="Emulsion") hasEmulsionGeometry = true;
     if ( !hasVetoGeometry && name=="Veto") hasVetoGeometry = true;
     if ( !hasTriggerGeometry && name=="Trigger") hasTriggerGeometry = true;
     if ( !hasPreshowerGeometry && name=="Preshower") hasPreshowerGeometry = true;