diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..99a3531c48cdaaf7512ffab7b543a15ecad8181f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,60 @@
+
+
+dist: bionic
+
+services:
+  - docker
+
+language: cpp
+
+env:
+  matrix:
+    - COMPILER=gcc;   LCG_RELEASE=LCG_96c_LS; STANDARD=17; COMPILER_VERSION=gcc8;
+
+before_install:
+  - wget --no-check-certificate https://ecsft.cern.ch/dist/cvmfs/cvmfs-release/cvmfs-release-latest_all.deb
+  - sudo dpkg -i cvmfs-release-latest_all.deb
+  - sudo apt-get update
+  - sudo apt-get install cvmfs cvmfs-config-default
+  - rm -f cvmfs-release-latest_all.deb
+  - sudo mkdir -p /etc/cvmfs
+  - echo "CVMFS_QUOTA_LIMIT='32140'"                                | sudo tee     /etc/cvmfs/default.local > /dev/null
+  - echo "CVMFS_HTTP_PROXY=DIRECT"                                  | sudo tee -a  /etc/cvmfs/default.local > /dev/null
+  - echo "CVMFS_CACHE_BASE='/var/lib/cvmfs'"                        | sudo tee -a  /etc/cvmfs/default.local > /dev/null
+  - echo "CVMFS_FORCE_SIGNING='yes'"                                | sudo tee -a  /etc/cvmfs/default.local > /dev/null
+  - echo "CVMFS_REPOSITORIES='sft.cern.ch,sw-nightlies.hsf.org'"    | sudo tee -a  /etc/cvmfs/default.local > /dev/null
+  - echo "CVMFS_SEND_INFO_HEADER=no"                                | sudo tee -a  /etc/cvmfs/default.local > /dev/null
+  - cat /etc/cvmfs/default.local
+  - # change wrt dd4hep setup: don't manually mount cvmfs folders
+  - #sudo /etc/init.d/autofs stop
+  - sudo cvmfs_config setup
+  - sudo cvmfs_config probe
+  - sudo mkdir -p /cvmfs/sft.cern.ch
+  - sudo mkdir -p /cvmfs/sft-nightlies.cern.ch
+  - sudo mkdir -p /cvmfs/geant4.cern.ch
+  - sudo mkdir -p /cvmfs/sw-nightlies.hsf.org
+  - ls /cvmfs/sft.cern.ch
+  - ls /cvmfs/geant4.cern.ch
+  - ls /cvmfs/sw-nightlies.hsf.org
+  - export CVMFS_REPOS="-v /cvmfs/sft.cern.ch:/cvmfs/sft.cern.ch"
+  - export CVMFS_REPOS="${CVMFS_REPOS} -v /cvmfs/sw-nightlies.hsf.org:/cvmfs/sw-nightlies.hsf.org"
+  - export CVMFS_REPOS="${CVMFS_REPOS} -v /cvmfs/geant4.cern.ch:/cvmfs/geant4.cern.ch"
+
+
+# command to install dependencies
+install:
+  - shopt -s extglob dotglob
+  - mkdir package
+  - mv !(package) package
+  - shopt -u dotglob
+  - export PKGDIR=${PWD}/package
+
+# command to run tests
+script:
+  - docker run -ti --name CI_CONTAINER -v $PKGDIR:/workspace -e COMPILER_TYPE=$COMPILER -e LCG_RELEASE=${LCG_RELEASE} -e STANDARD=${STANDARD} -e COMPILER_VERSION=${COMPILER_VERSION} ${CVMFS_REPOS} -d clicdp/cc7-lcg bash 
+  - docker exec -ti CI_CONTAINER  /bin/bash -c "cd /workspace; ln -s /usr/lib64/liblzma.so.5.2.2 /usr/lib64/liblzma.so; echo 'hello world'"
+
+
+# Don't send e-mail notifications
+notifications:
+  email: false
diff --git a/CMakeLists.txt b/CMakeLists.txt
index afa6f8d043bc91b34583734d4c4eabcccf7b0ae2..f5534af8ba553e8f2c4d65f38a203c53bc5bbc00 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,19 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0)
 
+find_package(ROOT COMPONENTS RIO Tree)
+
 find_package(GaudiProject)
 
-gaudi_project(CEPCSW HEAD
-              USE Gaudi v29r2 )
\ No newline at end of file
+# Set up C++ Standard
+# ``-DCMAKE_CXX_STANDARD=<standard>`` when invoking CMake
+set(CMAKE_CXX_STANDARD 17 CACHE STRING "")
+
+if(NOT CMAKE_CXX_STANDARD MATCHES "14|17")
+  message(FATAL_ERROR "Unsupported C++ standard: ${CMAKE_CXX_STANDARD}")
+endif()
+
+
+gaudi_project(CEPCSW v0r1
+              USE Gaudi v33r1 
+              USE K4FWCore v0r1
+)
\ No newline at end of file
diff --git a/Detector/DetCEPCv4/CMakeLists.txt b/Detector/DetCEPCv4/CMakeLists.txt
index 8d245fbd7245610a0bbb8648822399085c06105c..ff3a8a705aaac03ca036e80d14e4a045fed91286 100644
--- a/Detector/DetCEPCv4/CMakeLists.txt
+++ b/Detector/DetCEPCv4/CMakeLists.txt
@@ -9,6 +9,7 @@ gaudi_depends_on_subdirs(GaudiKernel)
 
 
 find_package(DD4hep COMPONENTS DDRec DDG4 DDParsers REQUIRED)
+# find_package(DD4hep)
 find_package(Geant4)
 include(${Geant4_USE_FILE})
 
@@ -25,14 +26,28 @@ set(DetCEPCv4_src
     src/tracker/SIT_Simple_Pixel_geo.cpp 
     src/tracker/TPC10_geo.cpp
     src/tracker/SET_Simple_Planar_geo.cpp
+    src/calorimeter/SEcal05_Helpers.cpp
+    src/calorimeter/SEcal05_Barrel.cpp
+    src/calorimeter/SEcal05_Endcaps.cpp
+    src/calorimeter/SEcal05_ECRing.cpp
     src/other/BoxSupport_o1_v01_geo.cpp
     src/other/TubeSupport_o1_v01_geo.cpp
 )
 
 gaudi_add_module(DetCEPCv4
                   ${DetCEPCv4_src}
-		  INCLUDE_DIRS DD4hep ROOT Geant4 src/include
-		  LINK_LIBRARIES GaudiKernel DD4hep ${DD4hep_COMPONENT_LIBRARIES} ROOT Geant4)
+		  INCLUDE_DIRS 
+                  # DD4hep 
+                  # ROOT 
+                  # Geant4 
+                  src/include
+		  LINK_LIBRARIES
+                  # GaudiKernel
+                  DD4hep
+                  ${DD4hep_COMPONENT_LIBRARIES}
+                  # ROOT 
+                  # Geant4
+)
 
 set(LIBRARY_OUTPUT_PATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
 message(STATUS "LIBRARY_OUTPUT_PATH -> ${LIBRARY_OUTPUT_PATH}")
diff --git a/Detector/DetCEPCv4/compact/CepC_v4-onlyECAL.xml b/Detector/DetCEPCv4/compact/CepC_v4-onlyECAL.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c24218a84234c2c90d31759f166de1845c82f49a
--- /dev/null
+++ b/Detector/DetCEPCv4/compact/CepC_v4-onlyECAL.xml
@@ -0,0 +1,77 @@
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0"
+       xmlns:xs="http://www.w3.org/2001/XMLSchema"
+       xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+  <info name="CepC_v04"
+        title="CepC detctor used for the optimisation"
+        author="C.D.Fu"
+        url="http://cepc.ihep.ac.cn"
+        status="experimental"
+        version="v04">
+    <comment>CepC detector simulation models used for detector optimisation </comment>
+  </info>
+  <includes>
+    <gdmlFile  ref="elements.xml"/>
+    <gdmlFile  ref="materials.xml"/>
+  </includes>
+  <define>
+    <include ref="top_defs_CepC_v04.xml"/>
+    <include ref="top_defs.xml"/>
+    <include ref="basic_defs.xml"/>
+    <include ref="envelope_defs.xml"/>
+    <include ref="tube_defs.xml"/>
+    <include ref="misc_defs.xml"/>
+    <include ref="tracker_defs.xml"/>
+    <include ref="fcal_defs.xml"/>
+    <include ref="ecal_defs.xml"/>
+    <include ref="hcal_defs.xml"/>
+    <include ref="yoke_defs.xml"/>
+    <include ref="services_defs.xml"/>
+    <include ref="${DD4hepINSTALL}/DDDetectors/compact/detector_types.xml"/>
+    <include ref="limits.xml"/>
+    <!-- Readout slice in ecal for reconstruction -->
+    <constant name="Ecal_readout_segmentation_slice0" value="4"/>
+    <constant name="Ecal_readout_segmentation_slice1" value="10"/>
+    <!-- Readout slice in hcal for reconstruction -->
+    <constant name="Hcal_readout_segmentation_slice" value="3"/>
+  </define>
+  <limits>
+    <limitset name="cal_limits">
+      <limit name="step_length_max" particles="*" value="cal_steplimit_val" unit="cal_steplimit_unit" />
+    </limitset>
+    <limitset name="TPC_limits">
+      <limit name="step_length_max" particles="*" value="tpc_steplimit_val" unit="tpc_steplimit_unit" />
+    </limitset>
+    <limitset name="Tracker_limits">
+      <limit name="step_length_max" particles="*" value="tracker_steplimit_val" unit="tracker_steplimit_unit" />
+    </limitset>
+  </limits>
+  <include ref="display.xml"/>
+  <!-- <include ref="Beampipe_o1_v01_01.xml"/> -->
+  <!-- <include ref="vxd07.xml"/> -->
+  <!-- <include ref="ftd_simple_staggered_02.xml"/> -->
+  <!-- <include ref="sit_simple_pixel_sensors_01.xml"/> -->
+  <!-- <include ref="tpc10_01.xml"/> -->
+  <!-- <include ref="set_simple_planar_sensors_01.xml"/> -->
+  <include ref="SEcal05_siw_Barrel.xml"/>
+  <include ref="SEcal05_siw_Endcaps.xml"/>
+  <include ref="SEcal05_siw_ECRing.xml"/>
+  <!-- <include ref="Hcal_Barrel_SD_v01.xml"/> -->
+  <!-- <include ref="Hcal_Endcaps_SD_v01.xml"/> -->
+  <!-- <include ref="Hcal_EndcapRing_SD_v01.xml"/> -->
+  <!-- <include ref="Yoke05_Barrel.xml"/> -->
+  <!-- <include ref="Yoke05_Endcaps.xml"/> -->
+  <!-- <include ref="LumiCal.xml"/> -->
+
+  <!--include ref="LHCal01.xml"/>
+  <include ref="BeamCal08.xml"/-->
+
+  <!--include ref="coil03.xml"/-->
+  <!--include ref="SServices00.xml"/-->
+  <plugins>
+    <plugin name="DD4hepVolumeManager"/>
+    <plugin name="InstallSurfaceManager"/>
+  </plugins>
+  <!--include ref="Field_Solenoid_Map_s_4.0T.xml"/>
+  <include ref="Field_AntiDID_Map_s.xml"/>
+  <include ref="Field_FwdMagnets_Ideal_1000GeV.xml"/-->
+</lccdd>
diff --git a/Detector/DetCEPCv4/compact/FullDetGear.xml b/Detector/DetCEPCv4/compact/FullDetGear.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00f51646ab7d08a72ee1f1d42d53d4f5dee70557
--- /dev/null
+++ b/Detector/DetCEPCv4/compact/FullDetGear.xml
@@ -0,0 +1,330 @@
+<gear>
+    <global detectorName="CEPC_v4" />
+    <!--Gear XML file automatically created with GearXML::createXMLFile ....-->
+    <BField type="ConstantBField" x="0.000000000e+00" y="0.000000000e+00" z="3.000000000e+00" />
+    <detectors>
+        <detector geartype="TPCParameters" name="TPC">
+            <maxDriftLength value="2.225000000e+03" />
+            <driftVelocity value="0.000000000e+00" />
+            <coordinateType value="polar" />
+            <modules>
+                <module>
+                    <moduleID value="0" />
+                    <readoutFrequency value="0.000000000e+00" />
+                    <PadRowLayout2D type="FixedPadSizeDiskLayout" rMin="3.840000000e+02" rMax="1.716000000e+03" padHeight="6.000000000e+00" padWidth="1.000000000e+00" maxRow="222" padGap="0.000000000e+00" phiMax="6.283185307e+00" />
+                    <offset x_r="0.000000000e+00" y_phi="0.000000000e+00" />
+                    <angle value="0.000000000e+00" />
+                    <enlargeActiveAreaBy value="0.000000000e+00" />
+                </module>
+            </modules>
+            <parameter name="TPCGasProperties_RadLen" type="double" value="1.155205461e+05" />
+            <parameter name="TPCGasProperties_dEdx" type="double" value="2.668179899e-07" />
+            <parameter name="TPCInnerWallProperties_RadLen" type="double" value="2.740688665e+03" />
+            <parameter name="TPCInnerWallProperties_dEdx" type="double" value="1.241647394e-05" />
+            <parameter name="TPCOuterWallProperties_RadLen" type="double" value="6.495646008e+03" />
+            <parameter name="TPCOuterWallProperties_dEdx" type="double" value="5.300932694e-06" />
+            <parameter name="TPCWallProperties_RadLen" type="double" value="2.740688665e+03" />
+            <parameter name="TPCWallProperties_dEdx" type="double" value="1.241647394e-05" />
+            <parameter name="tpcInnerRadius" type="double" value="3.290000000e+02" />
+            <parameter name="tpcInnerWallThickness" type="double" value="2.500000000e+01" />
+            <parameter name="tpcOuterRadius" type="double" value="1.808000000e+03" />
+            <parameter name="tpcOuterWallThickness" type="double" value="6.000000000e+01" />
+            <parameter name="tpcZAnode" type="double" value="4.600000000e+03" />
+        </detector>
+        <detector name="EcalBarrel" geartype="CalorimeterParameters">
+            <layout type="Barrel" symmetry="8" phi0="0.000000000e+00" />
+            <dimensions inner_r="1.847415655e+03" outer_z="2.350000000e+03" />
+            <layer repeat="19" thickness="5.250000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="1" thickness="6.300000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="9" thickness="7.350000000e+00" absorberThickness="4.200000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+        </detector>
+        <detector name="EcalEndcap" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="4.000000000e+02" outer_r="2.088800000e+03" inner_z="2.450000000e+03" />
+            <layer repeat="19" thickness="5.250000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="1" thickness="6.300000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="9" thickness="7.350000000e+00" absorberThickness="4.200000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+        </detector>
+        <detector name="EcalPlug" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="2.400000000e+02" outer_r="4.000000000e+02" inner_z="2.450000000e+03" />
+            <layer repeat="19" thickness="5.250000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="1" thickness="6.300000000e+00" absorberThickness="2.100000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+            <layer repeat="9" thickness="7.350000000e+00" absorberThickness="4.200000000e+00" cellSize0="1.016666667e+01" cellSize1="1.016666667e+01" />
+        </detector>
+        <detector name="YokeBarrel" geartype="CalorimeterParameters">
+            <layout type="Barrel" symmetry="12" phi0="0.000000000e+00" />
+            <dimensions inner_r="4.173929932e+03" outer_z="4.072000000e+03" />
+            <layer repeat="1" thickness="4.000000000e+01" absorberThickness="0.000000000e+00" cellSize0="3.000000000e+01" cellSize1="3.000000000e+01" />
+            <layer repeat="10" thickness="1.400000000e+02" absorberThickness="1.000000000e+02" cellSize0="3.000000000e+01" cellSize1="3.000000000e+01" />
+            <layer repeat="3" thickness="6.000000000e+02" absorberThickness="5.600000000e+02" cellSize0="3.000000000e+01" cellSize1="3.000000000e+01" />
+        </detector>
+        <detector name="YokeEndcap" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="3.200000000e+02" outer_r="7.414929932e+03" inner_z="4.072000000e+03" />
+            <layer repeat="10" thickness="1.400000000e+02" absorberThickness="1.000000000e+02" cellSize0="3.000000000e+01" cellSize1="3.000000000e+01" />
+            <layer repeat="2" thickness="6.000000000e+02" absorberThickness="5.600000000e+02" cellSize0="3.000000000e+01" cellSize1="3.000000000e+01" />
+        </detector>
+        <detector name="YokePlug" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="3.200000000e+02" outer_r="2.849254326e+03" inner_z="3.781430000e+03" />
+            <parameter name="YokePlugThickness" type="double" value="2.905700000e+02" />
+        </detector>
+        <detector name="HcalBarrel" geartype="CalorimeterParameters">
+            <layout type="Barrel" symmetry="8" phi0="1.570796327e+00" />
+            <dimensions inner_r="2.058000000e+03" outer_z="2.350000000e+03" />
+            <layer repeat="40" thickness="2.673000000e+01" absorberThickness="2.000000000e+01" cellSize0="1.000000000e+01" cellSize1="1.000000000e+01" />
+            <parameter name="Hcal_barrel_number_modules" type="int" value="5" />
+            <parameter name="N_cells_z" type="int" value="91" />
+            <parameter name="FrameWidth" type="double" value="1.000000000e+00" />
+            <parameter name="Hcal_lateral_structure_thickness" type="double" value="1.000000000e+01" />
+            <parameter name="Hcal_modules_gap" type="double" value="2.000000000e+00" />
+            <parameter name="Hcal_outer_radius" type="double" value="3.144432447e+03" />
+            <parameter name="Hcal_virtual_cell_size" type="double" value="1.000000000e+01" />
+            <parameter name="InnerOctoSize" type="double" value="1.704903012e+03" />
+            <parameter name="RPC_PadSeparation" type="double" value="0.000000000e+00" />
+            <parameter name="TPC_Ecal_Hcal_barrel_halfZ" type="double" value="2.350000000e+03" />
+        </detector>
+        <detector name="HcalEndcap" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="3.500000000e+02" outer_r="3.144432447e+03" inner_z="2.650000000e+03" />
+            <layer repeat="40" thickness="2.673000000e+01" absorberThickness="2.000000000e+01" cellSize0="1.000000000e+01" cellSize1="1.000000000e+01" />
+            <parameter name="FrameWidth" type="double" value="0.000000000e+00" />
+            <parameter name="Hcal_virtual_cell_size" type="double" value="1.000000000e+01" />
+        </detector>
+        <detector name="HcalRing" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="2" phi0="0.000000000e+00" />
+            <dimensions inner_r="2.138800000e+03" outer_r="3.144432447e+03" inner_z="2.450000000e+03" />
+            <layer repeat="6" thickness="2.673000000e+01" absorberThickness="2.000000000e+01" cellSize0="1.000000000e+01" cellSize1="1.000000000e+01" />
+            <parameter name="FrameWidth" type="double" value="0.000000000e+00" />
+            <parameter name="Hcal_virtual_cell_size" type="double" value="1.000000000e+01" />
+        </detector>
+        <detector name="Lcal" geartype="CalorimeterParameters">
+            <layout type="Endcap" symmetry="1" phi0="0.000000000e+00" />
+            <dimensions inner_r="3.225828541e+01" outer_r="9.880000000e+01" inner_z="9.519000000e+02" />
+            <layer repeat="30" thickness="4.290000000e+00" absorberThickness="3.500000000e+00" cellSize0="1.039714290e+00" cellSize1="1.308996939e-01" />
+            <parameter name="beam_crossing_angle" type="double" value="0.000000000e+00" />
+        </detector>
+        <detector name="VXD" geartype="ZPlanarParameters">
+            <type technology="HYBRID" />
+            <shell halfLength="1.450000000e+02" gap="0.000000000e+00" innerRadius="6.500000000e+01" outerRadius="6.549392000e+01" radLength="3.527597571e+02" />
+            <layers>
+                <layer nLadders="10" phi0="-1.570796327e+00">
+                    <ladder distance="1.600000000e+01" thickness="1.000000000e+00" width="1.150000000e+01" length="6.250000000e+01" offset="-1.874869853e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="1.595000000e+01" thickness="5.000000000e-02" width="1.100000000e+01" length="6.250000000e+01" offset="-1.624869853e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="10" phi0="-1.570796327e+00">
+                    <ladder distance="1.700000000e+01" thickness="1.000000000e+00" width="1.150000000e+01" length="6.250000000e+01" offset="-1.874869853e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="1.800000000e+01" thickness="5.000000000e-02" width="1.100000000e+01" length="6.250000000e+01" offset="-1.624869853e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="11" phi0="-1.570796327e+00">
+                    <ladder distance="3.700000000e+01" thickness="1.000000000e+00" width="2.250000000e+01" length="1.250000000e+02" offset="-1.837940563e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="3.695000000e+01" thickness="5.000000000e-02" width="2.200000000e+01" length="1.250000000e+02" offset="-1.587940563e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="11" phi0="-1.570796327e+00">
+                    <ladder distance="3.800000000e+01" thickness="1.000000000e+00" width="2.250000000e+01" length="1.250000000e+02" offset="-1.837940563e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="3.900000000e+01" thickness="5.000000000e-02" width="2.200000000e+01" length="1.250000000e+02" offset="-1.587940563e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="17" phi0="-1.570796327e+00">
+                    <ladder distance="5.800000000e+01" thickness="1.000000000e+00" width="2.250000000e+01" length="1.250000000e+02" offset="-2.636744400e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="5.795000000e+01" thickness="5.000000000e-02" width="2.200000000e+01" length="1.250000000e+02" offset="-2.386744400e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="17" phi0="-1.570796327e+00">
+                    <ladder distance="5.900000000e+01" thickness="1.000000000e+00" width="2.250000000e+01" length="1.250000000e+02" offset="-2.636744400e+00" radLength="1.014262421e+03" />
+                    <sensitive distance="6.000000000e+01" thickness="5.000000000e-02" width="2.200000000e+01" length="1.250000000e+02" offset="-2.386744400e+00" radLength="9.366070445e+01" />
+                </layer>
+            </layers>
+        </detector>
+        <detector name="FTD" geartype="FTDParameters">
+            <layers>
+                <layer nPetals="16" nSensors="1" isDoubleSided="0" sensorType="PIXEL" petalOpenningAngle="1.963495408e-01" phi0="0.000000000e+00" alpha="0.000000000e+00" zoffset="1.500000000e+00" zsign0="-1.000000000e+00" zposition="2.200000000e+02">
+                    <support thickness="1.000000000e+00" width="1.180723890e+02" lengthMin="2.502788316e+01" lengthMax="7.200000000e+01" rInner="2.950000000e+01" radLength="2.860837413e+02" />
+                    <sensitive thickness="2.000000000e-02" width="1.180723890e+02" lengthMin="2.502788316e+01" lengthMax="7.200000000e+01" rInner="2.950000000e+01" radLength="9.366070445e+01" />
+                </layer>
+                <layer nPetals="16" nSensors="1" isDoubleSided="0" sensorType="PIXEL" petalOpenningAngle="1.963495408e-01" phi0="0.000000000e+00" alpha="0.000000000e+00" zoffset="1.500000000e+00" zsign0="-1.000000000e+00" zposition="3.713094000e+02">
+                    <support thickness="1.000000000e+00" width="1.170317258e+02" lengthMin="2.544188474e+01" lengthMax="7.200000000e+01" rInner="3.054066325e+01" radLength="2.860837413e+02" />
+                    <sensitive thickness="2.000000000e-02" width="1.170317258e+02" lengthMin="2.544188474e+01" lengthMax="7.200000000e+01" rInner="3.054066325e+01" radLength="9.366070445e+01" />
+                </layer>
+                <layer nPetals="16" nSensors="2" isDoubleSided="1" sensorType="STRIP" petalOpenningAngle="1.963495408e-01" phi0="0.000000000e+00" alpha="0.000000000e+00" zoffset="1.500000000e+00" zsign0="-1.000000000e+00" zposition="6.429059500e+02">
+                    <support thickness="2.000000000e+00" width="2.600401444e+02" lengthMin="1.903959852e+01" lengthMax="1.224900000e+02" rInner="3.251798652e+01" radLength="2.860837413e+02" />
+                    <sensitive thickness="2.000000000e-01" width="2.600401444e+02" lengthMin="1.903959852e+01" lengthMax="1.224900000e+02" rInner="3.251798652e+01" radLength="9.366070445e+01" />
+                </layer>
+                <layer nPetals="16" nSensors="2" isDoubleSided="1" sensorType="STRIP" petalOpenningAngle="1.963495408e-01" phi0="0.000000000e+00" alpha="0.000000000e+00" zoffset="1.500000000e+00" zsign0="-1.000000000e+00" zposition="8.440001500e+02">
+                    <support thickness="2.000000000e+00" width="2.688914284e+02" lengthMin="1.551833880e+01" lengthMax="1.224900000e+02" rInner="3.397826298e+01" radLength="2.860837413e+02" />
+                    <sensitive thickness="2.000000000e-01" width="2.688914284e+02" lengthMin="1.551833880e+01" lengthMax="1.224900000e+02" rInner="3.397826298e+01" radLength="9.366070445e+01" />
+                </layer>
+                <layer nPetals="16" nSensors="2" isDoubleSided="1" sensorType="STRIP" petalOpenningAngle="1.963495408e-01" phi0="0.000000000e+00" alpha="0.000000000e+00" zoffset="1.500000000e+00" zsign0="-1.000000000e+00" zposition="9.249600000e+02">
+                    <support thickness="2.000000000e+00" width="2.683035260e+02" lengthMin="1.575222092e+01" lengthMax="1.224900000e+02" rInner="3.456616538e+01" radLength="2.860837413e+02" />
+                    <sensitive thickness="2.000000000e-01" width="2.683035260e+02" lengthMin="1.575222092e+01" lengthMax="1.224900000e+02" rInner="3.456616538e+01" radLength="9.366070445e+01" />
+                </layer>
+            </layers>
+            <parameter name="strip_angle_deg" type="double" value="5.000000000e+00" />
+            <parameter name="strip_length_mm" type="double" value="2.500000000e+02" />
+            <parameter name="strip_pitch_mm" type="double" value="1.000000000e-02" />
+            <parameter name="strip_width_mm" type="double" value="1.000000000e-03" />
+        </detector>
+        <detector name="SIT" geartype="ZPlanarParameters">
+            <type technology="CCD" />
+            <shell halfLength="0.000000000e+00" gap="0.000000000e+00" innerRadius="0.000000000e+00" outerRadius="0.000000000e+00" radLength="0.000000000e+00" />
+            <layers>
+                <layer nLadders="10" phi0="0.000000000e+00">
+                    <ladder distance="1.531000000e+02" thickness="1.000000000e+00" width="9.916044311e+01" length="3.680000000e+02" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="1.529000000e+02" thickness="2.000000000e-01" width="9.916044311e+01" length="3.680000000e+02" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="10" phi0="0.000000000e+00">
+                    <ladder distance="1.544000000e+02" thickness="1.000000000e+00" width="1.001352022e+02" length="3.680000000e+02" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="1.554000000e+02" thickness="2.000000000e-01" width="1.001352022e+02" length="3.680000000e+02" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="19" phi0="0.000000000e+00">
+                    <ladder distance="3.001000000e+02" thickness="1.000000000e+00" width="9.988891763e+01" length="6.440000000e+02" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="2.999000000e+02" thickness="2.000000000e-01" width="9.988891763e+01" length="6.440000000e+02" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="19" phi0="0.000000000e+00">
+                    <ladder distance="3.014000000e+02" thickness="1.000000000e+00" width="1.003895291e+02" length="6.440000000e+02" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="3.024000000e+02" thickness="2.000000000e-01" width="1.003895291e+02" length="6.440000000e+02" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+            </layers>
+            <parameter name="sensor_length_mm" type="double" value="9.200000000e+01" />
+            <parameter name="strip_angle_deg" type="double" value="7.000000000e+00" />
+            <parameter name="strip_length_mm" type="double" value="9.200000000e+01" />
+            <parameter name="strip_pitch_mm" type="double" value="5.000000000e-02" />
+            <parameter name="strip_width_mm" type="double" value="1.250000000e-02" />
+            <parameter name="n_sensors_per_ladder" type="IntVec" value="8 8 14 14" />
+        </detector>
+        <detector name="SET" geartype="ZPlanarParameters">
+            <type technology="CCD" />
+            <shell halfLength="0.000000000e+00" gap="0.000000000e+00" innerRadius="0.000000000e+00" outerRadius="0.000000000e+00" radLength="0.000000000e+00" />
+            <layers>
+                <layer nLadders="24" phi0="0.000000000e+00">
+                    <ladder distance="1.811100000e+03" thickness="1.000000000e+00" width="4.766190158e+02" length="2.300000000e+03" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="1.810900000e+03" thickness="2.000000000e-01" width="4.766190158e+02" length="2.300000000e+03" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+                <layer nLadders="24" phi0="0.000000000e+00">
+                    <ladder distance="1.812400000e+03" thickness="1.000000000e+00" width="4.770139733e+02" length="2.300000000e+03" offset="0.000000000e+00" radLength="2.134851878e+02" />
+                    <sensitive distance="1.813400000e+03" thickness="2.000000000e-01" width="4.770139733e+02" length="2.300000000e+03" offset="0.000000000e+00" radLength="9.366070445e+01" />
+                </layer>
+            </layers>
+            <parameter name="sensor_length_mm" type="double" value="9.200000000e+01" />
+            <parameter name="strip_angle_deg" type="double" value="7.000000000e+00" />
+            <parameter name="strip_length_mm" type="double" value="9.200000000e+01" />
+            <parameter name="strip_pitch_mm" type="double" value="5.000000000e-02" />
+            <parameter name="strip_width_mm" type="double" value="1.250000000e-02" />
+            <parameter name="n_sensors_per_ladder" type="IntVec" value="50 50" />
+        </detector>
+        <detector name="BeamPipe" geartype="GearParameters">
+            <parameter name="BeamPipeHalfZ" type="double" value="7.300000000e+02" />
+            <parameter name="BeamPipeProperties_RadLen" type="double" value="3.527597571e+02" />
+            <parameter name="BeamPipeProperties_dEdx" type="double" value="2.941795296e-04" />
+            <parameter name="BeamPipeRadius" type="double" value="1.400000000e+01" />
+            <parameter name="BeamPipeThickness" type="double" value="5.000000000e-01" />
+            <parameter name="RInner" type="DoubleVec" value="1.400000000e+01 1.400000000e+01 2.500000000e+00 1.300000000e+01 1.300000000e+01 1.300000000e+01 1.550000000e+01 1.550000000e+01 1.900000000e+01 1.900000000e+01 2.500000000e+01 2.500000000e+01 1.300000000e+01 1.300000000e+01 2.050000000e+01 2.050000000e+01 2.300000000e+01 2.300000000e+01 2.600000000e+01 2.600000000e+01 3.200000000e+01 3.200000000e+01" />
+            <parameter name="ROuter" type="DoubleVec" value="1.450000000e+01 1.450000000e+01 1.800000000e+01 1.800000000e+01 1.550000000e+01 1.550000000e+01 1.900000000e+01 1.900000000e+01 2.500000000e+01 2.500000000e+01 3.300000000e+01 3.300000000e+01 1.550000000e+01 1.550000000e+01 2.300000000e+01 2.300000000e+01 2.600000000e+01 2.600000000e+01 3.200000000e+01 3.200000000e+01 4.000000000e+01 4.000000000e+01" />
+            <parameter name="Z" type="DoubleVec" value="0.000000000e+00 5.000000000e+02 7.000000000e+02 7.010000000e+02 2.200000000e+03 2.200000000e+03 2.200000000e+03 2.200000000e+03 2.200000000e+03 2.200000000e+03 2.200000000e+03 2.200000000e+03 3.950000000e+03 3.950000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03 4.450000000e+03" />
+        </detector>
+        <detector name="CoilParameters" geartype="GearParameters">
+            <parameter name="Coil_cryostat_c_modules_half_z" type="double" value="1.224000000e+03" />
+            <parameter name="Coil_cryostat_c_modules_inner_radius" type="double" value="3.348930000e+03" />
+            <parameter name="Coil_cryostat_c_modules_outer_radius" type="double" value="3.733930000e+03" />
+            <parameter name="Coil_cryostat_half_z" type="double" value="3.872000000e+03" />
+            <parameter name="Coil_cryostat_inner_cyl_half_z" type="double" value="3.872000000e+03" />
+            <parameter name="Coil_cryostat_inner_cyl_inner_radius" type="double" value="3.173930000e+03" />
+            <parameter name="Coil_cryostat_inner_cyl_outer_radius" type="double" value="3.963930000e+03" />
+            <parameter name="Coil_cryostat_inner_radius" type="double" value="3.173930000e+03" />
+            <parameter name="Coil_cryostat_mandrel_half_z" type="double" value="3.675000000e+03" />
+            <parameter name="Coil_cryostat_mandrel_inner_radius" type="double" value="3.733930000e+03" />
+            <parameter name="Coil_cryostat_mandrel_outer_radius" type="double" value="3.808930000e+03" />
+            <parameter name="Coil_cryostat_modules_half_z" type="double" value="7.960000000e+02" />
+            <parameter name="Coil_cryostat_modules_inner_radius" type="double" value="3.348930000e+03" />
+            <parameter name="Coil_cryostat_modules_outer_radius" type="double" value="3.733930000e+03" />
+            <parameter name="Coil_cryostat_outer_cyl_half_z" type="double" value="3.872000000e+03" />
+            <parameter name="Coil_cryostat_outer_cyl_inner_radius" type="double" value="3.893930000e+03" />
+            <parameter name="Coil_cryostat_outer_cyl_outer_radius" type="double" value="3.923930000e+03" />
+            <parameter name="Coil_cryostat_outer_radius" type="double" value="3.923930000e+03" />
+            <parameter name="Coil_cryostat_scint1_inner_radius" type="double" value="3.263930000e+03" />
+            <parameter name="Coil_cryostat_scint1_outer_radius" type="double" value="3.273930000e+03" />
+            <parameter name="Coil_cryostat_scint1_zposend" type="double" value="3.972000000e+03" />
+            <parameter name="Coil_cryostat_scint1_zposin" type="double" value="3.772000000e+03" />
+            <parameter name="Coil_cryostat_scint2_inner_radius" type="double" value="3.278930000e+03" />
+            <parameter name="Coil_cryostat_scint2_outer_radius" type="double" value="3.288930000e+03" />
+            <parameter name="Coil_cryostat_scint2_zposend" type="double" value="3.972000000e+03" />
+            <parameter name="Coil_cryostat_scint2_zposin" type="double" value="3.772000000e+03" />
+            <parameter name="Coil_cryostat_scint3_inner_radius" type="double" value="3.833930000e+03" />
+            <parameter name="Coil_cryostat_scint3_outer_radius" type="double" value="3.843930000e+03" />
+            <parameter name="Coil_cryostat_scint3_zposend" type="double" value="3.972000000e+03" />
+            <parameter name="Coil_cryostat_scint3_zposin" type="double" value="3.772000000e+03" />
+            <parameter name="Coil_cryostat_scint4_inner_radius" type="double" value="3.818930000e+03" />
+            <parameter name="Coil_cryostat_scint4_outer_radius" type="double" value="3.828930000e+03" />
+            <parameter name="Coil_cryostat_scint4_zposend" type="double" value="3.972000000e+03" />
+            <parameter name="Coil_cryostat_scint4_zposin" type="double" value="3.772000000e+03" />
+            <parameter name="Coil_cryostat_side_l_half_z" type="double" value="2.500000000e+01" />
+            <parameter name="Coil_cryostat_side_l_inner_radius" type="double" value="3.213930000e+03" />
+            <parameter name="Coil_cryostat_side_l_outer_radius" type="double" value="3.893930000e+03" />
+            <parameter name="Coil_cryostat_side_r_half_z" type="double" value="2.500000000e+01" />
+            <parameter name="Coil_cryostat_side_r_inner_radius" type="double" value="3.213930000e+03" />
+            <parameter name="Coil_cryostat_side_r_outer_radius" type="double" value="3.893930000e+03" />
+            <parameter name="Coil_material_c_modules" type="string" value="aluminium" />
+            <parameter name="Coil_material_inner_cyl" type="string" value="aluminium" />
+            <parameter name="Coil_material_mandrel" type="string" value="aluminium" />
+            <parameter name="Coil_material_modules" type="string" value="aluminium" />
+            <parameter name="Coil_material_outer_cyl" type="string" value="aluminium" />
+            <parameter name="Coil_material_scint1" type="string" value="polystyrene" />
+            <parameter name="Coil_material_scint2" type="string" value="polystyrene" />
+            <parameter name="Coil_material_scint3" type="string" value="polystyrene" />
+            <parameter name="Coil_material_scint4" type="string" value="polystyrene" />
+            <parameter name="Coil_material_side_l" type="string" value="aluminium" />
+            <parameter name="Coil_material_side_r" type="string" value="aluminium" />
+        </detector>
+        <detector name="MokkaParameters" geartype="GearParameters">
+            <parameter name="Ecal_endcap_outer_radius" type="string" value="2088.8" />
+            <parameter name="Ecal_endcap_plug_rmin" type="string" value="240" />
+            <parameter name="Ecal_endcap_zmax" type="string" value="2635" />
+            <parameter name="Ecal_endcap_zmin" type="string" value="2450" />
+            <parameter name="Ecal_outer_radius" type="string" value="2028" />
+            <parameter name="Hcal_R_max" type="string" value="3144.43" />
+            <parameter name="Hcal_endcap_zmin" type="string" value="2650" />
+            <parameter name="Lcal_z_begin" type="string" value="951.9" />
+            <parameter name="Lcal_z_thickness" type="string" value="128.1" />
+            <parameter name="MokkaModel" type="string" value="CEPC_v4" />
+            <parameter name="MokkaVersion" type="string" value="void" />
+            <parameter name="SIT1_Half_Length_Z" type="string" value="368" />
+            <parameter name="SIT1_Radius" type="string" value="152.9" />
+            <parameter name="SIT2_Half_Length_Z" type="string" value="644" />
+            <parameter name="SIT2_Radius" type="string" value="299.9" />
+            <parameter name="TPC_Ecal_Hcal_barrel_halfZ" type="string" value="2350" />
+            <parameter name="Yoke_Z_start_endcaps" type="string" value="4072" />
+            <parameter name="Yoke_barrel_inner_radius" type="string" value="4173.92993164062" />
+            <parameter name="calorimeter_region_rmax" type="string" value="3144.43" />
+            <parameter name="calorimeter_region_zmax" type="string" value="3736.43" />
+            <parameter name="tracker_region_rmax" type="string" value="1842.9" />
+            <parameter name="tracker_region_zmax" type="string" value="2350" />
+            <parameter name="world_box_hx" type="string" value="" />
+            <parameter name="world_box_hy" type="string" value="" />
+            <parameter name="world_box_hz" type="string" value="" />
+        </detector>
+        <detector name="VXDInfra" geartype="GearParameters">
+            <parameter name="ActiveLayerProperties_dEdx" type="double" value="3.870163611e-04" />
+            <parameter name="BeSupportEndplateThickness" type="double" value="2.000000000e+00" />
+            <parameter name="BeSupport_dEdx" type="double" value="2.941795296e-04" />
+            <parameter name="CryostatAlHalfZ" type="double" value="1.766000000e+02" />
+            <parameter name="CryostatAlInnerR" type="double" value="2.420000000e+01" />
+            <parameter name="CryostatAlRadius" type="double" value="1.000000000e+02" />
+            <parameter name="CryostatAlThickness" type="double" value="5.000000000e-01" />
+            <parameter name="CryostatAlZEndCap" type="double" value="1.768500000e+02" />
+            <parameter name="CryostatFoamRadius" type="double" value="9.000000000e+01" />
+            <parameter name="CryostatFoamThickness" type="double" value="1.000000000e+01" />
+            <parameter name="Cryostat_RadLen" type="double" value="8.896317758e+01" />
+            <parameter name="Cryostat_dEdx" type="double" value="4.350185478e-04" />
+            <parameter name="ElectronicEndLength" type="double" value="1.000000000e+01" />
+            <parameter name="ElectronicEndThickness" type="double" value="1.000000000e-01" />
+            <parameter name="StripLineBeamPipeRadius" type="double" value="2.430000000e+01" />
+            <parameter name="VXDEndPlateInnerRadius" type="double" value="3.000000000e+01" />
+            <parameter name="VXDSupport_dEdx" type="double" value="5.431907412e-05" />
+            <parameter name="LadderGaps" type="DoubleVec" value="0.000000000e+00 0.000000000e+00 0.000000000e+00 0.000000000e+00 0.000000000e+00 0.000000000e+00" />
+            <parameter name="StripLineFinalZ" type="DoubleVec" value="1.500000000e+02 1.500000000e+02 1.500000000e+02 1.500000000e+02 1.500000000e+02 1.500000000e+02" />
+        </detector>
+    </detectors>
+    <materials>
+        <material name="VXDFoamShellMaterial" A="1.043890843e+01" Z="5.612886646e+00" density="2.500000000e+01" radLength="1.751650267e+04" intLength="6.594366018e+01" />
+        <material name="VXDSupportMaterial" A="2.075865162e+01" Z="1.039383117e+01" density="2.765900000e+02" radLength="1.014262421e+03" intLength="1.206635688e+02" />
+    </materials>
+</gear>
diff --git a/Detector/DetCEPCv4/src/calorimeter/SEcal05_Barrel.cpp b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Barrel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0329b4e2e351969fa8e0f5b4e2ceed47a1f5f8e
--- /dev/null
+++ b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Barrel.cpp
@@ -0,0 +1,444 @@
+//====================================================================
+//  lcgeo - LC detector models in DD4hep
+//--------------------------------------------------------------------
+//  DD4hep Geometry driver for SiWEcalBarrel
+//  Ported from Mokka
+//--------------------------------------------------------------------
+//  S.Lu, DESY
+//  D.Jeans, Tokyo <-- to 05: add possibility to remove preshower layer
+//====================================================================
+
+#include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/DetType.h"
+
+#include "XML/Layering.h"
+#include "TGeoTrd2.h"
+
+#include "XML/Utilities.h"
+#include "DDRec/DetectorData.h"
+
+#include "DDSegmentation/MegatileLayerGridXY.h"
+#include "DDSegmentation/WaferGridXY.h"
+
+#include "SEcal05_Helpers.h"
+
+#include <sstream>
+
+#undef NDEBUG
+#include <assert.h>
+
+using namespace std;
+
+using dd4hep::BUILD_ENVELOPE;
+using dd4hep::DetElement;
+using dd4hep::Detector;
+using dd4hep::Layering;
+using dd4hep::Material;
+using dd4hep::PlacedVolume;
+using dd4hep::Position;
+using dd4hep::Readout;
+using dd4hep::Ref_t;
+using dd4hep::RotationZYX;
+using dd4hep::Segmentation;
+using dd4hep::SensitiveDetector;
+using dd4hep::Transform3D;
+using dd4hep::Translation3D;
+using dd4hep::Trapezoid;
+using dd4hep::Volume;
+using dd4hep::_toString;
+
+using dd4hep::rec::LayeredCalorimeterData;
+
+#define VERBOSE 1
+
+// workaround for DD4hep v00-14 (and older)
+#ifndef DD4HEP_VERSION_GE
+#define DD4HEP_VERSION_GE(a,b) 0
+#endif
+
+/** SEcal05.cc
+ *
+ * new SEcal05 barrel driver: allows removal of preshower layer. DJeans UTokyo, sep/2016
+ * based on SEcal04
+ *
+ *  @author: Shaojun Lu, DESY
+ *  @version $Id: SEcal04_Barrel.cpp 1060 2016-09-05 07:48:41Z /C=JP/O=KEK/OU=CRC/CN=JEANS Daniel Thomelin Dietrich $
+ *              Ported from Mokka SEcal04 Barrel part. Read the constants from XML
+ *              instead of the DB. Then build the Barrel in the same way with DD4hep
+ *              construct.
+ *
+ * @history: F.Gaede, CERN/DESY, Nov. 10, 2014
+ *              added information for reconstruction: LayeringExtension and surfaces (experimental)
+ *              removed DetElement for slices (not needed) increased multiplicity for layer DetElement
+ *              along tower index
+ *   F.Gaede: 03/2015:
+ *            create the envelope volume with create_placed_envelope() using the xml
+ *
+ *  D. Jeans: 03/2015:
+ *             generalise to non-octagonal barrel shape
+ *             allow dead region between end of each slab and the module edge (e.g. for the slab fastening system)
+ */
+
+/*
+
+
+
+
+  y
+  ^
+  |     z is perpendicular to page (along beamline)
+  |
+  ----->  x
+
+  original coord system was very mixed up.
+  Daniel tried to rationalise it to make it more understandable (hopefully)
+
+  absorber layers are wrapped in a number of layers of carbon fibre composite (CF)
+
+  structure of slab (which is inserted into the structure) is defined in the compact description
+
+  general structure (from +ve y)
+  -------------------------------
+
+  if preshower, front face (CF)               \\\\\\\\\\\\\\\\\\
+
+  if no preshower, wrapped absorber           ==================
+
+                                              __________________
+  alveolus, containing the slab              |__________________|
+
+  wrapped absorber                           ===================
+                                              __________________
+  alveolus, containing the slab              |__________________|
+
+  .
+  repeat as required
+  .
+
+  wrapped absorber                           ===================
+                                             __________________
+  alveolus, containing the slab             |__________________|
+
+  back support plate (CF)                    \\\\\\\\\\\\\\\\\\\\
+                                             ////////////////////
+
+  */
+
+
+
+static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
+
+  cout << "-----------------------" << endl;
+  cout << "creating SEcal05_Barrel" << endl;
+  cout << "-----------------------" << endl;
+
+  xml_det_t     x_det     = element;
+  string        det_name  = x_det.nameStr();
+  Layering      layering (element);
+
+  Material      carbon_fibre = theDetector.material("CarbonFiber");
+
+  int           det_id    = x_det.id();
+  DetElement    sdet      (det_name,det_id);
+
+  xml_comp_t    x_dim     = x_det.dimensions();
+  int           nsides    = x_dim.numsides();
+
+  double        dphi      = (2*M_PI/nsides);
+  double        hphi      = dphi/2;
+
+  // --- create an envelope volume and position it into the world ---------------------
+
+  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
+
+  dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
+
+  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
+
+  //-----------------------------------------------------------------------------------
+
+  sens.setType("calorimeter");
+
+  DetElement    stave_det("module1stave1",det_id);
+
+  //====================================================================
+  //
+  // Read all the constant from ILD_o1_v05.xml
+  // Use them to build HcalBarrel
+  //
+  //====================================================================
+
+  // some hardcoded values!
+  //  const int N_FIBERS_W_STRUCTURE = 2; // number of CF layers around absorber layers in the structure
+  //  const int N_FIBERS_ALVEOLUS    = 3; // number of CF layers used to make alveolus
+
+  //  read other parameters from compact.xml file
+
+  // overall size
+  double Ecal_inner_radius                  = theDetector.constant<double>("Ecal_inner_radius");
+
+  double Ecal_Barrel_halfZ                  = theDetector.constant<double>("Ecal_Barrel_halfZ");
+  int    Ecal_barrel_z_modules              = theDetector.constant<int>("Ecal_barrel_z_modules");
+  int    Ecal_barrel_number_of_towers       = theDetector.constant<int>("Ecal_barrel_number_of_towers");
+
+  double Ecal_barrel_thickness              = theDetector.constant<double>("Ecal_barrel_thickness"); // what's assumed in the compact description
+
+  // absorber layers
+  int    Ecal_nlayers1                      = theDetector.constant<int>("Ecal_nlayers1");
+  int    Ecal_nlayers2                      = theDetector.constant<int>("Ecal_nlayers2");
+  int    Ecal_nlayers3                      = theDetector.constant<int>("Ecal_nlayers3");
+
+  double Ecal_radiator_thickness1           = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness");
+  double Ecal_radiator_thickness2           = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness");
+  double Ecal_radiator_thickness3           = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
+
+  // CF support dimensions
+  double Ecal_support_thickness             = theDetector.constant<double>("Ecal_support_thickness");
+  double Ecal_front_face_thickness          = theDetector.constant<double>("Ecal_front_face_thickness");
+  double Ecal_lateral_face_thickness        = theDetector.constant<double>("Ecal_lateral_face_thickness");
+  double Ecal_Slab_H_fiber_thickness        = theDetector.constant<double>("Ecal_Slab_H_fiber_thickness");
+
+  
+  //  double Ecal_fiber_thickness               = theDetector.constant<double>("Ecal_fiber_thickness");
+  // some hardcoded values!
+  // const int N_FIBERS_W_STRUCTURE = 2; // number of CF layers around absorber layers in the structure
+  // const int N_FIBERS_ALVEOLUS    = 3; // number of CF layers used to make alveolus
+  double Ecal_fiber_thickness_structure = theDetector.constant<double>("Ecal_fiber_thickness_structure"); // absorber wrapping thickness
+  double Ecal_fiber_thickness_alveolus  = theDetector.constant<double>("Ecal_fiber_thickness_alveolus"); // alveolar wall thickness
+
+  double Ecal_Slab_shielding                = theDetector.constant<double>("Ecal_Slab_shielding");
+
+  // first layer is preshower?
+  bool   Ecal_Barrel_PreshowerLayer         = theDetector.constant<int>("Ecal_Barrel_Preshower") > 0;
+
+  // internal dimensions of slab
+  double Ecal_guard_ring_size               = theDetector.constant<double>("Ecal_guard_ring_size");
+  int    Ecal_n_wafers_per_tower            = theDetector.constant<int>("Ecal_n_wafers_per_tower");
+
+  std::string Ecal_layerConfig              = theDetector.constant<string>("Ecal_layer_pattern");
+
+  int Ecal_end_of_slab_strategy             = theDetector.constant<int>("Ecal_end_of_slab_strategy");
+
+  int Ecal_cells_across_megatile            = theDetector.constant <int> ("Ecal_cells_across_megatile" );
+  int Ecal_strips_across_megatile           = theDetector.constant <int> ("Ecal_strips_across_megatile");
+  int Ecal_strips_along_megatile            = theDetector.constant <int> ("Ecal_strips_along_megatile" );
+
+  float Ecal_plugLength = 0.;
+  try {
+    Ecal_plugLength = theDetector.constant<double>("Ecal_Slab_Plug_length"); 
+  } catch (std::runtime_error&e) {
+    cout << "SEcal05_Barrel: Ecal_plugLength not found, using " << Ecal_plugLength << endl;    
+  }
+
+  //---------------------------------
+
+  // set up the helper, which will make a module for us
+
+  SEcal05_Helpers helper;
+  helper.setDet( & x_det );
+
+  //   absorber layer structure
+  helper.setPreshower( Ecal_Barrel_PreshowerLayer );
+
+  cout << "SEcal05_Barrel: Preshower ? " << Ecal_Barrel_PreshowerLayer << endl;
+
+  helper.setAbsLayers( Ecal_nlayers1, Ecal_radiator_thickness1,
+                       Ecal_nlayers2, Ecal_radiator_thickness2,
+                       Ecal_nlayers3, Ecal_radiator_thickness3 );
+
+  cout << "SEcal05_Barrel: absorber layers " << 
+    Ecal_nlayers1 << "*" << Ecal_radiator_thickness1/dd4hep::mm << " mm + " <<
+    Ecal_nlayers2 << "*" << Ecal_radiator_thickness2/dd4hep::mm << " mm + " <<
+    Ecal_nlayers3 << "*" << Ecal_radiator_thickness3/dd4hep::mm << " mm " << endl;
+
+  helper.checkLayerConsistency();
+
+  // structural CF thicknesses
+  helper.setCFthickness( Ecal_fiber_thickness_structure,  // was N_FIBERS_W_STRUCTURE*Ecal_fiber_thickness, : updated DJ
+			 Ecal_fiber_thickness_alveolus,   //     N_FIBERS_ALVEOLUS*Ecal_fiber_thickness,
+                         Ecal_front_face_thickness,
+                         Ecal_support_thickness);
+
+  helper.setPlugLength( Ecal_plugLength );
+
+  // check resulting thickness is consistent with what's in compact description
+  float module_thickness = helper.getTotalThickness();
+  if ( fabs( Ecal_barrel_thickness - module_thickness ) > 0.01 ) {
+    cout << "ERROR SEcal05_Barrel : ECAL barrel thickness in comapct decription not consistent with what I calculate!" << endl;
+    cout << "    calculated = " << module_thickness << "    compact description: " << Ecal_barrel_thickness << endl;
+    assert( 0 ); // exit
+  }
+
+  cout << "SEcal05_Barrel : module thickness = " << module_thickness << endl;
+
+  // set up the sensitive layer segmentation
+
+  Readout readout = sens.readout();
+  Segmentation seg = readout.segmentation();
+  helper.setSegmentation( &seg );
+
+  helper.setNCells( Ecal_cells_across_megatile, Ecal_strips_across_megatile, Ecal_strips_along_megatile);
+  helper.setMagicMegatileStrategy ( Ecal_end_of_slab_strategy );
+
+  // layer configuration
+  int ntemp;
+  stringstream stream(Ecal_layerConfig);
+  std::vector < int > layerConfig;
+  while ( stream >> ntemp ) {
+    assert (ntemp>=0 );
+    layerConfig.push_back( ntemp );
+  }
+  cout << "SEcal05_Barrel : layer config: ";
+  for (size_t i=0; i<layerConfig.size(); i++) cout << layerConfig[i] << " ";
+  cout << endl;
+
+  helper.setLayerConfig( layerConfig );
+
+
+  // set the alveolar structure
+
+  // get width of alveolus
+  double Ecal_Barrel_module_dim_z = 2 * Ecal_Barrel_halfZ / Ecal_barrel_z_modules ;
+  double alv_width = ( Ecal_Barrel_module_dim_z - 2.*Ecal_lateral_face_thickness ) / Ecal_barrel_number_of_towers;
+
+  cout << "SEcal05_Barrel : width of module, alveolus = " << Ecal_Barrel_module_dim_z << " " << alv_width << endl;
+
+  std::vector < int > ntowers; ntowers.push_back(Ecal_barrel_number_of_towers);
+
+  helper.setTowersUnits( ntowers,
+			 alv_width,
+			 Ecal_n_wafers_per_tower,
+			 Ecal_lateral_face_thickness,
+			 Ecal_fiber_thickness_alveolus + Ecal_Slab_H_fiber_thickness + Ecal_Slab_shielding,
+                         Ecal_guard_ring_size );
+
+  // shape of barrel module
+  // to get alignment as in ECAL interface design doc fig10
+  double module_thickness_noSupport = module_thickness - Ecal_support_thickness;
+
+  //  double max_dim_x    = 2. * tan(M_PI/8.) * Ecal_inner_radius + module_thickness_noSupport/sin(M_PI/4.); // longest side assumes oct
+  //  double min_dim_x = max_dim_x - 2*module_thickness; // shorter one (assumes octagon)
+
+  //  double max_dim_x    = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness_noSupport / tan( 2*M_PI/nsides );  // longest side 
+  double max_dim_x    = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness_noSupport / sin( 2*M_PI/nsides );  // longest side : fix DJeans 03/2017
+  double min_dim_x = max_dim_x - 2*module_thickness/tan( 2*M_PI/nsides ) ; // shorter one
+
+  if ( min_dim_x<0 || max_dim_x<0 ) {
+    std::cout << "SEcal05_Barrel ERROR : requesting too many sides! barrel modules have max/min extent " << max_dim_x << " " << min_dim_x << std::endl;
+    std::cout << "exiting" << std::endl;
+    assert(0); // exit gracefully
+  }
+
+  Trapezoid trd(max_dim_x / 2,
+                min_dim_x / 2,
+                Ecal_Barrel_module_dim_z / 2,
+                Ecal_Barrel_module_dim_z / 2,
+                module_thickness/2);
+
+  Volume mod_vol(det_name+"_module", trd, carbon_fibre); // DJeans 5-sep-2016
+
+  //========== fill data for reconstruction ============================
+  LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
+
+  helper.setModuleDimensions( 0, // int XYtype, // module shape in XY
+                              1, // int XZtype, // module shape in XZ
+                              max_dim_x, // double dX_max, // maximum extent in X
+			      -999, // dummy
+			      2.*M_PI/nsides
+                              );
+
+  // traslation to get layers within the envelope
+  helper.setTranslation ( Position ( -max_dim_x/2. , -Ecal_Barrel_module_dim_z/2., -module_thickness/2. ) );
+
+  // make the module
+
+  helper.makeModule( mod_vol, stave_det,
+		     *caloData,
+		     theDetector, sens );
+
+  for (size_t i=0; i<caloData->layers.size(); i++) {
+    caloData->layers[i].distance += Ecal_inner_radius; // add IP->front face distance
+  }
+
+  //  cout << "SEcal05_Barrel : cell sizes: " << endl;
+  //  for (size_t i=0; i<caloData->layers.size(); i++) {
+  //    cout << "sensitive layer " << i << " : x,y = " << caloData->layers[i].cellSize0 << " " << caloData->layers[i].cellSize1 << endl;
+  //  }
+
+  // ------------- create extension objects for reconstruction -----------------
+
+  caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
+  caloData->inner_symmetry = nsides  ;
+  caloData->outer_symmetry = nsides  ;
+  caloData->phi0 = 0 ; // hardcoded
+
+  // extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
+  caloData->extent[0] = Ecal_inner_radius ;
+  caloData->extent[1] = ( Ecal_inner_radius + module_thickness );
+  caloData->extent[2] = 0. ;
+  caloData->extent[3] = Ecal_Barrel_halfZ ;
+  //-------------------------------------------------------
+
+  //====================================================================
+  // Place ECAL Barrel stave module into the envelope volume
+  //====================================================================
+
+  double X = Ecal_inner_radius + module_thickness / 2.;
+
+  // altered to get alignment as in ECAL interface design doc fig10
+  //   end of slabs aligned to inner face of support plate in next stave (not the outer surface)
+  // double Y = (module_thickness/2.) / sin(M_PI/4.);
+  double Y = (module_thickness_noSupport/2.) / sin(2.*M_PI/nsides);
+
+  // stave numbering from 1->8
+  //   stave = 1 is in +ve x direction
+  //   stave = 3 is in +ve y direction (ie at top of barrel)
+  // module index from 1->5
+  //   module = 1 is at -ve z
+
+  for (int istave = 0; istave < nsides ; istave++) {
+    //for (int istave = 0; istave < 1 ; istave++) {
+    int stave_id = istave+1;
+
+    // dstave is the change in stave index from the top module to the one with smallest positive phi (which has istave=0)
+    int dstave = int( nsides/4. );
+
+
+    // rotations around the center to get the modules in the correct orientation
+    // top module (dstave) shits by hphi + pi/4
+    double phirot =  hphi + M_PI/2.; // 
+    phirot += (istave - dstave)*dphi;
+
+
+    // this angle is used to get the stave in the right position wrt the origin
+    double phirot2 =  (istave - dstave ) * dphi + hphi;
+
+    for (int imodule = 0; imodule < Ecal_barrel_z_modules; imodule++) {
+      int module_id = imodule+1;
+      Transform3D tr( RotationZYX( 0 , phirot, M_PI/2.),  // magic rotation!
+                      Translation3D(
+                                    ( X*cos(phirot2)-Y*sin(phirot2) ) ,
+                                    ( X*sin(phirot2)+Y*cos(phirot2) ) ,
+                                    ( imodule+0.5 )*Ecal_Barrel_module_dim_z - Ecal_Barrel_halfZ )
+                      );
+      PlacedVolume pv = envelope.placeVolume(mod_vol,tr);
+      pv.addPhysVolID("module",module_id);
+      pv.addPhysVolID("stave",stave_id);
+
+      DetElement sd = (imodule==0 && istave==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d"));
+      sd.setPlacement(pv);
+      sdet.add(sd);
+    }
+  }
+
+  // Set envelope volume attributes.
+  envelope.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+
+  sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
+
+  //  cout << "finished SEcal05_Barrel" << endl;
+
+  return sdet;
+}
+
+DECLARE_DETELEMENT(SEcal05_Barrel,create_detector)
diff --git a/Detector/DetCEPCv4/src/calorimeter/SEcal05_ECRing.cpp b/Detector/DetCEPCv4/src/calorimeter/SEcal05_ECRing.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9499c1facf20346c61a4a6058ad21b28316f2e13
--- /dev/null
+++ b/Detector/DetCEPCv4/src/calorimeter/SEcal05_ECRing.cpp
@@ -0,0 +1,689 @@
+//====================================================================
+//  lcgeo - LC detector models in DD4hep
+//--------------------------------------------------------------------
+//  DD4hep Geometry driver for SiWEcalEndcaps
+//  Ported from Mokka
+//--------------------------------------------------------------------
+//  S.Lu, DESY
+//  $Id$
+//====================================================================
+
+/* History:
+
+// *******************************************************
+// *                                                     *
+// *                      Mokka                          *
+// *   - the detailed geant4 simulation for ILC   -      *
+// *                                                     *
+// * For more information about Mokka, visit the         *
+// *                                                     *
+// *  Mokka.in2p3.fr  Mokka home page.                   *
+// *                                                     *
+// *******************************************************
+//
+// $Id$
+// $Name: mokka-07-00 $
+//
+//
+//
+// SEcal04.cc
+//
+Shaojun Lu:  Ported from Mokka SEcal04 Endcaps part. Read the constants from XML
+instead of the DB. Then build the Endcap in the same way with DD4hep
+construct.
+Inside SEcal04, some parameters, which used by Ecal Endcaps, come from
+Ecal Barrel. They can be seen here again.
+Start ECRing ...
+*/
+
+
+/*
+
+  ==============
+  SEcal05_ECRing
+  ===============
+  SEcal04_ECRing driver originally assumend 2 identical modules in +/- z
+  this is not true, because lumical (and therefore hole in EC plug) is not centred, but offset in +z position
+
+  SEcal05_ECRing driver corrects this (applies offset according to the crossing algle, to center it on the outgoing beampipe).
+  it also deals with the presence or not of a preshower layer
+
+  this is a hack of the 04 version, not a clean rewrite as was done for barrel and endcap, so it's not very clean & tidy....but I think it works
+
+  DJeans jan 2017
+
+  ========
+
+
+  - fixed dd4hep::rec::LayeredCalorimeterData for case with no preshower
+  - small fixes to layer thicknesses (now take from compact description) to get exactly same structure as main endcaps
+
+  DJeans July 2017
+
+
+  ======
+
+  - fixes to LayeredCalorimeterData: "distance" defined to start of layer, some other issues
+  - fix to use correct absorber thickness at transition between stacks
+  - LayeredCalorimeterData material describtion: overall structure made in CF (previously air)
+
+  DJeans Sep 2017
+
+*/
+
+
+#include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/DetType.h"
+#include "XML/Layering.h"
+#include "XML/Utilities.h"
+#include "DDRec/DetectorData.h"
+
+using namespace std;
+
+using dd4hep::BUILD_ENVELOPE;
+using dd4hep::Box;
+using dd4hep::DetElement;
+using dd4hep::Detector;
+using dd4hep::Layering;
+using dd4hep::Material;
+using dd4hep::PlacedVolume;
+using dd4hep::Position;
+using dd4hep::Readout;
+using dd4hep::Ref_t;
+using dd4hep::Rotation3D;
+using dd4hep::RotationZYX;
+using dd4hep::Segmentation;
+using dd4hep::SensitiveDetector;
+using dd4hep::SubtractionSolid;
+using dd4hep::Transform3D;
+using dd4hep::Tube;
+using dd4hep::Volume;
+using dd4hep::_toString;
+
+using dd4hep::rec::LayeredCalorimeterData;
+
+//#define VERBOSE 1
+
+// workaround for DD4hep v00-14 (and older)
+#ifndef DD4HEP_VERSION_GE
+#define DD4HEP_VERSION_GE(a,b) 0
+#endif
+
+static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
+  static double tolerance = 0e0;
+
+  cout << "---------------------------------" << endl;
+  cout << " creating Ecal ECRing ( SEcal05_ECRing ) " << endl;
+  cout << "---------------------------------" << endl;
+
+  xml_det_t     x_det     = element;
+  string        det_name  = x_det.nameStr();
+  Layering      layering (element);
+
+  Material      air       = theDetector.air();
+  Material      CF        = theDetector.material("CarbonFiber");
+
+  int           det_id    = x_det.id();
+  xml_comp_t    x_staves  = x_det.staves();
+  DetElement    sdet      (det_name,det_id);
+
+  // --- create an envelope volume and position it into the world ---------------------
+
+  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
+
+  dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
+
+  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
+
+  //-----------------------------------------------------------------------------------
+
+  sens.setType("calorimeter");
+
+  Material stave_material  = theDetector.material(x_staves.materialStr());
+
+  Readout readout = sens.readout();
+  Segmentation seg = readout.segmentation();
+
+  std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
+  double cell_sizeX      = cellSizeVector[0];
+  double cell_sizeY      = cellSizeVector[1];
+
+  //====================================================================
+  //
+  // Read all the constant from ILD_o1_v05.xml
+  // Use them to build Ecal ECRing
+  //
+  //====================================================================
+
+  //  read parametere from compact.xml file
+  double Ecal_fiber_thickness_alveolus      = theDetector.constant<double>("Ecal_fiber_thickness_alveolus");
+  double Ecal_fiber_thickness_structure     = theDetector.constant<double>("Ecal_fiber_thickness_structure");
+
+  double Ecal_radiator_thickness1           = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness");
+  double Ecal_radiator_thickness2           = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness");
+  double Ecal_radiator_thickness3           = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
+  double Ecal_Barrel_halfZ                  = theDetector.constant<double>("Ecal_Barrel_halfZ");
+
+  double Ecal_support_thickness             = theDetector.constant<double>("Ecal_support_thickness");
+  double Ecal_front_face_thickness          = theDetector.constant<double>("Ecal_front_face_thickness");
+  double Ecal_lateral_face_thickness        = theDetector.constant<double>("Ecal_lateral_face_thickness");
+
+  double Ecal_EC_Ring_gap                   = theDetector.constant<double>("Ecal_EC_Ring_gap");
+
+  double Ecal_cables_gap                    = theDetector.constant<double>("Ecal_cables_gap");
+  double Lcal_outer_radius                  = theDetector.constant<double>("Lcal_outer_radius");
+  double Ecal_Lcal_ring_gap                 = theDetector.constant<double>("Ecal_Lcal_ring_gap");
+  double Ecal_endcap_center_box_size        = theDetector.constant<double>("Ecal_endcap_center_box_size");
+
+  int    Ecal_nlayers1                      = theDetector.constant<int>("Ecal_nlayers1");
+  int    Ecal_nlayers2                      = theDetector.constant<int>("Ecal_nlayers2");
+  int    Ecal_nlayers3                      = theDetector.constant<int>("Ecal_nlayers3");
+
+  double      EcalEndcapRing_inner_radius   = theDetector.constant<double>("EcalEndcapRing_inner_radius");
+  double      EcalEndcapRing_outer_radius   = theDetector.constant<double>("EcalEndcapRing_outer_radius");
+  double      EcalEndcapRing_min_z          = theDetector.constant<double>("EcalEndcapRing_min_z");
+  double      EcalEndcapRing_max_z          = theDetector.constant<double>("EcalEndcapRing_max_z");
+
+
+  double      crossing_angle = theDetector.constant<double>("CepC_Main_Crossing_Angle");
+  bool        Ecal_Barrel_PreshowerLayer         = theDetector.constant<int>("Ecal_Barrel_Preshower") > 0;
+
+  double      Ecal_barrel_thickness         = theDetector.constant<double>("Ecal_barrel_thickness");
+
+  //========== fill data for reconstruction ============================
+  dd4hep::rec::LayeredCalorimeterData* caloData = new dd4hep::rec::LayeredCalorimeterData ;
+  caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::EndcapLayout ;
+  caloData->inner_symmetry = 0  ; // hard code cernter pipe hole
+  caloData->outer_symmetry = 4  ; // outer box
+  caloData->phi0 = 0 ;
+
+  /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
+  caloData->extent[0] = EcalEndcapRing_inner_radius ;
+  caloData->extent[1] = EcalEndcapRing_outer_radius ;
+  caloData->extent[2] = EcalEndcapRing_min_z ;
+  caloData->extent[3] = EcalEndcapRing_max_z ;
+
+
+  //====================================================================
+  //
+  // general calculated parameters
+  //
+  //====================================================================
+
+  int Number_of_Si_Layers_in_Barrel = 0;
+
+#ifdef VERBOSE
+  std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel  << std::endl;
+#endif
+
+  int n_total_layers = Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3;
+  Number_of_Si_Layers_in_Barrel = n_total_layers; // take account of preshower on/off (djeans)
+  if ( Ecal_Barrel_PreshowerLayer ) Number_of_Si_Layers_in_Barrel++;
+
+  // calculate total thickness of ECAL
+  // updated to take info from xml description - djeans: 12 July 2017
+  double module_thickness = Ecal_support_thickness + Ecal_front_face_thickness;// front and back supports
+
+  // the absorber in the structure
+  for (int i=0; i<Ecal_nlayers1+Ecal_nlayers2+Ecal_nlayers3; i++) {
+    bool inStructure = Ecal_Barrel_PreshowerLayer==1 ? i%2==1 : i%2==0 ;
+    if ( inStructure ) {
+      double thickness (Ecal_radiator_thickness1);
+      if ( i>=Ecal_nlayers1 ) thickness = Ecal_radiator_thickness2;
+      if ( i>=Ecal_nlayers1+Ecal_nlayers2 ) thickness = Ecal_radiator_thickness3;
+      module_thickness += thickness + 2*Ecal_fiber_thickness_structure; // the absorber and its wrapping
+    }
+  }
+
+  // the slabs
+  int l_num2(0);
+  for(xml_coll_t li(x_det,_U(layer)); li; ++li)  { // types of layers (i.e. thin/thick absorber) or "stack"
+    xml_comp_t x_layer = li;
+    // Loop over number of repeats for this layer.
+    for (int j=0; j< x_layer.repeat(); j++)    {  // layers within this type (or "stack")
+      float thisthick = layering.layer(l_num2)->thickness();
+      module_thickness+=thisthick + 2*Ecal_fiber_thickness_alveolus; // slab thickness, and the alveolar wall around it
+      l_num2++;
+    }
+  }
+
+
+  if ( fabs( Ecal_barrel_thickness - module_thickness) > 0.1 ) {
+    cout << "ERROR EC ecal thickness inconsistency: calculated, nominal = " << module_thickness << " " << Ecal_barrel_thickness << endl;
+    assert(0);
+  }
+
+#ifdef VERBOSE
+  std::cout << " module_thickness = " << module_thickness  << std::endl;
+#endif
+
+
+  double ECRingSiplateSize = Ecal_endcap_center_box_size
+    - 2 * Ecal_EC_Ring_gap
+    - 2 * Ecal_lateral_face_thickness;
+
+
+  // central hole is not centred on detector axis, but on outgoing beampipe (as is the lumical)
+  double hole_x_offset = tan(crossing_angle/2.) * (EcalEndcapRing_min_z + EcalEndcapRing_max_z)/2.;
+
+
+  // ========= Create Ecal end cap ring   ====================================
+  //  It will be the volume for palcing the Ecal endcaps alveolus(i.e. Layers).
+  //  And the structure W plate.
+  //  Itself will be placed into the world volume.
+  // ==========================================================================
+
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  //~              EndcapRing                           ~
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  for(int module_num=0;module_num<2;module_num++) { // move module loop to here (modules not identical)
+
+    DetElement    module_det(_toString(module_num,"module%d"),det_id);
+
+    double thismodule_hole_dx = hole_x_offset;
+    if ( module_num==0 ) thismodule_hole_dx*=-1;
+    Position hole_position(thismodule_hole_dx, 0, 0);
+
+    double Ecal_endcap_Tube_rmax = Lcal_outer_radius + Ecal_Lcal_ring_gap;
+
+    Tube CenterECTub(0., Ecal_endcap_Tube_rmax, module_thickness);
+    Box  CenterECBox((Ecal_endcap_center_box_size/2. - Ecal_EC_Ring_gap),
+                     (Ecal_endcap_center_box_size/2. - Ecal_EC_Ring_gap),
+                     module_thickness/2.);
+
+    SubtractionSolid ECRingSolid( CenterECBox, CenterECTub, hole_position);
+
+    //  Volume EnvLogECRing("ECRing",ECRingSolid,theDetector.material("g10"));
+    Volume EnvLogECRing("ECRing",ECRingSolid,theDetector.material("CarbonFiber")); // DJeans 5-sep-2016
+
+    //==============================================================
+    // build the layer and place into the ECRing
+    //==============================================================
+
+
+    //-------------------------------------------------------
+    // Radiator and towers placements inside the ECRing module
+    //-------------------------------------------------------
+
+    // We count the layers starting from IP and from 1,
+    // so odd layers should be inside slabs and
+    // even ones on the structure.
+    //
+
+
+    double distance_ip_to_front_face = Ecal_Barrel_halfZ + Ecal_cables_gap;
+    double dist_from_front_face_tally(0);
+
+    double z_floor =  - module_thickness/2;
+
+    double l_pos_z = z_floor;
+
+    dd4hep::rec::LayeredCalorimeterData::Layer caloLayer ;
+    caloLayer.cellSize0 = cell_sizeX;
+    caloLayer.cellSize1 = cell_sizeY;
+
+    //-------------------- start loop over ECAL layers ----------------------
+    // Loop over the sets of layer elements in the detector.
+    double radiator_dim_y = Ecal_radiator_thickness1; //to be updated with slice radiator thickness
+
+    double nRadiationLengths=0.;
+    double nInteractionLengths=0.;
+    double thickness_sum=0;
+
+    int l_num = 1;
+    bool isFirstSens = true;
+    int myLayerNum = 0 ;
+    bool isFrontFace=true;
+    int absorber_index(0);
+
+    for(xml_coll_t li(x_det,_U(layer)); li; ++li)  { // types of layer
+      xml_comp_t x_layer = li;
+      int repeat = x_layer.repeat();
+
+      // Loop over number of repeats for this layer.
+      for (int j=0; j<repeat; j++)    {
+
+        // move structural layer to before the slabs - djeans
+
+        // deal with preshower or lack thereof ------------------
+        double radiator_dim_Z(0);
+        //double rad_pos_Z(0);
+        double this_struct_CFthick_beforeAbs(0);
+        double this_struct_CFthick_afterAbs(0);
+        double _CF_absWrap = Ecal_fiber_thickness_structure;
+        double _CF_alvWall = Ecal_fiber_thickness_alveolus;
+        if ( isFrontFace ) { // the first part of the module depends on whether we have preshwer or not
+          if ( Ecal_Barrel_PreshowerLayer==1 ) { // don't include W+CF wrapping; only one side of alveolus
+            this_struct_CFthick_beforeAbs = 0;
+            this_struct_CFthick_afterAbs = Ecal_front_face_thickness + _CF_alvWall;
+            radiator_dim_Z = 0;
+          } else { // include W+CF wrapping; only one side of alveolus
+            this_struct_CFthick_beforeAbs = Ecal_front_face_thickness + _CF_absWrap;
+            this_struct_CFthick_afterAbs = _CF_absWrap + _CF_alvWall;
+            radiator_dim_Z = Ecal_radiator_thickness1; // this line implicitly assumes Ecal_nlayers1>0...
+            //rad_pos_Z = radiator_dim_Z/2. + this_struct_CFthick_beforeAbs; // distance from top surface of structure to centre of radiator
+            absorber_index++;
+          }
+
+          thickness_sum       += radiator_dim_Z;
+          nRadiationLengths   += radiator_dim_Z/stave_material.radLength();
+          nInteractionLengths += radiator_dim_Z/stave_material.intLength();
+
+          thickness_sum       += ( this_struct_CFthick_beforeAbs + this_struct_CFthick_afterAbs );
+          nRadiationLengths   += ( this_struct_CFthick_beforeAbs + this_struct_CFthick_afterAbs ) / CF.radLength();
+          nInteractionLengths += ( this_struct_CFthick_beforeAbs + this_struct_CFthick_afterAbs ) / CF.intLength();
+
+          isFrontFace=false;
+        } else { // internal layer: include W+CF wrapping; both sides of alveolus
+          this_struct_CFthick_beforeAbs = _CF_alvWall+_CF_absWrap;
+          this_struct_CFthick_afterAbs = _CF_alvWall+_CF_absWrap;
+
+          if ( absorber_index<Ecal_nlayers1 ) radiator_dim_Z=Ecal_radiator_thickness1;
+          else if ( absorber_index<Ecal_nlayers1+Ecal_nlayers2 ) radiator_dim_Z=Ecal_radiator_thickness2;
+          else if ( absorber_index<Ecal_nlayers1+Ecal_nlayers2+Ecal_nlayers3 ) radiator_dim_Z=Ecal_radiator_thickness3;
+          else {
+            assert(0 && "ERROR cannot determine absorber thickness for layer ");
+          }
+
+          absorber_index++;
+
+          assert( radiator_dim_Z>0 && "no radiator!" );
+        }
+        //-------------------------------
+
+        radiator_dim_y = radiator_dim_Z; // ahh different axis conventions....
+
+        l_pos_z += this_struct_CFthick_beforeAbs + radiator_dim_y/2;
+
+        // #########################
+        // BuildECRingStructureLayer
+        // #########################
+
+        Tube CenterECTubForSi(0.,
+                              Lcal_outer_radius + Ecal_Lcal_ring_gap + 0.001, // + tolerance,
+                              module_thickness,
+                              0.,
+                              2 * M_PI);
+
+
+        string l_name = _toString(l_num,"layer%d");
+        RotationZYX rot(0,0,0); // a null rotation
+
+        if ( radiator_dim_y>0 ) {
+
+          string bs_name="bs";
+          Box        EndcapStructureLayer_box(ECRingSiplateSize/ 2. - tolerance, ECRingSiplateSize/ 2. - tolerance, radiator_dim_y/2.);
+          SubtractionSolid  EndcapStructureLayerSolid( EndcapStructureLayer_box, CenterECTubForSi, hole_position);
+          Volume     EndcapStructureLayer_vol(det_name+"_"+l_name+"_"+bs_name,EndcapStructureLayerSolid,theDetector.material(x_staves.materialStr()));
+          EndcapStructureLayer_vol.setVisAttributes(theDetector.visAttributes( x_staves.visStr()));
+
+          // this is where we place the tungsten into the envelope
+          double bsl_pos_z = l_pos_z;
+          Position   bsl_pos(0,0,bsl_pos_z);
+          Transform3D bsl_tran3D(rot,bsl_pos);
+          EnvLogECRing.placeVolume(EndcapStructureLayer_vol,bsl_tran3D);
+        }
+
+        // Increment to next layer Z position.
+        l_pos_z += radiator_dim_y/2 + this_struct_CFthick_afterAbs;
+
+        // now move to the alveolus and what's inside
+        double l_thickness = layering.layer(l_num-1)->thickness();  // Layer's thickness. this is the internal thickness of the alveolus
+
+        l_pos_z  += l_thickness/2.; // add in half the alveolus thickness
+
+        int EC_Number_of_towers = 0;
+
+        // We use the same method able to create the Barrel
+        // Slabs, so we have to rotate it later when placing
+        // into the EC modules.
+        //
+        // We use the same method able to create the Barrel
+        // radiator plates between slabs, but with the good
+        // dimensions to avoid to rotate it later when placing
+        // into the EC modules.
+
+        // While the towers have the same shape use the same
+        // logical volumes and parameters.
+
+        string tower_name = _toString(EC_Number_of_towers,"tower%d");
+
+        // build the ECRing layer, a box with hole in the middle
+        Box  ECRingSiBox( ECRingSiplateSize/ 2. - tolerance, ECRingSiplateSize/ 2. - tolerance, l_thickness/2.0-tolerance);
+
+        SubtractionSolid ECRingSiSolid( ECRingSiBox, CenterECTubForSi, hole_position);
+
+        Volume     l_vol(det_name+"_"+l_name+"_"+tower_name,ECRingSiSolid,air);
+        DetElement layer(module_det, l_name+tower_name, det_id);
+
+        l_vol.setVisAttributes(theDetector.visAttributes( x_layer.visStr() ));
+
+        // Loop over the sublayers or slices for this layer.
+        int s_num = 1;
+        double s_pos_z = -(l_thickness / 2);
+
+        //--------------------------------------------------------------------------------
+        // BuildECRing keep the Alveolus structure, the same as the Barrel and Endcap
+        //--------------------------------------------------------------------------------
+
+        for(xml_coll_t si(x_layer,_U(slice)); si; ++si)  {
+          xml_comp_t x_slice = si;
+          string     s_name  =  _toString(s_num,"slice%d");
+          double     s_thick = x_slice.thickness();
+          Material slice_material  = theDetector.material(x_slice.materialStr());
+
+          double slab_dim_x = ECRingSiplateSize/2.-tolerance;
+          double slab_dim_y = s_thick/2.-tolerance;
+          double slab_dim_z = ECRingSiplateSize/2.-tolerance;
+
+          Box        s_box(slab_dim_x,slab_dim_z,slab_dim_y);
+
+          SubtractionSolid ECRingSiSliceSolid( s_box, CenterECTubForSi, hole_position);
+
+          Volume     s_vol(det_name+"_"+l_name+"_"+s_name,ECRingSiSliceSolid,slice_material);
+          DetElement slice(layer,s_name,det_id);
+
+          s_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
+
+#ifdef VERBOSE
+          std::cout<<"x_slice.materialStr(): "<< x_slice.materialStr() <<std::endl;
+#endif
+          if (x_slice.materialStr().compare(x_staves.materialStr()) == 0){
+            radiator_dim_y = s_thick;
+
+            absorber_index++;
+
+#if DD4HEP_VERSION_GE( 0, 15 )
+            caloLayer.outer_nRadiationLengths   = nRadiationLengths;
+            caloLayer.outer_nInteractionLengths = nInteractionLengths;
+            caloLayer.outer_thickness           = thickness_sum;
+            caloLayer.distance                  = distance_ip_to_front_face + dist_from_front_face_tally;
+#endif
+            if (Ecal_Barrel_PreshowerLayer==0 || !isFirstSens ){ // add this layer to the caloData (unless its the first absorber layer of a no-preshower calo)
+              if ( module_num==0 ) {
+                caloData->layers.push_back( caloLayer ) ;
+#ifdef VERBOSE
+#if DD4HEP_VERSION_GE( 0, 15 )
+                std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl;
+                std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl;
+                std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl;
+                std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl;
+                std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl;
+                std::cout<<" caloLayer.cellSize0, 1: "             << caloLayer.cellSize0 << " " << caloLayer.cellSize1 << std::endl;
+                std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl;
+                std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl;
+                std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl;
+                std::cout<<" EcalECRing[1]==>caloLayer.inner_thickness + caloLayer.outer_thickness: "
+                         << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl;
+#endif
+#endif
+                dist_from_front_face_tally += caloLayer.inner_thickness+caloLayer.outer_thickness;
+              }
+            }
+
+            nRadiationLengths   = 0. ;
+            nInteractionLengths = 0. ;
+            thickness_sum       = 0. ;
+            isFirstSens         = false;
+          } // if radiator
+
+          nRadiationLengths   += s_thick/(2.*slice_material.radLength());
+          nInteractionLengths += s_thick/(2.*slice_material.intLength());
+          thickness_sum       += s_thick/2;
+
+          if ( x_slice.isSensitive() ) {
+            s_vol.setSensitiveDetector(sens);
+
+#if DD4HEP_VERSION_GE( 0, 15 )
+            //Store "inner" quantities
+            caloLayer.inner_nRadiationLengths   = nRadiationLengths;
+            caloLayer.inner_nInteractionLengths = nInteractionLengths;
+            caloLayer.inner_thickness           = thickness_sum;
+            //Store sensitive slice thickness
+            caloLayer.sensitive_thickness       = s_thick;
+#ifdef VERBOSE
+            std::cout<<" l_num: "<<l_num <<std::endl;
+            std::cout<<" s_num: "<<s_num <<std::endl;
+            std::cout<<" module_thickness: "<< module_thickness <<std::endl;
+            std::cout<<" l_pos_z: "<< l_pos_z <<std::endl;
+            std::cout<<" l_thickness: "<< l_thickness <<std::endl;
+            std::cout<<" s_pos_z: "<< s_pos_z <<std::endl;
+            std::cout<<" s_thick: "<< s_thick <<std::endl;
+            std::cout<<" radiator_dim_y: "<< radiator_dim_y <<std::endl;
+#endif
+            caloLayer.absorberThickness = radiator_dim_y ;
+#endif
+            nRadiationLengths   = 0. ;
+            nInteractionLengths = 0. ;
+            thickness_sum       = 0. ;
+          } // if sensitive
+
+          nRadiationLengths   += s_thick/(2.*slice_material.radLength());
+          nInteractionLengths += s_thick/(2.*slice_material.intLength());
+          thickness_sum       += s_thick/2;
+
+          slice.setAttributes(theDetector,s_vol,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
+
+          // Slice placement.
+          PlacedVolume slice_phv = l_vol.placeVolume(s_vol,Position(0,0,s_pos_z+s_thick/2));
+
+          if ( x_slice.isSensitive() ) {
+            slice_phv.addPhysVolID("layer", myLayerNum++);
+          }
+
+          slice.setPlacement(slice_phv);
+          // Increment Z position of slice.
+          s_pos_z += s_thick;
+
+          // Increment slice number.
+          ++s_num;
+        }
+
+        // add material between the "slabs"
+
+        // we need to use correct thickness here! especially at the interface between stacks.
+        if      ( absorber_index < Ecal_nlayers1 ) radiator_dim_y=Ecal_radiator_thickness1;
+        else if ( absorber_index < Ecal_nlayers1+Ecal_nlayers2 ) radiator_dim_y=Ecal_radiator_thickness2;
+        else if ( absorber_index < Ecal_nlayers1+Ecal_nlayers2+Ecal_nlayers3 ) radiator_dim_y=Ecal_radiator_thickness3;
+        else {
+          radiator_dim_y=0;
+        }
+	
+        // deal with final support plate
+        float cf_thick = Ecal_fiber_thickness_alveolus;
+        if ( absorber_index<Ecal_nlayers1+Ecal_nlayers2+Ecal_nlayers3 ) {
+          cf_thick += Ecal_fiber_thickness_structure;
+        } else {
+          cf_thick += Ecal_support_thickness;
+        }
+
+        if ( module_num==0 ) {
+#if DD4HEP_VERSION_GE( 0, 15 )
+          caloLayer.distance = distance_ip_to_front_face + dist_from_front_face_tally;
+          caloLayer.outer_nRadiationLengths   = nRadiationLengths + cf_thick/CF.radLength();
+          caloLayer.outer_nInteractionLengths = nInteractionLengths + cf_thick/CF.intLength();
+          caloLayer.outer_thickness           = thickness_sum + cf_thick;
+#endif
+          caloData->layers.push_back( caloLayer ) ;
+
+#ifdef VERBOSE
+#if DD4HEP_VERSION_GE( 0, 15 )
+          std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl;
+          std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl;
+          std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl;
+          std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl;
+          std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl;
+          std::cout<<" caloLayer.cellSize0, 1: "             << caloLayer.cellSize0 << " " << caloLayer.cellSize1 << std::endl;
+          std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl;
+          std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl;
+          std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl;
+
+          std::cout<<" EcalECRing[2]==>caloLayer.inner_thickness + caloLayer.outer_thickness: "
+                   << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl;
+#endif
+#endif
+          dist_from_front_face_tally += caloLayer.inner_thickness+caloLayer.outer_thickness;
+        }
+
+        nRadiationLengths   = radiator_dim_y/stave_material.radLength() + cf_thick/CF.radLength();
+        nInteractionLengths = radiator_dim_y/stave_material.intLength() + cf_thick/CF.intLength();
+        thickness_sum       = radiator_dim_y + cf_thick;
+
+        // this is where we place the slab (l_vol) into the envelope
+        int i_stave = 1;
+        int i_tower = 1;
+        Position l_pos(0,0,l_pos_z);
+        Transform3D tran3D(rot,l_pos);
+        PlacedVolume layer_phv = EnvLogECRing.placeVolume(l_vol,tran3D);
+        layer_phv.addPhysVolID("tower", i_tower);
+        layer_phv.addPhysVolID("stave", i_stave);
+        layer.setPlacement(layer_phv);
+
+        l_pos_z +=   l_thickness/2.; // add in the other half of the alveolus
+
+        ++l_num;
+
+      }
+    }
+
+
+    // Set stave visualization.
+    if (x_staves)   {
+      EnvLogECRing.setVisAttributes(theDetector.visAttributes(x_staves.visStr()));
+    }
+
+
+    //====================================================================
+    // Place Ecal Endcap module into the assembly envelope volume
+    //====================================================================
+
+    double EC_module_z_offset = (EcalEndcapRing_min_z + EcalEndcapRing_max_z)/2.;
+
+    int module_id = ( module_num == 0 ) ? 0:6;
+    double this_module_z_offset = ( module_id == 0 ) ? - EC_module_z_offset : EC_module_z_offset;
+    double this_module_rotY = ( module_id == 0 ) ? M_PI:0;
+
+    Position xyzVec(0,0,this_module_z_offset);
+    RotationZYX rot(0,this_module_rotY,0);
+    Rotation3D rot3D(rot);
+    Transform3D tran3D(rot3D,xyzVec);
+
+    PlacedVolume pv = envelope.placeVolume(EnvLogECRing,tran3D);
+    pv.addPhysVolID("module",module_id); // z: -/+ 0/6
+
+    DetElement sd = module_det;
+    sd.setPlacement(pv);
+
+  }
+
+  sdet.addExtension< dd4hep::rec::LayeredCalorimeterData >( caloData ) ;
+
+  return sdet;
+
+}
+
+
+
+DECLARE_DETELEMENT(SEcal05_ECRing, create_detector)
+
diff --git a/Detector/DetCEPCv4/src/calorimeter/SEcal05_Endcaps.cpp b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Endcaps.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0f4c69ab8d19f05f2380a693f4549bbcf8dc8f5
--- /dev/null
+++ b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Endcaps.cpp
@@ -0,0 +1,390 @@
+//====================================================================
+//  lcgeo - LC detector models in DD4hep 
+//--------------------------------------------------------------------
+//  DD4hep Geometry driver for SiWEcalEndcaps
+//  Ported from Mokka
+//--------------------------------------------------------------------
+//  S.Lu, DESY
+//  $Id: SEcal04_Endcaps.cpp 1060 2016-09-05 07:48:41Z /C=JP/O=KEK/OU=CRC/CN=JEANS Daniel Thomelin Dietrich $
+//====================================================================
+
+ /* History:  
+  
+// *******************************************************
+// *                                                     *
+// *                      Mokka                          * 
+// *   - the detailed geant4 simulation for ILC   -      *
+// *                                                     *
+// * For more information about Mokka, visit the         *
+// *                                                     *
+// *  Mokka.in2p3.fr  Mokka home page.                   *
+// *                                                     *
+// *******************************************************
+//
+// $Id: SEcal04_Endcaps.cpp 1060 2016-09-05 07:48:41Z /C=JP/O=KEK/OU=CRC/CN=JEANS Daniel Thomelin Dietrich $
+// $Name: mokka-07-00 $
+//
+// 
+//
+// SEcal04.cc
+//
+   Shaojun Lu:  Ported from Mokka SEcal04 Endcaps part. Read the constants from XML
+                instead of the DB. Then build the Endcap in the same way with DD4hep
+		construct.
+		Inside SEcal04, some parameters, which used by Ecal Endcaps, come from
+		Ecal Barrel. They can be ssen here again.
+ */
+
+#include "DD4hep/DetFactoryHelper.h"
+#include "XML/Layering.h"
+#include "DD4hep/Shapes.h"
+#include "XML/Utilities.h"
+#include "DDRec/DetectorData.h"
+#include "DDSegmentation/WaferGridXY.h"
+#include <sstream>
+
+using namespace std;
+
+using dd4hep::BUILD_ENVELOPE;
+using dd4hep::Box;
+using dd4hep::DetElement;
+using dd4hep::Detector;
+using dd4hep::IntersectionSolid;
+using dd4hep::Layering;
+using dd4hep::Material;
+using dd4hep::PlacedVolume;
+using dd4hep::PolyhedraRegular;
+using dd4hep::Position;
+using dd4hep::Readout;
+using dd4hep::Ref_t;
+using dd4hep::Rotation3D;
+using dd4hep::RotationZYX;
+using dd4hep::Segmentation;
+using dd4hep::SensitiveDetector;
+using dd4hep::Transform3D;
+using dd4hep::Volume;
+using dd4hep::_toString;
+
+using dd4hep::rec::LayeredCalorimeterData;
+
+#include "SEcal05_Helpers.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+
+//#define VERBOSE 1
+
+// workaround for DD4hep v00-14 (and older) 
+#ifndef DD4HEP_VERSION_GE
+#define DD4HEP_VERSION_GE(a,b) 0 
+#endif
+
+static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
+
+  cout << "------------------------" << endl;
+  cout << "creating SEcal05_Endcaps" << endl;
+  cout << "------------------------" << endl;
+
+  xml_det_t     x_det     = element;
+  string        det_name  = x_det.nameStr();
+  Layering      layering (element);
+
+  int           det_id    = x_det.id();
+  //  xml_comp_t    x_staves  = x_det.staves();
+  DetElement    sdet      (det_name,det_id);
+  //  Volume        motherVol = theDetector.pickMotherVolume(sdet);
+
+  // --- create an envelope volume and position it into the world ---------------------
+
+  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
+
+  dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
+
+  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
+  //-----------------------------------------------------------------------------------
+
+  sens.setType("calorimeter");
+
+  Readout readout = sens.readout();
+  Segmentation seg = readout.segmentation();
+
+  //====================================================================
+  //
+  // Read all the constant from ILD_o1_v05.xml
+  // Use them to build Ecal endcaps
+  //
+  //====================================================================
+  
+  //  read parameters from compact.xml file
+  double Ecal_Slab_shielding                = theDetector.constant<double>("Ecal_Slab_shielding");
+  double Ecal_fiber_thickness_structure = theDetector.constant<double>("Ecal_fiber_thickness_structure"); // absorber wrapping thickness
+  double Ecal_fiber_thickness_alveolus  = theDetector.constant<double>("Ecal_fiber_thickness_alveolus"); // alveolar wall thickness
+  
+  double EcalBarrel_inner_radius                  = theDetector.constant<double>("TPC_outer_radius") +theDetector.constant<double>("Ecal_Tpc_gap");
+  int    Ecal_barrel_z_modules              = theDetector.constant<int>("Ecal_barrel_z_modules");
+
+  double Ecal_radiator_thickness1           = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness");
+  double Ecal_radiator_thickness2           = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness");
+  double Ecal_radiator_thickness3           = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
+  double Ecal_Barrel_halfZ                  = theDetector.constant<double>("Ecal_Barrel_halfZ");
+
+  int    Ecal_barrel_number_of_towers       = theDetector.constant<int>("Ecal_barrel_number_of_towers");
+  
+  double Ecal_support_thickness             = theDetector.constant<double>("Ecal_support_thickness");
+  double Ecal_front_face_thickness          = theDetector.constant<double>("Ecal_front_face_thickness");
+  double Ecal_lateral_face_thickness        = theDetector.constant<double>("Ecal_lateral_face_thickness");
+  double Ecal_Slab_H_fiber_thickness        = theDetector.constant<double>("Ecal_Slab_H_fiber_thickness");
+
+  double Ecal_endcap_extra_size             = theDetector.constant<double>("Ecal_endcap_extra_size");
+  double Ecal_cables_gap                    = theDetector.constant<double>("Ecal_cables_gap");
+
+  int    Ecal_nlayers1                      = theDetector.constant<int>("Ecal_nlayers1");
+  int    Ecal_nlayers2                      = theDetector.constant<int>("Ecal_nlayers2");
+  int    Ecal_nlayers3                      = theDetector.constant<int>("Ecal_nlayers3");
+
+  // first layer is preshower?
+  bool   Ecal_Endcap_PreshowerLayer         = theDetector.constant<int>("Ecal_Endcap_Preshower") > 0;
+
+  std::string Ecal_endcap_number_of_towers       = theDetector.constant<string>("Ecal_endcap_number_of_towers");
+
+  int Ecal_end_of_slab_strategy             = theDetector.constant<int>("Ecal_end_of_slab_strategy");
+
+
+  int    Ecal_n_wafers_per_tower            = theDetector.constant<int>("Ecal_n_wafers_per_tower");
+  
+  double Ecal_guard_ring_size               = theDetector.constant<double>("Ecal_guard_ring_size");
+
+  double      EcalEndcap_inner_radius          = theDetector.constant<double>("EcalEndcap_inner_radius");
+  double      EcalEndcap_outer_radius          = theDetector.constant<double>("EcalEndcap_outer_radius");
+  double      EcalEndcap_min_z                 = theDetector.constant<double>("EcalEndcap_min_z");
+  double      EcalEndcap_max_z                 = theDetector.constant<double>("EcalEndcap_max_z");
+
+  std::string Ecal_layerConfig              = theDetector.constant<string>("Ecal_layer_pattern");
+
+  int Ecal_cells_across_megatile = theDetector.constant <int> ("Ecal_cells_across_megatile" );
+  int Ecal_strips_across_megatile= theDetector.constant <int> ("Ecal_strips_across_megatile");
+  int Ecal_strips_along_megatile = theDetector.constant <int> ("Ecal_strips_along_megatile" );
+
+  double Ecal_barrel_thickness              = theDetector.constant<double>("Ecal_barrel_thickness"); // what's assumed in the compact description
+ 
+
+  //====================================================================
+  //
+  // set up the helper
+  //
+  //====================================================================
+
+  SEcal05_Helpers helper;
+
+  helper.setDet( & x_det );
+
+  // layer configuration
+  helper.setPreshower( Ecal_Endcap_PreshowerLayer );
+
+  cout << "Preshower ? " << Ecal_Endcap_PreshowerLayer << endl;
+
+  helper.setAbsLayers( Ecal_nlayers1, Ecal_radiator_thickness1,
+                       Ecal_nlayers2, Ecal_radiator_thickness2,
+                       Ecal_nlayers3, Ecal_radiator_thickness3 );
+
+  cout << "absorber layers " <<
+    Ecal_nlayers1 << "*" << Ecal_radiator_thickness1 << "mm + " <<
+    Ecal_nlayers2 << "*" << Ecal_radiator_thickness2 << "mm + " <<
+    Ecal_nlayers3 << "*" << Ecal_radiator_thickness3 << "mm " << endl;
+
+  // check this setup is self-consistent
+  helper.checkLayerConsistency();
+
+  // set structural CF thicknesses
+  helper.setCFthickness( Ecal_fiber_thickness_structure,
+                         Ecal_fiber_thickness_alveolus,
+                         Ecal_front_face_thickness,
+                         Ecal_support_thickness);
+
+  // check that resulting total thickness is consistent with what's in the compact file
+  //   n.b. this assumes same thickness in barrel and endcap!
+  float module_thickness = helper.getTotalThickness();
+  if ( fabs( Ecal_barrel_thickness - module_thickness ) > 0.1*dd4hep::mm ) {
+    cout << "ERROR : thickness in comapct decription not consistent with what I calculate!" << endl;
+    cout << "    calculated = " << module_thickness << "    compact description: " << Ecal_barrel_thickness << endl;
+    assert( 0 ); // exit
+  }
+
+  cout << "module thickness = " << module_thickness << endl;
+
+  // set up the sensitive layer segmentation
+  helper.setSegmentation( &seg );
+
+  helper.setNCells( Ecal_cells_across_megatile, Ecal_strips_across_megatile, Ecal_strips_along_megatile);
+  helper.setMagicMegatileStrategy ( Ecal_end_of_slab_strategy );
+
+
+  int ntemp;
+  std::stringstream stream(Ecal_layerConfig);
+  std::vector < int > layerConfig;
+  while ( stream >> ntemp ) {
+    assert( ntemp>=0 );
+    layerConfig.push_back( ntemp );
+  }
+  cout << "layer config: ";
+  for (size_t i=0; i<layerConfig.size(); i++) cout << layerConfig[i] << " ";
+  cout << endl;
+
+  helper.setLayerConfig( layerConfig );
+
+  // set the number of towers/modules
+  std::vector < int > ntowers;
+  std::stringstream stream2( Ecal_endcap_number_of_towers );
+  while ( stream2 >> ntemp ) {
+    ntowers.push_back( ntemp );
+  }
+
+  cout << "ECAL endcap tower configuration " << Ecal_endcap_number_of_towers << " : ";
+  for (size_t i=0; i<ntowers.size(); i++) 
+    cout << ntowers[i] << " ";
+  cout << endl;
+
+  // check that resulting quadrant size is consistent with compact description
+  // here we assume that the width of an alveolus in the endcaps is the same as that in the barrel.
+  double barrel_alv_width    = ( Ecal_Barrel_halfZ*2./Ecal_barrel_z_modules - 2.*Ecal_lateral_face_thickness ) / Ecal_barrel_number_of_towers;
+  double calc_endcap_rout(EcalEndcap_inner_radius);
+  for (size_t i=0; i<ntowers.size(); i++) {
+    calc_endcap_rout+=ntowers[i]*barrel_alv_width + 2.*Ecal_lateral_face_thickness;
+  }
+
+  cout << "alveolus width = " << barrel_alv_width << endl;
+
+  //  compare calculated size vs that in compact description
+  if ( fabs( calc_endcap_rout - EcalEndcap_outer_radius ) > 0.1*dd4hep::mm ) {
+    cout << "WARNING, inconsistent ECAL endcap radial extent! calculated: " << calc_endcap_rout << 
+      " cm , nominal (from compact descrition): " << EcalEndcap_outer_radius << endl;
+    cout << "consider changing Ecal_endcap_extra_size from " << Ecal_endcap_extra_size << 
+      " to " << calc_endcap_rout - EcalBarrel_inner_radius - Ecal_barrel_thickness << endl;
+    assert(0);
+  }
+
+
+  helper.setTowersUnits( ntowers,
+			 barrel_alv_width,
+			 Ecal_n_wafers_per_tower,
+			 Ecal_lateral_face_thickness,
+                         Ecal_fiber_thickness_alveolus + Ecal_Slab_H_fiber_thickness + Ecal_Slab_shielding,
+			 Ecal_guard_ring_size );
+
+
+
+  // ========= Create Ecal endcaps   ====================================
+  //  It will be the volume for palcing the Ecal endcaps alveolus(i.e. Layers).
+  //  And the structure W plate.
+  //  Itself will be placed into the world volume.
+  // ==========================================================================
+
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  //~              EndcapStandardModule                 ~
+  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  // octagon
+  PolyhedraRegular ECPolyHedra(8, M_PI/8., 0., calc_endcap_rout, module_thickness);
+
+  // take just one quadrant of the octagon, and remove the centre box
+  double quadr = calc_endcap_rout; // anything which is big enough
+  Box quadrant( quadr, quadr , module_thickness);
+  IntersectionSolid EndCapSolid( ECPolyHedra, 
+				 quadrant,
+				 Position( quadr - EcalEndcap_inner_radius, 
+					   quadr + EcalEndcap_inner_radius, 0 ) );
+
+  Volume EnvLogEndCap("EcalEndcapQuadrant",EndCapSolid,theDetector.material("CarbonFiber"));
+
+  // kink position wrt bottom of quadrant (inside the lateral support)
+  // Y==0 is defined as outer edge of lateral face of inner module of quadrant
+  double kink_y = calc_endcap_rout*tan(M_PI/8.) - EcalEndcap_inner_radius;
+
+  helper.setModuleDimensions(1, // xytype
+			     0, // xztype
+			     calc_endcap_rout + EcalEndcap_inner_radius, // dxMax
+			     kink_y
+			     );
+  
+  helper.setTranslation ( Position ( -EcalEndcap_inner_radius , EcalEndcap_inner_radius, -module_thickness/2. ) );
+
+  // make the module
+
+  LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
+  caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
+
+  DetElement mod_det ("quad0",det_id);
+
+  helper.makeModule( EnvLogEndCap, 
+		     mod_det,
+		     *caloData,
+		     theDetector, 
+		     sens );
+
+  for (size_t i=0; i<caloData->layers.size(); i++) {
+    caloData->layers[i].distance += Ecal_Barrel_halfZ + Ecal_cables_gap; // add IP->front face distance
+  }
+
+  //  cout << "cell sizes: " << endl;
+  //  for (size_t i=0; i<caloData->layers.size(); i++) {
+  //    cout << "sensitive layer " << i << " : x,y = " << caloData->layers[i].cellSize0 << " " << caloData->layers[i].cellSize1 << endl;
+  //  }
+  
+  caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
+  caloData->inner_symmetry = 4  ; // hard code cernter box hole
+  caloData->outer_symmetry = 8  ; // outer Octagun
+  caloData->phi0 = 0 ;
+
+  /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
+  caloData->extent[0] = EcalEndcap_inner_radius ;
+  caloData->extent[1] = EcalEndcap_outer_radius ;
+  caloData->extent[2] = EcalEndcap_min_z ;
+  caloData->extent[3] = EcalEndcap_max_z ;
+
+
+
+  //====================================================================
+  // Place Ecal Endcap modules into the assembly envelope volume
+  //====================================================================
+   
+  for (int iend=0; iend<2; iend++) { // the 2 endcaps
+    int module_id = ( iend == 0 ) ? 0:6;
+
+    double this_module_z_offset = (EcalEndcap_min_z + EcalEndcap_max_z)/2.;
+    if ( iend == 0 ) this_module_z_offset*=-1;
+
+    double this_module_rotY = iend==0 ? M_PI : 0;
+    double rotZ_offset = iend==0 ? M_PI/8. - M_PI/2. : M_PI/8. + 3.*M_PI/4.; // magic rotation to get modules in right place
+    for (int iquad=0; iquad<4; iquad++) { // the 4 quadrants per endcap
+      int stave_id=iquad+1;
+      double this_module_rotZ(0);
+      if ( iend==0 ) {
+	this_module_rotZ = rotZ_offset - (iquad-2) * M_PI/2.;
+      } else {
+	this_module_rotZ = rotZ_offset + (iquad+1) * M_PI/2.;
+      }
+      Position xyzVec(0,0,this_module_z_offset);
+      RotationZYX rot( this_module_rotZ ,this_module_rotY, 0);
+      Rotation3D rot3D(rot);
+      Transform3D tran3D(rot3D,xyzVec);
+      PlacedVolume pv = envelope.placeVolume(EnvLogEndCap,tran3D);
+      pv.addPhysVolID("module",module_id); // z: -/+ 0/6
+      pv.addPhysVolID("stave",stave_id);
+      DetElement sd = (iend==0 && iquad==0) ? mod_det : mod_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d"));
+      sd.setPlacement(pv);
+    }
+  }
+  
+  sdet.addExtension< LayeredCalorimeterData >( caloData ) ; 
+
+  //  cout << "finished SEcal05_Endcaps" << endl;
+
+  return sdet;
+  
+}
+
+
+
+DECLARE_DETELEMENT(SEcal05_Endcaps, create_detector)
+
diff --git a/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.cpp b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f5b57dcf0a37225ae152b788954ac4664967712a
--- /dev/null
+++ b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.cpp
@@ -0,0 +1,729 @@
+#include "SEcal05_Helpers.h"
+
+SEcal05_Helpers::SEcal05_Helpers() {
+  // constructor, initialise internal variables
+  _x_det=NULL;
+  _layering=NULL;
+  _preshower=-1;
+
+  _CF_absWrap=-1;
+  _CF_alvWall=-1;
+  _CF_front=-1;
+  _CF_back=-1;
+
+  _ntowers.clear();
+  _towerGap=-999;
+  _unitsPerTower=0;
+  _unitDeadEdge=-999;
+
+  _cells_across_megatile=0;
+  _strips_across_megatile=0;
+  _strips_along_megatile=0;
+
+  _constantSlabXYDimensions.clear();
+
+  _caloLayer.absorberThickness = -999;
+  _caloLayer.sensitive_thickness = -999;
+  _caloLayer.distance = 0;
+
+  _totThick=0;
+
+  _plugLength=0;
+
+  _magicMegatileStrategy=-1;
+}
+
+
+void SEcal05_Helpers::setAbsLayers( int nl1, double th1, int nl2, double th2, int nl3, double th3 ) {
+  // set the number and thicknesses of absorber layers
+  _nlayers1=nl1;
+  _nlayers2=nl2;
+  _nlayers3=nl3;
+  _radiator_thickness1=th1;
+  _radiator_thickness2=th2;
+  _radiator_thickness3=th3;
+  return;
+}
+
+void SEcal05_Helpers::checkLayerConsistency() {
+  // check requested number of absorber layers is cinsistent with preshower status 
+  // we are constrained to have an even number of sensitive layers [ 2 sens. layers / slab ]
+  assert( (_preshower==0 || _preshower==1) && "_preshower not set" );
+  int n_total_abs_layers = _nlayers1 + _nlayers2 + _nlayers3;    // total number of Absorber layers
+  // check that number of requested absober layers is consistent
+  // if we want a preshower layer, total number of Absorber layers should be odd; otherwise even
+  if ( _preshower==1 && n_total_abs_layers%2==0 ) {
+    std::cout << "SEcal05_Helpers ERROR: inconsistent ECAL model !! if you request a preshower layer, the number of absorber layers = _nlayers1 + _nlayers2 + _nlayers3 must be odd" << std::endl;
+    std::cout << " Ecal_PreshowerLayer = " << _preshower << " ; _nlayers1/2/3 = " << _nlayers1 << " " << _nlayers2 << " " << _nlayers3 << std::endl;
+    assert(0);
+  } else if ( _preshower==0 && n_total_abs_layers%2==1 ) {
+    std::cout << "SEcal05_Helpers ERROR: inconsistent ECAL model !! if you request no preshower layer, the number of absorber layers = _nlayers1 + _nlayers2 + _nlayers3 must be even" << std::endl;
+    std::cout << " Ecal_PreshowerLayer = " << _preshower << " ; _nlayers1/2/3 = " << _nlayers1 << " " << _nlayers2 << " " << _nlayers3 << std::endl;
+    assert(0);
+  }
+  return;
+}
+
+float SEcal05_Helpers::getTotalThickness() {
+  // calculate total thickness of ECAL
+  checkLayerConsistency();
+  assert( _x_det && _layering && "_x_det or _layering not set" );
+  assert( (_preshower==0 || _preshower==1) && "_preshower not set" );
+  assert( _CF_absWrap>=0. && _CF_alvWall>=0. && _CF_front>=0. && _CF_back>=0. && "CF thicknesses not set" );
+  float totalThickness = _CF_front+_CF_back;// front and back supports
+
+  // the absorber in the structure
+  for (unsigned int i=0; i<_nlayers1+_nlayers2+_nlayers3; i++) {
+    bool inStructure = _preshower ? i%2==1 : i%2==0 ;
+    if ( inStructure ) {
+      double thickness (_radiator_thickness1);
+      if ( i>=_nlayers1 ) thickness = _radiator_thickness2;
+      if ( i>=_nlayers1+_nlayers2 ) thickness = _radiator_thickness3;
+      totalThickness += thickness + 2*_CF_absWrap; // the absorber and its wrapping
+    }
+  }
+  // the slabs
+  int l_num(0);
+  for(xml_coll_t li(*_x_det,_U(layer)); li; ++li)  { // types of layers (i.e. thin/thick absorber) or "stack"
+    xml_comp_t x_layer = li;
+    // Loop over number of repeats for this layer.
+    for (int j=0; j< x_layer.repeat(); j++)    {  // layers within this type (or "stack")
+      float thisthick = _layering->layer(l_num)->thickness();
+      totalThickness+=thisthick + 2*_CF_alvWall; // slab thickness, and the alveolar wall around it
+      l_num++;
+    }
+  }
+  return totalThickness;
+}
+
+void SEcal05_Helpers::printSEcal05LayerInfo( dd4hep::rec::LayeredCalorimeterData::Layer & caloLayer) {
+  std::cout<<"SEcal05_Helpers === CALOLAYER printout: "                 << std::endl;
+  std::cout<<"    caloLayer.distance: "                 << caloLayer.distance <<std::endl;
+  std::cout<<"    caloLayer.inner_nRadiationLengths: "  << caloLayer.inner_nRadiationLengths <<std::endl;
+  std::cout<<"    caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl;
+  std::cout<<"    caloLayer.inner_thickness: "          << caloLayer.inner_thickness <<std::endl;
+  std::cout<<"    caloLayer.sensitive_thickness: "      << caloLayer.sensitive_thickness <<std::endl;
+  std::cout<<"    caloLayer.cellSize0, 1: "             << caloLayer.cellSize0 << " " << caloLayer.cellSize1 << std::endl;
+  std::cout<<"    caloLayer.outer_nRadiationLengths: "  << caloLayer.outer_nRadiationLengths <<std::endl;
+  std::cout<<"    caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl;
+  std::cout<<"    caloLayer.outer_thickness: "          << caloLayer.outer_thickness <<std::endl;
+  return;
+}
+
+double SEcal05_Helpers::getAbsThickness( unsigned int iAbsLay ) { //, int n1, int n2, int n3, double t1, double t2, double t3) {
+  // get the thickness of a given absorber layer
+  if ( iAbsLay < _nlayers1 ) return _radiator_thickness1;
+  else if ( iAbsLay - _nlayers1 < _nlayers2 ) return _radiator_thickness2;
+  else if ( iAbsLay - _nlayers1 - _nlayers2 < _nlayers3 ) return _radiator_thickness3;
+  assert(0 && "impossible layer number"); // should never get here
+  return -999.;
+}
+
+
+
+std::vector <SEcal05_Helpers::dimposXYStruct> SEcal05_Helpers::getAbsPlateXYDimensions( double ztop ) {
+  // get the dimensions of absorber plates
+  // for trapeziodal case, this depends on the Z position
+  // CF wrap not taken into account, so this width constains both absorber and its wrapping
+
+  if ( _module_XZtype==1 ) assert( ztop>=0 && "getAbsPlateXYDimensions: ztop not specified" ); // must specify Z position for case with non-uniform layers
+
+  std::vector <dimposXYStruct> absorbersheets;
+
+  if ( _module_XYtype == 1 ) { // each slab is different: calculate slab-by-slab (eg in endcap)
+    absorbersheets = getSlabXYDimensions( ztop );
+  } else {                    // single sheet over all slabs (eg in barrel)
+    dimposXYStruct ss;
+    if ( _module_XZtype==0 ) { // no taper
+      ss.sizeX = _module_dX_max;
+      ss.posX = ss.sizeX/2.;
+    } else {   // size varies by laer
+
+      //      ss.sizeX = _module_dX_max - 2.*ztop; // this assumes octagon
+
+      ss.sizeX = _module_dX_max - 2.*ztop/tan(_module_angle); // for general shape
+
+      ss.posX  = _module_dX_max/2.;   // keep it centered
+    }
+    ss.sizeY = _module_dY_total;
+    ss.posY = _module_dY_total/2.;
+    absorbersheets.push_back(ss);
+  }
+  return absorbersheets;
+}
+
+std::vector <SEcal05_Helpers::dimposXYStruct> SEcal05_Helpers::getSlabXYDimensions( double ztop ) {
+  // calculate size and position of slab volumes
+  //  size includes slab and dead area around it
+
+  // ztop is Z of upper face of this slab (the face shortest in X)
+  if ( _module_XZtype==1 ) assert( ztop>=0 && "getSlabXYDimensions: ztop not specified" ); // must specify Z position for case with non-uniform layers
+
+  std::vector <dimposXYStruct> layerslabdims;
+  if ( _module_XZtype == 0 && _constantSlabXYDimensions.size()>0 ) { // every layer is the same, and has already been calculated
+    layerslabdims = _constantSlabXYDimensions;
+  } else {
+    dimposXYStruct ss;
+    int totTow(0);
+    for (size_t imod=0; imod<_ntowers.size(); imod++) { // loop over "modules" [nb, for barrel, we only make a single module; for endcaps, typically have 3 per quadrant]
+      for (int itow = 0; itow<_ntowers[imod]; itow++) { // towers within the module
+	// each slab has same width
+        ss.sizeY = _alveolus_total_dim_Y; // this size include edge-of-tower dead space
+        ss.posY = 
+	  _moduleGap * ( 1 + 2*imod ) + // edge-of-module gaps from Y=0 to this slab
+	  _alveolus_total_dim_Y * (totTow+0.5); // position of slab centre w.r.t (X,Y) = (0,0)
+
+        if ( _module_XYtype==0 ) { // all slabs in a layer have same length
+
+          if ( _module_XZtype == 0 ) { // all layers have same length
+            ss.sizeX = _module_dX_max;
+            ss.posX = ss.sizeX/2.;
+          } else {                     // layers vary in length : barrel module
+
+            // ss.sizeX = _module_dX_max - 2.*ztop; // assumes octagon
+
+	    ss.sizeX = _module_dX_max - 2.*ztop/tan(_module_angle); // for general shape
+
+            ss.posX = _module_dX_max/2.;  // slabs all centred
+          }
+
+	  ss.sizeX -= _plugLength; // DANIELHACK 
+	  ss.posX += _plugLength/2.;  // DANIELHACK 
+
+
+
+        } else if ( _module_XYtype==1 ) { // slabs within layer have different lengths : this is for endcap
+          // placing in Y
+          double upperY = ss.posY + 0.5*_alveolus_total_dim_Y; // Y position of upper edge
+
+	  if ( upperY<=_module_dY_kink ) { // straight edge part under kink
+	    ss.sizeX = _module_dX_max;
+	  } else {            // sloping edge: take length at upperY, which is the shortest one
+	    ss.sizeX = _module_dX_max - ( upperY - _module_dY_kink );
+	  }
+
+          ss.posX = ss.sizeX/2.; // this aligns the -X end of slab
+
+	  ss.sizeX -=  _plugLength;  // DANIELHACK
+	  ss.posX  +=  _plugLength/2.;  // DANIELHACK      
+
+        } else {
+	  cout << " SEcal05_Helpers ERROR _module_XYtype = " << _module_XYtype << "!!!" << endl;
+	  assert(0);
+	}
+	layerslabdims.push_back(ss);
+	totTow++;
+      } // towers
+    } // modules
+
+    // if slab dimensions do not change layer-by-layer, memorise for next time
+    if ( _module_XZtype == 0 ) _constantSlabXYDimensions = layerslabdims;
+  }
+  return layerslabdims;
+}
+
+
+void SEcal05_Helpers::updateCaloLayers(double thickness,
+                                       dd4hep::Material mat,
+                                       bool isAbsorber,
+                                       bool isSensitive,
+                                       double cell_size_x, double cell_size_y,
+                                       bool isFinal
+                                       ) {
+
+  if ( isFinal ) { // add material before saving layer
+    _layer_thickness           += (thickness);
+    _layer_nRadiationLengths   += (thickness)/mat.radLength() ;
+    _layer_nInteractionLengths += (thickness)/mat.intLength() ;
+  }
+
+  // should we finish off the current layer?
+  if ( isFinal ||  // last slice of calo
+       (isAbsorber && _caloLayer.sensitive_thickness > 0 )  // end of a caloLayer
+       ) {
+
+    // finalise caloLayer entry, add to caloData
+    _caloLayer.outer_thickness           = _layer_thickness;
+    _caloLayer.outer_nRadiationLengths   = _layer_nRadiationLengths;
+    _caloLayer.outer_nInteractionLengths = _layer_nInteractionLengths;
+    //_caloLayer.thickness                 = _caloLayer.inner_thickness + _caloLayer.outer_thickness ;
+
+    // push it back
+    _caloData->layers.push_back( _caloLayer ) ;
+    //    printSEcal05LayerInfo( _caloLayer );
+
+    // reset layer thicknesses
+    _layer_thickness=0;
+    _layer_nRadiationLengths=0;
+    _layer_nInteractionLengths=0;
+
+    // update the calolayer.distance ( DJeans 12 sep 2017)
+    // here this is distance from ECAL start to the layer start; the Barrel and Endcap drivers add the distance from IP
+    _caloLayer.distance += _caloLayer.inner_thickness+_caloLayer.outer_thickness;
+
+
+  }
+
+  if (!isFinal) {
+
+    // first add half the material
+    _layer_thickness           += (thickness/2.);
+    _layer_nRadiationLengths   += (thickness/2.)/mat.radLength() ;
+    _layer_nInteractionLengths += (thickness/2.)/mat.intLength() ;
+
+    // then we store material before and after centre of this layer
+    if ( isSensitive ) {
+      _caloLayer.cellSize0 = cell_size_x;
+      _caloLayer.cellSize1 = cell_size_y;
+      _caloLayer.sensitive_thickness       = thickness ;
+      _caloLayer.inner_nRadiationLengths   = _layer_nRadiationLengths ;
+      _caloLayer.inner_nInteractionLengths = _layer_nInteractionLengths ;
+      _caloLayer.inner_thickness           = _layer_thickness ;
+
+      // reset layer thicknesses
+      _layer_thickness=0;
+      _layer_nRadiationLengths=0;
+      _layer_nInteractionLengths=0;
+    }
+
+    // add in remaining half of layer
+    _layer_thickness           += (thickness/2.);
+    _layer_nRadiationLengths   += (thickness/2.)/mat.radLength() ;
+    _layer_nInteractionLengths += (thickness/2.)/mat.intLength() ;
+  }
+
+  _totThick+=thickness;
+
+  return;
+}
+
+
+SEcal05_Helpers::dxinfo SEcal05_Helpers::getNormalMagicUnitsInX( double dx_total, double dx_unit, double dx_cell, double dx_dead ,
+								 int magicStrategy ) {
+
+  dxinfo dxInf;
+  dxInf.normal_nX=-1;
+  dxInf.magic1_unitDX=-1;
+  dxInf.magic1_ncellsX=-1;
+  dxInf.magic2_unitDX=-1;
+
+  int nNormalUnit = int( floor( dx_total / dx_unit ) );
+
+  if ( magicStrategy==0 ) { // just integer number of standard units (wafers/megatiles)
+    dxInf.normal_nX = nNormalUnit;
+  } else {
+
+    double extraSpace = dx_total - nNormalUnit*dx_unit;
+    double extraSensitiveSpace = extraSpace - 2.*dx_dead;
+    double extraNCells = extraSensitiveSpace / dx_cell;
+ 
+    if ( magicStrategy==1 ) { // last magic megatile has integer number of standard-sized cells
+      dxInf.normal_nX = nNormalUnit;
+      if ( extraNCells > 1.0 ) { 
+	int iext = int( floor( extraNCells ) );
+	dxInf.magic1_unitDX = iext*dx_cell + 2.*dx_dead;
+	dxInf.magic1_ncellsX = iext;
+      }
+    } else if ( magicStrategy==2 ) { 
+
+      // one magic megatile with integer number of standard cells, 
+      //  second with non-standard cell size to fill space exactly
+      //   last magic cell size in range  shortestMacigCell<magicCellsSize/standardCellSize<shortestMagicCell
+
+      // the shortest magic cell (in terms of the usual cell size)
+      const double shortestMagicCell = 1.0; // this means that the last magic cell is at least as long as the standard cell
+
+      extraSensitiveSpace = extraSpace - 4.*dx_dead; // because both the magic tiles may have a dead area
+      extraNCells = extraSensitiveSpace / dx_cell;
+
+      if ( extraNCells < shortestMagicCell ) { // too small to make magic unit. remove one normal unit
+	nNormalUnit-=1;
+	extraSpace = dx_total - nNormalUnit*dx_unit;
+	extraSensitiveSpace = extraSpace - 4.*dx_dead;
+	extraNCells = extraSensitiveSpace / dx_cell;
+      }
+      
+      int imagic1 = int( floor( extraNCells ) ); // rounded down number of standard-sized cells
+
+      double magic1size = imagic1>0 ? imagic1*dx_cell + 2*dx_dead : 0.;
+
+      double magic2cellsize = extraSpace - magic1size - 2*dx_dead;
+
+      if ( magic2cellsize/dx_cell < shortestMagicCell ) { // too small
+	imagic1 -= 1; // remove last standard cell
+	magic1size = imagic1>0 ? imagic1*dx_cell + 2*dx_dead : 0;
+	magic2cellsize = extraSpace - magic1size - 2*dx_dead;
+      }
+
+      assert( magic2cellsize/dx_cell >= shortestMagicCell && magic2cellsize/dx_cell <= shortestMagicCell+1.0 && "problem in deciding magic unit size" );
+
+      dxInf.normal_nX = nNormalUnit;
+      dxInf.magic1_ncellsX = imagic1;
+      dxInf.magic1_unitDX = imagic1>0 ? imagic1*dx_cell + 2*dx_dead : 0;
+
+      dxInf.magic2_unitDX = magic2cellsize + 2*dx_dead;
+      
+    }
+  }
+
+  if ( magicStrategy==2 ) {
+    // check it fills exactly
+    if ( fabs( dxInf.normal_nX*dxInf.magic1_unitDX + dxInf.magic1_unitDX + dxInf.magic2_unitDX - dx_total ) < 0.01*dd4hep::mm ) {
+      cout << " SEcal05_Helpers ERROR : " << endl;
+      cout << dxInf.normal_nX*dxInf.magic1_unitDX << " " << dxInf.magic1_unitDX << " " << dxInf.magic2_unitDX << endl;
+      cout << dxInf.normal_nX*dxInf.magic1_unitDX + dxInf.magic1_unitDX + dxInf.magic2_unitDX << " " << dx_total << endl;
+      cout << dxInf.normal_nX*dxInf.magic1_unitDX + dxInf.magic1_unitDX + dxInf.magic2_unitDX - dx_total << endl;
+      assert(0 && "magic unit does not fill space exactly");
+    }
+
+  }
+
+  return dxInf;
+}
+
+
+void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol,  // the volume we'll fill
+				  dd4hep::DetElement & stave_det, // the detector element
+				  dd4hep::rec::LayeredCalorimeterData & caloData, // the reco data we'll fill
+				  dd4hep::Detector & theDetector,
+				  dd4hep::SensitiveDetector & sens
+				  ) {
+  // make the module
+  _caloData = &caloData;
+
+  // calculate widths of module/tower/unit (in z-direction for barrel: across the slab/module
+  assert ( _ntowers.size()>0 && _unitsPerTower>0 && "_ntowers or _unitsPerTower not set" );
+
+  _module_dY_total=0;
+  for (size_t i=0; i<_ntowers.size(); i++) {
+    _module_dY_total = _ntowers[i]*_alveolus_total_dim_Y + 2.*_moduleGap;
+  }
+
+  double alveolus_active_dim_Y = _alveolus_total_dim_Y - 2.*_towerGap;
+  double unit_dim_Y            = alveolus_active_dim_Y/_unitsPerTower;
+  double unit_sensitive_dim_Y  = unit_dim_Y - 2*_unitDeadEdge; // width of the sensitive area in each sensor
+  assert( unit_sensitive_dim_Y>0 && "negative-sized sensitive area..." ); // otherwise really weird!
+
+  // get detector stuff
+  assert ( _x_det && "_x_det not set");
+  int det_id           = _x_det->id();
+  xml_comp_t x_staves  = _x_det->staves();
+
+  _carbon_fibre_material = theDetector.material("CarbonFiber");
+  _radiator_material     = theDetector.material(x_staves.materialStr());
+  _air_material          = theDetector.air();
+
+  dd4hep::VisAttr _radiator_visatt      = theDetector.visAttributes( x_staves.visStr() );
+
+  // get segmentation stuff
+  assert (_geomseg && "segmentation not set");
+
+  dd4hep::DDSegmentation::WaferGridXY* waferSeg = dynamic_cast< dd4hep::DDSegmentation::WaferGridXY* > ( _geomseg->segmentation() ) ;
+
+
+  dd4hep::DDSegmentation::MegatileLayerGridXY* megatileSeg = dynamic_cast< dd4hep::DDSegmentation::MegatileLayerGridXY* > ( _geomseg->segmentation() ) ;
+  assert( (waferSeg || megatileSeg) && "no segmentation found" );
+
+  // set up the standard megatile size and offset
+  if ( megatileSeg ) {
+    megatileSeg->setMegaTileSizeXY( unit_sensitive_dim_Y, unit_sensitive_dim_Y );
+    megatileSeg->setMegaTileOffsetXY( -unit_sensitive_dim_Y/2., -unit_sensitive_dim_Y/2. );
+  }
+
+  _module_thickness = getTotalThickness();
+
+  double currentLayerBase_pos_Z  = 0; // this gets updated: it's the position of the bottom face of the next detector slice
+
+  int layer_index = 0; // 1;// layer number - Daniel changes to c-type counting from 0...lets get rid of fortran habits!
+
+  // to deal with initial layers
+  bool isFrontFace = true;
+  int myLayerNum = 0 ; // this is the sensitive layer number (one per sensitive)
+  unsigned int absorber_index(0); // keep track of which absorber layer we're in
+
+  // keep track of thickness within a layer
+  // initialise
+  _layer_thickness           = 0. ;
+  _layer_nRadiationLengths   = 0. ;
+  _layer_nInteractionLengths = 0. ;
+
+  //--------------------------------
+  // loop over the layers
+  //---------------------------------
+
+  for(xml_coll_t li(*_x_det,_U(layer)); li; ++li)  { // types of layers (i.e. thin/thick absorber) or "stack"
+    xml_comp_t x_layer = li;
+    //    cout << " ---- NEW LAYER TYPE " << layer_index << " repeat " <<  x_layer.repeat() << endl;
+
+    // Loop over number of repeats for this layer type
+    for (int j=0; j< x_layer.repeat(); j++)    {  // layers within this type (or "stack")
+      std::string l_name = dd4hep::_toString(layer_index,"layer%d");
+
+      // #########################
+      // Build Structure Layer
+      // #########################
+
+      //----------------------------------------------------
+      // position and thickness of absorber plates in the structure
+      //----------------------------------------------------
+      double radiator_dim_Z(0);
+      double rad_pos_Z(0);
+      double this_struct_CFthick_beforeAbs(0);
+      double this_struct_CFthick_afterAbs(0);
+
+      if ( isFrontFace ) { // the first part of the module depends on whether we have preshwer or not
+        if ( _preshower==1 ) { // don't include W+CF wrapping; only one side of alveolus
+          this_struct_CFthick_beforeAbs = 0;
+          this_struct_CFthick_afterAbs = _CF_front + _CF_alvWall;
+          radiator_dim_Z = 0;
+        } else { // include W+CF wrapping; only one side of alveolus
+          // cout << " -- no preshower, including absorber" << endl;
+          this_struct_CFthick_beforeAbs = _CF_front + _CF_absWrap; // allow for initial CF front plate also in no preshower case - djeans 6 july 2017
+          this_struct_CFthick_afterAbs = _CF_absWrap + _CF_alvWall;
+          radiator_dim_Z = getAbsThickness( absorber_index++ );
+          rad_pos_Z = radiator_dim_Z/2. + this_struct_CFthick_beforeAbs; // distance from top surface of structure to centre of radiator
+        }
+        isFrontFace=false;
+      } else { // internal layer: include W+CF wrapping; both sides of alveolus
+        this_struct_CFthick_beforeAbs = _CF_alvWall+_CF_absWrap;
+        this_struct_CFthick_afterAbs = _CF_alvWall+_CF_absWrap;
+        radiator_dim_Z = getAbsThickness( absorber_index++ );
+        assert( radiator_dim_Z>0 && "no radiator!" );
+        rad_pos_Z = this_struct_CFthick_beforeAbs + radiator_dim_Z/2.; // distance from top surface of structure to centre of radiator
+      }
+
+
+      // create the radiator volume
+      if ( radiator_dim_Z>0 ) {       // only create the volume if we have radiator
+        std::vector < dimposXYStruct > absorbersheets = getAbsPlateXYDimensions( currentLayerBase_pos_Z + this_struct_CFthick_beforeAbs + radiator_dim_Z ); // add CF before abs. added djeans 21 nov 2016
+        // create and place the absorber sheets
+        for ( size_t ipl=0; ipl<absorbersheets.size(); ipl++) {
+          dimposXYStruct plSize = absorbersheets[ipl];
+          dd4hep::Box    barrelStructureLayer_box( plSize.sizeX/2.,
+                                                             plSize.sizeY/2. - _CF_absWrap,  // remove CF wrapping
+                                                             radiator_dim_Z/2.);
+
+          dd4hep::Volume barrelStructureLayer_vol( _det_name+"_"+l_name+"_"+dd4hep::_toString(int(ipl),"bs%02d"),
+                                                             barrelStructureLayer_box, _radiator_material);
+
+          barrelStructureLayer_vol.setVisAttributes( _radiator_visatt );
+
+          // Position the layer.
+          dd4hep::Position      bsl_pos = getTranslatedPosition(plSize.posX, plSize.posY, currentLayerBase_pos_Z + rad_pos_Z );
+
+	  //          dd4hep::PlacedVolume  barrelStructureLayer_phv = 
+	  mod_vol.placeVolume(barrelStructureLayer_vol, bsl_pos);
+
+        } // loop over sheets
+      }
+
+      // update layer thickness until front face of absorber
+      updateCaloLayers( this_struct_CFthick_beforeAbs, _carbon_fibre_material, false, false);
+      updateCaloLayers( radiator_dim_Z, _radiator_material, true, false );
+      updateCaloLayers( this_struct_CFthick_afterAbs, _carbon_fibre_material, false, false);
+
+      // update position within module
+      currentLayerBase_pos_Z += this_struct_CFthick_beforeAbs + radiator_dim_Z + this_struct_CFthick_afterAbs;
+
+      // #########################
+      // Build Slab
+      // #########################
+
+      //-------------------------------
+      // first sum the various materials for the caloData/caloLayer
+      //-------------------------------
+      int myLayerNumTemp = myLayerNum;
+      for(xml_coll_t si(x_layer,_U(slice)); si; ++si)  {
+        xml_comp_t  x_slice = si;
+        double      s_thick = x_slice.thickness();
+        dd4hep::Material slice_material  = theDetector.material( x_slice.materialStr() );
+        if (x_slice.materialStr().compare(x_staves.materialStr()) == 0){
+          // this is absorber material
+          //  check it's consistent with what we expect from the detector parameters
+          assert ( fabs( s_thick - getAbsThickness( absorber_index++ ) ) < 1e-5 && "inconsistent radiator thickness" );
+          updateCaloLayers( s_thick, slice_material, true, false ); // absorber
+        } else if ( x_slice.isSensitive() ) {
+          double cell_size_x(0), cell_size_y(0);
+          if ( waferSeg ) {
+            cell_size_x = waferSeg->cellDimensions(0)[0];
+            cell_size_y = waferSeg->cellDimensions(0)[1];
+          } else if ( megatileSeg ) {
+            // setup megatile
+            int laytype = _layerConfig [ myLayerNumTemp%_layerConfig.size() ];
+            if ( laytype==0 ) {
+              megatileSeg->setMegaTileCellsXY( myLayerNumTemp, _cells_across_megatile , _cells_across_megatile );
+            } else if  ( laytype==1 ) {
+              megatileSeg->setMegaTileCellsXY( myLayerNumTemp, _strips_across_megatile , _strips_along_megatile ); // strips in one orientation
+            } else if  ( laytype==2 ) {
+              megatileSeg->setMegaTileCellsXY( myLayerNumTemp, _strips_along_megatile , _strips_across_megatile ); // and in the other
+            } else {
+              assert(0 && "unknown layer type");
+            }
+            cell_size_x = megatileSeg->cellDimensions(myLayerNumTemp, 0)[0]; // dummy wafer
+            cell_size_y = megatileSeg->cellDimensions(myLayerNumTemp, 0)[1];
+          }
+          updateCaloLayers( s_thick, slice_material, false, true, cell_size_x, cell_size_y ); // sensitive
+          myLayerNumTemp++;
+        } else {
+          updateCaloLayers( s_thick, slice_material, false, false );
+        }
+      }
+
+      //------------------------------------
+      // then actually construct the slabs
+      //------------------------------------
+      double slab_dim_Z = _layering->layer(layer_index)->thickness();
+      double slab_pos_Z = currentLayerBase_pos_Z + slab_dim_Z/2.; // centre position of slab
+
+      std::vector <dimposXYStruct> slabDims = getSlabXYDimensions( currentLayerBase_pos_Z + slab_dim_Z );
+
+      for (size_t islab = 0; islab<slabDims.size(); islab++) {
+        myLayerNumTemp = myLayerNum;
+        double slab_dim_X  = slabDims[islab].sizeX;
+
+        // make an air volume for the alveolus
+        dd4hep::Box        l_box( slab_dim_X/2. ,
+                                            slabDims[islab].sizeY/2. - _CF_alvWall,
+                                            slab_dim_Z/2. );
+
+        dd4hep::Volume     l_vol( _det_name+"_alveolus_"+l_name, l_box, _air_material);
+	l_vol.setVisAttributes(theDetector.visAttributes( "GrayVis" ) );
+
+        dd4hep::DetElement l_det( stave_det, l_name+dd4hep::_toString(int(islab),"tower%02d") , det_id );
+        dd4hep::Position   l_pos = getTranslatedPosition(slabDims[islab].posX, slabDims[islab].posY, slab_pos_Z );
+        dd4hep::PlacedVolume l_phv = mod_vol.placeVolume(l_vol,l_pos);
+        l_phv.addPhysVolID("tower", int(islab) );
+        l_det.setPlacement(l_phv);
+
+        // then fill it with the slab sublayers
+        int s_num(0);
+        double s_pos_Z = -slab_dim_Z / 2.; // position of sub-layer with respect to centre of this slab
+
+        for(xml_coll_t si(x_layer,_U(slice)); si; ++si)  { // the sub-layers
+          xml_comp_t  x_slice = si;
+          std::string s_name  = dd4hep::_toString(s_num,"slice%d");
+          double      s_thick = x_slice.thickness();
+
+          dd4hep::Material slice_material  = theDetector.material( x_slice.materialStr() );
+
+	  std::string vis_str = x_slice.visStr();
+
+	  if ( !x_slice.isSensitive() ) { // not the sensitive slice: just a layer of stuff
+
+	    dd4hep::Box      s_box( slab_dim_X/2. , slabDims[islab].sizeY/2. - _CF_alvWall, s_thick/2. );
+	    dd4hep::Volume   s_vol(_det_name+"_"+l_name+"_"+s_name, s_box, slice_material);
+	    s_vol.setVisAttributes(theDetector.visAttributes( vis_str ));
+
+	    dd4hep::Position s_pos( 0, 0, s_pos_Z + s_thick/2. );
+	    //	    dd4hep::PlacedVolume slice_phv = 
+	    l_vol.placeVolume(s_vol, s_pos );
+
+	  } else { // sensitive slice
+
+            // Normal squared wafers - this is just the sensitive part
+            // square piece of silicon, not including guard ring. guard ring material is not included
+
+            dd4hep::Box WaferSiSolid( unit_sensitive_dim_Y/2., unit_sensitive_dim_Y/2., s_thick/2.);
+
+	    // get the standard cell size in X for this layer
+	    double cell_size_x = waferSeg ? waferSeg->cellDimensions(0)[0] : megatileSeg->cellDimensions(myLayerNumTemp, 0)[0];
+	    double cell_size_y = waferSeg ? waferSeg->cellDimensions(0)[1] : megatileSeg->cellDimensions(myLayerNumTemp, 0)[1];
+
+	    // work out how to make the magic units, if requested
+	    dxinfo xseg = getNormalMagicUnitsInX( slab_dim_X,
+						  unit_dim_Y,
+						  cell_size_x,
+						  _unitDeadEdge,
+						  _magicMegatileStrategy );						  
+
+            int n_wafers_x = xseg.normal_nX;
+	    int ncellsy = int( unit_sensitive_dim_Y/cell_size_y + 0.5 ); // should be exactly integer. take nearest integer to account for possible rounding errors.
+
+            int wafer_num = 0;
+
+	    double wafer_pos_X = -slab_dim_X/2.; // keep track of wafer position in X
+
+            for (int n_wafer_x = 0; n_wafer_x < n_wafers_x+2 ; n_wafer_x++) { // loop along slab, including magic megatile/wafer
+
+              double megatile_size_x = unit_dim_Y;
+	      int ncellsx(-1);
+
+	      bool isMagic = n_wafer_x >= n_wafers_x;
+
+	      if ( n_wafer_x==n_wafers_x ) { // first magic unit
+		megatile_size_x = xseg.magic1_unitDX;
+		ncellsx = xseg.magic1_ncellsX;
+	      } else if ( n_wafer_x==n_wafers_x+1 ) { // second magic unit
+		megatile_size_x = xseg.magic2_unitDX;
+		ncellsx = 1;
+	      }
+
+	      // cout << "ismagic " << isMagic << " wafer " << n_wafer_x << " / " << n_wafers_x << " : sizex " << megatile_size_x << " nx " << ncellsx << endl;
+
+	      if ( megatile_size_x<=0 ) continue;
+
+	      // cout << " PASSED" << endl;
+
+              double megatile_sensitive_size_x = megatile_size_x - 2*_unitDeadEdge;
+
+              for (int n_wafer_Y = 0; n_wafer_Y < _unitsPerTower; n_wafer_Y++) { // loop across slab (usually 2 wafers, or 1 EBU) [ie along beam dir for barrel module]
+
+                double wafer_pos_Y = -alveolus_active_dim_Y/2.0 + (n_wafer_Y+0.5)*unit_dim_Y;
+                wafer_num++;
+                std::string Wafer_name;
+                if ( isMagic ) Wafer_name="magic";
+                Wafer_name +=  dd4hep::_toString(wafer_num,"wafer%d");
+
+                dd4hep::Box* box = isMagic ? new dd4hep::Box( megatile_sensitive_size_x/2,unit_sensitive_dim_Y/2,s_thick/2.) : &WaferSiSolid;
+                dd4hep::Volume WaferSiLog(_det_name+"_"+l_name+"_"+s_name+"_"+Wafer_name,*box,slice_material);
+
+		std::string wafer_vis_str = isMagic ? "YellowVis" : vis_str;
+		
+		WaferSiLog.setVisAttributes(theDetector.visAttributes( wafer_vis_str ));	  
+                WaferSiLog.setSensitiveDetector(sens);
+
+                dd4hep::Position w_pos(wafer_pos_X + megatile_size_x/2., wafer_pos_Y, s_pos_Z + s_thick/2. );
+                dd4hep::PlacedVolume wafer_phv = l_vol.placeVolume(WaferSiLog, w_pos );
+                wafer_phv.addPhysVolID("wafer", wafer_num);
+		wafer_phv.addPhysVolID("layer", myLayerNumTemp );
+
+                if ( isMagic ) {
+                  if ( megatileSeg ) { // define the special megatile
+                    megatileSeg->setSpecialMegaTile( myLayerNumTemp, wafer_num,
+                                                     megatile_sensitive_size_x, unit_sensitive_dim_Y,
+                                                     -megatile_size_x/2., -unit_sensitive_dim_Y/2., // the offset
+                                                     ncellsx, ncellsy ); // the segmentation
+                  }
+                } else { // not magic
+                  if ( waferSeg ) {  // Normal squared wafers, this waferOffsetX is 0.0 // if its an odd number of cells, need to do something?
+                    waferSeg->setWaferOffsetX(myLayerNumTemp, wafer_num, 0.0);
+                  }
+                } // isMagic
+
+              } // y-wafers
+
+	      wafer_pos_X += megatile_size_x;
+
+            } // x-wafers
+            myLayerNumTemp++;
+          } // end sensitive slice
+
+          // Increment Z position of slice.
+          s_pos_Z += s_thick;
+
+          // Increment slice number.
+          ++s_num;
+
+        } // end slice within one slab
+      } // slabs
+      myLayerNum = myLayerNumTemp;
+      currentLayerBase_pos_Z += slab_dim_Z;
+      layer_index++; // this is the structural layer counter (one per slab, not per sensitive layer)
+    } // layers in compact file
+  } // layer types in compact file
+
+    // add material after last slab. Just CF
+  updateCaloLayers( _CF_alvWall + _CF_back, _carbon_fibre_material, false, false, -1, -1, true ); // the last layer
+
+  return;
+}
diff --git a/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.h b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..80e8e829a336eb25410247cdc5e7433d70777684
--- /dev/null
+++ b/Detector/DetCEPCv4/src/calorimeter/SEcal05_Helpers.h
@@ -0,0 +1,309 @@
+#ifndef __SECAL05_HELPERS_H__
+#define __SECAL05_HELPERS_H__ 1
+
+#include "DD4hep/DetFactoryHelper.h"
+
+#include "DDRec/DetectorData.h"
+
+#include "XML/Layering.h"
+#include "XML/Utilities.h"
+
+#include "DD4hep/Segmentations.h"
+
+#include "DDSegmentation/MegatileLayerGridXY.h"
+
+#include "DDSegmentation/WaferGridXY.h"
+
+#include <iostream>
+
+#undef NDEBUG
+#include <assert.h>
+
+using std::cout;
+using std::endl;
+
+/*
+
+we build general ECAL modules on a horizontal table. 
+
+X-Y are on the table
+Z is vertically upwards
+slabs are aligned along X
+the lower Z side will face the IP
+
+2 shapes when looking down on table:
+
+XYtype = 0:  (barrel and endcap)
+     -----------------------------     ^ Y
+     |                           |     |
+     |                           |     |
+     -----------------------------      ----> X
+
+XYtype = 1:  (endcap)
+     ----------------------
+     |                      \
+     |                        \
+     |                          \
+     |                           |   ^
+     |                           |   | dY_kink
+     -----------------------------   |
+
+2 shapes when looking from side:
+
+XZtype = 0:  (endcap)
+   ---------------------------------
+   |                               |
+   |                               |
+   ---------------------------------
+
+XZtype = 1:  (barrel)
+       --------------------------        ^ Z
+      /                          \       |
+     /                            \      |
+    /                              \     |
+    --------------------------------     ----> X
+
+the slabs are prefectly aligned at -ve X side
+"magic" wafers are at +ve X
+
+local position: 0,0 defined as -veX,Y,Z corner
+
+we start building from Z=0, the face nearest IP, moving in the +ve Z direction
+
+
+D.Jeans update: 03/2015
+dead space between slab end and module edge
+other than 8-fold symmetry for barrel
+
+ */
+
+class SEcal05_Helpers {
+
+ public:
+
+  SEcal05_Helpers();
+
+  ~SEcal05_Helpers() {
+    delete _layering;
+  }
+
+  // SET THE PARAMETERS
+
+  void setDet( xml_det_t* x_det ) {
+    _x_det = x_det;
+    _layering = new dd4hep::Layering(*x_det);
+    _det_name  = x_det->nameStr();
+  }
+
+  void setAbsLayers( int nl1, double th1, int nl2, double th2, int nl3=0, double th3=0 );
+
+  void setLayerConfig( std::vector < int > layerConfig ) {
+    _layerConfig=layerConfig;
+  }
+
+  void setSegmentation(  dd4hep::Segmentation & seg ) {
+    _geomseg = &seg;
+  }
+
+  void setSegmentation(  dd4hep::Segmentation * seg ) {
+    _geomseg = seg;
+  }
+
+  void setNCells( int Ecal_cells_across_megatile, int Ecal_strips_across_megatile, int Ecal_strips_along_megatile) {
+    _cells_across_megatile   =  Ecal_cells_across_megatile   ;
+    _strips_across_megatile  =  Ecal_strips_across_megatile  ;
+    _strips_along_megatile   =  Ecal_strips_along_megatile   ;
+  }
+
+  void setMagicMegatileStrategy ( int i ) {
+    // magic megatile strategy
+    //  0: no magic megatile at lend of slab
+    //  1: magic megatile includes integer number of standard-sized cells
+    //  2: last cell of magic megatile adjusted to fill up to end of slab (size between 1 and 2 times normal cell size)
+    assert ( i>=0 && i<=2 );
+    _magicMegatileStrategy = i;
+  }
+
+  void setPreshower( bool p ) {
+    _preshower = p? 1 : 0; // do we have preshower layer? (if 1, first layer is sensitive; if 0, first layer is absorber)
+  }
+
+  void setCFthickness( double absWrap, double alvWall, double front, double back ) {
+    _CF_absWrap = absWrap; // wrapping around absorber
+    _CF_alvWall = alvWall; // alveolar wall
+    _CF_front   = front;   // front (IP side) support plate
+    _CF_back    = back;    // back support plate
+  }
+
+  void setModuleDimensions( int XYtype, // module shape in XY
+			    int XZtype, // module shape in XZ
+			    double dX_max, // maximum extent in X
+			    double dY_kink = -999, // distance from lowerY edge to kink for XYtype=2
+			    double angle = M_PI/4. // angle, if not rectangular. pi/4 for octagon
+			    ) {
+    if ( XYtype>0 ) assert ( XZtype==0 ); // endcap module has vertical edges
+    if ( XZtype>0 ) assert ( XYtype==0 ); // barrel module should have rectangular shadow
+
+    _module_XYtype  = XYtype;
+    _module_XZtype  = XZtype;
+    _module_dX_max  = dX_max;
+    _module_dY_kink = dY_kink;
+    _module_angle   = angle;
+
+  }
+
+  void setTowersUnits( std::vector <int> ntowers, // a vector of modules, containing the specified # of towers/alveolii
+		       double towerWidth,
+		       int unitsPerTower, // # megatiles/units per tower
+		       double moduleDeadEdge, // dead region at edge of module
+		       double towerDeadEdge, // dead region at edge of tower
+		       double unitDeadEdge // width of dead region at edge of each unit (e.g. wafer's guard ring)
+		       ) {
+    _ntowers = ntowers;                 // number of towers (or alveoli) across Y
+    _alveolus_total_dim_Y = towerWidth; // width of tower (including dead area)
+    _unitsPerTower = unitsPerTower;     // how many units (megatiles/wafers) across one tower
+    _moduleGap = moduleDeadEdge;        // distance from tower boundary to edge of unit
+    _towerGap = towerDeadEdge;          // distance from tower boundary to edge of unit
+    _unitDeadEdge = unitDeadEdge;       // width of dead area around edge of unit
+  }
+
+  void checkLayerConsistency();
+
+  float getTotalThickness();
+
+  void setTranslation( dd4hep::Position trans ) {_trans = trans;}
+
+  // ---- this is the main workhorse
+  void makeModule( dd4hep::Volume & mod_vol,  // the volume we'll fill
+		   dd4hep::DetElement & stave_det, // the detector element
+		   dd4hep::rec::LayeredCalorimeterData & caloData, // the reco data we'll fill
+		   dd4hep::Detector & theDetector,
+		   dd4hep::SensitiveDetector & sens
+		   );
+
+  void setPlugLength( float ll ) { _plugLength = ll; }
+
+
+ private:
+
+  void printSEcal05LayerInfo( dd4hep::rec::LayeredCalorimeterData::Layer & caloLayer);
+
+  double getAbsThickness( unsigned int iAbsLay );
+
+  int getNumberOfAbsorberLayers() {
+    // total number of absorber layers
+    return _nlayers1+_nlayers2+_nlayers2;
+  }
+
+  int getNumberOfStructuralAbsorberLayers() {
+    // number of absorber layers in the module (not in the slabs)
+    assert( _preshower==0 || _preshower==1 );
+    return _preshower ? getNumberOfAbsorberLayers()/2 : (getNumberOfAbsorberLayers()-1)/2 ;
+  }
+
+  struct dimposXYStruct {
+    double sizeX, sizeY;
+    double posX, posY;
+  };
+
+  struct dxinfo {
+    int normal_nX;
+    
+    double magic1_unitDX;
+    int magic1_ncellsX;
+
+    double magic2_unitDX;
+  };
+
+  xml_det_t* _x_det;
+  dd4hep::Layering* _layering=NULL;
+  std::string _det_name;
+
+  std::vector <dimposXYStruct> getAbsPlateXYDimensions( double ztop=-999 );
+
+  std::vector <dimposXYStruct> getSlabXYDimensions( double ztop=-999 );
+
+
+  dd4hep::Position  getTranslatedPosition(double x, double y, double z) {
+    return dd4hep::Position ( x, y, z ) + _trans;
+  }
+
+  dxinfo getNormalMagicUnitsInX( double dx_total, double dx_unit, double dx_cell, double dx_dead ,
+				 int magicStrategy );
+
+  void updateCaloLayers(double thickness,
+			dd4hep::Material mat,
+			bool isAbsorber,
+			bool isSensitive,
+			double cell_size_x=0, double cell_size_y=0,
+			bool isFinal=false
+			);
+
+
+  dd4hep::Segmentation* _geomseg;
+
+  dd4hep::Material _air_material;
+  dd4hep::Material _carbon_fibre_material;
+  dd4hep::Material _radiator_material;
+
+  unsigned int _cells_across_megatile;
+  unsigned int _strips_across_megatile;
+  unsigned int _strips_along_megatile;   
+
+  int _preshower;
+
+  unsigned int _nlayers1;
+  unsigned int _nlayers2;
+  unsigned int _nlayers3;
+
+  double _radiator_thickness1;
+  double _radiator_thickness2;
+  double _radiator_thickness3;
+
+  std::vector < int > _layerConfig; // square or X or Y strips
+
+  double _CF_absWrap;
+  double _CF_alvWall;
+  double _CF_front;
+  double _CF_back;
+
+  // overall module size
+  int    _module_XYtype;
+  int    _module_XZtype;
+  double _module_dX_max;
+  double _module_dY_total;
+  double _module_dY_kink;
+  double _module_angle;
+
+  // internal details
+  std::vector <int> _ntowers;
+  double _towerGap;
+  double _moduleGap;
+  int    _unitsPerTower;
+  double _unitDeadEdge;
+
+  dd4hep::rec::LayeredCalorimeterData* _caloData;
+  dd4hep::rec::LayeredCalorimeterData::Layer _caloLayer ; // this is the output info which is passed to reconstruction
+
+  double _layer_thickness;
+  double _layer_nRadiationLengths;
+  double _layer_nInteractionLengths;
+
+  double _totThick;
+
+  double _alveolus_total_dim_Y;
+  double _module_thickness;
+
+  int _magicMegatileStrategy;
+
+  dd4hep::Position _trans;
+
+  std::vector <dimposXYStruct> _constantSlabXYDimensions;
+
+
+  float _plugLength;
+
+
+};
+
+#endif
diff --git a/Detector/DetEcalMatrix/CMakeLists.txt b/Detector/DetEcalMatrix/CMakeLists.txt
index 569a9e8fdb5ae716b4d7982c4f6a5a4fb5a8944f..54407d226fed4c44d41a0294e3ac8a8f0ebef1db 100644
--- a/Detector/DetEcalMatrix/CMakeLists.txt
+++ b/Detector/DetEcalMatrix/CMakeLists.txt
@@ -24,8 +24,13 @@ set(DetEcalMatrix_src
 
 gaudi_add_module(DetEcalMatrix
                   ${DetEcalMatrix_src}
-		  INCLUDE_DIRS DD4hep ROOT Geant4 src/include
-		  LINK_LIBRARIES GaudiKernel DD4hep ${DD4hep_COMPONENT_LIBRARIES} ROOT Geant4)
+		  INCLUDE_DIRS
+                  # DD4hep ROOT Geant4 src/include
+		  LINK_LIBRARIES 
+                  # GaudiKernel 
+                  DD4hep ${DD4hep_COMPONENT_LIBRARIES} 
+                  # ROOT Geant4
+)
 
 set(LIBRARY_OUTPUT_PATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
 message(STATUS "LIBRARY_OUTPUT_PATH -> ${LIBRARY_OUTPUT_PATH}")
diff --git a/Detector/DetEcalMatrix/compact/det.xml b/Detector/DetEcalMatrix/compact/det.xml
index bb4f486360a1c5bee3176f9ca2214653ddda0cf7..2cd46f4fe3081ca4bb416e503022108b450466a9 100644
--- a/Detector/DetEcalMatrix/compact/det.xml
+++ b/Detector/DetEcalMatrix/compact/det.xml
@@ -32,16 +32,19 @@
 
   <detectors>
     <detector id="1" name="CaloDetector" type="EcalMatrix" readout="CaloHitsCollection" vis="VisibleGreen" sensitive="true">
-      <position x="0"  y="0"  z="1835*mm+30*cm"/>
+      <!-- Use cm as unit if you want to use Pandora for reconstruction -->
+      <position x="200*cm"  y="0"  z="0"/>
       <dimensions dx="30*cm"  dy="30*cm"  dz="30*cm"/>
     </detector>
   </detectors>
   
   <readouts>
     <readout name="CaloHitsCollection">
-      <segmentation type="CartesianGridXYZ" 
-                    grid_size_x="1*cm" 
-                    grid_size_y="1*cm" 
+      <!-- <segmentation type="NoSegmentation"/> -->
+
+      <segmentation type="CartesianGridXYZ"
+                    grid_size_x="1*cm"
+                    grid_size_y="1*cm"
                     grid_size_z="1*cm"/>
       <id>system:8,x:32:-6,y:-6,z:-6</id>
     </readout>
diff --git a/Detector/DetEcalMatrix/src/calorimeter/EcalMatrix.cpp b/Detector/DetEcalMatrix/src/calorimeter/EcalMatrix.cpp
index 274330ba63acddec63b9c15abcdea8e8b3ac6d37..f12972c81dcdbc647b9112324e7d16b59e746ad8 100644
--- a/Detector/DetEcalMatrix/src/calorimeter/EcalMatrix.cpp
+++ b/Detector/DetEcalMatrix/src/calorimeter/EcalMatrix.cpp
@@ -16,6 +16,7 @@
 #define MYDEBUG(x) std::cout << __FILE__ << ":" << __LINE__ << ": " << x << std::endl;
 #define MYDEBUGVAL(x) std::cout << __FILE__ << ":" << __LINE__ << ": " << #x << ": " << x << std::endl;
 
+using dd4hep::rec::LayeredCalorimeterData;
 static dd4hep::Ref_t create_detector(dd4hep::Detector& theDetector,
                                      xml_h e,
                                      dd4hep::SensitiveDetector sens) {
@@ -40,6 +41,51 @@ static dd4hep::Ref_t create_detector(dd4hep::Detector& theDetector,
     dd4hep::Transform3D transform(dd4hep::Rotation3D(),
                                   dd4hep::Position(pos.x(),pos.y(),pos.z()));
     dd4hep::PlacedVolume phv = motherVol.placeVolume(det_vol,transform);
+    //Create caloData object to extend driver with data required for reconstruction
+    LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
+    caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
+    caloData->inner_symmetry = 8 ;//nsides
+    caloData->outer_symmetry = 8; //nsides;
+    caloData->inner_phi0 = 0.;
+    caloData->outer_phi0 = 0.; 
+    caloData->gap0 = 0.; //FIXME
+    caloData->gap1 = 0.; //FIXME
+    caloData->gap2 = 0.; //FIXME
+    // extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
+    caloData->extent[0] = 10*( pos.x()-dim.dx() );// from cm to mm
+    caloData->extent[1] = 10*( pos.x()+dim.dx() );// from cm to mm
+    caloData->extent[2] = 0 ;
+    caloData->extent[3] = 10*( pos.z()+dim.dz() );// from cm to mm
+    std::cout<<"rmin="<<caloData->extent[0]<<",rmax="<<caloData->extent[1]<<",zmin="<<caloData->extent[2]<<",zmax="<<caloData->extent[3]<<std::endl;
+    dd4hep::Readout readout = sens.readout();
+    dd4hep::Segmentation seg = readout.segmentation();
+
+    std::cout << "TAO: "
+              << " field description: " << seg.segmentation()->fieldDescription()
+              // << " grid size x/y/z: "
+              // << seg.segmentation()->parameter("grid_size_x")->toString()
+              // << seg.segmentation()->parameter("grid_size_x")->toString()
+              // << seg.segmentation()->parameter("grid_size_x")->toString()
+              << std::endl;
+
+
+    double cellSize_x = ::atof( seg.segmentation()->parameter("grid_size_x")->value().c_str() ) * 10;// from cm to mm
+    double cellSize_y = ::atof( seg.segmentation()->parameter("grid_size_y")->value().c_str() ) * 10;// from cm to mm
+    double cellSize_z = ::atof( seg.segmentation()->parameter("grid_size_z")->value().c_str() ) * 10;// from cm to mm
+    int n_layer = int(2*dim.dx()*10/cellSize_x) ; // here the calorimeter is placed in barrel, so x direaction is layer direction
+    std::cout<<"cellx="<<cellSize_x<<",celly="<<cellSize_y<<",cellz="<<cellSize_z<<",dx="<<dim.dx()*10<<"mm,n_layer="<<n_layer<<std::endl;
+    for(int i=1 ; i <= n_layer; i++)
+    {
+        LayeredCalorimeterData::Layer caloLayer ;
+        caloLayer.distance = caloData->extent[0] + (i-0.5)*cellSize_x; //NEED TO START FROM ORIGIN, to mm
+        caloLayer.sensitive_thickness = cellSize_x ;
+        caloLayer.inner_thickness = cellSize_x ;
+        caloLayer.outer_thickness = cellSize_x ;
+        caloLayer.absorberThickness = cellSize_x;
+        caloLayer.cellSize0 = cellSize_y;
+        caloLayer.cellSize1 = cellSize_z;
+        caloData->layers.push_back(caloLayer); 
+    }
 
     if ( x_det.isSensitive() )   {
         dd4hep::SensitiveDetector sd = sens;
@@ -50,7 +96,7 @@ static dd4hep::Ref_t create_detector(dd4hep::Detector& theDetector,
         phv.addPhysVolID("system",x_det.id());
     }
     sdet.setPlacement(phv);
-    
+    sdet.addExtension< LayeredCalorimeterData >(caloData) ; 
     MYDEBUG("create_detector DONE. ");
     return sdet;
 }
diff --git a/Detector/DetInterface/DetInterface/IGeoSvc.h b/Detector/DetInterface/DetInterface/IGeoSvc.h
index 58df046d4aed0d5e22674f84db704c2d06bf749b..2925d7a2dec6ce96ffbe3f26779fadd1fa742c57 100644
--- a/Detector/DetInterface/DetInterface/IGeoSvc.h
+++ b/Detector/DetInterface/DetInterface/IGeoSvc.h
@@ -13,14 +13,18 @@
 #include "GaudiKernel/IService.h"
 
 namespace dd4hep {
-class Detector;
-class DetElement;
+    class Detector;
+    class DetElement;
+    namespace DDSegmentation {
+        class BitFieldCoder;
+    }
 }
 
 // class G4VUserDetectorConstruction;
 
 class GAUDI_API IGeoSvc : virtual public IService {
-
+public:
+  typedef dd4hep::DDSegmentation::BitFieldCoder Decoder;
 public:
   /// InterfaceID
   DeclareInterfaceID(IGeoSvc, 1, 0);
@@ -30,6 +34,9 @@ public:
   // receive Geant4 Geometry
   // virtual G4VUserDetectorConstruction* getGeant4Geo() = 0;
 
+  // short cut to retrieve the Decoder according to the Readout name
+  virtual Decoder* getDecoder(const std::string& readout_name) = 0;
+
   virtual ~IGeoSvc() {}
 };
 
diff --git a/Detector/GeoSvc/CMakeLists.txt b/Detector/GeoSvc/CMakeLists.txt
index 569c85334afb3ab6027dd66d158c6e6bd4b1afd6..2a5b97ded1389cd0a45a5f41ba8d5c562580a031 100644
--- a/Detector/GeoSvc/CMakeLists.txt
+++ b/Detector/GeoSvc/CMakeLists.txt
@@ -18,7 +18,13 @@ find_package(DD4hep COMPONENTS DDG4 DDRec REQUIRED)
 gaudi_add_module(GeoSvc
                  src/GeoSvc.cpp
                  INCLUDE_DIRS
-                   DetInterface DD4hep GaudiKernel ROOT 
+                   # DetInterface
+                   # DD4hep
+                   # GaudiKernel
+                   # ROOT 
                  LINK_LIBRARIES
-                   DD4hep ${DD4hep_COMPONENT_LIBRARIES} GaudiKernel ROOT
+                   DD4hep 
+                   ${DD4hep_COMPONENT_LIBRARIES} 
+                   GaudiKernel 
+                   # ROOT
 )
\ No newline at end of file
diff --git a/Detector/GeoSvc/src/GeoSvc.cpp b/Detector/GeoSvc/src/GeoSvc.cpp
index 305896c44546a12d3e34e3630f2632fe23a0806c..1739aa8a68e3996ea56d37849ffefa8dcd0b2f71 100644
--- a/Detector/GeoSvc/src/GeoSvc.cpp
+++ b/Detector/GeoSvc/src/GeoSvc.cpp
@@ -46,3 +46,34 @@ dd4hep::Detector*
 GeoSvc::lcdd() {
     return m_dd4hep_geo;
 }
+
+IGeoSvc::Decoder*
+GeoSvc::getDecoder(const std::string& readout_name) {
+
+    IGeoSvc::Decoder* decoder = nullptr;
+
+    if (!lcdd()) {
+        error() << "Failed to get lcdd()" << endmsg;
+        return decoder;
+    }
+
+    auto readouts = m_dd4hep_geo->readouts();
+    if (readouts.find(readout_name) == readouts.end()) {
+        error() << "Failed to find readout name '" << readout_name << "'"
+                << " in DD4hep::readouts. "
+                << endmsg;
+        return decoder;
+    }
+    
+    dd4hep::Readout readout = lcdd()->readout(readout_name);
+    auto m_idspec = readout.idSpec(); 
+
+    decoder = m_idspec.decoder();
+
+    if (!decoder) {
+        error() << "Failed to get the decoder with readout '"
+                << readout_name << "'" << endmsg;
+    }
+
+    return decoder;
+}
diff --git a/Detector/GeoSvc/src/GeoSvc.h b/Detector/GeoSvc/src/GeoSvc.h
index 9c98daa9d58bb5f4786aa2881eb639716fc7d5ff..1be2b4ff4e0d4a504e216cc9b9a302dec001f5f6 100644
--- a/Detector/GeoSvc/src/GeoSvc.h
+++ b/Detector/GeoSvc/src/GeoSvc.h
@@ -28,6 +28,8 @@ public:
     dd4hep::DetElement getDD4HepGeo() override;
     dd4hep::Detector* lcdd() override;
 
+    Decoder* getDecoder(const std::string& readout_name) override;
+
 private:
 
     // DD4hep XML compact file path
@@ -38,4 +40,4 @@ private:
 };
 
 
-#endif GeoSvc_h
+#endif // GeoSvc_h
diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt
index f9f4c9d92f6f09025b391d2fb50a756371fe8006..8a0ba74979b16bc41d1e26dee535ac00fd12f51f 100644
--- a/Examples/CMakeLists.txt
+++ b/Examples/CMakeLists.txt
@@ -2,14 +2,23 @@
 gaudi_subdir(Examples v0r0)
 
 find_package(podio REQUIRED)
-find_package(plcio REQUIRED)
+#find_package(plcio REQUIRED)
 find_package(LCIO REQUIRED)
+find_package(EDM4HEP REQUIRED)
+find_package(K4FWCore REQUIRED)
+find_package(DD4hep COMPONENTS DDRec DDParsers REQUIRED)
+
+gaudi_depends_on_subdirs(
+    Detector/DetInterface
+)
 
 set(Examples_srcs
     src/HelloWorld/*.cpp
     src/FirstSvc/*.cpp
     src/SecondAlg/*.cpp
-    src/PlcioTest/*.cpp
+ #   src/PlcioTest/*.cpp
+    src/Edm4hepTest/*.cpp
+    src/DumpIDAlg/*.cpp
 )
 
 # Headers and Libraries
@@ -18,8 +27,11 @@ gaudi_install_headers(Examples)
 
 # Modules
 gaudi_add_module(Examples ${Examples_srcs}
-    INCLUDE_DIRS GaudiKernel FWCore ${plcio_INCLUDE_DIRS} ${podio_INCLUDE_DIRS} ${LCIO_INCLUDE_DIRS}
-    LINK_LIBRARIES GaudiKernel FWCore ${podio_LIBRARIES} ${LCIO_LIBRARIES} $ENV{PLCIO}/lib/libplcio.so
+    INCLUDE_DIRS K4FWCore GaudiAlgLib GaudiKernel ${podio_INCLUDE_DIRS} ${LCIO_INCLUDE_DIRS}
+    LINK_LIBRARIES K4FWCore GaudiAlgLib GaudiKernel ${LCIO_LIBRARIES} 
+      DD4hep ${DD4hep_COMPONENT_LIBRARIES}
+      # Force loading the libraries.
+      -Wl,--no-as-needed EDM4HEP::edm4hep EDM4HEP::edm4hepDict ${podio_LIBRARIES} podio::podioRootIO -Wl,--as-needed
 )
 
 # Unit tests
@@ -35,6 +47,12 @@ gaudi_add_test(PlcioWriteAlg
 gaudi_add_test(PlcioReadAlg
                FRAMEWORK options/plcio_read.py)
 
+gaudi_add_test(Edm4hepWriteAlg
+               FRAMEWORK options/edm4hep_write.py)
+
+gaudi_add_test(Edm4hepReadAlg
+               FRAMEWORK options/edm4hep_read.py)
+
 gaudi_add_test(LCIOReadAlg
                FRAMEWORK options/LCIO_read.py)
 
diff --git a/Examples/options/LCIO_read_pan.py b/Examples/options/LCIO_read_pan.py
new file mode 100644
index 0000000000000000000000000000000000000000..97b5f9e974a0db059bb5a7d4a1da503d07887a16
--- /dev/null
+++ b/Examples/options/LCIO_read_pan.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+
+from Gaudi.Configuration import *
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
+
+# read LCIO files
+from Configurables import LCIOInput
+read = LCIOInput("read")
+read.inputs = [
+#"/cefs/data/FullSim/CEPC240/CEPC_v4/higgs/smart_final_states/E240.Pffh_invi.e0.p0.whizard195//ffh_inv.e0.p0.00001_1000_sim.slcio"
+#"/junofs/users/wxfang/CEPC/CEPCOFF/doReco/reco_output/nnh_aa.e0.p0.00010_000000_rec.slcio"
+"/cefs/higgs/wxfang/cepc/Pandora/CaloDigi/gamma/Digi_sim_0.slcio"
+]
+read.collections = {
+        #"COILCollection" : "SimTrackerHit",
+        #"EcalBarrelSiliconCollection" : "SimCalorimeterHit",
+        "MCParticle" : "MCParticle",
+        "ECALBarrel" : "CalorimeterHit",
+        "ECALEndcap" : "CalorimeterHit",
+        "ECALOther"  : "CalorimeterHit",
+        "HCALBarrel" : "CalorimeterHit",
+        "HCALEndcap" : "CalorimeterHit",
+        "HCALOther"  : "CalorimeterHit",
+        "MUON"       : "CalorimeterHit",
+        "LCAL"       : "CalorimeterHit",
+        "LHCAL"      : "CalorimeterHit",
+        "BCAL"       : "CalorimeterHit",
+        #"MarlinTrkTracks" : "Track"
+        #"TPCCollection" : "SimTrackerHit",
+        #"VXDCollection" : "SimTrackerHit"
+}
+##############################################################################
+from Configurables import GearSvc
+gearSvc  = GearSvc("GearSvc")
+gearSvc.GearXMLFile = "/junofs/users/wxfang/CEPC/CEPCOFF/doSim/fullDet/GearOutput.xml"
+##############################################################################
+from Configurables import PandoraPFAlg
+
+pandoralg = PandoraPFAlg("PandoraPFAlg")
+## KEEP same with lcioinput name for the ReadXXX ###########
+pandoralg.ReadMCParticle                       = "MCParticle"                   
+pandoralg.ReadECALBarrel                       = "ECALBarrel"                   
+pandoralg.ReadECALEndcap                       = "ECALEndcap"                   
+pandoralg.ReadECALOther                        = "ECALOther"                    
+pandoralg.ReadHCALBarrel                       = "HCALBarrel"                   
+pandoralg.ReadHCALEndcap                       = "HCALEndcap"                   
+pandoralg.ReadHCALOther                        = "HCALOther"                    
+pandoralg.ReadMUON                             = "MUON"                         
+pandoralg.ReadLCAL                             = "LCAL"                         
+pandoralg.ReadLHCAL                            = "LHCAL"                        
+pandoralg.ReadBCAL                             = "BCAL"                         
+pandoralg.ReadKinkVertices                     = "KinkVertices"                 
+pandoralg.ReadProngVertices                    = "ProngVertices"                
+pandoralg.ReadSplitVertices                    = "SplitVertices"                
+pandoralg.ReadV0Vertices                       = "V0Vertices"                   
+pandoralg.ReadTracks                           = "MarlinTrkTracks"                       
+pandoralg.WriteClusterCollection               = "PandoraClusters"              
+pandoralg.WriteReconstructedParticleCollection = "PandoraPFOs" 
+pandoralg.WriteVertexCollection                = "PandoraPFANewStartVertices"               
+pandoralg.AnaOutput = "/cefs/higgs/wxfang/cepc/Pandora/Ana/gamma/Ana_gamma_test.root"
+
+pandoralg.PandoraSettingsDefault_xml = "/junofs/users/wxfang/MyGit/MarlinPandora/scripts/PandoraSettingsDefault_wx.xml"
+#### Do not chage the collection name, only add or delete ###############
+pandoralg.TrackCollections      =  ["MarlinTrkTracks"]
+pandoralg.ECalCaloHitCollections=  ["ECALBarrel", "ECALEndcap", "ECALOther"]
+pandoralg.HCalCaloHitCollections=  ["HCALBarrel", "HCALEndcap", "HCALOther"]
+pandoralg.LCalCaloHitCollections=  ["LCAL"]
+pandoralg.LHCalCaloHitCollections= ["LHCAL"]
+pandoralg.MuonCaloHitCollections=  ["MUON"]
+pandoralg.MCParticleCollections =  ["MCParticle"]
+pandoralg.RelCaloHitCollections =  ["RecoCaloAssociation_ECALBarrel", "RecoCaloAssociation_ECALEndcap", "RecoCaloAssociation_ECALOther", "RecoCaloAssociation_HCALBarrel", "RecoCaloAssociation_HCALEndcap", "RecoCaloAssociation_HCALOther", "RecoCaloAssociation_LCAL", "RecoCaloAssociation_LHCAL", "RecoCaloAssociation_MUON"]
+pandoralg.RelTrackCollections   =  ["MarlinTrkTracksMCTruthLink"]
+pandoralg.KinkVertexCollections =  ["KinkVertices"]
+pandoralg.ProngVertexCollections=  ["ProngVertices"]
+pandoralg.SplitVertexCollections=  ["SplitVertices"]
+pandoralg.V0VertexCollections   =  ["V0Vertices"]
+pandoralg.ECalToMipCalibration  = 160.0 
+pandoralg.HCalToMipCalibration  = 34.8 
+pandoralg.ECalMipThreshold      = 0.5 
+pandoralg.HCalMipThreshold      = 0.3 
+pandoralg.ECalToEMGeVCalibration= 0.9 #for G2CD Digi, 1.007 for NewLDCaloDigi 
+pandoralg.HCalToEMGeVCalibration= 1.007 
+pandoralg.ECalToHadGeVCalibrationBarrel= 1.12 #very small effect 
+pandoralg.ECalToHadGeVCalibrationEndCap= 1.12 
+pandoralg.HCalToHadGeVCalibration= 1.07
+pandoralg.MuonToMipCalibration= 10.0 
+pandoralg.DigitalMuonHits= 0 
+pandoralg.MaxHCalHitHadronicEnergy   = 1.0 
+pandoralg.UseOldTrackStateCalculation= 0 
+pandoralg.AbsorberRadLengthECal= 0.2854 
+pandoralg.AbsorberIntLengthECal= 0.0101 
+pandoralg.AbsorberRadLengthHCal= 0.0569 
+pandoralg.AbsorberIntLengthHCal= 0.006  
+pandoralg.AbsorberRadLengthOther= 0.0569
+pandoralg.AbsorberIntLengthOther= 0.006 
+
+##############################################################################
+
+# write PODIO file
+from Configurables import PodioOutput
+write = PodioOutput("write")
+write.filename = "test.root"
+write.outputCommands = ["keep *"]
+
+# ApplicationMgr
+from Configurables import ApplicationMgr
+ApplicationMgr(
+        #TopAlg = [read, pandoralg, write],
+        TopAlg = [read, pandoralg],
+        EvtSel = 'NONE',
+        EvtMax = 10,
+        ExtSvc = [dsvc, gearSvc],
+        OutputLevel=INFO
+)
diff --git a/Examples/options/edm4hep_read.py b/Examples/options/edm4hep_read.py
new file mode 100644
index 0000000000000000000000000000000000000000..998b300ec72179a375eb687f25dcbc09a742108b
--- /dev/null
+++ b/Examples/options/edm4hep_read.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+from Gaudi.Configuration import *
+
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc", input="test.root")
+
+from Configurables import Edm4hepReadAlg
+alg = Edm4hepReadAlg("Edm4hepReadAlg")
+alg.HeaderCol.Path = "EventHeader"
+alg.InputCol.Path = "MCParticle"
+
+from Configurables import PodioInput
+podioinput = PodioInput("PodioReader", collections=[
+    "EventHeader",
+    "MCParticle"
+    ])
+
+# ApplicationMgr
+from Configurables import ApplicationMgr
+ApplicationMgr( TopAlg = [podioinput, alg],
+                EvtSel = 'NONE',
+                EvtMax = 10,
+                ExtSvc = [dsvc],
+                OutputLevel=DEBUG
+)
diff --git a/Examples/options/edm4hep_write.py b/Examples/options/edm4hep_write.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5ad0bef5550d9cab2a7d6e451bb189fefa6120b
--- /dev/null
+++ b/Examples/options/edm4hep_write.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+from Gaudi.Configuration import *
+
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
+
+from Configurables import Edm4hepWriteAlg
+alg = Edm4hepWriteAlg("Edm4hepWriteAlg")
+alg.HeaderCol.Path = "EventHeader"
+alg.OutputCol.Path = "MCParticle"
+
+from Configurables import PodioOutput
+out = PodioOutput("out")
+out.filename = "test.root"
+out.outputCommands = ["keep *"]
+
+# ApplicationMgr
+from Configurables import ApplicationMgr
+ApplicationMgr( TopAlg = [alg, out],
+                EvtSel = 'NONE',
+                EvtMax = 10,
+                ExtSvc=[dsvc],
+                OutputLevel=DEBUG
+)
diff --git a/Examples/options/plcio_read.py b/Examples/options/plcio_read.py
index d8b0b7395def1db1c04df844372967d7b42d4ab1..62c682b119b0acf413bbc3e1eca65983d4cd6343 100644
--- a/Examples/options/plcio_read.py
+++ b/Examples/options/plcio_read.py
@@ -2,8 +2,8 @@
 
 from Gaudi.Configuration import *
 
-from Configurables import CEPCDataSvc
-dsvc = CEPCDataSvc("EventDataSvc", input="test.root")
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc", input="test.root")
 
 from Configurables import PlcioReadAlg
 alg = PlcioReadAlg("PlcioReadAlg")
diff --git a/Examples/options/plcio_write.py b/Examples/options/plcio_write.py
index 378aae8406012a0f008c3ce3ff6a5fb306297938..17bab8ed634928f0193f467e58d55aec30b54a54 100644
--- a/Examples/options/plcio_write.py
+++ b/Examples/options/plcio_write.py
@@ -2,8 +2,8 @@
 
 from Gaudi.Configuration import *
 
-from Configurables import CEPCDataSvc
-dsvc = CEPCDataSvc("EventDataSvc")
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
 
 from Configurables import PlcioWriteAlg
 alg = PlcioWriteAlg("PlcioWriteAlg")
diff --git a/Examples/options/tut_detsim.py b/Examples/options/tut_detsim.py
index 2ecb5e3f6ea15ba4ce0dd5b6f8e37b33c102c1c2..3c9071ed5e8580691c2d7412e9478feb83500ea9 100644
--- a/Examples/options/tut_detsim.py
+++ b/Examples/options/tut_detsim.py
@@ -24,8 +24,8 @@ rndmengine.Seeds = [42]
 ##############################################################################
 # Event Data Svc
 ##############################################################################
-from Configurables import CEPCDataSvc
-dsvc = CEPCDataSvc("EventDataSvc")
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
 
 
 ##############################################################################
@@ -58,18 +58,19 @@ from Configurables import SLCIORdr
 from Configurables import HepMCRdr
 from Configurables import GenPrinter
 
-# gun = GtGunTool("GtGunTool")
-# gun.Particles = ["pi+"]
-# gun.Energies = [100.] # GeV
+gun = GtGunTool("GtGunTool")
+gun.Particles = ["pi+"]
+gun.EnergyMins = [100.] # GeV
+gun.EnergyMaxs = [100.] # GeV
 
-# gun.ThetaMins = [] # rad; 45deg
-# gun.ThetaMaxs = [] # rad; 45deg
+gun.ThetaMins = [0] # rad; 45deg
+gun.ThetaMaxs = [180.] # rad; 45deg
 
-# gun.PhiMins = [] # rad; 0deg
-# gun.PhiMaxs = [] # rad; 360deg
+gun.PhiMins = [0] # rad; 0deg
+gun.PhiMaxs = [360.] # rad; 360deg
 
-stdheprdr = StdHepRdr("StdHepRdr")
-stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
+# stdheprdr = StdHepRdr("StdHepRdr")
+# stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
 
 # lciordr = SLCIORdr("SLCIORdr")
 # lciordr.Input = "/cefs/data/stdhep/lcio250/signal/Higgs/E250.Pbbh.whizard195/E250.Pbbh_X.e0.p0.whizard195/Pbbh_X.e0.p0.00001.slcio"
@@ -80,8 +81,8 @@ stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizar
 genprinter = GenPrinter("GenPrinter")
 
 genalg = GenAlgo("GenAlgo")
-# genalg.GenTools = ["GtGunTool"]
-genalg.GenTools = ["StdHepRdr"]
+genalg.GenTools = ["GtGunTool"]
+# genalg.GenTools = ["StdHepRdr"]
 # genalg.GenTools = ["StdHepRdr", "GenPrinter"]
 # genalg.GenTools = ["SLCIORdr", "GenPrinter"]
 # genalg.GenTools = ["HepMCRdr", "GenPrinter"]
@@ -107,7 +108,8 @@ detsimalg.RunCmds = [
 ]
 detsimalg.AnaElems = [
     # example_anatool.name()
-    "ExampleAnaElemTool"
+    # "ExampleAnaElemTool"
+    "Edm4hepWriterAnaElemTool"
 ]
 detsimalg.RootDetElem = "WorldDetElemTool"
 
diff --git a/Examples/options/tut_detsim_pan_matrix.py b/Examples/options/tut_detsim_pan_matrix.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d5bd4561d3f5bd4318455d7c6a9a54df88c5aa2
--- /dev/null
+++ b/Examples/options/tut_detsim_pan_matrix.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+
+import os
+print(os.environ["DD4HEP_LIBRARY_PATH"])
+import sys
+# sys.exit(0)
+
+from Gaudi.Configuration import *
+
+##############################################################################
+# Random Number Svc
+##############################################################################
+from Configurables import RndmGenSvc, HepRndm__Engine_CLHEP__RanluxEngine_
+
+# rndmengine = HepRndm__Engine_CLHEP__RanluxEngine_() # The default engine in Gaudi
+rndmengine = HepRndm__Engine_CLHEP__HepJamesRandom_() # The default engine in Geant4
+rndmengine.SetSingleton = True
+rndmengine.Seeds = [42]
+
+# rndmgensvc = RndmGenSvc("RndmGenSvc")
+# rndmgensvc.Engine = rndmengine.name()
+
+
+##############################################################################
+# Event Data Svc
+##############################################################################
+#from Configurables import CEPCDataSvc
+#dsvc = CEPCDataSvc("EventDataSvc")
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
+
+
+##############################################################################
+# Geometry Svc
+##############################################################################
+
+# geometry_option = "CepC_v4-onlyTracker.xml"
+geometry_option = "CepC_v4-onlyVXD.xml"
+
+if not os.getenv("DETCEPCV4ROOT"):
+    print("Can't find the geometry. Please setup envvar DETCEPCV4ROOT." )
+    sys.exit(-1)
+
+geometry_path = os.path.join(os.getenv("DETCEPCV4ROOT"), "compact", geometry_option)
+if not os.path.exists(geometry_path):
+    print("Can't find the compact geometry file: %s"%geometry_path)
+    sys.exit(-1)
+
+from Configurables import GeoSvc
+geosvc = GeoSvc("GeoSvc")
+#geosvc.compact = geometry_path
+geosvc.compact = "../Detector/DetEcalMatrix/compact/det.xml"
+
+##############################################################################
+# Physics Generator
+##############################################################################
+from Configurables import GenAlgo
+from Configurables import GtGunTool
+from Configurables import StdHepRdr
+from Configurables import SLCIORdr
+from Configurables import HepMCRdr
+from Configurables import GenPrinter
+
+gun = GtGunTool("GtGunTool")
+gun.Particles = ["gamma","gamma"]
+gun.EnergyMins= [10, 10] # GeV
+gun.EnergyMaxs= [10, 10] # GeV
+gun.ThetaMins = [90, 90] # degree
+gun.ThetaMaxs = [90, 90] # degree
+gun.PhiMins   = [0,  1 ] # degree
+gun.PhiMaxs   = [0,  1 ] # degree
+
+
+stdheprdr = StdHepRdr("StdHepRdr")
+#stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
+#stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
+stdheprdr.Input = "/cefs/data/stdhep/CEPC250/higgs/E250.Pbbh.whizard195/E250.Pbbh_X.e0.p0.whizard195/Pbbh_X.e0.p0.00001.stdhep"
+
+# lciordr = SLCIORdr("SLCIORdr")
+# lciordr.Input = "/cefs/data/stdhep/lcio250/signal/Higgs/E250.Pbbh.whizard195/E250.Pbbh_X.e0.p0.whizard195/Pbbh_X.e0.p0.00001.slcio"
+
+# hepmcrdr = HepMCRdr("HepMCRdr")
+# hepmcrdr.Input = "example_UsingIterators.txt"
+
+genprinter = GenPrinter("GenPrinter")
+
+genalg = GenAlgo("GenAlgo")
+genalg.GenTools = ["GtGunTool"]
+#genalg.GenTools = ["StdHepRdr"]
+# genalg.GenTools = ["StdHepRdr", "GenPrinter"]
+# genalg.GenTools = ["SLCIORdr", "GenPrinter"]
+# genalg.GenTools = ["HepMCRdr", "GenPrinter"]
+
+##############################################################################
+# Detector Simulation
+##############################################################################
+from Configurables import DetSimSvc
+
+detsimsvc = DetSimSvc("DetSimSvc")
+
+# from Configurables import ExampleAnaElemTool
+# example_anatool = ExampleAnaElemTool("ExampleAnaElemTool")
+
+from Configurables import DetSimAlg
+
+detsimalg = DetSimAlg("DetSimAlg")
+
+# detsimalg.VisMacs = ["vis.mac"]
+
+detsimalg.RunCmds = [
+#    "/tracking/verbose 1",
+]
+detsimalg.AnaElems = [
+    # example_anatool.name()
+    # "ExampleAnaElemTool"
+    "Edm4hepWriterAnaElemTool"
+]
+detsimalg.RootDetElem = "WorldDetElemTool"
+
+from Configurables import AnExampleDetElemTool
+example_dettool = AnExampleDetElemTool("AnExampleDetElemTool")
+
+##############################################################################
+from Configurables import CaloDigiAlg
+example_CaloDigiAlg = CaloDigiAlg("CaloDigiAlg")
+example_CaloDigiAlg.Scale = 1
+example_CaloDigiAlg.SimCaloHitCollection = "SimCalorimeterCol"
+example_CaloDigiAlg.CaloHitCollection    = "ECALBarrel"
+example_CaloDigiAlg.CaloAssociationCollection    = "RecoCaloAssociation_ECALBarrel"
+##############################################################################
+from Configurables import GearSvc
+gearSvc  = GearSvc("GearSvc")
+#gearSvc.GearXMLFile = "/junofs/users/wxfang/CEPC/CEPCOFF/doSim/fullDet/GearOutput.xml"
+gearSvc.GearXMLFile = "../Detector/DetCEPCv4/compact/FullDetGear.xml"
+##############################################################################
+#from Configurables import PandoraPFAlg
+from Configurables import PandoraMatrixAlg
+
+#pandoralg = PandoraPFAlg("PandoraPFAlg")
+pandoralg = PandoraMatrixAlg("PandoraMatrixAlg")
+## KEEP same with lcioinput name for the ReadXXX ###########
+pandoralg.ReadMCParticle                       = "MCParticle"                   
+pandoralg.ReadECALBarrel                       = "ECALBarrel"                   
+pandoralg.ReadECALEndcap                       = "ECALEndcap"                   
+pandoralg.ReadECALOther                        = "ECALOther"                    
+pandoralg.ReadHCALBarrel                       = "HCALBarrel"                   
+pandoralg.ReadHCALEndcap                       = "HCALEndcap"                   
+pandoralg.ReadHCALOther                        = "HCALOther"                    
+pandoralg.ReadMUON                             = "MUON"                         
+pandoralg.ReadLCAL                             = "LCAL"                         
+pandoralg.ReadLHCAL                            = "LHCAL"                        
+pandoralg.ReadBCAL                             = "BCAL"                         
+pandoralg.ReadKinkVertices                     = "KinkVertices"                 
+pandoralg.ReadProngVertices                    = "ProngVertices"                
+pandoralg.ReadSplitVertices                    = "SplitVertices"                
+pandoralg.ReadV0Vertices                       = "V0Vertices"                   
+pandoralg.ReadTracks                           = "MarlinTrkTracks"                       
+pandoralg.MCRecoCaloAssociation                = "RecoCaloAssociation_ECALBarrel"                       
+pandoralg.WriteClusterCollection               = "PandoraClusters"              
+pandoralg.WriteReconstructedParticleCollection = "PandoraPFOs" 
+pandoralg.WriteVertexCollection                = "PandoraPFANewStartVertices"               
+pandoralg.AnaOutput = "/cefs/higgs/wxfang/cepc/Pandora/Ana/gamma/Ana_gamma_Matrix_Rel_10GeV_test.root"
+
+pandoralg.PandoraSettingsDefault_xml = "/junofs/users/wxfang/MyGit/MarlinPandora/scripts/PandoraSettingsDefault_wx.xml"
+#### Do not chage the collection name, only add or delete ###############
+pandoralg.TrackCollections      =  ["MarlinTrkTracks"]
+pandoralg.ECalCaloHitCollections=  ["ECALBarrel", "ECALEndcap", "ECALOther"]
+pandoralg.HCalCaloHitCollections=  ["HCALBarrel", "HCALEndcap", "HCALOther"]
+pandoralg.LCalCaloHitCollections=  ["LCAL"]
+pandoralg.LHCalCaloHitCollections= ["LHCAL"]
+pandoralg.MuonCaloHitCollections=  ["MUON"]
+pandoralg.MCParticleCollections =  ["MCParticle"]
+pandoralg.RelCaloHitCollections =  ["RecoCaloAssociation_ECALBarrel", "RecoCaloAssociation_ECALEndcap", "RecoCaloAssociation_ECALOther", "RecoCaloAssociation_HCALBarrel", "RecoCaloAssociation_HCALEndcap", "RecoCaloAssociation_HCALOther", "RecoCaloAssociation_LCAL", "RecoCaloAssociation_LHCAL", "RecoCaloAssociation_MUON"]
+pandoralg.RelTrackCollections   =  ["MarlinTrkTracksMCTruthLink"]
+pandoralg.KinkVertexCollections =  ["KinkVertices"]
+pandoralg.ProngVertexCollections=  ["ProngVertices"]
+pandoralg.SplitVertexCollections=  ["SplitVertices"]
+pandoralg.V0VertexCollections   =  ["V0Vertices"]
+pandoralg.ECalToMipCalibration  = 112 #1000MeV/8.918 #CEPC :160.0 
+pandoralg.HCalToMipCalibration  = 34.8 
+pandoralg.ECalMipThreshold      = 0.225# 8.918*0.225=2.00655 #CEPC 0.5 
+pandoralg.HCalMipThreshold      = 0.3 
+pandoralg.ECalToEMGeVCalibration= 1.# BGO, to be tuned  # CEPC: 0.9 for G2CD Digi, 1.007 for NewLDCaloDigi 
+pandoralg.HCalToEMGeVCalibration= 1.007 
+pandoralg.ECalToHadGeVCalibrationBarrel= 1.12 #very small effect 
+pandoralg.ECalToHadGeVCalibrationEndCap= 1.12 
+pandoralg.HCalToHadGeVCalibration= 1.07
+pandoralg.MuonToMipCalibration= 10.0 
+pandoralg.DigitalMuonHits= 0 
+pandoralg.MaxHCalHitHadronicEnergy   = 1.0 
+pandoralg.UseOldTrackStateCalculation= 0 
+pandoralg.AbsorberRadLengthECal= 0.08945 #BG0: 1/11.18 mm , CEPC: 0.2854 = 1/3.504 mm 
+pandoralg.AbsorberIntLengthECal= 0.00448 #BG0: 1/223.2 mm , CEPC: 0.0101 = 1/99.46 mm 
+pandoralg.AbsorberRadLengthHCal= 0.0569 
+pandoralg.AbsorberIntLengthHCal= 0.006  
+pandoralg.AbsorberRadLengthOther= 0.0569
+pandoralg.AbsorberIntLengthOther= 0.006 
+
+##############################################################################
+
+# write PODIO file
+from Configurables import PodioOutput
+write = PodioOutput("write")
+write.filename = "test.root"
+write.outputCommands = ["keep *"]
+
+# ApplicationMgr
+from Configurables import ApplicationMgr
+ApplicationMgr(
+        TopAlg = [genalg, detsimalg, example_CaloDigiAlg, pandoralg],
+        #TopAlg = [genalg, detsimalg],
+        #TopAlg = [genalg, detsimalg,  write],
+        #TopAlg = [read, pandoralg],
+        EvtSel = 'NONE',
+        EvtMax = 10,
+        #ExtSvc = [rndmengine, dsvc, geosvc, gearSvc],
+        ExtSvc = [rndmengine, dsvc, geosvc, gearSvc,detsimsvc],
+        OutputLevel=INFO
+)
diff --git a/Examples/options/tut_detsim_pandora.py b/Examples/options/tut_detsim_pandora.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4ceaf07377898130aea5d39e6e304242cda1262
--- /dev/null
+++ b/Examples/options/tut_detsim_pandora.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+
+import os
+print(os.environ["DD4HEP_LIBRARY_PATH"])
+import sys
+# sys.exit(0)
+
+from Gaudi.Configuration import *
+
+##############################################################################
+# Random Number Svc
+##############################################################################
+from Configurables import RndmGenSvc, HepRndm__Engine_CLHEP__RanluxEngine_
+
+# rndmengine = HepRndm__Engine_CLHEP__RanluxEngine_() # The default engine in Gaudi
+rndmengine = HepRndm__Engine_CLHEP__HepJamesRandom_() # The default engine in Geant4
+rndmengine.SetSingleton = True
+rndmengine.Seeds = [42]
+
+# rndmgensvc = RndmGenSvc("RndmGenSvc")
+# rndmgensvc.Engine = rndmengine.name()
+
+
+##############################################################################
+# Event Data Svc
+##############################################################################
+#from Configurables import CEPCDataSvc
+#dsvc = CEPCDataSvc("EventDataSvc")
+from Configurables import K4DataSvc
+dsvc = K4DataSvc("EventDataSvc")
+
+
+##############################################################################
+# Geometry Svc
+##############################################################################
+
+# geometry_option = "CepC_v4-onlyTracker.xml"
+geometry_option = "CepC_v4-onlyVXD.xml"
+
+if not os.getenv("DETCEPCV4ROOT"):
+    print("Can't find the geometry. Please setup envvar DETCEPCV4ROOT." )
+    sys.exit(-1)
+
+geometry_path = os.path.join(os.getenv("DETCEPCV4ROOT"), "compact", geometry_option)
+if not os.path.exists(geometry_path):
+    print("Can't find the compact geometry file: %s"%geometry_path)
+    sys.exit(-1)
+
+from Configurables import GeoSvc
+geosvc = GeoSvc("GeoSvc")
+geosvc.compact = geometry_path
+
+##############################################################################
+# Physics Generator
+##############################################################################
+from Configurables import GenAlgo
+from Configurables import GtGunTool
+from Configurables import StdHepRdr
+from Configurables import SLCIORdr
+from Configurables import HepMCRdr
+from Configurables import GenPrinter
+
+gun = GtGunTool("GtGunTool")
+gun.Particles = ["gamma","gamma"]
+gun.EnergyMins= [10, 10] # GeV
+gun.EnergyMaxs= [10, 10] # GeV
+gun.ThetaMins = [90, 90] # degree
+gun.ThetaMaxs = [90, 90] # degree
+gun.PhiMins   = [0,  1 ] # degree
+gun.PhiMaxs   = [0,  1 ] # degree
+
+
+stdheprdr = StdHepRdr("StdHepRdr")
+#stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
+#stdheprdr.Input = "/cefs/data/stdhep/CEPC250/2fermions/E250.Pbhabha.e0.p0.whizard195/bhabha.e0.p0.00001.stdhep"
+stdheprdr.Input = "/cefs/data/stdhep/CEPC250/higgs/E250.Pbbh.whizard195/E250.Pbbh_X.e0.p0.whizard195/Pbbh_X.e0.p0.00001.stdhep"
+
+# lciordr = SLCIORdr("SLCIORdr")
+# lciordr.Input = "/cefs/data/stdhep/lcio250/signal/Higgs/E250.Pbbh.whizard195/E250.Pbbh_X.e0.p0.whizard195/Pbbh_X.e0.p0.00001.slcio"
+
+# hepmcrdr = HepMCRdr("HepMCRdr")
+# hepmcrdr.Input = "example_UsingIterators.txt"
+
+genprinter = GenPrinter("GenPrinter")
+
+genalg = GenAlgo("GenAlgo")
+genalg.GenTools = ["GtGunTool"]
+#genalg.GenTools = ["StdHepRdr"]
+# genalg.GenTools = ["StdHepRdr", "GenPrinter"]
+# genalg.GenTools = ["SLCIORdr", "GenPrinter"]
+# genalg.GenTools = ["HepMCRdr", "GenPrinter"]
+
+##############################################################################
+# Detector Simulation
+##############################################################################
+from Configurables import DetSimSvc
+
+detsimsvc = DetSimSvc("DetSimSvc")
+
+# from Configurables import ExampleAnaElemTool
+# example_anatool = ExampleAnaElemTool("ExampleAnaElemTool")
+
+from Configurables import DetSimAlg
+
+detsimalg = DetSimAlg("DetSimAlg")
+
+# detsimalg.VisMacs = ["vis.mac"]
+
+detsimalg.RunCmds = [
+#    "/tracking/verbose 1",
+]
+detsimalg.AnaElems = [
+    # example_anatool.name()
+    # "ExampleAnaElemTool"
+    "Edm4hepWriterAnaElemTool"
+]
+detsimalg.RootDetElem = "WorldDetElemTool"
+
+from Configurables import AnExampleDetElemTool
+example_dettool = AnExampleDetElemTool("AnExampleDetElemTool")
+
+##############################################################################
+from Configurables import CaloDigiAlg
+example_CaloDigiAlg = CaloDigiAlg("CaloDigiAlg")
+example_CaloDigiAlg.Scale = 1
+example_CaloDigiAlg.SimCaloHitCollection = "SimCalorimeterCol"
+example_CaloDigiAlg.CaloHitCollection    = "ECALBarrel"
+example_CaloDigiAlg.CaloAssociationCollection    = "RecoCaloAssociation_ECALBarrel"
+##############################################################################
+from Configurables import GearSvc
+gearSvc  = GearSvc("GearSvc")
+gearSvc.GearXMLFile = "../Detector/DetCEPCv4/compact/FullDetGear.xml"
+##############################################################################
+from Configurables import PandoraPFAlg
+
+pandoralg = PandoraPFAlg("PandoraPFAlg")
+## KEEP same with lcioinput name for the ReadXXX ###########
+pandoralg.ReadMCParticle                       = "MCParticle"                   
+pandoralg.ReadECALBarrel                       = "ECALBarrel"                   
+pandoralg.ReadECALEndcap                       = "ECALEndcap"                   
+pandoralg.ReadECALOther                        = "ECALOther"                    
+pandoralg.ReadHCALBarrel                       = "HCALBarrel"                   
+pandoralg.ReadHCALEndcap                       = "HCALEndcap"                   
+pandoralg.ReadHCALOther                        = "HCALOther"                    
+pandoralg.ReadMUON                             = "MUON"                         
+pandoralg.ReadLCAL                             = "LCAL"                         
+pandoralg.ReadLHCAL                            = "LHCAL"                        
+pandoralg.ReadBCAL                             = "BCAL"                         
+pandoralg.ReadKinkVertices                     = "KinkVertices"                 
+pandoralg.ReadProngVertices                    = "ProngVertices"                
+pandoralg.ReadSplitVertices                    = "SplitVertices"                
+pandoralg.ReadV0Vertices                       = "V0Vertices"                   
+pandoralg.ReadTracks                           = "MarlinTrkTracks"                       
+pandoralg.MCRecoCaloAssociation                = "RecoCaloAssociation_ECALBarrel"                       
+pandoralg.WriteClusterCollection               = "PandoraClusters"              
+pandoralg.WriteReconstructedParticleCollection = "PandoraPFOs" 
+pandoralg.WriteVertexCollection                = "PandoraPFANewStartVertices"               
+pandoralg.AnaOutput = "Ana.root"
+
+pandoralg.PandoraSettingsDefault_xml = "../Reconstruction/PFA/Pandora/PandoraSettingsDefault.xml"
+#### Do not chage the collection name, only add or remove ###############
+pandoralg.TrackCollections      =  ["MarlinTrkTracks"]
+pandoralg.ECalCaloHitCollections=  ["ECALBarrel", "ECALEndcap", "ECALOther"]
+pandoralg.HCalCaloHitCollections=  ["HCALBarrel", "HCALEndcap", "HCALOther"]
+pandoralg.LCalCaloHitCollections=  ["LCAL"]
+pandoralg.LHCalCaloHitCollections= ["LHCAL"]
+pandoralg.MuonCaloHitCollections=  ["MUON"]
+pandoralg.MCParticleCollections =  ["MCParticle"]
+pandoralg.RelCaloHitCollections =  ["RecoCaloAssociation_ECALBarrel", "RecoCaloAssociation_ECALEndcap", "RecoCaloAssociation_ECALOther", "RecoCaloAssociation_HCALBarrel", "RecoCaloAssociation_HCALEndcap", "RecoCaloAssociation_HCALOther", "RecoCaloAssociation_LCAL", "RecoCaloAssociation_LHCAL", "RecoCaloAssociation_MUON"]
+pandoralg.RelTrackCollections   =  ["MarlinTrkTracksMCTruthLink"]
+pandoralg.KinkVertexCollections =  ["KinkVertices"]
+pandoralg.ProngVertexCollections=  ["ProngVertices"]
+pandoralg.SplitVertexCollections=  ["SplitVertices"]
+pandoralg.V0VertexCollections   =  ["V0Vertices"]
+pandoralg.ECalToMipCalibration  = 160.0 
+pandoralg.HCalToMipCalibration  = 34.8 
+pandoralg.ECalMipThreshold      = 0.5 
+pandoralg.HCalMipThreshold      = 0.3 
+pandoralg.ECalToEMGeVCalibration= 0.9 #for G2CD Digi, 1.007 for NewLDCaloDigi 
+pandoralg.HCalToEMGeVCalibration= 1.007 
+pandoralg.ECalToHadGeVCalibrationBarrel= 1.12 #very small effect 
+pandoralg.ECalToHadGeVCalibrationEndCap= 1.12 
+pandoralg.HCalToHadGeVCalibration= 1.07
+pandoralg.MuonToMipCalibration= 10.0 
+pandoralg.DigitalMuonHits= 0 
+pandoralg.MaxHCalHitHadronicEnergy   = 1.0 
+pandoralg.UseOldTrackStateCalculation= 0 
+pandoralg.AbsorberRadLengthECal= 0.2854 #= 1/3.504 mm 
+pandoralg.AbsorberIntLengthECal= 0.0101 #= 1/99.46 mm 
+pandoralg.AbsorberRadLengthHCal= 0.0569 
+pandoralg.AbsorberIntLengthHCal= 0.006  
+pandoralg.AbsorberRadLengthOther= 0.0569
+pandoralg.AbsorberIntLengthOther= 0.006 
+
+##############################################################################
+
+# write PODIO file
+from Configurables import PodioOutput
+write = PodioOutput("write")
+write.filename = "test.root"
+write.outputCommands = ["keep *"]
+
+# ApplicationMgr
+from Configurables import ApplicationMgr
+ApplicationMgr(
+        TopAlg = [genalg, detsimalg, example_CaloDigiAlg, pandoralg],
+        EvtSel = 'NONE',
+        EvtMax = 10,
+        ExtSvc = [rndmengine, dsvc, geosvc, gearSvc,detsimsvc],
+        OutputLevel=INFO
+)
diff --git a/Examples/src/DumpIDAlg/DumpIDAlg.cpp b/Examples/src/DumpIDAlg/DumpIDAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ae59e335bb44fcb32a428a5fb03f77c37df9f29
--- /dev/null
+++ b/Examples/src/DumpIDAlg/DumpIDAlg.cpp
@@ -0,0 +1,110 @@
+#include "DumpIDAlg.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/SimCalorimeterHitCollection.h"
+#include "edm4hep/CaloHitContributionCollection.h"
+
+#include "DD4hep/Detector.h"
+#include "DD4hep/IDDescriptor.h"
+#include "DD4hep/Plugins.h"
+
+DECLARE_COMPONENT(DumpIDAlg)
+
+DumpIDAlg::DumpIDAlg(const std::string& name, ISvcLocator* svcLoc)
+: GaudiAlgorithm(name, svcLoc), m_dd4hep_geo(nullptr), m_decoder(nullptr)
+{
+
+}
+
+StatusCode DumpIDAlg::initialize()
+{
+    m_geosvc = service<IGeoSvc>("GeoSvc");
+    if (!m_geosvc) {
+        error() << "Failed to find GeoSvc." << endmsg;
+        return StatusCode::FAILURE;
+    }
+    m_dd4hep_geo = m_geosvc->lcdd();
+    if (!m_dd4hep_geo) {
+        error() << "failed to retrieve dd4hep_geo: " << m_dd4hep_geo << endmsg;
+        return StatusCode::FAILURE;
+    }
+
+    // get the DD4hep readout
+    const std::string name_readout = "EcalBarrelCollection";
+    m_decoder = m_geosvc->getDecoder(name_readout);
+    if (!m_decoder) {
+        error() << "Failed to get the decoder. " << endmsg;
+        return StatusCode::FAILURE;
+    }
+
+    //  Book N-tuple 1
+    NTuplePtr nt1( ntupleSvc(), "MyTuples/1" );
+    if ( nt1 ) {
+        m_tuple_id = nt1;
+    } else {
+        m_tuple_id = ntupleSvc()->book( "MyTuples/1", CLID_RowWiseTuple, "Row-wise N-Tuple example" );
+        if ( m_tuple_id ) {
+            m_tuple_id->addItem( "system", m_id_system ).ignore();
+            m_tuple_id->addItem( "module", m_id_module ).ignore();
+            m_tuple_id->addItem( "stave", m_id_stave ).ignore();
+            m_tuple_id->addItem( "tower", m_id_tower ).ignore();
+            m_tuple_id->addItem( "layer", m_id_layer ).ignore();
+            m_tuple_id->addItem( "wafer", m_id_wafer ).ignore();
+            m_tuple_id->addItem( "cellX", m_id_cellX ).ignore();
+            m_tuple_id->addItem( "cellY", m_id_cellY ).ignore();
+
+        } else { // did not manage to book the N tuple....
+            error() << "    Cannot book N-tuple:" << long( m_tuple_id ) << endmsg;
+            return StatusCode::FAILURE;
+        }
+    }
+
+
+    return GaudiAlgorithm::initialize();
+}
+
+StatusCode DumpIDAlg::execute()
+{
+
+
+    auto ecalBarrelCol = m_EcalBarrelCol.get();
+    for (auto calohit: *ecalBarrelCol) {
+        auto cellid = calohit.getCellID();
+
+        m_id_system = m_decoder->get(cellid, "system");
+        m_id_module = m_decoder->get(cellid, "module");
+        m_id_stave = m_decoder->get(cellid, "stave");
+        m_id_tower = m_decoder->get(cellid, "tower");
+        m_id_layer = m_decoder->get(cellid, "layer");
+        m_id_wafer = m_decoder->get(cellid, "wafer");
+        m_id_cellX = m_decoder->get(cellid, "cellX");
+        m_id_cellY = m_decoder->get(cellid, "cellY");
+
+        info() << "Calo hit cellid: " << cellid
+               << " system: " << m_id_system
+               << " module: " << m_id_module
+               << " stave: " << m_id_stave
+               << " tower: " << m_id_tower
+               << " layer: " << m_id_layer
+               << " wafer: " << m_id_wafer
+               << " cellX: " << m_id_cellX
+               << " cellY: " << m_id_cellY
+               << endmsg;
+
+        // calculate I/J/K 
+
+        m_tuple_id->write();
+
+    }
+    return StatusCode::SUCCESS;
+}
+
+StatusCode DumpIDAlg::finalize()
+{
+
+    return GaudiAlgorithm::finalize();
+}
+
+
+
+
diff --git a/Examples/src/DumpIDAlg/DumpIDAlg.h b/Examples/src/DumpIDAlg/DumpIDAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..20bb9469ffaebe9f46fb50bf0a919cbf66218bb0
--- /dev/null
+++ b/Examples/src/DumpIDAlg/DumpIDAlg.h
@@ -0,0 +1,53 @@
+#ifndef DumpIDAlg_h
+#define DumpIDAlg_h
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "GaudiKernel/NTuple.h"
+
+#include "DetInterface/IGeoSvc.h"
+
+#include "DD4hep/Detector.h"
+
+namespace edm4hep {
+    class EventHeaderCollection;
+    class MCParticleCollection;
+    class SimCalorimeterHitCollection;
+    class CaloHitContributionCollection;
+}
+
+class DumpIDAlg: public GaudiAlgorithm
+{
+public:
+
+    DumpIDAlg(const std::string& name, ISvcLocator* svcLoc);
+
+    virtual StatusCode initialize();
+    virtual StatusCode execute();
+    virtual StatusCode finalize();
+
+private:
+    SmartIF<IGeoSvc> m_geosvc;
+    dd4hep::Detector* m_dd4hep_geo;
+    dd4hep::DDSegmentation::BitFieldCoder* m_decoder;
+
+    DataHandle<edm4hep::SimCalorimeterHitCollection> m_EcalBarrelCol{"EcalBarrelCollection", 
+            Gaudi::DataHandle::Reader, this};
+
+private:
+    // strore all the id for later analysis
+    NTuple::Tuple* m_tuple_id = nullptr;
+
+    NTuple::Item<int> m_id_system;
+    NTuple::Item<int> m_id_module;
+    NTuple::Item<int> m_id_stave;
+    NTuple::Item<int> m_id_tower;
+    NTuple::Item<int> m_id_layer;
+    NTuple::Item<int> m_id_wafer;
+    NTuple::Item<int> m_id_cellX;
+    NTuple::Item<int> m_id_cellY;
+    
+};
+
+
+#endif
diff --git a/Examples/src/Edm4hepTest/Edm4hepReadAlg.cpp b/Examples/src/Edm4hepTest/Edm4hepReadAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f41d333b18a5da763b0c7d21ce7f879f29cda822
--- /dev/null
+++ b/Examples/src/Edm4hepTest/Edm4hepReadAlg.cpp
@@ -0,0 +1,66 @@
+#include "Edm4hepReadAlg.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/SimCalorimeterHitCollection.h"
+#include "edm4hep/CaloHitContributionCollection.h"
+
+DECLARE_COMPONENT(Edm4hepReadAlg)
+
+Edm4hepReadAlg::Edm4hepReadAlg(const std::string& name, ISvcLocator* svcLoc)
+    : GaudiAlgorithm(name, svcLoc)
+{
+    declareProperty("HeaderCol", m_headerCol);
+    declareProperty("InputCol", m_mcParCol, "MCParticle collection (input)");
+}
+
+StatusCode Edm4hepReadAlg::initialize()
+{
+    debug() << "begin initialize Edm4hepReadAlg" << endmsg;
+    return GaudiAlgorithm::initialize();
+}
+
+StatusCode Edm4hepReadAlg::execute()
+{
+    debug() << "begin execute Edm4hepReadAlg" << endmsg;
+
+    auto mcCol = m_mcParCol.get();
+    for ( auto p : *mcCol ) {
+        info() << p.getObjectID().index << " : [";
+        for ( auto it = p.daughters_begin(), end = p.daughters_end(); it != end; ++it ) {
+            info() << " " << it->getObjectID().index;
+        }
+        info() << " ]; ";
+    }
+    info() << "}" << endmsg;
+
+    auto caloCol = m_calorimeterCol.get();
+    for (auto calohit : *caloCol) {
+        unsigned int contrib_size = calohit.contributions_size();
+        info() << " contributions_size: " 
+               << contrib_size
+               << endmsg;
+        for (unsigned int i = 0; i < contrib_size; ++i) {
+            auto contrib = calohit.getContributions(i);
+            auto primary_particle = contrib.getParticle();
+
+            info() << " - #" << i << ": "
+                   << " track with "
+                   << " PDG: " << contrib.getPDG() // current track
+                   << ". "
+                   << " primary track with "
+                   << " PDG: " << primary_particle.getPDG()
+                   << endmsg;
+
+
+        }
+
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode Edm4hepReadAlg::finalize()
+{
+    debug() << "begin finalize Edm4hepReadAlg" << endmsg;
+    return GaudiAlgorithm::finalize();
+}
diff --git a/Examples/src/Edm4hepTest/Edm4hepReadAlg.h b/Examples/src/Edm4hepTest/Edm4hepReadAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a194a64f54c221ea47905dbc855f2048e24892a
--- /dev/null
+++ b/Examples/src/Edm4hepTest/Edm4hepReadAlg.h
@@ -0,0 +1,36 @@
+#ifndef TEST_EDM4HEP_WRITE_ALG_H
+#define TEST_EDM4HEP_WRITE_ALG_H
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+
+namespace edm4hep {
+    class EventHeaderCollection;
+    class MCParticleCollection;
+    class SimCalorimeterHitCollection;
+    class CaloHitContributionCollection;
+}
+
+class Edm4hepReadAlg : public GaudiAlgorithm
+{
+
+    public :
+
+        Edm4hepReadAlg(const std::string& name, ISvcLocator* svcLoc);
+
+        virtual StatusCode initialize();
+        virtual StatusCode execute();
+        virtual StatusCode finalize();
+
+    private :
+
+        DataHandle<edm4hep::EventHeaderCollection> m_headerCol{"EventHeader", Gaudi::DataHandle::Reader, this};
+        DataHandle<edm4hep::MCParticleCollection> m_mcParCol{"MCParticle", Gaudi::DataHandle::Reader, this};
+        DataHandle<edm4hep::SimCalorimeterHitCollection> m_calorimeterCol{"SimCalorimeterCol", 
+                Gaudi::DataHandle::Reader, this};
+        DataHandle<edm4hep::CaloHitContributionCollection> m_caloContribCol{"SimCaloContributionCol", 
+                Gaudi::DataHandle::Reader, this};
+
+};
+
+#endif  // TEST_EDM4HEP_WRITE_ALG_H
diff --git a/Examples/src/Edm4hepTest/Edm4hepWriteAlg.cpp b/Examples/src/Edm4hepTest/Edm4hepWriteAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b33d5e8045507a7514a7358aa8375f7e9326b544
--- /dev/null
+++ b/Examples/src/Edm4hepTest/Edm4hepWriteAlg.cpp
@@ -0,0 +1,54 @@
+#include "Edm4hepWriteAlg.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/MCParticleCollection.h"
+
+DECLARE_COMPONENT(Edm4hepWriteAlg)
+
+Edm4hepWriteAlg::Edm4hepWriteAlg(const std::string& name, ISvcLocator* svcLoc)
+    : GaudiAlgorithm(name, svcLoc)
+{
+    declareProperty("HeaderCol", m_headerCol);
+    declareProperty("OutputCol", m_mcParCol, "MCParticle collection (output)");
+}
+
+StatusCode Edm4hepWriteAlg::initialize()
+{
+    debug() << "begin initialize Edm4hepWriteAlg" << endmsg;
+    return GaudiAlgorithm::initialize();
+}
+
+StatusCode Edm4hepWriteAlg::execute()
+{
+    debug() << "begin execute Edm4hepWriteAlg" << endmsg;
+
+    static int evtNo = 0;
+
+    auto headers = m_headerCol.createAndPut();
+    auto header = headers->create();
+    header.setRunNumber(-999);
+    header.setEventNumber(evtNo++);
+    // header.setDetectorName("TEST");
+
+    //auto mcCol = new edm4hep::MCParticleCollection;
+    //m_mcParCol.put(mcCol);
+    auto mcCol = m_mcParCol.createAndPut();
+
+    auto p1 = mcCol->create();
+    auto p2 = mcCol->create();
+
+    for ( int i = 0; i < 4; ++i ) {
+        auto d = mcCol->create();
+        d.addToParents(p1);
+        d.addToParents(p2);
+        p1.addToDaughters(d);
+        p2.addToDaughters(d);
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode Edm4hepWriteAlg::finalize()
+{
+    debug() << "begin finalize Edm4hepWriteAlg" << endmsg;
+    return GaudiAlgorithm::finalize();
+}
diff --git a/Examples/src/Edm4hepTest/Edm4hepWriteAlg.h b/Examples/src/Edm4hepTest/Edm4hepWriteAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..8058747476ab106edd3cdca52be0d04ba3110f33
--- /dev/null
+++ b/Examples/src/Edm4hepTest/Edm4hepWriteAlg.h
@@ -0,0 +1,30 @@
+#ifndef TEST_EDM4HEP_WRITE_ALG_H
+#define TEST_EDM4HEP_WRITE_ALG_H
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+
+namespace edm4hep {
+    class EventHeaderCollection;
+    class MCParticleCollection;
+}
+
+class Edm4hepWriteAlg : public GaudiAlgorithm
+{
+
+    public :
+
+        Edm4hepWriteAlg(const std::string& name, ISvcLocator* svcLoc);
+
+        virtual StatusCode initialize();
+        virtual StatusCode execute();
+        virtual StatusCode finalize();
+
+    private :
+
+        DataHandle<edm4hep::EventHeaderCollection> m_headerCol{"EventHeader", Gaudi::DataHandle::Writer, this};
+        DataHandle<edm4hep::MCParticleCollection> m_mcParCol{"MCParticle", Gaudi::DataHandle::Writer, this};
+
+};
+
+#endif  // TEST_EDM4HEP_WRITE_ALG_H
diff --git a/Examples/src/PlcioTest/PlcioReadAlg.h b/Examples/src/PlcioTest/PlcioReadAlg.h
index 4b66b143f4247487d14133aa1153ec106ff346ac..f5aba7dc3f878d355eaa213b01e22620a057b678 100644
--- a/Examples/src/PlcioTest/PlcioReadAlg.h
+++ b/Examples/src/PlcioTest/PlcioReadAlg.h
@@ -11,7 +11,6 @@ namespace plcio {
 
 class PlcioReadAlg : public GaudiAlgorithm
 {
-        friend class AlgFactory<PlcioReadAlg>;
 
     public :
 
diff --git a/Examples/src/PlcioTest/PlcioWriteAlg.h b/Examples/src/PlcioTest/PlcioWriteAlg.h
index c34aa29edc45bf4760775cec7ecab37c9abf69f1..377173d09bbdd3616edfb89705ca490969a1d57f 100644
--- a/Examples/src/PlcioTest/PlcioWriteAlg.h
+++ b/Examples/src/PlcioTest/PlcioWriteAlg.h
@@ -11,7 +11,6 @@ namespace plcio {
 
 class PlcioWriteAlg : public GaudiAlgorithm
 {
-        friend class AlgFactory<PlcioWriteAlg>;
 
     public :
 
diff --git a/FWCore/CMakeLists.txt b/FWCore/CMakeLists.txt
deleted file mode 100644
index 3cc5478bb80f00bc90fa56717ebb8331131dab3e..0000000000000000000000000000000000000000
--- a/FWCore/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-################################################################################
-# Package: FWCore
-################################################################################
-gaudi_subdir(FWCore v0r1)
-
-find_package(podio REQUIRED)
-find_package(plcio REQUIRED)
-find_package(LCIO REQUIRED)
-find_package(ROOT COMPONENTS RIO Tree)
-
-# this declaration will not be needed in the future
-gaudi_depends_on_subdirs(GaudiAlg GaudiKernel)
-# gaudi_install_scripts()
-gaudi_install_python_modules()
-
-gaudi_add_library(FWCore
-		  src/*.cpp
-                  INCLUDE_DIRS ${podio_INCLUDE_DIRS} ${LCIO_INCLUDE_DIRS} ${plcio_INCLUDE_DIRS} ROOT
-                  LINK_LIBRARIES GaudiAlgLib GaudiKernel ${podio_LIBRARIES} ${LCIO_LIBRARIES} ${plcio_LIBRARIES} ROOT
-                  PUBLIC_HEADERS FWCore)
-
-gaudi_add_module(FWCorePlugins
-                 src/components/*.cpp
-                 LINK_LIBRARIES GaudiAlgLib GaudiKernel FWCore ROOT)
-
diff --git a/FWCore/FWCore/DataHandle.h b/FWCore/FWCore/DataHandle.h
deleted file mode 100644
index 642d082380a708cbe88a2becbf74fc98418a47a9..0000000000000000000000000000000000000000
--- a/FWCore/FWCore/DataHandle.h
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef FWCORE_DATAHANDLE_H
-#define FWCORE_DATAHANDLE_H
-
-#include "FWCore/DataWrapper.h"
-#include "FWCore/PodioDataSvc.h"
-
-#include "GaudiKernel/AlgTool.h"
-#include "GaudiKernel/Algorithm.h"
-#include <GaudiKernel/DataObjectHandle.h>
-#include <GaudiKernel/GaudiException.h>
-#include <GaudiKernel/Property.h>
-#include <GaudiKernel/ServiceLocatorHelper.h>
-
-#include "TTree.h"
-
-#include <type_traits>
-
-template <typename T>
-class DataHandle : public DataObjectHandle<DataWrapper<T>> {
-
-public:
-  friend class Algorithm;
-  friend class AlgTool;
-
-public:
-  DataHandle();
-
-  /// Initialises mother class
-  DataHandle(DataObjID& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg);
-
-  DataHandle(const std::string& k, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg);
-  /**
-   * Retrieve object from transient data store
-   */
-  const T* get();
-
-  /**
-   * Register object in transient store
-   */
-  void put(T* object);
-
-  /**
-  * Create and register object in transient store
-  */
-  T* createAndPut();
-
-private:
-  ServiceHandle<IDataProviderSvc> m_eds;
-  bool m_isGoodType{false};
-  bool m_isCollection{false};
-  T* m_dataPtr;
-};
-
-//---------------------------------------------------------------------------
-template <typename T>
-DataHandle<T>::DataHandle(DataObjID& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg)
-    : DataObjectHandle<DataWrapper<T>>(descriptor, a, fatherAlg), m_eds("EventDataSvc", "DataHandle") {
-      
-}
-//---------------------------------------------------------------------------
-template <typename T>
-DataHandle<T>::DataHandle(const std::string& descriptor, Gaudi::DataHandle::Mode a, IDataHandleHolder* fatherAlg)
-    : DataObjectHandle<DataWrapper<T>>(descriptor, a, fatherAlg), m_eds("EventDataSvc", "DataHandle") {
-
-  if (a > 15) { // Gaudi::DataHandle::Mode is 'writer'
-  m_eds.retrieve();
-  PodioDataSvc* pds;
-  pds = dynamic_cast<PodioDataSvc*>( m_eds.get());
-  m_dataPtr = 0;
-  if (nullptr != pds) {
-    if (std::is_convertible<T*,podio::CollectionBase*>::value) {
-      // still handled in PodioOutput
-    } else {
-      TTree* tree = pds->eventDataTree();
-      tree->Branch(descriptor.c_str(),  &m_dataPtr);
-      }
-    }
-  }
-}
-
-/**
- * Try to retrieve from the transient store. If the retrieval succeded and
- * this is the first time we retrieve, perform a dynamic cast to the desired
- * object. Then finally set the handle as Read.
- * If this is not the first time we cast and the cast worked, just use the
- * static cast: we do not need the checks of the dynamic cast for every access!
- */
-template <typename T>
-const T* DataHandle<T>::get() {
-  DataObject* dataObjectp = nullptr;
-  auto sc = m_eds->retrieveObject(DataObjectHandle<DataWrapper<T>>::fullKey().key(), dataObjectp);
-
-  if (LIKELY(sc.isSuccess())) {
-    if (UNLIKELY(!m_isGoodType && !m_isCollection)) {
-      // only do this once (if both are false after this, we throw exception)
-      m_isGoodType = nullptr != dynamic_cast<DataWrapper<T>*>(dataObjectp);
-      if (!m_isGoodType) {
-        auto tmp = dynamic_cast<DataWrapper<podio::CollectionBase>*>(dataObjectp);
-        if (tmp != nullptr) {
-          m_isCollection = nullptr != dynamic_cast<T*>(tmp->collectionBase());
-        }
-      }
-    }
-    if (LIKELY(m_isGoodType)) {
-      DataObjectHandle<DataWrapper<T>>::setRead();
-      return static_cast<DataWrapper<T>*>(dataObjectp)->getData();
-    } else if (m_isCollection) {
-      // The reader does not know the specific type of the collection. So we need a reinterpret_cast if the handle was
-      // created by the reader.
-      DataWrapper<podio::CollectionBase>* tmp = static_cast<DataWrapper<podio::CollectionBase>*>(dataObjectp);
-      DataObjectHandle<DataWrapper<T>>::setRead();
-      return reinterpret_cast<const T*>(tmp->collectionBase());
-    } else {
-      std::string errorMsg("The type provided for " + DataObjectHandle<DataWrapper<T>>::toString() +
-                           " is different from the one of the object in the store.");
-      throw GaudiException(errorMsg, "wrong product type", StatusCode::FAILURE);
-    }
-  }
-  std::string msg("Could not retrieve product " + DataObjectHandle<DataWrapper<T>>::toString());
-  throw GaudiException(msg, "wrong product name", StatusCode::FAILURE);
-}
-
-//---------------------------------------------------------------------------
-template <typename T>
-void DataHandle<T>::put(T* objectp) {
-  DataWrapper<T>* dw = new DataWrapper<T>();
-  m_dataPtr = objectp;
-  dw->setData(objectp);
-  DataObjectHandle<DataWrapper<T>>::put(dw);
-
-}
-//---------------------------------------------------------------------------
-/**
- * Create the collection, put it in the DataObjectHandle and return the
- * pointer to the data. Call this function if you create a collection and
- * want to save it.
- */
-template <typename T>
-T* DataHandle<T>::createAndPut() {
-  T* objectp = new T();
-  this->put(objectp);
-  return objectp;
-}
-
-// temporary to allow property declaration
-namespace Gaudi {
-template <class T>
-class Property<::DataHandle<T>&> : public ::DataObjectHandleProperty {
-public:
-  Property(const std::string& name, ::DataHandle<T>& value) : ::DataObjectHandleProperty(name, value) {}
-
-  /// virtual Destructor
-  virtual ~Property() {}
-};
-}
-
-#endif
diff --git a/FWCore/FWCore/DataWrapper.h b/FWCore/FWCore/DataWrapper.h
deleted file mode 100644
index a6ec7a48d1628767e94b527a875495ad720426c3..0000000000000000000000000000000000000000
--- a/FWCore/FWCore/DataWrapper.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef FWCORE_DATAWRAPPER_H
-#define FWCORE_DATAWRAPPER_H
-
-#include <type_traits>
-
-// Include files
-#include "GaudiKernel/DataObject.h"
-#include "podio/CollectionBase.h"
-
-class GAUDI_API DataWrapperBase : public DataObject {
-public:
-  // ugly hack to circumvent the usage of boost::any yet
-  // DataSvc would need a templated register method
-  virtual podio::CollectionBase* collectionBase() = 0;
-  virtual ~DataWrapperBase(){};
-};
-
-template <class T>
-class GAUDI_API DataWrapper : public DataWrapperBase {
-public:
-  DataWrapper() : DataWrapperBase(), m_data(nullptr){};
-  virtual ~DataWrapper();
-
-  const T* getData() { return m_data; }
-  void setData(T* data) { m_data = data; }
-  /// try to cast to collectionBase; may return nullptr;
-  virtual podio::CollectionBase* collectionBase();
-
-private:
-  T* m_data;
-};
-
-template <class T>
-DataWrapper<T>::~DataWrapper<T>() {
-  if (m_data != nullptr) delete m_data;
-}
-
-template <class T>
-podio::CollectionBase* DataWrapper<T>::collectionBase() {
-  if (std::is_base_of<podio::CollectionBase, T>::value) {
-    return reinterpret_cast<podio::CollectionBase*>(m_data);
-  }
-  return nullptr;
-}
-
-#endif
diff --git a/FWCore/FWCore/KeepDropSwitch.h b/FWCore/FWCore/KeepDropSwitch.h
deleted file mode 100644
index d4bd4c0bc2d7525056b18d6f34914a7faa7a488e..0000000000000000000000000000000000000000
--- a/FWCore/FWCore/KeepDropSwitch.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef EXAMPLES_KEEPDROPSWITCH_H
-#define EXAMPLES_KEEPDROPSWITCH_H
-
-#include <map>
-#include <string>
-#include <vector>
-
-std::vector<std::string> split(const std::string& s, char delim);
-
-int wildcmp(const char* wild, const char* string);
-
-class KeepDropSwitch {
-public:
-  enum Cmd { KEEP, DROP, UNKNOWN };
-  typedef std::vector<std::string> CommandLines;
-  KeepDropSwitch() {}
-  explicit KeepDropSwitch(const CommandLines& cmds) { m_commandlines = cmds; }
-  bool isOn(const std::string& astring) const;
-
-private:
-  bool getFlag(const std::string& astring) const;
-  Cmd extractCommand(const std::string cmdLine) const;
-  CommandLines m_commandlines;
-  mutable std::map<std::string, bool> m_cache;
-};
-
-#endif
diff --git a/FWCore/FWCore/LCIODataSvc.h b/FWCore/FWCore/LCIODataSvc.h
deleted file mode 100644
index 8bfa3261f7d4e6da0da9e4dc860aaa9a282f8f58..0000000000000000000000000000000000000000
--- a/FWCore/FWCore/LCIODataSvc.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef FWCORE_LCIODATASVC_H
-#define FWCORE_LCIODATASVC_H
-
-#include "GaudiKernel/DataSvc.h"
-#include "GaudiKernel/IConversionSvc.h"
-// LCIO
-#include "podio/CollectionBase.h"
-#include "podio/CollectionIDTable.h"
-#include "podio/EventStore.h"
-#include "podio/ROOTReader.h"
-
-#include "IO/LCReader.h"
-#include "EVENT/LCCollection.h"
-#include "EVENT/MCParticle.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/MCParticle.h"
-#include "plcio/EventHeaderCollection.h"
-
-#include "src/components/LCIO2Plcio.h"
-#include <utility>
-// Forward declarations
-
-/** @class LCIOEvtSvc EvtDataSvc.h
- *
- *   An EvtDataSvc for LCIO classes
- *
- *  @author B. Hegner
- */
-class LCIODataSvc : public DataSvc {
-public:
-
-  friend class SvcFactory<LCIODataSvc>;
-
-  typedef std::vector<std::pair<std::string, podio::CollectionBase*>> CollRegistry;
-
-  virtual StatusCode initialize();
-  virtual StatusCode reinitialize();
-  virtual StatusCode finalize();
-  virtual StatusCode clearStore();
-
-  /// Standard Constructor
-  LCIODataSvc(const std::string& name, ISvcLocator* svc);
-
-  /// Standard Destructor
-  virtual ~LCIODataSvc();
-
-  // Use DataSvc functionality except where we override
-  using DataSvc::registerObject;
-  /// Overriding standard behaviour of evt service
-  /// Register object with the data store.
-  virtual StatusCode registerObject(const std::string& fullPath, DataObject* pObject) final;
-
-  StatusCode readCollection(const std::string& collectionName, int collectionID);
-
-  virtual const CollRegistry& getCollections() const { return m_collections; }
-  virtual const CollRegistry& getReadCollections() const { return m_readCollections; }
-  virtual podio::CollectionIDTable* getCollectionIDs() { return m_collectionIDs; }
-
-  /// Set the collection IDs (if reading a file)
-  void setCollectionIDs(podio::CollectionIDTable* collectionIds);
-  /// Resets caches of reader and event store, increases event counter
-  void endOfRead();
-
-
-  TTree* eventDataTree() {return m_eventDataTree;}
-
-private:
-
-  EVENT::LCEvent* evt = nullptr;
-  // eventDataTree
-  TTree* m_eventDataTree;
-  /// LCIO reader for ROOT files
-  IO::LCReader* m_reader;
-  /// LCIO reader for ROOT files
-  plcio::EventHeaderCollection* pl_evtcol;
-  /// the handle of DataProvider
-  IDataProviderSvc* m_pIDP{nullptr};
-  /// podio::ROOTReader m_reader;
-  /// LCIO EventStore, used to initialise collections
-  /// podio::EventStore m_provider;
-  /// Counter of the event number
-  int m_eventNum{0};
-  /// Number of events in the file / to process
-  int m_eventMax{-1};
-  /// the current file index in the m_filenames vector
-  int m_fileIndex{0};
-
-
-  SmartIF<IConversionSvc> m_cnvSvc;
-
-  // special members for podio handling
-  std::vector<std::pair<std::string, podio::CollectionBase*>> m_collections;
-  std::vector<std::pair<std::string, podio::CollectionBase*>> m_readCollections;
-  podio::CollectionIDTable* m_collectionIDs;
-
-protected:
-//  bool exist_MCP = false;
-  LCIO2Plcio cvtor;
-//  EVENT::LCCollection* mcpcol_lc;
-//  plcio::MCParticleCollection* mcpcol_pl;
-
-  /// ROOT file name the input is read from. Set by option filename
-  std::vector<std::string> m_filenames;
-  std::string m_filename;
-};
-#endif  // CORE_LCIODATASVC_H
diff --git a/FWCore/FWCore/PodioDataSvc.h b/FWCore/FWCore/PodioDataSvc.h
deleted file mode 100644
index 09194a30c404263f1b06f4457eafb02282a1e399..0000000000000000000000000000000000000000
--- a/FWCore/FWCore/PodioDataSvc.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef FWCORE_PODIODATASVC_H
-#define FWCORE_PODIODATASVC_H
-
-#include "GaudiKernel/DataSvc.h"
-#include "GaudiKernel/IConversionSvc.h"
-// PODIO
-#include "podio/CollectionBase.h"
-#include "podio/CollectionIDTable.h"
-#include "podio/EventStore.h"
-#include "podio/ROOTReader.h"
-
-#include <utility>
-// Forward declarations
-
-/** @class PodioEvtSvc EvtDataSvc.h
- *
- *   An EvtDataSvc for PODIO classes
- *
- *  @author B. Hegner
- */
-class PodioDataSvc : public DataSvc {
-public:
-  typedef std::vector<std::pair<std::string, podio::CollectionBase*>> CollRegistry;
-
-  virtual StatusCode initialize();
-  virtual StatusCode reinitialize();
-  virtual StatusCode finalize();
-  virtual StatusCode clearStore();
-
-  /// Standard Constructor
-  PodioDataSvc(const std::string& name, ISvcLocator* svc);
-
-  /// Standard Destructor
-  virtual ~PodioDataSvc();
-
-  // Use DataSvc functionality except where we override
-  using DataSvc::registerObject;
-  /// Overriding standard behaviour of evt service
-  /// Register object with the data store.
-  virtual StatusCode registerObject(const std::string& fullPath, DataObject* pObject) final;
-
-  StatusCode readCollection(const std::string& collectionName, int collectionID);
-
-  virtual const CollRegistry& getCollections() const { return m_collections; }
-  virtual const CollRegistry& getReadCollections() const { return m_readCollections; }
-  virtual podio::CollectionIDTable* getCollectionIDs() { return m_collectionIDs; }
-
-  /// Set the collection IDs (if reading a file)
-  void setCollectionIDs(podio::CollectionIDTable* collectionIds);
-  /// Resets caches of reader and event store, increases event counter
-  void endOfRead();
-
-
-  TTree* eventDataTree() {return m_eventDataTree;}
-
-
-private:
-
-  // eventDataTree
-  TTree* m_eventDataTree;
-  /// PODIO reader for ROOT files
-  podio::ROOTReader m_reader;
-  /// PODIO EventStore, used to initialise collections
-  podio::EventStore m_provider;
-  /// Counter of the event number
-  int m_eventNum{0};
-  /// Number of events in the file / to process
-  int m_eventMax{-1};
-
-
-  SmartIF<IConversionSvc> m_cnvSvc;
-
-  // special members for podio handling
-  std::vector<std::pair<std::string, podio::CollectionBase*>> m_collections;
-  std::vector<std::pair<std::string, podio::CollectionBase*>> m_readCollections;
-  podio::CollectionIDTable* m_collectionIDs;
-
-protected:
-  /// ROOT file name the input is read from. Set by option filename
-  std::vector<std::string> m_filenames;
-  std::string m_filename;
-};
-#endif  // CORE_PODIODATASVC_H
diff --git a/FWCore/python/FWCore/__init__.py b/FWCore/python/FWCore/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/FWCore/python/FWCore/dump_joboptions.py b/FWCore/python/FWCore/dump_joboptions.py
deleted file mode 100644
index eaf71c9aa02ca604f7c25c2777ed3f9e7cd00246..0000000000000000000000000000000000000000
--- a/FWCore/python/FWCore/dump_joboptions.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from __future__ import print_function
-import argparse
-import ROOT
-
-parser = argparse.ArgumentParser(description='Job Options Dumper')
-parser.add_argument( dest='fname', type=str, help="name of file to read")
-
-
-def dump_joboptions(filename):
-  """ Simple and straightforward dump of the output of Gaudi's JobOptionsSvc
-  to stdout.
-  
-  Parameters
-  ----------
-
-  filename: str
-      The name of the CEPCSW output file containing joboptions to print
-  """
-  f = ROOT.TFile(filename)
-  t = f.metadata
-  for event in t:
-      s =  event.gaudiConfigOptions
-      for e in s:
-          print(e)
-
-if __name__ == "__main__":
-    args = parser.parse_args()
-    dump_joboptions(args.fname)
-
-  
diff --git a/FWCore/python/FWCore/joboptions.py b/FWCore/python/FWCore/joboptions.py
deleted file mode 100644
index 47f8173d837c452551803be2690acb6d5e513ff2..0000000000000000000000000000000000000000
--- a/FWCore/python/FWCore/joboptions.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import argparse
-
-def parse_standard_job_options(scriptname=""):
-    """
-    Returns the parsed arguments, adding a parser with commonly needed opts:
-    - args.nevents      -- number of events (int), specify with --nevents
-    - args.inputfile    -- the input file (string), specify with --inputfile
-    - args.outputfile   -- the output file (string), specify with --outputfile
-    """
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--inputfile', type=str, default='', help='specify an input file')
-    parser.add_argument('--outputfile', type=str, default='', help='specify an output file')
-    parser.add_argument('--nevents', type=int, default=None, help='specify number of events to process')
-    args, _ = parser.parse_known_args()
-    return args
diff --git a/FWCore/src/KeepDropSwitch.cpp b/FWCore/src/KeepDropSwitch.cpp
deleted file mode 100644
index 6617c03208e39556e2594ebe48d7bf0c29796b8b..0000000000000000000000000000000000000000
--- a/FWCore/src/KeepDropSwitch.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "FWCore/KeepDropSwitch.h"
-
-#include <iostream>
-#include <sstream>
-#include <stdexcept>
-
-int wildcmp(const char* wild, const char* string) {
-  // Written by Jack Handy - <A href="mailto:jakkhandy@hotmail.com">jakkhandy@hotmail.com</A>
-  const char *cp = nullptr, *mp = nullptr;
-  while ((*string) && (*wild != '*')) {
-    if ((*wild != *string) && (*wild != '?')) {
-      return 0;
-    }
-    wild++;
-    string++;
-  }
-  while (*string) {
-    if (*wild == '*') {
-      if (!*++wild) {
-        return 1;
-      }
-      mp = wild;
-      cp = string + 1;
-    } else if ((*wild == *string) || (*wild == '?')) {
-      wild++;
-      string++;
-    } else {
-      wild = mp;
-      string = cp++;
-    }
-  }
-  while (*wild == '*') {
-    wild++;
-  }
-  return !*wild;
-}
-
-std::vector<std::string> split(const std::string& s, char delim) {
-  std::vector<std::string> elems;
-  std::stringstream ss(s);
-  std::string item;
-  while (std::getline(ss, item, delim)) {
-    if (item != "") elems.push_back(item);
-  }
-  return elems;
-}
-
-bool KeepDropSwitch::isOn(const std::string& astring) const {
-  typedef std::map<std::string, bool>::const_iterator MIter;
-  MIter im = m_cache.find(astring);
-  if (im != m_cache.end())
-    return im->second;
-  else {
-    bool val = getFlag(astring);
-    m_cache.insert(std::pair<std::string, bool>(astring, val));
-    return val;
-  }
-}
-
-bool KeepDropSwitch::getFlag(const std::string& astring) const {
-  bool flag = true;
-  for (const auto& cmdline : m_commandlines) {
-    std::vector<std::string> words = split(cmdline, ' ');
-    if (words.size() != 2) {
-      std::ostringstream msg;
-      msg << "malformed command string : " << cmdline;
-      throw std::invalid_argument(msg.str());
-    }
-    std::string cmd = words[0];
-    std::string pattern = words[1];
-    Cmd theCmd = UNKNOWN;
-    if (cmd == "keep")
-      theCmd = KEEP;
-    else if (cmd == "drop")
-      theCmd = DROP;
-    else {
-      std::ostringstream msg;
-      msg << "malformed command in line: " << std::endl;
-      msg << cmdline << std::endl;
-      msg << "should be keep or drop, lower case" << std::endl;
-      throw std::invalid_argument(msg.str());
-    }
-    bool match = wildcmp(pattern.c_str(), astring.c_str());
-    if (not match)
-      continue;
-    else if (theCmd == KEEP)
-      flag = true;
-    else
-      flag = false;
-  }
-  return flag;
-}
-
-KeepDropSwitch::Cmd KeepDropSwitch::extractCommand(const std::string cmdline) const {
-  std::vector<std::string> words = split(cmdline, ' ');
-  for (auto& word : words)
-    std::cout << "'" << word << "' ";
-  std::cout << std::endl;
-  return UNKNOWN;
-}
diff --git a/FWCore/src/PodioDataSvc.cpp b/FWCore/src/PodioDataSvc.cpp
deleted file mode 100644
index ce7d3699d5b7cd7e09d59be617ab73222803ad6c..0000000000000000000000000000000000000000
--- a/FWCore/src/PodioDataSvc.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#include "FWCore/PodioDataSvc.h"
-#include "GaudiKernel/IConversionSvc.h"
-#include "GaudiKernel/IEventProcessor.h"
-#include "GaudiKernel/ISvcLocator.h"
-
-#include "FWCore/DataWrapper.h"
-
-#include "TTree.h"
-
-/// Service initialisation
-StatusCode PodioDataSvc::initialize() {
-  // Nothing to do: just call base class initialisation
-  StatusCode status = DataSvc::initialize();
-  ISvcLocator* svc_loc = serviceLocator();
-
-
-  // Attach data loader facility
-  m_cnvSvc = svc_loc->service("EventPersistencySvc");
-  status = setDataLoader(m_cnvSvc);
-
-  if (m_filename != "") {
-    m_filenames.push_back(m_filename);
-  }
-
-  if (m_filenames.size() > 0) {
-    if (m_filenames[0] != "") {
-      m_reader.openFiles(m_filenames);
-      m_eventMax = m_reader.getEntries();
-      auto idTable = m_reader.getCollectionIDTable();
-
-      setCollectionIDs(idTable);
-      m_provider.setReader(&m_reader);
-    }
-  }
-  return status;
-}
-/// Service reinitialisation
-StatusCode PodioDataSvc::reinitialize() {
-  // Do nothing for this service
-  return StatusCode::SUCCESS;
-}
-/// Service finalization
-StatusCode PodioDataSvc::finalize() {
-  m_cnvSvc = 0;  // release
-  DataSvc::finalize().ignore();
-  return StatusCode::SUCCESS;
-}
-
-StatusCode PodioDataSvc::clearStore() {
-  for (auto& collNamePair : m_collections) {
-    if (collNamePair.second != nullptr) {
-      collNamePair.second->clear();
-    }
-  }
-  for (auto& collNamePair : m_readCollections) {
-    if (collNamePair.second != nullptr) {
-      collNamePair.second->clear();
-    }
-  }
-  DataSvc::clearStore().ignore();
-  m_collections.clear();
-  m_readCollections.clear();
-  return StatusCode::SUCCESS;
-}
-
-void PodioDataSvc::endOfRead() {
-  if (m_eventMax != -1) {
-    m_provider.clearCaches();
-    m_reader.endOfEvent();
-    if ( ++m_eventNum >= m_eventMax ) {
-      info() << "Reached end of file with event " << m_eventMax << endmsg;
-      IEventProcessor* eventProcessor;
-      service("ApplicationMgr", eventProcessor);
-      eventProcessor->stopRun();
-    }
-  }
-}
-
-void PodioDataSvc::setCollectionIDs(podio::CollectionIDTable* collectionIds) {
-  if (m_collectionIDs != nullptr) {
-    delete m_collectionIDs;
-  }
-  m_collectionIDs = collectionIds;
-}
-
-/// Standard Constructor
-PodioDataSvc::PodioDataSvc(const std::string& name, ISvcLocator* svc)
-    : DataSvc(name, svc), m_collectionIDs(new podio::CollectionIDTable()) {
-
-  m_eventDataTree = new TTree("events", "Events tree");
-    }
-
-/// Standard Destructor
-PodioDataSvc::~PodioDataSvc() {}
-
-StatusCode PodioDataSvc::readCollection(const std::string& collName, int collectionID) {
-  podio::CollectionBase* collection(nullptr);
-  m_provider.get(collectionID, collection);
-  auto wrapper = new DataWrapper<podio::CollectionBase>;
-  int id = m_collectionIDs->add(collName);
-  collection->setID(id);
-  wrapper->setData(collection);
-  m_readCollections.emplace_back(std::make_pair(collName, collection));
-  return DataSvc::registerObject(collName, wrapper);
-}
-
-StatusCode PodioDataSvc::registerObject(const std::string& fullPath, DataObject* pObject) {
-  DataWrapperBase* wrapper = dynamic_cast<DataWrapperBase*>(pObject);
-  if (wrapper != nullptr) {
-    podio::CollectionBase* coll = wrapper->collectionBase();
-    if (coll != nullptr) {
-      size_t pos = fullPath.find_last_of("/");
-      std::string shortPath(fullPath.substr(pos + 1, fullPath.length()));
-      int id = m_collectionIDs->add(shortPath);
-      coll->setID(id);
-      m_collections.emplace_back(std::make_pair(shortPath, coll));
-    }
-  }
-  return DataSvc::registerObject(fullPath, pObject);
-}
diff --git a/FWCore/src/components/CEPCDataSvc.cpp b/FWCore/src/components/CEPCDataSvc.cpp
deleted file mode 100644
index fa870478432eaf570360b8bceb73406cf2e66692..0000000000000000000000000000000000000000
--- a/FWCore/src/components/CEPCDataSvc.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "CEPCDataSvc.h"
-
-#include "GaudiKernel/IConversionSvc.h"
-#include "GaudiKernel/ISvcLocator.h"
-#include "GaudiKernel/SvcFactory.h"
-
-// Instantiation of a static factory class used by clients to create
-// instances of this service
-DECLARE_SERVICE_FACTORY(CEPCDataSvc)
-
-/// Standard Constructor
-CEPCDataSvc::CEPCDataSvc(const std::string& name, ISvcLocator* svc)
-    : PodioDataSvc(name, svc)
-{
-  declareProperty("inputs", m_filenames = {}, "Names of the files to read");
-  declareProperty("input", m_filename = "", "Name of the file to read");
-}
-
-/// Standard Destructor
-CEPCDataSvc::~CEPCDataSvc() {}
diff --git a/FWCore/src/components/CEPCDataSvc.h b/FWCore/src/components/CEPCDataSvc.h
deleted file mode 100644
index 4953799c435618413978cb309abbda04ae78e83d..0000000000000000000000000000000000000000
--- a/FWCore/src/components/CEPCDataSvc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef FWCORE_CEPCDATASVC_H
-#define FWCORE_CEPCDATASVC_H
-
-#include "FWCore/PodioDataSvc.h"
-
-class CEPCDataSvc : public PodioDataSvc
-{
-  friend class SvcFactory<CEPCDataSvc>;
-
-public:
-  /// Standard Constructor
-  CEPCDataSvc(const std::string& name, ISvcLocator* svc);
-
-  /// Standard Destructor
-  virtual ~CEPCDataSvc();
-};
-
-#endif  // FWCORE_CEPCDATASVC_H
diff --git a/FWCore/src/components/LCIO2Plcio.cpp b/FWCore/src/components/LCIO2Plcio.cpp
deleted file mode 100644
index 72cd688a9469a06c26113ec76aaf5be6df189d39..0000000000000000000000000000000000000000
--- a/FWCore/src/components/LCIO2Plcio.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-#include "LCIO2Plcio.h"
-
-#include "lcio.h"
-#include "EVENT/LCCollection.h" 
-#include "plcio/MCParticle.h"
-#include "plcio/MCParticleConst.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/LCRunHeader.h"
-#include "plcio/LCRunHeaderCollection.h"
-#include "EVENT/MCParticle.h"
-
-typedef std::vector<EVENT::MCParticle*> MCParticleVec ;
-
-CollectionsMap LCIO2Plcio::map_cols;
-std::string LCIO2Plcio::CollName;
-
-void lp_info(std::string s){
-  printf("[LCIO2Plcio]:\t\t%s.\n", &s[0]);
-}
-
-template<typename T>
-static plcio::FloatThree FloatThreeFROMConstPtr(const T* vpos){
-  float tmp[3];
-  for(unsigned i=0; i<3; i++){
-    tmp[i] = vpos[i];
-  }
-  return plcio::FloatThree(tmp);
-}
-
-template<typename T>
-static plcio::FloatThree FloatThreeFROMFloatVec(std::vector<T> vec){
-  float tmp[3];
-  for(unsigned i=0; i<3; i++){
-    tmp[i] = vec[i];
-  }
-  return plcio::FloatThree(tmp);
-}
-
-template<typename T>
-static plcio::DoubleThree DoubleThreeFROMConstPtr(const T* vpos){
-  double tmp[3];
-  for(unsigned i=0; i<3; i++)
-    tmp[i] = vpos[i];
-  return plcio::DoubleThree(tmp);
-}
-
-std::array<float, 6> vec6_2_arr6(std::vector<float> vec){
-  std::array<float, 6> arr;
-  for(unsigned i=0; i<6; i++){
-    arr[i] = vec[i];
-  }
-  return arr;
-}
-
-LCIO2Plcio::LCIO2Plcio(){
-  map_cvt.insert(std::make_pair<std::string, fptr>("MCParticle", Convertor_MCParticle));
-  map_cvt.insert(std::make_pair<std::string, fptr>("LCRunHeader", Convertor_LCRunHeader));
-  map_cvt.insert(std::make_pair<std::string, fptr>("SimTrackerHit", Convertor_SimTrackerHit));
-  map_cvt.insert(std::make_pair<std::string, fptr>("SimCalorimeterHit", Convertor_SimCalorimeterHit));
-  map_cvt.insert(std::make_pair<std::string, fptr>("Cluster", Convertor_Cluster));
-  map_cvt.insert(std::make_pair<std::string, fptr>("Track", Convertor_Track));
-  map_cvt.insert(std::make_pair<std::string, fptr>("TrackerHit", Convertor_TrackerHit));
-  map_cvt.insert(std::make_pair<std::string, fptr>("TPCHit", Convertor_TPCHit));
-  map_cvt.insert(std::make_pair<std::string, fptr>("ReconstructedParticle", Convertor_ReconstructedParticle));
-  map_cvt.insert(std::make_pair<std::string, fptr>("ParticleID", Convertor_ParticleID));
-}
-LCIO2Plcio::LCIO2Plcio(EVENT::LCCollection* collection){
-  LCIO2Plcio();
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_LCRunHeader(EVENT::LCCollection* lc_col){
-  plcio::LCRunHeaderCollection* pl_col = new plcio::LCRunHeaderCollection();
-
-  // Convert basic info from LCIO to plcio;
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-      EVENT::LCRunHeader* lc_var = (EVENT::LCRunHeader*) lc_col->getElementAt(i) ;
-      plcio::LCRunHeader pl_var = (plcio::LCRunHeader) pl_col->create();
-      pl_var.setRunNumber( lc_var->getRunNumber() );
-      pl_var.setDetectorName( lc_var->getDetectorName() );
-      pl_var.setDescription( lc_var->getDescription() );
-      
-      std::vector<std::string> vec_dct = *(lc_var->getActiveSubdetectors());
-      for( unsigned j=0,N=vec_dct.size(); j<N; j++){
-        pl_var.addActiveSubdetector( vec_dct[j] );
-      }
-  }
-  return pl_col;
-}
-
-void LCIO2Plcio::setMCParticle(EVENT::MCParticle* lc_var, plcio::MCParticle& pl_var){
-
-  pl_var.setPDG( lc_var->getPDG() );
-  pl_var.setGeneratorStatus( lc_var->getGeneratorStatus() );
-  pl_var.setSimulatorStatus( lc_var->getSimulatorStatus() );
-  pl_var.setCharge( lc_var->getCharge() );
-  pl_var.setTime( lc_var->getTime() );
-  pl_var.setMass( lc_var->getMass() );
-  pl_var.setStopped( lc_var->isStopped() );
-  pl_var.setOverlay( lc_var->isOverlay() );
-  pl_var.setBackscatter( lc_var->isBackscatter() );
-  pl_var.setDecayedInTracker( lc_var->isDecayedInTracker() );
-  pl_var.setDecayedInCalorimeter( lc_var->isDecayedInCalorimeter() );
-  pl_var.setCreatedInSimulation( lc_var->isCreatedInSimulation() );
-  pl_var.setVertexIsNotEndpointOfParent( lc_var->vertexIsNotEndpointOfParent() );
-  pl_var.setHasLeftDetector( lc_var->hasLeftDetector() );
-
-  pl_var.setSpin( plcio::FloatThree( lc_var->getSpin() ) );
-  pl_var.setColorFlow( plcio::IntTwo( lc_var->getColorFlow() ) );
-  pl_var.setVertex( plcio::DoubleThree( lc_var->getVertex()));
-  pl_var.setEndpoint( plcio::DoubleThree( lc_var->getEndpoint() ) );
-  pl_var.setMomentum( FloatThreeFROMConstPtr(lc_var->getMomentum()) );
-  pl_var.setMomentumAtEndpoint( FloatThreeFROMConstPtr(lc_var->getMomentumAtEndpoint()) );
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_MCParticle(EVENT::LCCollection* lc_col){
-  plcio::MCParticleCollection* pl_col = new plcio::MCParticleCollection();
-
-  // Convert basic info from LCIO to plcio;
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-      EVENT::MCParticle* lc_var = (EVENT::MCParticle*) lc_col->getElementAt(i) ;
-      plcio::MCParticle pl_var = (plcio::MCParticle) pl_col->create();
-
-      setMCParticle(lc_var, pl_var);
-      // dealing each of 'Parents' of lcio::MCParticle ;
-      const MCParticleVec& veclc = lc_var->getParents();
-      for(unsigned j=0; j<veclc.size(); j++){
-        EVENT::MCParticle* vlcreg = veclc[j];
-        for(unsigned k=0; k<i; ++k){
-          if(((EVENT::MCParticle*) lc_col->getElementAt(k)) == vlcreg){
-            // A loop for plcio's MCParticleCollection to recover plcio's relationship;
-            plcio::MCParticle mcprt = pl_col->at(k);
-            pl_var.addParent(mcprt);
-            mcprt.addDaughter(pl_var);        
-	  }
-	}
-      }
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_SimTrackerHit(EVENT::LCCollection* lc_col){
-  plcio::SimTrackerHitCollection* pl_col = new plcio::SimTrackerHitCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::SimTrackerHit* lc_var = (EVENT::SimTrackerHit*) lc_col->getElementAt(i) ;
-    plcio::SimTrackerHit pl_var = (plcio::SimTrackerHit) pl_col->create();
-
-    pl_var.setCellID0( lc_var->getCellID0() );
-    pl_var.setCellID1( lc_var->getCellID1() );
-    pl_var.setEDep( lc_var->getEDep() );
-    pl_var.setTime( lc_var->getTime() );
-    pl_var.setPathLength( lc_var->getPathLength() );
-    pl_var.setQuality( lc_var->getQuality() );
-    pl_var.setPosition( lc_var->getPosition() );
-    pl_var.setMomentum( lc_var->getMomentum() );
-    pl_var.setOverlay( lc_var->isOverlay() );
-    pl_var.setProducedBySecondary( lc_var->isProducedBySecondary() );
-
-    // Looping the LCIO::MCParticleCollection to pick Particle for Hits;
-    CollectionsVec vec_mcp;
-    vec_mcp = map_cols["MCParticle"];
-    EVENT::LCCollection* hitcol_lc = (EVENT::LCCollection*) vec_mcp[0].first;
-    plcio::MCParticleCollection* hitcol_pl = (plcio::MCParticleCollection*) vec_mcp[0].second;
-
-    int index = -1;
-    // search corresponding MCParticleCollection*;
-    EVENT::MCParticle* mcptr_reg = lc_var->getMCParticle();
-    for( unsigned j=0, M=hitcol_lc->getNumberOfElements(); j<M; ++j){
-      EVENT::MCParticle* mcpin_lc = (EVENT::MCParticle*) hitcol_lc->getElementAt(j);
-      if( mcpin_lc == mcptr_reg ){
-	index = j;
-      }
-    }
-//    if( index != -1) lp_info("Cedar: Convertor SimTrackerHit Success.");
-    bool is_empty = false;
-    if( index == -1){
-      if(mcptr_reg == nullptr) is_empty = true;
-//      lp_info("Convertor SimTrackerHit Problem.");
-//      printf("LCCollection size: %d\n", hitcol_lc->getNumberOfElements());
-//      printf("MCParticleCollection size: %d\n", hitcol_pl->size());
-//      printf("Index: %d\n", index);
-    }
-    if( is_empty == false )
-      pl_var.setMCParticle( hitcol_pl->at(index) );
-
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_SimCalorimeterHit(EVENT::LCCollection* lc_col){
-  plcio::SimCalorimeterHitCollection* pl_col = new plcio::SimCalorimeterHitCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::SimCalorimeterHit* lc_var = (EVENT::SimCalorimeterHit*) lc_col->getElementAt(i);
-    plcio::SimCalorimeterHit pl_var = (plcio::SimCalorimeterHit) pl_col->create();
-
-    pl_var.setCellID0( lc_var->getCellID0() );
-    pl_var.setCellID1( lc_var->getCellID1() );
-    pl_var.setEnergy( lc_var->getEnergy() );
-    pl_var.setPosition( FloatThreeFROMConstPtr(lc_var->getPosition()) );
-
-    // converting from lc_var to pl_var on the contribution variables;
-    for( unsigned j=0, N=lc_var->getNMCContributions(); j<N; j++){
-      plcio::ConstCaloHitContribution tmp(
-	lc_var->getPDGCont(j), lc_var->getEnergyCont(j),
-	lc_var->getTimeCont(j), FloatThreeFROMConstPtr(lc_var->getStepPosition(j)) 
-      );
-      pl_var.addContribution( tmp );
-    }
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_Cluster(EVENT::LCCollection* lc_col){
-  plcio::ClusterCollection* pl_col = new plcio::ClusterCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::Cluster* lc_var = (EVENT::Cluster*) lc_col->getElementAt(i);
-    plcio::Cluster pl_var = (plcio::Cluster) pl_col->create();
-
-    pl_var.setType(lc_var->getType());
-    pl_var.setEnergy(lc_var->getEnergy());
-    pl_var.setEnergyError(lc_var->getEnergyError());
-    pl_var.setPhi(lc_var->getIPhi());
-    pl_var.setITheta(lc_var->getITheta());
-    pl_var.setPosition( FloatThreeFROMConstPtr(lc_var->getPosition()) );
-    pl_var.setPositionError( vec6_2_arr6(lc_var->getPositionError()) );
-    pl_var.setDirectionError( FloatThreeFROMFloatVec(lc_var->getDirectionError()) );
-
-    std::vector<float> lcio_seq0 = lc_var->getShape();
-    for(unsigned j=0; j<lcio_seq0.size(); j++){
-      pl_var.addShap( lcio_seq0[j] );
-    }
-
-    lcio_seq0 = lc_var->getHitContributions();
-    for(unsigned j=0; j<lcio_seq0.size(); j++){
-      pl_var.addHitContribution( lcio_seq0[j] );
-    }
-
-    lcio_seq0 = lc_var->getSubdetectorEnergies();
-    for(unsigned j=0; j<lcio_seq0.size(); j++){
-      pl_var.addSubdetectorEnergie( lcio_seq0[j] );
-    }
-
-    EVENT::ParticleIDVec lcio_seq1 = lc_var->getParticleIDs();
-    for(unsigned j=0; j<lcio_seq1.size(); j++){
-      EVENT::ParticleID* lc_locx = lcio_seq1[j];
-
-      pl_var.addParticleID( plcio::ConstParticleID(
-        lc_locx->getType(), 
-	lc_locx->getPDG(),
-	lc_locx->getAlgorithmType(), 
-	lc_locx->getLikelihood()
-      ) );
-    }
-
-    EVENT::CalorimeterHitVec lcio_seq2 = lc_var->getCalorimeterHits();
-    for(unsigned j=0; j<lcio_seq2.size(); j++){
-      EVENT::CalorimeterHit* lc_locx = lcio_seq2[j];
-
-      podio::CollectionIDTable col2id;
-      plcio::ObjectID tmp;
-      tmp.index = i;
-      tmp.collectionID = col2id.collectionID(CollName);
-
-      pl_var.addHit( plcio::ConstCalorimeterHit(
-        lc_locx->getCellID0(),
-        lc_locx->getCellID1(),
-        lc_locx->getEnergy(),
-        lc_locx->getEnergyError(),
-        lc_locx->getTime(),
-        FloatThreeFROMConstPtr(lc_locx->getPosition()),
-        lc_locx->getType(),
-        tmp
-      ) );
-    }
-  }
-
-  for(unsigned i=0,N=lc_col->getNumberOfElements(); i<N; i++){
-    EVENT::Cluster* lc_var = (EVENT::Cluster*) lc_col->getElementAt(i);
-    plcio::Cluster pl_var = pl_col->at(i);
-    EVENT::ClusterVec lcio_seq3 = lc_var->getClusters();
-
-    for(unsigned j=0; j<lcio_seq3.size(); j++){
-      for(unsigned k=0,K=lc_col->getNumberOfElements(); k<K; k++){
-        if(lcio_seq3[j] == lc_col->getElementAt(k)){
-          pl_var.addCluster(pl_col->at(k));
-	  break;
-	}
-      }
-    }
-  }
-
-  return pl_col;
-}
-
-// QUEST::isAvailable dows not analyze;
-podio::CollectionBase* LCIO2Plcio::Convertor_ParticleID(EVENT::LCCollection* lc_col){
-  plcio::ParticleIDCollection* pl_col = new plcio::ParticleIDCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::ParticleID* lc_var = (EVENT::ParticleID*) lc_col->getElementAt(i);
-    plcio::ParticleID pl_var = (plcio::ParticleID) pl_col->create();
-
-    pl_var.setType( lc_var->getType() );
-    pl_var.setPDG( lc_var->getPDG() );
-    pl_var.setAlgorythmType( lc_var->getAlgorithmType() );
-    pl_var.setLikelihood( lc_var->getLikelihood() );
-    EVENT::FloatVec vec_float = lc_var->getParameters();
-    for(unsigned j=0; j<vec_float.size(); j++){
-      pl_var.addParameter(vec_float[j]);
-    }
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_ReconstructedParticle(EVENT::LCCollection* lc_col){
-  plcio::ReconstructedParticleCollection* pl_col = new plcio::ReconstructedParticleCollection();
-
-  for(unsigned i=0,N=lc_col->getNumberOfElements(); i<N; i++){
-    EVENT::ReconstructedParticle* lc_var = (EVENT::ReconstructedParticle*) lc_col->getElementAt(i);
-    plcio::ReconstructedParticle pl_var = (plcio::ReconstructedParticle) pl_col->create();
-
-    pl_var.setType( lc_var->getType() );
-    pl_var.setEnergy( lc_var->getEnergy() );
-    pl_var.setCharge( lc_var->getCharge() );
-    pl_var.setMass( lc_var->getMass() );
-    pl_var.setGoodnessOfPID( lc_var->getGoodnessOfPID() );
-
-    pl_var.setMomentum( FloatThreeFROMConstPtr(lc_var->getMomentum()) );
-    pl_var.setReferencePoint( FloatThreeFROMConstPtr(lc_var->getReferencePoint()) );
-
-    std::vector<float> vec = lc_var->getCovMatrix();
-    for(unsigned j=0,N=vec.size(); j<N; j++){
-      pl_var.setCovMatrix( j, vec[j] );
-    }
-
-    // QUEST: boolean to int: isPrimary, str2int: getAlgorithmType;
-    // pl_var.setStartVertex( lc_var->getStartVertex() ) 
-    // ignorant;
-    std::array<float, 6> arr_6;
-    EVENT::FloatVec fvec = lc_var->getStartVertex()->getCovMatrix();
-    for(unsigned j=0; j<6; j++){
-      arr_6[j] = fvec[j];
-    }
-    pl_var.setStartVertex( plcio::ConstVertex(
-      lc_var->getStartVertex()->isPrimary(),
-      lc_var->getStartVertex()->getChi2(),
-      lc_var->getStartVertex()->getProbability(),
-      FloatThreeFROMConstPtr( lc_var->getStartVertex()->getPosition() ),
-      arr_6,
-      0
-      //lc_var->getStartVertex()->getAlgorithmType()
-    ) );
-
-    //pl_var.setParticleIDUsed( lc_var->getParticleIDUsed() );
-    EVENT::ParticleID* lc_locx = lc_var->getParticleIDUsed();
-    CollectionsVec vec_cols = map_cols["ParticleID"];
-    EVENT::LCCollection* lc_mapcol = (EVENT::LCCollection*)vec_cols[0].first;
-    plcio::ParticleIDCollection* pl_mapcol = (plcio::ParticleIDCollection*)vec_cols[0].second;
-
-    for(unsigned k=0, LCsize=lc_mapcol->getNumberOfElements(); k<LCsize; k++){
-      if(lc_locx == lc_mapcol->getElementAt(k))
-        pl_var.setParticleIDUsed(pl_mapcol->at(k));
-    }
-    
-
-    //pl_var.addCluster();
-    std::vector<EVENT::Cluster*> vec_clust = lc_var->getClusters();
-    for(unsigned j=0; j<vec_clust.size(); j++){
-      CollectionsVec vec_cols = map_cols["Cluster"];
-      EVENT::LCCollection* lc_mapcol = (EVENT::LCCollection*)vec_cols[0].first;
-      plcio::ClusterCollection* pl_mapcol = (plcio::ClusterCollection*)vec_cols[0].second;
-
-      for(unsigned k=0; k<lc_mapcol->getNumberOfElements(); k++){
-        if( vec_clust[j] == lc_mapcol->getElementAt(k) )
-          pl_var.addCluster( pl_mapcol->at(k) );
-      }
-    }
-
-    //pl_var.addTrack();
-    EVENT::TrackVec vec_track = lc_var->getTracks();
-    for(unsigned j=0; j<vec_track.size(); j++){
-      CollectionsVec vec_cols = map_cols["Track"];
-      EVENT::LCCollection* lc_mapcol = (EVENT::LCCollection*)vec_cols[0].first;
-      plcio::TrackCollection* pl_mapcol = (plcio::TrackCollection*)vec_cols[0].second;
-
-      for(unsigned k=0; k<lc_mapcol->getNumberOfElements(); k++)
-        if(vec_track[j] == lc_mapcol->getElementAt(k))
-          pl_var.addTrack(pl_mapcol->at(k));
-    }
-
-    //pl_var.addParticleID( lc->getParticleIDs);
-    EVENT::ParticleIDVec vec_ParticleID = lc_var->getParticleIDs();
-    for(unsigned j=0; j<vec_ParticleID.size(); j++){
-      CollectionsVec vec_cols = map_cols["ParticleID"];
-      EVENT::LCCollection* lc_mapcol = (EVENT::LCCollection*)vec_cols[0].first;
-      plcio::ParticleIDCollection* pl_mapcol = (plcio::ParticleIDCollection*)vec_cols[0].second;
-
-      for(unsigned k=0,M=lc_mapcol->getNumberOfElements(); k<M; k++){
-        if(vec_ParticleID[j] == lc_mapcol->getElementAt(k))
-          pl_var.addParticleID( pl_mapcol->at(k) );
-      }
-    }
-  }
-  //pl_var.addParticle();
-  for(unsigned i=0, N=lc_col->getNumberOfElements(); i<N; i++){
-    EVENT::ReconstructedParticle* lc_var = (EVENT::ReconstructedParticle*)lc_col->getElementAt(i);
-    EVENT::ReconstructedParticleVec vec_RecPtc = lc_var->getParticles();
-
-    for(unsigned j=0; j<vec_RecPtc.size(); j++){
-      for(unsigned k=0, M=lc_col->getNumberOfElements(); k<M; k++){
-        if(vec_RecPtc[j] == lc_col->getElementAt(k))
-          pl_col->at(i).addParticle( pl_col->at(k) );
-      }
-    }
-  }
-
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_TrackerHit(EVENT::LCCollection* lc_col){
-  plcio::TrackerHitCollection* pl_col = new plcio::TrackerHitCollection();
-  
-  for(unsigned i=0,N=lc_col->getNumberOfElements(); i<N; i++){
-    EVENT::TrackerHit* lc_var = (EVENT::TrackerHit*) lc_col->getElementAt(i);
-    plcio::TrackerHit  pl_var = (plcio::TrackerHit) pl_col->create();
-    
-    pl_var.setCellID0(lc_var->getCellID0());
-    pl_var.setCellID1(lc_var->getCellID1());
-
-    pl_var.setType(lc_var->getType());
-    pl_var.setQuality(lc_var->getQuality());
-    pl_var.setTime(lc_var->getTime());
-    pl_var.setEDep(lc_var->getEDep());
-    pl_var.setEDepError(lc_var->getEDepError());
-    pl_var.setEdx(lc_var->getdEdx());
-    pl_var.setPosition( DoubleThreeFROMConstPtr(lc_var->getPosition()));
-    pl_var.setCovMatrix( vec6_2_arr6(lc_var->getCovMatrix()));
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_Track(EVENT::LCCollection* lc_col){
-  plcio::TrackCollection* pl_col = new plcio::TrackCollection();
-
-  for(unsigned i=0,N=lc_col->getNumberOfElements(); i<N; i++){
-    EVENT::Track* lc_var = (EVENT::Track*) lc_col->getElementAt(i);
-    plcio::Track pl_var = (plcio::Track) pl_col->create();
-
-    pl_var.setType( lc_var->getType() );
-    pl_var.setChi2( lc_var->getChi2() );
-    pl_var.setNdf( lc_var->getNdf() );
-    pl_var.setDEdx( lc_var->getdEdx() );
-    pl_var.setDEdxError( lc_var->getdEdxError() );
-    pl_var.setRadiusOfInnermostHit( lc_var->getRadiusOfInnermostHit() );
-
-    //pl_var.addTrackerHit( lc_var->getTrackerHits() );
-    //rely on TrackerHits collection;
-    //corresoponding with TrackerHit collection; 
-    EVENT::TrackerHitVec lcio_seq1 = lc_var->getTrackerHits();
-    for(unsigned j=0; j<lcio_seq1.size(); j++){
-      EVENT::TrackerHit* lc_locx = lcio_seq1[j];
-      CollectionsVec vec_cols = map_cols["TrackerHit"];
-      EVENT::LCCollection* lc_mapcol = (EVENT::LCCollection*)vec_cols[0].first;
-      plcio::TrackerHitCollection* pl_mapcol = (plcio::TrackerHitCollection*) vec_cols[0].second;
-
-      for(unsigned k=0; k<lc_mapcol->getNumberOfElements(); k++){
-        if( lc_locx == lc_mapcol->getElementAt(k) )
-          pl_var.addTrackerHit( pl_mapcol->at(k) );
-      } 
-    }
-
-    //pl_var.( lc_var->getSubdetectorHitNumbers() );
-    std::vector<int> lcio_IntVec1 = lc_var->getSubdetectorHitNumbers();
-    for(unsigned j=0; j<lcio_IntVec1.size(); j++){
-      pl_var.addSubDetectorHitNumber(lcio_IntVec1[j]);
-    }
-
-    //pl_var.( lc_var->getTrackStates() );
-    EVENT::TrackStateVec lcio_seq3 = lc_var->getTrackStates();
-    for(unsigned j=0; j<lcio_seq3.size(); j++){
-      EVENT::TrackState* lc_locx = lcio_seq3[j];
-      std::array<float, 15> tmp_covM;
-      for(unsigned k=0; k<15; k++){
-        tmp_covM[k] = lc_locx->getCovMatrix()[k];
-      }
-
-      plcio::TrackState tmp;
-      tmp.D0 = lc_locx->getD0();
-      tmp.Z0 = lc_locx->getZ0();
-      tmp.covMatrix = tmp_covM; 
-      tmp.location = lc_locx->getLocation();
-      tmp.omega = lc_locx->getOmega();
-      tmp.phi = lc_locx->getPhi();
-      tmp.referencePoint = FloatThreeFROMConstPtr( lc_locx->getReferencePoint() );
-      tmp.tanLambda = lc_locx->getTanLambda();
-      pl_var.addTrackState( tmp );
-    }
-  }
-
-  //pl_var.( lc_var->getTracks() );
-  for(unsigned i=0; i<lc_col->getNumberOfElements(); i++){
-    EVENT::Track* lc_var = (EVENT::Track*)lc_col->getElementAt(i);
-    EVENT::TrackVec lcio_seq2 = lc_var->getTracks();
-
-    for(unsigned j=0; j<lcio_seq2.size(); j++){
-      EVENT::Track* lc_locx = lcio_seq2[j];
-      for(unsigned k=0; k<lc_col->getNumberOfElements(); k++){
-        if( lc_locx == lc_col->getElementAt(k) )
-          pl_col->at(i).addTrack(pl_col->at(k));
-      }
-    }
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_Vertex(EVENT::LCCollection* lc_col){
-  plcio::VertexCollection* pl_col = new plcio::VertexCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::Vertex* lc_var = (EVENT::Vertex*) lc_col->getElementAt(i);
-    plcio::Vertex pl_var = (plcio::Vertex) pl_col->create();
-  
-    // Quest: data.primary is an int value, set by boolean number;
-    pl_var.setPrimary( lc_var->isPrimary() );
-    pl_var.setChi2( lc_var->getChi2() );
-    pl_var.setProbability( lc_var->getProbability() );
-
-    float plcio_v[3];
-    const float* lcio_v = lc_var->getPosition();
-    plcio_v[0] = lcio_v[0];
-    plcio_v[1] = lcio_v[1];
-    plcio_v[2] = lcio_v[2];
-    pl_var.setPosition( plcio::FloatThree(plcio_v) );
-
-    std::vector<float> vec_pra = lc_var->getParameters();
-    for( unsigned j=0,M=vec_pra.size(); j<M; j++){
-      pl_var.addParameter(vec_pra[j]);
-    }
-
-    // convert string into int(type code);
-//    pl_var.setAlgorithmType( lc_var->getAlgorithmType() );
-//    pl_var.setCovMatrix( lc_var->() );
-//    pl_var.setAssociatedParticle( lc_var->() );
-  }
-  return pl_col;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_TPCHit(EVENT::LCCollection* lc_col){
-  plcio::TPCHitCollection* pl_col = new plcio::TPCHitCollection();
-
-  for( unsigned i=0,N=lc_col->getNumberOfElements() ; i< N ; ++i){
-    EVENT::TPCHit* lc_var = (EVENT::TPCHit*) lc_col->getElementAt(i);
-    plcio::TPCHit pl_var = (plcio::TPCHit) pl_col->create();
-
-    pl_var.setCellID(lc_var->getCellID());
-    pl_var.setTime(lc_var->getTime());
-    pl_var.setCharge(lc_var->getCharge());
-    pl_var.setQuality(lc_var->getQuality());
-
-    for( unsigned j=0,M=lc_var->getNRawDataWords(); j<M; j++){
-      pl_var.addRawDataWord(lc_var->getRawDataWord(j));
-    }
-  }
-  return pl_col;
-}
-
-bool LCIO2Plcio::isReady(const std::string& TypeName){
-  if( TypeName == "SimTrackerHit" ){
-    std::vector<std::string>::iterator it = find(
-                  vec_Types.begin(), vec_Types.end(), "MCParticle"
-    );
-    if( it != vec_Types.end() )
-      return true;
-  }
-  return false;
-}
-
-podio::CollectionBase* LCIO2Plcio::Convertor_getPlcio(EVENT::LCCollection* lc_col){
-
-  podio::CollectionBase* collection(nullptr);
-  TypeName = lc_col->getTypeName();
-
-//  lp_info("Converting "+TypeName);
-  bool ready = true; 
-  if( !ready ){
-    lp_info("Not ready yet.");
-    lp_info("Please put MCParticle firstly in the python file, Please");
-    return nullptr;
-  }
-
-  fptr fp;
-  if( map_cvt.find(TypeName) == map_cvt.end()){
-    lp_info("unrecognized "+TypeName);
-  }else{
-    fp = *map_cvt[TypeName];
-  }
-
-  fp = *map_cvt[TypeName];
-  collection = fp(lc_col);
-
-// maintain map<TypeName, CollVec>;
-    map_cols[TypeName].push_back(
-      std::pair<EVENT::LCCollection*, podio::CollectionBase*>(lc_col, collection)
-    );
-
-//  lp_info("done.");
-  return collection;
-}
diff --git a/FWCore/src/components/LCIO2Plcio.h b/FWCore/src/components/LCIO2Plcio.h
deleted file mode 100644
index 3729105ce2c7dbf763c15d4524b4bde333b6d7a2..0000000000000000000000000000000000000000
--- a/FWCore/src/components/LCIO2Plcio.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef FWCORE_CONVERTOR_H
-#define FWCORE_CONVERTOR_H
-
-// LCIO
-
-#include <map>
-#include <iostream>
-#include <string>
-#include "lcio.h"
-// #include "IO/LCReader.h"
-// #include "EVENT/LCCollection.h"
-#include "EVENT/Vertex.h"
-#include "EVENT/SimTrackerHit.h"
-#include "plcio/SimTrackerHit.h"
-#include "plcio/SimTrackerHitCollection.h"
-#include "EVENT/SimCalorimeterHit.h"
-#include "plcio/SimCalorimeterHit.h"
-#include "plcio/SimCalorimeterHitCollection.h"
-#include "EVENT/MCParticle.h"
-#include "plcio/MCParticle.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/VertexCollection.h"
-#include "EVENT/TPCHit.h"
-#include "plcio/TPCHit.h"
-#include "plcio/TPCHitCollection.h"
-#include "EVENT/Cluster.h"
-#include "plcio/Cluster.h"
-#include "plcio/ClusterCollection.h"
-#include "EVENT/ParticleID.h"
-#include "EVENT/CalorimeterHit.h"
-#include "plcio/CalorimeterHit.h"
-#include "podio/CollectionIDTable.h"
-#include "EVENT/Track.h" 
-#include "EVENT/TrackerHit.h"
-#include "EVENT/TrackState.h" 
-#include "plcio/Track.h"  
-#include "plcio/TrackerHit.h"  
-#include "plcio/TrackCollection.h"  
-#include "plcio/TrackerHitCollection.h"  
-#include "EVENT/ReconstructedParticle.h" 
-#include "plcio/ReconstructedParticle.h"  
-#include "plcio/ReconstructedParticleCollection.h"  
-#include "plcio/ParticleID.h"  
-#include "plcio/ParticleIDCollection.h"  
-
-#include <utility>
-// Forward declarations
-
-/** @class LCIO2Plcio LCIO2Plcio.h
- *
- *   An LCIO2Plcio for Converting from LCCollection to plcio collection;
- *
- *  @author jhZou, gjCao 
- */
-
-// typedef plcio::MCParticleCollection* (*fptr) (EVENT::LCCollection*);
-typedef podio::CollectionBase* (*fptr) (EVENT::LCCollection*);
-typedef std::vector<std::pair<EVENT::LCCollection*, podio::CollectionBase*>> CollectionsVec;
-typedef std::map<std::string, CollectionsVec> CollectionsMap;
-
-class LCIO2Plcio{
-public:
-
-  /// Standard Constructor
-  LCIO2Plcio();
-  LCIO2Plcio(EVENT::LCCollection*);
-
-  /// Standard Destructor
-  virtual ~LCIO2Plcio(){}
-
-  void test(){ printf("MYTESTFUC\n"); }
-  void clear(){ map_cols.clear(); };
-
-//  plcio::MCParticleCollection* Convertor_getPlcio(EVENT::LCCollection*);
-  podio::CollectionBase* Convertor_getPlcio(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_MCParticle(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_LCRunHeader(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_SimTrackerHit(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_SimCalorimeterHit(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_Cluster(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_Track(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_TrackerHit(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_TPCHit(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_ReconstructedParticle(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_ParticleID(EVENT::LCCollection*);
-
-  static podio::CollectionBase* Convertor_LCRelation(EVENT::LCCollection*);
-  static podio::CollectionBase* Convertor_Vertex(EVENT::LCCollection*);
-
-  static void setMCParticle(EVENT::MCParticle*, plcio::MCParticle&);
-  void setCollName(const std::string &collName){ CollName = collName; };
-
-  bool isReady(const std::string&);
-
-private:
-  std::string TypeName;
-  static std::string CollName;
-  // maintain a log vec about data read;
-  std::vector<std::string> vec_Types;
-
-  // maintain a map from keyword to function pointer.
-  std::map<std::string, fptr> map_cvt;
-  static CollectionsMap map_cols;
-
-//  plcio::MCParticleCollection* hitcol_pl;
-//  EVENT::LCCollection* hitcol_lc;
-};
-#endif  // CORE_CONVERTOR_H
diff --git a/FWCore/src/components/LCIODataSvc.cpp b/FWCore/src/components/LCIODataSvc.cpp
deleted file mode 100644
index 3656f3ffc0770552333da606856a02209242921f..0000000000000000000000000000000000000000
--- a/FWCore/src/components/LCIODataSvc.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-#include "FWCore/LCIODataSvc.h"
-#include "LCIO2Plcio.h"
-#include "GaudiKernel/IConversionSvc.h"
-#include "GaudiKernel/IEventProcessor.h"
-#include "GaudiKernel/ISvcLocator.h"
-
-#include "IOIMPL/LCFactory.h"
-#include "FWCore/DataWrapper.h"
-#include "lcio.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/MCParticle.h"
-#include "plcio/EventHeaderCollection.h"
-#include "EVENT/MCParticle.h"
-
-#include "TTree.h"
-
-typedef std::vector<lcio::MCParticle*> MCParticleVec ;  
-
-DECLARE_SERVICE_FACTORY(LCIODataSvc)
-/// Service initialisation
-StatusCode LCIODataSvc::initialize() {
-  // Nothing to do: just call base class initialisation
-  StatusCode status = DataSvc::initialize();
-  ISvcLocator* svc_loc = serviceLocator();
-
-  // Attach data loader facility
-  m_cnvSvc = svc_loc->service("EventPersistencySvc");
-  status = setDataLoader(m_cnvSvc);
-
-  if ( name() != "EventDataSvc" ) {
-    service("EventDataSvc", m_pIDP, true);
-    if ( m_pIDP == nullptr ) {
-      error() << "Could not get the EventDataSvc instance" << endmsg;
-      return StatusCode::FAILURE;
-    }
-  }
-
-  m_reader = IOIMPL::LCFactory::getInstance()->createLCReader();
-
-  if (m_filename != "") {
-    m_filenames.push_back(m_filename);
-  }
-
-  if (m_filenames.size() > 0) {
-    m_reader->open(m_filenames[0]);
-    m_eventMax = m_reader->getNumberOfEvents();
-  }
-
-  return status;
-}
-/// Service reinitialisation
-StatusCode LCIODataSvc::reinitialize() {
-  // Do nothing for this service
-  return StatusCode::SUCCESS;
-}
-/// Service finalization
-StatusCode LCIODataSvc::finalize() {
-  m_reader->close();
-  delete m_reader;
-  m_reader = nullptr;
-  m_cnvSvc = 0;  // release
-  DataSvc::finalize().ignore();
-  return StatusCode::SUCCESS;
-}
-
-StatusCode LCIODataSvc::clearStore() {
-  for (auto& collNamePair : m_collections) {
-    if (collNamePair.second != nullptr) {
-      collNamePair.second->clear();
-    }
-  }
-  for (auto& collNamePair : m_readCollections) {
-    if (collNamePair.second != nullptr) {
-      collNamePair.second->clear();
-    }
-  }
-  DataSvc::clearStore().ignore();
-  m_collections.clear();
-  m_readCollections.clear();
-  return StatusCode::SUCCESS;
-}
-
-void LCIODataSvc::endOfRead() {
-  if (m_eventMax != -1) {
-    // m_provider.clearCaches();
-    // m_reader.endOfEvent();
-    if ( ++m_eventNum >= m_eventMax ) {
-      if ( ++m_fileIndex < m_filenames.size() ) {  // move to next file
-        m_reader->close();
-        m_reader->open( m_filenames[m_fileIndex] );
-        m_eventMax += m_reader->getNumberOfEvents();
-      }
-      else {  // reach to the end of the file list
-        info() << "Reached end of file with event " << m_eventMax << endmsg;
-        IEventProcessor* eventProcessor;
-        service("ApplicationMgr", eventProcessor);
-        eventProcessor->stopRun();
-      }
-    }
-  }
-  evt = nullptr;
-}
-
-void LCIODataSvc::setCollectionIDs(podio::CollectionIDTable* collectionIds) {
-  if (m_collectionIDs != nullptr) {
-    delete m_collectionIDs;
-  }
-  m_collectionIDs = collectionIds;
-}
-
-/// Standard Constructor
-LCIODataSvc::LCIODataSvc(const std::string& name, ISvcLocator* svc)
-    : DataSvc(name, svc), m_collectionIDs(new podio::CollectionIDTable()) {
-
-  m_eventDataTree = new TTree("events", "Events tree");
-  declareProperty("inputs", m_filenames = {}, "Names of the files to read");
-  declareProperty("input", m_filename = "", "Name of the file to read");
-
-    }
-
-/// Standard Destructor
-LCIODataSvc::~LCIODataSvc() {}
-
-
-StatusCode LCIODataSvc::readCollection(const std::string& collName, int collectionID) {
-
-  StatusCode stat = StatusCode::SUCCESS;
-  podio::CollectionBase* collection(nullptr);
-
-  if( evt == nullptr ){
-    evt = m_reader->readNextEvent();
-    cvtor.clear();
-
-    // basicly set EventHeader;
-    pl_evtcol = new plcio::EventHeaderCollection();
-    plcio::EventHeader evt_header;
-    evt_header = (plcio::EventHeader) pl_evtcol->create();
-    evt_header.setEventNumber( evt->getEventNumber() );
-    evt_header.setRunNumber( evt->getRunNumber() );
-    evt_header.setTimeStamp( evt->getTimeStamp() );
-    evt_header.setDetectorName( evt->getDetectorName() );
-
-    // wrap event header collection into Data service;
-    auto wrapper = new DataWrapper<podio::CollectionBase>;
-    int id = m_collectionIDs->add("EventHeader");
-    pl_evtcol->setID(id);
-    wrapper->setData(pl_evtcol);
-
-    if ( m_pIDP ) {
-      m_pIDP->registerObject("EventHeader", wrapper);
-    }
-    else {
-      m_readCollections.emplace_back(std::make_pair("EventHeader", pl_evtcol));
-      DataSvc::registerObject("EventHeader", wrapper);
-    }
-  }
-
-  debug() << "reading collection name: " << collName  << "." << endmsg;
-  EVENT::LCCollection* lc_col;
-  std::vector<std::string> vec_colns = *evt->getCollectionNames();
-  std::vector<std::string>::iterator it = find(vec_colns.begin(), vec_colns.end(), collName);
-  if( it != vec_colns.end() ){
-    lc_col = evt->getCollection(collName); 
-  }
-  else
-    return stat;
-//  debug() << "Got collection: " << collName  << "." << endmsg;
-
-  std::string TypeName = lc_col->getTypeName();
-//  if( !exist_MCP && (TypeName == "MCParticle") ) exist_MCP = true;
-//  if( TypeName == "MCParticle" ){
-//    if( !exist_MCP ) exist_MCP = true;
-//    mcpcol_pl = LCIO2Plcio::Core_MCParticle(lc_col);
-//    LCIO2Plcio::setLCIOMCParticleCollection(mcpcol_lc);
-//    LCIO2Plcio::setPlcioMCParticleCollection(mcpcol_pl);
-//  }
-  cvtor.setCollName(collName);
-  collection = cvtor.Convertor_getPlcio( lc_col );
-  pl_evtcol->at(0)->addCollectionName(collName);
-  pl_evtcol->at(0)->addCollectionType(TypeName);
-
-  auto wrapper = new DataWrapper<podio::CollectionBase>;
-  int id = m_collectionIDs->add(collName);
-  collection->setID(id);
-  wrapper->setData(collection);
-
-//  info() << "readCollection completed." << endmsg;
-
-  if ( m_pIDP ) {
-    stat = m_pIDP->registerObject(collName, wrapper);
-  }
-  else {
-    m_readCollections.emplace_back(std::make_pair(collName, collection));
-    stat = DataSvc::registerObject(collName, wrapper);
-  }
-  return stat;
-}
-
-StatusCode LCIODataSvc::registerObject(const std::string& fullPath, DataObject* pObject) {
-  DataWrapperBase* wrapper = dynamic_cast<DataWrapperBase*>(pObject);
-  if (wrapper != nullptr) {
-    podio::CollectionBase* coll = wrapper->collectionBase();
-    if (coll != nullptr) {
-      size_t pos = fullPath.find_last_of("/");
-      std::string shortPath(fullPath.substr(pos + 1, fullPath.length()));
-      int id = m_collectionIDs->add(shortPath);
-      coll->setID(id);
-      m_collections.emplace_back(std::make_pair(shortPath, coll));
-    }
-  }
-  return DataSvc::registerObject(fullPath, pObject);
-}
diff --git a/FWCore/src/components/LCIOInput.cpp b/FWCore/src/components/LCIOInput.cpp
deleted file mode 100644
index dab645881d2f0afce2407416e5a581bb76ae7c0a..0000000000000000000000000000000000000000
--- a/FWCore/src/components/LCIOInput.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "LCIOInput.h"
-
-#include "TFile.h"
-#include "TROOT.h"
-
-#include "FWCore/DataWrapper.h"
-#include "FWCore/LCIODataSvc.h"
-
-DECLARE_COMPONENT(LCIOInput)
-
-LCIOInput::LCIOInput(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) {}
-
-StatusCode LCIOInput::initialize() {
-  if (GaudiAlgorithm::initialize().isFailure()) return StatusCode::FAILURE;
-
-  // check whether we have the LCIOEvtSvc active
-  auto pSvc = service( m_dataSvc );
-  m_LCIODataSvc = dynamic_cast<LCIODataSvc*>(pSvc.get());
-  if (nullptr == m_LCIODataSvc) return StatusCode::FAILURE;
-
-  auto idTable = m_LCIODataSvc->getCollectionIDs();
-  for (auto& name : m_collectionNames) {
-    debug() << "Finding collection " << name << " in collection registry." << endmsg;
-/*
-    if (!idTable->present(name)) {
-      error() << "Requested product " << name << " not found." << endmsg;
-      return StatusCode::FAILURE;
-    }
-*/
-    m_collectionIDs.push_back(idTable->add(name));
-  }
-  return StatusCode::SUCCESS;
-}
-
-StatusCode LCIOInput::execute() {
-  size_t cntr = 0;
-  // Re-create the collections from ROOT file
-  for (auto& id : m_collectionIDs) {
-    const std::string& collName = m_collectionNames.value().at(cntr++);
-    debug() << "Registering collection to read " << collName << " with id " << id << endmsg;
-    if (m_LCIODataSvc->readCollection(collName, id).isFailure()) {
-      return StatusCode::FAILURE;
-    }
-  }
-  // Tell data service that we are done with requested collections
-  m_LCIODataSvc->endOfRead();
-  return StatusCode::SUCCESS;
-}
-
-StatusCode LCIOInput::finalize() {
-  if (GaudiAlgorithm::finalize().isFailure()) return StatusCode::FAILURE;
-  return StatusCode::SUCCESS;
-}
diff --git a/FWCore/src/components/LCIOInput.h b/FWCore/src/components/LCIOInput.h
deleted file mode 100644
index 1ede535f1bd62a54e565a20e9abf005d85825603..0000000000000000000000000000000000000000
--- a/FWCore/src/components/LCIOInput.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef FWCORE_LCIOINPUT_H
-#define FWCORE_LCIOINPUT_H
-// Gaaudi
-#include "GaudiAlg/GaudiAlgorithm.h"
-
-// STL
-#include <string>
-#include <vector>
-
-// forward declarations
-// from FWCore:
-class LCIODataSvc;
-
-/** @class LCIOInput FWCore/components/LCIOInput.h LCIOInput.h
- *
- *  Class that allows to read ROOT files written with LCIOInput
- *
- *  @author J. Lingemann
- */
-
-class LCIOInput : public GaudiAlgorithm {
-  friend class AlgFactory<LCIOInput>;
-
-public:
-  /// Constructor.
-  LCIOInput(const std::string& name, ISvcLocator* svcLoc);
-  /// Initialization of LCIOInput. Acquires the data service, opens root file and creates trees.
-  virtual StatusCode initialize();
-  /// Execute. Re-creates collections that are specified to be read and sets references.
-  virtual StatusCode execute();
-  /// Finalize. Closes ROOT file.
-  virtual StatusCode finalize();
-
-private:
-  /// Name of collections to read. Set by option collections (this is temporary)
-  Gaudi::Property<std::string> m_dataSvc{ this, "DataSvc", "LCIOInputSvc" };
-  Gaudi::Property<std::vector<std::string>> m_collectionNames{this, "collections", {}, "Places of collections to read"};
-  /// Collection IDs (retrieved with CollectionIDTable from ROOT file, using collection names)
-  std::vector<int> m_collectionIDs;
-  /// Data service: needed to register objects and get collection IDs. Just an observing pointer.
-  LCIODataSvc* m_LCIODataSvc;
-};
-
-#endif
diff --git a/FWCore/src/components/PodioInput.cpp b/FWCore/src/components/PodioInput.cpp
deleted file mode 100644
index f031744cdbe8c27728eeed3356cc8bc030fcf9d5..0000000000000000000000000000000000000000
--- a/FWCore/src/components/PodioInput.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "PodioInput.h"
-
-#include "TFile.h"
-#include "TROOT.h"
-
-#include "FWCore/DataWrapper.h"
-#include "FWCore/PodioDataSvc.h"
-
-DECLARE_COMPONENT(PodioInput)
-
-PodioInput::PodioInput(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) {}
-
-StatusCode PodioInput::initialize() {
-  if (GaudiAlgorithm::initialize().isFailure()) return StatusCode::FAILURE;
-
-  // check whether we have the PodioEvtSvc active
-  m_podioDataSvc = dynamic_cast<PodioDataSvc*>(evtSvc().get());
-  if (nullptr == m_podioDataSvc) return StatusCode::FAILURE;
-
-  auto idTable = m_podioDataSvc->getCollectionIDs();
-  for (auto& name : m_collectionNames) {
-    debug() << "Finding collection " << name << " in collection registry." << endmsg;
-    if (!idTable->present(name)) {
-      error() << "Requested product " << name << " not found." << endmsg;
-      return StatusCode::FAILURE;
-    }
-    m_collectionIDs.push_back(idTable->collectionID(name));
-  }
-  return StatusCode::SUCCESS;
-}
-
-StatusCode PodioInput::execute() {
-  size_t cntr = 0;
-  // Re-create the collections from ROOT file
-  for (auto& id : m_collectionIDs) {
-    const std::string& collName = m_collectionNames.value().at(cntr++);
-    debug() << "Registering collection to read " << collName << " with id " << id << endmsg;
-    if (m_podioDataSvc->readCollection(collName, id).isFailure()) {
-      return StatusCode::FAILURE;
-    }
-  }
-  // Tell data service that we are done with requested collections
-  m_podioDataSvc->endOfRead();
-  return StatusCode::SUCCESS;
-}
-
-StatusCode PodioInput::finalize() {
-  if (GaudiAlgorithm::finalize().isFailure()) return StatusCode::FAILURE;
-  return StatusCode::SUCCESS;
-}
diff --git a/FWCore/src/components/PodioInput.h b/FWCore/src/components/PodioInput.h
deleted file mode 100644
index 0319d78f63a715edd5bd42d5e08823328ed759f2..0000000000000000000000000000000000000000
--- a/FWCore/src/components/PodioInput.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef FWCORE_PODIOINPUT_H
-#define FWCORE_PODIOINPUT_H
-// Gaaudi
-#include "GaudiAlg/GaudiAlgorithm.h"
-
-// STL
-#include <string>
-#include <vector>
-
-// forward declarations
-// from FWCore:
-class PodioDataSvc;
-
-/** @class PodioInput FWCore/components/PodioInput.h PodioInput.h
- *
- *  Class that allows to read ROOT files written with PodioOutput
- *
- *  @author J. Lingemann
- */
-
-class PodioInput : public GaudiAlgorithm {
-  friend class AlgFactory<PodioInput>;
-
-public:
-  /// Constructor.
-  PodioInput(const std::string& name, ISvcLocator* svcLoc);
-  /// Initialization of PodioInput. Acquires the data service, opens root file and creates trees.
-  virtual StatusCode initialize();
-  /// Execute. Re-creates collections that are specified to be read and sets references.
-  virtual StatusCode execute();
-  /// Finalize. Closes ROOT file.
-  virtual StatusCode finalize();
-
-private:
-  /// Name of collections to read. Set by option collections (this is temporary)
-  Gaudi::Property<std::vector<std::string>> m_collectionNames{this, "collections", {}, "Places of collections to read"};
-  /// Collection IDs (retrieved with CollectionIDTable from ROOT file, using collection names)
-  std::vector<int> m_collectionIDs;
-  /// Data service: needed to register objects and get collection IDs. Just an observing pointer.
-  PodioDataSvc* m_podioDataSvc;
-};
-
-#endif
diff --git a/FWCore/src/components/PodioOutput.cpp b/FWCore/src/components/PodioOutput.cpp
deleted file mode 100644
index 26e6e37f6c367ec2a494b01a5606c578678e5de3..0000000000000000000000000000000000000000
--- a/FWCore/src/components/PodioOutput.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-#include "PodioOutput.h"
-#include "GaudiKernel/IJobOptionsSvc.h"
-#include "FWCore/PodioDataSvc.h"
-#include "TFile.h"
-
-DECLARE_COMPONENT(PodioOutput)
-
-PodioOutput::PodioOutput(const std::string& name, ISvcLocator* svcLoc)
-    : GaudiAlgorithm(name, svcLoc), m_firstEvent(true) {}
-
-StatusCode PodioOutput::initialize() {
-  if (GaudiAlgorithm::initialize().isFailure()) return StatusCode::FAILURE;
-
-  // check whether we have the PodioEvtSvc active
-  m_podioDataSvc = dynamic_cast<PodioDataSvc*>(evtSvc().get());
-  if (0 == m_podioDataSvc) return StatusCode::FAILURE;
-
-  m_file = std::unique_ptr<TFile>(new TFile(m_filename.value().c_str(), "RECREATE", "data file"));
-  // Both trees are written to the ROOT file and owned by it
-  // PodioDataSvc has ownership of EventDataTree
-  m_datatree = m_podioDataSvc->eventDataTree();
-  m_metadatatree = new TTree("metadata", "Metadata tree");
-  m_switch = KeepDropSwitch(m_outputCommands);
-  return StatusCode::SUCCESS;
-}
-
-void PodioOutput::resetBranches(const std::vector<std::pair<std::string, podio::CollectionBase*>>& collections,
-                                bool prepare) {
-  for (auto& collNamePair : collections) {
-    auto collName = collNamePair.first;
-    if (m_switch.isOn(collName)) {
-      // Reconnect branches and collections
-      m_datatree->SetBranchAddress(collName.c_str(), collNamePair.second->getBufferAddress());
-      auto colls = collNamePair.second->referenceCollections();
-      if (colls != nullptr) {
-        int j = 0;
-        for (auto& c : (*colls)) {
-          m_datatree->SetBranchAddress((collName + "#" + std::to_string(j)).c_str(), &c);
-          ++j;
-        }
-      }
-      // vector members
-      auto vminfo = collNamePair.second->vectorMembers();
-      if ( vminfo != nullptr ) {
-        int j = 0;
-        for ( auto& c : (*vminfo) ) {
-          m_datatree->SetBranchAddress((collName+"_"+std::to_string(j)).c_str(), c.second);
-          ++j;
-        }
-      }
-    }
-    if (prepare) {
-      collNamePair.second->prepareForWrite();
-    }
-  }
-}
-
-void PodioOutput::createBranches(const std::vector<std::pair<std::string, podio::CollectionBase*>>& collections,
-                                 bool prepare) {
-  for (auto& collNamePair : collections) {
-    auto collName = collNamePair.first;
-    // TODO: we need the class name in a better way
-    std::string className(typeid(*(collNamePair.second)).name());
-    size_t pos = className.find_first_not_of("0123456789");
-    className.erase(0, pos);
-    // demangling the namespace: due to namespace additional characters were introduced:
-    // e.g. N3fcc18TrackHit
-    // remove any number+char before the namespace:
-    pos = className.find_first_of("0123456789");
-    size_t pos1 = className.find_first_not_of("0123456789", pos);
-    className.erase(0, pos1);
-    // replace any numbers between namespace and class with "::"
-    pos = className.find_first_of("0123456789");
-    pos1 = className.find_first_not_of("0123456789", pos);
-    className.replace(pos, pos1 - pos, "::");
-
-    pos = className.find("Collection");
-    className.erase(pos, pos + 10);
-    std::string collClassName = "vector<" + className + "Data>";
-    int isOn = 0;
-    if (m_switch.isOn(collName)) {
-      isOn = 1;
-      m_datatree->Branch(collName.c_str(), collClassName.c_str(), collNamePair.second->getBufferAddress());
-      // Create branches for collections holding relations
-      auto colls = collNamePair.second->referenceCollections();
-      if (colls != nullptr) {
-        int j = 0;
-        for (auto& c : (*colls)) {
-          m_datatree->Branch((collName + "#" + std::to_string(j)).c_str(), c);
-          ++j;
-        }
-      }
-      // vector members
-      auto vminfo = collNamePair.second->vectorMembers();
-      if ( vminfo != nullptr ) {
-        int j = 0;
-        for ( auto& c : (*vminfo) ) {
-          std::string typeName = "vector<" + c.first + ">";
-          void* add = c.second;
-          m_datatree->Branch((collName+"_"+std::to_string(j)).c_str(), typeName.c_str(), add);
-          ++j;
-        }
-      }
-    }
-    debug() << isOn << " Registering collection " << collClassName << " " << collName.c_str() << " containing type "
-            << className << endmsg;
-    if (prepare) {
-      collNamePair.second->prepareForWrite();
-    }
-  }
-}
-
-StatusCode PodioOutput::execute() {
-  // for now assume identical content for every event
-  // register for writing
-  if (m_firstEvent) {
-    createBranches(m_podioDataSvc->getCollections(), true);
-    createBranches(m_podioDataSvc->getReadCollections(), false);
-  } else {
-    resetBranches(m_podioDataSvc->getCollections(), true);
-    resetBranches(m_podioDataSvc->getReadCollections(), false);
-  }
-  m_firstEvent = false;
-  debug() << "Filling DataTree .." << endmsg;
-  m_datatree->Fill();
-  return StatusCode::SUCCESS;
-}
-
-StatusCode PodioOutput::finalize() {
-  if (GaudiAlgorithm::finalize().isFailure()) return StatusCode::FAILURE;
-  // retrieve the configuration of the job
-  // and write it to file as vector of strings
-  std::vector<std::string> config_data;
-  auto jobOptionsSvc = service<IJobOptionsSvc>("JobOptionsSvc");
-  auto configured_components = jobOptionsSvc->getClients();
-  for (const auto& name : configured_components) {
-      auto properties = jobOptionsSvc->getProperties(name);
-      std::stringstream config_stream;
-      for (const auto& property : *properties) {
-          config_stream << name << " : " << property->name() << " = " << property->toString() << std::endl;
-        }
-        config_data.push_back(config_stream.str());
-      }
-      m_metadatatree->Branch("gaudiConfigOptions", &config_data);
-      
-  m_metadatatree->Branch("CollectionIDs", m_podioDataSvc->getCollectionIDs());
-  m_metadatatree->Fill();
-  m_datatree->Write();
-  m_file->Write();
-  m_file->Close();
-  info() << "Data written to: " << m_filename << endmsg;
-  return StatusCode::SUCCESS;
-}
diff --git a/FWCore/src/components/PodioOutput.h b/FWCore/src/components/PodioOutput.h
deleted file mode 100644
index f1c93beabd1436202330011ffe741bcdfa5d2dab..0000000000000000000000000000000000000000
--- a/FWCore/src/components/PodioOutput.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef FWCORE_PODIOOUTPUT_H
-#define FWCORE_PODIOOUTPUT_H
-
-#include "FWCore/KeepDropSwitch.h"
-#include "GaudiAlg/GaudiAlgorithm.h"
-#include "podio/CollectionBase.h"
-
-#include "TTree.h"
-
-#include <vector>
-
-// forward declarations
-class TFile;
-class PodioDataSvc;
-
-class PodioOutput : public GaudiAlgorithm {
-  friend class AlgFactory<PodioOutput>;
-
-public:
-  /// Constructor.
-  PodioOutput(const std::string& name, ISvcLocator* svcLoc);
-
-  /// Initialization of PodioOutput. Acquires the data service, creates trees and root file.
-  virtual StatusCode initialize();
-  /// Execute. For the first event creates branches for all collections known to PodioDataSvc and prepares them for
-  /// writing. For the following events it reconnects the branches with collections and prepares them for write.
-  virtual StatusCode execute();
-  /// Finalize. Writes the meta data tree; writes file and cleans up all ROOT-pointers.
-  virtual StatusCode finalize();
-
-private:
-  void resetBranches(const std::vector<std::pair<std::string, podio::CollectionBase*>>& collections, bool prepare);
-  void createBranches(const std::vector<std::pair<std::string, podio::CollectionBase*>>& collections, bool prepare);
-  /// First event or not
-  bool m_firstEvent;
-  /// Root file name the output is written to
-  Gaudi::Property<std::string> m_filename{this, "filename", "output.root", "Name of the file to create"};
-  /// Commands which output is to be kept
-  Gaudi::Property<std::vector<std::string>> m_outputCommands{
-      this, "outputCommands", {"keep *"}, "A set of commands to declare which collections to keep or drop."};
-  /// Switch for keeping or dropping outputs
-  KeepDropSwitch m_switch;
-  /// Needed for collection ID table
-  PodioDataSvc* m_podioDataSvc;
-  /// The actual ROOT file
-  std::unique_ptr<TFile> m_file;
-  /// The tree to be filled with collections
-  TTree* m_datatree;
-  /// The tree to be filled with meta data
-  TTree* m_metadatatree;
-  /// The stored collections
-  std::vector<podio::CollectionBase*> m_storedCollections;
-};
-
-#endif
diff --git a/Generator/CMakeLists.txt b/Generator/CMakeLists.txt
index 16be6fa4eb3ab82774fb6376827d19d06d87759d..41f325ec59a21f336721425edae877e76a822e5b 100644
--- a/Generator/CMakeLists.txt
+++ b/Generator/CMakeLists.txt
@@ -21,8 +21,11 @@ include(${Geant4_USE_FILE})
 find_package(ROOT COMPONENTS RIO Tree TreePlayer MathCore Net Graf3d Graf Gpad EG REQUIRED)
 find_package(LCIO)
 find_package(podio)
-find_package(plcio)
+find_package(EDM4HEP)
 find_package(HepMC)
+find_package(CLHEP)
+find_package(K4FWCore REQUIRED)
+
 if(ROOT_FOUND)
     message("found ROOT: ${ROOT_INCLUDE_DIRS} ${ROOT_LIBRARIES}")
 endif(ROOT_FOUND)
@@ -32,35 +35,26 @@ endif(LCIO_FOUND)
 if(podio_FOUND)
     message("found podio: ${podio_INCLUDE_DIRS} ${podio_LIBRARIES}")
 endif(podio_FOUND)
-if(plcio_FOUND)
-    message("found plcio: ${plcio_INCLUDE_DIRS} ${plcio_LIBRARY_DIR}")
-endif(plcio_FOUND)
 if(HepMC_FOUND)
     message("found HepMC: ${HepMC_INCLUDE_DIRS} ${HepMC_LIBRARY_DIR}")
 endif(HepMC_FOUND)
+if(CLHEP_FOUND)
+    message("found CLHEP: ${CLHEP_INCLUDE_DIRS} ${CLHEP_LIBRARY_DIR}")
+endif(CLHEP_FOUND)
 ############## for producing plcio library #############
 INCLUDE_DIRECTORIES(${GenAlgo_incs})
 
 gaudi_add_module(GenAlgo ${GenAlgo_srcs} 
   INCLUDE_DIRS 
-    GaudiKernel
-    FWCore
-    Geant4
-    ${LCIO_INCLUDE_DIRS}
-    ${podio_INCLUDE_DIRS}
-    ${plcio_INCLUDE_DIRS}
-    ${ROOT_INCLUDE_DIRS}
-    HepMC
+    K4FWCore
   LINK_LIBRARIES 
-    GaudiKernel 
-    ${LCIO_LIBRARIES}
-    ${podio_LIBRARIES}
     ROOT
-    ${plcio_LIBRARY_DIR}/libplcio.so
-    ${plcio_LIBRARY_DIR}/libplcioDict.so
-    FWCore 
+    K4FWCore 
+    GaudiAlgLib GaudiKernel
     HepMC
-    Geant4
+    CLHEP
+    LCIO
+    EDM4HEP::edm4hep EDM4HEP::edm4hepDict
   )
 #gaudi_add_test(Reader FRAMEWORK options/read.py)
 
diff --git a/Generator/src/GenAlgo.cpp b/Generator/src/GenAlgo.cpp
index 74c2db30e0f75fc02bd2015b349ddade470c4f40..58f9d4e8b438085a5322e565f778506830e7ec14 100644
--- a/Generator/src/GenAlgo.cpp
+++ b/Generator/src/GenAlgo.cpp
@@ -5,7 +5,7 @@
 #include "GaudiKernel/GaudiException.h"
 
 
-#include "plcio/MCParticleCollection.h"//plico
+#include "edm4hep/MCParticleCollection.h"//plico
 
 #include <iostream>
 #include <vector>
diff --git a/Generator/src/GenAlgo.h b/Generator/src/GenAlgo.h
index 0fd060dc2a004a32f3ec0d27e9b50e8f42d163ad..47745aefec9c8ac7a90819bf88c9eecf91fc7ab8 100644
--- a/Generator/src/GenAlgo.h
+++ b/Generator/src/GenAlgo.h
@@ -21,7 +21,6 @@ using namespace std;
 
 class GenAlgo: public GaudiAlgorithm {
 
-    friend class AlgFactory<GenAlgo>;
 public:
     GenAlgo(const std::string& name, ISvcLocator* pSvcLocator);
 
@@ -43,7 +42,7 @@ private:
     int m_evtid;                               
     int m_evtMax;
     //MyHepMC::GenEvent m_event;
-    DataHandle<plcio::MCParticleCollection> m_hdl{"MCParticle", Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::MCParticleCollection> m_hdl{"MCParticle", Gaudi::DataHandle::Writer, this};
 
 
 };
diff --git a/Generator/src/GenEvent.cpp b/Generator/src/GenEvent.cpp
index 1cd5ccb3c6bcc02df464106e391b846a77bbd159..3e40c65b8476c83a48e98fc4b596e60d15bcab5f 100644
--- a/Generator/src/GenEvent.cpp
+++ b/Generator/src/GenEvent.cpp
@@ -1,12 +1,12 @@
 #include "GenEvent.h" 
-#include "plcio/MCParticleCollection.h"//plico
+#include "edm4hep/MCParticleCollection.h"//plico
 
 using namespace std;
 
 namespace MyHepMC{
 
 //GenEvent::GenEvent(){
-GenEvent::GenEvent(plcio::MCParticleCollection& mcCol)
+GenEvent::GenEvent(edm4hep::MCParticleCollection& mcCol)
     : m_mc_vec(mcCol){
 
     m_event_id=-1;
@@ -24,11 +24,11 @@ void GenEvent::SetEventHeader(long event_id_, long run_id_, float time_, string
     m_det_name = det_name_;
 }
 /*
-void GenEvent::SetMCCollection(plcio::MCParticleCollection vec_){
+void GenEvent::SetMCCollection(edm4hep::MCParticleCollection vec_){
 m_mc_vec = vec_;
 }
 */
-plcio::MCParticleCollection GenEvent::getMCVec(){
+edm4hep::MCParticleCollection GenEvent::getMCVec(){
 return m_mc_vec;
 }
 
diff --git a/Generator/src/GenEvent.h b/Generator/src/GenEvent.h
index dae1b3772d3044ad3434898ec1c216ab41493d57..72895413a5d06438fcffe72495ef56b646921c5c 100644
--- a/Generator/src/GenEvent.h
+++ b/Generator/src/GenEvent.h
@@ -1,25 +1,25 @@
 #ifndef GenEvent_h 
 #define GenEvent_h 1
 
-#include "plcio/MCParticleCollection.h"//plico
+#include "edm4hep/MCParticleCollection.h"//plico
 
 namespace MyHepMC {
 
 class GenEvent{
     public: 
         //GenEvent();
-        GenEvent(plcio::MCParticleCollection& mcCol);
+        GenEvent(edm4hep::MCParticleCollection& mcCol);
         ~GenEvent();
         void SetEventHeader(long event_id_, long run_id_, float time_, std::string det_name_);
-        //void SetMCCollection(plcio::MCParticleCollection vec_);
+        //void SetMCCollection(edm4hep::MCParticleCollection vec_);
         long getID();
         long getRun();
         long getTime();
         void ReSet();
         std::string getName();
-        plcio::MCParticleCollection getMCVec();
-        plcio::MCParticleCollection& m_mc_vec;
-        //plcio::MCParticleCollection m_mc_vec;
+        edm4hep::MCParticleCollection getMCVec();
+        edm4hep::MCParticleCollection& m_mc_vec;
+        //edm4hep::MCParticleCollection m_mc_vec;
     private:
         long m_event_id;
         long m_run_id;
diff --git a/Generator/src/GtGunTool.cpp b/Generator/src/GtGunTool.cpp
index a8f65da3863f1622f63997fef74ebc77c36c4a05..df29f4a2821f0324d574fc71e316bd05f3054447 100644
--- a/Generator/src/GtGunTool.cpp
+++ b/Generator/src/GtGunTool.cpp
@@ -15,11 +15,12 @@ GtGunTool::initialize() {
         error() << "Please specify the list of particle names/pdgs" << endmsg;
         return StatusCode::FAILURE;
     }
-    if (m_energies.value().size() != m_particles.value().size()) {
+    
+    if (m_energymins.value().size() != m_particles.value().size()) {
         error() << "Mismatched energies and particles." << endmsg;
         return StatusCode::FAILURE;
     }
-
+    
     // others should be empty or specify
     if (m_thetamins.value().size()
         && m_thetamins.value().size() != m_particles.value().size()) {
@@ -78,10 +79,10 @@ GtGunTool::mutate(MyHepMC::GenEvent& event) {
             }
         }
 
-        double energy = m_energies.value()[i];
+        double energy = m_energymins.value()[i]==m_energymaxs.value()[i] ? m_energymins.value()[i] : CLHEP::RandFlat::shoot(m_energymins.value()[i], m_energymaxs.value()[i]);
 
         // create the MC particle
-        plcio::MCParticle mcp = event.m_mc_vec.create();
+        edm4hep::MCParticle mcp = event.m_mc_vec.create();
         mcp.setPDG(pdgcode);
         mcp.setGeneratorStatus(1);
         mcp.setSimulatorStatus(1);
@@ -96,45 +97,16 @@ GtGunTool::mutate(MyHepMC::GenEvent& event) {
         
         // direction
         // by default, randomize the direction
-        double costheta = CLHEP::RandFlat::shoot(-1, 1);
-        double phi = 360*CLHEP::RandFlat::shoot()*CLHEP::degree;
+        double theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]);
+        double phi =   m_phimins  .value()[i]==m_phimaxs  .value()[i] ? m_phimins  .value()[i] : CLHEP::RandFlat::shoot(m_phimins  .value()[i], m_phimaxs  .value()[i]);
+        double costheta = cos(theta*acos(-1)/180);
+        double phi_  = phi*acos(-1)/180;
         double sintheta = sqrt(1.-costheta*costheta);
-
-        // check if theta min/max is set
-
-        if (i < m_thetamins.value().size() 
-            && i < m_thetamaxs.value().size()) {
-            double thetamin = m_thetamins.value()[i];
-            double thetamax = m_thetamaxs.value()[i];
-
-            if (thetamin == thetamax) { // fixed theta
-                costheta = cos(thetamin);
-                sintheta = sin(thetamin);
-                info() << "theta is fixed: " << thetamin << endmsg;
-            }
-        }
-
-        if (i < m_phimins.value().size()
-            && i < m_phimaxs.value().size()) {
-            double phimin = m_phimins.value()[i];
-            double phimax = m_phimaxs.value()[i];
-
-            if (phimin == phimax) { // fixed phi
-                phi = phimin;
-                info() << "phi is fixed: " << phimin << endmsg;
-            }
-        }
-
-        debug() << "Direction: "
-                << " cos(theta): " << costheta
-                << " phi: " << phi
-                << endmsg;
-        
-        double px = p*sintheta*cos(phi);
-        double py = p*sintheta*sin(phi);
+        double px = p*sintheta*cos(phi_);
+        double py = p*sintheta*sin(phi_);
         double pz = p*costheta;
-
-        mcp.setMomentum(plcio::FloatThree(px,py,pz));
+        std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<<theta<<",phi="<<phi<<std::endl;
+        mcp.setMomentum(edm4hep::Vector3f(px,py,pz));
         // mcp.setMomentumAtEndpoint();
         // mcp.setSpin();
         // mcp.setColorFlow();
diff --git a/Generator/src/GtGunTool.h b/Generator/src/GtGunTool.h
index 22b02a811a19be2ce5a16ca1cdd4726635a0be4b..388c14d4d555bc4d3b436ebc90fabdca26f22337 100644
--- a/Generator/src/GtGunTool.h
+++ b/Generator/src/GtGunTool.h
@@ -34,7 +34,8 @@ private:
 
     Gaudi::Property<std::vector<std::string>> m_particles{this, "Particles"};
 
-    Gaudi::Property<std::vector<double>> m_energies{this, "Energies"};
+    Gaudi::Property<std::vector<double>> m_energymins{this, "EnergyMins"};
+    Gaudi::Property<std::vector<double>> m_energymaxs{this, "EnergyMaxs"};
 
     Gaudi::Property<std::vector<double>> m_thetamins{this, "ThetaMins"};
     Gaudi::Property<std::vector<double>> m_thetamaxs{this, "ThetaMaxs"};
diff --git a/Generator/src/HepMCRdr.cpp b/Generator/src/HepMCRdr.cpp
index b8c81809efb2efb4e0e25a5f4d3a9f3f624fdc60..c4bfb60d738e0780c523fe2f46f6ab7282c3c0b6 100644
--- a/Generator/src/HepMCRdr.cpp
+++ b/Generator/src/HepMCRdr.cpp
@@ -7,12 +7,10 @@
 #include "HepMC/Polarization.h"
 
 
-#include "plcio/MCParticle.h" //plcio
-#include "plcio/MCParticleObj.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/DoubleThree.h"
-#include "plcio/FloatThree.h"
-#include "plcio/EventHeaderCollection.h"
+#include "edm4hep/MCParticle.h" //edm4hep
+#include "edm4hep/MCParticleObj.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
 
 
 
@@ -21,7 +19,7 @@
 #include <fstream>
 
 
-using namespace plcio;
+using namespace edm4hep;
 using namespace std;
 
 DECLARE_COMPONENT(HepMCRdr)
@@ -41,7 +39,7 @@ bool HepMCRdr::mutate(MyHepMC::GenEvent& event){
     int index = 0 ;
     for ( HepMC::GenEvent::particle_iterator p = evt->particles_begin(); p != evt->particles_end(); ++p ) {
         //std::cout<<"start mc "<<index<<std::endl;
-        plcio::MCParticle mcp = event.m_mc_vec.create();
+        edm4hep::MCParticle mcp = event.m_mc_vec.create();
         pmcid_lmcid.insert(std::pair<int, int>((*p)->barcode(),index));
         index++;
         //std::cout<<"map<id,i>:"<<mc->id()<<","<< i <<std::endl;
@@ -55,35 +53,35 @@ bool HepMCRdr::mutate(MyHepMC::GenEvent& event){
         if ( (*p)->production_vertex() ){
             HepMC::GenVertex* vertex_pro =  (*p)->production_vertex();
             double three[3] = {vertex_pro->point3d().x(), vertex_pro->point3d().y(), vertex_pro->point3d().z()};
-            mcp.setVertex             (plcio::DoubleThree (three)); 
+            mcp.setVertex             (edm4hep::Vector3d (three)); 
         }
-        else mcp.setVertex(plcio::DoubleThree()); 
+        else mcp.setVertex(edm4hep::Vector3d()); 
         if ( (*p)->end_vertex() ){
             HepMC::GenVertex* vertex_end =  (*p)->end_vertex();
             double three[3] = {vertex_end->point3d().x(), vertex_end->point3d().y(), vertex_end->point3d().z()};
-            mcp.setEndpoint           (plcio::DoubleThree (three));
+            mcp.setEndpoint           (edm4hep::Vector3d (three));
         } 
-        else mcp.setEndpoint (plcio::DoubleThree());
-        mcp.setMomentum           (plcio::FloatThree(float((*p)->momentum().px()), float((*p)->momentum().py()), float((*p)->momentum().pz()) ));
-        mcp.setMomentumAtEndpoint (plcio::FloatThree(float((*p)->momentum().px()), float((*p)->momentum().py()), float((*p)->momentum().pz()) ));
+        else mcp.setEndpoint (edm4hep::Vector3d());
+        mcp.setMomentum           (edm4hep::Vector3f(float((*p)->momentum().px()), float((*p)->momentum().py()), float((*p)->momentum().pz()) ));
+        mcp.setMomentumAtEndpoint (edm4hep::Vector3f(float((*p)->momentum().px()), float((*p)->momentum().py()), float((*p)->momentum().pz()) ));
         const HepMC::Polarization & polar = (*p)->polarization();
-        mcp.setSpin               (plcio::FloatThree(polar.normal3d().x(), polar.normal3d().y(), polar.normal3d().z()) );
+        mcp.setSpin               (edm4hep::Vector3f(polar.normal3d().x(), polar.normal3d().y(), polar.normal3d().z()) );
         int two[2] = {1, (*p)->flow(1)};
-        mcp.setColorFlow          (plcio::IntTwo (two) );
+        mcp.setColorFlow          (edm4hep::Vector2i (two) );
     }
     // second loop for setting parents and daughters
     index = 0 ;
     for ( HepMC::GenEvent::particle_iterator p = evt->particles_begin(); p != evt->particles_end(); ++p ) {
-        plcio::MCParticle pmc = event.m_mc_vec.at(index);
+        edm4hep::MCParticle pmc = event.m_mc_vec.at(index);
         index++;
         if ( (*p)->production_vertex() ) {
             for ( HepMC::GenVertex::particle_iterator mother = (*p)->production_vertex()-> particles_begin(HepMC::parents); mother != (*p)->production_vertex()-> particles_end(HepMC::parents); ++mother ) {
-                pmc.addParent( event.m_mc_vec.at( pmcid_lmcid.at((*mother)->barcode()) ) );
+                pmc.addToParents( event.m_mc_vec.at( pmcid_lmcid.at((*mother)->barcode()) ) );
             }
         }
         if ( (*p)->end_vertex() ) {
             for ( HepMC::GenVertex::particle_iterator des =(*p)->end_vertex()-> particles_begin(HepMC::descendants); des != (*p)->end_vertex()-> particles_end(HepMC::descendants); ++des ) {
-                pmc.addDaughter( event.m_mc_vec.at( pmcid_lmcid.at((*des)->barcode()) ) );
+                pmc.addToDaughters( event.m_mc_vec.at( pmcid_lmcid.at((*des)->barcode()) ) );
                 }
         }   
     }
diff --git a/Generator/src/SLCIORdr.cpp b/Generator/src/SLCIORdr.cpp
index 9db71153961d29ece2a4479d36bddfa8fb7dde98..2f0b940a339e0aa63a4a709220a4f0c56f2b0843 100644
--- a/Generator/src/SLCIORdr.cpp
+++ b/Generator/src/SLCIORdr.cpp
@@ -12,12 +12,10 @@
 #include "IMPL/LCCollectionVec.h"
 
 
-#include "plcio/MCParticle.h" //plcio
-#include "plcio/MCParticleObj.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/DoubleThree.h"
-#include "plcio/FloatThree.h"
-#include "plcio/EventHeaderCollection.h"
+#include "edm4hep/MCParticle.h" //edm4hep
+#include "edm4hep/MCParticleObj.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
 
 
 
@@ -28,7 +26,7 @@
 
 using namespace lcio;
 using namespace IMPL;
-using namespace plcio;
+using namespace edm4hep;
 using namespace std;
 
 DECLARE_COMPONENT(SLCIORdr)
@@ -75,7 +73,7 @@ bool SLCIORdr::mutate(MyHepMC::GenEvent& event){
 	    for(i=0;i<NHEP;i++){
 	      if(p==lcCol->getElementAt(i)) break;
 	    }
-	    if(i==NHEP) cout << "HepLCIOInterfaceNew: error" << endl;
+	    if(i==NHEP) cout << "Heedm4hepInterfaceNew: error" << endl;
 	    mcp->addParent(dynamic_cast<MCParticleImpl*>(lcMCVec->getElementAt(i)));
 	  }
 	  //ignore daughter table, auto-regonize relationship while addParent()
@@ -88,8 +86,8 @@ bool SLCIORdr::mutate(MyHepMC::GenEvent& event){
             for(i=0;i<NHEP;i++){
               if(d==lcCol->getElementAt(i)) break;
             }
-            if(i==NHEP) cout << "HepLCIOInterfaceNew: error" << endl;
-            mcp->addDaughter(dynamic_cast<MCParticleImpl*>(lcMCVec->getElementAt(i)));
+            if(i==NHEP) cout << "Heedm4hepInterfaceNew: error" << endl;
+            mcp->addToDaughters(dynamic_cast<MCParticleImpl*>(lcMCVec->getElementAt(i)));
           }
           */
           
@@ -108,7 +106,7 @@ bool SLCIORdr::mutate(MyHepMC::GenEvent& event){
     for (int i=0; i < n_mc; i++){
         MCParticleImpl* mc = (MCParticleImpl*) lcMCVec->getElementAt(i);
         //std::cout<<"At mc :"<< i <<std::endl;
-        plcio::MCParticle mcp = event.m_mc_vec.create();
+        edm4hep::MCParticle mcp = event.m_mc_vec.create();
         pmcid_lmcid.insert(std::pair<int, int>(mc->id(),i));
         //std::cout<<"map<id,i>:"<<mc->id()<<","<< i <<std::endl;
                                  
@@ -120,8 +118,8 @@ bool SLCIORdr::mutate(MyHepMC::GenEvent& event){
         mcp.setMass               (mc->getMass());
         mcp.setVertex             (mc->getVertex()); 
         mcp.setEndpoint           (mc->getEndpoint());
-        mcp.setMomentum           (FloatThree(float(mc->getMomentum()[0]), float(mc->getMomentum()[1]), float(mc->getMomentum()[2]) ));
-        mcp.setMomentumAtEndpoint (FloatThree(float(mc->getMomentumAtEndpoint()[0]), float(mc->getMomentumAtEndpoint()[1]), float(mc->getMomentumAtEndpoint()[2]) ));
+        mcp.setMomentum           (Vector3f(float(mc->getMomentum()[0]), float(mc->getMomentum()[1]), float(mc->getMomentum()[2]) ));
+        mcp.setMomentumAtEndpoint (Vector3f(float(mc->getMomentumAtEndpoint()[0]), float(mc->getMomentumAtEndpoint()[1]), float(mc->getMomentumAtEndpoint()[2]) ));
         mcp.setSpin               (mc->getSpin());
         mcp.setColorFlow          (mc->getColorFlow());
     }
@@ -131,16 +129,16 @@ bool SLCIORdr::mutate(MyHepMC::GenEvent& event){
         MCParticleImpl* mc = (MCParticleImpl*) lcMCVec->getElementAt(i);
         const MCParticleVec & mc_parents = mc->getParents();
         const MCParticleVec & mc_daughters = mc->getDaughters();
-        plcio::MCParticle pmc = event.m_mc_vec.at(i);
+        edm4hep::MCParticle pmc = event.m_mc_vec.at(i);
         //std::cout<<"mc at "<< i<<", parent size "<<mc_parents.size() <<std::endl;
         for(unsigned int j=0; j< mc_parents.size(); j++){int p_id = mc_parents.at(j)->id();
                                                  //std::cout<<"parent id "<<p_id<<std::endl;
-                                                 pmc.addParent( event.m_mc_vec.at( pmcid_lmcid.at(p_id) ) );
+                                                 pmc.addToParents( event.m_mc_vec.at( pmcid_lmcid.at(p_id) ) );
                                                 }
         //std::cout<<"mc at "<< i<<", daughter size "<<mc_daughters.size() <<std::endl;
         for(unsigned int j=0; j< mc_daughters.size(); j++){int d_id = mc_daughters.at(j)->id();
                                                  //std::cout<<"daughter id "<<d_id<<std::endl;
-                                                 pmc.addDaughter( event.m_mc_vec.at( pmcid_lmcid.at(d_id) ) );
+                                                 pmc.addToDaughters( event.m_mc_vec.at( pmcid_lmcid.at(d_id) ) );
                                                 }
     }
     event.SetEventHeader( m_processed_event, -99, 9999, "Generator");
diff --git a/Generator/src/StdHepRdr.cpp b/Generator/src/StdHepRdr.cpp
index b81abb0569a52df5a3674290d9f8a958f33aba35..09fa9ddc009f7be254dcd414154a726b7a4db0d1 100644
--- a/Generator/src/StdHepRdr.cpp
+++ b/Generator/src/StdHepRdr.cpp
@@ -7,12 +7,10 @@
 #include "IMPL/MCParticleImpl.h"
 
 
-#include "plcio/MCParticle.h" //plcio
-#include "plcio/MCParticleObj.h"
-#include "plcio/MCParticleCollection.h"
-#include "plcio/DoubleThree.h"
-#include "plcio/FloatThree.h"
-#include "plcio/EventHeaderCollection.h"
+#include "edm4hep/MCParticle.h" //edm4hep
+#include "edm4hep/MCParticleObj.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
 
 
 
@@ -23,7 +21,7 @@
 
 using namespace lcio;
 using namespace IMPL;
-using namespace plcio;
+using namespace edm4hep;
 using namespace std;
 
 DECLARE_COMPONENT(StdHepRdr)
@@ -42,7 +40,7 @@ bool StdHepRdr::mutate(MyHepMC::GenEvent& event){
     for (int i=0; i < n_mc; i++){
         MCParticleImpl* mc = (MCParticleImpl*) mc_vec->getElementAt(i);
         //std::cout<<"At mc :"<< i <<std::endl;
-        plcio::MCParticle mcp = event.m_mc_vec.create();
+        edm4hep::MCParticle mcp = event.m_mc_vec.create();
         pmcid_lmcid.insert(std::pair<int, int>(mc->id(),i));
         //std::cout<<"map<id,i>:"<<mc->id()<<","<< i <<std::endl;
                                  
@@ -54,8 +52,8 @@ bool StdHepRdr::mutate(MyHepMC::GenEvent& event){
         mcp.setMass               (mc->getMass());
         mcp.setVertex             (mc->getVertex()); 
         mcp.setEndpoint           (mc->getEndpoint());
-        mcp.setMomentum           (FloatThree(float(mc->getMomentum()[0]), float(mc->getMomentum()[1]), float(mc->getMomentum()[2]) ));
-        mcp.setMomentumAtEndpoint (FloatThree(float(mc->getMomentumAtEndpoint()[0]), float(mc->getMomentumAtEndpoint()[1]), float(mc->getMomentumAtEndpoint()[2]) ));
+        mcp.setMomentum           (Vector3f(float(mc->getMomentum()[0]), float(mc->getMomentum()[1]), float(mc->getMomentum()[2]) ));
+        mcp.setMomentumAtEndpoint (Vector3f(float(mc->getMomentumAtEndpoint()[0]), float(mc->getMomentumAtEndpoint()[1]), float(mc->getMomentumAtEndpoint()[2]) ));
         mcp.setSpin               (mc->getSpin());
         mcp.setColorFlow          (mc->getColorFlow());
     }
@@ -65,16 +63,16 @@ bool StdHepRdr::mutate(MyHepMC::GenEvent& event){
         MCParticleImpl* mc = (MCParticleImpl*) mc_vec->getElementAt(i);
         const MCParticleVec & mc_parents = mc->getParents();
         const MCParticleVec & mc_daughters = mc->getDaughters();
-        plcio::MCParticle pmc = event.m_mc_vec.at(i);
+        edm4hep::MCParticle pmc = event.m_mc_vec.at(i);
         //std::cout<<"mc at "<< i<<", parent size "<<mc_parents.size() <<std::endl;
         for(unsigned int j=0; j< mc_parents.size(); j++){int p_id = mc_parents.at(j)->id();
                                                  //std::cout<<"parent id "<<p_id<<std::endl;
-                                                 pmc.addParent( event.m_mc_vec.at( pmcid_lmcid.at(p_id) ) );
+                                                 pmc.addToParents( event.m_mc_vec.at( pmcid_lmcid.at(p_id) ) );
                                                 }
         //std::cout<<"mc at "<< i<<", daughter size "<<mc_daughters.size() <<std::endl;
         for(unsigned int j=0; j< mc_daughters.size(); j++){int d_id = mc_daughters.at(j)->id();
                                                  //std::cout<<"daughter id "<<d_id<<std::endl;
-                                                 pmc.addDaughter( event.m_mc_vec.at( pmcid_lmcid.at(d_id) ) );
+                                                 pmc.addToDaughters( event.m_mc_vec.at( pmcid_lmcid.at(d_id) ) );
                                                 }
     }
      
diff --git a/README.md b/README.md
index d8d717f5780d40b0c0a5d4ebad3b93d5c653d8d2..aacb61725ed65ad568174932febb2bc8b6af56c8 100644
--- a/README.md
+++ b/README.md
@@ -8,11 +8,12 @@ Please refer to https://github.com/HEP-FCC/FCCSW
 ## Quick start
 
 ```
-$ source /cvmfs/cepcsw.ihep.ac.cn/prototype/setup.sh
-$ git clone git@cepcgit.ihep.ac.cn:cepc-prototype/CEPCSW.git
+$ source /cvmfs/cepcsw.ihep.ac.cn/prototype/releases/externals/97.0.2/setup.sh
+$ git clone git@github.com:cepc/CEPCSW.git
 $ cd CEPCSW
+$ git checkout lcg97
 $ mkdir build && cd build
-$ cmake ..
+$ cmake .. -DHOST_BINARY_TAG=${BINARY_TAG}
 $ make
 $ ./run gaudirun.py '$EXAMPLESROOT/options/helloalg.py'
 ```
diff --git a/Reconstruction/Digi_Calo/CMakeLists.txt b/Reconstruction/Digi_Calo/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..507720ca40cd718c485744ef5e95e68c0c674bd8
--- /dev/null
+++ b/Reconstruction/Digi_Calo/CMakeLists.txt
@@ -0,0 +1,25 @@
+gaudi_subdir(Digi_Calo v0r0)
+
+find_package(DD4hep COMPONENTS DDG4 REQUIRED)
+find_package(EDM4HEP REQUIRED )
+message("EDM4HEP_INCLUDE_DIRS: ${EDM4HEP_INCLUDE_DIR}")
+message("EDM4HEP_LIB: ${EDM4HEP_LIBRARIES}")
+include_directories(${EDM4HEP_INCLUDE_DIR})
+
+find_package(CLHEP REQUIRED)
+find_package(podio REQUIRED )
+
+set(srcs
+    src/*.cpp
+)
+
+gaudi_depends_on_subdirs(
+    Detector/DetInterface
+)
+## Modules
+gaudi_add_module(Digi_Calo ${srcs}
+    INCLUDE_DIRS FWCore GaudiKernel GaudiAlgLib CLHEP DD4hep 
+    LINK_LIBRARIES FWCore GaudiKernel GaudiAlgLib CLHEP DD4hep ${DD4hep_COMPONENT_LIBRARIES} DDRec
+    -Wl,--no-as-needed 
+    EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+)
diff --git a/Reconstruction/Digi_Calo/src/CaloDigiAlg.cpp b/Reconstruction/Digi_Calo/src/CaloDigiAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..93e2fb35c0fa217382f588947fb6ce7db60d0f90
--- /dev/null
+++ b/Reconstruction/Digi_Calo/src/CaloDigiAlg.cpp
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#include "CaloDigiAlg.h"
+
+
+#include "edm4hep/SimCalorimeterHit.h"
+#include "edm4hep/CalorimeterHit.h"
+#include "edm4hep/Vector3f.h"
+
+#include "DD4hep/Detector.h"
+#include <DD4hep/Objects.h>
+
+
+#include <math.h>
+#include <cmath>
+#include <algorithm>
+
+DECLARE_COMPONENT( CaloDigiAlg )
+
+CaloDigiAlg::CaloDigiAlg(const std::string& name, ISvcLocator* svcLoc)
+  : GaudiAlgorithm(name, svcLoc),
+    _nEvt(0)
+{
+  
+  // Input collections
+  declareProperty("SimCaloHitCollection", r_SimCaloCol, "Handle of the Input SimCaloHit collection");
+  
+  // Output collections
+  declareProperty("CaloHitCollection", w_DigiCaloCol, "Handle of Digi CaloHit collection");
+  
+  declareProperty("CaloAssociationCollection", w_CaloAssociationCol, "Handle of CaloAssociation collection");
+   
+}
+
+StatusCode CaloDigiAlg::initialize()
+{
+
+  std::cout<<"CaloDigiAlg::m_scale="<<m_scale<<std::endl;
+  m_geosvc = service<IGeoSvc>("GeoSvc");
+  if ( !m_geosvc )  throw "CaloDigiAlg :Failed to find GeoSvc ...";
+  dd4hep::Detector* m_dd4hep = m_geosvc->lcdd();
+  if ( !m_dd4hep )  throw "CaloDigiAlg :Failed to get dd4hep::Detector ...";
+  m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep);
+  return GaudiAlgorithm::initialize();
+}
+
+StatusCode CaloDigiAlg::execute()
+{
+  std::map<unsigned long long, edm4hep::SimCalorimeterHit> id_hit_map;
+  std::map<unsigned long long, std::vector<edm4hep::SimCalorimeterHit> > id_hits_map;
+  edm4hep::CalorimeterHitCollection* caloVec   = w_DigiCaloCol.createAndPut();
+  edm4hep::MCRecoCaloAssociationCollection* caloAssoVec   = w_CaloAssociationCol.createAndPut();
+  const edm4hep::SimCalorimeterHitCollection* SimHitCol =  r_SimCaloCol.get();
+  double tot_e = 0 ;
+  if(SimHitCol == 0) 
+  {
+     std::cout<<"not found SimCalorimeterHitCollection"<< std::endl;
+     return StatusCode::SUCCESS;
+  }
+  std::cout<<"digi, input sim hit size="<< SimHitCol->size() <<std::endl;
+  for( int i = 0; i < SimHitCol->size(); i++ ) 
+  {
+      edm4hep::SimCalorimeterHit SimHit = SimHitCol->at(i);
+      unsigned long long id = SimHit.getCellID();
+      float en = SimHit.getEnergy();
+      tot_e += en;
+      if ( id_hit_map.find(id) != id_hit_map.end()) id_hit_map[id].setEnergy(id_hit_map[id].getEnergy() + en);
+      else id_hit_map[id] = SimHit ;
+
+      if ( id_hits_map.find(id) != id_hits_map.end()) id_hits_map[id].push_back(SimHit);
+      else 
+      {
+          std::vector<edm4hep::SimCalorimeterHit> vhit;
+          vhit.push_back(SimHit);
+          id_hits_map[id] = vhit ;
+      }
+  }
+  for(std::map<unsigned long long, edm4hep::SimCalorimeterHit>::iterator iter = id_hit_map.begin(); iter != id_hit_map.end(); iter++)
+  {
+    auto caloHit = caloVec->create();
+    caloHit.setCellID((iter->second).getCellID());
+    caloHit.setEnergy((iter->second).getEnergy()*m_scale);
+    dd4hep::Position position = m_cellIDConverter->position(caloHit.getCellID());
+    edm4hep::Vector3f vpos(position.x()*10, position.y()*10, position.z()*10);// cm to mm
+    caloHit.setPosition(vpos);
+    //std::cout << "sim hit id =" << caloHit.getCellID() <<",x="<<position.x()<<",y="<<position.y()<<",z="<<position.z() <<",real x="<<(iter->second).getPosition().x <<",y="<<(iter->second).getPosition().y<<",z="<<(iter->second).getPosition().z<< std::endl;
+    
+    if( id_hits_map.find(iter->first) != id_hits_map.end()) 
+    {
+        for(unsigned int i=0; i< id_hits_map[iter->first].size(); i++)
+        {
+            auto asso = caloAssoVec->create();
+            asso.setRec(caloHit);
+            asso.setSim(id_hits_map[iter->first].at(i));
+            asso.setWeight(id_hits_map[iter->first].at(i).getEnergy()/(iter->second).getEnergy());
+        }
+    }
+    else std::cout<<"Error in Digi Calo"<<std::endl;
+  }
+    
+  std::cout<<"total sim e ="<< tot_e <<std::endl;
+  std::cout<<"digi, output digi hit size="<< caloVec->size() <<std::endl;
+  std::cout<<"digi, output caloAssoVec hit size="<< caloAssoVec->size() <<std::endl;
+  _nEvt ++ ;
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode CaloDigiAlg::finalize()
+{
+  info() << "Processed " << _nEvt << " events " << endmsg;
+  return GaudiAlgorithm::finalize();
+}
diff --git a/Reconstruction/Digi_Calo/src/CaloDigiAlg.h b/Reconstruction/Digi_Calo/src/CaloDigiAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1a82c8867450cf7335dce74d4743d0e7e9b374e
--- /dev/null
+++ b/Reconstruction/Digi_Calo/src/CaloDigiAlg.h
@@ -0,0 +1,58 @@
+#ifndef Calo_DIGI_ALG_H
+#define Calo_DIGI_ALG_H
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include "edm4hep/SimCalorimeterHitConst.h"
+#include "edm4hep/SimCalorimeterHit.h"
+#include "edm4hep/CalorimeterHit.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/SimCalorimeterHitCollection.h"
+#include "edm4hep/MCRecoCaloAssociationCollection.h"
+
+#include <DDRec/DetectorData.h>
+#include <DDRec/CellIDPositionConverter.h>
+#include "DetInterface/IGeoSvc.h"
+
+
+
+
+class CaloDigiAlg : public GaudiAlgorithm
+{
+ 
+public:
+ 
+  CaloDigiAlg(const std::string& name, ISvcLocator* svcLoc);
+ 
+  /** Called at the begin of the job before anything is read.
+   * Use to initialize the processor, e.g. book histograms.
+   */
+  virtual StatusCode initialize() ;
+ 
+  /** Called for every event - the working horse.
+   */
+  virtual StatusCode execute() ; 
+ 
+  /** Called after data processing for clean up.
+   */
+  virtual StatusCode finalize() ;
+ 
+protected:
+
+  SmartIF<IGeoSvc> m_geosvc;
+  typedef std::vector<float> FloatVec;
+
+  int _nEvt ;
+  float m_length;
+  dd4hep::rec::CellIDPositionConverter* m_cellIDConverter;
+ 
+  Gaudi::Property<float> m_scale{ this, "Scale", 1 };
+
+  // Input collections
+  DataHandle<edm4hep::SimCalorimeterHitCollection> r_SimCaloCol{"SimCaloCol", Gaudi::DataHandle::Reader, this};
+  // Output collections
+  DataHandle<edm4hep::CalorimeterHitCollection>    w_DigiCaloCol{"DigiCaloCol", Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::MCRecoCaloAssociationCollection>    w_CaloAssociationCol{"MCRecoCaloAssociationCollection", Gaudi::DataHandle::Writer, this};
+};
+
+#endif
diff --git a/Reconstruction/Digitisers/CMakeLists.txt b/Reconstruction/Digitisers/CMakeLists.txt
index b025fbcb4e2423afe6e98b1137e0086fa1b53808..56952b161a470fb392408a69fa0e50f740258e6b 100644
--- a/Reconstruction/Digitisers/CMakeLists.txt
+++ b/Reconstruction/Digitisers/CMakeLists.txt
@@ -4,18 +4,20 @@ find_package(CLHEP REQUIRED)
 find_package(GEAR REQUIRED)
 find_package(GSL REQUIRED ) 
 find_package(LCIO REQUIRED ) 
+find_package(podio REQUIRED ) 
+find_package(K4FWCore REQUIRED)
 
 gaudi_depends_on_subdirs(
     Service/GearSvc
     Service/EventSeeder
 )
 
-set(Digitisers_srcs
-    src/*.cpp
-)
+# set(Digitisers_srcs
+#     src/*.cpp
+# )
 
-# Modules
-gaudi_add_module(Digitisers ${Digitisers_srcs}
-    INCLUDE_DIRS GaudiKernel FWCore CLHEP gear ${plcio_INCLUDE_DIRS} ${GSL_INCLUDE_DIRS} ${LCIO_INCLUDE_DIRS}
-    LINK_LIBRARIES GaudiKernel FWCore CLHEP $ENV{GEAR}/lib/libgearsurf.so ${GSL_LIBRARIES} $ENV{PLCIO}/lib/libplcio.so ${LCIO_LIBRARIES}
-)
+# # Modules
+# gaudi_add_module(Digitisers ${Digitisers_srcs}
+#     INCLUDE_DIRS K4FWCore GaudiKernel GaudiAlgLib CLHEP gear ${plcio_INCLUDE_DIRS} ${GSL_INCLUDE_DIRS} ${LCIO_INCLUDE_DIRS}
+#     LINK_LIBRARIES K4FWCore GaudiKernel GaudiAlgLib CLHEP $ENV{GEAR}/lib/libgearsurf.so ${GSL_LIBRARIES} $ENV{PLCIO}/lib/libplcio.so ${LCIO_LIBRARIES}
+# )
diff --git a/Reconstruction/Digitisers/src/PlanarDigiAlg.h b/Reconstruction/Digitisers/src/PlanarDigiAlg.h
index 30386b64b84d2a8b09acc7b78299afceb11951cd..0b7b12b7d59a5b3ac089a4eb28a00089b2046d3c 100644
--- a/Reconstruction/Digitisers/src/PlanarDigiAlg.h
+++ b/Reconstruction/Digitisers/src/PlanarDigiAlg.h
@@ -44,7 +44,6 @@ class IEventSeeder;
 
 class PlanarDigiAlg : public GaudiAlgorithm
 {
-  friend class AlgFactory<PlanarDigiAlg>;
  
 public:
  
diff --git a/Reconstruction/PFA/Pandora/CED/.cepcenv/01-09-01/status/install.yml b/Reconstruction/PFA/Pandora/CED/.cepcenv/01-09-01/status/install.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9f2056abf76bd61b3cbb656e013a5088e599ab26
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/.cepcenv/01-09-01/status/install.yml
@@ -0,0 +1,20 @@
+clean:
+  end: 2018-09-04 10:38:21.535016
+  finished: true
+  start: 2018-09-04 10:38:21.503623
+compile:
+  end: 2018-09-04 10:38:21.449716
+  finished: true
+  start: 2018-09-04 10:38:07.382890
+download:
+  end: 2018-09-04 10:35:56.326883
+  finished: true
+  start: 2018-09-04 10:35:55.941740
+extract:
+  end: 2018-09-04 10:35:56.510664
+  finished: true
+  start: 2018-09-04 10:35:56.368258
+pre_compile:
+  end: 2018-09-04 10:37:33.127719
+  finished: true
+  start: 2018-09-04 10:37:33.110630
diff --git a/Reconstruction/PFA/Pandora/CED/CED/ced.cc b/Reconstruction/PFA/Pandora/CED/CED/ced.cc
new file mode 100644
index 0000000000000000000000000000000000000000..654444652e75bb0c8c5737b6787b4e0481055d67
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/CED/ced.cc
@@ -0,0 +1,382 @@
+/* "C" event display.
+ * Communications related part. 
+ *
+*ik
+ * Alexey Zhelezov, DESY/ITEP, 2005 */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <ced.h>
+
+//hauke
+//#include <stropts.h>
+#include <poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <sys/socket.h> /* for AF_INET */
+#include <iostream>
+
+
+//http://www.rhyolite.com/pipermail/dcc/2004/001986.html
+#ifndef POLLRDNORM //fg: should be defined in poll.h
+# define POLLRDNORM     0x040           /* Normal data may be read.  */
+# define POLLRDBAND     0x080           /* Priority data may be read.  */
+# define POLLWRNORM     0x100           /* Writing now will not block.  */
+# define POLLWRBAND     0x200           /* Priority data may be written.  */
+#endif
+//end hauke
+
+static int ced_fd=-1; // CED connection socket
+
+static unsigned short ced_port=7927; // port No of CED (assume localhost)
+static char ced_host[30];
+
+// Return 0 if can be connected, -1 otherwise.
+/*static*/ int ced_connect(void){
+  static time_t last_attempt=0;
+  time_t ct;
+  struct sockaddr_in addr;
+
+  if(ced_fd>=0){
+    return 0; // already connected;
+  }
+  time(&ct);
+  if(ct-last_attempt<5){
+    return -1; // don't try reconnect all the time
+  }
+  addr.sin_family=AF_INET;
+  addr.sin_port=htons(ced_port);
+  addr.sin_addr.s_addr=inet_addr(ced_host); 
+  memset(&addr.sin_zero, 0, sizeof(addr.sin_zero)); //not nessesary because sin_zero is not used!
+
+  ced_fd=socket(PF_INET,SOCK_STREAM,0);
+  if(connect(ced_fd,(struct sockaddr *)&addr,sizeof(addr)) != 0){
+    if(!last_attempt){
+        perror("WARNING:CED: can't connect to CED");
+    }
+    time(&last_attempt);
+    close(ced_fd);
+    ced_fd=-1;
+    return -1;
+  }
+  fprintf(stderr,"INFO:CED: connected to CED\n");
+  return 0;
+}
+
+
+typedef struct {
+  unsigned size;            // size of one item in bytes
+  unsigned char *b;         // "body" - data are stored here
+                            // (here is some trick :)
+  unsigned long count;      // number of usefull items
+  unsigned long alloced;    // number of allocated items
+  ced_draw_cb draw;         // draw fucation, NOT used in CED client
+} ced_element;
+
+typedef struct {
+  ced_element *e;
+  unsigned      e_count;
+} ced_event;
+
+//static ced_event eve = {0,0};
+
+static ced_event eve = {0,0};
+
+// NOT used in CED client
+static ced_event ceve = {0,0}; // current event on screen
+
+// we reserve this size just before ced_element.b data
+#define HDR_SIZE 8 
+
+unsigned ced_register_element(unsigned item_size,ced_draw_cb draw_func){
+  ced_element *pe;
+  if(!(eve.e_count&0xf)){
+    eve.e=(ced_element *) realloc(eve.e,(eve.e_count+0x10)*sizeof(ced_element));
+  }
+
+  pe=eve.e+eve.e_count;
+  memset(pe,0,sizeof(*pe));
+  pe->size=item_size;
+  pe->draw=draw_func;
+  return eve.e_count++;
+}
+
+static void ced_reset(void){
+  unsigned i;
+  
+  for(i=0;i<eve.e_count;i++){
+    eve.e[i].count=0;
+   // if( eve.e[i].alloced > 0){
+   //     eve.e[i].alloced=0; //hauke: 15.12.11
+   //     //free(eve.e[i].b-HDR_SIZE);
+   // }
+  }
+}
+
+static void ced_buf_alloc(ced_element *pe,unsigned count){
+  if(!pe->b){
+
+    //std::cout << "malloc  requestet: " << count*pe->size+HDR_SIZE << "bytes" << std::endl;
+    pe->b=(unsigned char *) malloc(count*pe->size+HDR_SIZE);
+    //printf("malloc: ask for NEW %lu bytes pointer: %p\n ", count*pe->size+HDR_SIZE, pe->b); //hauke
+    if(pe->b==NULL){ //hauke
+        printf("ERROR: malloc failed!\n");
+        exit(1);
+    }
+  }else{
+    //free(pe->b-HDR_SIZE);
+    //pe->b=(unsigned char *) malloc(count*pe->size+HDR_SIZE);
+
+    //std::cout << "realloc requestet: " << count*pe->size+HDR_SIZE << "bytes" << std::endl;
+    pe->b=(unsigned char *) realloc(pe->b-HDR_SIZE,count*pe->size+HDR_SIZE);
+
+    //printf("malloc: ask for %lu bytes, pointer: %p\n", count*pe->size+HDR_SIZE,pe->b);//hauke
+    if(pe->b==NULL){ //hauke
+        printf("ERROR: malloc failed!\n");
+        exit(1);
+    }
+  }
+  pe->b+=HDR_SIZE;
+  pe->alloced=count;
+}
+
+void *ced_add(unsigned id){
+  ced_element *pe;
+  if(id >= eve.e_count){
+    fprintf(stderr,"BUG:CED: attempt to access not registered element\n");
+    return 0;
+  }
+  pe=eve.e+id;
+
+  if(pe->count==pe->alloced){
+    ced_buf_alloc(pe,pe->alloced+256);
+  }
+
+  return (pe->b+(pe->count++)*pe->size);
+}
+
+static void ced_event_copy(ced_event *trg){
+  unsigned i;
+  ced_element *pe;
+  //std::cout << "trg->e_count: " << trg->e_count << std::endl;
+  //std::cout << "eve.e_count: " << eve.e_count << std::endl;
+
+  //eve.e_count = 0;
+  if(trg->e_count<eve.e_count){
+    //free(trg->e);
+    trg->e=(ced_element*) realloc(trg->e,eve.e_count*sizeof(ced_element));
+
+    //trg->e=(ced_element*) malloc(eve.e_count*sizeof(ced_element));
+  }
+
+
+  for(i=0;i<eve.e_count;i++){
+        pe=trg->e+i;
+        if(i<trg->e_count){
+            //if(pe->alloced > 0){
+            //  free(pe->b);
+            //  pe->b=NULL;
+            //  pe->alloced=0;
+            //}
+
+
+            //if(pe->alloced > 0){
+            //    std::cout << "try to free" << std::endl;
+            //    free(pe->b-HDR_SIZE);
+            //    pe->alloced = 0;
+            //    std::cout << "finished" << std::endl;
+            //}
+
+            if(pe->alloced<eve.e[i].alloced) {
+	          ced_buf_alloc(pe,eve.e[i].alloced);
+                //std::cout << "test1 " << std::endl;
+            }
+            pe->count=eve.e[i].count;
+
+        }else{
+            memcpy(pe,eve.e+i,sizeof(ced_element));
+            if(pe->b){
+	              pe->b=0;
+                  //  std::cout << "test2 " << std::endl;
+	              ced_buf_alloc(pe,pe->alloced);
+            }
+        }
+        if(pe->count){
+            memcpy(pe->b,eve.e[i].b,pe->count*pe->size);
+        }
+  }
+  trg->e_count=eve.e_count;
+}
+
+void ced_do_draw_event(void){
+  unsigned int i,j;
+  ced_element *pe;
+  unsigned char *pdata;
+  for(i=0;i<ceve.e_count;i++){
+    //printf("ceve.e_count: %i\n", ceve.e_count);
+    //for(i=ceve.e_count-1; i >=0;i--){ //quick hack, change order so that the detector is drawn at last
+    //printf("i = %i\n", i);
+
+    pe=ceve.e+i;
+    if(!pe->draw)
+      continue;
+    for(pdata=pe->b,j=0;j<pe->count;j++,pdata+=pe->size)
+      (*(pe->draw))(pdata);
+  }
+}
+
+typedef enum {
+  DRAW_EVENT=10000
+} MSG_TYPE;
+
+int ced_process_input(void *data){
+  struct _phdr{
+    unsigned size;
+    unsigned type;
+    unsigned char b[4];
+  } *hdr = (_phdr*) data;
+  unsigned count;
+  ced_element *pe;
+  
+  if(!data){ // new client is connected
+    ced_reset();
+    return 0;
+  }
+
+  if(hdr->type == DRAW_EVENT){
+    ced_event_copy(&ceve);
+    ced_reset();
+    return 1;
+  }
+  if(hdr->type>=eve.e_count){
+    fprintf(stderr,"WARNING:CED: undefined element type (%u), ignored\n",
+	    hdr->type);
+    return 0;
+  }
+  pe=eve.e+hdr->type;
+  if((hdr->size-HDR_SIZE)%pe->size){
+    fprintf(stderr,"BUG:CED: size alignment is wrong for element %u\n", hdr->type);
+    return 0;
+  }
+  count=(hdr->size-HDR_SIZE)/pe->size;
+  if(!count)
+    return 0;
+  if(count>=pe->alloced)
+    ced_buf_alloc(pe,count+256);
+  memcpy(pe->b,hdr->b,count*pe->size);
+  pe->count=count;
+  return 0;
+}
+
+void ced_send_event(void){
+  struct _phdr{
+    int size;
+    unsigned type;
+  } *hdr,draw_hdr;
+  unsigned i,problem=0;
+  int sent_sum;
+  char *buf;
+  int sent;
+  ced_element *pe;
+
+  if(ced_connect())
+    return;
+  for(i=0;i<eve.e_count && !problem;i++){
+    //printf("i=%i\n",i);
+    pe=eve.e+i;
+    if(!pe->count)
+      continue;
+    
+    //unsigned hauke;
+    //printf("size of unsigned %i\n", sizeof(hauke));
+    hdr=(struct _phdr *)(pe->b-HDR_SIZE); // !!! HERE is the trick :)
+    hdr->type=i;
+    //printf("pe->count %i, pe->size %i\n",pe->count, pe->size);
+    hdr->size=HDR_SIZE+pe->count*pe->size;
+    sent_sum=0;
+    //if(hdr->size > 10000000){printf("U P S!  This data set is realy big! (%f kB)(%i counts)\n",(hdr->size)/1024.0,pe->count);}
+    buf=(char *)hdr;
+    //printf("hdr->size=%i\n",hdr->size);
+    while(sent_sum<hdr->size){
+        //printf("sent_sum = %i, hdr->size=%i\n",sent_sum,hdr->size);
+	    sent=write(ced_fd,buf+sent_sum,hdr->size-sent_sum);
+        
+        //printf("byte: %u\n", buf[sent_sum]);
+	    if(sent<0){
+            printf("send < 0\n");
+	        problem=1;
+	        break;
+	    }
+	    sent_sum+=sent;
+    }
+  }
+  if(!problem){
+    draw_hdr.size=HDR_SIZE;
+    draw_hdr.type=DRAW_EVENT;
+    if(write(ced_fd,&draw_hdr,HDR_SIZE)!=HDR_SIZE)
+      problem=1;
+  }
+  if(problem){
+    perror("WARNING:CED: can't send event, till next time...");
+    close(ced_fd);
+    ced_fd=-1;
+  }
+}
+
+
+//hauke
+int ced_selected_id_noblock() {
+  int id=-1 ;
+  struct pollfd fds[1];
+  fds[0].fd=ced_fd;
+  fds[0].events = POLLRDNORM | POLLIN;
+  if(poll(fds,1,0) > 0){
+    if(recv(ced_fd, &id, sizeof(int) , 0 ) > 0){
+        return id;
+    }else{
+        return -1;
+    }
+  }else{
+   return -1;
+  }
+}
+
+int ced_selected_id() {
+  int id=-1 ;
+  if(recv(ced_fd, &id, sizeof(int) , 0 ) > 0){
+     return id;
+  }else{
+     return -1;
+  }
+}
+#include <signal.h>
+// API
+void ced_client_init(const char *hostname,unsigned short port){
+  struct hostent *host = gethostbyname(hostname);
+  snprintf(ced_host, 30, "%u.%u.%u.%u\n",(unsigned char)host->h_addr[0] ,(unsigned char)host->h_addr[1] ,(unsigned char)host->h_addr[2] ,(unsigned char)host->h_addr[3]); 
+
+
+  //printf("ip: %s\n",  ced_host);
+  //ced_host=host->h_addr;
+  ced_port=port;
+  signal(SIGPIPE,SIG_IGN);
+}
+
+void ced_new_event(void){
+  ced_reset();
+}
+
+void ced_draw_event(void){
+  ced_send_event();
+  ced_reset();
+}
diff --git a/Reconstruction/PFA/Pandora/CED/CED/ced.h b/Reconstruction/PFA/Pandora/CED/CED/ced.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccf355c27378db6a22b0bd473aad5b2f2aecb38b
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/CED/ced.h
@@ -0,0 +1,146 @@
+/* "C" event display.
+ * Main part. 
+ *
+ * Alexey Zhelezov, DESY/ITEP, 2005 */
+
+/*
+ * This file is internal. It must not be
+ * included into enduser application.
+ */
+
+#ifndef __CED_H
+#define __CED_H
+
+#include "ced_cli.h"
+
+//#ifdef __cplusplus
+// extern "C" {
+//#endif
+		
+
+//char trusted_hosts[50];
+//extern static char testchar;
+
+typedef void (*ced_draw_cb)(void *data);
+
+
+/*
+ * Register new element type. Order is important!
+ * Appropriate code must be defined in both
+ * client and server parts.
+ *
+ *  item_size - size of one item in bytes.
+ *  draw_func - function to call to draw one item,
+ *              called from ced_do_draw_event()
+ *              not used on client side.
+ */
+unsigned ced_register_element(unsigned item_size,ced_draw_cb draw_func);
+
+/*
+ * To be called from element functions
+ * on client side.
+ * Return allocated space for one item
+ * with size, specified by ced_register_element()
+ *
+ * Example: assume struct Dummy { int i; }; is item.
+ *
+ *          DummyID=ced_register_element(sizeof(struct Dummy),0);
+ *          ...
+ *          struct Dummy *item=(struct Dummy *)ced_add_element(DummyID);
+ *            item->i=0;
+ * This will add one Dummy item to the event
+ */
+void *ced_add(unsigned id);
+
+/*
+ * To be called in paint function
+ *
+ * It calls user defined functions for
+ * each item of all elements types.
+ */
+void ced_do_draw_event(void);
+
+/*
+ * Server side function.
+ * Must be used to process all incoming
+ * messages from client.
+ *
+ * It return positive value when
+ * new event must be drawn.
+ *
+ * Example:
+ *      glut_tcp_server(7285,my_process_input)
+ *
+ *      my_process_input(x){
+ *        if(ced_process_input(x)>0)
+ *          <do redraw>
+ */
+int ced_process_input(void *data);
+
+//------------
+void addLayerDescriptionToMenu(int,char *);//glced.c
+void selectFromMenu(int id);//glced.c
+void toggleHelpWindow(void);//glced.c
+void updateLayerEntryInPopupMenu(int); //glced.c
+int buildMenuPopup(void);//glced.c
+
+
+#define VERSION_CONFIG 3
+struct CEDsettings{
+    bool trans;         //grid or surface view
+    bool persp;         //perspectivic view or flat projection 
+    bool antia;         //anti aliasing
+    bool light;         //light source 
+    bool picking_highlight; //marker at picking position
+    double detector_trans[NUMBER_DETECTOR_LAYER];
+    double detector_cut_angle[NUMBER_DETECTOR_LAYER];
+    double detector_cut_z[NUMBER_DETECTOR_LAYER];
+    bool detector_picking;
+//    double cut_angle; //deprecated
+//    double trans_value; //deprecated
+//    double z_cutting; //deprecated
+    bool layer[CED_MAX_LAYER];
+    bool phi_projection;
+    bool z_projection;
+    double view[3];
+    double va; //vertical angle of view
+    double ha; //horionzional angle of view
+    bool fixed_view;
+    int win_h; //height of the window (pixel)
+    int win_w; //wight of the window (pixel)
+    double zoom;
+    double fisheye_alpha;
+    double world_size;
+    double fisheye_world_size;
+    double bgcolor[4];
+    bool show_axes;
+    bool fps;
+    double screenshot_sections;
+    int font; //size of text (menu, shortcuts, text in ced window)
+    bool autoshot; // If true, generate screencapture in every new event
+    int autoshot_scale; // If true, generate screencapture in every new event
+};
+
+/*
+//important: 
+//          - sum of all layers must be smaler than max_layer!
+//          - number_popup_layer must be smaler than number_data_layer
+
+#define CED_MAX_LAYER       100 
+#define NUMBER_POPUP_LAYER      20
+#define NUMBER_DATA_LAYER       25
+#define NUMBER_DETECTOR_LAYER   20
+
+
+#define CED_MAX_LAYER_CHAR 400
+*/
+
+//-------------
+
+//#ifdef __cplusplus
+// }
+//#endif
+
+	
+
+#endif /* __CED_H  */
diff --git a/Reconstruction/PFA/Pandora/CED/CED/ced_cli.cc b/Reconstruction/PFA/Pandora/CED/CED/ced_cli.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8c063e12483823a54b7920d92057a2331a5d56e3
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/CED/ced_cli.cc
@@ -0,0 +1,539 @@
+/* "C" event display.
+ * Client side elements definitions.
+ *
+ * Alexey Zhelezov, DESY/ITEP, 2005 */
+#include <string.h>
+
+#include <ced_cli.h>
+#include <ced.h>
+#include <stdio.h>
+//#include <iostream>
+
+#include <math.h>
+
+
+/*
+ * Hit element
+ */
+
+static unsigned HIT_ID=0;
+
+void ced_hit(float x,float y,float z,unsigned type,unsigned size,unsigned color){
+  ced_hit_ID(x,y,z, type & 0xFF,( type >> CED_LAYER_SHIFT ) & 0xFF, size,color, 0);
+}
+
+//deprecated
+void ced_hit_ID_old(float x,float y,float z,unsigned type, unsigned size,unsigned color, unsigned lcioID){
+  ced_hit_ID(x,y,z,type & 0xFF,(type >> CED_LAYER_SHIFT) & 0xFF,size,color,lcioID);
+}
+
+void ced_hit_ID(float x,float y,float z,unsigned type,unsigned layer, unsigned size,unsigned color, unsigned lcioID){
+ CED_Hit *h=(CED_Hit *)ced_add(HIT_ID);
+ if(!h)
+   return;
+ h->p.x=x;
+ h->p.y=y;
+ h->p.z=z;
+ h->type=type;
+ // if(layer > 255){ //downward compability
+ //    h->layer=layer >> CED_LAYER_SHIFT;
+ // }else{
+ h->layer=layer;
+ // }
+ h->size=size;
+ h->color=color;
+ h->lcioID=lcioID;
+}
+
+/*
+ * Line element
+ */
+
+static unsigned LINE_ID=0;
+
+void ced_line(float x0,float y0,float z0,
+	      float x1,float y1,float z1,
+	      unsigned type, unsigned width,unsigned color){
+    ced_line_ID(x0,y0,z0,x1,y1,z1, type, width, color, 0);
+}
+
+void ced_line_ID(float x0,float y0,float z0,
+	      float x1,float y1,float z1,
+	      unsigned layer, unsigned width,unsigned color, unsigned lcioID){
+//  //test for picking
+//  //static int anz;
+//  float length=(x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) + (z1-z0)*(z1-z0);
+//  //printf("CEDLINE length: %f\n x0 %f y0 %f z0 %f, x1 %f, y1 %f z1 %f", length, x0, y0, z0, x1, y1, z1);
+//
+//  if(length > 500.0){
+//      //std::cout << "devide line (length=" << length << ")" <<   std::endl;
+//      ced_line_ID(x0,y0,z0,
+//          (x1-x0)/2.0+x0,(y1-y0)/2.0+y0,(z1-z0)/2.0+z0,
+//          layer, width, color, lcioID);
+//              ced_line_ID(
+//          (x1-x0)/2.0+x0,(y1-y0)/2.0+y0,(z1-z0)/2.0+z0,
+//
+//          x1,y1,z1,
+//          layer, width, color, lcioID);
+//          //todo
+//          //printf("seperate line %i\n", anz++);
+//      return;
+//
+//  }
+
+/*
+//test
+  if( random()%100000 > 99990){
+    double size[]={10,100,50};
+    double position[]={x0,y0,z0};
+    double rotate[] = {20,50,70};
+    int color=1;
+    int lcio_id=5;
+    int layer=5;
+    //ced_geobox(size, position, color ); 
+    ced_geobox_ID(size, position, layer, 0xff00ff, 5); 
+    ced_geobox(size, position, color);
+
+  }
+
+//end test
+*/
+
+  CED_Line *l=(CED_Line *)ced_add(LINE_ID);
+  if(!l)
+    return;
+  l->p0.x=x0;
+  l->p0.y=y0;
+  l->p0.z=z0;
+  l->p1.x=x1;
+  l->p1.y=y1;
+  l->p1.z=z1;
+ if(layer > 255){ //downward compability
+    l->type=layer >> CED_LAYER_SHIFT;
+ }else{
+    l->type=layer;
+ }
+
+    //printf("layer pre: %i  after: %i\n" , layer, l->type); 
+
+//  l->type=type;
+  l->width=width;
+  l->color=color;
+  l->lcioID=lcioID;
+}
+/*
+ * GeoCylinder
+ */
+static unsigned GEOC_ID=0;
+
+void ced_geocylinder(float d,unsigned sides,float rotate,float z,float shift,
+		     unsigned color){
+  CED_GeoCylinder *c=(CED_GeoCylinder *)ced_add(GEOC_ID);
+  if(!c)
+    return;
+  c->d=d;
+  c->sides=sides;
+  c->rotate=rotate;
+  c->z=z;
+  c->shift=shift;
+  c->color=color;
+}
+
+/*
+ * Rotated Geocylinder
+ * Extension of the cylinder subject to a 3-DOF rotation
+ * @author: SD
+ * @date: 26.08.08
+ */
+static unsigned GEOCR_ID=0;
+
+void ced_geocylinder_r(float d, double z, double * center, double * rotate, unsigned sides, 
+		     unsigned int color, int layer){
+	int iDim;
+  CED_GeoCylinderR *c=(CED_GeoCylinderR *)ced_add(GEOCR_ID);
+  if(!c) return;
+    for (iDim = 0; iDim < 3; iDim ++ ) {
+   		c->center[iDim]  = center[iDim];
+   		c->rotate[iDim]   = rotate[iDim];
+    }
+  c->d=d;
+  c->sides=sides;
+  c->color=color;
+  c->z=z;
+ if(layer > 255){ //downward compability
+    c->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    c->layer=layer;
+ }
+
+  //c->layer=layer;
+}
+ 
+void ced_geocylinders(unsigned n,CED_GeoCylinder *all){
+  CED_GeoCylinder *c;
+  unsigned i;
+  for(i=0;i<n;i++){
+    c=(CED_GeoCylinder *)ced_add(GEOC_ID);
+    if(!c)
+      return;
+    memcpy(c,all+i,sizeof(CED_GeoCylinder));
+  }
+}
+
+static unsigned GEOT_ID=0;
+
+void ced_geotubes(unsigned n,CED_GeoTube *all){
+  CED_GeoTube *c;
+  unsigned i;
+  for(i=0;i<n;i++){
+    c=(CED_GeoTube *)ced_add(GEOT_ID);
+    if(!c)
+      return;
+    memcpy(c,all+i,sizeof(CED_GeoTube));
+  }
+}
+
+
+static unsigned GEOB_ID=0;
+
+void ced_geobox(double * sizes, double * center, unsigned int color ) {
+  int iDim;
+  CED_GeoBox * box = (CED_GeoBox*) ced_add(GEOB_ID);
+  if ( ! box ) return;
+  for ( iDim = 0; iDim < 3; iDim ++ ) {
+    box->sizes[iDim]   = sizes[iDim];
+    box->center[iDim]  = center[iDim];
+  }
+  box->color   = color;
+
+}
+
+void rotate3d(double *vektor, double *rotate){
+    //double cords2[3]; 
+    double r_rad[3]={rotate[0]/360*2*3.14159265358979323846, rotate[1]/360*2*3.14159265358979323846, rotate[2]/360*2*3.14159265358979323846};
+    double cords1[3] = {vektor[0], vektor[1], vektor[2]};
+
+    vektor[0] = ( cos(r_rad[1])*cos(r_rad[2]) )*cords1[0] + 
+                (-cos(r_rad[0])*sin(r_rad[2]) + sin(r_rad[0])*sin(r_rad[1])*cos(r_rad[2]) )*cords1[1] + 
+                ( sin(r_rad[0])*sin(r_rad[2]) + cos(r_rad[0])*sin(r_rad[1])*cos(r_rad[2]) )*cords1[2];
+    vektor[1] = ( cos(r_rad[1])*sin(r_rad[2]) ) * cords1[0] + 
+                ( cos(r_rad[0])*cos(r_rad[2]) + sin(r_rad[0])*sin(r_rad[1])*sin(r_rad[2])) * cords1[1] + 
+                ( -sin(r_rad[0])*cos(r_rad[2]) + cos(r_rad[0])*sin(r_rad[1])*sin(r_rad[2]) ) * cords1[2];
+    vektor[2] = (-sin(r_rad[1])) * cords1[0] + 
+                ( sin(r_rad[0])*cos(r_rad[1])) * cords1[1] + 
+                ( cos(r_rad[0])*cos(r_rad[1]))  * cords1[2];
+ 
+}
+
+void ced_geobox_r_ID(double *size, double *position, double *rotate, unsigned int layer, unsigned int color, unsigned int lcio_id) {
+
+    int i;
+    double vektor1[3], vektor2[3];
+    //unsigned int type = layer; //<< CED_LAYER_SHIFT;
+    //unsigned int type = layer;
+
+    double cubematrix[12][6] ={ {-1,-1,-1, +1,-1,-1},
+                                {-1,-1,-1, -1,+1,-1},
+                                {-1,-1,-1, -1,-1,+1},
+                                {+1,-1,-1, +1,+1,-1},
+                                {+1,-1,-1, +1,-1,+1},
+                                {+1,+1,-1, +1,+1,+1},
+                                {+1,+1,-1, -1,+1,-1},
+                                {+1,+1,+1, -1,+1,+1},
+                                {+1,+1,+1, +1,-1,+1},
+                                {-1,+1,+1, -1,-1,+1},
+                                {-1,+1,+1, -1,+1,-1},
+                                {-1,-1,+1, +1,-1,+1} };
+
+    for(i=0;i<12;i++){
+        vektor1[0] = cubematrix[i][0]*size[0]/2; 
+        vektor1[1] = cubematrix[i][1]*size[1]/2; 
+        vektor1[2] = cubematrix[i][2]*size[2]/2;
+ 
+        vektor2[0] = cubematrix[i][3]*size[0]/2;
+        vektor2[1] = cubematrix[i][4]*size[1]/2;
+        vektor2[2] = cubematrix[i][5]*size[2]/2;
+
+        rotate3d(vektor1,rotate);
+        rotate3d(vektor2,rotate);
+
+
+        ced_line_ID(position[0]+vektor1[0], position[1]+vektor1[1], position[2]+vektor1[2],
+                    position[0]+vektor2[0], position[1]+vektor2[1], position[2]+vektor2[2],
+                    layer, 1,color, lcio_id);
+    }
+}
+
+void ced_geobox_ID(double *size, double *position, unsigned int layer, unsigned int color, unsigned int lcio_id) {
+    double rotate[3]={0.0, 0.0, 0.0};
+    ced_geobox_r_ID(size, position, rotate, layer,  color, lcio_id);
+}
+
+
+void ced_geoboxes(unsigned int nBox, CED_GeoBox * allBoxes ) {
+  
+  CED_GeoBox * box;
+  unsigned int iBox;
+  for ( iBox = 0; iBox < nBox ; iBox++ ) {
+    box = (CED_GeoBox *) ced_add(GEOB_ID);
+    if ( ! box ) return;
+    memcpy( box, allBoxes + iBox, sizeof(CED_GeoBox) );
+  }
+}
+
+static unsigned GEOBR_ID=0;
+
+void ced_geobox_r(double * sizes, double * center, double * rotate, unsigned int color, unsigned int layer) {
+  int iDim;
+  CED_GeoBoxR * box = (CED_GeoBoxR*) ced_add(GEOBR_ID);
+  if ( ! box ) return;
+  for ( iDim = 0; iDim < 3; iDim ++ ) {
+    box->sizes[iDim]   = sizes[iDim];
+    box->center[iDim]  = center[iDim];
+    box->rotate[iDim] = rotate[iDim];
+  }
+  box->color = color;
+
+ if(layer > 255){ //downward compability
+    box->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    box->layer=layer;
+ }
+
+//  box->layer = layer;
+}
+
+static unsigned GEOBRS_ID=0;
+
+void ced_geobox_r_solid(double * sizes, double * center, double * rotate, unsigned int color, unsigned int layer) {
+  int iDim;
+  CED_GeoBoxR * box = (CED_GeoBoxR*) ced_add(GEOBRS_ID);
+  if ( ! box ) return;
+  for ( iDim = 0; iDim < 3; iDim ++ ) {
+    box->sizes[iDim]   = sizes[iDim];
+    box->center[iDim]  = center[iDim];
+    box->rotate[iDim] = rotate[iDim];
+  }
+  box->color = color;
+
+ if(layer > 255){ //downward compability
+    box->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    box->layer=layer;
+ }
+
+//  box->layer = layer;
+}
+
+static unsigned LEGEND_ID=0;
+
+void ced_legend(float ene_min, float ene_max, unsigned int color_steps, unsigned int ** rgb_matrix, unsigned int ticks, char scale) {
+	CED_Legend * legend = (CED_Legend*) ced_add(LEGEND_ID);
+	if ( ! legend ) return;
+	
+	legend->ene_min = ene_min;
+  	legend->ene_max = ene_max;
+ 	legend->color_steps = color_steps;
+ 	legend->ticks = ticks;
+ 	legend->scale = scale;
+ 	
+  	const unsigned int numberOfColours = 3;
+  	unsigned int i,j;
+  	for (i = 0; i < numberOfColours; i ++ ) {
+  		for (j = 0; j < color_steps; j ++ ) {
+  			legend->rgb_matrix[j][i] = rgb_matrix[j][i];
+  		}
+	}
+}
+//hauke 
+static unsigned TEXT_ID=0;
+
+void ced_describe_layer(const char *message, int id) {
+    //printf("ced_describe layer id=%i text: %s\n", id, message);
+
+    if(id >= CED_MAX_LAYER){
+        printf("WARNING: ced_describe_layer: Index out of range!\n");
+        return;
+    }
+
+	CED_TEXT *text = (CED_TEXT*) ced_add(TEXT_ID);
+	if(!text){
+        printf("WARNING: ced_describe_layer: cant register CED_TEXT");  
+        return;
+    }
+
+    strncpy(text->text,message,CED_MAX_LAYER_CHAR-1);
+    text->text[CED_MAX_LAYER_CHAR-1] = 0;
+    text->id=id;
+
+    //text->x=xCordinate;
+    //text->y=yCordinate;
+}
+
+/*
+static unsigned LAYER_TEXT_ID=0;
+
+void ced_layer_text(char *message, int id) {
+	LAYER_TEXT *obj = (LAYER_TEXT*) ced_add(LAYER_TEXT_ID);
+	if (!obj){ 
+        printf("ced_layer_text FAILED\n"); 
+        return;
+    }
+    strncpy(obj->str,message,CED_MAX_LAYER_CHAR-1);
+    obj->id=id;
+    //printf("ced_layer_text\n");
+}
+*/
+
+static unsigned PICKING_TEXT_ID=0;
+
+void ced_picking_text(const char *message, int id) {
+	CED_PICKING_TEXT *text = (CED_PICKING_TEXT*) ced_add(PICKING_TEXT_ID);
+	if(!text){
+        printf("WARNING: ced_picking_text: cant register CED_PICKING_TEXT");  
+        return;
+    }
+
+    strncpy(text->text,message,999);
+    text->id=id;
+    //text->text[CED_MAX_LAYER_CHAR-1] = 0;
+    //text->id=id;
+    //text->x=xCordinate;
+    //text->y=yCordinate;
+}
+//end hauke
+
+static unsigned CONER_ID=0;
+
+void ced_cone_r(float base, float height, double *center, double *rotate, unsigned int layer, float *RGBAcolor) {
+    ced_cone_r_ID(base,height,center,rotate,layer, RGBAcolor, 0);
+}
+
+void ced_cone_r_ID(float base, float height, double *center, double *rotate, unsigned int layer, float *RGBAcolor, int lcioid) {
+	CED_ConeR * cone = (CED_ConeR*) ced_add(CONER_ID);
+	if ( ! cone ) return;
+	
+	cone->base = base;
+  	cone->height = height;
+
+ if(layer > 255){ //downward compability
+    cone->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    cone->layer=layer;
+ }
+
+// 	cone->layer = layer;
+    cone->lcioid = lcioid;
+ 	
+  	const unsigned int dim = 3;
+  	const unsigned int channel = 4;
+  	unsigned int i, j;
+
+    // ced_line_ID(0,0,0, center[0], center[1], center[2], type, width, RGBAcolor, lcioid);
+
+    //ced_line_ID(center[0], center[1], center[2], rotate[0], rotate[1], rotate[2], layer, 1, RGBAcolor, lcioid);
+    //printf("CONE: from %f %f %f to %f %f %f\n", center[0], center[1], center[2], rotate[0], rotate[1], rotate[2]);
+
+  	for (i = 0; i < dim; i ++ ) {
+		cone->center[i] = center[i];
+		cone->rotate[i] = rotate[i];
+	}
+	for (j = 0; j < channel; j ++ ) {
+		cone->RGBAcolor[j] = RGBAcolor[j];
+	}
+}
+
+static unsigned ELLIPSOID_ID=0;
+
+void ced_ellipsoid_r(double *size, double *center, double *rotate, unsigned int layer, int color) {
+    ced_ellipsoid_r_ID(size, center, rotate, layer, color, 0);
+}
+
+void ced_ellipsoid_r_ID(double *size, double *center, double *rotate, unsigned int layer, int color, int lcioID) {
+	
+	CED_EllipsoidR * eli = (CED_EllipsoidR*) ced_add(ELLIPSOID_ID);
+	if ( ! eli ) return;	
+ 	
+  	const unsigned int dim = 3;
+  	unsigned int i;
+  	for (i = 0; i < dim; i ++ ) {
+		eli->center[i] = center[i];
+		eli->rotate[i] = rotate[i];
+		eli->size[i] = size[i];
+	}
+	eli->color = color;
+
+ if(layer > 255){ //downward compability
+    eli->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    eli->layer=layer;
+ }
+
+//	eli->layer = layer;
+    eli->lcioid = lcioID;
+}
+
+static unsigned CLUELLIPSE_ID=0;
+
+void ced_cluellipse_r(float radius, float height, float *center, double *rotate, unsigned int layer, int color) {
+    ced_cluellipse_r_ID(radius, height, center, rotate, layer, color, 0);
+}
+
+void ced_cluellipse_r_ID(float radius, float height, float *center, double *rotate, unsigned int layer, int color, int lcioid) { //hauke
+	
+	CED_CluEllipseR * eli = (CED_CluEllipseR*) ced_add(CLUELLIPSE_ID);
+	if ( ! eli ) return;	
+ 	
+  	const unsigned int dim = 3;
+  	unsigned int i;
+  	for (i = 0; i < dim; i ++ ) {
+		eli->center[i] = center[i];
+		eli->rotate[i] = rotate[i];
+	}
+	eli->radius = radius;
+	eli->height = height;
+
+ if(layer > 255){ //downward compability
+    eli->layer=layer >> CED_LAYER_SHIFT;
+ }else{
+    eli->layer=layer;
+ }
+
+//	eli->layer = layer;
+	eli->color = color;
+    eli->lcioid=lcioid;
+}
+
+
+void ced_register_elements(void){
+
+  //1:
+  GEOC_ID		=ced_register_element(sizeof(CED_GeoCylinder),0);
+  //2:
+  GEOCR_ID	    =ced_register_element(sizeof(CED_GeoCylinderR), 0);
+  //3:
+  LINE_ID		=ced_register_element(sizeof(CED_Line),0);
+  //4:
+  HIT_ID		=ced_register_element(sizeof(CED_Hit),0);
+  //5:
+  GEOB_ID		=ced_register_element(sizeof(CED_GeoBox), 0);
+  //6:
+  GEOBR_ID	    =ced_register_element(sizeof(CED_GeoBoxR), 0);
+  //7:
+  GEOBRS_ID	    =ced_register_element(sizeof(CED_GeoBoxR), 0);
+  //8:
+  CONER_ID	    =ced_register_element(sizeof(CED_ConeR), 0);
+  //9:
+  ELLIPSOID_ID	=ced_register_element(sizeof(CED_EllipsoidR), 0);
+  //10:
+  CLUELLIPSE_ID =ced_register_element(sizeof(CED_CluEllipseR), 0);
+  //11:
+  TEXT_ID       =ced_register_element(sizeof(CED_TEXT),0); //hauke: the order of this items is important
+  //12:
+  LEGEND_ID	    =ced_register_element(sizeof(CED_Legend), 0);
+  //13: 
+  GEOT_ID       =ced_register_element(sizeof(CED_GeoTube),0);
+  //14:
+  PICKING_TEXT_ID =ced_register_element(sizeof(CED_PICKING_TEXT),0);
+}
+
diff --git a/Reconstruction/PFA/Pandora/CED/CED/ced_cli.h b/Reconstruction/PFA/Pandora/CED/CED/ced_cli.h
new file mode 100644
index 0000000000000000000000000000000000000000..a92164b00f4aae239918a02e4874c058553d0cb4
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/CED/ced_cli.h
@@ -0,0 +1,432 @@
+/* "C" event display.
+ * Enduser accessable API.
+ *
+ * Alexey Zhelezov, DESY/ITEP, 2005 
+ */
+
+#ifndef __CED_CLI_H
+#define __CED_CLI_H
+
+#include <ced_config.h>
+
+
+//important:
+//          - sum of all layers must be smaler than max_layer!
+//          - number_popup_layer must be smaler than number_data_layer
+
+//#define CED_MAX_LAYER       100
+//#define NUMBER_POPUP_LAYER      20
+//#define NUMBER_DATA_LAYER       25
+//#define NUMBER_DETECTOR_LAYER   20
+//
+//
+//#define CED_MAX_LAYER_CHAR 400
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is the first function to call (before any other).
+ *
+ *  host - host with CED (must be "localhost")
+ *  port - server port number (let say 7285 :)
+ *
+ * NOTE: ced_register_elements() must be called
+ *       separately.
+ */
+void ced_client_init(const char *host,unsigned short port);
+
+/*
+ * Cancel current event output. So, all elements
+ * queued will be discarded.
+ *
+ * Good to call at the begining of every event processing.
+ */
+void ced_new_event(void);
+
+
+/*
+ * This function really attempt to display event in CED.
+ * When CED is not available, this function discard
+ * current event information.
+ *
+ * NOTE: between ced_new_event() and ced_draw_event()
+ *       must be some element creation calls.
+ */
+void ced_draw_event(void);
+
+/*
+ * This function really attempt to display event in CED.
+ * Unlike ced_draw_event() does not reset the event.
+ *
+ * NOTE: between ced_new_event() and ced_draw_event()
+ *       must be some element creation calls.
+ */
+void ced_send_event(void);
+
+int ced_selected_id(void);
+
+//hauke
+int ced_selected_id_noblock(void);
+
+
+/*********************************************
+ *
+ * The following is elements API.
+ *
+ *********************************************/
+
+void ced_register_elements(void);
+
+typedef enum {
+  CED_TYPE_SHIFT=0x0,
+  CED_LAYER_SHIFT=0x8
+} CED_TYPE_BITS;
+
+/*
+typedef enum {
+  CED_TYPE_SHIFT=0x0,
+  CED_LAYER_SHIFT=0x0
+} CED_TYPE_BITS;
+*/
+
+
+typedef struct {
+  float x;
+  float y;
+  float z;
+} CED_Point;
+
+//class CED_Point{
+//  public:
+//  CED_Point(float _x, float _y, float _z){
+//       x=_x;
+//       y=_y;
+//       z=_z;
+//   }
+//
+//  CED_Point(void){
+//  }
+//  float x;
+//  float y;
+//  float z;
+//}; 
+
+
+/*
+ * Hit element
+ */
+
+typedef enum {
+    CED_HIT_POINT=0,
+    CED_HIT_CROSS,
+    CED_HIT_STAR,
+    CED_HIT_BOX,
+    CED_HIT_VXD
+} CED_HIT_TYPE;
+
+typedef struct {
+  CED_Point p;
+  unsigned type;  // point, star, etc
+  unsigned layer; //layer
+  unsigned color; // in ARGB form (so, 0xff0000 is RED)
+  unsigned size;  // size of point/size of cross
+  unsigned lcioID; // unique id of LICO object
+} CED_Hit;
+
+void ced_hit(float x,float y,float z,unsigned type,unsigned size,unsigned color);
+
+//to give a bit of downward compatibility
+void ced_hit_ID_old(float x,float y,float z,unsigned type, unsigned size,unsigned color, unsigned lcioID);
+
+
+void ced_hit_ID(float x,float y,float z,unsigned type,unsigned layer, unsigned size,unsigned color, unsigned lcioID);
+
+/*
+ * Line element
+ */
+
+typedef struct {
+  CED_Point p0;
+  CED_Point p1;
+  unsigned type;  // not yet defined...
+  unsigned width; // not yet defined...
+  unsigned color; // in ARGB form (so, 0xff0000 is RED)
+  unsigned lcioID; // unique id of LICO object
+
+} CED_Line;
+
+void ced_line(float x0,float y0,float z0,
+	      float x1,float y1,float z1,
+	      unsigned type,unsigned width,unsigned color);
+void ced_line_ID(float x0,float y0,float z0,
+	      float x1,float y1,float z1,
+	      unsigned type,unsigned width,unsigned color, unsigned lcioID);
+
+/*
+ * GeoCylinder
+ */
+typedef struct {
+  float d;       // radius
+  unsigned  sides;   // poligon order
+  float rotate;  // angle degree
+  float z;       // 1/2 length
+  float shift;   // in z
+  unsigned color;
+} CED_GeoCylinder;
+
+/*
+ * GeoTube
+ */
+typedef struct {
+  float r_o;            // outer radius
+  float r_i;            // inner radius
+  unsigned edges_o;     // edges outer
+  unsigned edges_i;     // edges inner
+  float rotate_o;       // angle degree, rotate outer cylinder
+  float rotate_i;       //rotate inner cylinder
+  float z;              // 1/2 length
+  float shift;          // shift in z
+  unsigned color;       // color
+  unsigned type;        //describes the layer where this element lies
+  bool classic_inner;   //draw the outer detector lines in classic view?
+  bool classic_outer;   //draw the inner detector lines in classic view?
+}  CED_GeoTube;
+
+
+/** Same as CED_GeoTube but here as C++ struct with contstructor. This is allows
+ *  to dynamically allocate the detector structure (in an std::vector using the constructor) 
+ *  without knowing the exact number of  detector elements a priori (such as the #layers in the FTD).
+ *  This wasn't poassible with the static allocation using the C type struct.
+ *  ( Used in MArlinCED::drawGearDetector ).
+ */
+struct CEDGeoTube{
+  CEDGeoTube(double  r_out,
+	     double  r_in,
+	     int edges_out,
+	     int edges_in,
+	     double  rotate_out,
+	     double  rotate_in,
+	     double  zlength,
+	     double  zshift,
+	     int col,
+	     int layer,
+	     bool classic_i,
+	     bool classic_o ) :
+    r_o(r_out),
+    r_i(r_in),
+    edges_o(edges_out),
+    edges_i (edges_in),
+    rotate_o (rotate_out),
+    rotate_i (rotate_in),
+    z( zlength),
+    shift (zshift),
+    color (col),
+    type(layer),
+    classic_inner(classic_i),
+    classic_outer(classic_o) {} 
+  float r_o;            // outer radius
+  float r_i;            // inner radius
+  unsigned edges_o;     // edges outer
+  unsigned edges_i;     // edges inner
+  float rotate_o;       // angle degree, rotate outer cylinder
+  float rotate_i;       //rotate inner cylinder
+  float z;              // 1/2 length
+  float shift;          // shift in z
+  unsigned color;       // color
+  unsigned type;        //describes the layer where this element lies
+  bool classic_inner;   //draw the outer detector lines in classic view?
+  bool classic_outer;   //draw the inner detector lines in classic view?
+} ;
+
+void ced_geotubes(unsigned n,CED_GeoTube *all);
+
+
+void ced_geocylinder(float d,unsigned sides,float rotate,float z,float shift,
+		     unsigned color);
+
+void ced_geocylinders(unsigned n,CED_GeoCylinder *all);
+		   
+/*
+ * GeoCylinder rotatable
+ * @author: S.Daraszewicz (UoE)
+ * @date: 01.09.09
+ */
+typedef struct {
+  float d;       	// radius
+  unsigned sides; 	// poligon order
+  float center[3];  // cylinder centre z,y,z
+  float rotate[3];  // rotation angles wrt x,y,z axis
+  float z;       	// length
+  unsigned color;	// colour
+  unsigned layer; 	// layer the Cylinder to be displayed onto
+} CED_GeoCylinderR;
+		   
+		     
+void ced_geocylinder_r(float d, double z, double * center, double * rotate, unsigned sides, 
+		     unsigned int color, int layer);
+		     
+
+  /** GeoBox structure
+   */
+  typedef struct {
+    /** The three box sizes in mm */
+    double sizes[3];
+    /** position of the center of the box*/
+    double center[3];
+    /** box color */
+    unsigned int color;
+  } CED_GeoBox;
+
+  /** Send/Draw a box at position center (x,y,z in mm) with lengths along the 
+   * axes specified in sizes.
+   * 
+   * @author A.Bulgheroni, INFN
+   */
+  void ced_geobox(double * sizes, double * center, unsigned int color );
+  void ced_geobox_ID(double *size, double *position, unsigned int layer, unsigned int color, unsigned int lcio_id);
+  void ced_geobox_r_ID(double *size, double *position, double *rotate, unsigned int layer, unsigned int color, unsigned int lcio_id);
+  void rotate3d(double *vektor, double *rotate);
+
+
+
+   /* 
+   * @author A.Bulgheroni, INFN
+   */
+  void ced_geoboxes( unsigned int nBox, CED_GeoBox * allBoxes);
+
+  typedef struct {
+    /** The three box sizes in mm */
+    double sizes[3];
+    /** position of the center of the box*/
+    double center[3];
+    /** box color */
+    unsigned int color;
+    /** rotation angle in degrees */
+    double rotate[3];
+    /** layer for toggling display */
+    unsigned int layer;
+  } CED_GeoBoxR;
+
+void ced_geobox_r(double * sizes, double * center, double * rotate, unsigned int color, unsigned int layer);
+void ced_geobox_r_solid(double * sizes, double * center, double * rotate, unsigned int color, unsigned int layer);
+
+//hauke
+  typedef struct{
+    char text[1000];
+    int id;
+  } CED_PICKING_TEXT; 
+
+void ced_picking_text(const char *, int number);
+
+//--------
+
+  typedef struct{
+    char text[400];
+    int id;
+  } CED_TEXT; 
+
+
+void ced_describe_layer(const char *, int); //, int, int);
+
+
+  typedef struct{
+    char str[400];
+    unsigned int id;
+  } LAYER_TEXT; 
+
+void ced_layer_text(char *, int);
+//end hauke
+
+
+/*
+ * Energy spectrum colour map legend.
+ * @author: S.Daraszewicz (UoE)
+ * @date: 01.09.09
+ */
+  typedef struct {  
+  	/** min energy on the legend */	
+  	float ene_max;
+  	/** max energy on the legend */
+  	float ene_min;
+  	/** number of ticks on the legend */
+  	unsigned int ticks;
+  	/** spectrum colour steps */
+  	unsigned int color_steps; 
+  	/** spectrum colour matrix */
+  	unsigned int rgb_matrix[512][3]; //FIX ME: 512 size not changed with color_steps
+  	/** LOG or LIN */
+  	char scale;
+  } CED_Legend;
+
+void ced_legend(float ene_min, float ene_max, unsigned int color_steps, unsigned int ** rgb_matrix, unsigned int ticks, char scale);
+
+  typedef struct {  
+  	/** position of the centre of the base */	
+  	double center[3];
+  	/** rotation matrix */
+  	double rotate[3];
+    /** layer for toggling display */
+    unsigned int layer;
+    /** base radius */
+    float base;
+    /** height */
+    float height;
+    /** RGBA color */
+    float RGBAcolor[4];
+    unsigned lcioid; //hauke
+  } CED_ConeR;
+
+
+void ced_cone_r(float base, float height, double *center, double *rotate, unsigned int layer, float *RGBAcolor);
+void ced_cone_r_ID(float base, float height, double *center, double *rotate, unsigned int layer, float *RGBAcolor, int lcioid); //hauke
+
+
+  typedef struct {  
+  	/** position of the centre of the base */	
+  	double center[3];
+  	/** rotation matrix */
+  	double rotate[3];
+    /** layer for toggling display */
+    unsigned int layer;
+    /** xyz size */
+	double size[3];
+    /** RGBA color */
+   	int color;
+    unsigned lcioid; //hauke
+  } CED_EllipsoidR;
+
+
+void ced_ellipsoid_r(double *size, double *center, double *rotate, unsigned int layer, int color);
+void ced_ellipsoid_r_ID(double *size, double *center, double *rotate, unsigned int layer, int color, int lcioid); //hauke
+
+
+  typedef struct {  
+  	/** position of the centre of the base */	
+  	double center[3];
+  	/** rotation matrix */
+  	double rotate[3];
+    /** layer for toggling display */
+    unsigned int layer;
+    /** base radius */
+	float radius;
+	/** half height */
+	float height;
+    /** RGBA color */
+    int color;
+    unsigned lcioid; //hauke
+  } CED_CluEllipseR;
+
+
+void ced_cluellipse_r(float radius, float height, float *center, double *rotate, unsigned int layer, int color);
+void ced_cluellipse_r_ID(float radius, float height, float *center, double *rotate, unsigned int layer, int color, int lcioid); //hauke
+
+
+#ifdef __cplusplus
+ }
+#endif
+	
+
+#endif /* __CED_CLI_H */
diff --git a/Reconstruction/PFA/Pandora/CED/CED/ced_config.h b/Reconstruction/PFA/Pandora/CED/CED/ced_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..66214eada39ed69548a69765def00a0020f7a637
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/CED/CED/ced_config.h
@@ -0,0 +1,204 @@
+/********************************************************** 
+* ced_config.h, CED config file                           *    
+* Hauke Hoelbe, DESY, 2011                                *
+* Headerfile to adapt CED before the build.               *
+**********************************************************/
+
+#ifndef __CED_CONFIG
+#define __CED_CONFIG
+
+#include "ced_cli.h"
+
+
+/********************************************************** 
+* Handling                                                *
+**********************************************************/
+//enable zoom function by right click and pull
+#define ZOOM_RIGHT_CLICK                   0
+
+//time when 2 clicks should be a double click, in 1/1000000 secounds
+#define DOUBLE_CLICK_TIME                  300000 
+
+//data layer keys 
+#define DATALAYER_SHORTKEY_00       '0'
+#define DATALAYER_SHORTKEY_01       '1'
+#define DATALAYER_SHORTKEY_02       '2'
+#define DATALAYER_SHORTKEY_03       '3'
+#define DATALAYER_SHORTKEY_04       '4'
+#define DATALAYER_SHORTKEY_05       '5'
+#define DATALAYER_SHORTKEY_06       '6'
+#define DATALAYER_SHORTKEY_07       '7'
+#define DATALAYER_SHORTKEY_08       '8'
+#define DATALAYER_SHORTKEY_09       '9'
+#define DATALAYER_SHORTKEY_10       ')'
+#define DATALAYER_SHORTKEY_11       '!'
+#define DATALAYER_SHORTKEY_12       '@'
+#define DATALAYER_SHORTKEY_13       '#'
+#define DATALAYER_SHORTKEY_14       '$'
+#define DATALAYER_SHORTKEY_15       '%'
+#define DATALAYER_SHORTKEY_16       '^'
+#define DATALAYER_SHORTKEY_17       '&'
+#define DATALAYER_SHORTKEY_18       '*'
+#define DATALAYER_SHORTKEY_19       '('
+#define DATALAYER_SHORTKEY_20       't'
+#define DATALAYER_SHORTKEY_21       'y'
+#define DATALAYER_SHORTKEY_22       'u'
+#define DATALAYER_SHORTKEY_23       'i'
+#define DATALAYER_SHORTKEY_24       'o'
+
+//detector layer keys
+#define DETECTORLAYER_SHORTKEY_00   'j'
+#define DETECTORLAYER_SHORTKEY_01   'k'
+#define DETECTORLAYER_SHORTKEY_02   'l'
+#define DETECTORLAYER_SHORTKEY_03   ';'
+#define DETECTORLAYER_SHORTKEY_04   '\''
+#define DETECTORLAYER_SHORTKEY_05   'p'
+#define DETECTORLAYER_SHORTKEY_06   '['
+#define DETECTORLAYER_SHORTKEY_07   ']'
+#define DETECTORLAYER_SHORTKEY_08   '\\'
+#define DETECTORLAYER_SHORTKEY_09   'T'
+#define DETECTORLAYER_SHORTKEY_10   'Y'
+#define DETECTORLAYER_SHORTKEY_11   'U'
+#define DETECTORLAYER_SHORTKEY_12   'I'
+#define DETECTORLAYER_SHORTKEY_13   'O'
+#define DETECTORLAYER_SHORTKEY_14   'P'
+#define DETECTORLAYER_SHORTKEY_15   '{'
+#define DETECTORLAYER_SHORTKEY_16   '}'
+#define DETECTORLAYER_SHORTKEY_17   '|'
+#define DETECTORLAYER_SHORTKEY_18   'a'
+#define DETECTORLAYER_SHORTKEY_19   'e'
+
+
+/********************************************************** 
+* Colors and appearance                                   *
+**********************************************************/
+//size of the boarder line in filled (new view) of detector components.
+#define CED_GEOTUBE_LINE_WIDTH              0.3
+
+//maximal transparency of boarder lines 
+//#define CED_GEOTUBE_LINE_MAX_TRANS          0.2  
+#define CED_GEOTUBE_LINE_MAX_TRANS          1.0  
+
+
+//names and values of color apairs in popup menu
+#define CED_BGCOLOR_OPTION1_NAME            "Gainsboro" 
+#define CED_BGCOLOR_OPTION1_COLORCODE       0.862745,0.862745,0.862745,0 
+
+#define CED_BGCOLOR_OPTION2_NAME            "Lightgrey" 
+#define CED_BGCOLOR_OPTION2_COLORCODE       0.827451,0.827451,0.827451,0
+
+#define CED_BGCOLOR_OPTION3_NAME            "Darkgray" 
+#define CED_BGCOLOR_OPTION3_COLORCODE       0.662745,0.662745,0.662745,0
+
+#define CED_BGCOLOR_OPTION4_NAME            "Gray" 
+#define CED_BGCOLOR_OPTION4_COLORCODE       0.501961,0.501961,0.501961,0
+
+#define CED_BGCOLOR_OPTION5_NAME            "Silver" 
+#define CED_BGCOLOR_OPTION5_COLORCODE       0.7529,0.7529,0.7529,0
+
+#define CED_BGCOLOR_OPTION6_NAME            "Dimgray" 
+#define CED_BGCOLOR_OPTION6_COLORCODE       0.4118,0.4118,0.4118,0
+
+#define CED_BGCOLOR_OPTION7_NAME            "Lightsteelblue" 
+#define CED_BGCOLOR_OPTION7_COLORCODE       0.6902,0.7686 ,0.8706,0
+
+#define CED_BGCOLOR_OPTION8_NAME            "Steelblue" 
+#define CED_BGCOLOR_OPTION8_COLORCODE       0.2745,0.5098,0.70588,0
+
+#define CED_BGCOLOR_OPTION9_NAME            "Seagreen" 
+#define CED_BGCOLOR_OPTION9_COLORCODE       0.18039,0.54509,0.34117,0
+
+#define CED_BGCOLOR_OPTION10_NAME           "Orange" 
+#define CED_BGCOLOR_OPTION10_COLORCODE      1,0.647,0,0
+
+#define CED_BGCOLOR_OPTION11_NAME           "Yellow" 
+#define CED_BGCOLOR_OPTION11_COLORCODE      1,1,0,0
+
+#define CED_BGCOLOR_OPTION12_NAME           "Violett" 
+#define CED_BGCOLOR_OPTION12_COLORCODE      0.9333,0.5098,0.9333,0
+
+#define CED_BGCOLOR_OPTION13_NAME           "Black" 
+#define CED_BGCOLOR_OPTION13_COLORCODE      0,0,0,0
+
+#define CED_BGCOLOR_OPTION14_NAME           "Blue" 
+#define CED_BGCOLOR_OPTION14_COLORCODE      0,0.2,0.4,0
+
+#define CED_BGCOLOR_OPTION15_NAME           "White" 
+#define CED_BGCOLOR_OPTION15_COLORCODE      1,1,1,0
+
+
+
+
+//Color of xyz axes 
+#define AXES_COLOR                          0.2,0.2,0.8
+
+//Width of xyz axes 
+#define AXES_LINE_SIZE                      0.5
+
+
+//Help frame: Frame fill color, and transp
+#define HELP_FRAME_FILL_COLOR               0.5,1,1,0.8
+
+//Help frame: Frame boarder color and transp
+#define HELP_FRAME_BOARDER_COLOR            0.1,0.8,1.0,0.8 
+
+//Help frame: Frame boarder line width
+#define HELP_FRAME_BOARDER_LINE_SIZE        3. 
+
+//Help frame: Text color, and transp
+#define HELP_FRAME_TEXT_COLOR               0.0,0.0,0.0 
+
+
+
+
+/********************************************************** 
+* Layers                                                  *
+**********************************************************/
+//number of total number of layers 
+#define CED_MAX_LAYER                       100
+
+//number of layers shown in popup menu
+#define NUMBER_POPUP_LAYER                  20
+
+//number of layers reserved for data
+#define NUMBER_DATA_LAYER                   25
+
+//number of layers reserved for detector components 
+#define NUMBER_DETECTOR_LAYER               20
+
+//layer description text: maximal number of chars for one entry
+#define CED_MAX_LAYER_CHAR                  400
+
+/********************************************************** 
+* Graphics                                                *
+**********************************************************/
+
+//Camera field of view, in degree 
+#define CAMERA_FIELD_OF_VIEW                45
+
+//Camera min distance (hint: min and max should be close together)
+#define CAMERA_MIN_DISTANCE                 100
+
+//Camera max distance (hint: min and max should be close together)
+#define CAMERA_MAX_DISTANCE                 50000.0*mm.sf+50000/mm.sf 
+
+//Where the camera stands
+#define CAMERA_POSITION                     0,0,2000
+
+
+
+//Fisheye alpha factor
+#define FISHEYE_ALPHA                       1e-3
+#define FISHEYE_ZOOM                        8.
+
+/********************************************************** 
+* Debug                                                   *
+**********************************************************/
+
+//show pickable points:
+//#define DEBUG_PICKING 1
+
+
+
+
+#endif 
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/CMakeLists.txt b/Reconstruction/PFA/Pandora/GaudiPandora/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..46344f83049f4e45f51d5646fd3d24c142f70402
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/CMakeLists.txt
@@ -0,0 +1,56 @@
+gaudi_subdir(GaudiPandora v0r0)
+
+find_package(CLHEP REQUIRED)
+#find_package(GSL REQUIRED )##don't use this,  use CEPC LCIO version one , due to the ClusterShape.cc file which is from LCIO
+#message("GSL: ${GSL_LIBRARIES} ")
+set (gsl_include "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/include")
+set (gsl_lib1 "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/lib/libgsl.so")
+set (gsl_lib2 "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/lib/libgslcblas.so")
+find_package(LCIO REQUIRED ) 
+find_package(GEAR REQUIRED)
+message("ENV GEAR: $ENV{GEAR}")
+
+
+find_package(EDM4HEP REQUIRED )
+include_directories(${EDM4HEP_INCLUDE_DIR})
+
+find_package(PandoraSDK REQUIRED ) 
+include_directories(${PandoraSDK_INCLUDE_DIRS})
+link_libraries(${PandoraSDK_LIBRARIES})
+find_package(LCContent REQUIRED ) 
+include_directories(${LCContent_INCLUDE_DIRS})
+link_libraries(${LCContent_LIBRARIES})
+
+
+list(APPEND CMAKE_MODULE_PATH "$ENV{ROOTSYS}/etc/cmake/")
+find_package(ROOT 5.26.00 REQUIRED COMPONENTS Eve Geom RGL EG)
+
+#In order to use ClusterShape.cc
+include_directories("../CED/CED/")
+include_directories("../MarlinUtil/01-08/source/")
+
+gaudi_depends_on_subdirs(
+    Service/EventSeeder
+    Service/GearSvc
+)
+
+set(dir_srcs
+    src/PandoraPFAlg.cpp
+    src/MCParticleCreator.cpp
+    src/GeometryCreator.cpp
+    src/CaloHitCreator.cpp
+    src/TrackCreator.cpp
+    src/PfoCreator.cpp
+    ../CED/CED/*.cc
+    ../MarlinUtil/01-08/source/*.cc
+)
+set(dir_include include)
+# Modules
+gaudi_add_module(GaudiPandora ${dir_srcs}
+    INCLUDE_DIRS ${gsl_include} ${dir_include} GaudiKernel FWCore CLHEP  ${LCIO_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} gear  
+    LINK_LIBRARIES ${gsl_lib1} ${gsl_lib2} GaudiKernel FWCore CLHEP ROOT ${LCIO_LIBRARIES} $ENV{GEAR}/lib/libgear.so $ENV{GEAR}/lib/libgearxml.so 
+      -Wl,--no-as-needed 
+      EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+      -Wl,--as-needed 
+
+)
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/CaloHitCreator.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/CaloHitCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..91fd1ccd04f1de4ce7de89d83048171882564ab2
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/CaloHitCreator.h
@@ -0,0 +1,254 @@
+/**
+ * 
+ *  @brief  Header file for the calo hit creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef CALO_HIT_CREATOR_H
+#define CALO_HIT_CREATOR_H 1
+
+#include "GaudiKernel/ISvcLocator.h"
+#include "edm4hep/CalorimeterHit.h"
+
+#include "gear/LayerLayout.h"
+
+#include "Api/PandoraApi.h"
+
+#include <string>
+
+typedef std::vector<edm4hep::CalorimeterHit *> CalorimeterHitVector;
+
+namespace gear { class GearMgr; }
+
+class CollectionMaps;
+/**
+ *  @brief  CaloHitCreator class
+ */
+class CaloHitCreator
+{
+public:
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_eCalCaloHitCollections;               ///< The ecal calorimeter hit collections
+        StringVector    m_hCalCaloHitCollections;               ///< The hcal calorimeter hit collections
+        StringVector    m_lCalCaloHitCollections;               ///< The lcal calorimeter hit collections
+        StringVector    m_lHCalCaloHitCollections;              ///< The lhcal calorimeter hit collections
+        StringVector    m_muonCaloHitCollections;               ///< The muon calorimeter hit collections
+
+        float           m_absorberRadLengthECal;                ///< The absorber radiation length in the ECal
+        float           m_absorberIntLengthECal;                ///< The absorber interaction length in the ECal
+        float           m_absorberRadLengthHCal;                ///< The absorber radiation length in the HCal
+        float           m_absorberIntLengthHCal;                ///< The absorber interaction length in the HCal
+        float           m_absorberRadLengthOther;               ///< The absorber radiation length in other detector regions
+        float           m_absorberIntLengthOther;               ///< The absorber interaction length in other detector regions
+
+        float           m_eCalToMip;                            ///< The calibration from deposited ECal energy to mip
+        float           m_hCalToMip;                            ///< The calibration from deposited HCal energy to mip
+        float           m_muonToMip;                            ///< The calibration from deposited Muon energy to mip
+        float           m_eCalMipThreshold;                     ///< Threshold for creating calo hits in the ECal, units mip
+        float           m_hCalMipThreshold;                     ///< Threshold for creating calo hits in the HCal, units mip
+        float           m_muonMipThreshold;                     ///< Threshold for creating calo hits in the HCal, units mip
+
+        float           m_eCalToEMGeV;                          ///< The calibration from deposited ECal energy to EM energy
+        float           m_eCalToHadGeVBarrel;                   ///< The calibration from deposited ECal barrel energy to hadronic energy
+        float           m_eCalToHadGeVEndCap;                   ///< The calibration from deposited ECal endcap energy to hadronic energy
+        float           m_hCalToEMGeV;                          ///< The calibration from deposited HCal energy to EM energy
+        float           m_hCalToHadGeV;                         ///< The calibration from deposited HCal energy to hadronic energy
+        int             m_muonDigitalHits;                      ///< Muon hits are treated as digital (energy from hit count)
+        float           m_muonHitEnergy;                        ///< The energy for a digital muon calorimeter hit, units GeV
+
+        float           m_maxHCalHitHadronicEnergy;             ///< The maximum hadronic energy allowed for a single hcal hit
+        int             m_nOuterSamplingLayers;                 ///< Number of layers from edge for hit to be flagged as an outer layer hit
+        float           m_layersFromEdgeMaxRearDistance;        ///< Maximum number of layers from candidate outer layer hit to rear of detector
+
+        int             m_hCalEndCapInnerSymmetryOrder;         ///< HCal end cap inner symmetry order (missing from ILD00 gear file)
+        float           m_hCalEndCapInnerPhiCoordinate;         ///< HCal end cap inner phi coordinate (missing from ILD00 gear file)
+
+        // For Strip Splitting method and hybrid ECAL.
+        int             m_stripSplittingOn;                     ///< To use SSA, this should be true (default is false)
+        int             m_useEcalScLayers;                      ///< To use scintillator layers ~ hybrid ECAL, this should be true (default is false)
+        float           m_eCalSiToMip;                          ///< The calibration from deposited Si-layer energy to mip
+        float           m_eCalScToMip;                          ///< The calibration from deposited Sc-layer energy to mip
+        float           m_eCalSiMipThreshold;                   ///< Threshold for creating calo hits in the Si-layers of ECAL, units mip
+        float           m_eCalScMipThreshold;                   ///< Threshold for creating calo hits in the Sc-layers of ECAL, units mip
+        float           m_eCalSiToEMGeV;                        ///< The calibration from deposited Si-layer energy to EM energy
+        float           m_eCalScToEMGeV;                        ///< The calibration from deposited Sc-layer energy to EM energy
+        float           m_eCalSiToHadGeVBarrel;                 ///< The calibration from deposited Si-layer energy on the enecaps to hadronic energy
+        float           m_eCalScToHadGeVBarrel;                 ///< The calibration from deposited Sc-layer energy on the endcaps to hadronic energy
+        float           m_eCalSiToHadGeVEndCap;                 ///< The calibration from deposited Si-layer energy on the enecaps to hadronic energy
+        float           m_eCalScToHadGeVEndCap;                 ///< The calibration from deposited Sc-layer energy on the endcaps to hadronic energy
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     CaloHitCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc, bool encoder_style);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~CaloHitCreator();
+
+    /**
+     *  @brief  Create calo hits
+     * 
+     */    
+    pandora::StatusCode CreateCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get the calorimeter hit vector
+     * 
+     *  @return The calorimeter hit vector
+     */
+    const CalorimeterHitVector &GetCalorimeterHitVector() const;
+
+    /**
+     *  @brief  Reset the calo hit creator
+     */
+    void Reset();
+
+private:
+    /**
+     *  @brief  Create ecal calo hits
+     * 
+     */
+    pandora::StatusCode CreateECalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create hcal calo hits
+     * 
+     */
+    pandora::StatusCode CreateHCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create muon calo hits
+     * 
+     */
+    pandora::StatusCode CreateMuonCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create lcal calo hits
+     * 
+     */    
+    pandora::StatusCode CreateLCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create lhcal calo hits
+     * 
+     */
+    pandora::StatusCode CreateLHCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get common calo hit properties: position, parent address, input energy and time
+     * 
+     */
+    void GetCommonCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, PandoraApi::CaloHit::Parameters &caloHitParameters) const;
+
+    /**
+     *  @brief  Get end cap specific calo hit properties: cell size, absorber radiation and interaction lengths, normal vector
+     * 
+     */
+    void GetEndCapCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+        PandoraApi::CaloHit::Parameters &caloHitParameters, float &absorberCorrection) const;
+
+    /**
+     *  @brief  Get barrel specific calo hit properties: cell size, absorber radiation and interaction lengths, normal vector
+     * 
+     */
+    void GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+        unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+        float &absorberCorrection) const;
+
+    /**
+     *  @brief  Get number of active layers from position of a calo hit to the edge of the detector
+     * 
+     */
+    int GetNLayersFromEdge(const edm4hep::CalorimeterHit *const pCaloHit) const;
+
+    /**
+     *  @brief  Get the maximum radius of a calo hit in a polygonal detector structure
+     * 
+     */
+    float GetMaximumRadius(const edm4hep::CalorimeterHit *const pCaloHit, const unsigned int symmetryOrder, const float phi0) const;
+
+    /**
+     *  @brief  Get the layer coding string from the provided cell id encoding string
+     * 
+     *  @param  encodingString the cell id encoding string
+     * 
+     *  @return the layer coding string
+     */
+    std::string GetLayerCoding(const std::string &encodingString) const;
+
+    /**
+     *  @brief  Get the stave coding string from the provided cell id encoding string
+     * 
+     *  @param  encodingString the cell id encoding string
+     * 
+     *  @return the stave coding string
+     */
+    std::string GetStaveCoding(const std::string &encodingString) const;
+
+    const Settings                      m_settings;                         ///< The calo hit creator settings
+
+    const pandora::Pandora             *m_pPandora;                         ///< Address of the pandora object to create calo hits
+
+    float                               m_eCalBarrelOuterZ;                 ///< ECal barrel outer z coordinate
+    float                               m_hCalBarrelOuterZ;                 ///< HCal barrel outer z coordinate
+    float                               m_muonBarrelOuterZ;                 ///< Muon barrel outer z coordinate
+    float                               m_coilOuterR;                       ///< Coil outer r coordinate
+
+    float                               m_eCalBarrelInnerPhi0;              ///< ECal barrel inner phi0 coordinate
+    unsigned int                        m_eCalBarrelInnerSymmetry;          ///< ECal barrel inner symmetry order
+    float                               m_hCalBarrelInnerPhi0;              ///< HCal barrel inner phi0 coordinate
+    unsigned int                        m_hCalBarrelInnerSymmetry;          ///< HCal barrel inner symmetry order
+    float                               m_muonBarrelInnerPhi0;              ///< Muon barrel inner phi0 coordinate
+    unsigned int                        m_muonBarrelInnerSymmetry;          ///< Muon barrel inner symmetry order
+
+    float                               m_hCalEndCapOuterR;                 ///< HCal endcap outer r coordinate
+    float                               m_hCalEndCapOuterZ;                 ///< HCal endcap outer z coordinate
+    float                               m_hCalBarrelOuterR;                 ///< HCal barrel outer r coordinate
+    float                               m_hCalBarrelOuterPhi0;              ///< HCal barrel outer phi0 coordinate
+    unsigned int                        m_hCalBarrelOuterSymmetry;          ///< HCal barrel outer symmetry order
+
+    float                               m_hCalBarrelLayerThickness;         ///< HCal barrel layer thickness
+    float                               m_hCalEndCapLayerThickness;         ///< HCal endcap layer thickness
+
+    CalorimeterHitVector                m_calorimeterHitVector;             ///< The calorimeter hit vector
+    std::string                         m_encoder_str;
+    std::string                         m_encoder_str_MUON ; 
+    std::string                         m_encoder_str_LCal ; 
+    std::string                         m_encoder_str_LHCal; 
+    gear::GearMgr* _GEAR;
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline const CalorimeterHitVector &CaloHitCreator::GetCalorimeterHitVector() const
+{
+    return m_calorimeterHitVector;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline void CaloHitCreator::Reset()
+{
+    m_calorimeterHitVector.clear();
+}
+
+#endif // #ifndef CALO_HIT_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/GeometryCreator.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/GeometryCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..bb43d8a0f86a5211485a1e4cb301e3886da941a9
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/GeometryCreator.h
@@ -0,0 +1,155 @@
+/**
+ * 
+ *  @brief  Header file for the geometry creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef GEOMETRY_CREATOR_H
+#define GEOMETRY_CREATOR_H 1
+
+#include "Api/PandoraApi.h"
+
+#include "GaudiKernel/ISvcLocator.h"
+namespace gear { class CalorimeterParameters; class GearMgr; }
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  GeometryCreator class
+ */
+class GeometryCreator
+{
+public:
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        float           m_absorberRadLengthECal;                ///< The absorber radiation length in the ECal
+        float           m_absorberIntLengthECal;                ///< The absorber interaction length in the ECal
+        float           m_absorberRadLengthHCal;                ///< The absorber radiation length in the HCal
+        float           m_absorberIntLengthHCal;                ///< The absorber interaction length in the HCal
+        float           m_absorberRadLengthOther;               ///< The absorber radiation length in other detector regions
+        float           m_absorberIntLengthOther;               ///< The absorber interaction length in other detector regions
+
+        int             m_eCalEndCapInnerSymmetryOrder;         ///< ECal end cap inner symmetry order (missing from ILD gear files)
+        float           m_eCalEndCapInnerPhiCoordinate;         ///< ECal end cap inner phi coordinate (missing from ILD gear files)
+        int             m_eCalEndCapOuterSymmetryOrder;         ///< ECal end cap outer symmetry order (missing from ILD gear files)
+        float           m_eCalEndCapOuterPhiCoordinate;         ///< ECal end cap outer phi coordinate (missing from ILD gear files)
+
+        int             m_hCalEndCapInnerSymmetryOrder;         ///< HCal end cap inner symmetry order (missing from ILD gear files)
+        float           m_hCalEndCapInnerPhiCoordinate;         ///< HCal end cap inner phi coordinate (missing from ILD gear files)
+        int             m_hCalEndCapOuterSymmetryOrder;         ///< HCal end cap outer symmetry order (missing from ILD gear files)
+        float           m_hCalEndCapOuterPhiCoordinate;         ///< HCal end cap outer phi coordinate (missing from ILD gear files)
+
+        int             m_hCalRingInnerSymmetryOrder;           ///< HCal ring inner symmetry order (missing from ILD gear files)
+        float           m_hCalRingInnerPhiCoordinate;           ///< HCal ring inner phi coordinate (missing from ILD gear files)
+        int             m_hCalRingOuterSymmetryOrder;           ///< HCal ring outer symmetry order (missing from ILD gear files)
+        float           m_hCalRingOuterPhiCoordinate;           ///< HCal ring outer phi coordinate (missing from ILD gear files)
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     GeometryCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~GeometryCreator();
+
+    /**
+     *  @brief  Create geometry
+     */
+    pandora::StatusCode CreateGeometry(ISvcLocator* svcloc);
+
+private:
+    typedef std::map<pandora::SubDetectorType, PandoraApi::Geometry::SubDetector::Parameters> SubDetectorTypeMap;
+    typedef std::map<std::string, PandoraApi::Geometry::SubDetector::Parameters> SubDetectorNameMap;
+
+    /**
+     *  @brief  Set mandatory sub detector parameters
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     */
+    void SetMandatorySubDetectorParameters(SubDetectorTypeMap &subDetectorTypeMap) const;
+
+    /**
+     *  @brief  Set additional sub detector parameters
+     * 
+     *  @param  subDetectorNameMap the sub detector name map (for smaller sub detectors, identified uniquely only by name)
+     */
+    void SetAdditionalSubDetectorParameters(SubDetectorNameMap &subDetectorNameMap) const;
+
+    /**
+     *  @brief  Set sub detector parameters to their gear default values
+     * 
+     *  @param  inputParameters input parameters, from gear
+     *  @param  subDetectorName the sub detector name
+     *  @param  subDetectorType the sub detector type
+     *  @param  parameters the sub detector parameters
+     */
+    void SetDefaultSubDetectorParameters(const gear::CalorimeterParameters &inputParameters, const std::string &subDetectorName,
+        const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const;
+
+    /**
+     *  @brief  Set positions of gaps in ILD detector and add information missing from GEAR parameters file
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     *  @param  subDetectorNameMap the sub detector name map (for smaller sub detectors, identified uniquely only by name)
+     */
+    pandora::StatusCode SetILDSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap, SubDetectorNameMap &subDetectorNameMap) const;
+
+    /**
+     *  @brief  Add information missing from GEAR parameters file for ILD SDHCAL detector
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     */
+    pandora::StatusCode SetILD_SDHCALSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap) const;
+
+    /**
+     *  @brief  Specify positions of hcal barrel box gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalBarrelBoxGaps() const;
+
+    /**
+     *  @brief  Specify positions of hcal end cap box gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalEndCapBoxGaps() const;
+
+    /**
+     *  @brief  Specify positions of hcal barrel concentric polygon gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalBarrelConcentricGaps() const;
+
+    /**
+     *  @brief  Create box gaps at regular positions on polygonal prism, oriented along main z axis - ILD specific
+     * 
+     *  @param  symmetryOrder the pandora geometry parameters
+     *  @param  phi0 the phi coordinate
+     *  @param  innerRadius the inner r coordinate
+     *  @param  outerRadius the outer r coordinate
+     *  @param  minZ the minimum z coordinate
+     *  @param  maxZ the maximum z coordinate
+     *  @param  gapWidth the gap width
+     *  @param  vertexOffset position offset for vertex that doesn't point back to origin of xy plane
+     */
+    pandora::StatusCode CreateRegularBoxGaps(unsigned int symmetryOrder, float phi0, float innerRadius, float outerRadius, float minZ,
+        float maxZ, float gapWidth, pandora::CartesianVector vertexOffset = pandora::CartesianVector(0, 0, 0)) const;
+
+    const Settings          m_settings;                     ///< The geometry creator settings
+    const pandora::Pandora *m_pPandora;                     ///< Address of the pandora object to create the geometry
+    gear::GearMgr* _GEAR;
+};
+
+#endif // #ifndef GEOMETRY_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/MCParticleCreator.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/MCParticleCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..0926f870b6dc8738a7122f1a412f2ece40077f7a
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/MCParticleCreator.h
@@ -0,0 +1,88 @@
+/**
+ * 
+ *  @brief  Header file for the mc particle creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef MC_PARTICLE_CREATOR_H
+#define MC_PARTICLE_CREATOR_H 1
+
+#include "edm4hep/MCParticle.h"
+#include "Api/PandoraApi.h"
+
+#include "CaloHitCreator.h"
+#include "TrackCreator.h"
+/**
+ *  @brief  MCParticleCreator class
+ */
+
+class CollectionMaps;
+
+class MCParticleCreator
+{
+public:
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_mcParticleCollections;                ///< The mc particle collections
+        StringVector    m_CaloHitRelationCollections;         ///< The SimCaloHit to CaloHit particle relations
+        StringVector    m_TrackRelationCollections;           ///< The SimTrackerHit to TrackerHit particle relations
+        float           m_bField;                             ///< m_bField
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     MCParticleCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~MCParticleCreator();
+
+    /**
+     *  @brief  Create MCParticles
+     * 
+     */    
+    pandora::StatusCode CreateMCParticles(const CollectionMaps& collectionMaps ) const;
+
+    /**
+     *  @brief  Create Track to mc particle relationships
+     *
+     */
+     pandora::StatusCode CreateTrackToMCParticleRelationships(const CollectionMaps& collectionMaps, const TrackVector &trackVector) const;
+
+     void Reset();
+    /**
+     *  @brief  Create calo hit to mc particle relationships
+     *
+     */
+      pandora::StatusCode CreateCaloHitToMCParticleRelationships(const CollectionMaps& collectionMaps, const CalorimeterHitVector &calorimeterHitVector) const;
+
+private:
+    const Settings          m_settings;                         ///< The mc particle creator settings
+    const pandora::Pandora *m_pPandora;                         ///< Address of the pandora object to create the mc particles
+    const float             m_bField;                           ///< The bfield
+    std::map<unsigned int, const edm4hep::MCParticle*>*  m_id_pMC_map;
+};
+
+inline void MCParticleCreator::Reset()
+{
+    m_id_pMC_map->clear();
+}
+
+#endif // #ifndef MC_PARTICLE_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/PandoraPFAlg.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/PandoraPFAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e447790098de21001fb6c07cc3915af81ca8b8a
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/PandoraPFAlg.h
@@ -0,0 +1,306 @@
+#ifndef PandoraPFAlg_H
+#define PandoraPFAlg_H
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+//#include <gsl/gsl_rng.h>
+#include "edm4hep/ClusterCollection.h"
+#include "edm4hep/ReconstructedParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/SimTrackerHitCollection.h"
+#include "edm4hep/TrackerHitCollection.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/VertexCollection.h"
+#include "edm4hep/TrackCollection.h"
+#include "edm4hep/MCParticle.h" 
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/MCRecoCaloAssociation.h"
+#include "edm4hep/MCRecoTrackerAssociation.h"
+#include "edm4hep/MCRecoTrackerAssociationCollection.h"
+#include "edm4hep/MCRecoCaloAssociationCollection.h"
+#include "edm4hep/MCRecoParticleAssociation.h"
+#include "edm4hep/MCRecoParticleAssociationCollection.h"
+
+#include "Api/PandoraApi.h"
+
+#ifdef MONITORING
+#include "TApplication.h"
+#endif
+
+#include <iostream>
+#include <random>
+#include <string>
+#include <unistd.h>
+
+
+#include "CaloHitCreator.h"
+#include "GeometryCreator.h"
+#include "MCParticleCreator.h"
+#include "PfoCreator.h"
+#include "TrackCreator.h"
+
+#include "TROOT.h"
+#include "TTree.h"
+#include "TFile.h"
+
+
+/* PandoraPFAlg ========== <br>
+ * 
+ */
+namespace pandora {class Pandora;}
+
+
+class CollectionMaps
+{
+public:
+    CollectionMaps();
+    void clear();
+    std::map<std::string, std::vector<edm4hep::MCParticle> >     collectionMap_MC;
+    std::map<std::string, std::vector<edm4hep::CalorimeterHit> > collectionMap_CaloHit;
+    std::map<std::string, std::vector<edm4hep::Vertex> >         collectionMap_Vertex;
+    std::map<std::string, std::vector<edm4hep::Track> >          collectionMap_Track;
+    std::map<std::string, std::vector<edm4hep::MCRecoCaloAssociation> > collectionMap_CaloRel;
+    std::map<std::string, std::vector<edm4hep::MCRecoTrackerAssociation> > collectionMap_TrkRel;
+};
+
+
+
+class PandoraPFAlg : public GaudiAlgorithm
+{
+ 
+public:
+ 
+  PandoraPFAlg(const std::string& name, ISvcLocator* svcLoc);
+ 
+  /** Called at the begin of the job before anything is read.
+   * Use to initialize the processor, e.g. book histograms.
+   */
+  virtual StatusCode initialize() ;
+ 
+  /** Called for every event - the working horse.
+   */
+  virtual StatusCode execute() ; 
+ 
+  /** Called after data processing for clean up.
+   */
+  virtual StatusCode finalize() ;
+ 
+  void FinaliseSteeringParameters(ISvcLocator* svcloc);
+  pandora::StatusCode RegisterUserComponents() const;
+  void Reset();
+  typedef std::vector<float> FloatVector;
+  typedef std::vector<std::string> StringVector;
+
+
+  class Settings
+  {
+  public:
+      /**
+       *  @brief  Default constructor
+       */
+      Settings();
+
+      std::string     m_pandoraSettingsXmlFile;           ///< The pandora settings xml file
+
+      float           m_innerBField;                      ///< The bfield in the main tracker, ecal and hcal, units Tesla
+      float           m_muonBarrelBField;                 ///< The bfield in the muon barrel, units Tesla
+      float           m_muonEndCapBField;                 ///< The bfield in the muon endcap, units Tesla
+
+      FloatVector     m_inputEnergyCorrectionPoints;      ///< The input energy points for non-linearity energy correction
+      FloatVector     m_outputEnergyCorrectionPoints;     ///< The output energy points for non-linearity energy correction
+  };
+
+
+    /**
+     *  @brief  Get address of the pandora instance
+     * 
+     *  @return address of the pandora instance
+     */
+    const pandora::Pandora *GetPandora() const;
+    StatusCode updateMap();
+    StatusCode Ana();
+    StatusCode CreateMCRecoParticleAssociation();
+protected:
+ 
+  typedef std::vector<float> FloatVec;
+
+  int _nEvt ;
+
+ 
+
+  Gaudi::Property< std::string >              m_PandoraSettingsXmlFile { this, "PandoraSettingsDefault_xml", "/junofs/users/wxfang/MyGit/MarlinPandora/scripts/PandoraSettingsDefault_wx.xml" };
+  Gaudi::Property<int>                        m_NEventsToSkip                   { this, "NEventsToSkip", 0 };
+
+  Gaudi::Property< std::vector<std::string> > m_TrackCollections{ this, "TrackCollections", {"MarlinTrkTracks"} };
+  Gaudi::Property< std::vector<std::string> > m_ECalCaloHitCollections{ this, "ECalCaloHitCollections", {"ECALBarrel","ECALEndcap","ECALOther"} };
+  Gaudi::Property< std::vector<std::string> > m_HCalCaloHitCollections{ this, "HCalCaloHitCollections", {"HCALBarrel","HCALEndcap","HCALOther"} };
+  Gaudi::Property< std::vector<std::string> > m_LCalCaloHitCollections{ this, "LCalCaloHitCollections", {"LCAL"} };
+  Gaudi::Property< std::vector<std::string> > m_LHCalCaloHitCollections{ this, "LHCalCaloHitCollections", {"LHCAL"} };
+  Gaudi::Property< std::vector<std::string> > m_MuonCaloHitCollections{ this, "MuonCaloHitCollections", {"MUON"} };
+  Gaudi::Property< std::vector<std::string> > m_MCParticleCollections{ this, "MCParticleCollections", {"MCParticle"} };
+  Gaudi::Property< std::vector<std::string> > m_RelCaloHitCollections{ this, "RelCaloHitCollections", {"RelationCaloHit","RelationMuonHit"} };
+  Gaudi::Property< std::vector<std::string> > m_RelTrackCollections{ this, "RelTrackCollections", {"MarlinTrkTracksMCTruthLink"} };
+  Gaudi::Property< std::vector<std::string> > m_KinkVertexCollections{ this, "KinkVertexCollections", {"KinkVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_ProngVertexCollections{ this, "ProngVertexCollections", {"ProngVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_SplitVertexCollections{ this, "SplitVertexCollections", {"SplitVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_V0VertexCollections{ this, "V0VertexCollections", {"V0Vertices"} };
+  Gaudi::Property< std::string >              m_ClusterCollectionName { this, "ClusterCollectionName", "PandoraClusters" };
+  Gaudi::Property< std::string >              m_PFOCollectionName { this, "PFOCollectionName", "PandoraPFOs" };
+  Gaudi::Property<float>                      m_ECalToMipCalibration{ this, "ECalToMipCalibration", 160.0 };
+  Gaudi::Property<float>                      m_HCalToMipCalibration{ this, "HCalToMipCalibration", 34.8 };
+  Gaudi::Property<float>                      m_ECalMipThreshold{ this, "ECalMipThreshold", 0.5 };
+  Gaudi::Property<float>                      m_HCalMipThreshold{ this, "HCalMipThreshold", 0.3 };
+  Gaudi::Property<float>                      m_ECalToEMGeVCalibration{ this, "ECalToEMGeVCalibration", 1.007 };
+  Gaudi::Property<float>                      m_HCalToEMGeVCalibration{ this, "HCalToEMGeVCalibration", 1.007 };
+  Gaudi::Property<float>                      m_ECalToHadGeVCalibrationBarrel{ this, "ECalToHadGeVCalibrationBarrel", 1.12 };
+  Gaudi::Property<float>                      m_ECalToHadGeVCalibrationEndCap{ this, "ECalToHadGeVCalibrationEndCap", 1.12 };
+  Gaudi::Property<float>                      m_HCalToHadGeVCalibration{ this, "HCalToHadGeVCalibration", 1.07 };
+  Gaudi::Property<float>                      m_MuonToMipCalibration{ this, "MuonToMipCalibration", 10.0 };
+  Gaudi::Property<int>                        m_DigitalMuonHits{ this, "DigitalMuonHits", 0 };
+  Gaudi::Property<float>                      m_MaxHCalHitHadronicEnergy{ this, "MaxHCalHitHadronicEnergy", 1.0 };
+  Gaudi::Property<int>                        m_UseOldTrackStateCalculation{ this, "UseOldTrackStateCalculation", 0 };
+
+
+  Gaudi::Property<float>                      m_AbsorberRadLengthECal{ this, "AbsorberRadLengthECal", 0.2854 };
+  Gaudi::Property<float>                      m_AbsorberIntLengthECal{ this, "AbsorberIntLengthECal", 0.0101 };
+  Gaudi::Property<float>                      m_AbsorberRadLengthHCal{ this, "AbsorberRadLengthHCal", 0.0569 };
+  Gaudi::Property<float>                      m_AbsorberIntLengthHCal{ this, "AbsorberIntLengthHCal", 0.006  };
+  Gaudi::Property<float>                      m_AbsorberRadLengthOther{ this, "AbsorberRadLengthOther", 0.0569  };
+  Gaudi::Property<float>                      m_AbsorberIntLengthOther{ this, "AbsorberIntLengthOther", 0.006  };
+  Gaudi::Property< std::string >              m_StartVertexCollectionName { this, "StartVertexCollectionName", "PandoraPFANewStartVertices" };
+  Gaudi::Property< std::string >              m_StartVertexAlgorithmName { this, "StartVertexAlgorithmName", "PandoraPFANew" };
+  Gaudi::Property<float>                      m_EMStochasticTerm{ this, "EMStochasticTerm", 0.17  };
+  Gaudi::Property<float>                      m_HadStochasticTerm{ this, "HadStochasticTerm", 0.6  };
+  Gaudi::Property<float>                      m_EMConstantTerm{ this, "EMConstantTerm", 0.01  };
+  Gaudi::Property<float>                      m_HadConstantTerm{ this, "HadConstantTerm", 0.03  };
+  Gaudi::Property<float>                      m_MuonHitEnergy{ this, "MuonHitEnergy", 0.5 };
+  Gaudi::Property<int>                        m_NOuterSamplingLayers{ this, "NOuterSamplingLayers", 3 };
+  Gaudi::Property<float>                      m_LayersFromEdgeMaxRearDistance{ this, "LayersFromEdgeMaxRearDistance", 250.f };
+  Gaudi::Property<float>                      m_MuonBarrelBField{ this, "MuonBarrelBField", -1.5f };
+  Gaudi::Property<float>                      m_MuonEndCapBField{ this, "MuonEndCapBField", 0.01f };
+  Gaudi::Property<int>                        m_ShouldFormTrackRelationships{ this, "ShouldFormTrackRelationships", 1 };
+  Gaudi::Property<int>                        m_MinTrackHits{ this, "MinTrackHits", 5 };
+  Gaudi::Property<int>                        m_MinFtdTrackHits{ this, "MinFtdTrackHits", 0 };
+  Gaudi::Property<int>                        m_MaxTrackHits{ this, "MaxTrackHits", 5000 };
+  Gaudi::Property<float>                      m_D0TrackCut{ this, "D0TrackCut", 50. };
+  Gaudi::Property<float>                      m_Z0TrackCut{ this, "Z0TrackCut", 50. };
+  Gaudi::Property<int>                        m_UseNonVertexTracks{ this, "UseNonVertexTracks", 1 };
+  Gaudi::Property<int>                        m_UseUnmatchedNonVertexTracks{ this, "UseUnmatchedNonVertexTracks", 0 };
+  Gaudi::Property<int>                        m_UseUnmatchedVertexTracks{ this, "UseUnmatchedVertexTracks", 1 };
+  Gaudi::Property<float>                      m_UnmatchedVertexTrackMaxEnergy{ this, "UnmatchedVertexTrackMaxEnergy", 5. };
+  Gaudi::Property<float>                      m_D0UnmatchedVertexTrackCut{ this, "D0UnmatchedVertexTrackCut", 5. };
+  Gaudi::Property<float>                      m_Z0UnmatchedVertexTrackCut{ this, "Z0UnmatchedVertexTrackCut", 5. };
+  Gaudi::Property<float>                      m_ZCutForNonVertexTracks{ this, "ZCutForNonVertexTracks", 250. };
+  Gaudi::Property<int>                        m_ReachesECalNTpcHits{ this, "ReachesECalNTpcHits", 11 };
+  Gaudi::Property<int>                        m_ReachesECalNFtdHits{ this, "ReachesECalNFtdHits", 4 };
+  Gaudi::Property<float>                      m_ReachesECalTpcOuterDistance{ this, "ReachesECalTpcOuterDistance", -100. };
+  Gaudi::Property<int>                        m_ReachesECalMinFtdLayer{ this, "ReachesECalMinFtdLayer", 9 };
+  Gaudi::Property<float>                      m_ReachesECalTpcZMaxDistance{ this, "ReachesECalTpcZMaxDistance", -50. };
+  Gaudi::Property<float>                      m_ReachesECalFtdZMaxDistance{ this, "ReachesECalFtdZMaxDistance", -1. };
+  Gaudi::Property<float>                      m_CurvatureToMomentumFactor{ this, "CurvatureToMomentumFactor", 0.3 / 2000. };
+  Gaudi::Property<float>                      m_MinTrackECalDistanceFromIp{ this, "MinTrackECalDistanceFromIp", 100. };
+
+  Gaudi::Property<float>                      m_MaxTrackSigmaPOverP             { this, "MaxTrackSigmaPOverP", 0.15 };
+  Gaudi::Property<float>                      m_MinMomentumForTrackHitChecks    { this, "MinMomentumForTrackHitChecks", 1. };
+  Gaudi::Property<float>                      m_TpcMembraneMaxZ                 { this, "TpcMembraneMaxZ", 10. };
+  Gaudi::Property<float>                      m_MinTpcHitFractionOfExpected     { this, "MinTpcHitFractionOfExpected", 0.20 };
+  Gaudi::Property<int>                        m_MinFtdHitsForTpcHitFraction     { this, "MinFtdHitsForTpcHitFraction", 2 };
+  Gaudi::Property<float>                      m_MaxTpcInnerRDistance            { this, "MaxTpcInnerRDistance", 50.0 };
+  Gaudi::Property<int>                        m_ECalEndCapInnerSymmetryOrder    { this, "ECalEndCapInnerSymmetryOrder", 4 };
+  Gaudi::Property<float>                      m_ECalEndCapInnerPhiCoordinate    { this, "ECalEndCapInnerPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_ECalEndCapOuterSymmetryOrder    { this, "ECalEndCapOuterSymmetryOrder", 8 };
+  Gaudi::Property<float>                      m_ECalEndCapOuterPhiCoordinate    { this, "ECalEndCapOuterPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalEndCapInnerSymmetryOrder    { this, "HCalEndCapInnerSymmetryOrder", 4 };
+  Gaudi::Property<float>                      m_HCalEndCapInnerPhiCoordinate    { this, "HCalEndCapInnerPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalEndCapOuterSymmetryOrder    { this, "HCalEndCapOuterSymmetryOrder", 16 };
+  Gaudi::Property<float>                      m_HCalEndCapOuterPhiCoordinate    { this, "HCalEndCapOuterPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalRingInnerSymmetryOrder      { this, "HCalRingInnerSymmetryOrder",   8  };
+  Gaudi::Property<float>                      m_HCalRingInnerPhiCoordinate      { this, "HCalRingInnerPhiCoordinate",   0. };
+  Gaudi::Property<int>                        m_HCalRingOuterSymmetryOrder      { this, "HCalRingOuterSymmetryOrder",   16 };
+  Gaudi::Property<float>                      m_HCalRingOuterPhiCoordinate      { this, "HCalRingOuterPhiCoordinate",   0. };
+  Gaudi::Property<bool>                       m_StripSplittingOn                { this, "StripSplittingOn", false };
+  Gaudi::Property<bool>                       m_UseEcalScLayers                 { this, "UseEcalScLayers", false };
+  Gaudi::Property<float>                      m_ECalSiToMipCalibration          { this, "ECalSiToMipCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalScToMipCalibration          { this, "ECalScToMipCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalSiMipThreshold              { this, "ECalSiMipThreshold", 0. };
+  Gaudi::Property<float>                      m_ECalScMipThreshold              { this, "ECalScMipThreshold", 0. };
+  Gaudi::Property<float>                      m_ECalSiToEMGeVCalibration        { this, "ECalSiToEMGeVCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalScToEMGeVCalibration        { this, "ECalScToEMGeVCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalSiToHadGeVCalibrationEndCap { this, "ECalSiToHadGeVCalibrationEndCap", 1. };
+  Gaudi::Property<float>                      m_ECalScToHadGeVCalibrationEndCap { this, "ECalScToHadGeVCalibrationEndCap", 1. };
+  Gaudi::Property<float>                      m_ECalSiToHadGeVCalibrationBarrel { this, "ECalSiToHadGeVCalibrationBarrel", 1. };
+  Gaudi::Property<float>                      m_ECalScToHadGeVCalibrationBarrel { this, "ECalScToHadGeVCalibrationBarrel", 1. };
+
+  Gaudi::Property<FloatVector>                m_InputEnergyCorrectionPoints { this, "InputEnergyCorrectionPoints", {} };
+  Gaudi::Property<FloatVector>                m_OutputEnergyCorrectionPoints { this, "OutputEnergyCorrectionPoints", {} };
+
+
+  static pandora::Pandora        *m_pPandora;
+  GeometryCreator                *m_pGeometryCreator;             ///< The geometry creator
+  CaloHitCreator                 *m_pCaloHitCreator;              ///< The calo hit creator
+  TrackCreator                   *m_pTrackCreator;                ///< The track creator
+  MCParticleCreator              *m_pMCParticleCreator;           ///< The mc particle creator
+  PfoCreator                     *m_pPfoCreator;                  ///< The pfo creator
+ 
+  Settings                        m_settings;                     ///< The settings for the pandora pfa new algo
+  CollectionMaps                  *m_CollectionMaps;               ///< The settings for the pandora pfa new algo
+  GeometryCreator::Settings       m_geometryCreatorSettings;      ///< The geometry creator settings
+  TrackCreator::Settings          m_trackCreatorSettings;         ///< The track creator settings
+  CaloHitCreator::Settings        m_caloHitCreatorSettings;       ///< The calo hit creator settings
+  MCParticleCreator::Settings     m_mcParticleCreatorSettings;    ///< The mc particle creator settings
+  PfoCreator::Settings            m_pfoCreatorSettings;           ///< The pfo creator settings
+
+  std::string                     m_detectorName;                 ///< The detector name
+  unsigned int                    m_nRun;                         ///< The run number
+  unsigned int                    m_nEvent;                       ///< The event number
+  //### For Ana #################
+  TFile* m_fout;
+  TTree* m_tree;
+  std::vector<int  > m_pReco_PID;    
+  std::vector<float> m_pReco_mass;
+  std::vector<float> m_pReco_energy;
+  std::vector<float> m_pReco_px;
+  std::vector<float> m_pReco_py;
+  std::vector<float> m_pReco_pz;
+  std::vector<float> m_pReco_charge;
+
+  std::vector<int>   m_mc_p_size;
+  std::vector<int>   m_mc_pid   ;
+  std::vector<float> m_mc_mass  ;
+  std::vector<float> m_mc_px    ;
+  std::vector<float> m_mc_py    ;
+  std::vector<float> m_mc_pz    ;
+  std::vector<float> m_mc_charge;
+  int m_hasConversion;
+
+  Gaudi::Property< std::string >              m_AnaOutput{ this, "AnaOutput", "/junofs/users/wxfang/MyGit/CEPCSW/Reconstruction/PFA/Pandora/GaudiPandora/Ana.root" };
+  //######################
+  
+  DataHandle<edm4hep::MCParticleCollection>     m_mcParCol_r  {"MCParticle", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALBarrel_r{"ECALBarrel", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALEndcap_r{"ECALEndcap", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALOther_r {"ECALOther", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALBarrel_r{"HCALBarrel", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALEndcap_r{"HCALEndcap", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALOther_r {"HCALOther", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_MUON_r      {"MUON", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_LCAL_r      {"LCAL", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_LHCAL_r     {"LHCAL", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_BCAL_r      {"BCAL", Gaudi::DataHandle::Reader, this};
+
+  DataHandle<edm4hep::VertexCollection> m_KinkVertices_r    {"KinkVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_ProngVertices_r   {"ProngVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_SplitVertices_r   {"SplitVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_V0Vertices_r      {"V0Vertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::TrackCollection>  m_MarlinTrkTracks_r {"MarlinTrkTracks",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCRecoCaloAssociationCollection>  m_MCRecoCaloAssociation_r {"MCRecoCaloAssociation",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCRecoTrackerAssociationCollection>  m_MCRecoTrackerAssociation_r {"MCRecoTrackerAssociation",Gaudi::DataHandle::Reader, this};
+
+  DataHandle<edm4hep::ClusterCollection>                m_ClusterCollection_w {"PandoraClusters",Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::ReconstructedParticleCollection>  m_ReconstructedParticleCollection_w {"PandoraPFOs"    ,Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::VertexCollection>                 m_VertexCollection_w {"PandoraPFANewStartVertices",Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::MCRecoParticleAssociationCollection>  m_MCRecoParticleAssociation_w {"pfoMCRecoParticleAssociation",Gaudi::DataHandle::Writer, this};
+
+};
+
+#endif
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/PfoCreator.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/PfoCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..7619cd9fb36210b0ee50bf3413d39c18c4a1782f
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/PfoCreator.h
@@ -0,0 +1,212 @@
+/**
+ *  @brief  Header file for the pfo creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef PFO_CREATOR_H
+#define PFO_CREATOR_H 1
+
+#include "FWCore/DataHandle.h"
+#include "edm4hep/Vector3f.h"
+#include "edm4hep/ClusterCollection.h"
+#include "edm4hep/Cluster.h"
+#include "edm4hep/ReconstructedParticleCollection.h"
+#include "edm4hep/ReconstructedParticle.h"
+#include "edm4hep/VertexCollection.h"
+#include "edm4hep/Vertex.h"
+#include "edm4hep/TrackCollection.h"
+#include "edm4hep/Track.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/CalorimeterHit.h"
+
+#include "ClusterShapes.h"
+#include "Api/PandoraApi.h"
+
+class CollectionMaps;
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  PfoCreator class
+ */
+class PfoCreator
+{
+public:
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        std::string     m_clusterCollectionName;                ///< The name of the cluster output collection
+        std::string     m_pfoCollectionName;                    ///< The name of the pfo output collection
+        std::string     m_startVertexCollectionName;            ///< The name of the start vertex output collection
+        std::string     m_startVertexAlgName;                   ///< The name of the algorithm to fill the start vertex output collection
+        float           m_emStochasticTerm;                     ///< The stochastic term for EM shower energy resolution
+        float           m_hadStochasticTerm;                    ///< The stochastic term for Hadronic shower energy resolution
+        float           m_emConstantTerm;                       ///< The constant term for EM shower energy resolution
+        float           m_hadConstantTerm;                      ///< The constant term for Hadronic shower energy resolution
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     */
+     PfoCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~PfoCreator();
+
+    /**
+     *  @brief  Create particle flow objects
+     * 
+     */    
+    pandora::StatusCode CreateParticleFlowObjects(CollectionMaps& collectionMaps, DataHandle<edm4hep::ClusterCollection>& _pClusterCollection, DataHandle<edm4hep::ReconstructedParticleCollection>& _pReconstructedParticleCollection, DataHandle<edm4hep::VertexCollection>& _pStartVertexCollection);
+
+    CollectionMaps* m_collectionMaps;
+
+private:
+    /**
+     *  @brief  index for the subdetector
+     */
+    enum Index
+    {
+        ECAL_INDEX = 0,
+        HCAL_INDEX = 1,
+        YOKE_INDEX = 2,
+        LCAL_INDEX = 3,
+        LHCAL_INDEX = 4,
+        BCAL_INDEX = 5
+    };
+
+    /**
+     *  @brief  initialise sub detector name strings
+     * 
+     *  @param  subDetectorNames to receive the list of sub detector names
+     */
+    void InitialiseSubDetectorNames(pandora::StringVector &subDetectorNames) const;
+
+    /**
+     *  @brief  Set sub detector energies for a cluster
+     * 
+     *  @param  subDetectorNames the list of sub detector names
+     *  @param  pLcioCluster the address of the cluster to be set sub detector energies
+     *  @param  pandoraCaloHitList the pandora calorimeter hit list
+     *  @param  hitE the vector to receive the energy of hits
+     *  @param  hitX the vector to receive the x position of hits
+     *  @param  hitY the vector to receive the y position of hits
+     *  @param  hitZ the vector to receive the z position of hits
+     */
+    void SetClusterSubDetectorEnergies(const pandora::StringVector &subDetectorNames, edm4hep::Cluster *const pLcioCluster,
+        const pandora::CaloHitList &pandoraCaloHitList, pandora::FloatVector &hitE, pandora::FloatVector &hitX, pandora::FloatVector &hitY,
+        pandora::FloatVector &hitZ) const;
+
+    /**
+     *  @brief  Set cluster energies and errors
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  pPandoraCluster the address of the pandora cluster
+     *  @param  pLcioCluster the address of the cluster to be set energies and erros
+     *  @param  clusterCorrectEnergy a number to receive the cluster correct energy
+     */
+    void SetClusterEnergyAndError(const pandora::ParticleFlowObject *const pPandoraPfo, const pandora::Cluster *const pPandoraCluster, 
+        edm4hep::Cluster *const pLcioCluster, float &clusterCorrectEnergy) const;
+
+    /**
+     *  @brief  Set cluster position, errors and other shape info, by calculating culster shape first
+     * 
+     *  @param  nHitsInCluster number of hits in cluster
+     *  @param  hitE the vector of the energy of hits
+     *  @param  hitX the vector of the x position of hits
+     *  @param  hitY the vector of the y position of hits
+     *  @param  hitZ the vector of the z position of hits
+     *  @param  pLcioCluster the cluster to be set positions and errors
+     *  @param  clusterPosition a CartesianVector to receive the cluster position
+     */
+    void SetClusterPositionAndError(const unsigned int nHitsInCluster, pandora::FloatVector &hitE, pandora::FloatVector &hitX, 
+        pandora::FloatVector &hitY, pandora::FloatVector &hitZ, edm4hep::Cluster *const pLcioCluster, pandora::CartesianVector &clusterPositionVec) const;
+
+    /**
+     *  @brief  Calculate reference point for pfo with tracks
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  referencePoint a CartesianVector to receive the reference point
+     */
+    pandora::StatusCode CalculateTrackBasedReferencePoint(const pandora::ParticleFlowObject *const pPandoraPfo, pandora::CartesianVector &referencePoint) const;
+
+    /**
+     *  @brief  Set reference point of the reconstructed particle
+     * 
+     *  @param  referencePoint a CartesianVector of the reference point
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be reference point
+     */
+    void SetRecoParticleReferencePoint(const pandora::CartesianVector &referencePoint, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Add tracks to reconstructed particle
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be added tracks
+     */
+    void AddTracksToRecoParticle(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Set properties of reconstructed particle from pandora pfo
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo 
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be set properties
+     */
+    void SetRecoParticlePropertiesFromPFO(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Whether parent and daughter tracks are associated with the same pfo
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated with reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool IsValidParentTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether sibling tracks are associated with the same pfo
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated with reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool HasValidSiblingTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether the track is the closest (of those associated with the same pfo) to the interaction point
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated to reconstructed particle
+     * 
+     *  @return boolean
+     */ 
+    bool IsClosestTrackToIP(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether at least one track sibling track is associated to the reconstructed particle 
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated to reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool AreAnyOtherSiblingsInList(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    const Settings              m_settings;                         ///< The pfo creator settings
+    const pandora::Pandora      *m_pPandora;                        ///< Address of the pandora object from which to extract the pfos
+};
+
+#endif // #ifndef PFO_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/TrackCreator.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/TrackCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..de380e3f6d4b921a422ad6414d3d772b0f755820
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/TrackCreator.h
@@ -0,0 +1,316 @@
+/**
+ *  @brief  Header file for the track creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef TRACK_CREATOR_H
+#define TRACK_CREATOR_H 1
+
+
+
+
+#include "GaudiKernel/ISvcLocator.h"
+
+#include "edm4hep/Track.h"
+#include "edm4hep/TrackConst.h"
+#include "edm4hep/TrackState.h"
+#include "edm4hep/ReconstructedParticleConst.h"
+
+#include "Api/PandoraApi.h"
+#include "Objects/Helix.h"
+
+namespace gear { class GearMgr; }
+
+class CollectionMaps;
+
+typedef std::vector<const edm4hep::Track *> TrackVector;
+typedef std::set<unsigned int> TrackList;
+typedef std::map<edm4hep::ConstTrack, int> TrackToPidMap;
+/*
+inline LCCollectionVec *newTrkCol(const std::string &name, LCEvent *evt , bool isSubset)
+{
+    LCCollectionVec* col = new LCCollectionVec( LCIO::TRACK ) ;
+
+    LCFlagImpl hitFlag(0) ;
+    hitFlag.setBit( LCIO::TRBIT_HITS ) ;
+    col->setFlag( hitFlag.getFlag()  ) ;
+    evt->addCollection( col , name ) ;
+    col->setSubset( isSubset ) ;
+
+    return col ;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  TrackCreator class
+ */
+class TrackCreator
+{
+public:
+    typedef std::vector<double> DoubleVector;
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_trackCollections;                     ///< The reconstructed track collections
+        StringVector    m_kinkVertexCollections;                ///< The kink vertex collections
+        StringVector    m_prongVertexCollections;               ///< The prong vertex collections
+        StringVector    m_splitVertexCollections;               ///< The split vertex collections
+        StringVector    m_v0VertexCollections;                  ///< The v0 vertex collections
+
+        StringVector    m_prongSplitVertexCollections;          ///< Concatenated list of prong and split vertex collections
+        int             m_shouldFormTrackRelationships;         ///< Whether to form pandora track relationships using v0 and kink info
+
+        int             m_minTrackHits;                         ///< Track quality cut: the minimum number of track hits
+        int             m_minFtdTrackHits;                      ///< Track quality cut: the minimum number of FTD track hits for FTD only tracks
+        int             m_maxTrackHits;                         ///< Track quality cut: the maximum number of track hits
+
+        float           m_d0TrackCut;                           ///< Track d0 cut used to determine whether track can be used to form pfo
+        float           m_z0TrackCut;                           ///< Track z0 cut used to determine whether track can be used to form pfo
+
+        int             m_usingNonVertexTracks;                 ///< Whether can form pfos from tracks that don't start at vertex
+        int             m_usingUnmatchedNonVertexTracks;        ///< Whether can form pfos from unmatched tracks that don't start at vertex
+        int             m_usingUnmatchedVertexTracks;           ///< Whether can form pfos from unmatched tracks that start at vertex
+        float           m_unmatchedVertexTrackMaxEnergy;        ///< Maximum energy for unmatched vertex track
+
+        float           m_d0UnmatchedVertexTrackCut;            ///< d0 cut used to determine whether unmatched vertex track can form pfo
+        float           m_z0UnmatchedVertexTrackCut;            ///< z0 cut used to determine whether unmatched vertex track can form pfo
+        float           m_zCutForNonVertexTracks;               ///< Non vtx track z cut to determine whether track can be used to form pfo
+
+        int             m_reachesECalNTpcHits;                  ///< Minimum number of tpc hits to consider track as reaching ecal
+        int             m_reachesECalNFtdHits;                  ///< Minimum number of ftd hits to consider track as reaching ecal
+        float           m_reachesECalTpcOuterDistance;          ///< Max distance from track to tpc r max to id whether track reaches ecal
+        int             m_reachesECalMinFtdLayer;               ///< Min layer in Ftd for tracks to be considered to have reached decal
+        float           m_reachesECalTpcZMaxDistance;           ///< Max distance from track to tpc z max to id whether track reaches ecal
+        float           m_reachesECalFtdZMaxDistance;           ///< Max distance from track hit to ftd z position to identify ftd hits
+        float           m_curvatureToMomentumFactor;            ///< Constant relating track curvature in b field to momentum
+
+        float           m_minTrackECalDistanceFromIp;           ///< Sanity check on separation between ip and track projected ecal position
+        float           m_maxTrackSigmaPOverP;                  ///< Track fraction momentum error cut
+        float           m_minMomentumForTrackHitChecks;         ///< Min track momentum required to perform final quality checks on number of hits
+
+        float           m_tpcMembraneMaxZ;                      ///< Tpc membrane max z coordinate
+        float           m_maxTpcInnerRDistance;                 ///< Track cut on distance from tpc inner r to id whether track can form pfo
+        float           m_minTpcHitFractionOfExpected;          ///< Minimum fraction of TPC hits compared to expected
+        int             m_minFtdHitsForTpcHitFraction;          ///< Minimum number of FTD hits to ignore TPC hit fraction
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     */
+     TrackCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~TrackCreator();
+
+    /**
+     *  @brief  Create associations between tracks, V0s, kinks, etc
+     * 
+     */
+    pandora::StatusCode CreateTrackAssociations(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create tracks, insert user code here
+     * 
+     */
+    pandora::StatusCode CreateTracks(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get the track vector
+     * 
+     *  @return The track vector
+     */
+    const TrackVector &GetTrackVector() const;
+
+    /**
+     *  @brief  Reset the track creator
+     */
+    void Reset();
+
+private:
+    /**
+     *  @brief  Extract kink information from specified lcio collections
+     * 
+     */
+    pandora::StatusCode ExtractKinks(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Extract prong and split information from specified lcio collections
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode ExtractProngsAndSplits(const EVENT::LCEvent *const pLCEvent);
+
+    /**
+     *  @brief  Extract v0 information from specified lcio collections
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+   //pandora::StatusCode ExtractV0s(const EVENT::LCEvent *const pLCEvent);
+
+    /**
+     *  @brief  Whether the track vertex conflicts with previously provided relationship information
+     * 
+     *  @param  trackVec the vector of tracks associated with the vertex
+     */
+    bool IsConflictingRelationship(const edm4hep::ConstReconstructedParticle &Particle) const;
+
+    /**
+     *  @brief  Whether a track is a v0 track
+     * 
+     * 
+     */
+    bool IsV0(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Whether a track is a parent track
+     * 
+     * 
+     */
+    bool IsParent(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Whether a track is a daughter track
+     * 
+     */
+    bool IsDaughter(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Copy track states stored in tracks to pandora track parameters
+     * 
+     */
+    void GetTrackStates(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Copy track state from track state instance to pandora input track state
+     * 
+     */
+    void CopyTrackState(const edm4hep::TrackState & pTrackState, pandora::InputTrackState &inputTrackState) const;
+
+    /**
+     *  @brief  Obtain track time when it reaches ECAL
+     * 
+     */
+    float CalculateTrackTimeAtCalorimeter(const edm4hep::Track *const pTrack) const;
+
+    /**
+     *  @brief  Decide whether track reaches the ecal surface
+     * 
+     */
+    void TrackReachesECAL(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Determine whether a track can be used to form a pfo under the following conditions:
+     *          1) if the track proves to be associated with a cluster, OR
+     *          2) if the track proves to have no cluster associations
+     * 
+     */
+    void DefineTrackPfoUsage(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Whether track passes the quality cuts required in order to be used to form a pfo
+     * 
+     * 
+     *  @return boolean
+     */
+    bool PassesQualityCuts(const edm4hep::Track *const pTrack, const PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Get number of hits in TPC of a track
+     * 
+     */
+    int GetNTpcHits(const edm4hep::Track *const pTrack) const;
+
+    /**
+     *  @brief  Get number of hits in FTD of a track
+     * 
+     */
+    int GetNFtdHits(const edm4hep::Track *const pTrack) const;
+
+    const Settings          m_settings;                     ///< The track creator settings
+    const pandora::Pandora *m_pPandora;                     ///< Address of the pandora object to create tracks and track relationships
+
+    float             m_bField;                       ///< The bfield
+
+    float             m_tpcInnerR;                    ///< The tpc inner radius
+    float             m_tpcOuterR;                    ///< The tpc outer radius
+    unsigned int      m_tpcMaxRow;                    ///< The tpc maximum row number
+    float             m_tpcZmax;                      ///< The tpc maximum z coordinate
+    float                   m_cosTpc;                       ///< Cos(theta) value at end of tpc
+
+    DoubleVector            m_ftdInnerRadii;                ///< List of ftd inner radii
+    DoubleVector            m_ftdOuterRadii;                ///< List of ftd outer radii
+    DoubleVector            m_ftdZPositions;                ///< List of ftd z positions
+    unsigned int            m_nFtdLayers;                   ///< Number of ftd layers
+    float                   m_tanLambdaFtd;                 ///< Tan lambda for first ftd layer
+
+    int               m_eCalBarrelInnerSymmetry;      ///< ECal barrel inner symmetry order
+    float             m_eCalBarrelInnerPhi0;          ///< ECal barrel inner phi 0
+    float             m_eCalBarrelInnerR;             ///< ECal barrel inner radius
+    float             m_eCalEndCapInnerZ;             ///< ECal endcap inner z
+
+    float                   m_minEtdZPosition;              ///< Min etd z position
+    float                   m_minSetRadius;                 ///< Min set radius
+
+    TrackVector             m_trackVector;                  ///< The track vector
+    TrackList               m_v0TrackList;                  ///< The list of v0 tracks
+    TrackList               m_parentTrackList;              ///< The list of parent tracks
+    TrackList               m_daughterTrackList;            ///< The list of daughter tracks
+    TrackToPidMap           m_trackToPidMap;                ///< The map from track addresses to particle ids, where set by kinks/V0s
+    gear::GearMgr* _GEAR;
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline const TrackVector &TrackCreator::GetTrackVector() const
+{
+    return m_trackVector;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline void TrackCreator::Reset()
+{
+    m_trackVector.clear();
+    m_v0TrackList.clear();
+    m_parentTrackList.clear();
+    m_daughterTrackList.clear();
+    m_trackToPidMap.clear();
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline bool TrackCreator::IsV0(unsigned int pTrack_id) const // should check here, if id is correct one to do this
+{
+    return (m_v0TrackList.end() != m_v0TrackList.find(pTrack_id));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline bool TrackCreator::IsParent(unsigned int pTrack_id) const
+{
+    return (m_parentTrackList.end() != m_parentTrackList.find(pTrack_id));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline bool TrackCreator::IsDaughter(unsigned int pTrack_id) const
+{
+    return (m_daughterTrackList.end() != m_daughterTrackList.find(pTrack_id));
+}
+
+#endif // #ifndef TRACK_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/Utility.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/Utility.h
new file mode 100644
index 0000000000000000000000000000000000000000..0bd75b5d94f4725581e44176a02fbb94a99088fa
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/Utility.h
@@ -0,0 +1,6 @@
+#ifndef MYUTILITY
+#define MYUTILITY 1
+
+#include <sstream>
+std::string Convert (float number);
+#endif
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/include/cellIDDecoder.h b/Reconstruction/PFA/Pandora/GaudiPandora/include/cellIDDecoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..6503f352d754fdac3279dab087abd6a359994145
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/include/cellIDDecoder.h
@@ -0,0 +1,120 @@
+#ifndef cellIDDecoder_h
+#define cellIDDecoder_h 1
+
+#include "EVENT/LCCollection.h"
+#include "UTIL/BitField64.h"
+#include "lcio.h"
+#include <string>
+
+// fixes problem in gcc 4.0.3
+#include "EVENT/LCParameters.h"
+
+//##################### changed for EMD4HEP ########
+
+namespace ID_UTIL{
+
+
+  /** Convenient class for decoding cellIDs from collection parameter LCIO::CellIDEncoding.
+   *  See UTIL::BitField64 for a description of the encoding string. 
+   * 
+   *  @see BitField64
+   *  @version $Id: CellIDDecoder.h,v 1.9.16.1 2011-03-04 14:09:07 engels Exp $
+   */
+  template <class T> 
+  class CellIDDecoder {
+    
+  public:  
+
+    CellIDDecoder() = default ;
+    CellIDDecoder(const CellIDDecoder& ) = delete ;
+    CellIDDecoder& operator=(const CellIDDecoder& ) = delete ;
+    
+
+    /** Constructor takes encoding string as argument.
+     */
+  CellIDDecoder( const std::string& encoder_str ) : _oldHit(0) {
+      
+      if( encoder_str.length() == 0 ){
+      	throw( lcio::Exception( "CellIDDecoder : string of length zero provided as encoder string" ) ) ;
+      }
+      _b = new UTIL::BitField64( encoder_str ) ; 
+      
+    }
+    
+    /** Constructor reads encoding string from collection parameter LCIO::CellIDEncoding.
+     */
+    CellIDDecoder( const EVENT::LCCollection* col ) : _oldHit(0) {
+      
+      std::string initString("") ; 
+
+      if( col !=0 ) 
+	initString = col->getParameters().getStringVal(  lcio::LCIO::CellIDEncoding ) ;
+      
+      if( initString.size() == 0 ) {
+	
+	initString = _defaultEncoding ;
+
+	std::cout << "    ----------------------------------------- " << std::endl  
+		  << "       WARNING: CellIDDecoder - no CellIDEncoding parameter in collection ! " 
+		  << std::endl 
+		  << "         -> using default : \"" << initString << "\"" 
+		  << std::endl 
+		  << "    ------------------------------------------ "  
+		  << std::endl ;
+      }
+      
+      _b = new UTIL::BitField64(  initString ) ; 
+    }
+    
+    ~CellIDDecoder(){ 
+      
+      delete _b ;
+    } 
+    
+    
+    /** Provides access to the bit fields, e.g. <br>
+     *   int layer =  myCellIDEncoding( hit )[ "layer" ] ;
+     * 
+     */
+    inline const UTIL::BitField64 & operator()( const T* hit ){  
+      
+      if( hit != _oldHit && hit ) {
+	auto id = hit->getCellID();
+        unsigned int id0 = id&0xFFFFFFFF;
+        unsigned int id1 = id>>32;
+	//lcio::long64 val = lcio::long64( hit->getCellID0() & 0xffffffff ) | ( lcio::long64( hit->getCellID1() ) << 32      ) ;
+	lcio::long64 val = lcio::long64( id0 & 0xffffffff ) | ( lcio::long64( id1 ) << 32      ) ;
+	
+	_b->setValue( val ) ;
+
+	_oldHit = hit ;
+      }
+      
+      return  *_b ;
+    }
+    
+
+    /** This can be used to set the default encoding that is used if no
+     *  CellIDEncoding parameter is set in the collection, e.g. in older lcio files.
+     */ 
+    static void setDefaultEncoding(const std::string& defaultEncoding ) {
+
+      _defaultEncoding = std::string( defaultEncoding ) ;
+    }
+    
+  protected:
+    UTIL::BitField64* _b{} ;
+    const T* _oldHit{NULL} ;
+    
+    static std::string _defaultEncoding;
+  } ; 
+  
+  template <class T>
+  std::string CellIDDecoder<T>::_defaultEncoding
+  = std::string("byte0:8,byte1:8,byte2:8,byte3:8,byte4:8,byte5:8,byte6:8,byte7:8") ;
+
+  
+} // namespace
+#endif
+
+
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/CaloHitCreator.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/CaloHitCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c7fb1da1bcbc516ee597faf3b04d6f8eec33c4a
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/CaloHitCreator.cpp
@@ -0,0 +1,823 @@
+/**
+ * 
+ *  @brief  Implementation of the calo hit creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "gear/GearParameters.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/GearDistanceProperties.h"
+#include "gear/GearPointProperties.h"
+#include "gear/GEAR.h"
+#include "gear/TPCParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/LayerLayout.h"
+
+#include "cellIDDecoder.h"
+#include "GaudiKernel/IService.h"
+#include "GearSvc/IGearSvc.h"
+
+#include "PandoraPFAlg.h"
+#include "CaloHitCreator.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+
+CaloHitCreator::CaloHitCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc, bool encoder_style) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+    m_encoder_str = ""; 
+    m_encoder_str_MUON = ""; 
+    m_encoder_str_LCal = ""; 
+    m_encoder_str_LHCal = ""; 
+    if(encoder_style==0) // LCIO style
+    {
+        m_encoder_str     = "M:3,S-1:3,I:9,J:9,K-1:6";
+        m_encoder_str_MUON="S-1:4,M:3,K-1:6,I:16,GRZone:3,J:32:16";
+        m_encoder_str_LCal="I:10,J:10,K:10,S-1:2";
+        m_encoder_str_LHCal=m_encoder_str;
+    }
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+
+
+    m_eCalBarrelOuterZ        = (_GEAR->getEcalBarrelParameters().getExtent()[3]);
+    m_hCalBarrelOuterZ        = (_GEAR->getHcalBarrelParameters().getExtent()[3]);
+    m_muonBarrelOuterZ        = (_GEAR->getYokeBarrelParameters().getExtent()[3]);
+    m_coilOuterR              = (_GEAR->getGearParameters("CoilParameters").getDoubleVal("Coil_cryostat_outer_radius"));
+    m_eCalBarrelInnerPhi0     = (_GEAR->getEcalBarrelParameters().getPhi0());
+    m_eCalBarrelInnerSymmetry = (_GEAR->getEcalBarrelParameters().getSymmetryOrder());
+    m_hCalBarrelInnerPhi0     = (_GEAR->getHcalBarrelParameters().getPhi0());
+    m_hCalBarrelInnerSymmetry = (_GEAR->getHcalBarrelParameters().getSymmetryOrder());
+    m_muonBarrelInnerPhi0     = (_GEAR->getYokeBarrelParameters().getPhi0());
+    m_muonBarrelInnerSymmetry = (_GEAR->getYokeBarrelParameters().getSymmetryOrder());
+    m_hCalEndCapOuterR        = (_GEAR->getHcalEndcapParameters().getExtent()[1]);
+    m_hCalEndCapOuterZ        = (_GEAR->getHcalEndcapParameters().getExtent()[3]);
+    m_hCalBarrelOuterR        = (_GEAR->getHcalBarrelParameters().getExtent()[1]);
+    m_hCalBarrelOuterPhi0     =((std::find(_GEAR->getHcalBarrelParameters().getIntKeys().begin(),
+        _GEAR->getHcalBarrelParameters().getIntKeys().end(),
+        "Hcal_outer_polygon_phi0") != _GEAR->getHcalBarrelParameters().getIntKeys().end() ?
+        _GEAR->getHcalBarrelParameters().getIntVal("Hcal_outer_polygon_phi0")
+        : 0));
+    m_hCalBarrelOuterSymmetry = ((std::find(_GEAR->getHcalBarrelParameters().getIntKeys().begin(),
+        _GEAR->getHcalBarrelParameters().getIntKeys().end(),
+        "Hcal_outer_polygon_order") != _GEAR->getHcalBarrelParameters().getIntKeys().end() ?
+        _GEAR->getHcalBarrelParameters().getIntVal("Hcal_outer_polygon_order")
+        : 0));
+
+
+    const gear::LayerLayout &hCalEndCapLayerLayout(_GEAR->getHcalEndcapParameters().getLayerLayout());
+    const gear::LayerLayout &hCalBarrelLayerLayout(_GEAR->getHcalBarrelParameters().getLayerLayout()); 
+    m_hCalEndCapLayerThickness = hCalEndCapLayerLayout.getThickness(hCalEndCapLayerLayout.getNLayers() - 1);
+    m_hCalBarrelLayerThickness = hCalBarrelLayerLayout.getThickness(hCalBarrelLayerLayout.getNLayers() - 1);
+    if ((m_hCalEndCapLayerThickness < std::numeric_limits<float>::epsilon()) || (m_hCalBarrelLayerThickness < std::numeric_limits<float>::epsilon()))
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+
+
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+CaloHitCreator::~CaloHitCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateCaloHits(const CollectionMaps& collectionMaps)
+{
+    
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateECalCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateMuonCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateLCalCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateLHCalCaloHits(collectionMaps));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateECalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_eCalCaloHitCollections.begin(), iterEnd = m_settings.m_eCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getEcalEndcapParameters().getLayerLayout());
+            const gear::LayerLayout &barrelLayerLayout(_GEAR->getEcalBarrelParameters().getLayerLayout()); 
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str);
+            const std::string layerCodingString(m_encoder_str);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("CreateECalCaloHits pCaloHit Collection type mismatch");
+
+                    float eCalToMip(m_settings.m_eCalToMip), eCalMipThreshold(m_settings.m_eCalMipThreshold), eCalToEMGeV(m_settings.m_eCalToEMGeV),
+                        eCalToHadGeVBarrel(m_settings.m_eCalToHadGeVBarrel), eCalToHadGeVEndCap(m_settings.m_eCalToHadGeVEndCap);
+
+                    // Hybrid ECAL including pure ScECAL.
+                    if (m_settings.m_useEcalScLayers)
+                    {
+                        std::string collectionName(*iter);
+                        std::transform(collectionName.begin(), collectionName.end(), collectionName.begin(), ::tolower);
+
+                        if (collectionName.find("ecal", 0) == std::string::npos)
+                            std::cout << "WARNING: mismatching hybrid Ecal collection name. " << collectionName << std::endl;
+
+                        if (collectionName.find("si", 0) != std::string::npos)
+                        {
+                             eCalToMip = m_settings.m_eCalSiToMip;
+                             eCalMipThreshold = m_settings.m_eCalSiMipThreshold;
+                             eCalToEMGeV = m_settings.m_eCalSiToEMGeV;
+                             eCalToHadGeVBarrel = m_settings.m_eCalSiToHadGeVBarrel;
+                             eCalToHadGeVEndCap = m_settings.m_eCalSiToHadGeVEndCap;
+                        }
+                        else if (collectionName.find("sc", 0) != std::string::npos)
+                        {
+                             eCalToMip = m_settings.m_eCalScToMip;
+                             eCalMipThreshold = m_settings.m_eCalScMipThreshold;
+                             eCalToEMGeV = m_settings.m_eCalScToEMGeV;
+                             eCalToHadGeVBarrel = m_settings.m_eCalScToHadGeVBarrel;
+                             eCalToHadGeVEndCap = m_settings.m_eCalScToHadGeVEndCap;
+                        }
+                    }
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::ECAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()] + 1;
+                    caloHitParameters.m_isInOuterSamplingLayer = false;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+
+                    if (std::fabs(pCaloHit->getPosition()[2]) < m_eCalBarrelOuterZ)
+                    {
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_eCalBarrelInnerSymmetry, m_eCalBarrelInnerPhi0,
+                            cellIdDecoder(pCaloHit)[ staveCoding], caloHitParameters, absorberCorrection);
+
+                        caloHitParameters.m_hadronicEnergy = eCalToHadGeVBarrel * pCaloHit->getEnergy();
+                    }
+                    else
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                        caloHitParameters.m_hadronicEnergy = eCalToHadGeVEndCap * pCaloHit->getEnergy();
+                    }
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * eCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < eCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_electromagneticEnergy = eCalToEMGeV * pCaloHit->getEnergy();
+
+                    // ATTN If using strip splitting, must correct cell sizes for use in PFA to minimum of strip width and strip length
+                    if (m_settings.m_stripSplittingOn)
+                    {
+                        const float splitCellSize(std::min(caloHitParameters.m_cellSize0.Get(), caloHitParameters.m_cellSize1.Get()));
+                        caloHitParameters.m_cellSize0 = splitCellSize;
+                        caloHitParameters.m_cellSize1 = splitCellSize;
+                    }
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"Failed to extract ecal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"Failed to extract ecal calo hit" <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<< "Failed to extract ecal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateHCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_hCalCaloHitCollections.begin(), iterEnd = m_settings.m_hCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getHcalEndcapParameters().getLayerLayout());
+            const gear::LayerLayout &barrelLayerLayout(_GEAR->getHcalBarrelParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str);
+            const std::string layerCodingString(m_encoder_str);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("CreateHCalCaloHits Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::HCAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = (this->GetNLayersFromEdge(pCaloHit) <= m_settings.m_nOuterSamplingLayers);
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+
+                    if (std::fabs(pCaloHit->getPosition()[2]) < m_hCalBarrelOuterZ)
+                    {
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_hCalBarrelInnerSymmetry, m_hCalBarrelInnerPhi0,
+                            m_hCalBarrelInnerSymmetry - int(cellIdDecoder(pCaloHit)[ staveCoding] / 2), caloHitParameters, absorberCorrection);
+                    }
+                    else
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_hCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_hCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_hadronicEnergy = std::min(m_settings.m_hCalToHadGeV * pCaloHit->getEnergy(), m_settings.m_maxHCalHitHadronicEnergy);
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_hCalToEMGeV * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract hcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"Failed to extract hcal calo hit" << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract hcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateMuonCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_muonCaloHitCollections.begin(), iterEnd = m_settings.m_muonCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getYokeEndcapParameters().getLayerLayout());
+            const gear::LayerLayout &barrelLayerLayout(_GEAR->getYokeBarrelParameters().getLayerLayout()); 
+            const gear::LayerLayout &plugLayerLayout(_GEAR->getYokePlugParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_MUON);
+            const std::string layerCodingString(m_encoder_str_MUON);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("Muon Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::MUON;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()] + 1;
+                    caloHitParameters.m_isInOuterSamplingLayer = true;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    const float radius(std::sqrt(pCaloHit->getPosition()[0] * pCaloHit->getPosition()[0] +
+                        pCaloHit->getPosition()[1] * pCaloHit->getPosition()[1]));
+
+                    const bool isWithinCoil(radius < m_coilOuterR);
+                    const bool isInBarrelRegion(std::fabs(pCaloHit->getPosition()[2]) < m_muonBarrelOuterZ);
+
+                    float absorberCorrection(1.);
+
+                    if (isInBarrelRegion && isWithinCoil)
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, plugLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+                    else if (isInBarrelRegion)
+                    {
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_muonBarrelInnerSymmetry, m_muonBarrelInnerPhi0,
+                            cellIdDecoder(pCaloHit)[ staveCoding ], caloHitParameters, absorberCorrection);
+                    }
+                    else
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+
+                    if (m_settings.m_muonDigitalHits > 0)
+                    {
+                        caloHitParameters.m_isDigital = true;
+                        caloHitParameters.m_inputEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_hadronicEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_electromagneticEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_mipEquivalentEnergy = 1.f;
+                    }
+                    else
+                    {
+                        caloHitParameters.m_isDigital = false;
+                        caloHitParameters.m_inputEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_hadronicEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_electromagneticEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_muonToMip;
+                    }
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract muon hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract muon hit"  << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract muon hit collection: " << *iter  << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateLCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_lCalCaloHitCollections.begin(), iterEnd = m_settings.m_lCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getLcalParameters().getLayerLayout()); 
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_LCal);
+            const std::string layerCodingString(m_encoder_str_LCal);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("LCal Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::ECAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = false;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+                    this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_eCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_eCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_eCalToEMGeV * pCaloHit->getEnergy();
+                    caloHitParameters.m_hadronicEnergy = m_settings.m_eCalToHadGeVEndCap * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract lcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract lcal calo hit" << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract lcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateLHCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_lHCalCaloHitCollections.begin(), iterEnd = m_settings.m_lHCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getLHcalParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_LHCal);
+            const std::string layerCodingString(m_encoder_str_LHCal);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("LHCal Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::HCAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = (this->GetNLayersFromEdge(pCaloHit) <= m_settings.m_nOuterSamplingLayers);
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+                    this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_hCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_hCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_hadronicEnergy = std::min(m_settings.m_hCalToHadGeV * pCaloHit->getEnergy(), m_settings.m_maxHCalHitHadronicEnergy);
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_hCalToEMGeV * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract lhcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract lhcal calo hit" << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract lhcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetCommonCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, PandoraApi::CaloHit::Parameters &caloHitParameters) const
+{
+    const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+    const pandora::CartesianVector positionVector(pCaloHitPosition[0], pCaloHitPosition[1], pCaloHitPosition[2]);
+
+    caloHitParameters.m_cellGeometry = pandora::RECTANGULAR;
+    caloHitParameters.m_positionVector = positionVector;
+    caloHitParameters.m_expectedDirection = positionVector.GetUnitVector();
+    caloHitParameters.m_pParentAddress = pCaloHit;
+    caloHitParameters.m_inputEnergy = pCaloHit->getEnergy();
+    caloHitParameters.m_time = pCaloHit->getTime();
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetEndCapCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+    PandoraApi::CaloHit::Parameters &caloHitParameters, float &absorberCorrection) const
+{
+    caloHitParameters.m_hitRegion = pandora::ENDCAP;
+
+    const int physicalLayer(std::min(static_cast<int>(caloHitParameters.m_layer.Get()), layerLayout.getNLayers() - 1));
+    caloHitParameters.m_cellSize0 = layerLayout.getCellSize0(physicalLayer);
+    caloHitParameters.m_cellSize1 = layerLayout.getCellSize1(physicalLayer);
+    caloHitParameters.m_cellThickness = layerLayout.getThickness(physicalLayer);
+
+    const float radiationLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    const float layerAbsorberThickness(layerLayout.getAbsorberThickness(physicalLayer));
+    caloHitParameters.m_nCellRadiationLengths = radiationLength * layerAbsorberThickness;
+    caloHitParameters.m_nCellInteractionLengths = interactionLength * layerAbsorberThickness;
+
+    if (caloHitParameters.m_nCellRadiationLengths.Get() < std::numeric_limits<float>::epsilon() || caloHitParameters.m_nCellInteractionLengths.Get() < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"WARNING CaloHitCreator::GetEndCapCaloHitProperties Calo hit has 0 radiation length or interaction length: \
+            not creating a Pandora calo hit." << std::endl;
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    absorberCorrection = 1.;
+    for (unsigned int i = 0, iMax = layerLayout.getNLayers(); i < iMax; ++i)
+    {
+        const float absorberThickness(layerLayout.getAbsorberThickness(i));
+
+        if (absorberThickness < std::numeric_limits<float>::epsilon())
+            continue;
+
+        if (layerAbsorberThickness > std::numeric_limits<float>::epsilon())
+            absorberCorrection = absorberThickness / layerAbsorberThickness;
+
+        break;
+    }
+
+    caloHitParameters.m_cellNormalVector = (pCaloHit->getPosition()[2] > 0) ? pandora::CartesianVector(0, 0, 1) :
+        pandora::CartesianVector(0, 0, -1);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+    unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+    float &absorberCorrection) const
+{
+    caloHitParameters.m_hitRegion = pandora::BARREL;
+
+    const int physicalLayer(std::min(static_cast<int>(caloHitParameters.m_layer.Get()), layerLayout.getNLayers() - 1));
+    caloHitParameters.m_cellSize0 = layerLayout.getCellSize0(physicalLayer);
+    caloHitParameters.m_cellSize1 = layerLayout.getCellSize1(physicalLayer);
+    caloHitParameters.m_cellThickness = layerLayout.getThickness(physicalLayer);
+
+    const float radiationLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    const float layerAbsorberThickness(layerLayout.getAbsorberThickness(physicalLayer));
+    caloHitParameters.m_nCellRadiationLengths = radiationLength * layerAbsorberThickness;
+    caloHitParameters.m_nCellInteractionLengths = interactionLength * layerAbsorberThickness;
+
+    if (caloHitParameters.m_nCellRadiationLengths.Get() < std::numeric_limits<float>::epsilon() || caloHitParameters.m_nCellInteractionLengths.Get() < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"WARNIN CaloHitCreator::GetBarrelCaloHitProperties Calo hit has 0 radiation length or interaction length: \
+            not creating a Pandora calo hit." << std::endl;
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    absorberCorrection = 1.;
+    for (unsigned int i = 0, iMax = layerLayout.getNLayers(); i < iMax; ++i)
+    {
+        const float absorberThickness(layerLayout.getAbsorberThickness(i));
+
+        if (absorberThickness < std::numeric_limits<float>::epsilon())
+            continue;
+
+        if (layerAbsorberThickness > std::numeric_limits<float>::epsilon())
+            absorberCorrection = absorberThickness / layerAbsorberThickness;
+
+        break;
+    }
+
+    if (barrelSymmetryOrder > 2)
+    {
+        const float phi = barrelPhi0 + (2. * M_PI * static_cast<float>(staveNumber) / static_cast<float>(barrelSymmetryOrder));
+        caloHitParameters.m_cellNormalVector = pandora::CartesianVector(-std::sin(phi), std::cos(phi), 0);
+    }
+    else
+    {
+        const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+
+        if (pCaloHitPosition[1] != 0)
+        {
+            const float phi = barrelPhi0 + std::atan(pCaloHitPosition[0] / pCaloHitPosition[1]);
+            caloHitParameters.m_cellNormalVector = pandora::CartesianVector(std::sin(phi), std::cos(phi), 0);
+        }
+        else
+        {
+            caloHitParameters.m_cellNormalVector = (pCaloHitPosition[0] > 0) ? pandora::CartesianVector(1, 0, 0) :
+                pandora::CartesianVector(-1, 0, 0);
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+int CaloHitCreator::GetNLayersFromEdge(const edm4hep::CalorimeterHit *const pCaloHit) const
+{
+    // Calo hit coordinate calculations
+    const float barrelMaximumRadius(this->GetMaximumRadius(pCaloHit, m_hCalBarrelOuterSymmetry, m_hCalBarrelOuterPhi0));
+    const float endCapMaximumRadius(this->GetMaximumRadius(pCaloHit, m_settings.m_hCalEndCapInnerSymmetryOrder, m_settings.m_hCalEndCapInnerPhiCoordinate));
+    const float caloHitAbsZ(std::fabs(pCaloHit->getPosition()[2]));
+
+    // Distance from radial outer
+    float radialDistanceToEdge(std::numeric_limits<float>::max());
+
+    if (caloHitAbsZ < m_eCalBarrelOuterZ)
+    {
+        radialDistanceToEdge = (m_hCalBarrelOuterR - barrelMaximumRadius) / m_hCalBarrelLayerThickness;
+    }
+    else
+    {
+        radialDistanceToEdge = (m_hCalEndCapOuterR - endCapMaximumRadius) / m_hCalEndCapLayerThickness;
+    }
+
+    // Distance from rear of endcap outer
+    float rearDistanceToEdge(std::numeric_limits<float>::max());
+
+    if (caloHitAbsZ >= m_eCalBarrelOuterZ)
+    {
+        rearDistanceToEdge = (m_hCalEndCapOuterZ - caloHitAbsZ) / m_hCalEndCapLayerThickness;
+    }
+    else
+    {
+        const float rearDistance((m_eCalBarrelOuterZ - caloHitAbsZ) / m_hCalBarrelLayerThickness);
+
+        if (rearDistance < m_settings.m_layersFromEdgeMaxRearDistance)
+        {
+            const float overlapDistance((m_hCalEndCapOuterR - endCapMaximumRadius) / m_hCalEndCapLayerThickness);
+            rearDistanceToEdge = std::max(rearDistance, overlapDistance);
+        }
+    }
+
+    return static_cast<int>(std::min(radialDistanceToEdge, rearDistanceToEdge));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+float CaloHitCreator::GetMaximumRadius(const edm4hep::CalorimeterHit *const pCaloHit, const unsigned int symmetryOrder, const float phi0) const
+{
+    
+    const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+    if (symmetryOrder <= 2)
+        return std::sqrt((pCaloHitPosition[0] * pCaloHitPosition[0]) + (pCaloHitPosition[1] * pCaloHitPosition[1]));
+
+    float maximumRadius(0.f);
+    const float twoPi(2.f * M_PI);
+
+    for (unsigned int i = 0; i < symmetryOrder; ++i)
+    {
+        const float phi = phi0 + i * twoPi / static_cast<float>(symmetryOrder);
+        float radius = pCaloHitPosition[0] * std::cos(phi) + pCaloHitPosition[1] * std::sin(phi);
+
+        if (radius > maximumRadius)
+            maximumRadius = radius;
+    }
+
+    return maximumRadius;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+std::string CaloHitCreator::GetLayerCoding(const std::string &encodingString) const
+{
+    if (encodingString.find("layer") != std::string::npos)
+        return std::string("layer");
+
+    if (encodingString.find("K-1") != std::string::npos)
+        return std::string("K-1");
+
+    if (encodingString.find("K") != std::string::npos)
+        return std::string("K");
+
+    return std::string("unknown_layer_encoding");
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+std::string CaloHitCreator::GetStaveCoding(const std::string &encodingString) const
+{
+    if (encodingString.find("stave") != std::string::npos)
+        return std::string("stave");
+
+    if (encodingString.find("S-1") != std::string::npos)
+        return std::string("S-1");
+
+    return std::string("unknown_stave_encoding") ;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+CaloHitCreator::Settings::Settings() :
+    m_absorberRadLengthECal(1.f),
+    m_absorberIntLengthECal(1.f),
+    m_absorberRadLengthHCal(1.f),
+    m_absorberIntLengthHCal(1.f),
+    m_absorberRadLengthOther(1.f),
+    m_absorberIntLengthOther(1.f),
+    m_eCalToMip(1.f),
+    m_hCalToMip(1.f),
+    m_muonToMip(1.f),
+    m_eCalMipThreshold(0.f),
+    m_hCalMipThreshold(0.f),
+    m_muonMipThreshold(0.f),
+    m_eCalToEMGeV(1.f),
+    m_eCalToHadGeVBarrel(1.f),
+    m_eCalToHadGeVEndCap(1.f),
+    m_hCalToEMGeV(1.f),
+    m_hCalToHadGeV(1.f),
+    m_muonDigitalHits(1),
+    m_muonHitEnergy(0.5f),
+    m_maxHCalHitHadronicEnergy(10000.f),
+    m_nOuterSamplingLayers(3),
+    m_layersFromEdgeMaxRearDistance(250.f),
+    m_hCalEndCapInnerSymmetryOrder(4),
+    m_hCalEndCapInnerPhiCoordinate(0.f),
+    m_stripSplittingOn(0),
+    m_useEcalScLayers(0),
+    m_eCalSiToMip(1.f),
+    m_eCalScToMip(1.f),
+    m_eCalSiMipThreshold(0.f),
+    m_eCalScMipThreshold(0.f),
+    m_eCalSiToEMGeV(1.f),
+    m_eCalScToEMGeV(1.f),
+    m_eCalSiToHadGeVBarrel(1.f),
+    m_eCalScToHadGeVBarrel(1.f),
+    m_eCalSiToHadGeVEndCap(1.f),
+    m_eCalScToHadGeVEndCap(1.f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/GeometryCreator.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/GeometryCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c88f7ba826fcf806b9a25f253cf51e06d1a92e2
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/GeometryCreator.cpp
@@ -0,0 +1,420 @@
+/**
+ * 
+ *  @brief  Implementation of the geometry creator class.
+ * 
+ *  $Log: $
+ */
+#include "GaudiKernel/IService.h"
+#include "GearSvc/IGearSvc.h"
+#include "gear/BField.h"
+#include "gear/GEAR.h"
+#include "gear/GearParameters.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/TPCParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/LayerLayout.h"
+#include "GeometryCreator.h"
+
+GeometryCreator::GeometryCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+GeometryCreator::~GeometryCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateGeometry(ISvcLocator* svcloc) 
+{
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+    
+
+    try
+    {
+        SubDetectorTypeMap subDetectorTypeMap;
+        this->SetMandatorySubDetectorParameters(subDetectorTypeMap);
+
+        SubDetectorNameMap subDetectorNameMap;
+        this->SetAdditionalSubDetectorParameters(subDetectorNameMap);
+        
+        if (std::string::npos != _GEAR->getDetectorName().find("ILD"))
+            this->SetILDSpecificGeometry(subDetectorTypeMap, subDetectorNameMap);
+        
+        for (SubDetectorTypeMap::const_iterator iter = subDetectorTypeMap.begin(), iterEnd = subDetectorTypeMap.end(); iter != iterEnd; ++iter)
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::SubDetector::Create(*m_pPandora, iter->second));
+
+        for (SubDetectorNameMap::const_iterator iter = subDetectorNameMap.begin(), iterEnd = subDetectorNameMap.end(); iter != iterEnd; ++iter)
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::SubDetector::Create(*m_pPandora, iter->second));
+    }
+    catch (gear::Exception &exception)
+    {
+        std::cout << "Failure in marlin pandora geometry creator, gear exception: " << exception.what() << std::endl;
+        throw exception;
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetMandatorySubDetectorParameters(SubDetectorTypeMap &subDetectorTypeMap) const
+{
+    std::cout << "Begin SetMandatorySubDetectorParameters:" << std::endl;
+    PandoraApi::Geometry::SubDetector::Parameters eCalBarrelParameters, eCalEndCapParameters, hCalBarrelParameters, hCalEndCapParameters,
+        muonBarrelParameters, muonEndCapParameters;
+
+    this->SetDefaultSubDetectorParameters(_GEAR->getEcalBarrelParameters(), "ECalBarrel", pandora::ECAL_BARREL, eCalBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getEcalEndcapParameters(), "ECalEndCap", pandora::ECAL_ENDCAP, eCalEndCapParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getHcalBarrelParameters(), "HCalBarrel", pandora::HCAL_BARREL, hCalBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getHcalEndcapParameters(), "HCalEndCap", pandora::HCAL_ENDCAP, hCalEndCapParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getYokeBarrelParameters(), "MuonBarrel", pandora::MUON_BARREL, muonBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getYokeEndcapParameters(), "MuonEndCap", pandora::MUON_ENDCAP, muonEndCapParameters);
+
+    subDetectorTypeMap[pandora::ECAL_BARREL] = eCalBarrelParameters;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP] = eCalEndCapParameters;
+    subDetectorTypeMap[pandora::HCAL_BARREL] = hCalBarrelParameters;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP] = hCalEndCapParameters;
+    subDetectorTypeMap[pandora::MUON_BARREL] = muonBarrelParameters;
+    subDetectorTypeMap[pandora::MUON_ENDCAP] = muonEndCapParameters;
+
+    PandoraApi::Geometry::SubDetector::Parameters trackerParameters;
+    const gear::TPCParameters &tpcParameters(_GEAR->getTPCParameters());
+    trackerParameters.m_subDetectorName = "Tracker";
+    trackerParameters.m_subDetectorType = pandora::INNER_TRACKER;
+    trackerParameters.m_innerRCoordinate = tpcParameters.getPadLayout().getPlaneExtent()[0];
+    trackerParameters.m_innerZCoordinate = 0.f;
+    trackerParameters.m_innerPhiCoordinate = 0.f;
+    trackerParameters.m_innerSymmetryOrder = 0;
+    trackerParameters.m_outerRCoordinate = tpcParameters.getPadLayout().getPlaneExtent()[1];
+    trackerParameters.m_outerZCoordinate = tpcParameters.getMaxDriftLength();
+    trackerParameters.m_outerPhiCoordinate = 0.f;
+    trackerParameters.m_outerSymmetryOrder = 0;
+    trackerParameters.m_isMirroredInZ = true;
+    trackerParameters.m_nLayers = 0;
+    subDetectorTypeMap[pandora::INNER_TRACKER] = trackerParameters;
+
+    PandoraApi::Geometry::SubDetector::Parameters coilParameters;
+    const gear::GearParameters &gearParameters(_GEAR->getGearParameters("CoilParameters"));
+    coilParameters.m_subDetectorName = "Coil";
+    coilParameters.m_subDetectorType = pandora::COIL;
+    coilParameters.m_innerRCoordinate = gearParameters.getDoubleVal("Coil_cryostat_inner_radius");
+    coilParameters.m_innerZCoordinate = 0.f;
+    coilParameters.m_innerPhiCoordinate = 0.f;
+    coilParameters.m_innerSymmetryOrder = 0;
+    coilParameters.m_outerRCoordinate = gearParameters.getDoubleVal("Coil_cryostat_outer_radius");
+    coilParameters.m_outerZCoordinate = gearParameters.getDoubleVal("Coil_cryostat_half_z");
+    coilParameters.m_outerPhiCoordinate = 0.f;
+    coilParameters.m_outerSymmetryOrder = 0;
+    coilParameters.m_isMirroredInZ = true;
+    coilParameters.m_nLayers = 0;
+    subDetectorTypeMap[pandora::COIL] = coilParameters;
+    std::cout << "End SetMandatorySubDetectorParameters" << std::endl;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetAdditionalSubDetectorParameters(SubDetectorNameMap &subDetectorNameMap) const
+{
+    std::cout << "Begin SetAdditionalSubDetectorParameters:" << std::endl;
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getEcalPlugParameters(), "ECalPlug", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+        std::cout << " warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getHcalRingParameters(), "HCalRing", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout<< "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getLcalParameters(), "LCal", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout << "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getLHcalParameters(), "LHCal", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout << "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+    std::cout << "End SetAdditionalSubDetectorParameters" << std::endl;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetDefaultSubDetectorParameters(const gear::CalorimeterParameters &inputParameters, const std::string &subDetectorName,
+    const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const
+{
+    const gear::LayerLayout &layerLayout = inputParameters.getLayerLayout();
+
+    parameters.m_subDetectorName = subDetectorName;
+    parameters.m_subDetectorType = subDetectorType;
+    parameters.m_innerRCoordinate = inputParameters.getExtent()[0];
+    parameters.m_innerZCoordinate = inputParameters.getExtent()[2];
+    parameters.m_innerPhiCoordinate = inputParameters.getPhi0();
+    parameters.m_innerSymmetryOrder = inputParameters.getSymmetryOrder();
+    parameters.m_outerRCoordinate = inputParameters.getExtent()[1];
+    parameters.m_outerZCoordinate = inputParameters.getExtent()[3];
+    parameters.m_outerPhiCoordinate = inputParameters.getPhi0();
+    parameters.m_outerSymmetryOrder = inputParameters.getSymmetryOrder();
+    parameters.m_isMirroredInZ = true;
+    parameters.m_nLayers = layerLayout.getNLayers();
+
+    // ATTN Not always going to be correct for any optional subdetectors, but impact of this is negligible for ILD
+    const float radiationLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    for (int i = 0; i < layerLayout.getNLayers(); ++i)
+    {
+        PandoraApi::Geometry::LayerParameters layerParameters;
+        layerParameters.m_closestDistanceToIp = layerLayout.getDistance(i) + (0.5 * (layerLayout.getThickness(i) + layerLayout.getAbsorberThickness(i)));
+        layerParameters.m_nRadiationLengths = radiationLength * layerLayout.getAbsorberThickness(i);
+        layerParameters.m_nInteractionLengths = interactionLength * layerLayout.getAbsorberThickness(i);
+        parameters.m_layerParametersVector.push_back(layerParameters);
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::SetILDSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap, SubDetectorNameMap &subDetectorNameMap) const
+{
+    // Set positions of gaps in ILD detector and add information missing from GEAR parameters file
+    try
+    {
+        const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+        subDetectorTypeMap[pandora::HCAL_BARREL].m_outerPhiCoordinate = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_phi0");
+        subDetectorTypeMap[pandora::HCAL_BARREL].m_outerSymmetryOrder = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order");
+    }
+    catch (gear::Exception &)
+    {
+        // aLaVideauGeometry
+        return this->SetILD_SDHCALSpecificGeometry(subDetectorTypeMap);
+    }
+
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_eCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_eCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_eCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_eCalEndCapOuterPhiCoordinate;
+
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_hCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_hCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_hCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_hCalEndCapOuterPhiCoordinate;
+
+    subDetectorNameMap["HCalRing"].m_innerSymmetryOrder = m_settings.m_hCalRingInnerSymmetryOrder;
+    subDetectorNameMap["HCalRing"].m_innerPhiCoordinate = m_settings.m_hCalRingInnerPhiCoordinate;
+    subDetectorNameMap["HCalRing"].m_outerSymmetryOrder = m_settings.m_hCalRingOuterSymmetryOrder;
+    subDetectorNameMap["HCalRing"].m_outerPhiCoordinate = m_settings.m_hCalRingOuterPhiCoordinate;
+
+    // Gaps in detector active material
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalBarrelBoxGaps());
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalEndCapBoxGaps());
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalBarrelConcentricGaps());
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::SetILD_SDHCALSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap) const
+{
+    // Non-default values (and those missing from GEAR parameters file)...
+    // The following 2 parameters have no sense for Videau Geometry, set them to 0
+    subDetectorTypeMap[pandora::HCAL_BARREL].m_outerPhiCoordinate = 0;
+    subDetectorTypeMap[pandora::HCAL_BARREL].m_outerSymmetryOrder = 0;
+
+    // Endcap is identical to standard ILD geometry, only HCAL barrel is different
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_eCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_eCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_eCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_eCalEndCapOuterPhiCoordinate;
+
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_hCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_hCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_hCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_hCalEndCapOuterPhiCoordinate;
+
+    // TODO implement gaps between modules
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalBarrelBoxGaps() const
+{
+    const std::string detectorName(_GEAR->getDetectorName());
+
+    const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+    const unsigned int innerSymmetryOrder(hCalBarrelParameters.getSymmetryOrder());
+    const unsigned int outerSymmetryOrder(hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order"));
+
+    if ((0 == innerSymmetryOrder) || (2 != outerSymmetryOrder / innerSymmetryOrder))
+    {
+        std::cout << " Detector " << detectorName << " doesn't conform to expected ILD-specific geometry" << std::endl;
+        return pandora::STATUS_CODE_INVALID_PARAMETER;
+    }
+
+    const float innerRadius(hCalBarrelParameters.getExtent()[0]);
+    const float outerRadius(hCalBarrelParameters.getExtent()[1]);
+    const float outerZ(hCalBarrelParameters.getExtent()[3]);
+    const float phi0(hCalBarrelParameters.getPhi0());
+
+    const float staveGap(hCalBarrelParameters.getDoubleVal("Hcal_stave_gaps"));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(innerSymmetryOrder, phi0, innerRadius, outerRadius,
+        -outerZ, outerZ, staveGap));
+
+    const float outerPseudoPhi0(M_PI / static_cast<float>(innerSymmetryOrder));
+    const float cosOuterPseudoPhi0(std::cos(outerPseudoPhi0));
+
+    if ((0 == outerPseudoPhi0) || (0.f == cosOuterPseudoPhi0))
+    {
+        std::cout << " Detector " << detectorName << " doesn't conform to expected ILD-specific geometry" << std::endl;
+        return pandora::STATUS_CODE_INVALID_PARAMETER;
+    }
+
+    const float middleStaveGap(hCalBarrelParameters.getDoubleVal("Hcal_middle_stave_gaps"));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(innerSymmetryOrder, outerPseudoPhi0,
+        innerRadius / cosOuterPseudoPhi0, outerRadius, -outerZ, outerZ, middleStaveGap));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalEndCapBoxGaps() const
+{
+    const gear::CalorimeterParameters &hCalEndCapParameters = _GEAR->getHcalEndcapParameters();
+
+    const float staveGap(hCalEndCapParameters.getDoubleVal("Hcal_stave_gaps"));
+    const float innerRadius(hCalEndCapParameters.getExtent()[0]);
+    const float outerRadius(hCalEndCapParameters.getExtent()[1]);
+    const float innerZ(hCalEndCapParameters.getExtent()[2]);
+    const float outerZ(hCalEndCapParameters.getExtent()[3]);
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(m_settings.m_hCalEndCapInnerSymmetryOrder,
+        m_settings.m_hCalEndCapInnerPhiCoordinate, innerRadius, outerRadius, innerZ, outerZ, staveGap,
+        pandora::CartesianVector(-innerRadius, 0, 0)));
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(m_settings.m_hCalEndCapInnerSymmetryOrder,
+        m_settings.m_hCalEndCapInnerPhiCoordinate, innerRadius, outerRadius, -outerZ, -innerZ, staveGap,
+        pandora::CartesianVector(innerRadius, 0, 0)));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalBarrelConcentricGaps() const
+{
+    const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+    const float gapWidth(hCalBarrelParameters.getDoubleVal("Hcal_stave_gaps"));
+
+    PandoraApi::Geometry::ConcentricGap::Parameters gapParameters;
+
+    gapParameters.m_minZCoordinate = -0.5f * gapWidth;
+    gapParameters.m_maxZCoordinate =  0.5f * gapWidth;
+    gapParameters.m_innerRCoordinate = hCalBarrelParameters.getExtent()[0];
+    gapParameters.m_innerPhiCoordinate = hCalBarrelParameters.getPhi0();
+    gapParameters.m_innerSymmetryOrder = hCalBarrelParameters.getSymmetryOrder();
+    gapParameters.m_outerRCoordinate = hCalBarrelParameters.getExtent()[1];
+    gapParameters.m_outerPhiCoordinate = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_phi0");
+    gapParameters.m_outerSymmetryOrder = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order");
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::ConcentricGap::Create(*m_pPandora, gapParameters));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateRegularBoxGaps(unsigned int symmetryOrder, float phi0, float innerRadius, float outerRadius,
+    float minZ, float maxZ, float gapWidth, pandora::CartesianVector vertexOffset) const
+{
+    const pandora::CartesianVector basicGapVertex(pandora::CartesianVector(-0.5f * gapWidth, innerRadius, minZ) + vertexOffset);
+    const pandora::CartesianVector basicSide1(gapWidth, 0, 0);
+    const pandora::CartesianVector basicSide2(0, outerRadius - innerRadius, 0);
+    const pandora::CartesianVector basicSide3(0, 0, maxZ - minZ);
+
+    for (unsigned int i = 0; i < symmetryOrder; ++i)
+    {
+        const float phi = phi0 + (2. * M_PI * static_cast<float>(i) / static_cast<float>(symmetryOrder));
+        const float sinPhi(std::sin(phi));
+        const float cosPhi(std::cos(phi));
+
+        PandoraApi::Geometry::BoxGap::Parameters gapParameters;
+
+        gapParameters.m_vertex = pandora::CartesianVector(cosPhi * basicGapVertex.GetX() + sinPhi * basicGapVertex.GetY(),
+            -sinPhi * basicGapVertex.GetX() + cosPhi * basicGapVertex.GetY(), basicGapVertex.GetZ());
+        gapParameters.m_side1 = pandora::CartesianVector(cosPhi * basicSide1.GetX() + sinPhi * basicSide1.GetY(),
+            -sinPhi * basicSide1.GetX() + cosPhi * basicSide1.GetY(), basicSide1.GetZ());
+        gapParameters.m_side2 = pandora::CartesianVector(cosPhi * basicSide2.GetX() + sinPhi * basicSide2.GetY(),
+            -sinPhi * basicSide2.GetX() + cosPhi * basicSide2.GetY(), basicSide2.GetZ());
+        gapParameters.m_side3 = pandora::CartesianVector(cosPhi * basicSide3.GetX() + sinPhi * basicSide3.GetY(),
+            -sinPhi * basicSide3.GetX() + cosPhi * basicSide3.GetY(), basicSide3.GetZ());
+
+        PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::BoxGap::Create(*m_pPandora, gapParameters));
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+GeometryCreator::Settings::Settings() :
+    m_absorberRadLengthECal(1.f),
+    m_absorberIntLengthECal(1.f),
+    m_absorberRadLengthHCal(1.f),
+    m_absorberIntLengthHCal(1.f),
+    m_absorberRadLengthOther(1.f),
+    m_absorberIntLengthOther(1.f),
+    m_eCalEndCapInnerSymmetryOrder(4),
+    m_eCalEndCapInnerPhiCoordinate(0.f),
+    m_eCalEndCapOuterSymmetryOrder(8),
+    m_eCalEndCapOuterPhiCoordinate(0.f),
+    m_hCalEndCapInnerSymmetryOrder(4),
+    m_hCalEndCapInnerPhiCoordinate(0.f),
+    m_hCalEndCapOuterSymmetryOrder(16),
+    m_hCalEndCapOuterPhiCoordinate(0.f),
+    m_hCalRingInnerSymmetryOrder(8),
+    m_hCalRingInnerPhiCoordinate(0.f),
+    m_hCalRingOuterSymmetryOrder(16),
+    m_hCalRingOuterPhiCoordinate(0.f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/MCParticleCreator.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/MCParticleCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9042a82183231212b3362656c9d38ab8ef6bbf0
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/MCParticleCreator.cpp
@@ -0,0 +1,226 @@
+/**
+ * 
+ *  @brief  Implementation of the mc particle creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "edm4hep/MCParticleConst.h"
+#include "edm4hep/MCParticle.h" 
+#include "edm4hep/MCRecoCaloAssociation.h" 
+#include "edm4hep/SimCalorimeterHitConst.h" 
+#include "edm4hep/CaloHitContributionConst.h" 
+#include "edm4hep/Track.h" 
+#include "edm4hep/MCRecoTrackerAssociation.h" 
+#include "edm4hep/SimTrackerHitConst.h" 
+#include "PandoraPFAlg.h"
+#include "MCParticleCreator.h"
+
+#include <cmath>
+#include <limits>
+#include <assert.h>
+
+MCParticleCreator::MCParticleCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora),
+    m_bField(settings.m_bField)
+{
+m_id_pMC_map = new std::map<unsigned int, const edm4hep::MCParticle*>;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+MCParticleCreator::~MCParticleCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode MCParticleCreator::CreateMCParticles(const CollectionMaps& collectionMaps ) const
+{
+    for (StringVector::const_iterator iter = m_settings.m_mcParticleCollections.begin(), iterEnd = m_settings.m_mcParticleCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_MC.find(*iter) == collectionMaps.collectionMap_MC.end()) continue;
+        try
+        {
+            const std::vector<edm4hep::MCParticle>& pMCParticleCollection = (collectionMaps.collectionMap_MC.find(*iter))->second;
+            std::cout<<"Do CreateMCParticles, collection:"<<(*iter)<<", size="<<pMCParticleCollection.size()<<std::endl;
+            for (int im = 0; im < pMCParticleCollection.size(); im++)
+            {
+                try
+                {
+                    const edm4hep::MCParticle& pMcParticle = pMCParticleCollection.at(im);
+                    PandoraApi::MCParticle::Parameters mcParticleParameters;
+                    mcParticleParameters.m_energy =   sqrt(pMcParticle.getMomentum()[0] * pMcParticle.getMomentum()[0] + pMcParticle.getMomentum()[1] * pMcParticle.getMomentum()[1] + pMcParticle.getMomentum()[2] * pMcParticle.getMomentum()[2] + pMcParticle.getMass() * pMcParticle.getMass());
+                    mcParticleParameters.m_particleId = pMcParticle.getPDG();
+                    mcParticleParameters.m_mcParticleType = pandora::MC_3D;
+                    mcParticleParameters.m_pParentAddress = &pMcParticle;
+                    unsigned int p_id = pMcParticle.id();
+                    const edm4hep::MCParticle* p_mc = &pMcParticle;
+                    (*m_id_pMC_map) [p_id]   = p_mc;
+                    mcParticleParameters.m_momentum = pandora::CartesianVector(pMcParticle.getMomentum()[0], pMcParticle.getMomentum()[1],
+                        pMcParticle.getMomentum()[2]);
+                    mcParticleParameters.m_vertex = pandora::CartesianVector(pMcParticle.getVertex()[0], pMcParticle.getVertex()[1],
+                        pMcParticle.getVertex()[2]);
+                    mcParticleParameters.m_endpoint = pandora::CartesianVector(pMcParticle.getEndpoint()[0], pMcParticle.getEndpoint()[1],
+                        pMcParticle.getEndpoint()[2]);
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::MCParticle::Create(*m_pPandora, mcParticleParameters));
+
+                    // Create parent-daughter relationships
+                    for(std::vector<edm4hep::ConstMCParticle>::const_iterator itDaughter = pMcParticle.daughters_begin(),
+                        itDaughterEnd = pMcParticle.daughters_end(); itDaughter != itDaughterEnd; ++itDaughter)
+                    {   
+                        for (int ida = 0; ida < pMCParticleCollection.size(); ida++)
+                        {
+                           if(pMCParticleCollection.at(ida).id()==(*itDaughter).id())
+                           {
+                              
+                                const edm4hep::MCParticle& dMcParticle = pMCParticleCollection.at(ida);
+                                if(&pMcParticle == &dMcParticle){std::cout<< "error, mother and daughter are the same mc particle, don't save SetMCParentDaughterRelationship"<<std::endl;}
+                                else PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetMCParentDaughterRelationship(*m_pPandora, &pMcParticle, &dMcParticle));
+                                break;
+                           }
+                        }
+                    }
+                    
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract MCParticle: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract MCParticle: " <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract MCParticles collection: " << *iter << ", " <<  std::endl;
+        }
+    }
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+pandora::StatusCode MCParticleCreator::CreateCaloHitToMCParticleRelationships(const CollectionMaps& collectionMaps, const CalorimeterHitVector &calorimeterHitVector) const
+{
+    typedef std::map<const edm4hep::MCParticle *, float> MCParticleToEnergyWeightMap;
+    MCParticleToEnergyWeightMap mcParticleToEnergyWeightMap;
+
+    for (StringVector::const_iterator iter = m_settings.m_CaloHitRelationCollections.begin(), iterEnd = m_settings.m_CaloHitRelationCollections.end();
+         iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloRel.find(*iter) == collectionMaps.collectionMap_CaloRel.end()) continue;
+        try
+        {
+            const std::vector<edm4hep::MCRecoCaloAssociation>& pMCRecoCaloAssociationCollection = (collectionMaps.collectionMap_CaloRel.find(*iter))->second;
+
+            for (unsigned i_calo=0; i_calo < calorimeterHitVector.size(); i_calo++)
+            {
+                try
+                {
+                    mcParticleToEnergyWeightMap.clear();
+                    for(unsigned ic=0; ic < pMCRecoCaloAssociationCollection.size(); ic++)
+                    {
+                        if( pMCRecoCaloAssociationCollection.at(ic).getRec().id() != (*(calorimeterHitVector.at(i_calo))).id() ) continue;
+                        
+                        const edm4hep::ConstSimCalorimeterHit pSimHit = pMCRecoCaloAssociationCollection.at(ic).getSim();
+                        for (int iCont = 0, iEnd = pSimHit.contributions_size(); iCont < iEnd; ++iCont)
+                        {
+                            edm4hep::ConstCaloHitContribution conb = pSimHit.getContributions(iCont);
+                            const edm4hep::ConstMCParticle ipa = conb.getParticle();
+                            float  ien = conb.getEnergy();
+                            if( m_id_pMC_map->find(ipa.id()) == m_id_pMC_map->end() ) continue;
+                            const edm4hep::MCParticle * p_tmp = (*m_id_pMC_map)[ipa.id()]; 
+                            mcParticleToEnergyWeightMap[p_tmp] += ien;
+                        }
+                        
+                    }
+
+                    for (MCParticleToEnergyWeightMap::const_iterator mcParticleIter = mcParticleToEnergyWeightMap.begin(),
+                        mcParticleIterEnd = mcParticleToEnergyWeightMap.end(); mcParticleIter != mcParticleIterEnd; ++mcParticleIter)
+                    {
+                        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetCaloHitToMCParticleRelationship(*m_pPandora,
+                            calorimeterHitVector.at(i_calo), mcParticleIter->first, mcParticleIter->second));
+                    }
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"Failed to extract calo hit to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"Failed to extract calo hit to mc particle relationship " << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<<"Failed to extract calo hit to mc particle relationships collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+pandora::StatusCode MCParticleCreator::CreateTrackToMCParticleRelationships(const CollectionMaps& collectionMaps, const TrackVector &trackVector) const
+{
+    for (unsigned ik = 0; ik < trackVector.size(); ik++)
+    {
+        const edm4hep::Track *pTrack = trackVector.at(ik);
+        // Get reconstructed momentum at dca
+        const pandora::Helix helixFit(pTrack->getTrackStates(0).phi, pTrack->getTrackStates(0).D0, pTrack->getTrackStates(0).Z0, pTrack->getTrackStates(0).omega, pTrack->getTrackStates(0).tanLambda, m_bField);
+        const float recoMomentum(helixFit.GetMomentum().GetMagnitude());
+        // Use momentum magnitude to identify best mc particle
+        edm4hep::MCParticle *pBestMCParticle = NULL;
+        float bestDeltaMomentum(std::numeric_limits<float>::max());
+        try
+        {
+            for (StringVector::const_iterator iter = m_settings.m_TrackRelationCollections.begin(), iterEnd = m_settings.m_TrackRelationCollections.end(); iter != iterEnd; ++iter)
+            {
+                if(collectionMaps.collectionMap_TrkRel.find(*iter) == collectionMaps.collectionMap_TrkRel.end()) continue;
+                const std::vector<edm4hep::MCRecoTrackerAssociation>& pMCRecoTrackerAssociationCollection = (collectionMaps.collectionMap_TrkRel.find(*iter))->second;
+                for(unsigned ith=0 ; ith<pTrack->trackerHits_size(); ith++)
+                {
+                    for(unsigned ic=0; ic < pMCRecoTrackerAssociationCollection.size(); ic++)
+                    {
+                        if( pMCRecoTrackerAssociationCollection.at(ic).getRec().id() != pTrack->getTrackerHits(ith).id() ) continue;
+                        const edm4hep::ConstSimTrackerHit pSimHit = pMCRecoTrackerAssociationCollection.at(ic).getSim();
+                        const edm4hep::ConstMCParticle ipa = pSimHit.getMCParticle();
+                        if( m_id_pMC_map->find(ipa.id()) == m_id_pMC_map->end() ) continue;
+                        const float trueMomentum(pandora::CartesianVector(ipa.getMomentum()[0], ipa.getMomentum()[1], ipa.getMomentum()[2]).GetMagnitude());
+                        const float deltaMomentum(std::fabs(recoMomentum - trueMomentum));
+                        if (deltaMomentum < bestDeltaMomentum)
+                        {
+                            pBestMCParticle =const_cast<edm4hep::MCParticle*>((*m_id_pMC_map)[ipa.id()]);
+                            bestDeltaMomentum = deltaMomentum;
+                        }
+                    }
+                }
+            }
+            
+            if (NULL == pBestMCParticle) continue;
+            PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackToMCParticleRelationship(*m_pPandora, pTrack, pBestMCParticle));
+        }
+        catch (pandora::StatusCodeException &statusCodeException)
+        {
+            std::cout<<"Failed to extract track to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+        }
+        catch (...)
+        {
+            std::cout<<"Failed to extract track to mc particle relationship" << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+MCParticleCreator::Settings::Settings()
+{
+}
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/PandoraPFAlg.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/PandoraPFAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2e9db69f1a2184b3bbf1f3c6d27d344a2432a2c
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/PandoraPFAlg.cpp
@@ -0,0 +1,684 @@
+#include "GearSvc/IGearSvc.h"
+#include "PandoraPFAlg.h"
+#include "EventSeeder/IEventSeeder.h"
+#include "edm4hep/Vector3f.h"
+#include "edm4hep/Vector3d.h"
+#include "edm4hep/SimCalorimeterHit.h"
+#include "edm4hep/CaloHitContribution.h"
+#include "edm4hep/ClusterConst.h"
+//#include "UTIL/ILDConf.h"
+#include <cmath>
+#include <algorithm>
+#include "gear/BField.h"
+#include <gear/GEAR.h>
+
+#include "LCContent.h"
+
+
+pandora::Pandora* PandoraPFAlg::m_pPandora=0;
+
+DECLARE_COMPONENT( PandoraPFAlg )
+
+template<typename T ,typename T1>
+StatusCode getCol(T & t, T1 & t1)
+{
+    try {
+        t1 = t.get();
+    }
+    catch ( GaudiException &e ) {
+        std::cout << "Collection " << t.fullKey() << " is unavailable in event "  << std::endl;
+    }
+    return StatusCode::SUCCESS;
+}
+
+
+
+PandoraPFAlg::PandoraPFAlg(const std::string& name, ISvcLocator* svcLoc)
+  : GaudiAlgorithm(name, svcLoc),
+    _nEvt(0)
+{
+ m_CollectionMaps = new CollectionMaps();
+  
+ declareProperty("ReadMCParticle"                      , m_mcParCol_r,                        "Handle of the MCParticle    input collection" );
+ declareProperty("ReadECALBarrel"                      , m_ECALBarrel_r,                      "Handle of the ECALBarrel    input collection" );
+ declareProperty("ReadECALEndcap"                      , m_ECALEndcap_r,                      "Handle of the ECALEndcap    input collection" );
+ declareProperty("ReadECALOther"                       , m_ECALOther_r,                       "Handle of the ECALOther     input collection" );
+ declareProperty("ReadHCALBarrel"                      , m_HCALBarrel_r,                      "Handle of the HCALBarrel    input collection" );
+ declareProperty("ReadHCALEndcap"                      , m_HCALEndcap_r,                      "Handle of the HCALEndcap    input collection" );
+ declareProperty("ReadHCALOther"                       , m_HCALOther_r,                       "Handle of the HCALOther     input collection" );
+ declareProperty("ReadMUON"                            , m_MUON_r,                            "Handle of the MUON          input collection" );
+ declareProperty("ReadLCAL"                            , m_LCAL_r,                            "Handle of the LCAL          input collection" );
+ declareProperty("ReadLHCAL"                           , m_LHCAL_r,                           "Handle of the LHCAL         input collection" );
+ declareProperty("ReadBCAL"                            , m_BCAL_r,                            "Handle of the BCAL          input collection" );
+ declareProperty("ReadKinkVertices"                    , m_KinkVertices_r,                    "Handle of the KinkVertices  input collection" );
+ declareProperty("ReadProngVertices"                   , m_ProngVertices_r,                   "Handle of the ProngVertices input collection" );
+ declareProperty("ReadSplitVertices"                   , m_SplitVertices_r,                   "Handle of the SplitVertices input collection" );
+ declareProperty("ReadV0Vertices"                      , m_V0Vertices_r,                      "Handle of the V0Vertices    input collection" );
+ declareProperty("ReadTracks"                          , m_MarlinTrkTracks_r,                 "Handle of the Tracks        input collection" );
+ declareProperty("MCRecoCaloAssociation"               , m_MCRecoCaloAssociation_r,           "Handle of the MCRecoCaloAssociation input collection" );
+ declareProperty("MCRecoTrackerAssociation"            , m_MCRecoTrackerAssociation_r,        "Handle of the MCRecoTrackerAssociation input collection" );
+ declareProperty("WriteClusterCollection"              , m_ClusterCollection_w,               "Handle of the ClusterCollection               output collection" );
+ declareProperty("WriteReconstructedParticleCollection", m_ReconstructedParticleCollection_w, "Handle of the ReconstructedParticleCollection output collection" );
+ declareProperty("WriteVertexCollection"               , m_VertexCollection_w,                "Handle of the VertexCollection                output collection" );
+
+}
+
+
+void PandoraPFAlg::FinaliseSteeringParameters(ISvcLocator* svcloc)
+{
+    // ATTN: This function seems to be necessary for operations that cannot easily be performed at construction of the processor,
+    // when the steering file is parsed e.g. the call to GEAR to get the inner bfield
+    
+    m_caloHitCreatorSettings.m_absorberRadLengthECal = m_geometryCreatorSettings.m_absorberRadLengthECal;
+    m_caloHitCreatorSettings.m_absorberIntLengthECal = m_geometryCreatorSettings.m_absorberIntLengthECal;
+    m_caloHitCreatorSettings.m_absorberRadLengthHCal = m_geometryCreatorSettings.m_absorberRadLengthHCal;
+    m_caloHitCreatorSettings.m_absorberIntLengthHCal = m_geometryCreatorSettings.m_absorberIntLengthHCal;
+    m_caloHitCreatorSettings.m_absorberRadLengthOther = m_geometryCreatorSettings.m_absorberRadLengthOther;
+    m_caloHitCreatorSettings.m_absorberIntLengthOther = m_geometryCreatorSettings.m_absorberIntLengthOther;
+
+    m_caloHitCreatorSettings.m_hCalEndCapInnerSymmetryOrder = m_geometryCreatorSettings.m_hCalEndCapInnerSymmetryOrder;
+    m_caloHitCreatorSettings.m_hCalEndCapInnerPhiCoordinate = m_geometryCreatorSettings.m_hCalEndCapInnerPhiCoordinate;
+    
+    m_trackCreatorSettings.m_prongSplitVertexCollections = m_trackCreatorSettings.m_prongVertexCollections;
+    m_trackCreatorSettings.m_prongSplitVertexCollections.insert(m_trackCreatorSettings.m_prongSplitVertexCollections.end(),
+        m_trackCreatorSettings.m_splitVertexCollections.begin(), m_trackCreatorSettings.m_splitVertexCollections.end());
+    
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    gear::GearMgr* _GEAR = iSvc->getGearMgr();
+    m_settings.m_innerBField = _GEAR->getBField().at(gear::Vector3D(0., 0., 0.)).z();
+    std::cout<<"m_innerBField="<<m_settings.m_innerBField<<std::endl;    
+    m_mcParticleCreatorSettings.m_bField = m_settings.m_innerBField;
+}
+
+
+
+
+StatusCode PandoraPFAlg::initialize()
+{
+
+  std::cout<<"init PandoraPFAlg"<<std::endl;
+
+  std::string s_output =m_AnaOutput; 
+  m_fout = new TFile(s_output.c_str(),"RECREATE"); 
+  m_tree = new TTree("evt","tree");
+  m_tree->Branch("m_pReco_PID"   , &m_pReco_PID);
+  m_tree->Branch("m_pReco_mass"  , &m_pReco_mass);
+  m_tree->Branch("m_pReco_energy", &m_pReco_energy);
+  m_tree->Branch("m_pReco_px"    , &m_pReco_px);
+  m_tree->Branch("m_pReco_py"    , &m_pReco_py);
+  m_tree->Branch("m_pReco_pz"    , &m_pReco_pz);
+  m_tree->Branch("m_pReco_charge", &m_pReco_charge);
+
+  m_tree->Branch("m_mc_p_size", &m_mc_p_size);
+  m_tree->Branch("m_mc_pid"   , &m_mc_pid   );
+  m_tree->Branch("m_mc_mass"  , &m_mc_mass  );
+  m_tree->Branch("m_mc_px"    , &m_mc_px    );
+  m_tree->Branch("m_mc_py"    , &m_mc_py    );
+  m_tree->Branch("m_mc_pz"    , &m_mc_pz    );
+  m_tree->Branch("m_mc_charge", &m_mc_charge);
+  m_tree->Branch("m_hasConversion", &m_hasConversion);
+
+  // XML file
+  m_settings.m_pandoraSettingsXmlFile =  m_PandoraSettingsXmlFile ; 
+  // Hadronic energy non-linearity correction
+  m_settings.m_inputEnergyCorrectionPoints = m_InputEnergyCorrectionPoints;
+  m_settings.m_outputEnergyCorrectionPoints = m_OutputEnergyCorrectionPoints;
+  // B-field parameters
+  m_settings.m_muonBarrelBField = m_MuonBarrelBField; 
+  m_settings.m_muonEndCapBField = m_MuonEndCapBField;
+  
+  m_trackCreatorSettings.m_trackCollections = m_TrackCollections ; 
+  m_trackCreatorSettings.m_kinkVertexCollections = m_KinkVertexCollections; 
+  m_trackCreatorSettings.m_prongVertexCollections = m_ProngVertexCollections;
+  m_trackCreatorSettings.m_splitVertexCollections = m_SplitVertexCollections;
+  m_trackCreatorSettings.m_v0VertexCollections = m_V0VertexCollections; 
+  
+  m_caloHitCreatorSettings.m_eCalCaloHitCollections = m_ECalCaloHitCollections;
+  m_caloHitCreatorSettings.m_hCalCaloHitCollections = m_HCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_lCalCaloHitCollections = m_LCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_lHCalCaloHitCollections = m_LHCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_muonCaloHitCollections = m_MuonCaloHitCollections; 
+  m_mcParticleCreatorSettings.m_mcParticleCollections = m_MCParticleCollections;
+  m_mcParticleCreatorSettings.m_CaloHitRelationCollections = m_RelCaloHitCollections; 
+  m_mcParticleCreatorSettings.m_TrackRelationCollections = m_RelTrackCollections;
+  
+  
+  // Absorber properties
+  m_geometryCreatorSettings.m_absorberRadLengthECal = m_AbsorberRadLengthECal;
+  m_geometryCreatorSettings.m_absorberIntLengthECal = m_AbsorberIntLengthECal;
+  m_geometryCreatorSettings.m_absorberRadLengthHCal = m_AbsorberRadLengthHCal;
+  m_geometryCreatorSettings.m_absorberIntLengthHCal = m_AbsorberIntLengthHCal;
+  m_geometryCreatorSettings.m_absorberRadLengthOther = m_AbsorberRadLengthOther;
+  m_geometryCreatorSettings.m_absorberIntLengthOther = m_AbsorberIntLengthOther;
+  
+  // Name of PFO collection written by GaudiPandora
+  
+  m_pfoCreatorSettings.m_clusterCollectionName = m_ClusterCollectionName;// not used  
+  m_pfoCreatorSettings.m_pfoCollectionName = m_PFOCollectionName;//
+  m_pfoCreatorSettings.m_startVertexCollectionName = m_StartVertexCollectionName; //
+  m_pfoCreatorSettings.m_startVertexAlgName = m_StartVertexAlgorithmName;//
+   
+  m_pfoCreatorSettings.m_emStochasticTerm = m_EMStochasticTerm;
+  m_pfoCreatorSettings.m_hadStochasticTerm = m_HadStochasticTerm;
+  m_pfoCreatorSettings.m_emConstantTerm = m_EMConstantTerm;
+  m_pfoCreatorSettings.m_hadConstantTerm = m_HadConstantTerm;
+  
+  // Calibration constants
+  m_caloHitCreatorSettings.m_eCalToMip = m_ECalToMipCalibration; 
+  m_caloHitCreatorSettings.m_hCalToMip = m_HCalToMipCalibration;
+  m_caloHitCreatorSettings.m_eCalMipThreshold = m_ECalMipThreshold; 
+  m_caloHitCreatorSettings.m_muonToMip = m_MuonToMipCalibration;
+  m_caloHitCreatorSettings.m_hCalMipThreshold = m_HCalMipThreshold; 
+  m_caloHitCreatorSettings.m_eCalToEMGeV = m_ECalToEMGeVCalibration;
+  m_caloHitCreatorSettings.m_hCalToEMGeV = m_HCalToEMGeVCalibration;
+  m_caloHitCreatorSettings.m_eCalToHadGeVEndCap = m_ECalToHadGeVCalibrationEndCap;
+  m_caloHitCreatorSettings.m_eCalToHadGeVBarrel = m_ECalToHadGeVCalibrationBarrel; 
+  m_caloHitCreatorSettings.m_hCalToHadGeV = m_HCalToHadGeVCalibration;
+  m_caloHitCreatorSettings.m_muonDigitalHits = m_DigitalMuonHits; 
+  m_caloHitCreatorSettings.m_muonHitEnergy = m_MuonHitEnergy; 
+  m_caloHitCreatorSettings.m_maxHCalHitHadronicEnergy = m_MaxHCalHitHadronicEnergy; 
+  m_caloHitCreatorSettings.m_nOuterSamplingLayers = m_NOuterSamplingLayers; 
+  m_caloHitCreatorSettings.m_layersFromEdgeMaxRearDistance = m_LayersFromEdgeMaxRearDistance; 
+  
+  // Track relationship parameters
+  m_trackCreatorSettings.m_shouldFormTrackRelationships = m_ShouldFormTrackRelationships; 
+  // Initial track hit specifications
+  m_trackCreatorSettings.m_minTrackHits = m_MinTrackHits;
+  m_trackCreatorSettings.m_minFtdTrackHits = m_MinFtdTrackHits; 
+  m_trackCreatorSettings.m_maxTrackHits = m_MaxTrackHits; 
+  ////m_trackCreatorSettings.m_useOldTrackStateCalculation = m_UseOldTrackStateCalculation;
+  // Track PFO usage parameters
+  m_trackCreatorSettings.m_d0TrackCut = m_D0TrackCut; 
+  m_trackCreatorSettings.m_z0TrackCut = m_Z0TrackCut;
+  m_trackCreatorSettings.m_usingNonVertexTracks = m_UseNonVertexTracks;
+  m_trackCreatorSettings.m_usingUnmatchedNonVertexTracks = m_UseUnmatchedNonVertexTracks;
+  m_trackCreatorSettings.m_usingUnmatchedVertexTracks = m_UseUnmatchedVertexTracks;
+  m_trackCreatorSettings.m_unmatchedVertexTrackMaxEnergy = m_UnmatchedVertexTrackMaxEnergy; 
+  m_trackCreatorSettings.m_d0UnmatchedVertexTrackCut = m_D0UnmatchedVertexTrackCut; 
+  m_trackCreatorSettings.m_z0UnmatchedVertexTrackCut = m_Z0UnmatchedVertexTrackCut;
+  m_trackCreatorSettings.m_zCutForNonVertexTracks = m_ZCutForNonVertexTracks;
+  // Track "reaches ecal" parameters
+  m_trackCreatorSettings.m_reachesECalNTpcHits = m_ReachesECalNTpcHits;
+  m_trackCreatorSettings.m_reachesECalNFtdHits = m_ReachesECalNFtdHits;
+  m_trackCreatorSettings.m_reachesECalTpcOuterDistance = m_ReachesECalTpcOuterDistance;
+  m_trackCreatorSettings.m_reachesECalMinFtdLayer = m_ReachesECalMinFtdLayer;
+  m_trackCreatorSettings.m_reachesECalTpcZMaxDistance = m_ReachesECalTpcZMaxDistance;
+  m_trackCreatorSettings.m_reachesECalFtdZMaxDistance = m_ReachesECalFtdZMaxDistance;
+  m_trackCreatorSettings.m_curvatureToMomentumFactor = m_CurvatureToMomentumFactor;
+  m_trackCreatorSettings.m_minTrackECalDistanceFromIp = m_MinTrackECalDistanceFromIp;
+  // Final track quality parameters
+  m_trackCreatorSettings.m_maxTrackSigmaPOverP = m_MaxTrackSigmaPOverP;
+  m_trackCreatorSettings.m_minMomentumForTrackHitChecks = m_MinMomentumForTrackHitChecks;
+  m_trackCreatorSettings.m_tpcMembraneMaxZ = m_TpcMembraneMaxZ;
+  m_trackCreatorSettings.m_minTpcHitFractionOfExpected = m_MinTpcHitFractionOfExpected;
+  m_trackCreatorSettings.m_minFtdHitsForTpcHitFraction = m_MinFtdHitsForTpcHitFraction;
+  m_trackCreatorSettings.m_maxTpcInnerRDistance = m_MaxTpcInnerRDistance;
+  
+  
+  // Additional geometry parameters
+  m_geometryCreatorSettings.m_eCalEndCapInnerSymmetryOrder = m_ECalEndCapInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_eCalEndCapInnerPhiCoordinate = m_ECalEndCapInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_eCalEndCapOuterSymmetryOrder = m_ECalEndCapOuterSymmetryOrder;
+  m_geometryCreatorSettings.m_eCalEndCapOuterPhiCoordinate = m_ECalEndCapOuterPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalEndCapInnerSymmetryOrder = m_HCalEndCapInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalEndCapInnerPhiCoordinate = m_HCalEndCapInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalEndCapOuterSymmetryOrder = m_HCalEndCapOuterSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalEndCapOuterPhiCoordinate = m_HCalEndCapOuterPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalRingInnerSymmetryOrder = m_HCalRingInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalRingInnerPhiCoordinate = m_HCalRingInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalRingOuterSymmetryOrder = m_HCalRingOuterSymmetryOrder; 
+  m_geometryCreatorSettings.m_hCalRingOuterPhiCoordinate = m_HCalRingOuterPhiCoordinate;
+  
+  // For Strip Splitting method and also for hybrid ECAL
+  m_caloHitCreatorSettings.m_stripSplittingOn = m_StripSplittingOn;
+  m_caloHitCreatorSettings.m_useEcalScLayers = m_UseEcalScLayers;
+  // Parameters for hybrid ECAL
+  // Energy to MIP for Si-layers and Sc-layers, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToMip = m_ECalSiToMipCalibration;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToMip = m_ECalScToMipCalibration;
+  // MipThreshold for Si-layers and Sc-layers, respectively.
+  // Si
+  m_caloHitCreatorSettings.m_eCalSiMipThreshold = m_ECalSiMipThreshold;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScMipThreshold = m_ECalScMipThreshold;
+  // EcalToEM for Si-layers and Sc-layers, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToEMGeV = m_ECalSiToEMGeVCalibration;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToEMGeV = m_ECalScToEMGeVCalibration;
+  // EcalToHad for Si-layers and Sc-layers of the endcaps, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToHadGeVEndCap = m_ECalSiToHadGeVCalibrationEndCap;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToHadGeVEndCap = m_ECalScToHadGeVCalibrationEndCap;
+  // EcalToHad for Si-layers and Sc-layers of the barrel, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToHadGeVBarrel = m_ECalSiToHadGeVCalibrationBarrel;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToHadGeVBarrel = m_ECalScToHadGeVCalibrationBarrel;
+
+  try
+  {
+      ISvcLocator* svcloc = serviceLocator();
+      this->FinaliseSteeringParameters(svcloc);
+      m_pPandora = new pandora::Pandora();
+      m_pMCParticleCreator = new MCParticleCreator(m_mcParticleCreatorSettings, m_pPandora);
+      m_pGeometryCreator = new GeometryCreator(m_geometryCreatorSettings, m_pPandora);
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pGeometryCreator->CreateGeometry(svcloc));
+      m_pCaloHitCreator = new CaloHitCreator(m_caloHitCreatorSettings, m_pPandora, svcloc, 0);
+      m_pTrackCreator = new TrackCreator(m_trackCreatorSettings, m_pPandora, svcloc);
+      m_pPfoCreator = new PfoCreator(m_pfoCreatorSettings, m_pPandora);
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->RegisterUserComponents());
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::ReadSettings(*m_pPandora, m_settings.m_pandoraSettingsXmlFile));
+  }
+  catch (pandora::StatusCodeException &statusCodeException)
+  {
+      std::cout << "Failed to initialize gaudi pandora: " << statusCodeException.ToString() << std::endl;
+      throw statusCodeException;
+  }
+  catch (...)
+  {
+      std::cout << "Failed to initialize gaudi pandora: unrecognized exception" << std::endl;
+      throw;
+  }
+
+
+  return GaudiAlgorithm::initialize();
+}
+
+StatusCode PandoraPFAlg::execute()
+{
+    
+    try
+    {
+        
+        updateMap();
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateMCParticles(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pCaloHitCreator->CreateCaloHits(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateCaloHitToMCParticleRelationships(*m_CollectionMaps, m_pCaloHitCreator->GetCalorimeterHitVector() ));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pTrackCreator->CreateTrackAssociations(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pTrackCreator->CreateTracks(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateTrackToMCParticleRelationships(*m_CollectionMaps, m_pTrackCreator->GetTrackVector() ));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::ProcessEvent(*m_pPandora));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pPfoCreator->CreateParticleFlowObjects(*m_CollectionMaps, m_ClusterCollection_w, m_ReconstructedParticleCollection_w, m_VertexCollection_w));
+        
+        StatusCode sc0 = CreateMCRecoParticleAssociation();
+        StatusCode sc = Ana();
+
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Reset(*m_pPandora));
+        this->Reset();
+    }
+    catch (pandora::StatusCodeException &statusCodeException)
+    {
+        std::cout << "Gaudi pandora failed to process event: " << statusCodeException.ToString() << std::endl;
+        throw statusCodeException;
+    }
+    catch (...)
+    {
+        std::cout << "Gaudi pandora failed to process event: unrecognized exception" << std::endl;
+        throw;
+    }
+  
+  info() << "PandoraPFAlg Processed " << _nEvt << " events " << endmsg;
+  _nEvt ++ ;
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode PandoraPFAlg::finalize()
+{
+  info() << "Finalized. Processed " << _nEvt << " events " <<",saved tree with entries="<<m_tree->GetEntries()<< endmsg;
+  m_fout->cd();
+  m_tree->Write();
+  m_fout->Close();
+  delete m_pPandora;
+  delete m_pGeometryCreator;
+  delete m_pCaloHitCreator;
+  delete m_pTrackCreator;
+  delete m_pMCParticleCreator;
+  delete m_pPfoCreator;
+  return GaudiAlgorithm::finalize();
+}
+
+
+
+
+pandora::StatusCode PandoraPFAlg::RegisterUserComponents() const
+{
+    
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterAlgorithms(*m_pPandora));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterBasicPlugins(*m_pPandora));
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterBFieldPlugin(*m_pPandora,
+        m_settings.m_innerBField, m_settings.m_muonBarrelBField, m_settings.m_muonEndCapBField));
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterNonLinearityEnergyCorrection(*m_pPandora,
+        "NonLinearity", pandora::HADRONIC, m_settings.m_inputEnergyCorrectionPoints, m_settings.m_outputEnergyCorrectionPoints));
+    
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+void PandoraPFAlg::Reset()
+{
+    m_pCaloHitCreator->Reset();
+    m_pTrackCreator->Reset();
+    m_pMCParticleCreator->Reset();
+
+    std::vector<int>()  .swap(m_pReco_PID   );
+    std::vector<float>().swap(m_pReco_mass);
+    std::vector<float>().swap(m_pReco_energy);
+    std::vector<float>().swap(m_pReco_px);
+    std::vector<float>().swap(m_pReco_py);
+    std::vector<float>().swap(m_pReco_pz);
+    std::vector<float>().swap(m_pReco_charge);
+
+    std::vector<int>()  .swap(m_mc_p_size);
+    std::vector<int>()  .swap(m_mc_pid   );
+    std::vector<float>().swap(m_mc_mass  );
+    std::vector<float>().swap(m_mc_px    );
+    std::vector<float>().swap(m_mc_py    );
+    std::vector<float>().swap(m_mc_pz    );
+    std::vector<float>().swap(m_mc_charge);
+    m_hasConversion = 0;
+
+    m_CollectionMaps->clear();
+}
+
+const pandora::Pandora *PandoraPFAlg::GetPandora() const
+{
+    if (NULL == m_pPandora)
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+
+    return m_pPandora;
+}
+PandoraPFAlg::Settings::Settings() :
+    m_innerBField(3.5f),
+    m_muonBarrelBField(-1.5f),
+    m_muonEndCapBField(0.01f)
+{
+}
+CollectionMaps::CollectionMaps()
+{
+}
+void CollectionMaps::clear()
+{
+collectionMap_MC.clear();
+collectionMap_CaloHit.clear();
+collectionMap_Vertex.clear();
+collectionMap_Track.clear();
+collectionMap_CaloRel.clear();
+collectionMap_TrkRel.clear();
+}
+
+StatusCode PandoraPFAlg::updateMap()
+{
+        const edm4hep::MCParticleCollection*     MCParticle = nullptr;
+        const edm4hep::CalorimeterHitCollection* ECALBarrel = nullptr;        
+        const edm4hep::CalorimeterHitCollection* ECALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* ECALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALBarrel = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* MUON       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LCAL       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LHCAL      = nullptr; 
+        const edm4hep::CalorimeterHitCollection* BCAL       = nullptr; 
+        const edm4hep::VertexCollection* KinkVertices       = nullptr; 
+        const edm4hep::VertexCollection* ProngVertices      = nullptr; 
+        const edm4hep::VertexCollection* SplitVertices      = nullptr; 
+        const edm4hep::VertexCollection* V0Vertices         = nullptr; 
+        const edm4hep::TrackCollection*  MarlinTrkTracks    = nullptr; 
+        const edm4hep::MCRecoCaloAssociationCollection*  mcRecoCaloAssociation    = nullptr; 
+        const edm4hep::MCRecoTrackerAssociationCollection*  mcRecoTrackerAssociation    = nullptr; 
+        StatusCode sc = StatusCode::SUCCESS;
+        sc =  getCol(m_mcParCol_r  , MCParticle );
+        sc =  getCol(m_ECALBarrel_r, ECALBarrel );
+        sc =  getCol(m_ECALEndcap_r, ECALEndcap );
+        sc =  getCol(m_ECALOther_r , ECALOther  );
+        sc =  getCol(m_HCALBarrel_r, HCALBarrel );
+        sc =  getCol(m_HCALEndcap_r, HCALEndcap );
+        sc =  getCol(m_HCALOther_r , HCALOther  );
+        sc =  getCol(m_MUON_r      , MUON       );
+        sc =  getCol(m_LCAL_r      , LCAL       );
+        sc =  getCol(m_LHCAL_r     , LHCAL      );
+        sc =  getCol(m_BCAL_r      , BCAL       );        
+        sc =  getCol(m_KinkVertices_r  , KinkVertices );        
+        sc =  getCol(m_ProngVertices_r , ProngVertices);        
+        sc =  getCol(m_SplitVertices_r , SplitVertices);        
+        sc =  getCol(m_V0Vertices_r    , V0Vertices   );        
+        sc =  getCol(m_MarlinTrkTracks_r , MarlinTrkTracks   );        
+        sc =  getCol(m_MCRecoCaloAssociation_r , mcRecoCaloAssociation   );        
+        sc =  getCol(m_MCRecoTrackerAssociation_r , mcRecoTrackerAssociation);        
+
+        if (NULL != MCParticle   )  
+        {
+            std::vector<edm4hep::MCParticle> v_mc;
+            m_CollectionMaps->collectionMap_MC ["MCParticle"] = v_mc;
+            for(unsigned int i=0 ; i< MCParticle->size(); i++) m_CollectionMaps->collectionMap_MC ["MCParticle"].push_back(MCParticle->at(i));
+        }
+        if (NULL != ECALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["ECALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALBarrel->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALBarrel"].push_back(ECALBarrel->at(i));
+        }
+        if (NULL != ECALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["ECALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALEndcap->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALEndcap"].push_back(ECALEndcap->at(i));
+        }
+        if (NULL != ECALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["ECALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALOther->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALOther"].push_back(ECALOther->at(i));
+        }
+        if (NULL != HCALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["HCALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALBarrel->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALBarrel"].push_back(HCALBarrel->at(i));
+        }
+        if (NULL != HCALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["HCALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALEndcap->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALEndcap"].push_back(HCALEndcap->at(i));
+        }
+        if (NULL != HCALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["HCALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALOther->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALOther"].push_back(HCALOther->at(i));
+        }
+        if (NULL != MUON   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["MUON"] = v_cal ;
+            for(unsigned int i=0 ; i< MUON->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["MUON"].push_back(MUON->at(i));
+        }
+        if (NULL != LCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["LCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["LCAL"].push_back(LCAL->at(i));
+        }
+        if (NULL != LHCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["LHCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LHCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["LHCAL"].push_back(LHCAL->at(i));
+        }
+        if (NULL != BCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->collectionMap_CaloHit["BCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< BCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["BCAL"].push_back(BCAL->at(i));
+        }
+        if (NULL != KinkVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->collectionMap_Vertex["KinkVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< KinkVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["KinkVertices"].push_back(KinkVertices->at(i));
+        }
+        if (NULL != ProngVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->collectionMap_Vertex["ProngVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< ProngVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["ProngVertices"].push_back(ProngVertices->at(i));
+        }
+        if (NULL != SplitVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->collectionMap_Vertex["SplitVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< SplitVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["SplitVertices"].push_back(SplitVertices->at(i));
+        }
+        if (NULL != V0Vertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->collectionMap_Vertex["V0Vertices"] = v_cal ;
+            for(unsigned int i=0 ; i< V0Vertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["V0Vertices"].push_back(V0Vertices->at(i));
+        }
+        if (NULL != MarlinTrkTracks   )
+        {
+            std::vector<edm4hep::Track> v_cal;
+            m_CollectionMaps->collectionMap_Track["MarlinTrkTracks"] = v_cal ;
+            for(unsigned int i=0 ; i< MarlinTrkTracks->size(); i++) m_CollectionMaps->collectionMap_Track ["MarlinTrkTracks"].push_back(MarlinTrkTracks->at(i));
+        }
+        if (NULL != mcRecoCaloAssociation )
+        {
+            std::vector<edm4hep::MCRecoCaloAssociation> v_cal;
+            m_CollectionMaps->collectionMap_CaloRel["RecoCaloAssociation"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoCaloAssociation->size(); i++) m_CollectionMaps->collectionMap_CaloRel ["RecoCaloAssociation"].push_back(mcRecoCaloAssociation->at(i));
+        }
+        if (NULL != mcRecoTrackerAssociation )
+        {
+            std::vector<edm4hep::MCRecoTrackerAssociation> v_cal;
+            m_CollectionMaps->collectionMap_TrkRel["RecoTrackerAssociation"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoTrackerAssociation->size(); i++) m_CollectionMaps->collectionMap_TrkRel ["RecoTrackerAssociation"].push_back(mcRecoTrackerAssociation->at(i));
+        }
+    return StatusCode::SUCCESS;
+}
+
+
+
+
+StatusCode PandoraPFAlg::Ana()
+{
+    int n_current = m_tree->GetEntries()+1;
+    const edm4hep::ReconstructedParticleCollection* reco_col = m_ReconstructedParticleCollection_w.get();
+    const edm4hep::MCRecoParticleAssociationCollection* reco_associa_col = m_MCRecoParticleAssociation_w.get();
+    for(int i=0; i<reco_col->size();i++)
+    {
+        const edm4hep::ReconstructedParticle pReco = reco_col->at(i);
+        const float px = pReco.getMomentum()[0];
+        const float py = pReco.getMomentum()[1];
+        const float pz = pReco.getMomentum()[2];
+        const float energy = pReco.getEnergy();
+        const float mass = pReco.getMass();
+        const float charge = pReco.getCharge();
+        const int type = pReco.getType();
+        m_pReco_PID.push_back(type);
+        m_pReco_mass.push_back(mass);
+        m_pReco_charge.push_back(charge);
+        m_pReco_energy.push_back(energy);
+        m_pReco_px.push_back(px);
+        m_pReco_py.push_back(py);
+        m_pReco_pz.push_back(pz);
+        for(int j=0; j < reco_associa_col->size(); j++)
+        {
+            if(reco_associa_col->at(j).getRec().id() != pReco.id() ) continue;
+            std::cout<<"MC pid ="<<reco_associa_col->at(j).getSim().getPDG()<<",weight="<<reco_associa_col->at(j).getWeight()<<", px="<<reco_associa_col->at(j).getSim().getMomentum()[0]<<", py="<<reco_associa_col->at(j).getSim().getMomentum()[1]<<",pz="<<reco_associa_col->at(j).getSim().getMomentum()[2]<<std::endl;
+        }
+    }
+    const edm4hep::MCParticleCollection*     MCParticle = nullptr;
+    StatusCode sc = StatusCode::SUCCESS;
+    sc =  getCol(m_mcParCol_r  , MCParticle );
+    if (NULL != MCParticle   )  
+    { 
+        for(unsigned int i=0 ; i< MCParticle->size(); i++)
+        {
+            m_mc_p_size.push_back(MCParticle->at(i).parents_size());
+            m_mc_pid   .push_back(MCParticle->at(i).getPDG());
+            m_mc_mass  .push_back(MCParticle->at(i).getMass());
+            m_mc_px    .push_back(MCParticle->at(i).getMomentum()[0]);
+            m_mc_py    .push_back(MCParticle->at(i).getMomentum()[1]);
+            m_mc_pz    .push_back(MCParticle->at(i).getMomentum()[2]);
+            m_mc_charge.push_back(MCParticle->at(i).getCharge());
+            //if(MCParticle->at(i).parents_size()==0) std::cout<<"MYDBUG evt="<<n_current<<", mc i="<<i<<",px="<<MCParticle->at(i).getMomentum()[0]<<",py="<<MCParticle->at(i).getMomentum()[1]<<",pz="<<MCParticle->at(i).getMomentum()[2]<<std::endl;
+            if (MCParticle->at(i).getPDG() != 22) continue;
+            int hasEm = 0;
+            int hasEp = 0;
+            for(unsigned int j =0 ; j< MCParticle->at(i).daughters_size(); j++)
+            {
+                if      (MCParticle->at(i).getDaughters(j).getPDG() ==  11 ) hasEm=1;
+                else if (MCParticle->at(i).getDaughters(j).getPDG() == -11 ) hasEp=1;
+            }
+            if(hasEm && hasEp) m_hasConversion=1;
+        }
+    }
+    m_tree->Fill();
+    return StatusCode::SUCCESS;
+}
+
+
+// create simple MCRecoParticleAssociation using calorimeter hit only now
+StatusCode PandoraPFAlg::CreateMCRecoParticleAssociation()
+{
+    edm4hep::MCRecoParticleAssociationCollection* pMCRecoParticleAssociationCollection  = m_MCRecoParticleAssociation_w.createAndPut();
+    const edm4hep::ReconstructedParticleCollection* reco_col = m_ReconstructedParticleCollection_w.get();
+    for(int i=0; i<reco_col->size();i++)
+    {
+        std::map<int, edm4hep::ConstMCParticle> mc_map;
+        std::map<int, float > id_edep_map;
+        float tot_en = 0 ;
+        const edm4hep::ReconstructedParticle pReco = reco_col->at(i);
+        for(int j=0; j < pReco.clusters_size(); j++)
+        {
+            edm4hep::ConstCluster cluster = pReco.getClusters(j);
+            for(int k=0; k < cluster.hits_size(); k++)
+            {
+                edm4hep::ConstCalorimeterHit hit = cluster.getHits(k);
+                for(std::map<std::string, std::vector<edm4hep::MCRecoCaloAssociation> >::iterator iter = m_CollectionMaps->collectionMap_CaloRel.begin(); iter != m_CollectionMaps->collectionMap_CaloRel.end(); iter++)
+                {
+                    for(std::vector<edm4hep::MCRecoCaloAssociation>::iterator it = iter->second.begin(); it != iter->second.end(); it ++)
+                    {
+                        if(it->getRec().id() != hit.id()) continue;
+                        for(std::vector<edm4hep::ConstCaloHitContribution>::const_iterator itc = it->getSim().contributions_begin(); itc != it->getSim().contributions_end(); itc++)
+                        {
+                            if(mc_map.find(itc->getParticle().id()) == mc_map.end()) mc_map[itc->getParticle().id()] = itc->getParticle() ;
+                            if(id_edep_map.find(itc->getParticle().id()) != id_edep_map.end()) id_edep_map[itc->getParticle().id()] = id_edep_map[itc->getParticle().id()] + itc->getEnergy() ;
+                            else                                                               id_edep_map[itc->getParticle().id()] = itc->getEnergy() ;
+                            tot_en += itc->getEnergy() ;
+                        }
+                    }
+                }
+            }
+        }
+        for(std::map<int, edm4hep::ConstMCParticle>::iterator it = mc_map.begin(); it != mc_map.end(); it ++)
+        {      
+            edm4hep::MCRecoParticleAssociation association = pMCRecoParticleAssociationCollection->create();
+            association.setRec(pReco);
+            association.setSim(it->second);
+            if(tot_en==0) 
+            {
+                association.setWeight(0);
+                std::cout<<"Found 0 cluster energy"<<std::endl;
+            }  
+            else if(id_edep_map.find(it->first) != id_edep_map.end()) association.setWeight(id_edep_map[it->first]/tot_en);
+            else std::cout<<"Error in creating MCRecoParticleAssociation"<<std::endl;
+        }
+    }
+    return StatusCode::SUCCESS;
+}
+
+
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/PfoCreator.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/PfoCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce3cedd677748da435ee71bd1897c94a20ac7f67
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/PfoCreator.cpp
@@ -0,0 +1,410 @@
+/**
+ *  @brief  Implementation of the pfo creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "Api/PandoraApi.h"
+
+#include "Objects/Cluster.h"
+#include "Objects/ParticleFlowObject.h"
+#include "Objects/Track.h"
+
+#include "Pandora/PdgTable.h"
+#include "PfoCreator.h"
+#include "PandoraPFAlg.h"
+
+#include <algorithm>
+#include <cmath>
+
+PfoCreator::PfoCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+PfoCreator::~PfoCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode PfoCreator::CreateParticleFlowObjects(CollectionMaps& collectionMaps, DataHandle<edm4hep::ClusterCollection>& _pClusterCollection, DataHandle<edm4hep::ReconstructedParticleCollection>& _pReconstructedParticleCollection, DataHandle<edm4hep::VertexCollection>& _pStartVertexCollection)
+{
+    m_collectionMaps = &collectionMaps;
+    edm4hep::ClusterCollection* pClusterCollection                              = _pClusterCollection.createAndPut();
+    edm4hep::ReconstructedParticleCollection* pReconstructedParticleCollection  = _pReconstructedParticleCollection.createAndPut();
+    edm4hep::VertexCollection* pStartVertexCollection                           = _pStartVertexCollection.createAndPut();
+ 
+    const pandora::PfoList *pPandoraPfoList = NULL;
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::GetCurrentPfoList(*m_pPandora, pPandoraPfoList));
+
+    pandora::StringVector subDetectorNames;
+    this->InitialiseSubDetectorNames(subDetectorNames);
+
+    std::cout<<"pPandoraPfoList size="<<pPandoraPfoList->size()<<std::endl;
+    for (pandora::PfoList::const_iterator pIter = pPandoraPfoList->begin(), pIterEnd = pPandoraPfoList->end(); pIter != pIterEnd; ++pIter)
+    {
+        const pandora::ParticleFlowObject *const pPandoraPfo(*pIter);
+        edm4hep::ReconstructedParticle pReconstructedParticle0 = pReconstructedParticleCollection->create();
+        edm4hep::ReconstructedParticle* pReconstructedParticle = &pReconstructedParticle0;
+
+        const bool hasTrack(!pPandoraPfo->GetTrackList().empty());
+        const pandora::ClusterList &clusterList(pPandoraPfo->GetClusterList());
+
+        float clustersTotalEnergy(0.f);
+        pandora::CartesianVector referencePoint(0.f, 0.f, 0.f), clustersWeightedPosition(0.f, 0.f, 0.f);
+        for (pandora::ClusterList::const_iterator cIter = clusterList.begin(), cIterEnd = clusterList.end(); cIter != cIterEnd; ++cIter)
+        {
+            const pandora::Cluster *const pPandoraCluster(*cIter);
+            pandora::CaloHitList pandoraCaloHitList;
+            pPandoraCluster->GetOrderedCaloHitList().FillCaloHitList(pandoraCaloHitList);
+            pandoraCaloHitList.insert(pandoraCaloHitList.end(), pPandoraCluster->GetIsolatedCaloHitList().begin(), pPandoraCluster->GetIsolatedCaloHitList().end());
+
+            pandora::FloatVector hitE, hitX, hitY, hitZ;
+            edm4hep::Cluster p_Cluster0 = pClusterCollection->create();
+            edm4hep::Cluster* p_Cluster = &p_Cluster0;
+            this->SetClusterSubDetectorEnergies(subDetectorNames, p_Cluster, pandoraCaloHitList, hitE, hitX, hitY, hitZ);
+
+            float clusterCorrectEnergy(0.f);
+            this->SetClusterEnergyAndError(pPandoraPfo, pPandoraCluster, p_Cluster, clusterCorrectEnergy);
+
+            pandora::CartesianVector clusterPosition(0.f, 0.f, 0.f);
+            const unsigned int nHitsInCluster(pandoraCaloHitList.size());
+            this->SetClusterPositionAndError(nHitsInCluster, hitE, hitX, hitY, hitZ, p_Cluster, clusterPosition);
+
+            if (!hasTrack)
+            {
+                clustersWeightedPosition += clusterPosition * clusterCorrectEnergy;
+                clustersTotalEnergy += clusterCorrectEnergy;
+            }
+
+            edm4hep::ConstCluster p_ClusterCon = *p_Cluster;
+            pReconstructedParticle->addToClusters(p_ClusterCon);
+        }
+
+        if (!hasTrack)
+        {
+            if (clustersTotalEnergy < std::numeric_limits<float>::epsilon())
+            {
+                std::cout<<"WARNING PfoCreator::CreateParticleFlowObjects: invalid cluster energy " << clustersTotalEnergy << std::endl;
+                throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+            }
+            else
+            {
+                referencePoint = clustersWeightedPosition * (1.f / clustersTotalEnergy);
+            }
+        }
+        else
+        {
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CalculateTrackBasedReferencePoint(pPandoraPfo, referencePoint));
+        }
+
+        this->SetRecoParticleReferencePoint(referencePoint, pReconstructedParticle);
+        this->AddTracksToRecoParticle(pPandoraPfo, pReconstructedParticle);
+        this->SetRecoParticlePropertiesFromPFO(pPandoraPfo, pReconstructedParticle);
+
+        edm4hep::Vertex pStartVertex0 = pStartVertexCollection->create();
+        edm4hep::Vertex* pStartVertex = &pStartVertex0;
+        pStartVertex->setAlgorithmType(0);
+        const float ref_value[3] = {referencePoint.GetX(),referencePoint.GetY(),referencePoint.GetZ()};
+        pStartVertex->setPosition(edm4hep::Vector3f(ref_value));
+        pStartVertex->setAssociatedParticle(*pReconstructedParticle);
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::InitialiseSubDetectorNames(pandora::StringVector &subDetectorNames) const
+{
+    subDetectorNames.push_back("ecal");
+    subDetectorNames.push_back("hcal");
+    subDetectorNames.push_back("yoke");
+    subDetectorNames.push_back("lcal");
+    subDetectorNames.push_back("lhcal");
+    subDetectorNames.push_back("bcal");
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterSubDetectorEnergies(const pandora::StringVector &subDetectorNames, edm4hep::Cluster *const p_Cluster,
+    const pandora::CaloHitList &pandoraCaloHitList, pandora::FloatVector &hitE, pandora::FloatVector &hitX, pandora::FloatVector &hitY,
+    pandora::FloatVector &hitZ) const
+{
+    for (pandora::CaloHitList::const_iterator hIter = pandoraCaloHitList.begin(), hIterEnd = pandoraCaloHitList.end(); hIter != hIterEnd; ++hIter)
+    {
+        const pandora::CaloHit *const pPandoraCaloHit(*hIter);
+        edm4hep::CalorimeterHit *const pCalorimeterHit0 = (edm4hep::CalorimeterHit*)(pPandoraCaloHit->GetParentAddress());
+        const edm4hep::CalorimeterHit pCalorimeterHit = *pCalorimeterHit0;
+        
+        p_Cluster->addToHits(pCalorimeterHit);
+
+        const float caloHitEnergy(pCalorimeterHit.getEnergy());
+        hitE.push_back(caloHitEnergy);
+        hitX.push_back(pCalorimeterHit.getPosition()[0]);
+        hitY.push_back(pCalorimeterHit.getPosition()[1]);
+        hitZ.push_back(pCalorimeterHit.getPosition()[2]);
+        /*Can be added later 
+        std::vector<float> &subDetectorEnergies = p_Cluster->subdetectorEnergies();
+        subDetectorEnergies.resize(subDetectorNames.size());
+
+        switch (CHT(pCalorimeterHit->getType()).caloID())
+        {
+            case CHT::ecal:  subDetectorEnergies[ECAL_INDEX ] += caloHitEnergy; break;
+            case CHT::hcal:  subDetectorEnergies[HCAL_INDEX ] += caloHitEnergy; break;
+            case CHT::yoke:  subDetectorEnergies[YOKE_INDEX ] += caloHitEnergy; break;
+            case CHT::lcal:  subDetectorEnergies[LCAL_INDEX ] += caloHitEnergy; break;
+            case CHT::lhcal: subDetectorEnergies[LHCAL_INDEX] += caloHitEnergy; break;
+            case CHT::bcal:  subDetectorEnergies[BCAL_INDEX ] += caloHitEnergy; break;
+            default: streamlog_out(WARNING) << "PfoCreator::SetClusterSubDetectorEnergies: no subdetector found for hit with type: " << pCalorimeterHit->getType() << std::endl;
+        }
+        */
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterEnergyAndError(const pandora::ParticleFlowObject *const pPandoraPfo, const pandora::Cluster *const pPandoraCluster, 
+    edm4hep::Cluster *const p_Cluster, float &clusterCorrectEnergy) const
+{
+    const bool isEmShower((pandora::PHOTON == pPandoraPfo->GetParticleId()) || (pandora::E_MINUS == std::abs(pPandoraPfo->GetParticleId())));
+    clusterCorrectEnergy = (isEmShower ? pPandoraCluster->GetCorrectedElectromagneticEnergy(*m_pPandora) : pPandoraCluster->GetCorrectedHadronicEnergy(*m_pPandora));
+
+    if (clusterCorrectEnergy < std::numeric_limits<float>::epsilon())
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+
+    const float stochasticTerm(isEmShower ? m_settings.m_emStochasticTerm : m_settings.m_hadStochasticTerm); 
+    const float constantTerm(isEmShower ? m_settings.m_emConstantTerm : m_settings.m_hadConstantTerm);
+    const float energyError(std::sqrt(stochasticTerm * stochasticTerm / clusterCorrectEnergy + constantTerm * constantTerm) * clusterCorrectEnergy);
+
+    p_Cluster->setEnergy(clusterCorrectEnergy);
+    p_Cluster->setEnergyError(energyError);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterPositionAndError(const unsigned int nHitsInCluster, pandora::FloatVector &hitE, pandora::FloatVector &hitX, 
+    pandora::FloatVector &hitY, pandora::FloatVector &hitZ, edm4hep::Cluster *const p_Cluster, pandora::CartesianVector &clusterPositionVec) const
+{
+    ClusterShapes *const pClusterShapes(new ClusterShapes(nHitsInCluster, hitE.data(), hitX.data(), hitY.data(), hitZ.data()));//this need GSL/1.14 
+
+    try
+    {
+        p_Cluster->setPhi(std::atan2(pClusterShapes->getEigenVecInertia()[1], pClusterShapes->getEigenVecInertia()[0]));
+        p_Cluster->setITheta(std::acos(pClusterShapes->getEigenVecInertia()[2]));
+        p_Cluster->setPosition(pClusterShapes->getCentreOfGravity());
+        clusterPositionVec.SetValues(pClusterShapes->getCentreOfGravity()[0], pClusterShapes->getCentreOfGravity()[1], pClusterShapes->getCentreOfGravity()[2]);
+    }
+    catch (...)
+    {
+        std::cout<<"WARNING PfoCreator::SetClusterPositionAndError: unidentified exception caught." << std::endl;
+    }
+
+    delete pClusterShapes;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode PfoCreator::CalculateTrackBasedReferencePoint(const pandora::ParticleFlowObject *const pPandoraPfo, pandora::CartesianVector &referencePoint) const
+{
+    const pandora::TrackList &trackList(pPandoraPfo->GetTrackList());
+
+    float totalTrackMomentumAtDca(0.f), totalTrackMomentumAtStart(0.f);
+    pandora::CartesianVector referencePointAtDCAWeighted(0.f, 0.f, 0.f), referencePointAtStartWeighted(0.f, 0.f, 0.f);
+
+    bool hasSiblings(false);
+    for (pandora::TrackList::const_iterator tIter = trackList.begin(), tIterEnd = trackList.end(); tIter != tIterEnd; ++tIter)
+    {
+        const pandora::Track *const pPandoraTrack(*tIter);
+
+        if (!this->IsValidParentTrack(pPandoraTrack, trackList))
+            continue;
+
+        if (this->HasValidSiblingTrack(pPandoraTrack, trackList))
+        {
+            // Presence of sibling tracks typically represents a conversion
+            const pandora::CartesianVector &trackStartPoint((pPandoraTrack->GetTrackStateAtStart()).GetPosition());
+            const float trackStartMomentum(((pPandoraTrack->GetTrackStateAtStart()).GetMomentum()).GetMagnitude());
+            referencePointAtStartWeighted += trackStartPoint * trackStartMomentum;
+            totalTrackMomentumAtStart += trackStartMomentum;
+            hasSiblings = true;
+        }
+        else
+        {
+            const edm4hep::Track *const pLcioTrack0 = (edm4hep::Track*)(pPandoraTrack->GetParentAddress());
+            const edm4hep::Track pLcioTrack = *pLcioTrack0;
+
+            const float z0(pPandoraTrack->GetZ0());
+            pandora::CartesianVector intersectionPoint(0.f, 0.f, 0.f);
+
+            if(pLcioTrack.trackStates_size()==0) throw "zero trackStates size find";
+            intersectionPoint.SetValues(pLcioTrack.getTrackStates(0).D0 * std::cos(pLcioTrack.getTrackStates(0).phi), pLcioTrack.getTrackStates(0).D0 * std::sin(pLcioTrack.getTrackStates(0).phi), z0);
+            const float trackMomentumAtDca((pPandoraTrack->GetMomentumAtDca()).GetMagnitude());
+            referencePointAtDCAWeighted += intersectionPoint * trackMomentumAtDca;
+            totalTrackMomentumAtDca += trackMomentumAtDca;
+        }
+    }
+
+    if (hasSiblings)
+    {
+        if (totalTrackMomentumAtStart < std::numeric_limits<float>::epsilon())
+        {
+            std::cout<<" WARNING PfoCreator::CalculateTrackBasedReferencePoint: invalid track momentum " << totalTrackMomentumAtStart << std::endl;
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+        }
+        else
+        {
+            referencePoint = referencePointAtStartWeighted * (1.f / totalTrackMomentumAtStart);
+        }
+    }
+    else
+    {
+        if (totalTrackMomentumAtDca < std::numeric_limits<float>::epsilon())
+        {
+            std::cout<<"WARNING PfoCreator::CalculateTrackBasedReferencePoint: invalid track momentum " << totalTrackMomentumAtDca << std::endl;
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+        }
+        else
+        {
+            referencePoint = referencePointAtDCAWeighted * (1.f / totalTrackMomentumAtDca);
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::IsValidParentTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &parentTrackList(pPandoraTrack->GetParentList());
+
+    for (pandora::TrackList::const_iterator iter = parentTrackList.begin(), iterEnd = parentTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            continue;
+
+        // ATTN This track must have a parent not in the all track list; still use it if it is the closest to the ip
+        std::cout<<"WARNING PfoCreator::IsValidParentTrack: mismatch in track relationship information, use information as available " << std::endl;
+
+        if (this->IsClosestTrackToIP(pPandoraTrack, allTrackList))
+            return true;
+
+        return false;
+    }
+
+    // Ideal case: All parents are associated to same pfo
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::HasValidSiblingTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &siblingTrackList(pPandoraTrack->GetSiblingList());
+
+    for (pandora::TrackList::const_iterator iter = siblingTrackList.begin(), iterEnd = siblingTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            continue;
+
+        // ATTN This track must have a sibling not in the all track list; still use it if it has a second sibling that is in the list
+        std::cout<<"WARNING PfoCreator::HasValidSiblingTrack: mismatch in track relationship information, use information as available " << std::endl;
+
+        if (this->AreAnyOtherSiblingsInList(pPandoraTrack, allTrackList))
+            return true;
+
+        return false;
+    }
+
+    // Ideal case: All siblings associated to same pfo
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::IsClosestTrackToIP(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const 
+{
+    const pandora::Track *pClosestTrack(NULL);
+    float closestTrackDisplacement(std::numeric_limits<float>::max()); 
+
+    for (pandora::TrackList::const_iterator iter = allTrackList.begin(), iterEnd = allTrackList.end(); iter != iterEnd; ++iter)
+    {
+        const pandora::Track *const pTrack(*iter);
+        const float trialTrackDisplacement(pTrack->GetTrackStateAtStart().GetPosition().GetMagnitude());
+
+        if (trialTrackDisplacement < closestTrackDisplacement)
+        {
+            closestTrackDisplacement = trialTrackDisplacement;
+            pClosestTrack = pTrack;
+        }
+    }
+
+    return (pPandoraTrack == pClosestTrack);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::AreAnyOtherSiblingsInList(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &siblingTrackList(pPandoraTrack->GetSiblingList());
+
+    for (pandora::TrackList::const_iterator iter = siblingTrackList.begin(), iterEnd = siblingTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            return true;
+    }
+
+    return false;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetRecoParticleReferencePoint(const pandora::CartesianVector &referencePoint, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const float referencePointArray[3] = {referencePoint.GetX(), referencePoint.GetY(), referencePoint.GetZ()};
+    pReconstructedParticle->setReferencePoint(referencePointArray);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::AddTracksToRecoParticle(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const pandora::TrackList &trackList(pPandoraPfo->GetTrackList());
+
+    for (pandora::TrackList::const_iterator tIter = trackList.begin(), tIterEnd = trackList.end(); tIter != tIterEnd; ++tIter)
+    {
+        const pandora::Track *const pTrack(*tIter);
+        const edm4hep::Track *const pLcioTrack0 = (edm4hep::Track*)(pTrack->GetParentAddress());
+        const edm4hep::Track pLcioTrack = *pLcioTrack0;
+        pReconstructedParticle->addToTracks(pLcioTrack);
+
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetRecoParticlePropertiesFromPFO(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const float momentum[3] = {pPandoraPfo->GetMomentum().GetX(), pPandoraPfo->GetMomentum().GetY(), pPandoraPfo->GetMomentum().GetZ()};
+    pReconstructedParticle->setMomentum(momentum);
+    pReconstructedParticle->setEnergy(pPandoraPfo->GetEnergy());
+    pReconstructedParticle->setMass(pPandoraPfo->GetMass());
+    pReconstructedParticle->setCharge(pPandoraPfo->GetCharge());
+    pReconstructedParticle->setType(pPandoraPfo->GetParticleId());
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+PfoCreator::Settings::Settings():
+    m_emStochasticTerm(0.17f),
+    m_hadStochasticTerm(0.6f),
+    m_emConstantTerm(0.01f),
+    m_hadConstantTerm(0.03f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/TrackCreator.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/TrackCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dc23c5725546cdb3626cbe3b4c1281648e4da8a
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/TrackCreator.cpp
@@ -0,0 +1,948 @@
+/**
+ * 
+ *  @brief  Implementation of the track creator class.
+ * 
+ *  $Log: $
+ */
+
+
+//#include "UTIL/ILDConf.h"
+
+#include "edm4hep/Vertex.h"
+#include "edm4hep/ReconstructedParticle.h"
+
+#include "gear/BField.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/TPCParameters.h"
+#include "gear/FTDParameters.h"
+#include "gear/FTDLayerLayout.h"
+
+#include "GaudiKernel/IService.h"
+#include "GearSvc/IGearSvc.h"
+#include "PandoraPFAlg.h"
+
+#include "TrackCreator.h"
+#include "Pandora/PdgTable.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+TrackCreator::TrackCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+
+
+    m_bField                  = (_GEAR->getBField().at(gear::Vector3D(0., 0., 0.)).z());
+    m_tpcInnerR               = (_GEAR->getTPCParameters().getPadLayout().getPlaneExtent()[0]);
+    m_tpcOuterR               = (_GEAR->getTPCParameters().getPadLayout().getPlaneExtent()[1]);
+    m_tpcMaxRow               = (_GEAR->getTPCParameters().getPadLayout().getNRows());
+    m_tpcZmax                 = (_GEAR->getTPCParameters().getMaxDriftLength());
+    m_eCalBarrelInnerSymmetry = (_GEAR->getEcalBarrelParameters().getSymmetryOrder());
+    m_eCalBarrelInnerPhi0     = (_GEAR->getEcalBarrelParameters().getPhi0());
+    m_eCalBarrelInnerR        = (_GEAR->getEcalBarrelParameters().getExtent()[0]);
+    m_eCalEndCapInnerZ        = (_GEAR->getEcalEndcapParameters().getExtent()[2]);
+    // fg: FTD description in GEAR has changed ...
+    try
+    {
+        m_ftdInnerRadii = _GEAR->getGearParameters("FTD").getDoubleVals("FTDInnerRadius");
+        m_ftdOuterRadii = _GEAR->getGearParameters("FTD").getDoubleVals("FTDOuterRadius");
+        m_ftdZPositions = _GEAR->getGearParameters("FTD").getDoubleVals("FTDZCoordinate");
+        m_nFtdLayers = m_ftdZPositions.size();
+    }
+    catch (gear::UnknownParameterException &)
+    {
+        const gear::FTDLayerLayout &ftdLayerLayout(_GEAR->getFTDParameters().getFTDLayerLayout());
+        std::cout << " Filling FTD parameters from gear::FTDParameters - n layers: " << ftdLayerLayout.getNLayers() << std::endl;
+
+        for(unsigned int i = 0, N = ftdLayerLayout.getNLayers(); i < N; ++i)
+        {
+            // Create a disk to represent even number petals front side
+            m_ftdInnerRadii.push_back(ftdLayerLayout.getSensitiveRinner(i));
+            m_ftdOuterRadii.push_back(ftdLayerLayout.getMaxRadius(i));
+
+            // Take the mean z position of the staggered petals
+            const double zpos(ftdLayerLayout.getZposition(i));
+            m_ftdZPositions.push_back(zpos);
+            std::cout << "     layer " << i << " - mean z position = " << zpos << std::endl;
+        }
+
+        m_nFtdLayers = m_ftdZPositions.size() ;
+    }
+
+    // Check tpc parameters
+    if ((std::fabs(m_tpcZmax) < std::numeric_limits<float>::epsilon()) || (std::fabs(m_tpcInnerR) < std::numeric_limits<float>::epsilon())
+        || (std::fabs(m_tpcOuterR - m_tpcInnerR) < std::numeric_limits<float>::epsilon()))
+    {
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    m_cosTpc = m_tpcZmax / std::sqrt(m_tpcZmax * m_tpcZmax + m_tpcInnerR * m_tpcInnerR);
+
+    // Check ftd parameters
+    if ((0 == m_nFtdLayers) || (m_nFtdLayers != m_ftdInnerRadii.size()) || (m_nFtdLayers != m_ftdOuterRadii.size()))
+    {
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    for (unsigned int iFtdLayer = 0; iFtdLayer < m_nFtdLayers; ++iFtdLayer)
+    {
+        if ((std::fabs(m_ftdOuterRadii[iFtdLayer]) < std::numeric_limits<float>::epsilon()) ||
+            (std::fabs(m_ftdInnerRadii[iFtdLayer]) < std::numeric_limits<float>::epsilon()))
+        {
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+        }
+    }
+
+    m_tanLambdaFtd = m_ftdZPositions[0] / m_ftdOuterRadii[0];
+
+    // Calculate etd and set parameters
+    // fg: make SET and ETD optional - as they might not be in the model ...
+    try
+    {
+        const DoubleVector &etdZPositions(_GEAR->getGearParameters("ETD").getDoubleVals("ETDLayerZ"));
+        const DoubleVector &setInnerRadii(_GEAR->getGearParameters("SET").getDoubleVals("SETLayerRadius"));
+
+        if (etdZPositions.empty() || setInnerRadii.empty())
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+
+        m_minEtdZPosition = *(std::min_element(etdZPositions.begin(), etdZPositions.end()));
+        m_minSetRadius = *(std::min_element(setInnerRadii.begin(), setInnerRadii.end()));
+    }
+    catch(gear::UnknownParameterException &)
+    {
+        std::cout << "Warnning, ETDLayerZ or SETLayerRadius parameters missing from GEAR parameters!" << std::endl
+                               << "     -> both will be set to " << std::numeric_limits<float>::quiet_NaN() << std::endl;
+
+        //fg: Set them to NAN, so that they cannot be used to set   trackParameters.m_reachesCalorimeter = true;
+        m_minEtdZPosition = std::numeric_limits<float>::quiet_NaN();
+        m_minSetRadius = std::numeric_limits<float>::quiet_NaN();
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+TrackCreator::~TrackCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::CreateTrackAssociations(const CollectionMaps& collectionMaps)//TODO, due to the lack of full Vertex information
+{
+//    TODO, because the Vertex.getAssociatedParticle() doesn't work for LCIO to plcio transfer
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractKinks(collectionMaps));
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractProngsAndSplits(const CollectionMaps& collectionMaps));
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractV0s(const CollectionMaps& collectionMaps));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode TrackCreator::ExtractKinks(const CollectionMaps& collectionMaps)
+{
+    std::cout<<"start TrackCreator::ExtractKinks:"<<std::endl;
+    for (StringVector::const_iterator iter = m_settings.m_kinkVertexCollections.begin(), iterEnd = m_settings.m_kinkVertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.CollectionMap_Vertex.find(*iter) == collectionMaps.CollectionMap_Vertex.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const edm4hep::VertexCollection *pKinkCollection = (collectionMaps.CollectionMap_Vertex.find(*iter))->second;
+
+            for (int i = 0, iMax = pKinkCollection->size(); i < iMax; ++i)
+            {
+                try
+                {
+                    const edm4hep::Vertex  pVertex0 = pKinkCollection->at(i);
+                    const edm4hep::Vertex* pVertex  = &(pVertex0);
+
+                    if (NULL == pVertex) throw ("Collection type mismatch");
+
+                    std::cout<<"pVertex0 getChi2="<<pVertex0.getChi2()<<std::endl;
+                    std::cout<<"pVertex getChi2="<<pVertex->getChi2()<<std::endl;
+                    std::cout<<"Hi 0 "<<std::endl;
+                    const plcio::ConstReconstructedParticle pReconstructedParticle0 = pVertex0.getAssociatedParticle();
+                    std::cout<<"Hi 1"<<std::endl;
+                    //EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const plcio::ConstReconstructedParticle pReconstructedParticle = pVertex->getAssociatedParticle();
+                    std::cout<<"Hi 2:"<<&pReconstructedParticle<<std::endl;
+                    //const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+                    //plcio::ConstTrack trackVec = pReconstructedParticle.getTracks();
+
+                    std::cout<<"pReconstructedParticle0 en="<<pReconstructedParticle0.getEnergy()<<std::endl;
+                    std::cout<<"pReconstructedParticle en="<<pReconstructedParticle.getEnergy()<<std::endl;
+                    //if (this->IsConflictingRelationship(trackVec))continue;
+                    if (this->IsConflictingRelationship(pReconstructedParticle))continue;
+
+                    //const int vertexPdgCode(pReconstructedParticle->getType());
+                    const int vertexPdgCode(pReconstructedParticle.getType());
+
+                    // Extract the kink vertex information
+                    //for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    //for (unsigned int iTrack = 0, nTracks = trackVec.tracks_size(); iTrack < nTracks; ++iTrack)
+                    for (unsigned int iTrack = 0, nTracks = pReconstructedParticle.tracks_size(); iTrack < nTracks; ++iTrack)
+                    {
+                        //EVENT::Track *pTrack = trackVec[iTrack];
+                        //plcio::ConstTrack pTrack = trackVec.getTracks(iTrack);
+                        plcio::ConstTrack pTrack = pReconstructedParticle.getTracks(iTrack);
+                        //(0 == iTrack) ? m_parentTrackList.insert(pTrack) : m_daughterTrackList.insert(pTrack);
+                        (0 == iTrack) ? m_parentTrackList.insert(pTrack.id()) : m_daughterTrackList.insert(pTrack.id());
+                       //std::cout << "KinkTrack " << iTrack << ", nHits " << pTrack.getTrackerHits().size() << std::endl;
+                       std::cout << "KinkTrack " << iTrack << ", nHits " << pTrack.trackerHits_size() << std::endl;
+
+                        int trackPdgCode = pandora::UNKNOWN_PARTICLE_TYPE;
+
+                        if (0 == iTrack)
+                        {
+                            trackPdgCode = vertexPdgCode;
+                        }
+                        else
+                        {
+                            switch (vertexPdgCode)
+                            {
+                            case pandora::PI_PLUS :
+                            case pandora::K_PLUS :
+                                trackPdgCode = pandora::MU_PLUS;
+                                break;
+                            case pandora::PI_MINUS :
+                            case pandora::K_MINUS :
+                                trackPdgCode = pandora::MU_MINUS;
+                                break;
+                            case pandora::HYPERON_MINUS_BAR :
+                            case pandora::SIGMA_PLUS :
+                                trackPdgCode = pandora::PI_PLUS;
+                                break;
+                            case pandora::SIGMA_MINUS :
+                            case pandora::HYPERON_MINUS :
+                                trackPdgCode = pandora::PI_PLUS;
+                                break;
+                            default :
+                                //(pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                                (pTrack.getTrackStates(0).omega > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                                break;
+                            }
+                        }
+
+                        m_trackToPidMap.insert(TrackToPidMap::value_type(pTrack, trackPdgCode));
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track parent-daughter relationships
+                        if (0 == iTrack)
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, pTrack, trackVec[jTrack]));
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(trackVec.getTracks(jTrack).id()) ) );
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(pReconstructedParticle.getTracks(jTrack).id()) ) );
+                            }
+                        }
+
+                        // Make track sibling relationships
+                        else
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, pTrack, trackVec[jTrack]));
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(trackVec.getTracks(jTrack).id()) ));
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(pReconstructedParticle.getTracks(jTrack).id()) ));
+                            }
+                        }
+                    }
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract kink vertex: " <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract kink vertex collection: " << *iter <<  std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode TrackCreator::ExtractProngsAndSplits(const EVENT::LCEvent *const pLCEvent)
+{
+    for (StringVector::const_iterator iter = m_settings.m_prongSplitVertexCollections.begin(), iterEnd = m_settings.m_prongSplitVertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pProngOrSplitCollection = pLCEvent->getCollection(*iter);
+
+            for (int i = 0, iMax = pProngOrSplitCollection->getNumberOfElements(); i < iMax; ++i)
+            {
+                try
+                {
+                    EVENT::Vertex *pVertex = dynamic_cast<Vertex*>(pProngOrSplitCollection->getElementAt(i));
+
+                    if (NULL == pVertex)
+                        throw EVENT::Exception("Collection type mismatch");
+
+                    EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+
+                    if (this->IsConflictingRelationship(trackVec))
+                        continue;
+
+                    // Extract the prong/split vertex information
+                    for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    {
+                        EVENT::Track *pTrack = trackVec[iTrack];
+                        (0 == iTrack) ? m_parentTrackList.insert(pTrack) : m_daughterTrackList.insert(pTrack);
+                        streamlog_out(DEBUG) << "Prong or Split Track " << iTrack << ", nHits " << pTrack->getTrackerHits().size() << std::endl;
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track parent-daughter relationships
+                        if (0 == iTrack)
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora,
+                                    pTrack, trackVec[jTrack]));
+                            }
+                        }
+
+                        // Make track sibling relationships
+                        else
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora,
+                                    pTrack, trackVec[jTrack]));
+                            }
+                        }
+                    }
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract prong/split vertex: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract prong/split vertex collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::ExtractV0s(const EVENT::LCEvent *const pLCEvent)
+{
+    for (StringVector::const_iterator iter = m_settings.m_v0VertexCollections.begin(), iterEnd = m_settings.m_v0VertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pV0Collection = pLCEvent->getCollection(*iter);
+
+            for (int i = 0, iMax = pV0Collection->getNumberOfElements(); i < iMax; ++i)
+            {
+                try
+                {
+                    EVENT::Vertex *pVertex = dynamic_cast<Vertex*>(pV0Collection->getElementAt(i));
+
+                    if (NULL == pVertex)
+                        throw EVENT::Exception("Collection type mismatch");
+
+                    EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+
+                    if (this->IsConflictingRelationship(trackVec))
+                        continue;
+
+                    // Extract the v0 vertex information
+                    const int vertexPdgCode(pReconstructedParticle->getType());
+
+                    for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    {
+                        EVENT::Track *pTrack = trackVec[iTrack];
+                        m_v0TrackList.insert(pTrack);
+                        streamlog_out(DEBUG) << "V0Track " << iTrack << ", nHits " << pTrack->getTrackerHits().size() << std::endl;
+
+                        int trackPdgCode = pandora::UNKNOWN_PARTICLE_TYPE;
+
+                        switch (vertexPdgCode)
+                        {
+                        case pandora::PHOTON :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::E_PLUS : trackPdgCode = pandora::E_MINUS;
+                            break;
+                        case pandora::LAMBDA :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PROTON : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        case pandora::LAMBDA_BAR :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PROTON_BAR;
+                            break;
+                        case pandora::K_SHORT :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        default :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        }
+
+                        m_trackToPidMap.insert(TrackToPidMap::value_type(pTrack, trackPdgCode));
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track sibling relationships
+                        for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                        {
+                            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora,
+                                pTrack, trackVec[jTrack]));
+                        }
+                    }
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract v0 vertex: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract v0 vertex collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool TrackCreator::IsConflictingRelationship(const edm4hep::ConstReconstructedParticle &Particle) const
+{
+    for (unsigned int iTrack = 0, nTracks = Particle.tracks_size(); iTrack < nTracks; ++iTrack)
+    {
+        edm4hep::ConstTrack pTrack = Particle.getTracks(iTrack) ;
+        unsigned int pTrack_id = pTrack.id() ;
+
+        if (this->IsDaughter(pTrack_id) || this->IsParent(pTrack_id) || this->IsV0(pTrack_id))
+            return true;
+    }
+
+    return false;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::CreateTracks(const CollectionMaps& collectionMaps)
+{
+    std::cout<<"start TrackCreator::CreateTracks:"<<std::endl;
+    for (StringVector::const_iterator iter = m_settings.m_trackCollections.begin(), iterEnd = m_settings.m_trackCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_Track.find(*iter) == collectionMaps.collectionMap_Track.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::Track>& pTrackCollection = (collectionMaps.collectionMap_Track.find(*iter))->second;
+
+            for (int i = 0, iMax = pTrackCollection.size(); i < iMax; ++i)
+            {
+                try
+                {
+                    const edm4hep::Track& pTrack0 = pTrackCollection.at(i);
+                    const edm4hep::Track* pTrack  = (const edm4hep::Track*)(&pTrack0);
+
+                    if (NULL == pTrack) throw ("Collection type mismatch");
+
+                    int minTrackHits = m_settings.m_minTrackHits;
+                    const float tanLambda(std::fabs(pTrack->getTrackStates(0).tanLambda));
+
+                    if (tanLambda > m_tanLambdaFtd)
+                    {
+                        int expectedFtdHits(0);
+
+                        for (unsigned int iFtdLayer = 0; iFtdLayer < m_nFtdLayers; ++iFtdLayer)
+                        {
+                            if ((tanLambda > m_ftdZPositions[iFtdLayer] / m_ftdOuterRadii[iFtdLayer]) &&
+                                (tanLambda < m_ftdZPositions[iFtdLayer] / m_ftdInnerRadii[iFtdLayer]))
+                            {
+                                expectedFtdHits++;
+                            }
+                        }
+
+                        minTrackHits = std::max(m_settings.m_minFtdTrackHits, expectedFtdHits);
+                    }
+
+                    const int nTrackHits(static_cast<int>(pTrack->trackerHits_size()));
+
+                    if ((nTrackHits < minTrackHits) || (nTrackHits > m_settings.m_maxTrackHits))
+                        continue;
+
+                    // Proceed to create the pandora track
+                    PandoraApi::Track::Parameters trackParameters;
+                    trackParameters.m_d0 = pTrack->getTrackStates(0).D0;
+                    trackParameters.m_z0 = pTrack->getTrackStates(0).Z0;
+                    trackParameters.m_pParentAddress = pTrack;
+                    // By default, assume tracks are charged pions
+                    const float signedCurvature(pTrack->getTrackStates(0).omega);
+                    trackParameters.m_particleId = (signedCurvature > 0) ? pandora::PI_PLUS : pandora::PI_MINUS;
+                    trackParameters.m_mass = pandora::PdgTable::GetParticleMass(pandora::PI_PLUS);
+
+                    // Use particle id information from V0 and Kink finders
+                    TrackToPidMap::const_iterator iter_t = m_trackToPidMap.find(*pTrack);
+
+                    if(iter_t != m_trackToPidMap.end())
+                    {
+                        trackParameters.m_particleId = (*iter_t).second;
+                        trackParameters.m_mass = pandora::PdgTable::GetParticleMass((*iter_t).second);
+                    }
+
+                    if (std::numeric_limits<float>::epsilon() < std::fabs(signedCurvature))
+                        trackParameters.m_charge = static_cast<int>(signedCurvature / std::fabs(signedCurvature));
+
+                    this->GetTrackStates(pTrack, trackParameters);
+                    this->TrackReachesECAL(pTrack, trackParameters);
+                    this->DefineTrackPfoUsage(pTrack, trackParameters);
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Track::Create(*m_pPandora, trackParameters));
+                    m_trackVector.push_back(pTrack);
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"Failed to extract a track: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract a track "<< std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<<"Failed to extract track collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::GetTrackStates(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    edm4hep::TrackState pTrackState = pTrack->getTrackStates(1); // ref  /cvmfs/cepcsw.ihep.ac.cn/prototype/LCIO/include/EVENT/TrackState.h 
+
+    const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState.omega));
+    trackParameters.m_momentumAtDca = pandora::CartesianVector(std::cos(pTrackState.phi), std::sin(pTrackState.phi), pTrackState.tanLambda) * pt;
+    this->CopyTrackState(pTrack->getTrackStates(2), trackParameters.m_trackStateAtStart);
+
+    auto pEndTrack = (pTrack->tracks_size() ==0 ) ?  *pTrack  :  pTrack->getTracks(pTrack->tracks_size()-1);
+
+    this->CopyTrackState(pEndTrack.getTrackStates(3), trackParameters.m_trackStateAtEnd);
+    //FIXME ? LCIO input only has 4 states, so 4 can't be used.
+    this->CopyTrackState(pEndTrack.getTrackStates(3), trackParameters.m_trackStateAtCalorimeter);
+    
+    
+    trackParameters.m_isProjectedToEndCap = ((std::fabs(trackParameters.m_trackStateAtCalorimeter.Get().GetPosition().GetZ()) < m_eCalEndCapInnerZ) ? false : true);
+
+    // Convert generic time (length from reference point to intersection, divided by momentum) into nanoseconds
+    const float minGenericTime(this->CalculateTrackTimeAtCalorimeter(pTrack));
+    const float particleMass(trackParameters.m_mass.Get());
+    const float particleEnergy(std::sqrt(particleMass * particleMass + trackParameters.m_momentumAtDca.Get().GetMagnitudeSquared()));
+    trackParameters.m_timeAtCalorimeter = minGenericTime * particleEnergy / 299.792f;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+float TrackCreator::CalculateTrackTimeAtCalorimeter(const edm4hep::Track *const pTrack) const
+{
+    const pandora::Helix helix(pTrack->getTrackStates(0).phi, pTrack->getTrackStates(0).D0, pTrack->getTrackStates(0).Z0, pTrack->getTrackStates(0).omega, pTrack->getTrackStates(0).tanLambda, m_bField);
+    const pandora::CartesianVector &referencePoint(helix.GetReferencePoint());
+
+    // First project to endcap
+    float minGenericTime(std::numeric_limits<float>::max());
+
+    pandora::CartesianVector bestECalProjection(0.f, 0.f, 0.f);
+    const int signPz((helix.GetMomentum().GetZ() > 0.f) ? 1 : -1);
+    (void) helix.GetPointInZ(static_cast<float>(signPz) * m_eCalEndCapInnerZ, referencePoint, bestECalProjection, minGenericTime);
+
+    // Then project to barrel surface(s)
+    pandora::CartesianVector barrelProjection(0.f, 0.f, 0.f);
+    if (m_eCalBarrelInnerSymmetry > 0)
+    {
+        // Polygon
+        float twopi_n = 2. * M_PI / (static_cast<float>(m_eCalBarrelInnerSymmetry));
+
+        for (int i = 0; i < m_eCalBarrelInnerSymmetry; ++i)
+        {
+            float genericTime(std::numeric_limits<float>::max());
+            const float phi(twopi_n * static_cast<float>(i) + m_eCalBarrelInnerPhi0);
+
+            const pandora::StatusCode statusCode(helix.GetPointInXY(m_eCalBarrelInnerR * std::cos(phi), m_eCalBarrelInnerR * std::sin(phi),
+                std::cos(phi + 0.5 * M_PI), std::sin(phi + 0.5 * M_PI), referencePoint, barrelProjection, genericTime));
+
+            if ((pandora::STATUS_CODE_SUCCESS == statusCode) && (genericTime < minGenericTime))
+            {
+                minGenericTime = genericTime;
+                bestECalProjection = barrelProjection;
+            }
+        }
+    }
+    else
+    {
+        // Cylinder
+        float genericTime(std::numeric_limits<float>::max());
+        const pandora::StatusCode statusCode(helix.GetPointOnCircle(m_eCalBarrelInnerR, referencePoint, barrelProjection, genericTime));
+
+        if ((pandora::STATUS_CODE_SUCCESS == statusCode) && (genericTime < minGenericTime))
+        {
+            minGenericTime = genericTime;
+            bestECalProjection = barrelProjection;
+        }
+    }
+
+    if (bestECalProjection.GetMagnitudeSquared() < std::numeric_limits<float>::epsilon())
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+
+    return minGenericTime;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::CopyTrackState(const edm4hep::TrackState & pTrackState, pandora::InputTrackState &inputTrackState) const
+{
+    const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState.omega));
+
+    const double px(pt * std::cos(pTrackState.phi));
+    const double py(pt * std::sin(pTrackState.phi));
+    const double pz(pt * pTrackState.tanLambda);
+
+    const double xs(pTrackState.referencePoint[0]);
+    const double ys(pTrackState.referencePoint[1]);
+    const double zs(pTrackState.referencePoint[2]);
+
+    inputTrackState = pandora::TrackState(xs, ys, zs, px, py, pz);
+}
+
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::TrackReachesECAL(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    
+    // Calculate hit position information
+    float hitZMin(std::numeric_limits<float>::max());
+    float hitZMax(-std::numeric_limits<float>::max());
+    float hitOuterR(-std::numeric_limits<float>::max());
+
+    int maxOccupiedFtdLayer=0;
+    
+    
+    const unsigned int nTrackHits(pTrack->trackerHits_size());
+    for (unsigned int i = 0; i < nTrackHits; ++i)
+    {
+        
+        const edm4hep::ConstTrackerHit Hit ( pTrack->getTrackerHits(i) );
+        const edm4hep::Vector3d pos = Hit.getPosition();
+        
+        float x = float(pos[0]);
+        float y = float(pos[1]);
+        float z = float(pos[2]);
+        float r = std::sqrt(x * x + y * y);
+
+        if (z > hitZMax) hitZMax = z;
+
+        if (z < hitZMin) hitZMin = z;
+
+        if (r > hitOuterR) hitOuterR = r;
+
+        if ((r > m_tpcInnerR) && (r < m_tpcOuterR) && (std::fabs(z) <= m_tpcZmax))  continue;
+
+        for (unsigned int j = 0; j < m_nFtdLayers; ++j)
+        {
+            if ((r > m_ftdInnerRadii[j]) && (r < m_ftdOuterRadii[j]) &&
+                (std::fabs(z) - m_settings.m_reachesECalFtdZMaxDistance < m_ftdZPositions[j]) &&
+                (std::fabs(z) + m_settings.m_reachesECalFtdZMaxDistance > m_ftdZPositions[j]))
+            {
+                if ( j > maxOccupiedFtdLayer) maxOccupiedFtdLayer = j;
+                break;
+            }
+        }
+    }
+    const int nTpcHits(this->GetNTpcHits(pTrack));
+    const int nFtdHits(this->GetNFtdHits(pTrack));
+
+    // Look to see if there are hits in etd or set, implying track has reached edge of ecal
+    if ((hitOuterR > m_minSetRadius) || (hitZMax > m_minEtdZPosition))
+    {
+        trackParameters.m_reachesCalorimeter = true;
+        return;
+    }
+
+    // Require sufficient hits in tpc or ftd, then compare extremal hit positions with tracker dimensions
+    if ((nTpcHits >= m_settings.m_reachesECalNTpcHits) || (nFtdHits >= m_settings.m_reachesECalNFtdHits))
+    {
+        if ((hitOuterR - m_tpcOuterR > m_settings.m_reachesECalTpcOuterDistance) ||
+            (std::fabs(hitZMax) - m_tpcZmax > m_settings.m_reachesECalTpcZMaxDistance) ||
+            (std::fabs(hitZMin) - m_tpcZmax > m_settings.m_reachesECalTpcZMaxDistance) ||
+            (maxOccupiedFtdLayer >= m_settings.m_reachesECalMinFtdLayer))
+        {
+            trackParameters.m_reachesCalorimeter = true;
+            return;
+        }
+    }
+
+    // If track is lowpt, it may curl up and end inside tpc inner radius
+    const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+    const float cosAngleAtDca(std::fabs(momentumAtDca.GetZ()) / momentumAtDca.GetMagnitude());
+    const float pX(momentumAtDca.GetX()), pY(momentumAtDca.GetY());
+    const float pT(std::sqrt(pX * pX + pY * pY));
+
+    if ((cosAngleAtDca > m_cosTpc) || (pT < m_settings.m_curvatureToMomentumFactor * m_bField * m_tpcOuterR))
+    {
+        trackParameters.m_reachesCalorimeter = true;
+        return;
+    }
+    
+    trackParameters.m_reachesCalorimeter = false;
+    
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::DefineTrackPfoUsage(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    bool canFormPfo(false);
+    bool canFormClusterlessPfo(false);
+
+    if (trackParameters.m_reachesCalorimeter.Get() && !this->IsParent(pTrack->id()))
+    {
+        const float d0(std::fabs(pTrack->getTrackStates(0).D0)), z0(std::fabs(pTrack->getTrackStates(0).Z0));
+
+        float rInner(std::numeric_limits<float>::max()), zMin(std::numeric_limits<float>::max());
+
+        for (std::vector<edm4hep::ConstTrackerHit>::const_iterator iter = pTrack->trackerHits_begin(), iterEnd = pTrack->trackerHits_end(); iter != iterEnd; ++iter)
+        {
+            const edm4hep::Vector3d pPosition = (*iter).getPosition(); 
+            const float x(pPosition[0]), y(pPosition[1]), absoluteZ(std::fabs(pPosition[2]));
+            const float r(std::sqrt(x * x + y * y));
+
+            if (r < rInner)
+                rInner = r;
+
+            if (absoluteZ < zMin)
+                zMin = absoluteZ;
+        }
+
+        if (this->PassesQualityCuts(pTrack, trackParameters))
+        {
+            const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+            const float pX(momentumAtDca.GetX()), pY(momentumAtDca.GetY()), pZ(momentumAtDca.GetZ());
+            const float pT(std::sqrt(pX * pX + pY * pY));
+
+            const float zCutForNonVertexTracks(m_tpcInnerR * std::fabs(pZ / pT) + m_settings.m_zCutForNonVertexTracks);
+            const bool passRzQualityCuts((zMin < zCutForNonVertexTracks) && (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance));
+
+            const bool isV0(this->IsV0(pTrack->id()));
+            const bool isDaughter(this->IsDaughter(pTrack->id()));
+
+            // Decide whether track can be associated with a pandora cluster and used to form a charged PFO
+            if ((d0 < m_settings.m_d0TrackCut) && (z0 < m_settings.m_z0TrackCut) && (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance))
+            {
+                canFormPfo = true;
+            }
+            else if (passRzQualityCuts && (0 != m_settings.m_usingNonVertexTracks))
+            {
+                canFormPfo = true;
+            }
+            else if (isV0 || isDaughter)
+            {
+                canFormPfo = true;
+            }
+
+            // Decide whether track can be used to form a charged PFO, even if track fails to be associated with a pandora cluster
+            const float particleMass(trackParameters.m_mass.Get());
+            const float trackEnergy(std::sqrt(momentumAtDca.GetMagnitudeSquared() + particleMass * particleMass));
+
+            if ((0 != m_settings.m_usingUnmatchedVertexTracks) && (trackEnergy < m_settings.m_unmatchedVertexTrackMaxEnergy))
+            {
+                if ((d0 < m_settings.m_d0UnmatchedVertexTrackCut) && (z0 < m_settings.m_z0UnmatchedVertexTrackCut) &&
+                    (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance))
+                {
+                    canFormClusterlessPfo = true;
+                }
+                else if (passRzQualityCuts && (0 != m_settings.m_usingNonVertexTracks) && (0 != m_settings.m_usingUnmatchedNonVertexTracks))
+                {
+                    canFormClusterlessPfo = true;
+                }
+                else if (isV0 || isDaughter)
+                {
+                    canFormClusterlessPfo = true;
+                }
+            }
+        }
+        else if (this->IsDaughter(pTrack->id()) || this->IsV0(pTrack->id()))
+        {
+            std::cout<<"WARNING Recovering daughter or v0 track " << trackParameters.m_momentumAtDca.Get().GetMagnitude() << std::endl;
+            canFormPfo = true;
+        }
+    }
+
+    trackParameters.m_canFormPfo = canFormPfo;
+    trackParameters.m_canFormClusterlessPfo = canFormClusterlessPfo;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool TrackCreator::PassesQualityCuts(const edm4hep::Track *const pTrack, const PandoraApi::Track::Parameters &trackParameters) const
+{
+    // First simple sanity checks
+    if (trackParameters.m_trackStateAtCalorimeter.Get().GetPosition().GetMagnitude() < m_settings.m_minTrackECalDistanceFromIp)
+        return false;
+
+    if (std::fabs(pTrack->getTrackStates(0).omega) < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"ERROR Track has Omega = 0 " << std::endl;
+        return false;
+    }
+
+    // Check momentum uncertainty is reasonable to use track
+    const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+    const float sigmaPOverP(std::sqrt(pTrack->getTrackStates(0).covMatrix[5]) / std::fabs(pTrack->getTrackStates(0).omega));
+
+    if (sigmaPOverP > m_settings.m_maxTrackSigmaPOverP)
+    {
+        std::cout<<"WARNING Dropping track : " << momentumAtDca.GetMagnitude() << "+-" << sigmaPOverP * (momentumAtDca.GetMagnitude())
+                               << " chi2 = " <<  pTrack->getChi2() << " " << pTrack->getNdf()
+                               << " from " << pTrack->trackerHits_size() << std::endl;
+        return false;
+    }
+
+    // Require reasonable number of TPC hits 
+    if (momentumAtDca.GetMagnitude() > m_settings.m_minMomentumForTrackHitChecks)
+    {
+        const float pX(fabs(momentumAtDca.GetX()));
+        const float pY(fabs(momentumAtDca.GetY()));
+        const float pZ(fabs(momentumAtDca.GetZ()));
+        const float pT(std::sqrt(pX * pX + pY * pY));
+        const float rInnermostHit(pTrack->getRadiusOfInnermostHit());
+
+        if ((std::numeric_limits<float>::epsilon() > std::fabs(pT)) || (std::numeric_limits<float>::epsilon() > std::fabs(pZ)) || (rInnermostHit == m_tpcOuterR))
+        {
+            std::cout<<"ERROR Invalid track parameter, pT " << pT << ", pZ " << pZ << ", rInnermostHit " << rInnermostHit << std::endl;
+            return false;
+        }
+
+        float nExpectedTpcHits(0.);
+
+        if (pZ < m_tpcZmax / m_tpcOuterR * pT)
+        {
+            const float innerExpectedHitRadius(std::max(m_tpcInnerR, rInnermostHit));
+            const float frac((m_tpcOuterR - innerExpectedHitRadius) / (m_tpcOuterR - m_tpcInnerR));
+            nExpectedTpcHits = m_tpcMaxRow * frac;
+        }
+
+        if ((pZ <= m_tpcZmax / m_tpcInnerR * pT) && (pZ >= m_tpcZmax / m_tpcOuterR * pT))
+        {
+            const float innerExpectedHitRadius(std::max(m_tpcInnerR, rInnermostHit));
+            const float frac((m_tpcZmax * pT / pZ - innerExpectedHitRadius) / (m_tpcOuterR - innerExpectedHitRadius));
+            nExpectedTpcHits = frac * m_tpcMaxRow;
+        }
+
+        // TODO Get TPC membrane information from GEAR when available
+        if (std::fabs(pZ) / momentumAtDca.GetMagnitude() < m_settings.m_tpcMembraneMaxZ / m_tpcInnerR)
+            nExpectedTpcHits = 0;
+
+        const int nTpcHits(this->GetNTpcHits(pTrack));
+        const int nFtdHits(this->GetNFtdHits(pTrack));
+
+        const int minTpcHits = static_cast<int>(nExpectedTpcHits * m_settings.m_minTpcHitFractionOfExpected);
+
+        if ((nTpcHits < minTpcHits) && (nFtdHits < m_settings.m_minFtdHitsForTpcHitFraction))
+        {
+            std::cout<<"WARNING Dropping track : " << momentumAtDca.GetMagnitude() << " Number of TPC hits = " << nTpcHits
+                                   << " < " << minTpcHits << " nftd = " << nFtdHits  << std::endl;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+int TrackCreator::GetNTpcHits(const edm4hep::Track *const pTrack) const
+{
+    // ATTN
+    //fg: hit numbers are now given in different order wrt LOI:  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 1 ] =  hitsInFit ;  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 2 ] =  hitCount ;  
+    // ---- use hitsInFit :
+    //return pTrack->getSubdetectorHitNumbers()[ 2 * lcio::ILDDetID::TPC - 1 ];
+    return pTrack->getSubDetectorHitNumbers(2 * 4 - 1);// lcio::ILDDetID::TPC=4, still use LCIO code now
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+int TrackCreator::GetNFtdHits(const edm4hep::Track *const pTrack) const
+{
+    // ATTN
+    //fg: hit numbers are now given in different order wrt LOI:  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 1 ] =  hitsInFit ;  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 2 ] =  hitCount ;  
+    // ---- use hitsInFit :
+    //return pTrack->getSubdetectorHitNumbers()[ 2 * lcio::ILDDetID::FTD - 1 ];
+    return pTrack->getSubDetectorHitNumbers( 2 * 3 - 1 );// lcio::ILDDetID::FTD=3
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+TrackCreator::Settings::Settings() :
+    m_shouldFormTrackRelationships(1),
+    m_minTrackHits(5),
+    m_minFtdTrackHits(0),
+    m_maxTrackHits(5000.f),
+    m_d0TrackCut(50.f),
+    m_z0TrackCut(50.f),
+    m_usingNonVertexTracks(1),
+    m_usingUnmatchedNonVertexTracks(0),
+    m_usingUnmatchedVertexTracks(1),
+    m_unmatchedVertexTrackMaxEnergy(5.f),
+    m_d0UnmatchedVertexTrackCut(5.f),
+    m_z0UnmatchedVertexTrackCut(5.f),
+    m_zCutForNonVertexTracks(250.f),
+    m_reachesECalNTpcHits(11),
+    m_reachesECalNFtdHits(4),
+    m_reachesECalTpcOuterDistance(-100.f),
+    m_reachesECalMinFtdLayer(9),
+    m_reachesECalTpcZMaxDistance(-50.f),
+    m_reachesECalFtdZMaxDistance(1.f),
+    m_curvatureToMomentumFactor(0.3f / 2000.f),
+    m_minTrackECalDistanceFromIp(100.f),
+    m_maxTrackSigmaPOverP(0.15f),
+    m_minMomentumForTrackHitChecks(1.f),
+    m_tpcMembraneMaxZ(10.f),
+    m_maxTpcInnerRDistance(50.f),
+    m_minTpcHitFractionOfExpected(0.2f),
+    m_minFtdHitsForTpcHitFraction(2)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/GaudiPandora/src/Utility.cpp b/Reconstruction/PFA/Pandora/GaudiPandora/src/Utility.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..819fa15d4771c80d65e6437d22ebd46120d311de
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/GaudiPandora/src/Utility.cpp
@@ -0,0 +1,7 @@
+#include "Utility.h"
+
+std::string Convert (float number){
+    std::ostringstream buff;
+    buff<<number;
+    return buff.str();   
+}
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.cc b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e7e8d4fca32578d72ccad1c451164b2d441f7687
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.cc
@@ -0,0 +1,2005 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+#include "ClusterShapes.h"
+
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_matrix.h>
+//#include <gsl/gsl_blas.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_eigen.h>
+#include <gsl/gsl_multifit_nlin.h>
+#include <gsl/gsl_sf_gamma.h>
+#include <gsl/gsl_integration.h>
+//#include <gsl/gsl_rng.h>
+//#include <gsl/gsl_sf_pow_int.h>
+
+
+
+// #################################################
+// #####                                       #####
+// #####  Additional Structures and Functions  #####
+// #####                                       #####
+// #################################################
+//=============================================================================
+
+struct data {
+  int n;
+  float* x;
+  float* y;
+  float* z;
+  float* ex;
+  float* ey;
+  float* ez;
+};
+
+//=============================================================================
+
+// Gammafunction
+double G(double x) {
+
+  return gsl_sf_gamma(x);
+  
+}
+
+//=============================================================================
+
+// inverse Gammafunction
+double invG(double x) {
+  
+ return gsl_sf_gammainv(x);
+    
+}
+
+//=============================================================================
+
+// Integral needed for deriving the derivative of the Gammafunction
+double Integral_G(double x, void* params) {
+  double a = *(double*)params;
+  double f = exp(-x) * pow(x,a-1) * log(x);
+  return f;
+}
+    
+//=============================================================================
+
+double DinvG(double x) {
+
+  int workspace_size = 1000;
+  double abs_error = 0;
+  double rel_error = 1e-6;
+  double result = 0.0;
+  double error = 0.0;
+  int status = 0;
+  
+  gsl_integration_workspace* w  = gsl_integration_workspace_alloc(workspace_size);
+  gsl_function F;
+  F.function = &Integral_G;
+  F.params = &x;
+    
+  status = gsl_integration_qagiu(&F,0,abs_error,rel_error,workspace_size,w,
+      			   &result,&error); 
+
+  // debug  
+  /*  
+  printf ("Numeric Integration : \n");
+  printf ("parameter of integration = % .18f\n", x);
+  printf ("status of integration    = %d \n"   , status);
+  printf ("result                   = % .18f\n", result);
+  printf ("estimated error          = % .18f\n", error);
+  printf ("intervals                =  %d\n\n", w->size);
+  */
+  
+  double G2 = pow(gsl_sf_gamma(x),2); 
+  double DG = result;
+  
+  gsl_integration_workspace_free(w);
+  
+  return -DG/G2;
+
+}
+
+//=============================================================================
+
+int ShapeFitFunct(const gsl_vector* par, void* d, gsl_vector* f) {
+
+  // Used for shape fitting. Function to fit: 
+  //
+  // a[i](t[i],s[i]) =
+  // 
+  // E0 * b * 1/Gamma(a) * ( b * (t[i] - t0) )^(a-1) * exp(-b*(t[i] - t0)) * exp(-d*s[i])
+  //
+  // Function to minimise:
+  //
+  // f0[i] =  E0 * b * 1/Gamma(a) * 
+  //        ( b * (t[i] - t0) )^(a-1) * exp(-b*(t[i] - t0)) * exp(-d*s[i]) - a[i]
+  //
+
+
+  //  float E0   = gsl_vector_get(par,0);
+  float A    = gsl_vector_get(par,0);
+  float B    = gsl_vector_get(par,1);
+  float D    = gsl_vector_get(par,2);
+  float t0   = gsl_vector_get(par,3);
+  int n      = ((struct data*)d)->n;
+  float* t   = ((struct data*)d)->x;
+  float* s   = ((struct data*)d)->y;
+  float* a   = ((struct data*)d)->z; // amplitude stored in z[i]
+  float fi   = 0.0;
+
+
+  for (int i(0); i < n; i++) {
+    fi = /*E0 * */ B * invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) * exp(-D*s[i]) 
+         - a[i];
+    gsl_vector_set(f,i,fi);
+  }
+
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int dShapeFitFunct(const gsl_vector* par, void* d, gsl_matrix* J) {
+
+  // Used for shape fitting
+  //float E0  = gsl_vector_get(par,0);
+  float A   = gsl_vector_get(par,0);
+  float B   = gsl_vector_get(par,1);
+  float D   = gsl_vector_get(par,2);
+  float t0  = gsl_vector_get(par,3);
+  int n     = ((struct data*)d)->n;
+  float* t  = ((struct data*)d)->x;
+  float* s  = ((struct data*)d)->y;
+
+
+  // calculate Jacobi's matrix J[i][j] = dfi/dparj, but here only one dimension
+
+  for (int i(0); i < n; i++) {
+
+    /*    
+    gsl_matrix_set(J,i,0,B * invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) 
+		                                            * exp(-D*s[i]) );
+    */
+
+    gsl_matrix_set(J,i,0,( /* E0 * */ B * invG(A) * log(B*(t[i]-t0))*pow(B*(t[i]-t0),A-1) * 
+			   exp(-B*(t[i]-t0)) + DinvG(A) * /* E0 * */ B * pow(B*(t[i]-t0),A-1) *
+			                       exp(-B*(t[i]-t0))
+			 ) * exp(-D*s[i]));
+		         
+    gsl_matrix_set(J,i,1,( /* E0 * */ invG(A) * pow(B*(t[i]-t0),A-1) * exp(-B*(t[i]-t0)) +
+			   /* E0 * */ invG(A) * (A-1) * B * (t[i]-t0) * pow(B*(t[i]-t0),A-2) * 
+			                                exp(-B*(t[i]-t0)) -
+			   /* E0 * */ B * invG(A) * (t[i]-t0) * pow(B*(t[i]-t0),A-1) * 
+			                                exp(-B*(t[i]-t0)) 
+			 ) * exp(-D*s[i]));
+                         
+    gsl_matrix_set(J,i,2,-/* E0 * */ B * invG(A) * s[i] * pow(B*(t[i]-t0),A-1) *
+		         exp(-B*(t[i]-t0)) * exp(-D*s[i]));
+       		         
+    gsl_matrix_set(J,i,3,(-/* E0 * */ pow(B,2) * invG(A) * (A-1) * pow(B*(t[i]-t0),A-2) * 
+			                                     exp(-B*(t[i]-t0)) +
+			   /* E0 * */ pow(B,2) * invG(A) * pow(B*(t[i]-t0),A-1) * 
+			                             exp(-B*(t[i]-t0))
+			 ) * exp(-D*s[i]));
+ 		         
+
+  }
+  
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int fdfShapeFitFunct(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {
+
+  //     For helix fitting
+  ShapeFitFunct(par, d, f);
+  dShapeFitFunct(par, d, J);
+
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+int signum(float x) {
+
+  // computes the signum of x. Needed for the 3. parametrisation
+
+  if ( x >= 0 ) return 1; // x == 0 is taken as positive
+  else return -1;
+
+}
+
+//=============================================================================
+
+int functParametrisation1(const gsl_vector* par, void* d, gsl_vector* f) {
+
+  //     For helix fitting
+  // calculate fit function f0[i] = 
+  // ( (x0 + R*cos(b*z[i] + phi0)) - x[i] ) for i = 0 to n-1
+  //                    and f1[i] = 
+  // ( (y0 + R*sin(b*z[i] + phi0)) - y[i] ) for i = n to dim*n - 1
+  // That means, minimise the two functions f0[i] and f1[i]
+
+  float x0   = gsl_vector_get(par,0);
+  float y0   = gsl_vector_get(par,1);
+  float R    = gsl_vector_get(par,2);
+  float b    = gsl_vector_get(par,3);
+  float phi0 = gsl_vector_get(par,4);
+  int n    = ((struct data*)d)->n;
+  float* x = ((struct data*)d)->x;
+  float* y = ((struct data*)d)->y;
+  float* z = ((struct data*)d)->z;
+//float* ex = ((struct data*)d)->ex;
+//float* ey = ((struct data*)d)->ey;
+//float* ez = ((struct data*)d)->ez;
+  float fi = 0.0;
+
+  // first dimension
+  for (int i(0); i < n; i++) {
+    fi = (x0 + R*cos(b*z[i] + phi0)) - x[i];
+    //    float err = sqrt(ex[i]*ex[i]+R*b*R*b*sin(b*z[i] + phi0)*R*b*R*b*sin(b*z[i] + phi0)*ez[i]*ez[i]);
+    //    fi = fi/err;
+    gsl_vector_set(f,i,fi);
+  }
+  // second dimension
+  for (int i(0); i < n; i++) {
+    fi = (y0 + R*sin(b*z[i] + phi0)) - y[i];
+    //    float err = sqrt(ey[i]*ey[i]+R*b*R*b*cos(b*z[i] + phi0)*R*b*R*b*cos(b*z[i] + phi0)*ez[i]*ez[i]);
+    //    fi = fi/err;  
+    gsl_vector_set(f,i+n,fi);
+  }
+
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int dfunctParametrisation1(const gsl_vector* par, void* d, gsl_matrix* J) {
+
+  //     For helix fitting
+  float R    = gsl_vector_get(par,2);
+  float b    = gsl_vector_get(par,3);
+  float phi0 = gsl_vector_get(par,4);
+
+  int n    = ((struct data*)d)->n;
+  float* z = ((struct data*)d)->z;
+//float* ex = ((struct data*)d)->ex;
+//float* ey = ((struct data*)d)->ey;
+//float* ez = ((struct data*)d)->ez;
+
+
+  // calculate Jacobi's matrix J[i][j] = dfi/dparj
+
+  // part of Jacobi's matrix corresponding to first dimension
+  for (int i(0); i < n; i++) {
+    //    float err = sqrt(ex[i]*ex[i]+R*b*R*b*sin(b*z[i] + phi0)*R*b*R*b*sin(b*z[i] + phi0)*ez[i]*ez[i]);
+    gsl_matrix_set(J,i,0,1);
+    gsl_matrix_set(J,i,1,0);
+    gsl_matrix_set(J,i,2,cos(b*z[i]+phi0));
+    gsl_matrix_set(J,i,3,-z[i]*R*sin(b*z[i]+phi0));
+    gsl_matrix_set(J,i,4,-R*sin(b*z[i]+phi0));
+
+  }
+
+  // part of Jacobi's matrix corresponding to second dimension
+  for (int i(0); i < n; i++) {
+    //    float err = sqrt(ey[i]*ey[i]+R*b*R*b*cos(b*z[i] + phi0)*R*b*R*b*cos(b*z[i] + phi0)*ez[i]*ez[i]);
+    gsl_matrix_set(J,i+n,0,0);
+    gsl_matrix_set(J,i+n,1,1);
+    gsl_matrix_set(J,i+n,2,sin(b*z[i]+phi0));
+    gsl_matrix_set(J,i+n,3,z[i]*R*cos(b*z[i]+phi0));
+    gsl_matrix_set(J,i+n,4,R*cos(b*z[i]+phi0));
+    
+  }
+  
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int fdfParametrisation1(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {
+
+  //     For helix fitting
+  functParametrisation1(par, d, f);
+  dfunctParametrisation1(par, d, J);
+
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+int functParametrisation2(const gsl_vector* par, void* d, gsl_vector* f) {
+
+  //     For helix fitting
+  // calculate fit function f0[i] = 
+  // ( (x0 + R*cos(phi)) - x[i] ) for i = 0 to n-1
+  //                        f1[i] = 
+  // ( (y0 + R*sin(phi)) - y[i] ) for i = n to dim*n - 1
+  //                    and f2[i] =
+  // ( (z0 + b*phi     ) - z[i] )
+  // That means, minimise the three functions f0[i], f1[i] and f2[i]
+
+  float x0   = gsl_vector_get(par,0);
+  float y0   = gsl_vector_get(par,1);
+  float z0   = gsl_vector_get(par,2);
+  float R    = gsl_vector_get(par,3);
+  float b    = gsl_vector_get(par,4);
+  int n    = ((struct data*)d)->n;
+  float* x = ((struct data*)d)->x;
+  float* y = ((struct data*)d)->y;
+  float* z = ((struct data*)d)->z;
+  float fi = 0.0;
+  float phii = 0.0;
+
+  // first dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( y[i]-y0, x[i]-x0 );
+    fi = (x0 + R*cos(phii)) - x[i];
+    gsl_vector_set(f,i,fi);
+  }
+  // second dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( y[i]-y0, x[i]-x0 );
+    fi = (y0 + R*sin(phii)) - y[i];  
+    gsl_vector_set(f,i+n,fi);
+  }
+  // third dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( y[i]-y0, x[i]-x0 );
+    fi = (z0 + b*phii) - z[i];  
+    gsl_vector_set(f,i+2*n,fi);
+  }
+
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int dfunctParametrisation2(const gsl_vector* par, void* d, gsl_matrix* J) {
+
+  //     For helix fitting
+  float x0   = gsl_vector_get(par,0);
+  float y0   = gsl_vector_get(par,1);
+  float R    = gsl_vector_get(par,3);
+  float b    = gsl_vector_get(par,4);
+  int n    = ((struct data*)d)->n;
+  float* x = ((struct data*)d)->x;
+  float* y = ((struct data*)d)->y;
+  float phii = 0.0;
+
+  // calculate Jacobi's matrix J[i][j] = dfi/dparj
+
+  // part of Jacobi's matrix corresponding to first dimension
+  for (int i(0); i < n; i++) {
+    
+    phii = atan2( y[i]-y0, x[i]-x0 );
+
+    gsl_matrix_set(J,i,0,1 - R*sin(phii)*
+		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i,1,R*sin(phii)*
+		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i,2,0);
+    gsl_matrix_set(J,i,3,cos(phii));
+    gsl_matrix_set(J,i,4,0);
+
+  }
+  
+  // part of Jacobi's matrix corresponding to second dimension
+  for (int i(0); i < n; i++) {
+
+    phii = atan2( y[i]-y0, x[i]-x0 );
+    
+    gsl_matrix_set(J,i+n,0,R*cos(phii)*
+		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i+n,1,1 + R*cos(phii)*
+		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i+n,2,0);
+    gsl_matrix_set(J,i+n,3,sin(phii));
+    gsl_matrix_set(J,i+n,4,0);
+    
+  }
+
+  // part of Jacobi's matrix corresponding to third dimension
+  for (int i(0); i < n; i++) {
+
+    phii = atan2( y[i]-y0, x[i]-x0 );
+    
+    gsl_matrix_set(J,i+2*n,0,b*
+		   ( (y[i]-y0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i+2*n,1,b*
+		   ( (x[i]-x0)/( (x[i]-x0)*(x[i]-x0) + (y[i]-y0)*(y[i]-y0) ) ) );
+    gsl_matrix_set(J,i+2*n,2,1);
+    gsl_matrix_set(J,i+2*n,3,0);
+    gsl_matrix_set(J,i+2*n,4,phii);
+    
+  }
+  
+  return GSL_SUCCESS;
+}
+
+//=============================================================================
+
+int fdfParametrisation2(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {
+
+  //     For helix fitting
+  functParametrisation2(par, d, f);
+  dfunctParametrisation2(par, d, J);
+
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+int functParametrisation3(const gsl_vector* par, void* d, gsl_vector* f) {
+
+  //     For helix fitting
+  // calculate fit function f0[i] = 
+  // ( ( ( (1/omega) - d0 )*sin(Phi0) + ( 1/fabs(omega) )*cos( ( -omega/sqrt(1+tanL^2) )*s + Phi0 +( (omega*pi)/(2*fabs(omega)) ) ) ) - x[i] ) for i = 0 to n-1
+  //                        f1[i] = 
+  // ( ( (-1.0)*( (1/omega) - d0 )*cos(Phi0) + ( 1/fabs(omega) )*sin( ( -omega/sqrt(1+tanL^2) )*s + Phi0 +( (omega*pi)/(2*fabs(omega)) ) ) ) - y[i] ) for i = n to dim*n - 1
+  //                    and f2[i] =
+  // ( ( z0 + (tanL/sqrt(1+tanL^2))*s ) - z[i] )
+  // That means, minimise the three functions f0[i], f1[i] and f2[i]
+
+  double z0    = gsl_vector_get(par,0);
+  double Phi0  = gsl_vector_get(par,1);
+  double omega = gsl_vector_get(par,2);
+  double d0    = gsl_vector_get(par,3);
+  double tanL  = gsl_vector_get(par,4);
+  int n    = ((struct data*)d)->n;
+  float* x = ((struct data*)d)->x;
+  float* y = ((struct data*)d)->y;
+  float* z = ((struct data*)d)->z;
+  double phii = 0.0;
+  double fi = 0.0;
+  double si = 0.0;
+
+  // first dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    fi = ( ( (1/omega) - d0 )*sin(Phi0) + ( 1/fabs(omega) )*cos(phii) ) - ((double)x[i]);
+    gsl_vector_set(f,i,fi);
+  }
+  // second dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    fi = ( (-1.0)*( (1/omega) - d0 )*cos(Phi0) + ( 1/fabs(omega) )*sin(phii) ) - ((double)y[i]);
+    gsl_vector_set(f,i+n,fi);
+  }
+  // third dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));
+    fi = ( z0 + (tanL/sqrt(1+pow(tanL,2)))*si ) - ((double)z[i]);
+    gsl_vector_set(f,i+2*n,fi);
+  }
+  
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+int dfunctParametrisation3(const gsl_vector* par, void* d, gsl_matrix* J) {
+
+ 
+  //     For helix fitting
+  // double z0    = gsl_vector_get(par,0); // not needed
+  double Phi0  = gsl_vector_get(par,1);
+  double omega = gsl_vector_get(par,2);
+  double d0    = gsl_vector_get(par,3);
+  double tanL  = gsl_vector_get(par,4);
+  int n    = ((struct data*)d)->n;
+  float* x = ((struct data*)d)->x;
+  float* y = ((struct data*)d)->y;
+  // float* z = ((struct data*)d)->z; // not needed
+  double phii = 0.0;
+  double si = 0.0;
+
+  // calculate Jacobi's matrix J[i][j] = dfi/dparj
+
+  // part of Jacobi's matrix corresponding to first dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 ) * cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));
+
+    gsl_matrix_set(J,i,0,0);
+    gsl_matrix_set(J,i,1,((1/omega) - d0) * cos(Phi0) - (1/fabs(omega)) * sin(phii) );
+    gsl_matrix_set(J,i,2,((-1.0)*sin(Phi0))/pow(omega,2) - ( (signum(omega))/(pow(fabs(omega),2)) ) * cos(phii) - 
+                   (1/fabs(omega)) * sin(phii) * ( ( ((-1.0)/sqrt(1+pow(tanL,2)))*si) + (M_PI)/(2*fabs(omega)) - (signum(omega)*omega*M_PI)/(2*pow(fabs(omega),2)) ) );
+    gsl_matrix_set(J,i,3,(-1.0)*sin(Phi0));
+    gsl_matrix_set(J,i,4,((-1.0)/fabs(omega))*sin(phii) * ( (omega*tanL*si)/sqrt(pow(1+pow(tanL,2),3)) ) );
+
+  }
+  
+  // part of Jacobi's matrix corresponding to second dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));
+
+    gsl_matrix_set(J,i+n,0,0);
+    gsl_matrix_set(J,i+n,1,((1/omega) - d0)*sin(Phi0) + (1/fabs(omega)) * cos(phii) );
+    gsl_matrix_set(J,i+n,2,cos(Phi0)/pow(omega,2) + ( (signum(omega))/(pow(fabs(omega),2)) ) * sin(phii) + 
+                   (1/fabs(omega))*cos(phii) * ( ( ((-1.0)/sqrt(1+pow(tanL,2)))*si) + (M_PI)/(2*fabs(omega)) - (signum(omega)*omega*M_PI)/(2*pow(fabs(omega),2)) ) );
+    gsl_matrix_set(J,i+n,3,cos(Phi0));
+    gsl_matrix_set(J,i+n,4,(1/fabs(omega))*cos(phii) * ( (omega*tanL*si)/sqrt(pow(1+pow(tanL,2),3)) ) );
+    
+  }
+
+  // part of Jacobi's matrix corresponding to third dimension
+  for (int i(0); i < n; i++) {
+    phii = atan2( ( ((double)y[i]) + ((1/omega) - d0 )*cos(Phi0) ), ( ((double)x[i]) - ((1/omega) - d0 )*sin(Phi0) ) );
+    si = (-1.0)*( (sqrt(1+pow(tanL,2)))/omega )*(phii - Phi0 - (omega*M_PI)/(2*fabs(omega)));
+
+    gsl_matrix_set(J,i+2*n,0,1.0);
+    gsl_matrix_set(J,i+2*n,1,0);
+    gsl_matrix_set(J,i+2*n,2,0);
+    gsl_matrix_set(J,i+2*n,3,0);
+    gsl_matrix_set(J,i+2*n,4,si/sqrt(1+pow(tanL,2)) - (pow(tanL,2)*si)/sqrt(pow(1+pow(tanL,2),3)) );
+    
+  }
+  
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+int fdfParametrisation3(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J) {
+  
+  //     For helix fitting
+  functParametrisation3(par, d, f);
+  dfunctParametrisation3(par, d, J);
+  
+  return GSL_SUCCESS;
+
+}
+
+//=============================================================================
+
+
+
+
+// ##########################################
+// #####                                #####
+// #####   Constructor and Destructor   #####
+// #####                                #####
+// ##########################################
+
+//=============================================================================
+
+ClusterShapes::ClusterShapes(int nhits, float* a, float* x, float* y, float* z){
+
+  _nHits = nhits;
+  _aHit = new float[_nHits];
+  _xHit = new float[_nHits];
+  _yHit = new float[_nHits];
+  _zHit = new float[_nHits];
+  _exHit = new float[_nHits];   
+  _eyHit = new float[_nHits];
+  _ezHit = new float[_nHits];         
+  _types = new int[_nHits];
+
+  _xl = new float[_nHits];
+  _xt = new float[_nHits];
+
+  _t = new float[_nHits];
+  _s = new float[_nHits]; 
+
+  for (int i(0); i < nhits; ++i) {
+    _aHit[i] = a[i];
+    _xHit[i] = x[i];
+    _yHit[i] = y[i];
+    _zHit[i] = z[i];
+    _exHit[i] = 1.0;
+    _eyHit[i] = 1.0;
+    _ezHit[i] = 1.0;
+    _types[i] = 1; // all hits are assumed to be "cyllindrical"
+  }
+
+  _ifNotGravity     = 1;
+  _ifNotWidth       = 1;
+  _ifNotInertia     = 1;
+  _ifNotEigensystem = 1;
+
+}
+
+
+//=============================================================================
+
+ClusterShapes::~ClusterShapes() {
+
+  delete[] _aHit;
+  delete[] _xHit;
+  delete[] _yHit;
+  delete[] _zHit;
+  delete[] _exHit;
+  delete[] _eyHit;
+  delete[] _ezHit;
+  delete[] _types;
+  delete[] _xl;
+  delete[] _xt;
+  delete[] _t;
+  delete[] _s;
+}
+
+//=============================================================================
+
+void ClusterShapes::setErrors(float *ex, float *ey, float *ez) {
+
+  for (int i=0; i<_nHits; ++i) {
+    _exHit[i] = ex[i];
+    _eyHit[i] = ey[i];
+    _ezHit[i] = ez[i];
+  }	
+
+}
+
+void ClusterShapes::setHitTypes(int* typ) {
+  for (int i=0; i<_nHits; ++i) {
+    _types[i] = typ[i];
+
+  }
+  
+}
+
+
+
+// ##########################################
+// #####                                #####
+// #####        public methods          #####
+// #####                                #####
+// ##########################################
+
+//=============================================================================
+
+int ClusterShapes::getNumberOfHits() {
+  return _nHits;
+}
+
+//=============================================================================
+
+float ClusterShapes::getTotalAmplitude() {
+  if (_ifNotGravity == 1) findGravity();
+  return _totAmpl;
+}
+
+//=============================================================================
+
+float* ClusterShapes::getCentreOfGravity() {
+  if (_ifNotGravity == 1) findGravity() ;
+  return &_analogGravity[0] ;
+}
+
+//=============================================================================
+
+float* ClusterShapes::getEigenValInertia() {
+  if (_ifNotInertia == 1) findInertia();
+  return &_ValAnalogInertia[0] ;
+}
+
+//=============================================================================
+
+float* ClusterShapes::getEigenVecInertia() {
+  if (_ifNotInertia == 1) findInertia();
+  return &_VecAnalogInertia[0] ;
+}
+
+//=============================================================================
+
+float ClusterShapes::getWidth() {
+  if (_ifNotWidth == 1) findWidth();
+  return _analogWidth;
+}
+
+//=============================================================================
+
+int ClusterShapes::getEigenSytemCoordinates(float* xlong, float* xtrans) {
+
+  float xStart[3];
+  int index_xStart;
+
+
+  // NOT SAVE, change to class variables !!!!!
+  float X0 = 7.0;
+  float Rm = 13.5;
+
+  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);
+
+  for (int i = 0; i < _nHits; ++i) {
+    xlong[i]  = _xl[i];
+    xtrans[i] = _xt[i];
+  }
+
+  return 0; // no error messages at the moment
+
+}
+
+//=============================================================================
+
+int ClusterShapes::getEigenSytemCoordinates(float* xlong, float* xtrans, float* a) {
+
+  float xStart[3];
+  int index_xStart;
+
+  // NOT SAVE, change to class variables !!!!!
+  float X0 = 7.0;
+  float Rm = 13.5;
+
+  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);
+
+  for (int i = 0; i < _nHits; ++i) {
+    xlong[i]  = _xl[i];
+    xtrans[i] = _xt[i];
+    a[i] = _aHit[i];
+  }
+
+  return 0; // no error messages at the moment
+
+}
+
+//=============================================================================
+
+int ClusterShapes::fit3DProfile(float& chi2, float& E0, float& A, float& B, float& D,
+				float& xl0, float* xStart, int& index_xStart,
+				float X0, float Rm) {
+
+  const int npar = 4;
+
+
+  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);
+
+  float* E = new float[_nHits];
+
+
+  double par_init[npar];
+  for (int i = 0; i < npar; ++i) par_init[i] = 0.0; // initialise
+
+  float E0_init = 0.0;
+  float A_init  = 0.0;
+  float B_init  = 0.5; // empirically
+  float D_init  = 0.5; // empirically
+  float t0_init = -10.0/X0; // shift xl0_ini is assumed to be -10.0 without a reason ????
+  
+  float E0_tmp = 0.0;
+  int i_max = 0;
+  float t_max = 0.0;
+  for (int i = 0; i < _nHits; ++i) {
+    if (E0_tmp < _aHit[i]) {
+      E0_tmp = _aHit[i]; 
+      i_max = i;
+    }
+    E0_init += _aHit[i];
+  }
+
+  // first definition
+  //t_max = _xl[i_max]/X0;
+  //A_init = t_max*B_init + 1.0;
+
+  // second definition
+  //t_max = (1.0/3.0) * (t[_nHits-1] - t[0]);
+  //A_init = t_max*B_init + 1.0;
+
+  // third definition
+  float Ec = X0 * 0.021/Rm;
+  A_init =  B_init * log(E0_init/Ec) + 0.5 * B_init + 1.0; // (+0.5 for Photons initiated showers)
+
+
+
+  // par_init[0] = E0_init;
+  E0 = E0_init;
+  for (int i = 0; i < _nHits; ++i) E[i] = _aHit[i]/E0_init;
+  par_init[0] = A_init; // 2.0
+  par_init[1] = B_init;
+  par_init[2] = D_init;
+  par_init[3] = t0_init;
+
+  // debug
+
+  std::cout << "E0_init : " <<  E0_init << "\t" << "A_init : " << A_init << "\t" 
+	    << "B_init : " <<  B_init << "\t" << "D_init : " << D_init << "\t" 
+	    << "xl0_init : "  << t0_init*X0 << "\t" << "X0 : " << X0 
+	    << "\t" << "t_max : " << t_max << std::endl << std::endl;
+
+
+  double t0 = xl0/X0;
+  double par[npar];
+  par[0] = A;
+  par[1] = B;
+  par[2] = D;
+  par[3] = t0;
+
+  fit3DProfileAdvanced(chi2,par_init,par,npar,_t,_s,E,E0);
+
+  A   = par[0];
+  B   = par[1];
+  D   = par[2];
+  xl0 = par[3] * X0;
+
+  delete[] E;
+
+  int result = 0;  // no error handling at the moment
+  return result;
+}
+
+//=============================================================================
+
+float ClusterShapes::getChi2Fit3DProfileSimple(float a, float b, float c, float d,
+					       float X0, float Rm) {
+
+  float chi2 = 0.0;
+
+  float xStart[3];
+  int index_xStart;
+
+  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);
+
+  chi2 = calculateChi2Fit3DProfileSimple(a,b,c,d);
+  
+  return chi2;
+  
+}
+
+//=============================================================================
+
+float ClusterShapes::getChi2Fit3DProfileAdvanced(float E0, float a, float b, float d,
+						 float t0, float X0, float Rm) {
+
+  float chi2 = 0.0;
+
+  float xStart[3];
+  int index_xStart;
+
+  if (_ifNotEigensystem == 1) transformToEigensystem(xStart,index_xStart,X0,Rm);
+
+  chi2 = calculateChi2Fit3DProfileAdvanced(E0,a,b,d,t0);
+
+  return chi2;
+
+}
+
+//=============================================================================
+
+int ClusterShapes::FitHelix(int max_iter, int status_out, int parametrisation,
+			    float* parameter, float* dparameter, float& chi2, 
+			    float& distmax, int direction) {
+
+
+  // Modified by Hengne Li @ LAL
+  
+  double parameterdb[5];
+  double dparameterdb[5];
+  double chi2db;
+  double distmaxdb;
+  for ( int i=0; i<5; i++ ){
+    parameterdb[i] = double(parameter[i]);
+    dparameterdb[i] = double(dparameter[i]);
+  }
+  chi2db = double(chi2);
+  distmaxdb = double(distmax);
+  
+  int returnvalue = FitHelix(max_iter,status_out,parametrisation,parameterdb,dparameterdb,chi2db,distmaxdb,direction);
+  
+  for ( int i=0; i<5; i++ ){
+    parameter[i] = float(parameterdb[i]);
+    dparameter[i] = float(dparameterdb[i]);
+  }
+  chi2 = float(chi2db);
+  distmax = float(distmaxdb);
+  
+  return returnvalue ;
+
+}
+
+//=============================================================================
+
+int ClusterShapes::FitHelix(int max_iter, int status_out, int parametrisation,
+			    double* parameter, double* dparameter, double& chi2, 
+                            double& distmax, int direction) {
+
+  // FIXME: version with double typed parameters needed 2006/06/10 OW
+  
+  if (_nHits < 3) {
+      std::cout << "ClusterShapes : helix fit impossible, two few points" ;
+      std::cout << std::endl;
+      for (int i = 0; i < 5; ++i) {
+	  parameter[i] = 0.0;
+	  dparameter[i] = 0.0;
+      }
+      return 1;
+  }
+
+  // find initial parameters
+
+  double Rmin = 1.0e+10;
+  double Rmax = -1.0;
+  int i1 = -1;
+
+  // 1st loop  
+  for (int i(0); i < _nHits; ++i) {
+      double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
+      if (Rz < Rmin) {
+        Rmin = Rz;
+        i1 = i;
+      }
+      if (Rz > Rmax) {
+        Rmax = Rz;
+      }
+
+  }
+
+
+
+  // debug
+  /*
+  for (int i(0); i < _nHits; ++i) std::cout << i << "  " << _xHit[i] << "  " << _yHit[i] << "  " << _zHit[i] << std::endl;
+  std::cout << std::endl << Rmin << "  " <<  Rmax << "  " << i1 << std::endl;
+  */
+
+
+
+
+
+  // 2nd loop
+  double Upper = Rmin + 1.1*(Rmax-Rmin);
+  double Lower = Rmin + 0.9*(Rmax-Rmin);
+  double dZmin  = 1.0e+20;
+
+  int i3 = -1 ;
+
+  for (int i(0); i < _nHits; ++i) {
+    double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
+    if ((Rz > Lower) && (Rz < Upper)) {
+      double dZ = fabs(_zHit[i]-_zHit[i1]);
+      if (dZ < dZmin) {
+        dZmin = dZ;
+        i3 = i;
+      }
+    }
+  }
+
+  // debug
+  //std::cout << std::endl << Upper << "  " << Lower << "  " << dZmin << "  " << i3 << std::endl;
+
+
+
+
+  double z1 = std::min(_zHit[i1],_zHit[i3]);
+  double z3 = std::max(_zHit[i1],_zHit[i3]);
+
+
+  int i2 = -1;
+  double dRmin = 1.0e+20;
+  double Rref = 0.5 * ( Rmax + Rmin );
+
+  // 3d loop
+
+  for (int i(0); i < _nHits; ++i) {
+      if (_zHit[i] >= z1 && _zHit[i] <= z3) {
+        double Rz = sqrt(_xHit[i]*_xHit[i] + _yHit[i]*_yHit[i]);
+        double dRz = fabs(Rz - Rref);
+        if (dRz < dRmin) {
+          i2 = i;
+          dRmin = dRz;
+        }
+      }
+  }
+
+  int problematic = 0;
+
+  if (i2 < 0 || i2 == i1 || i2 == i3) {
+    problematic = 1;
+    // std::cout << "here we are " << std::endl;
+    for (int i(0); i < _nHits; ++i) {
+      if (i != i1 && i != i3) {
+        i2 = i;
+        if (_zHit[i2] < z1) {
+          int itemp = i1;
+          i1 = i2;
+          i2 = itemp;
+        }
+        else if (_zHit[i2] > z3) {
+          int itemp = i3;
+          i3 = i2;
+          i2 = itemp;
+        }        
+        break;
+      }
+    }      
+    // std::cout << i1 << " " << i2 << " " << i3 << std::endl;
+  }
+
+
+  double x0  = 0.5*(_xHit[i2]+_xHit[i1]);
+  double y0  = 0.5*(_yHit[i2]+_yHit[i1]);
+  double x0p = 0.5*(_xHit[i3]+_xHit[i2]);
+  double y0p = 0.5*(_yHit[i3]+_yHit[i2]);
+  double ax  = _yHit[i2] - _yHit[i1];
+  double ay  = _xHit[i1] - _xHit[i2];
+  double axp = _yHit[i3] - _yHit[i2];
+  double ayp = _xHit[i2] - _xHit[i3];
+  double det = ax * ayp - axp * ay;
+  double time;
+
+  if (det == 0.) {
+      time = 500.;
+  }
+  else {
+      gsl_matrix* A = gsl_matrix_alloc(2,2);
+      gsl_vector* B = gsl_vector_alloc(2);
+      gsl_vector* T = gsl_vector_alloc(2);     
+      gsl_matrix_set(A,0,0,ax);
+      gsl_matrix_set(A,0,1,-axp);
+      gsl_matrix_set(A,1,0,ay);
+      gsl_matrix_set(A,1,1,-ayp);
+      gsl_vector_set(B,0,x0p-x0);
+      gsl_vector_set(B,1,y0p-y0);
+      gsl_linalg_HH_solve(A,B,T);
+      time = gsl_vector_get(T,0); 
+      gsl_matrix_free(A);
+      gsl_vector_free(B);
+      gsl_vector_free(T);
+  }
+
+  double X0 = x0 + ax*time;
+  double Y0 = y0 + ay*time;
+
+  double dX = _xHit[i1] - X0;
+  double dY = _yHit[i1] - Y0;
+
+  double R0 = sqrt(dX*dX + dY*dY);
+
+  /*
+   if (problematic == 1) {
+     std::cout << i1 << " " << i2 << " " << i3 << std::endl;
+     std::cout << _xHit[i1] << " " << _yHit[i1] << " " << _zHit[i1] << std::endl;
+     std::cout << _xHit[i2] << " " << _yHit[i2] << " " << _zHit[i2] << std::endl;
+     std::cout << _xHit[i3] << " " << _yHit[i3] << " " << _zHit[i3] << std::endl;
+     std::cout << "R0 = " << R0 << std::endl;
+   }
+  */
+
+  double phi1 = (double)atan2(_yHit[i1]-Y0,_xHit[i1]-X0);
+  double phi2 = (double)atan2(_yHit[i2]-Y0,_xHit[i2]-X0);
+  double phi3 = (double)atan2(_yHit[i3]-Y0,_xHit[i3]-X0);
+
+// testing bz > 0 hypothesis
+
+  if ( phi1 > phi2 ) 
+      phi2 = phi2 + 2.0*M_PI;
+  if ( phi1 > phi3 )
+      phi3 = phi3 + 2.0*M_PI;
+  if ( phi2 > phi3 )
+      phi3 = phi3 + 2.0*M_PI;
+
+  double bz_plus = (phi3 - phi1) / (_zHit[i3]-_zHit[i1]);
+  double phi0_plus = phi1 - bz_plus * _zHit[i1];
+  double dphi_plus = fabs( bz_plus * _zHit[i2] + phi0_plus - phi2 );
+
+// testing bz < 0 hypothesis
+
+  phi1 = (double)atan2(_yHit[i1]-Y0,_xHit[i1]-X0);
+  phi2 = (double)atan2(_yHit[i2]-Y0,_xHit[i2]-X0);
+  phi3 = (double)atan2(_yHit[i3]-Y0,_xHit[i3]-X0);
+
+  if ( phi1 < phi2 ) 
+      phi2 = phi2 - 2.0*M_PI;
+  if ( phi1 < phi3 )
+      phi3 = phi3 - 2.0*M_PI;
+  if ( phi2 < phi3 )
+      phi3 = phi3 - 2.0*M_PI;
+
+  double bz_minus = (phi3 - phi1) / (_zHit[i3]-_zHit[i1]);
+  double phi0_minus = phi1 - bz_minus * _zHit[i1];
+  double dphi_minus = fabs( bz_minus * _zHit[i2] + phi0_minus - phi2 );
+
+  double bz;
+  double phi0;
+
+  if (dphi_plus < dphi_minus) {
+      bz = bz_plus;
+      phi0 = phi0_plus;
+  }
+  else {
+      bz = bz_minus;
+      phi0 = phi0_minus;
+
+  }
+
+  double par_init[5];
+
+  if (parametrisation == 1) {
+    par_init[0] = (double)X0;
+    par_init[1] = (double)Y0;
+    par_init[2] = (double)R0;
+    par_init[3] = (double)bz;
+    par_init[4] = (double)phi0;
+  }
+  else if (parametrisation == 2) {
+    par_init[0] = (double)X0;
+    par_init[1] = (double)Y0;
+    par_init[2] = (double)(-phi0/bz);
+    par_init[3] = (double)R0;
+    par_init[4] = (double)(1/bz);
+  }
+
+  else if (parametrisation == 3) {  // parameter vector: (z0,Phi0,omega,d0,tanL)
+
+    // debug
+    // std::cout << std::setprecision(6) << "InitFit (X0,Y0,R0,bz,phi0) = " << "(" << X0 << "," << Y0 << "," << R0 << "," << bz << "," << phi0 << ")" << std::endl;
+
+    
+    // debug
+    /*    
+    X0 = -1205.28;
+    Y0 = 175.317;
+    R0 = 1217.97;
+    bz = 0.00326074;
+    phi0 = -0.144444;
+    */ 
+
+
+    // debug
+    // std::cout << std::setprecision(6) << "InitUsed (X0,Y0,R0,bz,phi0) = " << "(" << X0 << "," << Y0 << "," << R0 << "," << bz << "," << phi0 << ")" << std::endl;
+        
+    double omega = 1/R0*direction;
+    double tanL  = (-1.0)*omega/bz;
+
+    double Phi0  = (-1.0)*atan2(X0,Y0);
+    
+    if (direction == 1) {
+
+      if (tanL >= 0.0) Phi0 += M_PI; // add pi (see LC-DET-2006-004) //  >= or > ?
+      else Phi0 -= M_PI; // < or <= ?
+      
+    }
+
+    //double d0 = R0 - X0/sin(Phi0);
+    //double d0 = R0 + Y0/cos(Phi0);
+
+    double d0 = 0.0;
+    if (true /*direction != 1*/) d0 = R0 - sqrt(X0*X0 + Y0*Y0);
+    // else d0 = R0 + sqrt(X0*X0 + Y0*Y0);
+
+
+
+    // double d0 = R0 - ( (X0-Y0)/(sqrt(2.0)*cos(pi/4 - Phi0)) );    
+    // double d0 = R0 - ((X0-Y0)/(sin(Phi0)+cos(Phi0)));
+
+    // double Phi0 = asin(X0/(R0-d0));
+
+    
+    double z0 = (1/bz)*((-1.0)*phi0+Phi0+(omega*M_PI)/(2.0*fabs(omega)));
+
+
+    // debug
+    /*
+    std::cout << std::setprecision(6) << "InitFitCalculated (d0,z0,phi0,omega,tanL) = " << "(" << d0 << "," << z0 << "," << Phi0 << "," << omega << "," << tanL << ")" 
+              << "  " << "sign(omega) = " << direction << std::endl;
+    */
+
+    // debug        
+    /*
+    d0    = 0.00016512;
+    z0    = 0.000853511;
+    Phi0  = 1.11974;
+    omega = -4.22171e-05;
+    tanL  = -0.33436;
+    */
+
+
+    
+
+    // debug
+    // std::cout << std::setprecision(6) << "InitFitUsed (d0,z0,phi0,omega,tanL) = " << "(" << d0 << "," << z0 << "," << Phi0 << "," << omega << "," << tanL << ")" << std::endl;
+
+    par_init[0] = z0;
+    par_init[1] = Phi0;
+    par_init[2] = omega;
+    par_init[3] = d0;
+    par_init[4] = tanL;
+  }
+  else return 1;
+
+
+  // local variables
+  int status = 0;
+  int iter = 0;
+
+  int npar = 5; // five parameters to fit
+  int ndim = 0;
+  if (parametrisation == 1) ndim = 2; // two dependent dimensions 
+  else if (parametrisation == 2) ndim = 3; // three dependent dimensions
+  else if (parametrisation == 3) ndim = 3; // three dependent dimensions
+
+  else return 1;
+
+
+
+  double chi2_nofit = 0.0;
+  int iFirst = 1;
+  for (int ipoint(0); ipoint < _nHits; ipoint++) {
+    double distRPZ[2];
+    double Dist = DistanceHelix(_xHit[ipoint],_yHit[ipoint],_zHit[ipoint],
+			       X0,Y0,R0,bz,phi0,distRPZ);
+    double chi2rphi = distRPZ[0]/_exHit[ipoint];
+    chi2rphi = chi2rphi*chi2rphi;
+    double chi2z = distRPZ[1]/_ezHit[ipoint];
+    chi2z = chi2z*chi2z;
+    chi2_nofit = chi2_nofit + chi2rphi + chi2z;
+    if (Dist > distmax || iFirst == 1) {
+      distmax = Dist;
+      iFirst = 0;
+    }
+  }      
+  chi2_nofit = chi2_nofit/double(_nHits);
+
+  if ( status_out == 1 ) {
+    for (int i(0); i < 5; ++i) {
+      parameter[i] = (double)par_init[i];
+      dparameter[i] = 0.0;      
+    }
+    chi2 = chi2_nofit;
+    return 0;
+  }
+
+  // converging criteria
+  const double abs_error = 1e-4;
+  const double rel_error = 1e-4;
+
+  gsl_multifit_function_fdf fitfunct;
+
+  const gsl_multifit_fdfsolver_type* T = gsl_multifit_fdfsolver_lmsder;
+
+  gsl_multifit_fdfsolver* s = gsl_multifit_fdfsolver_alloc(T,ndim*_nHits,npar);
+
+  gsl_matrix* covar = gsl_matrix_alloc(npar,npar);   // covariance matrix
+
+  data d;
+  d.n = _nHits;
+  d.x = &_xHit[0];
+  d.y = &_yHit[0];
+  d.z = &_zHit[0];
+  d.ex = &_exHit[0];
+  d.ey = &_eyHit[0];
+  d.ez = &_ezHit[0];
+
+
+  if (parametrisation == 1) {
+    fitfunct.f = &functParametrisation1;
+    fitfunct.df = &dfunctParametrisation1;
+    fitfunct.fdf = &fdfParametrisation1;
+    fitfunct.n = ndim*_nHits;
+    fitfunct.p = npar;
+    fitfunct.params = &d;
+  }
+  else if (parametrisation == 2) {
+    fitfunct.f = &functParametrisation2;
+    fitfunct.df = &dfunctParametrisation2;
+    fitfunct.fdf = &fdfParametrisation2;
+    fitfunct.n = ndim*_nHits;
+    fitfunct.p = npar;
+    fitfunct.params = &d;
+  }
+  else if (parametrisation == 3) {
+    fitfunct.f = &functParametrisation3;
+    fitfunct.df = &dfunctParametrisation3;
+    fitfunct.fdf = &fdfParametrisation3;
+    fitfunct.n = ndim*_nHits;
+    fitfunct.p = npar;
+    fitfunct.params = &d;
+  }
+  else return 1;
+
+  gsl_vector_view pinit = gsl_vector_view_array(par_init,npar);
+  gsl_multifit_fdfsolver_set(s,&fitfunct,&pinit.vector);
+
+  // perform fit
+  do {
+    iter++;
+    status = gsl_multifit_fdfsolver_iterate(s);
+
+    if (status) break;
+    status = gsl_multifit_test_delta (s->dx, s->x,abs_error,rel_error);
+
+  } while ( status==GSL_CONTINUE && iter < max_iter);
+
+  gsl_multifit_covar (s->J, rel_error, covar);
+
+
+
+  chi2 = 0.0;
+
+  if (parametrisation == 1) {
+    X0   = (double)gsl_vector_get(s->x,0);
+    Y0   = (double)gsl_vector_get(s->x,1);
+    R0   = (double)gsl_vector_get(s->x,2);
+    bz   = (double)gsl_vector_get(s->x,3);
+    phi0 = (double)gsl_vector_get(s->x,4);
+  }
+  else if (parametrisation == 2) {
+    X0   = (double)gsl_vector_get(s->x,0);
+    Y0   = (double)gsl_vector_get(s->x,1);
+    R0   = (double)gsl_vector_get(s->x,3);
+    bz   = (double)(1/gsl_vector_get(s->x,4));
+    phi0 = (double)(-gsl_vector_get(s->x,2)/gsl_vector_get(s->x,4));
+  }
+  else if (parametrisation == 3) { // (parameter vector: (z0,phi0,omega,d0,tanL)
+
+    double z0    = gsl_vector_get(s->x,0);
+    double Phi0  = gsl_vector_get(s->x,1);
+    double omega = gsl_vector_get(s->x,2);
+    double d0    = gsl_vector_get(s->x,3);
+    double tanL  = gsl_vector_get(s->x,4);
+
+    X0   = (double)( ( (1/omega) - d0 )*sin(Phi0) );
+    Y0   = (double)( (-1)*( (1/omega) - d0 )*cos(Phi0) );
+    R0   = (double)( 1/fabs(omega) );
+    bz   = (double)( (-1)*(omega/tanL) );
+    phi0 = (double)( ( (z0*omega)/tanL ) + Phi0 + ( (omega*M_PI)/(2*fabs(omega)) ) );
+  }
+  else return 1;
+
+  iFirst = 1;
+  double ddmax = 0.0;
+  for (int ipoint(0); ipoint < _nHits; ipoint++) {
+    double distRPZ[2];
+    double Dist = DistanceHelix(_xHit[ipoint],_yHit[ipoint],_zHit[ipoint],
+			       X0,Y0,R0,bz,phi0,distRPZ);
+    double chi2rphi = distRPZ[0]/_exHit[ipoint];
+    chi2rphi = chi2rphi*chi2rphi;
+    double chi2z = distRPZ[1]/_ezHit[ipoint];
+    chi2z = chi2z*chi2z;
+    chi2 = chi2 + chi2rphi + chi2z;
+    if (Dist > ddmax || iFirst == 1) {
+      iFirst = 0;
+      ddmax = Dist;
+    }
+  }
+      
+
+  chi2 = chi2/double(_nHits);
+  if (chi2 < chi2_nofit) {
+    for (int i = 0; i < npar; i++) {
+      parameter[i]  = gsl_vector_get(s->x,i);
+      dparameter[i] = sqrt(gsl_matrix_get(covar,i,i));
+    }    
+    distmax = ddmax;
+  }
+  else {
+    chi2 = chi2_nofit;
+    for (int i = 0; i < npar; i++) {
+      parameter[i] = (double)par_init[i];
+      dparameter[i] = 0.0;
+    }
+  }
+
+  //  if (problematic == 1)
+  //    std::cout << "chi2 = " << chi2 << std::endl;
+
+  gsl_multifit_fdfsolver_free(s);
+  gsl_matrix_free(covar);
+  return 0; 
+
+}
+
+
+
+// ##########################################
+// #####                                #####
+// #####        private methods         #####
+// #####                                #####
+// ##########################################
+
+//=============================================================================
+
+void ClusterShapes::findElipsoid() {
+
+  /**   Elipsoid parameter calculations see cluster_proper.f  */
+  float cx,cy,cz ;
+  float dx,dy,dz ;
+  float r_hit_max, d_begn, d_last, r_max, proj;
+  if (_ifNotInertia == 1) findInertia() ;
+  //   Normalize the eigen values of inertia tensor
+  float wr1 = sqrt(_ValAnalogInertia[0]/_totAmpl);
+  float wr2 = sqrt(_ValAnalogInertia[1]/_totAmpl);
+  float wr3 = sqrt(_ValAnalogInertia[2]/_totAmpl);
+  _r1 = sqrt(wr2*wr3);                // spatial axis length -- the largest
+  _r2 = sqrt(wr1*wr3);                // spatial axis length -- less
+  _r3 = sqrt(wr1*wr2);                // spatial axis length -- even more less
+  _vol = 4.*M_PI*_r1*_r2*_r3/3.;      // ellipsoid volume
+  _r_ave = pow(_vol,1/3);             // average radius  (quibc root)
+  _density = _totAmpl/_vol;           // density
+  //    _eccentricity = _r_ave/_r1;   // Cluster Eccentricity
+  _eccentricity =_analogWidth/_r1;   // Cluster Eccentricity
+
+  // Find Minumal and Maximal Lenght for Principal axis
+  r_hit_max = -100000.;
+  d_begn    =  100000.;
+  d_last    = -100000.;
+  cx = _VecAnalogInertia[0] ;
+  cy = _VecAnalogInertia[1] ;
+  cz = _VecAnalogInertia[2] ;
+  for (int i(0); i < _nHits; ++i) {
+    dx = _xHit[i] - _xgr;
+    dy = _yHit[i] - _ygr;
+    dz = _zHit[i] - _zgr;
+    r_max = sqrt(dx*dx + dy*dy + dz*dz);;
+    if(r_max > r_hit_max) r_hit_max = r_max;
+    proj = dx*cx + dy*cy + dz*cz;
+    if(proj < d_begn)
+      d_begn = proj;
+    //            lad_begn = ladc(L)
+    if(proj > d_last)
+      d_last = proj;
+    //            lad_last = ladc(L)
+  }
+  //        if (r_hit_max > 0.0)
+  //	  _r1 = 1.05*r_hit_max; // + 5% of length
+  _r1_forw = fabs(d_last);
+  _r1_back = fabs(d_begn);
+}
+
+//=============================================================================
+
+void ClusterShapes::findGravity() {
+
+    _totAmpl = 0. ;
+    for (int i(0); i < 3; ++i) {
+	_analogGravity[i] = 0.0 ;
+    }
+    for (int i(0); i < _nHits; ++i) {
+	_totAmpl+=_aHit[i] ;
+	_analogGravity[0]+=_aHit[i]*_xHit[i] ;
+	_analogGravity[1]+=_aHit[i]*_yHit[i] ;
+	_analogGravity[2]+=_aHit[i]*_zHit[i] ;
+    }
+    for (int i(0); i < 3; ++i) {
+	_analogGravity[i]/=_totAmpl ;
+    }
+    _xgr = _analogGravity[0];
+    _ygr = _analogGravity[1];
+    _zgr = _analogGravity[2];
+    _ifNotGravity = 0;
+}
+
+//=============================================================================
+
+void ClusterShapes::findInertia() {
+
+  double aIne[3][3];
+  //  float radius1;
+  float radius2 = 0.0;
+
+  findGravity();
+
+  for (int i(0); i < 3; ++i) {
+      for (int j(0); j < 3; ++j) {
+	  aIne[i][j] = 0.0;
+      }
+  }
+
+  for (int i(0); i < _nHits; ++i) {
+      float dX = _xHit[i] - _analogGravity[0];
+      float dY = _yHit[i] - _analogGravity[1];
+      float dZ = _zHit[i] - _analogGravity[2];
+      aIne[0][0] += _aHit[i]*(dY*dY+dZ*dZ);
+      aIne[1][1] += _aHit[i]*(dX*dX+dZ*dZ);
+      aIne[2][2] += _aHit[i]*(dX*dX+dY*dY);
+      aIne[0][1] -= _aHit[i]*dX*dY;
+      aIne[0][2] -= _aHit[i]*dX*dZ;
+      aIne[1][2] -= _aHit[i]*dY*dZ;
+  }
+
+  for (int i(0); i < 2; ++i) {
+      for (int j = i+1; j < 3; ++j) {
+	  aIne[j][i] = aIne[i][j];
+      }
+  }
+  //****************************************
+  // analog Inertia
+  //****************************************
+
+  gsl_matrix_view aMatrix = gsl_matrix_view_array((double*)aIne,3,3);
+  gsl_vector* aVector = gsl_vector_alloc(3);
+  gsl_matrix* aEigenVec = gsl_matrix_alloc(3,3);
+  gsl_eigen_symmv_workspace* wa = gsl_eigen_symmv_alloc(3);
+  gsl_eigen_symmv(&aMatrix.matrix,aVector,aEigenVec,wa);
+  gsl_eigen_symmv_free(wa);
+  gsl_eigen_symmv_sort(aVector,aEigenVec,GSL_EIGEN_SORT_ABS_ASC);
+
+  for (int i(0); i < 3; i++) {
+    _ValAnalogInertia[i] = gsl_vector_get(aVector,i);
+    for (int j(0); j < 3; j++) {
+      _VecAnalogInertia[i+3*j] = gsl_matrix_get(aEigenVec,i,j);
+    }
+  }
+
+  // Main principal points away from IP
+
+  _radius = 0.;
+  radius2 = 0.;
+
+  for (int i(0); i < 3; ++i) {
+      _radius += _analogGravity[i]*_analogGravity[i];
+      radius2 += (_analogGravity[i]+_VecAnalogInertia[i])*(_analogGravity[i]+_VecAnalogInertia[i]);
+  }
+
+  if ( radius2 < _radius) {
+      for (int i(0); i < 3; ++i)
+	  _VecAnalogInertia[i] = - _VecAnalogInertia[i];
+  }
+
+  _radius = sqrt(_radius);
+  _ifNotInertia = 0;
+
+  // The final job
+  findWidth();
+  findElipsoid();
+
+  gsl_vector_free(aVector);
+  gsl_matrix_free(aEigenVec);
+
+}
+
+//=============================================================================
+
+void ClusterShapes::findWidth() {
+
+  float dist = 0.0;
+  if (_ifNotInertia == 1)  findInertia() ;
+  _analogWidth  = 0.0 ;
+  for (int i(0); i < _nHits; ++i) {
+    dist = findDistance(i) ;
+    _analogWidth+=_aHit[i]*dist*dist ;
+  }
+  _analogWidth  = sqrt(_analogWidth / _totAmpl) ;
+  _ifNotWidth = 0 ;
+}
+
+//=============================================================================
+
+float ClusterShapes::findDistance(int i) {
+
+    float cx = 0.0;
+    float cy = 0.0;
+    float cz = 0.0;
+    float dx = 0.0;
+    float dy = 0.0;
+    float dz = 0.0;
+    cx = _VecAnalogInertia[0] ;
+    cy = _VecAnalogInertia[1] ;
+    cz = _VecAnalogInertia[2] ;
+    dx = _analogGravity[0] - _xHit[i] ;
+    dy = _analogGravity[1] - _yHit[i] ;
+    dz = _analogGravity[2] - _zHit[i] ;
+    float tx = cy*dz - cz*dy ;
+    float ty = cz*dx - cx*dz ;
+    float tz = cx*dy - cy*dx ;
+    float tt = sqrt(tx*tx+ty*ty+tz*tz) ;
+    float ti = sqrt(cx*cx+cy*cy+cz*cz) ;
+    float f = tt / ti ;
+    return f ;
+}
+/**
+      Function sdist(xp,yp,zp,cx,cy,cz,xv,yv,zv)
+c----------------------------------------------------------------------
+c        Distance from line to point
+c       xp, yp, zp -- point is at the line
+c       xv, yv, zv -- point is out of line
+********************************************************************
+*     Last update     V.L.Morgunov     08-Apr-2002                 *
+********************************************************************
+      real xp,yp,zp,cx,cy,cz,xv,yv,zv,t1,t2,t3,tt,sdist
+
+      t1 = cy*(zp-zv)-cz*(yp-yv)
+      t2 = cz*(xp-xv)-cx*(zp-zv)
+      t3 = cx*(yp-yv)-cy*(xp-xv)
+      tt = sqrt(cx**2+cy**2+cz**2)
+      sdist = sqrt(t1**2+t2**2+t3**2)/tt
+
+      return
+      end
+*/
+
+//=============================================================================
+
+float ClusterShapes::vecProduct(float * x1, float * x2) {
+
+    float x1abs(0.);
+    float x2abs(0.);
+    float prod(0.);
+
+    for (int i(0); i < 3; ++i) {
+	x1abs += x1[i]*x1[i];
+	x2abs += x2[i]*x2[i];
+	prod  += x1[i]*x2[i];
+    }
+
+
+    x1abs = sqrt(x1abs);
+    x2abs = sqrt(x2abs);
+
+    if (x1abs > 0.0 && x2abs > 0.0) {
+	prod = prod/(x1abs*x2abs);
+    }
+    else {
+	prod = 0.;
+    }
+
+    return prod;
+
+}
+
+//=============================================================================
+
+float ClusterShapes::vecProject(float * x, float * axis) {
+    float axisabs(0.);
+    float prod(0.);
+    for (int i(0); i < 3; ++i) {
+	axisabs += axis[i]*axis[i];
+	prod  += x[i]*axis[i];
+    }
+    axisabs = sqrt(axisabs);
+    if (axisabs > 0.0 ) {
+	prod = prod/axisabs;
+    }
+    else {
+	prod = 0.;
+    }
+    return prod;
+}
+
+//=============================================================================
+
+double ClusterShapes::DistanceHelix(double x, double y, double z, double X0, double Y0,
+				   double R0, double bz, double phi0, double * distRPZ) {
+
+  double phi  = atan2(y-Y0,x-X0);
+  double R    = sqrt( (y-Y0)*(y-Y0) + (x-X0)*(x-X0) );
+  double dXY2 = (R-R0)*(R-R0);
+  double _const_2pi = 2.0*M_PI;
+  double xN = (bz*z + phi0 - phi)/_const_2pi;
+
+  int n1 = 0;
+  int n2 = 0;
+  int nSpirals = 0;
+
+  if (xN > 0) {
+    n1 = (int)xN;
+    n2 = n1 + 1;
+  }
+  else {
+    n1 = (int)xN - 1;
+    n2 = n1 + 1;
+  }
+
+  if (fabs(n1-xN) < fabs(n2-xN)) {
+    nSpirals = n1;
+  }
+  else {
+    nSpirals = n2;
+  }
+
+  double dZ = (phi + _const_2pi*nSpirals - phi0)/bz - z;
+  double dZ2 = dZ*dZ;
+
+  distRPZ[0] = sqrt(dXY2);
+  distRPZ[1] = sqrt(dZ2);
+
+  return sqrt(dXY2 + dZ2);
+
+}
+
+//=============================================================================
+
+int ClusterShapes::transformToEigensystem(float* xStart, int& index_xStart, float X0,
+					  float Rm) {
+
+  if (_ifNotInertia == 1) findInertia();
+
+  float MainAxis[3];
+  float MainCentre[3];
+
+
+  MainAxis[0] = _VecAnalogInertia[0];
+  MainAxis[1] = _VecAnalogInertia[1];
+  MainAxis[2] = _VecAnalogInertia[2];
+  MainCentre[0] = _analogGravity[0];
+  MainCentre[1] = _analogGravity[1];
+  MainCentre[2] = _analogGravity[2];
+
+  int ifirst = 0;
+  float xx[3];
+  float prodmin = 0.0;
+  int index = 0;
+
+  for (int i(0); i < _nHits; ++i) {
+    xx[0] = _xHit[i] - MainCentre[0];
+    xx[1] = _yHit[i] - MainCentre[1];
+    xx[2] = _zHit[i] - MainCentre[2];
+    float prod = vecProject(xx,MainAxis);
+    if (ifirst == 0 || prod < prodmin) {
+      ifirst = 1;
+      prodmin = prod;
+      index = i;
+    }
+  }
+  xStart[0] = MainCentre[0] + prodmin*MainAxis[0];
+  xStart[1] = MainCentre[1] + prodmin*MainAxis[1];
+  xStart[2] = MainCentre[2] + prodmin*MainAxis[2];
+  index_xStart = index;
+
+  for (int i(0); i < _nHits; ++i) {
+    xx[0] = _xHit[i] - xStart[0];
+    xx[1] = _yHit[i] - xStart[1];
+    xx[2] = _zHit[i] - xStart[2];
+    float xx2(0.);
+    for (int j(0); j < 3; ++j) xx2 += xx[j]*xx[j];
+
+    _xl[i] = 0.001 + vecProject(xx,MainAxis);
+    _xt[i] = sqrt(std::max(0.0,xx2 + 0.1 - _xl[i]*_xl[i]));
+    //    std::cout << i << " " << _xl[i] << " " << _xt[i] << " " << _aHit[i] << " "
+    //              << std::endl;
+  }
+
+  for (int i = 0; i < _nHits; ++i) {
+    _t[i] = _xl[i]/X0;
+    _s[i] = _xt[i]/Rm;
+  }
+
+  _ifNotEigensystem = 0;
+
+  return 0; // no error messages at the moment
+
+}
+
+//=============================================================================
+
+float ClusterShapes::calculateChi2Fit3DProfileSimple(float a, float b, float c,
+						     float d) {
+
+  // ClusterShapes::transformToEigensystem needs to be executed before
+
+  float chi2 = 0.0;
+  float Ampl = 0.0;
+
+  for (int i(0); i < _nHits; ++i) {
+    // old definition of Ampl and chi2
+    //Ampl = a*(float)pow(_xl[i],b)*exp(-c*_xl[i]-d*_xt[i]); 
+    //chi2 += ((Ampl - _aHit[i])*(Ampl - _aHit[i]))/(_aHit[i]*_aHit[i]);
+
+    Ampl = a*(float)pow(_xl[i],b)*exp(-c*_xl[i]-d*_xt[i]);
+    chi2 += (log(_aHit[i]) - log(Ampl))*(log(_aHit[i]) - log(Ampl));
+  }
+
+  chi2 = chi2/std::max((float)1.0,(float)(_nHits - 4));
+
+  return chi2;
+
+}
+
+//=============================================================================
+
+float ClusterShapes::calculateChi2Fit3DProfileAdvanced(float E0, float a, float b,
+						       float d, float t0) {
+
+  // ClusterShapes::transformToEigensystem needs to be executed before
+
+  float chi2  = 0.0;
+  float Ampl  = 0.0;
+  float shift = 0.0;
+
+  for (int i(0); i < _nHits; ++i) {
+
+    shift = _t[i]-t0;
+
+    if (shift <= 0) Ampl = 0.0;
+    else {
+      Ampl = E0 * b * invG(a) * pow(b*(shift),a-1) 
+	* exp(-b*(shift)) * exp(-d*_s[i]);
+    }
+
+    // debug 
+    /*
+    std::cout << "OUT : " << Ampl << "  " << E0  << "  " << a  << "  " << b  << "  " 
+	      << d  << "  " << t0  << "  " << _t[i] << "  " << invG(a)  << "  "
+	      << pow(b*(_t[i]-t0),a-1)  << "  " << exp(-b*(_t[i]-t0))  << "  " 
+	      << exp(-d*_s[i]) 
+	      << std::endl;
+    */
+
+    chi2 += ((Ampl - _aHit[i])*(Ampl - _aHit[i]))/(_aHit[i]*_aHit[i]);
+    //chi2 += (log(_aHit[i]) - log(Ampl))*(log(_aHit[i]) - log(Ampl));
+    //chi2 += log((Ampl - _aHit[i])*(Ampl - _aHit[i]))/log(_aHit[i]*_aHit[i]);
+
+  }
+  chi2 = chi2/std::max((float)1.0,(float)(_nHits - 4));
+
+  return chi2;
+
+}
+
+//=============================================================================
+
+int ClusterShapes::fit3DProfileSimple(float& chi2, float& a, float& b, float& c,
+				      float& d) {
+
+  // Fit function: _aHit[i] = a * pow(_xl[i],b) * exp(-c*_xl[i]) * exp(-d*_xt[i])
+
+  float Slnxl(0.);
+  float Sxl(0.);
+  float Sxt(0.);
+  float Sln2xl(0.);
+  float Sxllnxl(0.);
+  float Sxtlnxl(0.);
+  float Sxlxl(0.);
+  float Sxlxt(0.);
+  float Sxtxt(0.);
+  float SlnA(0.);
+  float SlnAlnxl(0.);
+  float SlnAxl(0.);
+  float SlnAxt(0.);
+
+  // for a quadratic matrix
+  for (int i = 0; i < _nHits; i++) {
+    Slnxl += log(_xl[i]);
+    Sxl += _xl[i];
+    Sxt += _xt[i];
+    Sln2xl += log(_xl[i])*log(_xl[i]);
+    Sxllnxl += _xl[i]*log(_xl[i]);
+    Sxtlnxl += _xt[i]*log(_xl[i]);
+    Sxlxl += _xl[i]*_xl[i];
+    Sxlxt += _xl[i]*_xt[i];
+    Sxtxt += _xt[i]*_xt[i];
+    SlnA += log(_aHit[i]);
+    SlnAlnxl += log(_aHit[i])*log(_xl[i]);
+    SlnAxl += log(_aHit[i])*_xl[i];
+    SlnAxt += log(_aHit[i])*_xt[i]; 
+  }
+  // create system of linear equations, written as Ae = z
+
+  gsl_matrix* A = gsl_matrix_alloc(4,4);
+  gsl_vector* z = gsl_vector_alloc(4);
+  gsl_vector* e = gsl_vector_alloc(4);
+  
+  // initialise matrix and vectors
+  
+  gsl_matrix_set(A,0,0,_nHits);
+  gsl_matrix_set(A,0,1,Slnxl);
+  gsl_matrix_set(A,0,2,-Sxl);
+  gsl_matrix_set(A,0,3,-Sxt);
+  
+  gsl_matrix_set(A,1,0,Slnxl);
+  gsl_matrix_set(A,1,1,Sln2xl);
+  gsl_matrix_set(A,1,2,-Sxllnxl);
+  gsl_matrix_set(A,1,3,-Sxtlnxl);
+  
+  gsl_matrix_set(A,2,0,-Sxl);
+  gsl_matrix_set(A,2,1,-Sxllnxl);
+  gsl_matrix_set(A,2,2,Sxlxl);
+  gsl_matrix_set(A,2,3,Sxlxt);
+
+  gsl_matrix_set(A,3,0,-Sxt);
+  gsl_matrix_set(A,3,1,-Sxtlnxl);
+  gsl_matrix_set(A,3,2,Sxlxt);
+  gsl_matrix_set(A,3,3,Sxtxt);
+
+  gsl_vector_set(z,0,SlnA);
+  gsl_vector_set(z,1,SlnAlnxl);
+  gsl_vector_set(z,2,-SlnAxl);
+  gsl_vector_set(z,3,-SlnAxt);
+
+  gsl_linalg_HH_solve(A,z,e);
+
+  a = exp(gsl_vector_get(e,0));
+  b = gsl_vector_get(e,1);
+  c = gsl_vector_get(e,2);
+  d = gsl_vector_get(e,3);
+
+  chi2 = calculateChi2Fit3DProfileSimple(a,b,c,d);
+  
+  gsl_matrix_free(A);
+  gsl_vector_free(z);
+  gsl_vector_free(e);
+
+  int result = 0;  // no error handling at the moment
+  return result;
+
+}
+
+//=============================================================================
+
+int ClusterShapes::fit3DProfileAdvanced(float& chi2, double* par_init, double* par,
+					int npar, float* t, float* s, float* E, 
+					float E0) {
+
+  // local variables
+  int status = 0;
+  int iter = 0;
+  int max_iter = 1000;
+
+
+  // converging criteria
+  const double abs_error = 0.0;
+  const double rel_error = 1e-1;
+
+
+
+  gsl_multifit_function_fdf fitfunct;
+
+  const gsl_multifit_fdfsolver_type* T = gsl_multifit_fdfsolver_lmsder;
+
+  gsl_multifit_fdfsolver* Solver = gsl_multifit_fdfsolver_alloc(T,_nHits,npar);
+
+  gsl_matrix* covar = gsl_matrix_alloc(npar,npar);   // covariance matrix
+
+  data DataSet;
+  DataSet.n = _nHits;
+  DataSet.x = &t[0];
+  DataSet.y = &s[0];
+  DataSet.z = &E[0];  // _aHit[0]; // ???? normalise per volume ????
+
+
+  fitfunct.f = &ShapeFitFunct;
+  fitfunct.df = &dShapeFitFunct;
+  fitfunct.fdf = &fdfShapeFitFunct;
+  fitfunct.n = _nHits;
+  fitfunct.p = npar;
+  fitfunct.params = &DataSet;
+
+  gsl_vector_view pinit = gsl_vector_view_array(par_init,npar);
+  gsl_multifit_fdfsolver_set(Solver,&fitfunct,&pinit.vector);
+
+  gsl_set_error_handler_off();
+
+  // perform fit
+  do {
+    iter++;
+    std::cout << "Multidimensional Fit Iteration started ... ... ";
+    status = gsl_multifit_fdfsolver_iterate(Solver);
+    std::cout << "--- DONE ---" << std::endl;
+
+    if (status) break;
+    status = gsl_multifit_test_delta (Solver->dx,Solver->x,abs_error,rel_error);
+
+    // debug
+    /*
+    //    E0  = (float)gsl_vector_get(Solver->x,0);
+    par[0] = (float)gsl_vector_get(Solver->x,0);
+    par[1] = (float)gsl_vector_get(Solver->x,1);
+    par[2] = (float)gsl_vector_get(Solver->x,2);
+    par[3] = (float)gsl_vector_get(Solver->x,3);
+
+    std::cout << "Status of multidimensional fit : " << status << "  "
+	      << "Iterations : " << iter << std::endl;
+    std::cout << "E0 : " <<  "FIXED" << "\t" << "A : " << par[0] << "\t" << "B : " 
+	      <<  par[1] << "\t" << "D : " << par[2] << "\t" << "t0 : "  << par[3] 
+	      << std::endl << std::endl;
+    */
+
+  } while ( status==GSL_CONTINUE && iter < max_iter);
+
+  gsl_multifit_covar (Solver->J,rel_error,covar);
+
+  //  E0  = (float)gsl_vector_get(Solver->x,0);
+  par[0] = (float)gsl_vector_get(Solver->x,0); // A
+  par[1] = (float)gsl_vector_get(Solver->x,1); // B
+  par[2] = (float)gsl_vector_get(Solver->x,2); // D
+  par[3] = (float)gsl_vector_get(Solver->x,3); // t0
+
+  gsl_multifit_fdfsolver_free(Solver);
+  gsl_matrix_free(covar);
+  
+  chi2 = calculateChi2Fit3DProfileAdvanced(E0,par[0],par[1],par[2],par[3]);
+  if (status) chi2 = -1.0;
+
+  int result = 0;  // no error handling at the moment
+  return result;
+
+}
+
+//=============================================================================
+
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.h b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b97b685cf3c2604caaced1a9fb0f44dc17ff6af
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/ClusterShapes.h
@@ -0,0 +1,356 @@
+#ifndef ClusterShapes_h
+#define ClusterShapes_h
+
+
+#include <stdio.h>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <cstdlib>
+#include "HelixClass.h"
+#include <math.h>
+
+
+/**
+ *    Utility class to derive properties of clusters, such as centre of gravity,
+ *    axes of inertia, fits of the cluster shape and so on. All the details are
+ *    explained in the documentation of the methods. Several classes of the GSL 
+ *    (GNU Scientific Library) are needed in this class.
+ *
+ *    @authors V. Morgunov (ITEP/DESY), A. Raspereza (DESY), O. Wendt (DESY)
+ *    @version $Id: ClusterShapes.h,v 1.14 2007-04-27 13:56:53 owendt Exp $
+ *
+ */
+class ClusterShapes {
+
+ public:
+
+  /**
+   *    Constructor
+   *    @param nhits : number of hits in the cluster
+   *    @param a     : amplitudes of elements ('cells') of the cluster. Stored in 
+   *                   an array, with one entry for each element ('cell'). Each entry 
+   *                   is depending on coordinates x,y,z (Cartesian), which are stored 
+   *                   in the arrays x,y,z.
+   *    @param x,y,z : array of coordinates corresponding to the array of amplitudes a.
+   *
+   *
+   */
+  ClusterShapes(int nhits, float* a, float* x, float* y, float* z);
+
+
+  /**
+   *    Destructor
+   */
+  ~ClusterShapes();
+
+  /**
+   *    Defining errors for Helix Fit
+   */
+   void setErrors(float *ex, float* ey, float *ez);
+
+   /**
+    *   Defining hit types for Helix Fit :
+    *   type 1 - cyllindrical detector
+    *   type 2 - Z disk detector
+    */
+   void setHitTypes(int *ityp);
+
+
+  /**
+   * returns the number of elements of the cluster
+   */
+   int getNumberOfHits();
+
+  /**
+   * returns the accumulated amplitude for the whole cluster (just the sum of the 
+   * energy in all the entries of the cluster)
+   */
+  float getTotalAmplitude();
+
+  /**
+   * returns an array, which represents a vector from the origin of the
+   * coordiante system, i.\ e.\ IP, to the centre of gravity of the cluster. The centre 
+   * of gravity is calculated with the energy of the entries of the cluster.
+   */
+  float* getCentreOfGravity();
+
+  /** US spelling of getCentreOfGravity */
+  inline float* getCenterOfGravity() { return getCentreOfGravity() ; }
+  
+  /**
+   * array of the inertias of mass (i.\ e.\ energy) corresponding to the three main axes 
+   * of inertia. The array is sorted in ascending order.
+   */
+  float* getEigenValInertia();
+
+  /**
+   * array of the three main axes of inertia (9 entries) starting
+   * with the axis corresponding to the smallest inertia of mass 
+   * (main principal axis). All axes are normalised to a length 
+   * of 1.
+   */
+  float* getEigenVecInertia();
+
+  /**
+   * 'mean' width of the cluster perpendicular to the main 
+   * principal axis, defined as: 
+   * width := sqrt( 1/TotalAmplitude * Sum(a[i]*d[i]*d[i]) ),
+   * where d[i] is the distance of the i-th point to the main
+   * principal axis.
+   */
+  float getWidth();
+
+  /**
+   * returns the coordinates of the cluster transformed into 
+   * the CoG-System.
+   * @param xlong  : pointer to an array, where the calculated longitudinal coordiantes
+   *                 are stored in.
+   * @param xtrans : pointer to an array, where the calculated transversal coordiantes
+   *                 are stored in.
+   */
+  int getEigenSytemCoordinates(float* xlong, float* xtrans);
+
+  /**
+   * returns the coordinates and the amplitudes of the cluster
+   * transformed into the CoG-System.
+   * @param xlong  : pointer to an array, where the calculated longitudinal coordiantes
+   *                 are stored in.
+   * @param xtrans : pointer to an array, where the calculated transversal coordiantes
+   *                 are stored in.
+   * @param a      : pointer to an array, where the amplitudes corresponding to the 
+   *                 longitudinal and transversal coordiantes are stored in.
+   */
+  int getEigenSytemCoordinates(float* xlong, float* xtrans, float* a);
+
+  /**
+   * performs a least square fit on the shape of an electro-
+   * magnetic-shower, which is defined as:
+   * A[i] = a * (xl[i]-xl0)^b * exp(-c*(xl[i]-xl0)) * exp(-d*xt[i]),
+   * where A[i] is the array of amplitudes, xl[i] is the 
+   * coordinate of the actual point along the main principal 
+   * axis and xt[i] the coordinate perpendicular to it. The return value 
+   * of the method itself is not used at the moment (always returns 0).
+   * @param a,b,c,d,xl0  : references to the parameters, which are fitted.
+   * @param chi2         : reference to the chi2 of the fit
+   * @param xStart       : pointer to the 'initial hit' of the cluster. It is defined 
+   *                       as the point with the largest distance to the CoG measured 
+   *                       in the direction towards the IP.
+   * @param index_xStart : index of the point in the cluster corresponding to xStart
+   * @param X0           : radiation length of the detector material. For a composite 
+   *                       detector this is meant to be the 'mean' radiation length.
+   * @param Rm           : Moliere radius of the the detector material. For a composite 
+   *                       detector this is meant to be the 'mean' Moliere radius.
+   */
+  int fit3DProfile(float& chi2, float& a, float& b, float& c, float& d, float& xl0, 
+		   float * xStart, int& index_xStart, float X0, float Rm);
+
+  /**
+   * returns the chi2 of the fit in the method Fit3DProfile (if simple
+   * parametrisation is used)for a given set of parameters a,b,c,d
+   * @param a,b,c,d,xl0  : fitted parameters, which have been calculated before
+   * @param X0           : radiation length of the detector material. For a composite 
+   *                       detector this is meant to be the 'mean' radiation length.
+   * @param Rm           : Moliere radius of the the detector material. For a composite 
+   *                       detector this is meant to be the 'mean' Moliere radius.
+   */
+  float getChi2Fit3DProfileSimple(float a, float b, float c, float d, float X0, 
+				  float Rm);
+
+  /**
+   * returns the chi2 of the fit in the method Fit3DProfile (if advanced
+   * parametrisation is used) for a given set of parameters E0,a,b,d,t0
+   * @param E0,a,b,d,t0 : fitted parameters, which have been calculated before
+   * @param X0          : radiation length of the detector material. For a composite 
+   *                      detector this is meant to be the 'mean' radiation length.
+   * @param Rm          : Moliere radius of the the detector material. For a composite 
+   *                      detector this is meant to be the 'mean' Moliere radius.
+   */
+  float getChi2Fit3DProfileAdvanced(float E0, float a, float b, float d, float t0, 
+				    float X0, float Rm);
+
+  /**
+   * performs a least square fit on a helix path in space, which
+   * which is defined as (Cartesian coordiantes):
+   *
+   * 1. parametrisation:
+   * x[i] = x0 + R*cos(b*z[i] + phi0)
+   * y[i] = y0 + R*sin(b*z[i] + phi0)
+   * z[i] = z[i],
+   * where x0,y0,R,b and phi0 are the parameters to be fitted and
+   * x[i],y[i],z[i] are the (Cartesian) coordiantes of the space
+   * points.
+   * 
+   * 2. parametrisation:   
+   * x[i] = x0 + R*cos(phi)
+   * y[i] = y0 + R*sin(phi)
+   * z[i] = z0 + b*phi
+   * and phi = atan2( y[i]-y0 , x[i]-x0 ),
+   * where x0,y0,z0,R and b are the parameters to be fitted and
+   * x[i],y[i],z[i] are the (Cartesian) coordiantes of the space
+   * points.
+   * 
+   * The method returns 1 if an error occured and 0 if not.
+   *
+   * The following output/input parameters are returned/needed:
+   *
+   * OUTPUTS:
+   * @param parameter     : array of parameters to be fitted.
+   *                        For parametrisation 1: parameter[5] = {x0,y0,R,b,phi0}
+   *                        For parametrisation 2: parameter[5] = {x0,y0,z0,R,b}
+   * @param dparameter    : error on the parameters, that means: 
+   *                        dparameter[i] = sqrt( CovarMatrix[i][i] )
+   * @param chi2          : chi2 of the fit
+   * @param distmax       : maximal distance between the points x[i],y[i]
+   *                        z[i] and the fitted function
+   *
+   * INPUTS:
+   * @param parametrisation : 1 for first and 2 for second parametrisation (see above)
+   * @param max_iter        : maximal number of iterations, before fit cancels
+   * @param status_out      : if set to 1, only the initial parameters of
+   *                          the fit are calculated and are stored in
+   *                          parameter. The entries of dparameter are
+   *                          set to 0.0
+   */
+  int FitHelix(int max_iter, int status_out, int parametrisation,
+	       double* parameter, double* dparameter, double& chi2, double& distmax, int direction=1);
+
+
+  int FitHelix(int max_iter, int status_out, int parametrisation,
+	       float* parameter, float* dparameter, float& chi2, float& distmax, int direction=1);
+
+  /**
+   * distance to the centre of gravity measured from IP
+   * (absolut value of the vector to the centre of gravity)
+   */
+  inline float radius() { return _radius; }
+
+  /**
+   * largest spatial axis length of the ellipsoid derived
+   * by the inertia tensor (by their eigenvalues and eigen-
+   * vectors)
+   */
+  inline float getElipsoid_r1() { return _r1; }
+
+  /**
+   * medium spatial axis length of the ellipsoid derived
+   * by the inertia tensor (by their eigenvalues and eigen-
+   * vectors)
+   */
+  inline float getElipsoid_r2() { return _r2; }
+
+  /**
+   * smallest spatial axis length of the ellipsoid derived
+   * by the inertia tensor (by their eigenvalues and eigen-   
+   * vectors)
+   */
+  inline float getElipsoid_r3() { return _r3; }
+
+  /**
+   * volume of the ellipsoid
+   */
+  inline float getElipsoid_vol() { return _vol; }
+
+  /**
+   * average radius of the ellipsoid (qubic root of volume)
+   */
+  inline float getElipsoid_r_ave() { return _r_ave; }
+
+  /**
+   * density of the ellipsoid defined by: totAmpl/vol
+   */
+  inline float getElipsoid_density() { return _density; }
+
+  /**
+   * eccentricity of the ellipsoid defined by: 
+   * Width/r1
+   */
+  inline float getElipsoid_eccentricity() { return _eccentricity; }
+
+  /**
+   * distance from centre of gravity to the point most far 
+   * away from IP projected on the main principal axis
+   */
+  inline float getElipsoid_r_forw() { return _r1_forw; }
+
+  /**
+   * distance from centre of gravity to the point nearest 
+   * to IP projected on the main principal axis    
+   */
+  inline float getElipsoid_r_back() { return _r1_back; }
+
+
+
+
+
+ private:
+
+  int _nHits;
+
+  float* _aHit;
+  float* _xHit;
+  float* _yHit;
+  float* _zHit;
+  float* _exHit;
+  float* _eyHit;
+  float* _ezHit;
+  int* _types;
+  float* _xl;
+  float* _xt;
+  float* _t;
+  float* _s;
+
+  int   _ifNotGravity;
+  float _totAmpl;
+  float _radius;
+  float _xgr;
+  float _ygr;
+  float _zgr;
+  float _analogGravity[3];
+
+  int   _ifNotWidth;
+  float _analogWidth;
+
+  int   _ifNotInertia;
+  float _ValAnalogInertia[3];
+  float _VecAnalogInertia[9];
+
+  int _ifNotEigensystem;
+
+  int   _ifNotElipsoid;
+  float _r1           ;  // Cluster spatial axis length -- the largest
+  float _r2           ;  // Cluster spatial axis length -- less
+  float _r3           ;  // Cluster spatial axis length -- less
+  float _vol          ;  // Cluster ellipsoid volume
+  float _r_ave        ;  // Cluster average radius  (qubic root)
+  float _density      ;  // Cluster density
+  float _eccentricity ;  // Cluster Eccentricity
+  float _r1_forw      ;
+  float _r1_back      ;
+
+  void  findElipsoid();
+  void  findGravity();
+  void  findInertia();
+  void  findWidth();
+  float findDistance(int i);
+  float vecProduct(float * x1, float * x2);
+  float vecProject(float * x, float * axis);
+  double DistanceHelix(double x, double y, double z, double X0, double Y0, double R0, double bz,
+		      double phi0, double * distRPhiZ);
+  int transformToEigensystem(float* xStart, int& index_xStart, float X0, float Xm);
+  float calculateChi2Fit3DProfileSimple(float a, float b, float c, float d);
+  float calculateChi2Fit3DProfileAdvanced(float E0, float a, float b, float d, float t0);
+  int fit3DProfileSimple(float& chi2, float& a, float& b, float& c, float& d);
+  int fit3DProfileAdvanced(float& chi2, double* par_init, double* par, int npar,
+			   float* t, float* s, float* E, float E0);
+
+  // private methods for non-linear, multidim. fitting (helix)
+  // static int functParametrisation1(const gsl_vector* par, void* data, gsl_vector* f);
+  // static int dfunctParametrisation1(const gsl_vector* par, void* d, gsl_matrix* J);
+  // static int fdfParametrisation1(const gsl_vector* par, void* d, gsl_vector* f, gsl_matrix* J);
+
+
+};
+
+#endif
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.cc b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6582e17e49d105cd27dcef084b14e5e0c851f2fc
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.cc
@@ -0,0 +1,768 @@
+#include "HelixClass.h"
+#include <math.h>
+#include <stdlib.h>
+#include <iostream>
+#include "ced_cli.h"
+
+HelixClass::HelixClass() {
+    _const_2pi = 2.0*M_PI;
+    _const_pi2 = 0.5*M_PI;
+    _FCT = 2.99792458E-4;
+}
+
+HelixClass::~HelixClass() {}
+
+void HelixClass::Initialize_VP(float * pos, float * mom, float q, float B) {
+    _referencePoint[0] = pos[0];
+    _referencePoint[1] = pos[1];
+    _referencePoint[2] = pos[2];
+    _momentum[0] = mom[0];
+    _momentum[1] = mom[1];
+    _momentum[2] = mom[2];
+    _charge = q;
+    _bField = B;
+    _pxy = sqrt(mom[0]*mom[0]+mom[1]*mom[1]);
+    _radius = _pxy / (_FCT*B);
+    _omega = q/_radius;
+    _tanLambda = mom[2]/_pxy;
+    _phiMomRefPoint = atan2(mom[1],mom[0]);
+    _xCentre = pos[0] + _radius*cos(_phiMomRefPoint-_const_pi2*q);
+    _yCentre = pos[1] + _radius*sin(_phiMomRefPoint-_const_pi2*q);
+    _phiRefPoint = atan2(pos[1]-_yCentre,pos[0]-_xCentre);
+    _phiAtPCA = atan2(-_yCentre,-_xCentre);
+    _phi0 = -_const_pi2*q + _phiAtPCA;
+    while (_phi0<0) _phi0+=_const_2pi;
+    while (_phi0>=_const_2pi) _phi0-=_const_2pi;
+    _xAtPCA = _xCentre + _radius*cos(_phiAtPCA);
+    _yAtPCA = _yCentre + _radius*sin(_phiAtPCA);
+    //    _d0 = -_xAtPCA*sin(_phi0) + _yAtPCA*cos(_phi0);
+    double pxy = double(_pxy);
+    double radius = pxy/double(_FCT*B);
+    double xCentre = double(pos[0]) + radius*double(cos(_phiMomRefPoint-_const_pi2*q));
+    double yCentre = double(pos[1]) + radius*double(sin(_phiMomRefPoint-_const_pi2*q));
+    
+    double d0;
+
+    if (q>0) {
+      d0 = double(q)*radius - double(sqrt(xCentre*xCentre+yCentre*yCentre));
+    }
+    else {
+      d0 = double(q)*radius + double(sqrt(xCentre*xCentre+yCentre*yCentre));
+    }
+
+    _d0 = float(d0);
+
+//     if (fabs(_d0)>0.001 ) {
+//       std::cout << "New helix : " << std::endl;
+//       std::cout << " Position : " << pos[0] 
+// 		<< " " << pos[1]
+// 		<< " " << pos[2] << std::endl;
+//       std::cout << " Radius = " << _radius << std::endl;
+//       std::cout << " RC = " << sqrt(_xCentre*_xCentre+_yCentre*_yCentre) << std::endl;  
+//       std::cout << " D0 = " << _d0 << std::endl;
+//     }
+
+    _pxAtPCA = _pxy*cos(_phi0);
+    _pyAtPCA = _pxy*sin(_phi0);
+    float deltaPhi = _phiRefPoint - _phiAtPCA;    
+    float xCircles = -pos[2]*q/(_radius*_tanLambda) - deltaPhi;
+    xCircles = xCircles/_const_2pi;
+    int nCircles;
+    int n1,n2;
+
+    if (xCircles >= 0.) {
+	n1 = int(xCircles);
+	n2 = n1 + 1;
+    }
+    else {
+	n1 = int(xCircles) - 1;
+	n2 = n1 + 1;
+    }
+    
+    if (fabs(n1-xCircles) < fabs(n2-xCircles)) {
+	nCircles = n1;
+    }
+    else {
+	nCircles = n2;
+    }
+    _z0 = pos[2] + _radius*_tanLambda*q*(deltaPhi + _const_2pi*nCircles);
+
+}
+
+void HelixClass::Initialize_Canonical(float phi0, float d0, float z0, 
+				      float omega, float tanLambda, float B) {
+    _omega = omega;
+    _d0 = d0;
+    _phi0 = phi0;
+    _z0 = z0;
+    _tanLambda = tanLambda;
+    _charge = omega/fabs(omega);
+    _radius = 1./fabs(omega);
+    _xAtPCA = -_d0*sin(_phi0);
+    _yAtPCA = _d0*cos(_phi0);    
+    _referencePoint[0] = _xAtPCA;
+    _referencePoint[1] = _yAtPCA;
+    _referencePoint[2] = _z0;
+    _pxy = _FCT*B*_radius;
+    _momentum[0] = _pxy*cos(_phi0);
+    _momentum[1] = _pxy*sin(_phi0);
+    _momentum[2] = _tanLambda * _pxy;    
+    _pxAtPCA = _momentum[0];
+    _pyAtPCA = _momentum[1];
+    _phiMomRefPoint = atan2(_momentum[1],_momentum[0]);
+    _xCentre = _referencePoint[0] + 
+      _radius*cos(_phi0-_const_pi2*_charge);
+    _yCentre = _referencePoint[1] + 
+      _radius*sin(_phi0-_const_pi2*_charge);
+    _phiAtPCA = atan2(-_yCentre,-_xCentre);
+    _phiRefPoint =  _phiAtPCA ;
+    _bField = B;
+}
+
+
+void HelixClass::Initialize_BZ(float xCentre, float yCentre, float radius, 
+			       float bZ, float phi0, float B, float signPz,
+			       float zBegin) {
+
+  _radius = radius;
+  _pxy = _FCT*B*_radius;
+  _charge = -(bZ*signPz)/fabs(bZ*signPz);
+  _momentum[2] = -_charge*_pxy/(bZ*_radius);
+  _xCentre = xCentre;
+  _yCentre = yCentre;
+  _omega = _charge/radius;
+  _phiAtPCA = atan2(-_yCentre,-_xCentre);
+  _phi0 = -_const_pi2*_charge + _phiAtPCA;
+  while (_phi0<0) _phi0+=_const_2pi;
+  while (_phi0>=_const_2pi) _phi0-=_const_2pi;
+  _xAtPCA = _xCentre + _radius*cos(_phiAtPCA);
+  _yAtPCA = _yCentre + _radius*sin(_phiAtPCA);
+  _d0 = -_xAtPCA*sin(_phi0) + _yAtPCA*cos(_phi0);
+  _pxAtPCA = _pxy*cos(_phi0);
+  _pyAtPCA = _pxy*sin(_phi0);
+  _referencePoint[2] = zBegin;
+  _referencePoint[0] = xCentre + radius*cos(bZ*zBegin+phi0);
+  _referencePoint[1] = yCentre + radius*sin(bZ*zBegin+phi0);
+  _phiRefPoint = atan2(_referencePoint[1]-_yCentre,_referencePoint[0]-_xCentre);
+  _phiMomRefPoint =  -_const_pi2*_charge + _phiRefPoint;
+  _tanLambda = _momentum[2]/_pxy;
+  _momentum[0] = _pxy*cos(_phiMomRefPoint);
+  _momentum[1] = _pxy*sin(_phiMomRefPoint);
+  
+  float deltaPhi = _phiRefPoint - _phiAtPCA;    
+  float xCircles = bZ*_referencePoint[2] - deltaPhi;
+  xCircles = xCircles/_const_2pi;
+  int nCircles;
+  int n1,n2;
+
+  if (xCircles >= 0.) {
+    n1 = int(xCircles);
+    n2 = n1 + 1;
+  }
+  else {
+    n1 = int(xCircles) - 1;
+    n2 = n1 + 1;
+  }
+  
+  if (fabs(n1-xCircles) < fabs(n2-xCircles)) {
+    nCircles = n1;
+  }
+  else {
+    nCircles = n2;
+  }  
+  _z0 = _referencePoint[2] - (deltaPhi + _const_2pi*nCircles)/bZ;  
+  _bField = B;
+
+}
+
+const float * HelixClass::getMomentum() {
+    return _momentum;
+}
+const float * HelixClass::getReferencePoint() {
+    return _referencePoint;
+}
+float HelixClass::getPhi0() {
+  if (_phi0<0.0)
+    _phi0 += 2*M_PI;
+  return _phi0;
+}
+float HelixClass::getD0() {
+    return _d0;
+}
+float HelixClass::getZ0() {
+    return _z0;
+}
+float HelixClass::getOmega() {
+    return _omega;
+}
+float HelixClass::getTanLambda() {
+    return _tanLambda;
+}
+float HelixClass::getPXY() {
+    return _pxy;
+}
+float HelixClass::getXC() {
+  return _xCentre;
+}
+
+float HelixClass::getYC() {
+  return _yCentre;
+}
+
+float HelixClass::getRadius() {
+  return _radius;
+}
+
+float HelixClass::getBz() {
+  return _bZ;
+}
+
+float HelixClass::getPhiZ() {
+  return _phiZ;
+}
+
+float HelixClass::getCharge() {
+    return _charge;
+}
+
+float HelixClass::getPointInXY(float x0, float y0, float ax, float ay, 
+			      float * ref , float * point) {
+
+  float time;
+
+  float AA = sqrt(ax*ax+ay*ay);
+
+
+  if (AA <= 0) {
+    time = -1.0e+20; 
+    return time;
+  }
+
+
+  float BB = ax*(x0-_xCentre) + ay*(y0-_yCentre);
+  BB = BB / AA;
+
+  float CC = (x0-_xCentre)*(x0-_xCentre) 
+    + (y0-_yCentre)*(y0-_yCentre) - _radius*_radius;
+
+  CC = CC / AA;
+
+  float DET = BB*BB - CC;
+  float tt1 = 0.;
+  float tt2 = 0.;
+  float xx1,xx2,yy1,yy2; 
+
+
+  if (DET < 0 ) {
+    time = 1.0e+10;
+    point[0]=0.0;
+    point[1]=0.0;
+    point[2]=0.0;
+    return time;
+  }
+  
+  
+  tt1 = - BB + sqrt(DET);
+  tt2 = - BB - sqrt(DET);
+
+  xx1 = x0 + tt1*ax;
+  yy1 = y0 + tt1*ay;
+  xx2 = x0 + tt2*ax;
+  yy2 = y0 + tt2*ay;
+  
+  float phi1 = atan2(yy1-_yCentre,xx1-_xCentre);
+  float phi2 = atan2(yy2-_yCentre,xx2-_xCentre);
+  float phi0 = atan2(ref[1]-_yCentre,ref[0]-_xCentre);
+
+  float dphi1 = phi1 - phi0;
+  float dphi2 = phi2 - phi0;
+
+  if (dphi1 < 0 && _charge < 0) {
+    dphi1 = dphi1 + _const_2pi;
+  }
+  else if (dphi1 > 0 && _charge > 0) { 
+    dphi1 = dphi1 - _const_2pi;
+  }
+
+  if (dphi2 < 0 && _charge < 0) {
+    dphi2 = dphi2 + _const_2pi;
+  }
+  else if (dphi2 > 0 && _charge > 0) { 
+    dphi2 = dphi2 - _const_2pi;
+  }
+
+  // Times
+  tt1 = -_charge*dphi1*_radius/_pxy;
+  tt2 = -_charge*dphi2*_radius/_pxy;
+
+  if (tt1 < 0. )
+    std::cout << "WARNING " << tt1 << std::endl;
+  if (tt2 < 0. )
+    std::cout << "WARNING " << tt2 << std::endl;
+  
+
+  if (tt1 < tt2) {
+    point[0] = xx1;
+    point[1] = yy1;
+    time = tt1;
+  }
+  else {
+    point[0] = xx2;
+    point[1] = yy2;
+    time = tt2;
+  }
+
+  point[2] = ref[2]+time*_momentum[2];
+
+  
+
+  return time;
+
+}
+
+
+float HelixClass::getPointOnCircle(float Radius, float * ref, float * point) {
+
+  float distCenterToIP = sqrt(_xCentre*_xCentre + _yCentre*_yCentre);
+
+  point[0] = 0.0;
+  point[1] = 0.0;
+  point[2] = 0.0;
+
+  if ((distCenterToIP+_radius)<Radius) {
+    float xx = -1.0e+20;
+    return xx;
+  }
+
+  if ((_radius+Radius)<distCenterToIP) {
+    float xx = -1.0e+20;
+    return xx;
+  }
+
+  float phiCentre = atan2(_yCentre,_xCentre);
+  float phiStar   = Radius*Radius + distCenterToIP*distCenterToIP 
+                                    - _radius*_radius;
+
+  phiStar = 0.5*phiStar/fmax(1.0e-20,Radius*distCenterToIP);
+  
+  if (phiStar > 1.0) 
+    phiStar = 0.9999999;
+  
+  if (phiStar < -1.0)
+    phiStar = -0.9999999;
+  
+  phiStar = acos(phiStar);
+
+  float tt1,tt2,time;
+
+  float xx1 = Radius*cos(phiCentre+phiStar);
+  float yy1 = Radius*sin(phiCentre+phiStar);
+
+  float xx2 = Radius*cos(phiCentre-phiStar);
+  float yy2 = Radius*sin(phiCentre-phiStar);
+
+
+  float phi1 = atan2(yy1-_yCentre,xx1-_xCentre);
+  float phi2 = atan2(yy2-_yCentre,xx2-_xCentre);
+  float phi0 = atan2(ref[1]-_yCentre,ref[0]-_xCentre);
+
+  float dphi1 = phi1 - phi0;
+  float dphi2 = phi2 - phi0;
+
+  if (dphi1 < 0 && _charge < 0) {
+    dphi1 = dphi1 + _const_2pi;
+  }
+  else if (dphi1 > 0 && _charge > 0) { 
+    dphi1 = dphi1 - _const_2pi;
+  }
+
+  if (dphi2 < 0 && _charge < 0) {
+    dphi2 = dphi2 + _const_2pi;
+  }
+  else if (dphi2 > 0 && _charge > 0) { 
+    dphi2 = dphi2 - _const_2pi;
+  }
+
+  // Times
+  tt1 = -_charge*dphi1*_radius/_pxy;
+  tt2 = -_charge*dphi2*_radius/_pxy;
+
+  if (tt1 < 0. )
+    std::cout << "WARNING " << tt1 << std::endl;
+  if (tt2 < 0. )
+    std::cout << "WARNING " << tt2 << std::endl;
+  
+
+  float time2;
+  if (tt1 < tt2) {
+    point[0] = xx1;
+    point[1] = yy1;
+    point[3] = xx2;
+    point[4] = yy2;
+    time = tt1;
+    time2 = tt2;
+  }
+  else {
+    point[0] = xx2;
+    point[1] = yy2;
+    point[3] = xx1;
+    point[4] = yy1;
+    time = tt2;
+    time2 = tt1;
+  }
+
+  point[2] = ref[2]+time*_momentum[2];
+  point[5] = ref[2]+time2*_momentum[2];
+  
+
+  return time;
+
+}
+
+
+float HelixClass::getPointInZ(float zLine, float * ref, float * point) {
+
+  float time = zLine - ref[2];
+
+  if (_momentum[2] == 0.) {
+    time = -1.0e+20;
+    point[0] = 0.;
+    point[1] = 0.;
+    point[2] = 0.;
+    return time;
+  }
+
+  time = time/_momentum[2];
+
+  float phi0 = atan2(ref[1] - _yCentre , ref[0] - _xCentre);
+  float phi = phi0 - _charge*_pxy*time/_radius;
+  float xx = _xCentre + _radius*cos(phi);
+  float yy = _yCentre + _radius*sin(phi);
+
+  point[0] = xx;
+  point[1] = yy;
+  point[2] = zLine;
+
+  return time;
+
+
+}
+
+float HelixClass::getDistanceToPoint(float * xPoint, float * Distance) {
+
+  float zOnHelix;
+  float phi = atan2(xPoint[1]-_yCentre,xPoint[0]-_xCentre);
+  float phi0 = atan2(_referencePoint[1]-_yCentre,_referencePoint[0]-_xCentre);
+  //calculate distance to XYprojected centre of Helix, comparing this with distance to radius around centre gives DistXY
+  float DistXY = (_xCentre-xPoint[0])*(_xCentre-xPoint[0]) + (_yCentre-xPoint[1])*(_yCentre-xPoint[1]);
+  DistXY = sqrt(DistXY);
+  DistXY = fabs(DistXY - _radius);
+  
+  int nCircles = 0;
+
+  if (fabs(_tanLambda*_radius)>1.0e-20) {
+    float xCircles = phi0 - phi -_charge*(xPoint[2]-_referencePoint[2])/(_tanLambda*_radius);
+    xCircles = xCircles/_const_2pi;
+    int n1,n2;
+
+    if (xCircles >= 0.) {
+	n1 = int(xCircles);
+	n2 = n1 + 1;
+    }
+    else {
+	n1 = int(xCircles) - 1;
+	n2 = n1 + 1;
+    }
+    
+    if (fabs(n1-xCircles) < fabs(n2-xCircles)) {
+	nCircles = n1;
+    }
+    else {
+	nCircles = n2;
+    }
+
+  }
+  
+  float DPhi = _const_2pi*((float)nCircles) + phi - phi0;
+
+  zOnHelix = _referencePoint[2] - _charge*_radius*_tanLambda*DPhi;
+
+  float DistZ = fabs(zOnHelix - xPoint[2]);
+  float Time;
+
+  if (fabs(_momentum[2]) > 1.0e-20) {
+    Time = (zOnHelix - _referencePoint[2])/_momentum[2];
+  }
+  else {
+    Time = _charge*_radius*DPhi/_pxy;
+  }
+
+  Distance[0] = DistXY;
+  Distance[1] = DistZ;
+  Distance[2] = sqrt(DistXY*DistXY+DistZ*DistZ);
+
+  return Time;
+
+
+}
+
+//When we are not interested in the exact distance, we can check if we are
+//already far enough away in XY, before we start calculating in Z as the
+//distance will only increase
+float HelixClass::getDistanceToPoint(const std::vector<float>& xPoint, float distCut) {
+  //calculate distance to XYprojected centre of Helix, comparing this with distance to radius around centre gives DistXY
+  float tempx = xPoint[0]-_xCentre;
+  float tempy = xPoint[1]-_yCentre;
+  float tempsq = sqrt(tempx*tempx + tempy*tempy);
+  float tempdf = tempsq - _radius;
+  float DistXY = fabs( tempdf );
+  //If this is bigger than distCut, we dont have to know how much bigger this is
+  if( DistXY > distCut) {
+    return DistXY;
+  }
+
+  int nCircles = 0;
+  float phi = atan2(tempy,tempx);
+  float phi0 = atan2(_referencePoint[1]-_yCentre,_referencePoint[0]-_xCentre);
+  float phidiff = phi0-phi;
+  float  tempz = xPoint[2] - _referencePoint[2];//Yes referencePoint
+  float tanradius = _tanLambda*_radius;
+  if (fabs(tanradius)>1.0e-20) {
+    float xCircles = (phidiff -_charge*tempz/tanradius)/_const_2pi;
+    int n1,n2;
+    if (xCircles >= 0.) {
+	n1 = int(xCircles);
+	n2 = n1 + 1;
+    }
+    else {
+	n1 = int(xCircles) - 1;
+	n2 = n1 + 1;
+    }
+    if (fabs(n1-xCircles) < fabs(n2-xCircles)) {
+	nCircles = n1;
+    }
+    else {
+	nCircles = n2;
+    }
+  }
+  float DistZ = - tempz - _charge*tanradius*(_const_2pi*((float)nCircles) - phidiff);
+  return sqrt(DistXY*DistXY+DistZ*DistZ);
+}//getDistanceToPoint(vector,float)
+
+float HelixClass::getDistanceToPoint(const float* xPoint, float distCut) {
+  std::vector<float> xPosition(xPoint, xPoint + 3 );//We are expecting three coordinates, must be +3, last element is excluded!
+  return getDistanceToPoint(xPosition, distCut);
+}//getDistanceToPoint(float*,float)
+
+
+
+void HelixClass::setHelixEdges(float * xStart, float * xEnd) {
+  for (int i=0; i<3; ++i) {
+    _xStart[i] = xStart[i];
+    _xEnd[i] = xEnd[i];
+  }
+
+}
+
+float HelixClass::getDistanceToHelix(HelixClass * helix, float * pos, float * mom) {
+
+  float x01 = getXC();
+  float y01 = getYC();
+  
+  float x02 = helix->getXC();
+  float y02 = helix->getYC();
+  
+  float rad1 = getRadius();
+  float rad2 = helix->getRadius();
+
+  float distance = sqrt((x01-x02)*(x01-x02)+(y01-y02)*(y01-y02));
+
+  bool singlePoint = true;
+
+  float phi1 = 0;
+  float phi2 = 0;
+
+  if (rad1+rad2<distance) {
+    phi1 = atan2(y02-y01,x02-x01);
+    phi2 = atan2(y01-y02,x01-x02);
+  }
+  else if (distance+rad2<rad1) {
+    phi1 = atan2(y02-y01,x02-x01);
+    phi2 = phi1;
+  }
+  else if (distance+rad1<rad2) {
+    phi1 = atan2(y01-y02,x01-x02);
+    phi2 = phi1;
+  }
+  else {
+    singlePoint = false;
+    float cosAlpha = 0.5*(distance*distance+rad2*rad2-rad1*rad1)/(distance*rad2);
+    float alpha = acos(cosAlpha);
+    float phi0 = atan2(y01-y02,x01-x02);
+    phi1 = phi0 + alpha;
+    phi2 = phi0 - alpha;
+  }
+  
+
+  float ref1[3];
+  float ref2[3];
+  for (int i=0;i<3;++i) {
+    ref1[i]=_referencePoint[i];
+    ref2[i]=helix->getReferencePoint()[i];
+  }
+  
+  float pos1[3];
+  float pos2[3];
+  float mom1[3];
+  float mom2[3];
+
+
+  if (singlePoint ) {
+
+    float xSect1 = x01 + rad1*cos(phi1);
+    float ySect1 = y01 + rad1*sin(phi1);
+    float xSect2 = x02 + rad2*cos(phi2);
+    float ySect2 = y02 + rad2*sin(phi2);
+    float R1 = sqrt(xSect1*xSect1+ySect1*ySect1);
+    float R2 = sqrt(xSect2*xSect2+ySect2*ySect2);
+
+    getPointOnCircle(R1,ref1,pos1);
+    helix->getPointOnCircle(R2,ref2,pos2);
+    
+  }
+  else {    
+
+    float xSect1 = x02 + rad2*cos(phi1);
+    float ySect1 = y02 + rad2*sin(phi1);
+    float xSect2 = x02 + rad2*cos(phi2);
+    float ySect2 = y02 + rad2*sin(phi2);
+
+//     std::cout << "(xSect1,ySect1)=(" << xSect1 << "," << ySect1 << ")" << std::endl;
+//     std::cout << "(xSect2,ySect2)=(" << xSect2 << "," << ySect2 << ")" << std::endl;
+
+    float temp21[3];
+    float temp22[3];
+
+    float phiI2  = atan2(ref2[1]-y02,ref2[0]-x02); 
+    float phiF21 = atan2(ySect1-y02,xSect1-x02);
+    float phiF22 = atan2(ySect2-y02,xSect2-x02);
+    float deltaPhi21 = phiF21 - phiI2;
+    float deltaPhi22 = phiF22 - phiI2;
+    float charge2 = helix->getCharge();
+    float pxy2 = helix->getPXY();
+    float pz2   = helix->getMomentum()[2];
+    if (deltaPhi21 < 0 && charge2 < 0) {
+      deltaPhi21 += _const_2pi;
+    }
+    else if (deltaPhi21 > 0 && charge2 > 0) { 
+      deltaPhi21 -= _const_2pi;
+    }
+
+    if (deltaPhi22 < 0 && charge2 < 0) {
+      deltaPhi22 += _const_2pi;
+    }
+    else if (deltaPhi22 > 0 && charge2 > 0) { 
+      deltaPhi22 -= _const_2pi;
+    }
+
+    float time21 = -charge2*deltaPhi21*rad2/pxy2;
+    float time22 = -charge2*deltaPhi22*rad2/pxy2;
+
+    float Z21 = ref2[2] + time21*pz2;
+    float Z22 = ref2[2] + time22*pz2;
+
+    temp21[0] = xSect1; temp21[1] = ySect1; temp21[2] = Z21;
+    temp22[0] = xSect2; temp22[1] = ySect2; temp22[2] = Z22;
+    
+
+//     std::cout << "temp21 = " << temp21[0] << " " << temp21[1] << " " << temp21[2] << std::endl;
+//     std::cout << "temp22 = " << temp22[0] << " " << temp22[1] << " " << temp22[2] << std::endl;
+
+
+    float temp11[3];
+    float temp12[3];
+
+    float phiI1  = atan2(ref1[1]-y01,ref1[0]-x01); 
+    float phiF11 = atan2(ySect1-y01,xSect1-x01);
+    float phiF12 = atan2(ySect2-y01,xSect2-x01);
+    float deltaPhi11 = phiF11 - phiI1;
+    float deltaPhi12 = phiF12 - phiI1;
+    float charge1 = _charge;
+    float pxy1 = _pxy;
+    float pz1   = _momentum[2];
+    if (deltaPhi11 < 0 && charge1 < 0) {
+      deltaPhi11 += _const_2pi;
+    }
+    else if (deltaPhi11 > 0 && charge1 > 0) { 
+      deltaPhi11 -= _const_2pi;
+    }
+
+    if (deltaPhi12 < 0 && charge1 < 0) {
+      deltaPhi12 += _const_2pi;
+    }
+    else if (deltaPhi12 > 0 && charge1 > 0) { 
+      deltaPhi12 -= _const_2pi;
+    }
+
+    float time11 = -charge1*deltaPhi11*rad1/pxy1;
+    float time12 = -charge1*deltaPhi12*rad1/pxy1;
+
+    float Z11 = ref1[2] + time11*pz1;
+    float Z12 = ref1[2] + time12*pz1;
+
+    temp11[0] = xSect1; temp11[1] = ySect1; temp11[2] = Z11;
+    temp12[0] = xSect2; temp12[1] = ySect2; temp12[2] = Z12;
+    
+//     std::cout << "temp11 = " << temp11[0] << " " << temp11[1] << " " << temp11[2] << std::endl;
+//     std::cout << "temp12 = " << temp12[0] << " " << temp12[1] << " " << temp12[2] << std::endl;
+
+    float Dist1 = 0;
+    float Dist2 = 0;
+
+    for (int j=0;j<3;++j) {
+      Dist1 += (temp11[j]-temp21[j])*(temp11[j]-temp21[j]);
+      Dist2 += (temp12[j]-temp22[j])*(temp12[j]-temp22[j]);
+    }
+
+    if (Dist1<Dist2) {
+      for (int l=0;l<3;++l) {
+	pos1[l] = temp11[l];
+	pos2[l] = temp21[l];
+      }
+    }
+    else {
+       for (int l=0;l<3;++l) {
+	pos1[l] = temp12[l];
+	pos2[l] = temp22[l];
+      }
+    }
+
+  }
+
+  getExtrapolatedMomentum(pos1,mom1);
+  helix->getExtrapolatedMomentum(pos2,mom2);
+
+  float helixDistance = 0;
+
+  for (int i=0;i<3;++i) {
+    helixDistance += (pos1[i] - pos2[i])*(pos1[i] - pos2[i]);
+    pos[i] = 0.5*(pos1[i]+pos2[i]);
+    mom[i] = mom1[i]+mom2[i];
+  }
+  helixDistance = sqrt(helixDistance);
+
+  return helixDistance;
+
+}
+
+void HelixClass::getExtrapolatedMomentum(float * pos, float * momentum) {
+
+  float phi = atan2(pos[1]-_yCentre,pos[0]-_xCentre);
+  if (phi <0.) phi += _const_2pi;
+  phi = phi - _phiAtPCA + _phi0;
+  momentum[0] = _pxy*cos(phi);
+  momentum[1] = _pxy*sin(phi);
+  momentum[2] = _momentum[2];
+
+
+}
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.h b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.h
new file mode 100644
index 0000000000000000000000000000000000000000..794f8158652a637180cb99de38e35a249c2142d9
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/HelixClass.h
@@ -0,0 +1,302 @@
+#ifndef HELIXAR_H
+#define HELIXAR_H 1
+#include <vector>
+/**
+ *    Utility class to manipulate with different parameterisations <br>
+ *    of helix. Helix can be initialized in a three different <br>
+ *    ways using the following public methods : <br>
+ *    1) Initialize_VP(float * pos, float * mom, float q, float B) : <br>
+ *       initialization of helix is done using <br>
+ *       - position of the reference point : pos[3]; <br>
+ *       - momentum vector at the reference point : mom[3];<br>
+ *       - particle charge : q;<br>
+ *       - magnetic field (in Tesla) : B;<br>
+ *    2) Initialize_BZ(float xCentre, float yCentre, float radius, <br>
+ *				   float bZ, float phi0, float B, float signPz,<br>
+ *				   float zBegin):<br>
+ *       initialization of helix is done according to the following<br>
+ *       parameterization<br>
+ *       x = xCentre + radius*cos(bZ*z + phi0)<br>
+ *       y = yCentre + radius*sin(bZ*z + phi0)<br>
+ *       where (x,y,z) - position of point on the helix<br>
+ *       - (xCentre,yCentre) is the centre of circumference in R-Phi plane<br>
+ *       - radius is the radius of circumference<br>
+ *       - bZ is the helix slope parameter<br>
+ *       - phi0 is the initial phase of circumference<br>
+ *       - B is the magnetic field (in Tesla)<br>
+ *       - signPz is the sign of the z component of momentum vector<br>
+ *       - zBegin is the z coordinate of the reference point;<br>
+ *    3) void Initialize_Canonical(float phi0, float d0, float z0, float omega,<br> 
+ *			      float tanlambda, float B) :<br>
+ *    canonical (LEP-wise) parameterisation with the following parameters<br>
+ *       - phi0 - Phi angle of momentum vector at the point of<br>
+ *         closest approach to IP in R-Phi plane;
+ *       - d0 - signed distance of closest approach to IP in R-Phi plane;<br>
+ *       - z0 - z coordinate of the point of closest approach in R-Phi plane;<br>
+ *       - omega - signed curvature;<br>
+ *       - tanlambda - tangent of dip angle;<br>
+ *       - B - magnetic field (in Tesla);<br>
+ *    A set of public methods (getters) provide access to <br>
+ *    various parameters associated with helix. Helix Class contains<br>
+ *    also several utility methods, allowing for calculation of helix<br>
+ *    intersection points with planes parallel and perpendicular to <br>
+ *    z (beam) axis and determination of the distance of closest approach<br>
+ *    from arbitrary 3D point to the helix. <br>
+ *    @author A. Raspereza (DESY)<br>
+ *    @version $Id: HelixClass.h,v 1.16 2008-06-05 13:47:18 rasp Exp $<br>
+ *
+ */
+
+#include "LineClass.h"
+class HelixClass;
+
+class HelixClass {
+ public:
+
+/**
+ *  Constructor. Initializations of constants which are used
+ *  to calculate various parameters associated with helix.
+ */ 
+    HelixClass();
+/**
+ *  Destructor. 
+ */
+    ~HelixClass();
+/**
+ *   Initialization of helix using <br>
+ *     - position of the reference point : pos[3]; <br>
+ *     - momentum vector at the reference point : mom[3];<br>
+ *     - particle charge : q;<br>
+ *     - magnetic field (in Tesla) : B<br>
+ */  
+    void Initialize_VP(float * pos, float * mom, float q, float B);
+
+/**
+ *   Initialization of helix according to the following<br>
+ *   parameterization<br>
+ *   x = xCentre + radius*cos(bZ*z + phi0)<br>
+ *   y = yCentre + radius*sin(bZ*z + phi0)<br>
+ *     where (x,y,z) - position of point on the helix<br>
+ *     - (xCentre,yCentre) is the centre of circumference in R-Phi plane<br>
+ *     - radius is the radius of circumference<br>
+ *     - bZ is the helix slope parameter<br>
+ *     - phi0 is the initial phase of circumference<br>
+ *     - B is the magnetic field (in Tesla)<br>
+ *     - signPz is the sign of the z component of momentum vector<br>
+ *     - zBegin is the z coordinate of the reference point<br>
+ */  
+    void Initialize_BZ(float xCentre, float yCentre, float radius, 
+				   float bZ, float phi0, float B, float signPz,
+				   float zBegin);
+/**
+ *  Canonical (LEP-wise) parameterisation with the following parameters<br>
+ *     - phi0 - Phi angle of momentum vector at the point of<br>
+ *       closest approach to IP in R-Phi plane;
+ *     - d0 - signed distance of closest approach in R-Phi plane;<br>
+ *     - z0 - z coordinate of the point of closest approach to IP 
+ *       in R-Phi plane;<br>
+ *     - omega - signed curvature;<br>
+ *     - tanlambda - tangent of dip angle;<br>
+ *     - B - magnetic field (in Tesla)<br>
+ */  
+    void Initialize_Canonical(float phi0, float d0, float z0, float omega, 
+			      float tanlambda, float B);
+    /**
+     *  Returns momentum of particle at the point of closest approach <br>
+     *  to IP <br>
+     */
+    const float * getMomentum();
+
+    /**
+     *  Returns reference point of track <br>     
+     */
+    const float * getReferencePoint();
+
+    /**
+     *  Returns Phi angle of the momentum vector <br>
+     *  at the point of closest approach to IP <br>     
+     */
+    float getPhi0();
+
+    /**
+     *  Returns signed distance of closest approach <br>
+     *  to IP in the R-Phi plane <br>     
+     */
+    float getD0();
+
+    /**
+     *  Returns z coordinate of the point of closest 
+     *  approach to IP in the R-Phi plane <br>     
+     */
+    float getZ0();
+
+    /**
+     *  Returns signed curvature of the track <br>     
+     */
+    float getOmega();
+
+    /**
+     *  Returns tangent of dip angle of the track <br>     
+     */
+    float getTanLambda();
+
+    /**
+     *  Returns transverse momentum of the track <br>     
+     */
+    float getPXY();
+
+
+    /**
+     *  Returns x coordinate of circumference
+     */
+    float getXC();
+
+    /**
+     *  Returns y coordinate of circumference
+     */
+    float getYC();
+
+
+     /**
+     *  Returns radius of circumference
+     */
+    float getRadius();   
+
+
+    /**
+     *  Returns helix intersection point with the plane <br>
+     *  parallel to z axis. Plane is defined by two coordinates <br>
+     *  of the point belonging to the plane (x0,y0) and normal <br>
+     *  vector (ax,ay).  ref[3] is the reference point of the helix. <br>
+     *  point[3] - returned vector holding the coordinates of <br>
+     *  intersection point <br>     
+     */
+    float getPointInXY(float x0, float y0, float ax, float ay, 
+			      float * ref , float * point);
+
+    /**
+     *  Returns helix intersection point with the plane <br>
+     *  perpendicular to z axis. Plane is defined by z coordinate <br>
+     *  of the plane. ref[3] is the reference point of the helix. <br>
+     *  point[3] - returned vector holding the coordinates of <br>
+     *  intersection point <br>     
+     */
+    float getPointInZ(float zLine, float * ref, float * point);
+
+    /**
+     * Return distance of the closest approach of the helix to <br>
+     * arbitrary 3D point in space. xPoint[3] - coordinates of <br>
+     * space point. Distance[3] - vector of distances of helix to <br> 
+     * a given point in various projections : <br>
+     * Distance[0] - distance in R-Phi plane <br>
+     * Distance[1] - distance along Z axis <br>
+     * Distance[2] - 3D distance <br> 
+     */
+    float getDistanceToPoint(float * xPoint, float * Distance);
+
+    /**
+     * Return distance of the closest approach of the helix to <br>
+     * arbitrary 3D point in space. xPoint[3] - coordinates of <br>
+     * space point. distCut - limit on the distance between helix <br> 
+     * and the point to reduce calculation time <br>
+     * If R-Phi is found to be greater than distCut, rPhi distance is returned <br>
+     * If the R-Phi distance is not too big, than the exact 3D distance is returned <br>
+     * This function can be used, if the exact distance is not always needed <br>
+     */
+    float getDistanceToPoint(const float* xPoint, float distCut);
+    float getDistanceToPoint(const std::vector<float>& xPoint, float distCut);
+
+    /**
+     * This method calculates coordinates of both intersection <br>
+     * of the helix with a cylinder. <br>
+     * Rotational symmetry with respect to z axis is assumed,  <br>
+     * meaning that cylinder axis corresponds to the z axis <br>
+     * of reference frame. <br>
+     * Inputs : <br> 
+     * Radius - radius of cylinder. <br>
+     * ref[3] - point of closest approach to the origin of the helix. <br>
+     * Output : <br>
+     * point[6] - coordinates of intersection point. <br>
+     * Method returns also generic time, defined as the <br>
+     * ratio of helix length from reference point to the intersection <br>
+     * point to the particle momentum <br>
+     */
+    float getPointOnCircle(float Radius, float * ref, float * point);
+
+    /** Returns distance between two helixes <br>
+     * Output : <br> 
+     * pos[3] - position of the point of closest approach <br>
+     * mom[3] - momentum of V0 <br>
+     */
+    float getDistanceToHelix(HelixClass * helix, float * pos, float * mom);
+
+    /**
+     * Set Edges of helix 
+     */
+    void setHelixEdges(float * xStart, float * xEnd);
+
+    /**
+     * Returns starting point of helix
+     */
+    float * getStartingPoint() {return _xStart;}
+
+    /**
+     * Returns endpoint of helix
+     */
+    float * getEndPoint() {return _xEnd;}
+    
+    /**
+     * Returns BZ for the second parameterization
+     */
+    float getBz();
+
+    /**
+     * Returns Phi for the second parameterization
+     */
+    float getPhiZ();
+
+    /**
+     * Returns extrapolated momentum
+     */
+    void getExtrapolatedMomentum(float * pos, float * momentum);
+
+    /**
+     * Returns charge 
+     */
+    float getCharge();
+
+ private:    
+    float _momentum[3]; // momentum @ ref point 
+    float _referencePoint[3]; // coordinates @ ref point
+    float _phi0; // phi0 in canonical parameterization 
+    float _d0;   // d0 in canonical parameterisation
+    float _z0;   // z0 in canonical parameterisation
+    float _omega; // signed curvuture in canonical parameterisation
+    float _tanLambda; // TanLambda 
+    float _pxy; // Transverse momentum
+    float _charge; // Particle Charge
+    float _bField; // Magnetic field (assumed to point to Z>0)
+    float _radius; // radius of circle in XY plane
+    float _xCentre; // X of circle centre
+    float _yCentre; // Y of circle centre
+    float _phiRefPoint; // Phi w.r.t. (X0,Y0) of circle @ ref point
+    float _phiAtPCA; // Phi w.r.t. (X0,Y0) of circle @ PCA 
+    float _xAtPCA; // X @ PCA
+    float _yAtPCA; // Y @ PCA
+    float _pxAtPCA; // PX @ PCA
+    float _pyAtPCA; // PY @ PCA
+    float _phiMomRefPoint; // Phi of Momentum vector @ ref point
+    float _const_pi; // PI
+    float _const_2pi; // 2*PI
+    float _const_pi2; // PI/2    
+    float _FCT; // 2.99792458E-4
+    float _xStart[3]; // Starting point of track segment
+    float _xEnd[3]; // Ending point of track segment
+
+    float _bZ;
+    float _phiZ;
+
+};
+
+
+#endif
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.cc b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e23db1fa3f46982b8fff4a5ecb27a0264896f97d
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.cc
@@ -0,0 +1,73 @@
+#include "LineClass.h"
+#include <math.h> 
+
+/*
+ * Constructor
+ */
+
+LineClass::LineClass(float x0,
+		     float y0,
+		     float z0,
+		     float ax,
+		     float ay,
+		     float az) {
+  _x0[0] = x0;
+  _x0[1] = y0;
+  _x0[2] = z0;
+  _ax[0] = ax;
+  _ax[1] = ay;
+  _ax[2] = az;
+}
+
+LineClass::LineClass(float *x0,
+		     float *ax) {
+
+  for (int i=0; i<3; ++i) {
+    _x0[i] = x0[i];
+    _ax[i] = ax[i];
+  }
+}
+
+float * LineClass::getReferencePoint() {
+  return _x0;
+}
+
+float * LineClass::getDirectionalVector() {
+  return _ax;
+}
+
+void LineClass::setReferencePoint(float *x0) {
+  for (int i=0; i<3; ++i)
+    _x0[i] = x0[i];
+}
+ 
+void LineClass::setDirectionalVector(float *ax) {
+  for (int i=0; i<3; ++i)
+    _ax[i] = ax[i];
+ 
+}
+
+float LineClass::getDistanceToPoint(float * xpoint, float * pos) {
+  
+  float dif[3];
+  float prod = 0;
+  float den = 0;
+  for (int i=0; i<3; ++i) {
+    dif[i] = xpoint[i] - _x0[i];
+    prod += _ax[i]*dif[i];
+    den += _ax[i]*_ax[i];
+  }
+  float time = prod/fmax(1e-10,den);
+
+  float dist = 0.0;
+  for (int i=0; i<3; ++i) {
+    pos[i] = _x0[i] + _ax[i]*time;
+    dist += (xpoint[i]-pos[i])*(xpoint[i]-pos[i]);
+  }
+  dist = sqrt(dist);
+
+  return dist;
+
+
+
+}
diff --git a/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.h b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.h
new file mode 100644
index 0000000000000000000000000000000000000000..98970a263225b5a53ccfded69f33c92ae517d182
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MarlinUtil/01-08/source/LineClass.h
@@ -0,0 +1,32 @@
+#ifndef LINECLASS_H
+#define LINECLASS_H  
+class LineClass {
+
+  public:
+  LineClass(float x0,
+	    float y0,
+	    float z0,
+	    float ax,
+	    float ay,
+	    float az);
+
+  LineClass(float *x0,
+	    float *ax);
+  
+  ~LineClass();
+
+  float * getReferencePoint();
+  void setReferencePoint(float *x0);
+  float * getDirectionalVector();
+  void setDirectionalVector(float *ax);
+  float getDistanceToPoint(float * xpoint, float * pos);
+
+ private:
+
+  float _x0[3];
+  float _ax[3];
+
+
+};
+
+#endif
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/CMakeLists.txt b/Reconstruction/PFA/Pandora/MatrixPandora/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..73dc84e3d20f447bdf73fba3060bf1ae6e27c887
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/CMakeLists.txt
@@ -0,0 +1,60 @@
+gaudi_subdir(MatrixPandora v0r0)
+
+find_package(DD4hep COMPONENTS DDG4 REQUIRED)
+find_package(CLHEP REQUIRED)
+find_package(GSL REQUIRED )##don't use this,  use CEPC LCIO version one , due to the ClusterShape.cc file which is from LCIO
+message("GSL: ${GSL_LIBRARIES} ")
+set (gsl_include "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/include")
+set (gsl_lib1 "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/lib/libgsl.so")
+set (gsl_lib2 "/cvmfs/cepc.ihep.ac.cn/software/cepcsoft/x86_64-sl6-gcc49/external/GSL/1.14/install/lib/libgslcblas.so")
+find_package(LCIO REQUIRED ) 
+find_package(GEAR REQUIRED)
+#message("ENV GEAR: $ENV{GEAR}")
+find_package(EDM4HEP REQUIRED ) 
+#message("EDM4HEP_INCLUDE_DIRS: ${EDM4HEP_INCLUDE_DIR}")
+#message("EDM4HEP_LIB: ${EDM4HEP_LIBRARIES}")
+include_directories(${EDM4HEP_INCLUDE_DIR})
+
+find_package(PandoraSDK REQUIRED ) 
+#message("PandoraSDK_INCLUDE_DIRS: ${PandoraSDK_INCLUDE_DIRS}")
+#message("PandoraSDK_LIB:          ${PandoraSDK_LIBRARIES}")
+find_package(LCContent REQUIRED ) 
+#message("LCContent_INCLUDE_DIRS: ${LCContent_INCLUDE_DIRS}")
+#message("LCContent_LIB:          ${LCContent_LIBRARIES}")
+include_directories(${PandoraSDK_INCLUDE_DIRS})
+link_libraries(${PandoraSDK_LIBRARIES})
+include_directories(${LCContent_INCLUDE_DIRS})
+link_libraries(${LCContent_LIBRARIES})
+
+
+list(APPEND CMAKE_MODULE_PATH "$ENV{ROOTSYS}/etc/cmake/")
+find_package(ROOT 5.26.00 REQUIRED COMPONENTS Eve Geom RGL EG)
+
+include_directories("../CED/CED/")
+include_directories("../MarlinUtil/01-08/source/")
+
+gaudi_depends_on_subdirs(
+    Service/EventSeeder
+    Service/GearSvc
+    Detector/DetInterface
+)
+
+set(dir_srcs
+    src/PandoraMatrixAlg.cpp
+    src/MCParticleCreator.cpp
+    src/GeometryCreator.cpp
+    src/CaloHitCreator.cpp
+    src/TrackCreator.cpp
+    src/PfoCreator.cpp
+    ../CED/CED/*.cc
+    ../MarlinUtil/01-08/source/*.cc
+)
+set(dir_include include)
+# Modules
+gaudi_add_module(MatrixPandora ${dir_srcs}
+    INCLUDE_DIRS ${gsl_include} ${dir_include} GaudiKernel FWCore CLHEP  ${LCIO_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} gear DD4hep  
+    LINK_LIBRARIES ${gsl_lib1} ${gsl_lib2} GaudiKernel FWCore CLHEP ROOT ${LCIO_LIBRARIES} $ENV{GEAR}/lib/libgear.so $ENV{GEAR}/lib/libgearxml.so DD4hep ${DD4hep_COMPONENT_LIBRARIES} DDRec
+      -Wl,--no-as-needed 
+      EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+      -Wl,--as-needed 
+)
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/CaloHitCreator.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/CaloHitCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7714205c558c0df913d3f28b2198204aec59f58
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/CaloHitCreator.h
@@ -0,0 +1,298 @@
+/**
+ *  @file   MarlinPandora/include/CaloHitCreator.h
+ * 
+ *  @brief  Header file for the calo hit creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef CALO_HIT_CREATOR_H
+#define CALO_HIT_CREATOR_H 1
+
+#include "GaudiKernel/ISvcLocator.h"
+#include "edm4hep/CalorimeterHit.h"
+
+#include "gear/LayerLayout.h"
+
+#include "Api/PandoraApi.h"
+
+#include "DetInterface/IGeoSvc.h"
+#include "DD4hep/DD4hepUnits.h"
+#include "DD4hep/Detector.h"
+#include <DDRec/DetectorData.h>
+#include <DDRec/CellIDPositionConverter.h>
+#include "DD4hep/BitFieldCoder.h"
+
+
+#include <string>
+
+typedef std::vector<edm4hep::CalorimeterHit *> CalorimeterHitVector;
+
+namespace gear { class GearMgr; }
+
+class CollectionMaps;
+/**
+ *  @brief  CaloHitCreator class
+ */
+class CaloHitCreator
+{
+public:
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_eCalCaloHitCollections;               ///< The ecal calorimeter hit collections
+        StringVector    m_hCalCaloHitCollections;               ///< The hcal calorimeter hit collections
+        StringVector    m_lCalCaloHitCollections;               ///< The lcal calorimeter hit collections
+        StringVector    m_lHCalCaloHitCollections;              ///< The lhcal calorimeter hit collections
+        StringVector    m_muonCaloHitCollections;               ///< The muon calorimeter hit collections
+
+        float           m_absorberRadLengthECal;                ///< The absorber radiation length in the ECal
+        float           m_absorberIntLengthECal;                ///< The absorber interaction length in the ECal
+        float           m_absorberRadLengthHCal;                ///< The absorber radiation length in the HCal
+        float           m_absorberIntLengthHCal;                ///< The absorber interaction length in the HCal
+        float           m_absorberRadLengthOther;               ///< The absorber radiation length in other detector regions
+        float           m_absorberIntLengthOther;               ///< The absorber interaction length in other detector regions
+
+        float           m_eCalToMip;                            ///< The calibration from deposited ECal energy to mip
+        float           m_hCalToMip;                            ///< The calibration from deposited HCal energy to mip
+        float           m_muonToMip;                            ///< The calibration from deposited Muon energy to mip
+        float           m_eCalMipThreshold;                     ///< Threshold for creating calo hits in the ECal, units mip
+        float           m_hCalMipThreshold;                     ///< Threshold for creating calo hits in the HCal, units mip
+        float           m_muonMipThreshold;                     ///< Threshold for creating calo hits in the HCal, units mip
+
+        float           m_eCalToEMGeV;                          ///< The calibration from deposited ECal energy to EM energy
+        float           m_eCalToHadGeVBarrel;                   ///< The calibration from deposited ECal barrel energy to hadronic energy
+        float           m_eCalToHadGeVEndCap;                   ///< The calibration from deposited ECal endcap energy to hadronic energy
+        float           m_hCalToEMGeV;                          ///< The calibration from deposited HCal energy to EM energy
+        float           m_hCalToHadGeV;                         ///< The calibration from deposited HCal energy to hadronic energy
+        int             m_muonDigitalHits;                      ///< Muon hits are treated as digital (energy from hit count)
+        float           m_muonHitEnergy;                        ///< The energy for a digital muon calorimeter hit, units GeV
+
+        float           m_maxHCalHitHadronicEnergy;             ///< The maximum hadronic energy allowed for a single hcal hit
+        int             m_nOuterSamplingLayers;                 ///< Number of layers from edge for hit to be flagged as an outer layer hit
+        float           m_layersFromEdgeMaxRearDistance;        ///< Maximum number of layers from candidate outer layer hit to rear of detector
+
+        int             m_hCalEndCapInnerSymmetryOrder;         ///< HCal end cap inner symmetry order (missing from ILD00 gear file)
+        float           m_hCalEndCapInnerPhiCoordinate;         ///< HCal end cap inner phi coordinate (missing from ILD00 gear file)
+
+        // For Strip Splitting method and hybrid ECAL.
+        int             m_stripSplittingOn;                     ///< To use SSA, this should be true (default is false)
+        int             m_useEcalScLayers;                      ///< To use scintillator layers ~ hybrid ECAL, this should be true (default is false)
+        float           m_eCalSiToMip;                          ///< The calibration from deposited Si-layer energy to mip
+        float           m_eCalScToMip;                          ///< The calibration from deposited Sc-layer energy to mip
+        float           m_eCalSiMipThreshold;                   ///< Threshold for creating calo hits in the Si-layers of ECAL, units mip
+        float           m_eCalScMipThreshold;                   ///< Threshold for creating calo hits in the Sc-layers of ECAL, units mip
+        float           m_eCalSiToEMGeV;                        ///< The calibration from deposited Si-layer energy to EM energy
+        float           m_eCalScToEMGeV;                        ///< The calibration from deposited Sc-layer energy to EM energy
+        float           m_eCalSiToHadGeVBarrel;                 ///< The calibration from deposited Si-layer energy on the enecaps to hadronic energy
+        float           m_eCalScToHadGeVBarrel;                 ///< The calibration from deposited Sc-layer energy on the endcaps to hadronic energy
+        float           m_eCalSiToHadGeVEndCap;                 ///< The calibration from deposited Si-layer energy on the enecaps to hadronic energy
+        float           m_eCalScToHadGeVEndCap;                 ///< The calibration from deposited Sc-layer energy on the endcaps to hadronic energy
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     CaloHitCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc, bool encoder_style);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~CaloHitCreator();
+
+    /**
+     *  @brief  Create calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */    
+    //pandora::StatusCode CreateCaloHits(const LCEvent *const pLCEvent);
+    pandora::StatusCode CreateCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get the calorimeter hit vector
+     * 
+     *  @return The calorimeter hit vector
+     */
+    const CalorimeterHitVector &GetCalorimeterHitVector() const;
+
+    /**
+     *  @brief  Reset the calo hit creator
+     */
+    void Reset();
+
+private:
+    /**
+     *  @brief  Create ecal calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode CreateECalCaloHits(const EVENT::LCEvent *const pLCEvent);
+    pandora::StatusCode CreateECalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create hcal calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    pandora::StatusCode CreateHCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create muon calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    pandora::StatusCode CreateMuonCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create lcal calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */    
+    pandora::StatusCode CreateLCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create lhcal calo hits
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    pandora::StatusCode CreateLHCalCaloHits(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get common calo hit properties: position, parent address, input energy and time
+     * 
+     *  @param  pCaloHit the lcio calorimeter hit
+     *  @param  caloHitParameters the calo hit parameters to populate
+     */
+    void GetCommonCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, PandoraApi::CaloHit::Parameters &caloHitParameters) const;
+
+    /**
+     *  @brief  Get end cap specific calo hit properties: cell size, absorber radiation and interaction lengths, normal vector
+     * 
+     *  @param  pCaloHit the lcio calorimeter hit
+     *  @param  layerLayout the gear end cap layer layout
+     *  @param  caloHitParameters the calo hit parameters to populate
+     *  @param  absorberCorrection to receive the absorber thickness correction for the mip equivalent energy
+     */
+    void GetEndCapCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+        PandoraApi::CaloHit::Parameters &caloHitParameters, float &absorberCorrection) const;
+
+    /**
+     *  @brief  Get barrel specific calo hit properties: cell size, absorber radiation and interaction lengths, normal vector
+     * 
+     *  @param  pCaloHit the lcio calorimeter hit
+     *  @param  layerLayout the gear barrel layer layout
+     *  @param  barrelSymmetryOrder the barrel order of symmetry
+     *  @param  barrelPhi0 the barrel orientation
+     *  @param  staveNumber the stave number
+     *  @param  caloHitParameters the calo hit parameters to populate
+     *  @param  absorberCorrection to receive the absorber thickness correction for the mip equivalent energy
+     */
+    void GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+        unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+        float &absorberCorrection) const;
+
+    void GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer> &layerLayout,
+        unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+        float &absorberCorrection) const;
+    /**
+     *  @brief  Get number of active layers from position of a calo hit to the edge of the detector
+     * 
+     *  @param  pCaloHit the lcio calorimeter hit
+     */
+    int GetNLayersFromEdge(const edm4hep::CalorimeterHit *const pCaloHit) const;
+
+    /**
+     *  @brief  Get the maximum radius of a calo hit in a polygonal detector structure
+     * 
+     *  @param  pCaloHit the lcio calorimeter hit
+     *  @param  symmetryOrder the symmetry order
+     *  @param  phi0 the angular orientation
+     * 
+     *  @return the maximum radius
+     */
+    float GetMaximumRadius(const edm4hep::CalorimeterHit *const pCaloHit, const unsigned int symmetryOrder, const float phi0) const;
+
+    void GetCoding(const edm4hep::CalorimeterHit* pCaloHit, long& sys, long& x, long& y, long& z) const ;
+    int GetBarrelLayer(const edm4hep::CalorimeterHit *const pCaloHit, const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer> &layerLayout) const;
+    /**
+     *  @brief  Get the layer coding string from the provided cell id encoding string
+     * 
+     *  @param  encodingString the cell id encoding string
+     * 
+     *  @return the layer coding string
+     */
+    std::string GetLayerCoding(const std::string &encodingString) const;
+
+    /**
+     *  @brief  Get the stave coding string from the provided cell id encoding string
+     * 
+     *  @param  encodingString the cell id encoding string
+     * 
+     *  @return the stave coding string
+     */
+    std::string GetStaveCoding(const std::string &encodingString) const;
+
+    const Settings                      m_settings;                         ///< The calo hit creator settings
+
+    const pandora::Pandora             *m_pPandora;                         ///< Address of the pandora object to create calo hits
+
+    float                               m_eCalBarrelOuterZ;                 ///< ECal barrel outer z coordinate
+    float                               m_hCalBarrelOuterZ;                 ///< HCal barrel outer z coordinate
+    float                               m_muonBarrelOuterZ;                 ///< Muon barrel outer z coordinate
+    float                               m_coilOuterR;                       ///< Coil outer r coordinate
+
+    float                               m_eCalBarrelInnerPhi0;              ///< ECal barrel inner phi0 coordinate
+    unsigned int                        m_eCalBarrelInnerSymmetry;          ///< ECal barrel inner symmetry order
+    float                               m_hCalBarrelInnerPhi0;              ///< HCal barrel inner phi0 coordinate
+    unsigned int                        m_hCalBarrelInnerSymmetry;          ///< HCal barrel inner symmetry order
+    float                               m_muonBarrelInnerPhi0;              ///< Muon barrel inner phi0 coordinate
+    unsigned int                        m_muonBarrelInnerSymmetry;          ///< Muon barrel inner symmetry order
+
+    float                               m_hCalEndCapOuterR;                 ///< HCal endcap outer r coordinate
+    float                               m_hCalEndCapOuterZ;                 ///< HCal endcap outer z coordinate
+    float                               m_hCalBarrelOuterR;                 ///< HCal barrel outer r coordinate
+    float                               m_hCalBarrelOuterPhi0;              ///< HCal barrel outer phi0 coordinate
+    unsigned int                        m_hCalBarrelOuterSymmetry;          ///< HCal barrel outer symmetry order
+
+    float                               m_hCalBarrelLayerThickness;         ///< HCal barrel layer thickness
+    float                               m_hCalEndCapLayerThickness;         ///< HCal endcap layer thickness
+
+    CalorimeterHitVector                m_calorimeterHitVector;             ///< The calorimeter hit vector
+    std::string                         m_encoder_str;
+    std::string                         m_encoder_str_MUON ; 
+    std::string                         m_encoder_str_LCal ; 
+    std::string                         m_encoder_str_LHCal; 
+    gear::GearMgr* _GEAR;
+    dd4hep::Detector* m_dd4hep;
+    dd4hep::rec::CellIDPositionConverter* m_cellIDConverter;
+    std::string                         m_compact ;
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline const CalorimeterHitVector &CaloHitCreator::GetCalorimeterHitVector() const
+{
+    return m_calorimeterHitVector;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline void CaloHitCreator::Reset()
+{
+    m_calorimeterHitVector.clear();
+}
+
+#endif // #ifndef CALO_HIT_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/GeometryCreator.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/GeometryCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..0a0c1ae2d6953e7d1b066e4107fda52c55396ff1
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/GeometryCreator.h
@@ -0,0 +1,166 @@
+/**
+ *  @file   MarlinPandora/include/GeometryCreator.h
+ * 
+ *  @brief  Header file for the geometry creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef GEOMETRY_CREATOR_H
+#define GEOMETRY_CREATOR_H 1
+
+#include "Api/PandoraApi.h"
+
+#include "GaudiKernel/ISvcLocator.h"
+
+#include "DetInterface/IGeoSvc.h"
+#include "DD4hep/DD4hepUnits.h"
+#include "DD4hep/Detector.h"
+
+namespace gear { class CalorimeterParameters; class GearMgr; }
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  GeometryCreator class
+ */
+class GeometryCreator
+{
+public:
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        float           m_absorberRadLengthECal;                ///< The absorber radiation length in the ECal
+        float           m_absorberIntLengthECal;                ///< The absorber interaction length in the ECal
+        float           m_absorberRadLengthHCal;                ///< The absorber radiation length in the HCal
+        float           m_absorberIntLengthHCal;                ///< The absorber interaction length in the HCal
+        float           m_absorberRadLengthOther;               ///< The absorber radiation length in other detector regions
+        float           m_absorberIntLengthOther;               ///< The absorber interaction length in other detector regions
+
+        int             m_eCalEndCapInnerSymmetryOrder;         ///< ECal end cap inner symmetry order (missing from ILD gear files)
+        float           m_eCalEndCapInnerPhiCoordinate;         ///< ECal end cap inner phi coordinate (missing from ILD gear files)
+        int             m_eCalEndCapOuterSymmetryOrder;         ///< ECal end cap outer symmetry order (missing from ILD gear files)
+        float           m_eCalEndCapOuterPhiCoordinate;         ///< ECal end cap outer phi coordinate (missing from ILD gear files)
+
+        int             m_hCalEndCapInnerSymmetryOrder;         ///< HCal end cap inner symmetry order (missing from ILD gear files)
+        float           m_hCalEndCapInnerPhiCoordinate;         ///< HCal end cap inner phi coordinate (missing from ILD gear files)
+        int             m_hCalEndCapOuterSymmetryOrder;         ///< HCal end cap outer symmetry order (missing from ILD gear files)
+        float           m_hCalEndCapOuterPhiCoordinate;         ///< HCal end cap outer phi coordinate (missing from ILD gear files)
+
+        int             m_hCalRingInnerSymmetryOrder;           ///< HCal ring inner symmetry order (missing from ILD gear files)
+        float           m_hCalRingInnerPhiCoordinate;           ///< HCal ring inner phi coordinate (missing from ILD gear files)
+        int             m_hCalRingOuterSymmetryOrder;           ///< HCal ring outer symmetry order (missing from ILD gear files)
+        float           m_hCalRingOuterPhiCoordinate;           ///< HCal ring outer phi coordinate (missing from ILD gear files)
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     GeometryCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~GeometryCreator();
+
+    /**
+     *  @brief  Create geometry
+     */
+    //pandora::StatusCode CreateGeometry() const;
+    pandora::StatusCode CreateGeometry(ISvcLocator* svcloc);
+
+private:
+    typedef std::map<pandora::SubDetectorType, PandoraApi::Geometry::SubDetector::Parameters> SubDetectorTypeMap;
+    typedef std::map<std::string, PandoraApi::Geometry::SubDetector::Parameters> SubDetectorNameMap;
+
+    /**
+     *  @brief  Set mandatory sub detector parameters
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     */
+    void SetMandatorySubDetectorParameters(SubDetectorTypeMap &subDetectorTypeMap) const;
+
+    /**
+     *  @brief  Set additional sub detector parameters
+     * 
+     *  @param  subDetectorNameMap the sub detector name map (for smaller sub detectors, identified uniquely only by name)
+     */
+    void SetAdditionalSubDetectorParameters(SubDetectorNameMap &subDetectorNameMap) const;
+
+    /**
+     *  @brief  Set sub detector parameters to their gear default values
+     * 
+     *  @param  inputParameters input parameters, from gear
+     *  @param  subDetectorName the sub detector name
+     *  @param  subDetectorType the sub detector type
+     *  @param  parameters the sub detector parameters
+     */
+    void SetDefaultSubDetectorParameters(const gear::CalorimeterParameters &inputParameters, const std::string &subDetectorName,
+        const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const;
+
+    void SetDefaultSubDetectorParameters(const dd4hep::Detector* theDetector, const std::string &subDetectorName,
+        const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const;
+
+    /**
+     *  @brief  Set positions of gaps in ILD detector and add information missing from GEAR parameters file
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     *  @param  subDetectorNameMap the sub detector name map (for smaller sub detectors, identified uniquely only by name)
+     */
+    pandora::StatusCode SetILDSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap, SubDetectorNameMap &subDetectorNameMap) const;
+
+    /**
+     *  @brief  Add information missing from GEAR parameters file for ILD SDHCAL detector
+     * 
+     *  @param  subDetectorTypeMap the sub detector type map
+     */
+    pandora::StatusCode SetILD_SDHCALSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap) const;
+
+    /**
+     *  @brief  Specify positions of hcal barrel box gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalBarrelBoxGaps() const;
+
+    /**
+     *  @brief  Specify positions of hcal end cap box gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalEndCapBoxGaps() const;
+
+    /**
+     *  @brief  Specify positions of hcal barrel concentric polygon gaps - ILD specific
+     */
+    pandora::StatusCode CreateHCalBarrelConcentricGaps() const;
+
+    /**
+     *  @brief  Create box gaps at regular positions on polygonal prism, oriented along main z axis - ILD specific
+     * 
+     *  @param  symmetryOrder the pandora geometry parameters
+     *  @param  phi0 the phi coordinate
+     *  @param  innerRadius the inner r coordinate
+     *  @param  outerRadius the outer r coordinate
+     *  @param  minZ the minimum z coordinate
+     *  @param  maxZ the maximum z coordinate
+     *  @param  gapWidth the gap width
+     *  @param  vertexOffset position offset for vertex that doesn't point back to origin of xy plane
+     */
+    pandora::StatusCode CreateRegularBoxGaps(unsigned int symmetryOrder, float phi0, float innerRadius, float outerRadius, float minZ,
+        float maxZ, float gapWidth, pandora::CartesianVector vertexOffset = pandora::CartesianVector(0, 0, 0)) const;
+
+    const Settings          m_settings;                     ///< The geometry creator settings
+    const pandora::Pandora *m_pPandora;                     ///< Address of the pandora object to create the geometry
+    gear::GearMgr* _GEAR;
+    dd4hep::Detector* m_dd4hep;
+};
+
+#endif // #ifndef GEOMETRY_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/MCParticleCreator.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/MCParticleCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..4ad9f27553b03b7c795d6fc457fa6ecddaa46463
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/MCParticleCreator.h
@@ -0,0 +1,98 @@
+/**
+ *  @file   MarlinPandora/include/MCParticleCreator.h
+ * 
+ *  @brief  Header file for the mc particle creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef MC_PARTICLE_CREATOR_H
+#define MC_PARTICLE_CREATOR_H 1
+
+#include "edm4hep/MCParticle.h"
+#include "Api/PandoraApi.h"
+
+#include "CaloHitCreator.h"
+#include "TrackCreator.h"
+/**
+ *  @brief  MCParticleCreator class
+ */
+
+class CollectionMaps;
+
+class MCParticleCreator
+{
+public:
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_mcParticleCollections;                ///< The mc particle collections
+        StringVector    m_CaloHitRelationCollections;         ///< The SimCaloHit to CaloHit particle relations
+        StringVector    m_TrackRelationCollections;           ///< The SimTrackerHit to TrackerHit particle relations
+        float           m_bField;                             ///< m_bField
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     MCParticleCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~MCParticleCreator();
+
+    /**
+     *  @brief  Create MCParticles
+     * 
+     *  @param  pLCEvent the lcio event
+     */    
+    //pandora::StatusCode CreateMCParticles(const EVENT::LCEvent *const pLCEvent) const;
+    //pandora::StatusCode CreateMCParticles(const std::map<std::string, const podio::CollectionBase*>& collectionMap ) const;
+    pandora::StatusCode CreateMCParticles(const CollectionMaps& collectionMaps ) const;
+
+    /**
+     *  @brief  Create Track to mc particle relationships
+     *
+     *  @param  pLCEvent the lcio event
+     *  @param  trackVector the vector containing all tracks successfully passed to pandora
+     */
+ //   pandora::StatusCode CreateTrackToMCParticleRelationships(const EVENT::LCEvent *const pLCEvent, const TrackVector &trackVector) const;
+     pandora::StatusCode CreateTrackToMCParticleRelationships(const CollectionMaps& collectionMaps, const TrackVector &trackVector) const;
+
+     void Reset();
+    /**
+     *  @brief  Create calo hit to mc particle relationships
+     *
+     *  @param  pLCEvent the lcio event
+     *  @param  calorimeterHitVector the vector containing all calorimeter hits successfully passed to pandora
+     */
+//    pandora::StatusCode CreateCaloHitToMCParticleRelationships(const EVENT::LCEvent *const pLCEvent, const CalorimeterHitVector &calorimeterHitVector) const;
+      pandora::StatusCode CreateCaloHitToMCParticleRelationships(const CollectionMaps& collectionMaps, const CalorimeterHitVector &calorimeterHitVector) const;
+
+private:
+    const Settings          m_settings;                         ///< The mc particle creator settings
+    const pandora::Pandora *m_pPandora;                         ///< Address of the pandora object to create the mc particles
+    const float             m_bField;                           ///< The bfield
+    std::map<unsigned int, const edm4hep::MCParticle*>*  m_id_pMC_map;
+};
+
+inline void MCParticleCreator::Reset()
+{
+    m_id_pMC_map->clear();
+}
+
+#endif // #ifndef MC_PARTICLE_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/PandoraMatrixAlg.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/PandoraMatrixAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..63210760fdcfe3b7b4e08697ce340639dee6edf3
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/PandoraMatrixAlg.h
@@ -0,0 +1,327 @@
+#ifndef PandoraMatrixAlg_H
+#define PandoraMatrixAlg_H
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+#include <gsl/gsl_rng.h>
+#include "edm4hep/ClusterCollection.h"
+#include "edm4hep/ReconstructedParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/SimTrackerHitCollection.h"
+#include "edm4hep/TrackerHitCollection.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/VertexCollection.h"
+#include "edm4hep/TrackCollection.h"
+#include "edm4hep/MCParticle.h" 
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/MCRecoCaloAssociation.h"
+#include "edm4hep/MCRecoTrackerAssociation.h"
+#include "edm4hep/MCRecoTrackerAssociationCollection.h"
+#include "edm4hep/MCRecoCaloAssociationCollection.h"
+#include "edm4hep/MCRecoParticleAssociation.h"
+#include "edm4hep/MCRecoParticleAssociationCollection.h"
+
+#include "Api/PandoraApi.h"
+
+#ifdef MONITORING
+#include "TApplication.h"
+#endif
+
+#include <iostream>
+#include <random>
+#include <string>
+#include <unistd.h>
+
+
+#include "CaloHitCreator.h"
+#include "GeometryCreator.h"
+#include "MCParticleCreator.h"
+#include "PfoCreator.h"
+#include "TrackCreator.h"
+
+#include "TROOT.h"
+#include "TTree.h"
+#include "TFile.h"
+
+
+/* PandoraMatrixAlg ========== <br>
+ * 
+ */
+namespace pandora {class Pandora;}
+
+class IEventSeeder;
+
+class CollectionMaps
+{
+public:
+    /**
+     *  @brief  Default constructor
+     */
+    CollectionMaps();
+    void clear();
+    std::map<std::string, const edm4hep::MCParticleCollection*> CollectionMap_MC;
+    std::map<std::string, const edm4hep::CalorimeterHitCollection*> CollectionMap_CaloHit;
+    std::map<std::string, const edm4hep::VertexCollection*> CollectionMap_Vertex;
+    std::map<std::string, const edm4hep::TrackCollection*> CollectionMap_Track;
+
+    std::map<std::string, std::vector<edm4hep::MCParticle> >     collectionMap_MC;
+    std::map<std::string, std::vector<edm4hep::CalorimeterHit> > collectionMap_CaloHit;
+    std::map<std::string, std::vector<edm4hep::Vertex> >         collectionMap_Vertex;
+    std::map<std::string, std::vector<edm4hep::Track> >          collectionMap_Track;
+    std::map<std::string, std::vector<edm4hep::MCRecoCaloAssociation> > collectionMap_CaloRel;
+    std::map<std::string, std::vector<edm4hep::MCRecoTrackerAssociation> > collectionMap_TrkRel;
+};
+
+
+
+class PandoraMatrixAlg : public GaudiAlgorithm
+{
+  //friend class AlgFactory<PandoraMatrixAlg>;//gives error in 97 version
+ 
+public:
+ 
+  PandoraMatrixAlg(const std::string& name, ISvcLocator* svcLoc);
+ 
+  /** Called at the begin of the job before anything is read.
+   * Use to initialize the processor, e.g. book histograms.
+   */
+  virtual StatusCode initialize() ;
+ 
+  /** Called for every event - the working horse.
+   */
+  virtual StatusCode execute() ; 
+ 
+  /** Called after data processing for clean up.
+   */
+  virtual StatusCode finalize() ;
+ 
+  //void FinaliseSteeringParameters();
+  void FinaliseSteeringParameters(ISvcLocator* svcloc);
+  pandora::StatusCode RegisterUserComponents() const;
+  void Reset();
+  typedef std::vector<float> FloatVector;
+  typedef std::vector<std::string> StringVector;
+
+
+  class Settings
+  {
+  public:
+      /**
+       *  @brief  Default constructor
+       */
+      Settings();
+
+      std::string     m_pandoraSettingsXmlFile;           ///< The pandora settings xml file
+
+      float           m_innerBField;                      ///< The bfield in the main tracker, ecal and hcal, units Tesla
+      float           m_muonBarrelBField;                 ///< The bfield in the muon barrel, units Tesla
+      float           m_muonEndCapBField;                 ///< The bfield in the muon endcap, units Tesla
+
+      FloatVector     m_inputEnergyCorrectionPoints;      ///< The input energy points for non-linearity energy correction
+      FloatVector     m_outputEnergyCorrectionPoints;     ///< The output energy points for non-linearity energy correction
+  };
+
+
+    /**
+     *  @brief  Get address of the pandora instance
+     * 
+     *  @return address of the pandora instance
+     */
+    const pandora::Pandora *GetPandora() const;
+    StatusCode updateMap();
+    StatusCode updateMap(CollectionMaps & tmp_map);
+    StatusCode Ana();
+    StatusCode CreateMCRecoParticleAssociation();
+    //StatusCode Create_MC(); 
+protected:
+ 
+  typedef std::vector<float> FloatVec;
+
+  int _nEvt ;
+
+  IEventSeeder * _SEEDER;
+ 
+
+  Gaudi::Property< std::string >              m_PandoraSettingsXmlFile { this, "PandoraSettingsDefault_xml", "/junofs/users/wxfang/MyGit/MarlinPandora/scripts/PandoraSettingsDefault_wx.xml" };
+  Gaudi::Property<int>                        m_NEventsToSkip                   { this, "NEventsToSkip", 0 };
+
+  Gaudi::Property< std::vector<std::string> > m_TrackCollections{ this, "TrackCollections", {"MarlinTrkTracks"} };
+  Gaudi::Property< std::vector<std::string> > m_ECalCaloHitCollections{ this, "ECalCaloHitCollections", {"ECALBarrel","ECALEndcap","ECALOther"} };
+  Gaudi::Property< std::vector<std::string> > m_HCalCaloHitCollections{ this, "HCalCaloHitCollections", {"HCALBarrel","HCALEndcap","HCALOther"} };
+  Gaudi::Property< std::vector<std::string> > m_LCalCaloHitCollections{ this, "LCalCaloHitCollections", {"LCAL"} };
+  Gaudi::Property< std::vector<std::string> > m_LHCalCaloHitCollections{ this, "LHCalCaloHitCollections", {"LHCAL"} };
+  Gaudi::Property< std::vector<std::string> > m_MuonCaloHitCollections{ this, "MuonCaloHitCollections", {"MUON"} };
+  Gaudi::Property< std::vector<std::string> > m_MCParticleCollections{ this, "MCParticleCollections", {"MCParticle"} };
+  Gaudi::Property< std::vector<std::string> > m_RelCaloHitCollections{ this, "RelCaloHitCollections", {"RelationCaloHit","RelationMuonHit"} };
+  Gaudi::Property< std::vector<std::string> > m_RelTrackCollections{ this, "RelTrackCollections", {"MarlinTrkTracksMCTruthLink"} };
+  Gaudi::Property< std::vector<std::string> > m_KinkVertexCollections{ this, "KinkVertexCollections", {"KinkVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_ProngVertexCollections{ this, "ProngVertexCollections", {"ProngVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_SplitVertexCollections{ this, "SplitVertexCollections", {"SplitVertices"} };
+  Gaudi::Property< std::vector<std::string> > m_V0VertexCollections{ this, "V0VertexCollections", {"V0Vertices"} };
+  Gaudi::Property< std::string >              m_ClusterCollectionName { this, "ClusterCollectionName", "PandoraClusters" };
+  Gaudi::Property< std::string >              m_PFOCollectionName { this, "PFOCollectionName", "PandoraPFOs" };
+  Gaudi::Property<float>                      m_ECalToMipCalibration{ this, "ECalToMipCalibration", 160.0 };
+  Gaudi::Property<float>                      m_HCalToMipCalibration{ this, "HCalToMipCalibration", 34.8 };
+  Gaudi::Property<float>                      m_ECalMipThreshold{ this, "ECalMipThreshold", 0.5 };
+  Gaudi::Property<float>                      m_HCalMipThreshold{ this, "HCalMipThreshold", 0.3 };
+  Gaudi::Property<float>                      m_ECalToEMGeVCalibration{ this, "ECalToEMGeVCalibration", 1.007 };
+  Gaudi::Property<float>                      m_HCalToEMGeVCalibration{ this, "HCalToEMGeVCalibration", 1.007 };
+  Gaudi::Property<float>                      m_ECalToHadGeVCalibrationBarrel{ this, "ECalToHadGeVCalibrationBarrel", 1.12 };
+  Gaudi::Property<float>                      m_ECalToHadGeVCalibrationEndCap{ this, "ECalToHadGeVCalibrationEndCap", 1.12 };
+  Gaudi::Property<float>                      m_HCalToHadGeVCalibration{ this, "HCalToHadGeVCalibration", 1.07 };
+  Gaudi::Property<float>                      m_MuonToMipCalibration{ this, "MuonToMipCalibration", 10.0 };
+  Gaudi::Property<int>                        m_DigitalMuonHits{ this, "DigitalMuonHits", 0 };
+  Gaudi::Property<float>                      m_MaxHCalHitHadronicEnergy{ this, "MaxHCalHitHadronicEnergy", 1.0 };
+  Gaudi::Property<int>                        m_UseOldTrackStateCalculation{ this, "UseOldTrackStateCalculation", 0 };
+
+
+  Gaudi::Property<float>                      m_AbsorberRadLengthECal{ this, "AbsorberRadLengthECal", 0.2854 };
+  Gaudi::Property<float>                      m_AbsorberIntLengthECal{ this, "AbsorberIntLengthECal", 0.0101 };
+  Gaudi::Property<float>                      m_AbsorberRadLengthHCal{ this, "AbsorberRadLengthHCal", 0.0569 };
+  Gaudi::Property<float>                      m_AbsorberIntLengthHCal{ this, "AbsorberIntLengthHCal", 0.006  };
+  Gaudi::Property<float>                      m_AbsorberRadLengthOther{ this, "AbsorberRadLengthOther", 0.0569  };
+  Gaudi::Property<float>                      m_AbsorberIntLengthOther{ this, "AbsorberIntLengthOther", 0.006  };
+  Gaudi::Property< std::string >              m_StartVertexCollectionName { this, "StartVertexCollectionName", "PandoraPFANewStartVertices" };
+  Gaudi::Property< std::string >              m_StartVertexAlgorithmName { this, "StartVertexAlgorithmName", "PandoraPFANew" };
+  Gaudi::Property<float>                      m_EMStochasticTerm{ this, "EMStochasticTerm", 0.17  };
+  Gaudi::Property<float>                      m_HadStochasticTerm{ this, "HadStochasticTerm", 0.6  };
+  Gaudi::Property<float>                      m_EMConstantTerm{ this, "EMConstantTerm", 0.01  };
+  Gaudi::Property<float>                      m_HadConstantTerm{ this, "HadConstantTerm", 0.03  };
+  Gaudi::Property<float>                      m_MuonHitEnergy{ this, "MuonHitEnergy", 0.5 };
+  Gaudi::Property<int>                        m_NOuterSamplingLayers{ this, "NOuterSamplingLayers", 3 };
+  Gaudi::Property<float>                      m_LayersFromEdgeMaxRearDistance{ this, "LayersFromEdgeMaxRearDistance", 250.f };
+  Gaudi::Property<float>                      m_MuonBarrelBField{ this, "MuonBarrelBField", -1.5f };
+  Gaudi::Property<float>                      m_MuonEndCapBField{ this, "MuonEndCapBField", 0.01f };
+  Gaudi::Property<int>                        m_ShouldFormTrackRelationships{ this, "ShouldFormTrackRelationships", 1 };
+  Gaudi::Property<int>                        m_MinTrackHits{ this, "MinTrackHits", 5 };
+  Gaudi::Property<int>                        m_MinFtdTrackHits{ this, "MinFtdTrackHits", 0 };
+  Gaudi::Property<int>                        m_MaxTrackHits{ this, "MaxTrackHits", 5000 };
+  Gaudi::Property<float>                      m_D0TrackCut{ this, "D0TrackCut", 50. };
+  Gaudi::Property<float>                      m_Z0TrackCut{ this, "Z0TrackCut", 50. };
+  Gaudi::Property<int>                        m_UseNonVertexTracks{ this, "UseNonVertexTracks", 1 };
+  Gaudi::Property<int>                        m_UseUnmatchedNonVertexTracks{ this, "UseUnmatchedNonVertexTracks", 0 };
+  Gaudi::Property<int>                        m_UseUnmatchedVertexTracks{ this, "UseUnmatchedVertexTracks", 1 };
+  Gaudi::Property<float>                      m_UnmatchedVertexTrackMaxEnergy{ this, "UnmatchedVertexTrackMaxEnergy", 5. };
+  Gaudi::Property<float>                      m_D0UnmatchedVertexTrackCut{ this, "D0UnmatchedVertexTrackCut", 5. };
+  Gaudi::Property<float>                      m_Z0UnmatchedVertexTrackCut{ this, "Z0UnmatchedVertexTrackCut", 5. };
+  Gaudi::Property<float>                      m_ZCutForNonVertexTracks{ this, "ZCutForNonVertexTracks", 250. };
+  Gaudi::Property<int>                        m_ReachesECalNTpcHits{ this, "ReachesECalNTpcHits", 11 };
+  Gaudi::Property<int>                        m_ReachesECalNFtdHits{ this, "ReachesECalNFtdHits", 4 };
+  Gaudi::Property<float>                      m_ReachesECalTpcOuterDistance{ this, "ReachesECalTpcOuterDistance", -100. };
+  Gaudi::Property<int>                        m_ReachesECalMinFtdLayer{ this, "ReachesECalMinFtdLayer", 9 };
+  Gaudi::Property<float>                      m_ReachesECalTpcZMaxDistance{ this, "ReachesECalTpcZMaxDistance", -50. };
+  Gaudi::Property<float>                      m_ReachesECalFtdZMaxDistance{ this, "ReachesECalFtdZMaxDistance", -1. };
+  Gaudi::Property<float>                      m_CurvatureToMomentumFactor{ this, "CurvatureToMomentumFactor", 0.3 / 2000. };
+  Gaudi::Property<float>                      m_MinTrackECalDistanceFromIp{ this, "MinTrackECalDistanceFromIp", 100. };
+
+  Gaudi::Property<float>                      m_MaxTrackSigmaPOverP             { this, "MaxTrackSigmaPOverP", 0.15 };
+  Gaudi::Property<float>                      m_MinMomentumForTrackHitChecks    { this, "MinMomentumForTrackHitChecks", 1. };
+  Gaudi::Property<float>                      m_TpcMembraneMaxZ                 { this, "TpcMembraneMaxZ", 10. };
+  Gaudi::Property<float>                      m_MinTpcHitFractionOfExpected     { this, "MinTpcHitFractionOfExpected", 0.20 };
+  Gaudi::Property<int>                        m_MinFtdHitsForTpcHitFraction     { this, "MinFtdHitsForTpcHitFraction", 2 };
+  Gaudi::Property<float>                      m_MaxTpcInnerRDistance            { this, "MaxTpcInnerRDistance", 50.0 };
+  Gaudi::Property<int>                        m_ECalEndCapInnerSymmetryOrder    { this, "ECalEndCapInnerSymmetryOrder", 4 };
+  Gaudi::Property<float>                      m_ECalEndCapInnerPhiCoordinate    { this, "ECalEndCapInnerPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_ECalEndCapOuterSymmetryOrder    { this, "ECalEndCapOuterSymmetryOrder", 8 };
+  Gaudi::Property<float>                      m_ECalEndCapOuterPhiCoordinate    { this, "ECalEndCapOuterPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalEndCapInnerSymmetryOrder    { this, "HCalEndCapInnerSymmetryOrder", 4 };
+  Gaudi::Property<float>                      m_HCalEndCapInnerPhiCoordinate    { this, "HCalEndCapInnerPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalEndCapOuterSymmetryOrder    { this, "HCalEndCapOuterSymmetryOrder", 16 };
+  Gaudi::Property<float>                      m_HCalEndCapOuterPhiCoordinate    { this, "HCalEndCapOuterPhiCoordinate", 0. };
+  Gaudi::Property<int>                        m_HCalRingInnerSymmetryOrder      { this, "HCalRingInnerSymmetryOrder",   8  };
+  Gaudi::Property<float>                      m_HCalRingInnerPhiCoordinate      { this, "HCalRingInnerPhiCoordinate",   0. };
+  Gaudi::Property<int>                        m_HCalRingOuterSymmetryOrder      { this, "HCalRingOuterSymmetryOrder",   16 };
+  Gaudi::Property<float>                      m_HCalRingOuterPhiCoordinate      { this, "HCalRingOuterPhiCoordinate",   0. };
+  Gaudi::Property<bool>                       m_StripSplittingOn                { this, "StripSplittingOn", false };
+  Gaudi::Property<bool>                       m_UseEcalScLayers                 { this, "UseEcalScLayers", false };
+  Gaudi::Property<float>                      m_ECalSiToMipCalibration          { this, "ECalSiToMipCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalScToMipCalibration          { this, "ECalScToMipCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalSiMipThreshold              { this, "ECalSiMipThreshold", 0. };
+  Gaudi::Property<float>                      m_ECalScMipThreshold              { this, "ECalScMipThreshold", 0. };
+  Gaudi::Property<float>                      m_ECalSiToEMGeVCalibration        { this, "ECalSiToEMGeVCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalScToEMGeVCalibration        { this, "ECalScToEMGeVCalibration", 1. };
+  Gaudi::Property<float>                      m_ECalSiToHadGeVCalibrationEndCap { this, "ECalSiToHadGeVCalibrationEndCap", 1. };
+  Gaudi::Property<float>                      m_ECalScToHadGeVCalibrationEndCap { this, "ECalScToHadGeVCalibrationEndCap", 1. };
+  Gaudi::Property<float>                      m_ECalSiToHadGeVCalibrationBarrel { this, "ECalSiToHadGeVCalibrationBarrel", 1. };
+  Gaudi::Property<float>                      m_ECalScToHadGeVCalibrationBarrel { this, "ECalScToHadGeVCalibrationBarrel", 1. };
+
+  Gaudi::Property<FloatVector>                m_InputEnergyCorrectionPoints { this, "InputEnergyCorrectionPoints", {} };
+  Gaudi::Property<FloatVector>                m_OutputEnergyCorrectionPoints { this, "OutputEnergyCorrectionPoints", {} };
+
+
+  static pandora::Pandora        *m_pPandora;
+  GeometryCreator                *m_pGeometryCreator;             ///< The geometry creator
+  CaloHitCreator                 *m_pCaloHitCreator;              ///< The calo hit creator
+  TrackCreator                   *m_pTrackCreator;                ///< The track creator
+  MCParticleCreator              *m_pMCParticleCreator;           ///< The mc particle creator
+  PfoCreator                     *m_pPfoCreator;                  ///< The pfo creator
+ 
+  Settings                        m_settings;                     ///< The settings for the pandora pfa new algo
+  CollectionMaps                  *m_CollectionMaps;               ///< The settings for the pandora pfa new algo
+  GeometryCreator::Settings       m_geometryCreatorSettings;      ///< The geometry creator settings
+  TrackCreator::Settings          m_trackCreatorSettings;         ///< The track creator settings
+  CaloHitCreator::Settings        m_caloHitCreatorSettings;       ///< The calo hit creator settings
+  MCParticleCreator::Settings     m_mcParticleCreatorSettings;    ///< The mc particle creator settings
+  PfoCreator::Settings            m_pfoCreatorSettings;           ///< The pfo creator settings
+
+  std::string                     m_detectorName;                 ///< The detector name
+  unsigned int                    m_nRun;                         ///< The run number
+  unsigned int                    m_nEvent;                       ///< The event number
+  //### For Ana #################
+  TFile* m_fout;
+  TTree* m_tree;
+  std::vector< std::vector<int>   > m_pReco_mc_id;
+  std::vector< std::vector<float> > m_pReco_mc_weight;
+  std::vector<int  > m_pReco_PID;    
+  std::vector<float> m_pReco_mass;
+  std::vector<float> m_pReco_energy;
+  std::vector<float> m_pReco_px;
+  std::vector<float> m_pReco_py;
+  std::vector<float> m_pReco_pz;
+  std::vector<float> m_pReco_charge;
+
+  std::vector<int>   m_mc_id;
+  std::vector<int>   m_mc_p_size;
+  std::vector<int>   m_mc_pid   ;
+  std::vector<float> m_mc_mass  ;
+  std::vector<float> m_mc_px    ;
+  std::vector<float> m_mc_py    ;
+  std::vector<float> m_mc_pz    ;
+  std::vector<float> m_mc_charge;
+  int m_hasConversion;
+  std::vector<float> m_hits_x ;
+  std::vector<float> m_hits_y ;
+  std::vector<float> m_hits_z ;
+  std::vector<float> m_hits_E ;
+
+  Gaudi::Property< std::string >              m_AnaOutput{ this, "AnaOutput", "/junofs/users/wxfang/MyGit/CEPCSW/Reconstruction/PFA/Pandora/GaudiPandora/Ana.root" };
+  //######################
+  
+  DataHandle<edm4hep::MCParticleCollection>     m_mcParCol_r  {"MCParticle", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALBarrel_r{"ECALBarrel", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALEndcap_r{"ECALEndcap", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_ECALOther_r {"ECALOther", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALBarrel_r{"HCALBarrel", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALEndcap_r{"HCALEndcap", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_HCALOther_r {"HCALOther", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_MUON_r      {"MUON", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_LCAL_r      {"LCAL", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_LHCAL_r     {"LHCAL", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::CalorimeterHitCollection> m_BCAL_r      {"BCAL", Gaudi::DataHandle::Reader, this};
+
+  DataHandle<edm4hep::VertexCollection> m_KinkVertices_r    {"KinkVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_ProngVertices_r   {"ProngVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_SplitVertices_r   {"SplitVertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::VertexCollection> m_V0Vertices_r      {"V0Vertices",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::TrackCollection>  m_MarlinTrkTracks_r {"MarlinTrkTracks",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCRecoCaloAssociationCollection>  m_MCRecoCaloAssociation_r {"MCRecoCaloAssociation",Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCRecoTrackerAssociationCollection>  m_MCRecoTrackerAssociation_r {"MCRecoTrackerAssociation",Gaudi::DataHandle::Reader, this};
+
+  DataHandle<edm4hep::ClusterCollection>                m_ClusterCollection_w {"PandoraClusters",Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::ReconstructedParticleCollection>  m_ReconstructedParticleCollection_w {"PandoraPFOs"    ,Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::VertexCollection>                 m_VertexCollection_w {"PandoraPFANewStartVertices",Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::MCRecoParticleAssociationCollection>  m_MCRecoParticleAssociation_w {"pfoMCRecoParticleAssociation",Gaudi::DataHandle::Writer, this};
+
+};
+
+#endif
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/PfoCreator.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/PfoCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..83c6e14932bb00178cfc70453b478dced3a72f90
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/PfoCreator.h
@@ -0,0 +1,219 @@
+/**
+ *  @file   MarlinPandora/include/PfoCreator.h
+ * 
+ *  @brief  Header file for the pfo creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef PFO_CREATOR_H
+#define PFO_CREATOR_H 1
+
+#include "FWCore/DataHandle.h"
+#include "edm4hep/Vector3f.h"
+#include "edm4hep/ClusterCollection.h"
+#include "edm4hep/Cluster.h"
+#include "edm4hep/ReconstructedParticleCollection.h"
+#include "edm4hep/ReconstructedParticle.h"
+#include "edm4hep/VertexCollection.h"
+#include "edm4hep/Vertex.h"
+#include "edm4hep/TrackCollection.h"
+#include "edm4hep/Track.h"
+#include "edm4hep/CalorimeterHitCollection.h"
+#include "edm4hep/CalorimeterHit.h"
+
+#include "ClusterShapes.h"
+#include "Api/PandoraApi.h"
+
+class CollectionMaps;
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  PfoCreator class
+ */
+class PfoCreator
+{
+public:
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        std::string     m_clusterCollectionName;                ///< The name of the cluster output collection
+        std::string     m_pfoCollectionName;                    ///< The name of the pfo output collection
+        std::string     m_startVertexCollectionName;            ///< The name of the start vertex output collection
+        std::string     m_startVertexAlgName;                   ///< The name of the algorithm to fill the start vertex output collection
+        float           m_emStochasticTerm;                     ///< The stochastic term for EM shower energy resolution
+        float           m_hadStochasticTerm;                    ///< The stochastic term for Hadronic shower energy resolution
+        float           m_emConstantTerm;                       ///< The constant term for EM shower energy resolution
+        float           m_hadConstantTerm;                      ///< The constant term for Hadronic shower energy resolution
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     PfoCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~PfoCreator();
+
+    /**
+     *  @brief  Create particle flow objects
+     * 
+     *  @param  pLCEvent the lcio event
+     */    
+    //pandora::StatusCode CreateParticleFlowObjects(EVENT::LCEvent *pLCEvent);
+    //pandora::StatusCode CreateParticleFlowObjects(const CollectionMaps& collectionMaps);
+    pandora::StatusCode CreateParticleFlowObjects(CollectionMaps& collectionMaps, DataHandle<edm4hep::ClusterCollection>& _pClusterCollection, DataHandle<edm4hep::ReconstructedParticleCollection>& _pReconstructedParticleCollection, DataHandle<edm4hep::VertexCollection>& _pStartVertexCollection);
+
+    CollectionMaps* m_collectionMaps;
+
+private:
+    /**
+     *  @brief  index for the subdetector
+     */
+    enum Index
+    {
+        ECAL_INDEX = 0,
+        HCAL_INDEX = 1,
+        YOKE_INDEX = 2,
+        LCAL_INDEX = 3,
+        LHCAL_INDEX = 4,
+        BCAL_INDEX = 5
+    };
+
+    /**
+     *  @brief  initialise sub detector name strings
+     * 
+     *  @param  subDetectorNames to receive the list of sub detector names
+     */
+    void InitialiseSubDetectorNames(pandora::StringVector &subDetectorNames) const;
+
+    /**
+     *  @brief  Set sub detector energies for a cluster
+     * 
+     *  @param  subDetectorNames the list of sub detector names
+     *  @param  pLcioCluster the address of the lcio cluster to be set sub detector energies
+     *  @param  pandoraCaloHitList the pandora calorimeter hit list
+     *  @param  hitE the vector to receive the energy of hits
+     *  @param  hitX the vector to receive the x position of hits
+     *  @param  hitY the vector to receive the y position of hits
+     *  @param  hitZ the vector to receive the z position of hits
+     */
+    void SetClusterSubDetectorEnergies(const pandora::StringVector &subDetectorNames, edm4hep::Cluster *const pLcioCluster,
+        const pandora::CaloHitList &pandoraCaloHitList, pandora::FloatVector &hitE, pandora::FloatVector &hitX, pandora::FloatVector &hitY,
+        pandora::FloatVector &hitZ) const;
+
+    /**
+     *  @brief  Set cluster energies and errors
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  pPandoraCluster the address of the pandora cluster
+     *  @param  pLcioCluster the address of the lcio cluster to be set energies and erros
+     *  @param  clusterCorrectEnergy a number to receive the cluster correct energy
+     */
+    void SetClusterEnergyAndError(const pandora::ParticleFlowObject *const pPandoraPfo, const pandora::Cluster *const pPandoraCluster, 
+        edm4hep::Cluster *const pLcioCluster, float &clusterCorrectEnergy) const;
+
+    /**
+     *  @brief  Set cluster position, errors and other shape info, by calculating culster shape first
+     * 
+     *  @param  nHitsInCluster number of hits in cluster
+     *  @param  hitE the vector of the energy of hits
+     *  @param  hitX the vector of the x position of hits
+     *  @param  hitY the vector of the y position of hits
+     *  @param  hitZ the vector of the z position of hits
+     *  @param  pLcioCluster the lcio cluster to be set positions and errors
+     *  @param  clusterPosition a CartesianVector to receive the cluster position
+     */
+    void SetClusterPositionAndError(const unsigned int nHitsInCluster, pandora::FloatVector &hitE, pandora::FloatVector &hitX, 
+        pandora::FloatVector &hitY, pandora::FloatVector &hitZ, edm4hep::Cluster *const pLcioCluster, pandora::CartesianVector &clusterPositionVec) const;
+
+    /**
+     *  @brief  Calculate reference point for pfo with tracks
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  referencePoint a CartesianVector to receive the reference point
+     */
+    pandora::StatusCode CalculateTrackBasedReferencePoint(const pandora::ParticleFlowObject *const pPandoraPfo, pandora::CartesianVector &referencePoint) const;
+
+    /**
+     *  @brief  Set reference point of the reconstructed particle
+     * 
+     *  @param  referencePoint a CartesianVector of the reference point
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be reference point
+     */
+    void SetRecoParticleReferencePoint(const pandora::CartesianVector &referencePoint, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Add tracks to reconstructed particle
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be added tracks
+     */
+    void AddTracksToRecoParticle(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Set properties of reconstructed particle from pandora pfo
+     * 
+     *  @param  pPandoraPfo the address of the pandora pfo 
+     *  @param  pReconstructedParticle the address of the reconstructed particle to be set properties
+     */
+    void SetRecoParticlePropertiesFromPFO(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const;
+
+    /**
+     *  @brief  Whether parent and daughter tracks are associated with the same pfo
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated with reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool IsValidParentTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether sibling tracks are associated with the same pfo
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated with reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool HasValidSiblingTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether the track is the closest (of those associated with the same pfo) to the interaction point
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated to reconstructed particle
+     * 
+     *  @return boolean
+     */ 
+    bool IsClosestTrackToIP(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    /**
+     *  @brief  Whether at least one track sibling track is associated to the reconstructed particle 
+     *
+     *  @param  pPandoraTrack the address of the pandora track
+     *  @param  allTrackList list of all tracks associated to reconstructed particle
+     * 
+     *  @return boolean
+     */
+    bool AreAnyOtherSiblingsInList(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const;
+
+    const Settings              m_settings;                         ///< The pfo creator settings
+    const pandora::Pandora      *m_pPandora;                        ///< Address of the pandora object from which to extract the pfos
+};
+
+#endif // #ifndef PFO_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/TrackCreator.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/TrackCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e1588c2629db7a4f7728b9edb62b86f5cf3fd0e
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/TrackCreator.h
@@ -0,0 +1,373 @@
+/**
+ *  @file   MarlinPandora/include/TrackCreator.h
+ * 
+ *  @brief  Header file for the track creator class.
+ * 
+ *  $Log: $
+ */
+
+#ifndef TRACK_CREATOR_H
+#define TRACK_CREATOR_H 1
+
+
+
+
+#include "GaudiKernel/ISvcLocator.h"
+
+#include "edm4hep/Track.h"
+#include "edm4hep/TrackConst.h"
+#include "edm4hep/TrackState.h"
+#include "edm4hep/ReconstructedParticleConst.h"
+
+#include "Api/PandoraApi.h"
+#include "Objects/Helix.h"
+
+namespace gear { class GearMgr; }
+
+class CollectionMaps;
+
+typedef std::vector<const edm4hep::Track *> TrackVector;
+//typedef std::set<const edm4hep::Track *> TrackList;
+typedef std::set<unsigned int> TrackList;
+//typedef std::map<edm4hep::Track *, int> TrackToPidMap;
+typedef std::map<edm4hep::ConstTrack, int> TrackToPidMap;
+/*
+inline LCCollectionVec *newTrkCol(const std::string &name, LCEvent *evt , bool isSubset)
+{
+    LCCollectionVec* col = new LCCollectionVec( LCIO::TRACK ) ;
+
+    LCFlagImpl hitFlag(0) ;
+    hitFlag.setBit( LCIO::TRBIT_HITS ) ;
+    col->setFlag( hitFlag.getFlag()  ) ;
+    evt->addCollection( col , name ) ;
+    col->setSubset( isSubset ) ;
+
+    return col ;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ *  @brief  TrackCreator class
+ */
+class TrackCreator
+{
+public:
+    typedef std::vector<double> DoubleVector;
+    typedef std::vector<std::string> StringVector;
+
+    /**
+     *  @brief  Settings class
+     */
+    class Settings
+    {
+    public:
+        /**
+         *  @brief  Default constructor
+         */
+        Settings();
+
+        StringVector    m_trackCollections;                     ///< The reconstructed track collections
+        StringVector    m_kinkVertexCollections;                ///< The kink vertex collections
+        StringVector    m_prongVertexCollections;               ///< The prong vertex collections
+        StringVector    m_splitVertexCollections;               ///< The split vertex collections
+        StringVector    m_v0VertexCollections;                  ///< The v0 vertex collections
+
+        StringVector    m_prongSplitVertexCollections;          ///< Concatenated list of prong and split vertex collections
+        int             m_shouldFormTrackRelationships;         ///< Whether to form pandora track relationships using v0 and kink info
+
+        int             m_minTrackHits;                         ///< Track quality cut: the minimum number of track hits
+        int             m_minFtdTrackHits;                      ///< Track quality cut: the minimum number of FTD track hits for FTD only tracks
+        int             m_maxTrackHits;                         ///< Track quality cut: the maximum number of track hits
+
+        float           m_d0TrackCut;                           ///< Track d0 cut used to determine whether track can be used to form pfo
+        float           m_z0TrackCut;                           ///< Track z0 cut used to determine whether track can be used to form pfo
+
+        int             m_usingNonVertexTracks;                 ///< Whether can form pfos from tracks that don't start at vertex
+        int             m_usingUnmatchedNonVertexTracks;        ///< Whether can form pfos from unmatched tracks that don't start at vertex
+        int             m_usingUnmatchedVertexTracks;           ///< Whether can form pfos from unmatched tracks that start at vertex
+        float           m_unmatchedVertexTrackMaxEnergy;        ///< Maximum energy for unmatched vertex track
+
+        float           m_d0UnmatchedVertexTrackCut;            ///< d0 cut used to determine whether unmatched vertex track can form pfo
+        float           m_z0UnmatchedVertexTrackCut;            ///< z0 cut used to determine whether unmatched vertex track can form pfo
+        float           m_zCutForNonVertexTracks;               ///< Non vtx track z cut to determine whether track can be used to form pfo
+
+        int             m_reachesECalNTpcHits;                  ///< Minimum number of tpc hits to consider track as reaching ecal
+        int             m_reachesECalNFtdHits;                  ///< Minimum number of ftd hits to consider track as reaching ecal
+        float           m_reachesECalTpcOuterDistance;          ///< Max distance from track to tpc r max to id whether track reaches ecal
+        int             m_reachesECalMinFtdLayer;               ///< Min layer in Ftd for tracks to be considered to have reached decal
+        float           m_reachesECalTpcZMaxDistance;           ///< Max distance from track to tpc z max to id whether track reaches ecal
+        float           m_reachesECalFtdZMaxDistance;           ///< Max distance from track hit to ftd z position to identify ftd hits
+        float           m_curvatureToMomentumFactor;            ///< Constant relating track curvature in b field to momentum
+
+        float           m_minTrackECalDistanceFromIp;           ///< Sanity check on separation between ip and track projected ecal position
+        float           m_maxTrackSigmaPOverP;                  ///< Track fraction momentum error cut
+        float           m_minMomentumForTrackHitChecks;         ///< Min track momentum required to perform final quality checks on number of hits
+
+        float           m_tpcMembraneMaxZ;                      ///< Tpc membrane max z coordinate
+        float           m_maxTpcInnerRDistance;                 ///< Track cut on distance from tpc inner r to id whether track can form pfo
+        float           m_minTpcHitFractionOfExpected;          ///< Minimum fraction of TPC hits compared to expected
+        int             m_minFtdHitsForTpcHitFraction;          ///< Minimum number of FTD hits to ignore TPC hit fraction
+    };
+
+    /**
+     *  @brief  Constructor
+     * 
+     *  @param  settings the creator settings
+     *  @param  pPandora address of the relevant pandora instance
+     */
+     //TrackCreator(const Settings &settings, const pandora::Pandora *const pPandora);
+     TrackCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc);
+
+    /**
+     *  @brief  Destructor
+     */
+     ~TrackCreator();
+
+    /**
+     *  @brief  Create associations between tracks, V0s, kinks, etc
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode CreateTrackAssociations(const EVENT::LCEvent *const pLCEvent);
+    pandora::StatusCode CreateTrackAssociations(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Create tracks, insert user code here
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode CreateTracks(EVENT::LCEvent *pLCEvent);
+    pandora::StatusCode CreateTracks(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Get the track vector
+     * 
+     *  @return The track vector
+     */
+    const TrackVector &GetTrackVector() const;
+
+    /**
+     *  @brief  Reset the track creator
+     */
+    void Reset();
+
+private:
+    /**
+     *  @brief  Extract kink information from specified lcio collections
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode ExtractKinks(const EVENT::LCEvent *const pLCEvent);
+    pandora::StatusCode ExtractKinks(const CollectionMaps& collectionMaps);
+
+    /**
+     *  @brief  Extract prong and split information from specified lcio collections
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+    //pandora::StatusCode ExtractProngsAndSplits(const EVENT::LCEvent *const pLCEvent);
+
+    /**
+     *  @brief  Extract v0 information from specified lcio collections
+     * 
+     *  @param  pLCEvent the lcio event
+     */
+   //pandora::StatusCode ExtractV0s(const EVENT::LCEvent *const pLCEvent);
+
+    /**
+     *  @brief  Whether the track vertex conflicts with previously provided relationship information
+     * 
+     *  @param  trackVec the vector of tracks associated with the vertex
+     */
+    //bool IsConflictingRelationship(const EVENT::TrackVec &trackVec) const;
+    //bool IsConflictingRelationship(edm4hep::ConstTrack &trackVec) const;
+    bool IsConflictingRelationship(const edm4hep::ConstReconstructedParticle &Particle) const;
+
+    /**
+     *  @brief  Whether a track is a v0 track
+     * 
+     *  @param  pTrack the lcio track
+     * 
+     *  @return boolean
+     */
+    //bool IsV0(const EVENT::Track *const pTrack) const;
+    bool IsV0(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Whether a track is a parent track
+     * 
+     *  @param  pTrack the lcio track
+     * 
+     *  @return boolean
+     */
+    //bool IsParent(const EVENT::Track *const pTrack) const;
+    bool IsParent(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Whether a track is a daughter track
+     * 
+     *  @param  pTrack the lcio track
+     * 
+     *  @return boolean
+     */
+    //bool IsDaughter(const EVENT::Track *const pTrack) const;
+    bool IsDaughter(unsigned int pTrack_id) const;
+
+    /**
+     *  @brief  Copy track states stored in lcio tracks to pandora track parameters
+     * 
+     *  @param  pTrack the lcio track
+     *  @param  trackParameters the track parameters
+     */
+    //void GetTrackStates(const EVENT::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+    void GetTrackStates(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Copy track state from lcio track state instance to pandora input track state
+     * 
+     *  @param  pTrackState the lcio track state instance
+     *  @param  inputTrackState the pandora input track state
+     */
+    //void CopyTrackState(const TrackState *const pTrackState, pandora::InputTrackState &inputTrackState) const;
+    void CopyTrackState(const edm4hep::TrackState & pTrackState, pandora::InputTrackState &inputTrackState) const;
+
+    /**
+     *  @brief  Obtain track time when it reaches ECAL
+     * 
+     *  @param  pTrack the lcio track
+     */
+    //float CalculateTrackTimeAtCalorimeter(const EVENT::Track *const pTrack) const;
+    float CalculateTrackTimeAtCalorimeter(const edm4hep::Track *const pTrack) const;
+
+    /**
+     *  @brief  Decide whether track reaches the ecal surface
+     * 
+     *  @param  pTrack the lcio track
+     *  @param  trackParameters the track parameters
+     */
+    //void TrackReachesECAL(const EVENT::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+    void TrackReachesECAL(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+    //void TrackReachesECAL(const edm4hep::Track& pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Determine whether a track can be used to form a pfo under the following conditions:
+     *          1) if the track proves to be associated with a cluster, OR
+     *          2) if the track proves to have no cluster associations
+     * 
+     *  @param  pTrack the lcio track
+     *  @param  trackParameters the track parameters
+     */
+    //void DefineTrackPfoUsage(const EVENT::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+    void DefineTrackPfoUsage(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Whether track passes the quality cuts required in order to be used to form a pfo
+     * 
+     *  @param  pTrack the lcio track
+     *  @param  trackParameters the track parameters
+     * 
+     *  @return boolean
+     */
+    //bool PassesQualityCuts(const EVENT::Track *const pTrack, const PandoraApi::Track::Parameters &trackParameters) const;
+    bool PassesQualityCuts(const edm4hep::Track *const pTrack, const PandoraApi::Track::Parameters &trackParameters) const;
+
+    /**
+     *  @brief  Get number of hits in TPC of a track
+     * 
+     *  @param  pTrack the lcio track
+     * 
+     *  @return number of hits in TPC of a track
+     */
+    //int GetNTpcHits(const EVENT::Track *const pTrack) const;
+    int GetNTpcHits(const edm4hep::Track *const pTrack) const;
+
+    /**
+     *  @brief  Get number of hits in FTD of a track
+     * 
+     *  @param  pTrack the lcio track
+     * 
+     *  @return number of hits in FTDof a track
+     */
+    //int GetNFtdHits(const EVENT::Track *const pTrack) const;
+    int GetNFtdHits(const edm4hep::Track *const pTrack) const;
+
+    const Settings          m_settings;                     ///< The track creator settings
+    const pandora::Pandora *m_pPandora;                     ///< Address of the pandora object to create tracks and track relationships
+
+    float             m_bField;                       ///< The bfield
+
+    float             m_tpcInnerR;                    ///< The tpc inner radius
+    float             m_tpcOuterR;                    ///< The tpc outer radius
+    unsigned int      m_tpcMaxRow;                    ///< The tpc maximum row number
+    float             m_tpcZmax;                      ///< The tpc maximum z coordinate
+    float                   m_cosTpc;                       ///< Cos(theta) value at end of tpc
+
+    DoubleVector            m_ftdInnerRadii;                ///< List of ftd inner radii
+    DoubleVector            m_ftdOuterRadii;                ///< List of ftd outer radii
+    DoubleVector            m_ftdZPositions;                ///< List of ftd z positions
+    unsigned int            m_nFtdLayers;                   ///< Number of ftd layers
+    float                   m_tanLambdaFtd;                 ///< Tan lambda for first ftd layer
+
+    int               m_eCalBarrelInnerSymmetry;      ///< ECal barrel inner symmetry order
+    float             m_eCalBarrelInnerPhi0;          ///< ECal barrel inner phi 0
+    float             m_eCalBarrelInnerR;             ///< ECal barrel inner radius
+    float             m_eCalEndCapInnerZ;             ///< ECal endcap inner z
+
+    float                   m_minEtdZPosition;              ///< Min etd z position
+    float                   m_minSetRadius;                 ///< Min set radius
+
+    TrackVector             m_trackVector;                  ///< The track vector
+    TrackList               m_v0TrackList;                  ///< The list of v0 tracks
+    TrackList               m_parentTrackList;              ///< The list of parent tracks
+    TrackList               m_daughterTrackList;            ///< The list of daughter tracks
+    TrackToPidMap           m_trackToPidMap;                ///< The map from track addresses to particle ids, where set by kinks/V0s
+    gear::GearMgr* _GEAR;
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline const TrackVector &TrackCreator::GetTrackVector() const
+{
+    return m_trackVector;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+inline void TrackCreator::Reset()
+{
+    m_trackVector.clear();
+    m_v0TrackList.clear();
+    m_parentTrackList.clear();
+    m_daughterTrackList.clear();
+    m_trackToPidMap.clear();
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+//inline bool TrackCreator::IsV0(const Track *const pTrack) const
+inline bool TrackCreator::IsV0(unsigned int pTrack_id) const // should check here, if id is correct one to do this
+{
+    //return (m_v0TrackList.end() != m_v0TrackList.find(pTrack));
+    return (m_v0TrackList.end() != m_v0TrackList.find(pTrack_id));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+//inline bool TrackCreator::IsParent(const Track *const pTrack) const
+inline bool TrackCreator::IsParent(unsigned int pTrack_id) const
+{
+    //return (m_parentTrackList.end() != m_parentTrackList.find(pTrack));
+    return (m_parentTrackList.end() != m_parentTrackList.find(pTrack_id));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+//inline bool TrackCreator::IsDaughter(const Track *const pTrack) const
+inline bool TrackCreator::IsDaughter(unsigned int pTrack_id) const
+{
+    //return (m_daughterTrackList.end() != m_daughterTrackList.find(pTrack));
+    return (m_daughterTrackList.end() != m_daughterTrackList.find(pTrack_id));
+}
+
+#endif // #ifndef TRACK_CREATOR_H
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/Utility.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/Utility.h
new file mode 100644
index 0000000000000000000000000000000000000000..0bd75b5d94f4725581e44176a02fbb94a99088fa
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/Utility.h
@@ -0,0 +1,6 @@
+#ifndef MYUTILITY
+#define MYUTILITY 1
+
+#include <sstream>
+std::string Convert (float number);
+#endif
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/include/cellIDDecoder.h b/Reconstruction/PFA/Pandora/MatrixPandora/include/cellIDDecoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..f15159967865ae3ab64def320daf820def08bcf8
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/include/cellIDDecoder.h
@@ -0,0 +1,127 @@
+#ifndef cellIDDecoder_h
+#define cellIDDecoder_h 1
+
+//#include <vector>
+//#include "EVENT/LCObject.h"
+#include "EVENT/LCCollection.h"
+//#include "EVENT/SimTrackerHit.h"
+#include "UTIL/BitField64.h"
+#include "lcio.h"
+#include <string>
+
+// fixes problem in gcc 4.0.3
+#include "EVENT/LCParameters.h"
+
+//#include <sstream>
+//#include <typeinfo>
+
+//##################### changed for EMD4HEP ########
+//need check !!
+
+namespace ID_UTIL{
+
+
+  /** Convenient class for decoding cellIDs from collection parameter LCIO::CellIDEncoding.
+   *  See UTIL::BitField64 for a description of the encoding string. 
+   * 
+   *  @see BitField64
+   *  @version $Id: CellIDDecoder.h,v 1.9.16.1 2011-03-04 14:09:07 engels Exp $
+   */
+  template <class T> 
+  class CellIDDecoder {
+    
+  public:  
+
+    CellIDDecoder() = default ;
+    CellIDDecoder(const CellIDDecoder& ) = delete ;
+    CellIDDecoder& operator=(const CellIDDecoder& ) = delete ;
+    
+
+    /** Constructor takes encoding string as argument.
+     */
+  CellIDDecoder( const std::string& encoder_str ) : _oldHit(0) {
+      
+      if( encoder_str.length() == 0 ){
+      	throw( lcio::Exception( "CellIDDecoder : string of length zero provided as encoder string" ) ) ;
+      }
+      _b = new UTIL::BitField64( encoder_str ) ; 
+      
+    }
+    
+    /** Constructor reads encoding string from collection parameter LCIO::CellIDEncoding.
+     */
+    CellIDDecoder( const EVENT::LCCollection* col ) : _oldHit(0) {
+      
+      std::string initString("") ; 
+
+      if( col !=0 ) 
+	initString = col->getParameters().getStringVal(  lcio::LCIO::CellIDEncoding ) ;
+      
+      if( initString.size() == 0 ) {
+	
+	initString = _defaultEncoding ;
+
+	std::cout << "    ----------------------------------------- " << std::endl  
+		  << "       WARNING: CellIDDecoder - no CellIDEncoding parameter in collection ! " 
+		  << std::endl 
+		  << "         -> using default : \"" << initString << "\"" 
+		  << std::endl 
+		  << "    ------------------------------------------ "  
+		  << std::endl ;
+      }
+      
+      _b = new UTIL::BitField64(  initString ) ; 
+    }
+    
+    ~CellIDDecoder(){ 
+      
+      delete _b ;
+    } 
+    
+    
+    /** Provides access to the bit fields, e.g. <br>
+     *   int layer =  myCellIDEncoding( hit )[ "layer" ] ;
+     * 
+     */
+    inline const UTIL::BitField64 & operator()( const T* hit ){  
+      
+      if( hit != _oldHit && hit ) {
+	auto id = hit->getCellID();
+        unsigned int id0 = id&0xFFFFFFFF;
+        unsigned int id1 = id>>32;
+	//lcio::long64 val = lcio::long64( hit->getCellID0() & 0xffffffff ) | ( lcio::long64( hit->getCellID1() ) << 32      ) ;
+	lcio::long64 val = lcio::long64( id0 & 0xffffffff ) | ( lcio::long64( id1 ) << 32      ) ;
+	
+	_b->setValue( val ) ;
+
+	_oldHit = hit ;
+      }
+      
+      return  *_b ;
+    }
+    
+
+    /** This can be used to set the default encoding that is used if no
+     *  CellIDEncoding parameter is set in the collection, e.g. in older lcio files.
+     */ 
+    static void setDefaultEncoding(const std::string& defaultEncoding ) {
+
+      _defaultEncoding = std::string( defaultEncoding ) ;
+    }
+    
+  protected:
+    UTIL::BitField64* _b{} ;
+    const T* _oldHit{NULL} ;
+    
+    static std::string _defaultEncoding;
+  } ; 
+  
+  template <class T>
+  std::string CellIDDecoder<T>::_defaultEncoding
+  = std::string("byte0:8,byte1:8,byte2:8,byte3:8,byte4:8,byte5:8,byte6:8,byte7:8") ;
+
+  
+} // namespace
+#endif
+
+
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/CaloHitCreator.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/CaloHitCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3196cde227b8c14c647aa2e042c89b36ba91ad9e
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/CaloHitCreator.cpp
@@ -0,0 +1,959 @@
+/**
+ *  @file   MarlinPandora/src/CaloHitCreator.cc
+ * 
+ *  @brief  Implementation of the calo hit creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "gear/GearParameters.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/GearDistanceProperties.h"
+#include "gear/GearPointProperties.h"
+#include "gear/GEAR.h"
+#include "gear/TPCParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/LayerLayout.h"
+
+#include <DD4hep/Detector.h>
+#include <DDRec/DetectorData.h>
+#include <DDRec/CellIDPositionConverter.h>
+#include <DD4hep/Objects.h>
+
+#include "UTIL/CellIDDecoder.h"
+#include "cellIDDecoder.h"
+#include "GaudiKernel/IService.h"
+#include "GearSvc/IGearSvc.h"
+
+#include "PandoraMatrixAlg.h"
+#include "CaloHitCreator.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+
+CaloHitCreator::CaloHitCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc, bool encoder_style) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+    m_encoder_str = ""; 
+    m_encoder_str_MUON = ""; 
+    m_encoder_str_LCal = ""; 
+    m_encoder_str_LHCal = ""; 
+    if(encoder_style==0) 
+    {
+        m_encoder_str     = "M:3,S-1:3,I:9,J:9,K-1:6";// LCIO style
+        m_encoder_str_MUON="S-1:4,M:3,K-1:6,I:16,GRZone:3,J:32:16";
+        m_encoder_str_LCal="I:10,J:10,K:10,S-1:2";
+        m_encoder_str_LHCal=m_encoder_str;
+    }
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+
+
+    IGeoSvc*  Svc = 0;
+    StatusCode sc1 = svcloc->service("GeoSvc", Svc, false);
+    if ( !sc1 )
+    {
+        throw "Failed to find GeoSvc ...";
+    }
+    m_dd4hep = Svc->lcdd();
+    const dd4hep::DetElement &detElement = m_dd4hep->detector("CaloDetector");
+    dd4hep::rec::LayeredCalorimeterData* Data = detElement.extension<dd4hep::rec::LayeredCalorimeterData>() ;
+    if(!Data) throw "Failed to get LayeredCalorimeterData ...";
+    m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(*m_dd4hep);
+    /*
+    m_compact = "/junofs/users/wxfang/MyGit/lcg97/UsingK4FWCore/0514/CEPCSW/Detector/DetEcalMatrix/compact/det.xml";
+    dd4hep::Detector& description = dd4hep::Detector::getInstance();
+    description.fromCompact( m_compact );
+    m_cellIDConverter = new dd4hep::rec::CellIDPositionConverter(description);
+    */
+
+    m_eCalBarrelOuterZ        = Data->extent[3];
+    m_eCalBarrelInnerPhi0     = Data->inner_phi0;
+    m_eCalBarrelInnerSymmetry = Data->inner_symmetry;
+    m_hCalBarrelOuterZ        = (_GEAR->getHcalBarrelParameters().getExtent()[3]);
+    m_muonBarrelOuterZ        = (_GEAR->getYokeBarrelParameters().getExtent()[3]);
+    m_coilOuterR              = (_GEAR->getGearParameters("CoilParameters").getDoubleVal("Coil_cryostat_outer_radius"));
+    m_hCalBarrelInnerPhi0     = (_GEAR->getHcalBarrelParameters().getPhi0());
+    m_hCalBarrelInnerSymmetry = (_GEAR->getHcalBarrelParameters().getSymmetryOrder());
+    m_muonBarrelInnerPhi0     = (_GEAR->getYokeBarrelParameters().getPhi0());
+    m_muonBarrelInnerSymmetry = (_GEAR->getYokeBarrelParameters().getSymmetryOrder());
+    m_hCalEndCapOuterR        = (_GEAR->getHcalEndcapParameters().getExtent()[1]);
+    m_hCalEndCapOuterZ        = (_GEAR->getHcalEndcapParameters().getExtent()[3]);
+    m_hCalBarrelOuterR        = (_GEAR->getHcalBarrelParameters().getExtent()[1]);
+    m_hCalBarrelOuterPhi0     =((std::find(_GEAR->getHcalBarrelParameters().getIntKeys().begin(),
+        _GEAR->getHcalBarrelParameters().getIntKeys().end(),
+        "Hcal_outer_polygon_phi0") != _GEAR->getHcalBarrelParameters().getIntKeys().end() ?
+        _GEAR->getHcalBarrelParameters().getIntVal("Hcal_outer_polygon_phi0")
+        : 0));
+    m_hCalBarrelOuterSymmetry = ((std::find(_GEAR->getHcalBarrelParameters().getIntKeys().begin(),
+        _GEAR->getHcalBarrelParameters().getIntKeys().end(),
+        "Hcal_outer_polygon_order") != _GEAR->getHcalBarrelParameters().getIntKeys().end() ?
+        _GEAR->getHcalBarrelParameters().getIntVal("Hcal_outer_polygon_order")
+        : 0));
+
+
+    const gear::LayerLayout &hCalEndCapLayerLayout(_GEAR->getHcalEndcapParameters().getLayerLayout());
+    const gear::LayerLayout &hCalBarrelLayerLayout(_GEAR->getHcalBarrelParameters().getLayerLayout()); 
+    m_hCalEndCapLayerThickness = hCalEndCapLayerLayout.getThickness(hCalEndCapLayerLayout.getNLayers() - 1);
+    m_hCalBarrelLayerThickness = hCalBarrelLayerLayout.getThickness(hCalBarrelLayerLayout.getNLayers() - 1);
+    if ((m_hCalEndCapLayerThickness < std::numeric_limits<float>::epsilon()) || (m_hCalBarrelLayerThickness < std::numeric_limits<float>::epsilon()))
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+
+
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+CaloHitCreator::~CaloHitCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateCaloHits(const CollectionMaps& collectionMaps)
+{
+    
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateECalCaloHits (collectionMaps));
+    // not used for ECAL Matrix
+    /*
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateMuonCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateLCalCaloHits (collectionMaps));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateLHCalCaloHits(collectionMaps));
+    */
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateECalCaloHits(const CollectionMaps& collectionMaps)
+{
+    std::cout<<"start CreateECalCaloHits:"<<std::endl;
+    for (StringVector::const_iterator iter = m_settings.m_eCalCaloHitCollections.begin(), iterEnd = m_settings.m_eCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            std::cout<<(*iter)<<"has nElements="<<nElements<<std::endl;
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getEcalEndcapParameters().getLayerLayout());
+            const dd4hep::DetElement &detElement = m_dd4hep->detector("CaloDetector");
+            dd4hep::rec::LayeredCalorimeterData* Data = detElement.extension<dd4hep::rec::LayeredCalorimeterData>() ;
+            const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer>& barrelLayerLayout = Data->layers;
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str);
+            const std::string layerCodingString(m_encoder_str);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("CreateECalCaloHits pCaloHit Collection type mismatch");
+
+                    float eCalToMip(m_settings.m_eCalToMip), eCalMipThreshold(m_settings.m_eCalMipThreshold), eCalToEMGeV(m_settings.m_eCalToEMGeV),
+                        eCalToHadGeVBarrel(m_settings.m_eCalToHadGeVBarrel), eCalToHadGeVEndCap(m_settings.m_eCalToHadGeVEndCap);
+
+                    // Hybrid ECAL including pure ScECAL.
+                    if (m_settings.m_useEcalScLayers)
+                    {
+                        std::string collectionName(*iter);
+                        std::transform(collectionName.begin(), collectionName.end(), collectionName.begin(), ::tolower);
+
+                        if (collectionName.find("ecal", 0) == std::string::npos)
+                            std::cout << "WARNING: mismatching hybrid Ecal collection name. " << collectionName << std::endl;
+
+                        if (collectionName.find("si", 0) != std::string::npos)
+                        {
+                             eCalToMip = m_settings.m_eCalSiToMip;
+                             eCalMipThreshold = m_settings.m_eCalSiMipThreshold;
+                             eCalToEMGeV = m_settings.m_eCalSiToEMGeV;
+                             eCalToHadGeVBarrel = m_settings.m_eCalSiToHadGeVBarrel;
+                             eCalToHadGeVEndCap = m_settings.m_eCalSiToHadGeVEndCap;
+                        }
+                        else if (collectionName.find("sc", 0) != std::string::npos)
+                        {
+                             eCalToMip = m_settings.m_eCalScToMip;
+                             eCalMipThreshold = m_settings.m_eCalScMipThreshold;
+                             eCalToEMGeV = m_settings.m_eCalScToEMGeV;
+                             eCalToHadGeVBarrel = m_settings.m_eCalScToHadGeVBarrel;
+                             eCalToHadGeVEndCap = m_settings.m_eCalScToHadGeVEndCap;
+                        }
+                    }
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::ECAL;
+                    caloHitParameters.m_isDigital = false;//FIXME, maybe this means the MIP thershold cut haven't be applied yet ?
+                    /* 
+                    dd4hep::Position position = m_cellIDConverter->position(pCaloHit->getCellID());
+                    long id_sys,id_x,id_y,id_z ;
+                    GetCoding(pCaloHit, id_sys, id_x, id_y, id_z);
+                    std::cout << "ECAL id =" << pCaloHit->getCellID()<<",sys="<<id_sys<<",x="<<id_x<<",y="<<id_y<<",z="<<id_z << std::endl;
+                    std::cout << "ECAL id =" << pCaloHit->getCellID()<<",x="<<position.x()<<",y="<<position.y()<<",z="<<position.z() << std::endl;
+                    */
+                    caloHitParameters.m_isInOuterSamplingLayer = false;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+
+                    if (std::fabs(pCaloHit->getPosition()[2]) < m_eCalBarrelOuterZ)
+                    {
+                        caloHitParameters.m_layer = GetBarrelLayer(pCaloHit, barrelLayerLayout);
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_eCalBarrelInnerSymmetry, m_eCalBarrelInnerPhi0, 6, caloHitParameters, absorberCorrection);//6
+                        caloHitParameters.m_hadronicEnergy = eCalToHadGeVBarrel * pCaloHit->getEnergy();
+                        
+                    }
+                    else
+                    { // will not be used for ECAL Matrix
+                        caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()] + 1;//FIXME, should use + 1? because the decoded layer is start from 0.
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                        caloHitParameters.m_hadronicEnergy = eCalToHadGeVEndCap * pCaloHit->getEnergy();
+                    }
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * eCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < eCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_electromagneticEnergy = eCalToEMGeV * pCaloHit->getEnergy();
+
+                    // ATTN If using strip splitting, must correct cell sizes for use in PFA to minimum of strip width and strip length
+                    if (m_settings.m_stripSplittingOn)
+                    {
+                        const float splitCellSize(std::min(caloHitParameters.m_cellSize0.Get(), caloHitParameters.m_cellSize1.Get()));
+                        caloHitParameters.m_cellSize0 = splitCellSize;
+                        caloHitParameters.m_cellSize1 = splitCellSize;
+                    }
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"ERROR Failed to extract ecal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"WARNING Failed to extract ecal calo hit: " <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<< "Failed to extract ecal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateHCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_hCalCaloHitCollections.begin(), iterEnd = m_settings.m_hCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            std::cout<<(*iter)<<"has nElements="<<nElements<<std::endl;
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getHcalEndcapParameters().getLayerLayout());
+            const gear::LayerLayout &barrelLayerLayout(_GEAR->getHcalBarrelParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str);
+            const std::string layerCodingString(m_encoder_str);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("CreateHCalCaloHits Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::HCAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = (this->GetNLayersFromEdge(pCaloHit) <= m_settings.m_nOuterSamplingLayers);
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+
+                    if (std::fabs(pCaloHit->getPosition()[2]) < m_hCalBarrelOuterZ)
+                    {
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_hCalBarrelInnerSymmetry, m_hCalBarrelInnerPhi0,
+                            m_hCalBarrelInnerSymmetry - int(cellIdDecoder(pCaloHit)[ staveCoding] / 2), caloHitParameters, absorberCorrection);
+                    }
+                    else
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_hCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_hCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_hadronicEnergy = std::min(m_settings.m_hCalToHadGeV * pCaloHit->getEnergy(), m_settings.m_maxHCalHitHadronicEnergy);
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_hCalToEMGeV * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Error, Failed to extract hcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"WARNING Failed to extract hcal calo hit: " << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract hcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateMuonCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_muonCaloHitCollections.begin(), iterEnd = m_settings.m_muonCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            std::cout<<(*iter)<<"has nElements="<<nElements<<std::endl;
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getYokeEndcapParameters().getLayerLayout());
+            const gear::LayerLayout &barrelLayerLayout(_GEAR->getYokeBarrelParameters().getLayerLayout()); 
+            const gear::LayerLayout &plugLayerLayout(_GEAR->getYokePlugParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_MUON);
+            const std::string layerCodingString(m_encoder_str_MUON);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+            const std::string staveCoding(this->GetStaveCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("Muon Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::MUON;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()] + 1;//FIXME, should use +1? it starts from 0.
+                    caloHitParameters.m_isInOuterSamplingLayer = true;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    const float radius(std::sqrt(pCaloHit->getPosition()[0] * pCaloHit->getPosition()[0] +
+                        pCaloHit->getPosition()[1] * pCaloHit->getPosition()[1]));
+
+                    const bool isWithinCoil(radius < m_coilOuterR);
+                    const bool isInBarrelRegion(std::fabs(pCaloHit->getPosition()[2]) < m_muonBarrelOuterZ);
+
+                    float absorberCorrection(1.);
+
+                    if (isInBarrelRegion && isWithinCoil)
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, plugLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+                    else if (isInBarrelRegion)
+                    {
+                        this->GetBarrelCaloHitProperties(pCaloHit, barrelLayerLayout, m_muonBarrelInnerSymmetry, m_muonBarrelInnerPhi0,
+                            cellIdDecoder(pCaloHit)[ staveCoding ], caloHitParameters, absorberCorrection);
+                    }
+                    else
+                    {
+                        this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+                    }
+
+                    if (m_settings.m_muonDigitalHits > 0)
+                    {
+                        caloHitParameters.m_isDigital = true;
+                        caloHitParameters.m_inputEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_hadronicEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_electromagneticEnergy = m_settings.m_muonHitEnergy;
+                        caloHitParameters.m_mipEquivalentEnergy = 1.f;
+                    }
+                    else
+                    {
+                        caloHitParameters.m_isDigital = false;
+                        caloHitParameters.m_inputEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_hadronicEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_electromagneticEnergy = pCaloHit->getEnergy();
+                        caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_muonToMip;
+                    }
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract muon hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract muon hit: "  << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract muon hit collection: " << *iter  << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateLCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_lCalCaloHitCollections.begin(), iterEnd = m_settings.m_lCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            std::cout<<(*iter)<<"has nElements="<<nElements<<std::endl;
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getLcalParameters().getLayerLayout()); 
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_LCal);
+            const std::string layerCodingString(m_encoder_str_LCal);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("LCal Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::ECAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = false;
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+                    this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_eCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_eCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_eCalToEMGeV * pCaloHit->getEnergy();
+                    caloHitParameters.m_hadronicEnergy = m_settings.m_eCalToHadGeVEndCap * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract lcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract lcal calo hit: " << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract lcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode CaloHitCreator::CreateLHCalCaloHits(const CollectionMaps& collectionMaps)
+{
+    for (StringVector::const_iterator iter = m_settings.m_lHCalCaloHitCollections.begin(), iterEnd = m_settings.m_lHCalCaloHitCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloHit.find(*iter) == collectionMaps.collectionMap_CaloHit.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::CalorimeterHit>& pCaloHitCollection = (collectionMaps.collectionMap_CaloHit.find(*iter))->second;
+            const int nElements(pCaloHitCollection.size());
+
+            std::cout<<(*iter)<<"has nElements="<<nElements<<std::endl;
+            if (0 == nElements)
+                continue;
+
+            const gear::LayerLayout &endcapLayerLayout(_GEAR->getLHcalParameters().getLayerLayout());
+
+            ID_UTIL::CellIDDecoder<const edm4hep::CalorimeterHit> cellIdDecoder(m_encoder_str_LHCal);
+            const std::string layerCodingString(m_encoder_str_LHCal);
+            const std::string layerCoding(this->GetLayerCoding(layerCodingString));
+
+            for (int i = 0; i < nElements; ++i)
+            {
+                try
+                {
+                    const edm4hep::CalorimeterHit& pCaloHit0 = pCaloHitCollection.at(i);
+                    const edm4hep::CalorimeterHit* pCaloHit = &(pCaloHit0);
+
+                    if (NULL == pCaloHit)
+                        throw ("LHCal Collection type mismatch");
+
+                    PandoraApi::CaloHit::Parameters caloHitParameters;
+                    caloHitParameters.m_hitType = pandora::HCAL;
+                    caloHitParameters.m_isDigital = false;
+                    caloHitParameters.m_layer = cellIdDecoder(pCaloHit)[layerCoding.c_str()];
+                    caloHitParameters.m_isInOuterSamplingLayer = (this->GetNLayersFromEdge(pCaloHit) <= m_settings.m_nOuterSamplingLayers);
+                    this->GetCommonCaloHitProperties(pCaloHit, caloHitParameters);
+
+                    float absorberCorrection(1.);
+                    this->GetEndCapCaloHitProperties(pCaloHit, endcapLayerLayout, caloHitParameters, absorberCorrection);
+
+                    caloHitParameters.m_mipEquivalentEnergy = pCaloHit->getEnergy() * m_settings.m_hCalToMip * absorberCorrection;
+
+                    if (caloHitParameters.m_mipEquivalentEnergy.Get() < m_settings.m_hCalMipThreshold)
+                        continue;
+
+                    caloHitParameters.m_hadronicEnergy = std::min(m_settings.m_hCalToHadGeV * pCaloHit->getEnergy(), m_settings.m_maxHCalHitHadronicEnergy);
+                    caloHitParameters.m_electromagneticEnergy = m_settings.m_hCalToEMGeV * pCaloHit->getEnergy();
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*m_pPandora, caloHitParameters));
+                    m_calorimeterHitVector.push_back(const_cast<edm4hep::CalorimeterHit*>(pCaloHit));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract lhcal calo hit: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract lhcal calo hit: " << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract lhcal calo hit collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetCommonCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, PandoraApi::CaloHit::Parameters &caloHitParameters) const
+{
+    const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+    const pandora::CartesianVector positionVector(pCaloHitPosition[0], pCaloHitPosition[1], pCaloHitPosition[2]);
+
+    caloHitParameters.m_cellGeometry = pandora::RECTANGULAR;
+    caloHitParameters.m_positionVector = positionVector;
+    caloHitParameters.m_expectedDirection = positionVector.GetUnitVector();
+    caloHitParameters.m_pParentAddress = pCaloHit;
+    caloHitParameters.m_inputEnergy = pCaloHit->getEnergy();
+    caloHitParameters.m_time = pCaloHit->getTime();
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetEndCapCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+    PandoraApi::CaloHit::Parameters &caloHitParameters, float &absorberCorrection) const
+{
+    caloHitParameters.m_hitRegion = pandora::ENDCAP;
+
+    const int physicalLayer(std::min(static_cast<int>(caloHitParameters.m_layer.Get()), layerLayout.getNLayers() - 1));
+    caloHitParameters.m_cellSize0 = layerLayout.getCellSize0(physicalLayer);
+    caloHitParameters.m_cellSize1 = layerLayout.getCellSize1(physicalLayer);
+    caloHitParameters.m_cellThickness = layerLayout.getThickness(physicalLayer);
+
+    const float radiationLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    const float layerAbsorberThickness(layerLayout.getAbsorberThickness(physicalLayer));
+    caloHitParameters.m_nCellRadiationLengths = radiationLength * layerAbsorberThickness;
+    caloHitParameters.m_nCellInteractionLengths = interactionLength * layerAbsorberThickness;
+
+    if (caloHitParameters.m_nCellRadiationLengths.Get() < std::numeric_limits<float>::epsilon() || caloHitParameters.m_nCellInteractionLengths.Get() < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"WARNING CaloHitCreator::GetEndCapCaloHitProperties Calo hit has 0 radiation length or interaction length: \
+            not creating a Pandora calo hit." << std::endl;
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    absorberCorrection = 1.;
+    for (unsigned int i = 0, iMax = layerLayout.getNLayers(); i < iMax; ++i)
+    {
+        const float absorberThickness(layerLayout.getAbsorberThickness(i));
+
+        if (absorberThickness < std::numeric_limits<float>::epsilon())
+            continue;
+
+        if (layerAbsorberThickness > std::numeric_limits<float>::epsilon())
+            absorberCorrection = absorberThickness / layerAbsorberThickness;
+
+        break;
+    }
+
+    caloHitParameters.m_cellNormalVector = (pCaloHit->getPosition()[2] > 0) ? pandora::CartesianVector(0, 0, 1) :
+        pandora::CartesianVector(0, 0, -1);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void CaloHitCreator::GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const gear::LayerLayout &layerLayout,
+    unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+    float &absorberCorrection) const
+{
+    caloHitParameters.m_hitRegion = pandora::BARREL;
+
+    const int physicalLayer(std::min(static_cast<int>(caloHitParameters.m_layer.Get()), layerLayout.getNLayers() - 1));
+    caloHitParameters.m_cellSize0 = layerLayout.getCellSize0(physicalLayer);
+    caloHitParameters.m_cellSize1 = layerLayout.getCellSize1(physicalLayer);
+    caloHitParameters.m_cellThickness = layerLayout.getThickness(physicalLayer);
+
+    const float radiationLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    const float layerAbsorberThickness(layerLayout.getAbsorberThickness(physicalLayer));
+    caloHitParameters.m_nCellRadiationLengths = radiationLength * layerAbsorberThickness;
+    caloHitParameters.m_nCellInteractionLengths = interactionLength * layerAbsorberThickness;
+
+    //std::cout<<"m_layer="<<caloHitParameters.m_layer.Get()<<",layerLayout.getNLayers() - 1="<<layerLayout.getNLayers() - 1<<",layerAbsorberThickness="<<layerAbsorberThickness<<std::endl;
+    if (caloHitParameters.m_nCellRadiationLengths.Get() < std::numeric_limits<float>::epsilon() || caloHitParameters.m_nCellInteractionLengths.Get() < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"interactionLength="<<interactionLength<<",layerAbsorberThickness="<<layerAbsorberThickness<<",radiationLength="<<radiationLength<<",physicalLayer="<<physicalLayer<<",l1="<<caloHitParameters.m_layer.Get()<<",l2="<<layerLayout.getNLayers()-1<<std::endl;
+        std::cout<<"WARNIN CaloHitCreator::GetBarrelCaloHitProperties Calo hit has 0 radiation length or interaction length: \
+            not creating a Pandora calo hit." << std::endl;
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    absorberCorrection = 1.;
+    for (unsigned int i = 0, iMax = layerLayout.getNLayers(); i < iMax; ++i)
+    {
+        const float absorberThickness(layerLayout.getAbsorberThickness(i));
+
+        if (absorberThickness < std::numeric_limits<float>::epsilon())
+            continue;
+
+        if (layerAbsorberThickness > std::numeric_limits<float>::epsilon())
+            absorberCorrection = absorberThickness / layerAbsorberThickness;
+
+        break;
+    }
+
+    if (barrelSymmetryOrder > 2)
+    {
+        const float phi = barrelPhi0 + (2. * M_PI * static_cast<float>(staveNumber) / static_cast<float>(barrelSymmetryOrder));
+        caloHitParameters.m_cellNormalVector = pandora::CartesianVector(-std::sin(phi), std::cos(phi), 0);
+    }
+    else
+    {
+        const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+
+        if (pCaloHitPosition[1] != 0)
+        {
+            const float phi = barrelPhi0 + std::atan(pCaloHitPosition[0] / pCaloHitPosition[1]);
+            caloHitParameters.m_cellNormalVector = pandora::CartesianVector(std::sin(phi), std::cos(phi), 0);
+        }
+        else
+        {
+            caloHitParameters.m_cellNormalVector = (pCaloHitPosition[0] > 0) ? pandora::CartesianVector(1, 0, 0) :
+                pandora::CartesianVector(-1, 0, 0);
+        }
+    }
+}
+
+void CaloHitCreator::GetBarrelCaloHitProperties(const edm4hep::CalorimeterHit *const pCaloHit, const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer> &layerLayout,
+    unsigned int barrelSymmetryOrder, float barrelPhi0, unsigned int staveNumber, PandoraApi::CaloHit::Parameters &caloHitParameters,
+    float &absorberCorrection) const
+{
+    caloHitParameters.m_hitRegion = pandora::BARREL;
+
+    const int physicalLayer = std::max(0, int(caloHitParameters.m_layer.Get()-1) );
+    caloHitParameters.m_cellSize0 = layerLayout.at(physicalLayer).cellSize0;
+    caloHitParameters.m_cellSize1 = layerLayout.at(physicalLayer).cellSize1;
+    caloHitParameters.m_cellThickness = layerLayout.at(physicalLayer).sensitive_thickness;
+
+    const float radiationLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength((pandora::ECAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthECal :
+        (pandora::HCAL == caloHitParameters.m_hitType.Get()) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    const float layerAbsorberThickness(layerLayout.at(physicalLayer).absorberThickness);
+    caloHitParameters.m_nCellRadiationLengths   = radiationLength   * layerAbsorberThickness;
+    caloHitParameters.m_nCellInteractionLengths = interactionLength * layerAbsorberThickness;
+
+    
+    if (caloHitParameters.m_nCellRadiationLengths.Get() < std::numeric_limits<float>::epsilon() || caloHitParameters.m_nCellInteractionLengths.Get() < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"interactionLength="<<interactionLength<<",layerAbsorberThickness="<<layerAbsorberThickness<<",radiationLength="<<radiationLength<<",physicalLayer="<<physicalLayer<<",l1="<<caloHitParameters.m_layer.Get()<<",l2="<<layerLayout.size()-1<<std::endl;
+        std::cout<<"WARNIN CaloHitCreator::GetBarrelCaloHitProperties Calo hit has 0 radiation length or interaction length: \
+            not creating a Pandora calo hit." << std::endl;
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+    
+    absorberCorrection = 1.;
+    for (unsigned int i = 0, iMax = layerLayout.size(); i < iMax; ++i)
+    {
+        const float absorberThickness(layerLayout.at(i).absorberThickness);
+
+        if (absorberThickness < std::numeric_limits<float>::epsilon())
+            continue;
+
+        if (layerAbsorberThickness > std::numeric_limits<float>::epsilon())
+            absorberCorrection = absorberThickness / layerAbsorberThickness;
+
+        break;
+    }
+    if (barrelSymmetryOrder > 2)
+    {
+        float phi = barrelPhi0 + (2. * M_PI * float(staveNumber) / float(barrelSymmetryOrder));
+        caloHitParameters.m_cellNormalVector = pandora::CartesianVector(-std::sin(phi), std::cos(phi), 0);
+        //std::cout<<"barrelPhi0="<<barrelPhi0<<",phi="<<phi<<",GetX()="<<caloHitParameters.m_cellNormalVector.Get().GetX()<<",GetY()="<<caloHitParameters.m_cellNormalVector.Get().GetY()<<",GetZ()="<<caloHitParameters.m_cellNormalVector.Get().GetZ()<<std::endl;
+    }
+    else
+    {
+        const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+
+        if (pCaloHitPosition[1] != 0)
+        {
+            const float phi = barrelPhi0 + std::atan(pCaloHitPosition[0] / pCaloHitPosition[1]);
+            caloHitParameters.m_cellNormalVector = pandora::CartesianVector(std::sin(phi), std::cos(phi), 0);
+        }
+        else
+        {
+            caloHitParameters.m_cellNormalVector = (pCaloHitPosition[0] > 0) ? pandora::CartesianVector(1, 0, 0) :
+                pandora::CartesianVector(-1, 0, 0);
+        }
+    }
+}
+//------------------------------------------------------------------------------------------------------------------------------------------
+int CaloHitCreator::GetBarrelLayer(const edm4hep::CalorimeterHit *const pCaloHit, const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer> &layerLayout) const
+{
+    int layer = -1 ;   
+    for (unsigned int i = 0, iMax = layerLayout.size(); i < iMax; ++i)
+    {
+        const float distance(layerLayout.at(i).distance);
+        const float sensitive_thickness(layerLayout.at(i).sensitive_thickness);
+        if( (distance - 0.5*sensitive_thickness) <= pCaloHit->getPosition().x && pCaloHit->getPosition().x <= (distance + 0.5*sensitive_thickness)) {layer = i+1 ; break;}
+    }
+    if(layer==-1)
+    {
+        int lmax = layerLayout.size()-1;
+        std::cout<<"Error BarrelLayer, set to default 1, Hit.x="<<pCaloHit->getPosition().x<<", min_x="<<layerLayout.at(0).distance-0.5*layerLayout.at(0).sensitive_thickness<<", max_x="<<layerLayout.at(lmax).distance+0.5*layerLayout.at(lmax).sensitive_thickness<<std::endl;
+        layer = 1;
+    }
+    return layer;
+}
+
+int CaloHitCreator::GetNLayersFromEdge(const edm4hep::CalorimeterHit *const pCaloHit) const
+{
+    // Calo hit coordinate calculations
+    const float barrelMaximumRadius(this->GetMaximumRadius(pCaloHit, m_hCalBarrelOuterSymmetry, m_hCalBarrelOuterPhi0));
+    const float endCapMaximumRadius(this->GetMaximumRadius(pCaloHit, m_settings.m_hCalEndCapInnerSymmetryOrder, m_settings.m_hCalEndCapInnerPhiCoordinate));
+    const float caloHitAbsZ(std::fabs(pCaloHit->getPosition()[2]));
+
+    // Distance from radial outer
+    float radialDistanceToEdge(std::numeric_limits<float>::max());
+
+    if (caloHitAbsZ < m_eCalBarrelOuterZ)
+    {
+        radialDistanceToEdge = (m_hCalBarrelOuterR - barrelMaximumRadius) / m_hCalBarrelLayerThickness;
+    }
+    else
+    {
+        radialDistanceToEdge = (m_hCalEndCapOuterR - endCapMaximumRadius) / m_hCalEndCapLayerThickness;
+    }
+
+    // Distance from rear of endcap outer
+    float rearDistanceToEdge(std::numeric_limits<float>::max());
+
+    if (caloHitAbsZ >= m_eCalBarrelOuterZ)
+    {
+        rearDistanceToEdge = (m_hCalEndCapOuterZ - caloHitAbsZ) / m_hCalEndCapLayerThickness;
+    }
+    else
+    {
+        const float rearDistance((m_eCalBarrelOuterZ - caloHitAbsZ) / m_hCalBarrelLayerThickness);
+
+        if (rearDistance < m_settings.m_layersFromEdgeMaxRearDistance)
+        {
+            const float overlapDistance((m_hCalEndCapOuterR - endCapMaximumRadius) / m_hCalEndCapLayerThickness);
+            rearDistanceToEdge = std::max(rearDistance, overlapDistance);
+        }
+    }
+
+    return static_cast<int>(std::min(radialDistanceToEdge, rearDistanceToEdge));
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+float CaloHitCreator::GetMaximumRadius(const edm4hep::CalorimeterHit *const pCaloHit, const unsigned int symmetryOrder, const float phi0) const
+{
+    
+    const float pCaloHitPosition[3]={pCaloHit->getPosition()[0], pCaloHit->getPosition()[1], pCaloHit->getPosition()[2]};
+    if (symmetryOrder <= 2)
+        return std::sqrt((pCaloHitPosition[0] * pCaloHitPosition[0]) + (pCaloHitPosition[1] * pCaloHitPosition[1]));
+
+    float maximumRadius(0.f);
+    const float twoPi(2.f * M_PI);
+
+    for (unsigned int i = 0; i < symmetryOrder; ++i)
+    {
+        const float phi = phi0 + i * twoPi / static_cast<float>(symmetryOrder);
+        float radius = pCaloHitPosition[0] * std::cos(phi) + pCaloHitPosition[1] * std::sin(phi);
+
+        if (radius > maximumRadius)
+            maximumRadius = radius;
+    }
+
+    return maximumRadius;
+}
+
+void CaloHitCreator::GetCoding(const edm4hep::CalorimeterHit* pCaloHit, long& sys, long& x, long& y, long& z) const
+{
+    //sys = (pCaloHit->getCellID() << (64-8)) >> (64-8) ;
+    //x   = (pCaloHit->getCellID() << (64-(8+16))) >> (64-(8+16)) ;
+    //y   = (pCaloHit->getCellID() << (64-(8+16+16))) >> (64-(8+16+16)) ;
+    //z   = (pCaloHit->getCellID() << (64-(8+16+16+16))) >> (64-(8+16+16+16)) ;
+    unsigned long long id = pCaloHit->getCellID();
+    sys =  id               &  0xFF ;
+    x   = (id >> 8)         &  0xFFFF ;
+    y   = (id >> (8+16))    &  0xFFFF ;
+    z   = (id >> (8+16+16)) &  0xFFFF ;
+}
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+std::string CaloHitCreator::GetLayerCoding(const std::string &encodingString) const
+{
+    if (encodingString.find("layer") != std::string::npos)
+        return std::string("layer");
+
+    if (encodingString.find("K-1") != std::string::npos)
+        return std::string("K-1");
+
+    if (encodingString.find("K") != std::string::npos)
+        return std::string("K");
+
+    return std::string("unknown_layer_encoding");
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+std::string CaloHitCreator::GetStaveCoding(const std::string &encodingString) const
+{
+    if (encodingString.find("stave") != std::string::npos)
+        return std::string("stave");
+
+    if (encodingString.find("S-1") != std::string::npos)
+        return std::string("S-1");
+
+    return std::string("unknown_stave_encoding") ;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+CaloHitCreator::Settings::Settings() :
+    m_absorberRadLengthECal(1.f),
+    m_absorberIntLengthECal(1.f),
+    m_absorberRadLengthHCal(1.f),
+    m_absorberIntLengthHCal(1.f),
+    m_absorberRadLengthOther(1.f),
+    m_absorberIntLengthOther(1.f),
+    m_eCalToMip(1.f),
+    m_hCalToMip(1.f),
+    m_muonToMip(1.f),
+    m_eCalMipThreshold(0.f),
+    m_hCalMipThreshold(0.f),
+    m_muonMipThreshold(0.f),
+    m_eCalToEMGeV(1.f),
+    m_eCalToHadGeVBarrel(1.f),
+    m_eCalToHadGeVEndCap(1.f),
+    m_hCalToEMGeV(1.f),
+    m_hCalToHadGeV(1.f),
+    m_muonDigitalHits(1),
+    m_muonHitEnergy(0.5f),
+    m_maxHCalHitHadronicEnergy(10000.f),
+    m_nOuterSamplingLayers(3),
+    m_layersFromEdgeMaxRearDistance(250.f),
+    m_hCalEndCapInnerSymmetryOrder(4),
+    m_hCalEndCapInnerPhiCoordinate(0.f),
+    m_stripSplittingOn(0),
+    m_useEcalScLayers(0),
+    m_eCalSiToMip(1.f),
+    m_eCalScToMip(1.f),
+    m_eCalSiMipThreshold(0.f),
+    m_eCalScMipThreshold(0.f),
+    m_eCalSiToEMGeV(1.f),
+    m_eCalScToEMGeV(1.f),
+    m_eCalSiToHadGeVBarrel(1.f),
+    m_eCalScToHadGeVBarrel(1.f),
+    m_eCalSiToHadGeVEndCap(1.f),
+    m_eCalScToHadGeVEndCap(1.f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/GeometryCreator.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/GeometryCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ab6cc805b00cc2f2a74c5baecdeba10c9cb1907
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/GeometryCreator.cpp
@@ -0,0 +1,488 @@
+/**
+ *  @file   MarlinPandora/src/GeometryCreator.cc
+ * 
+ *  @brief  Implementation of the geometry creator class.
+ * 
+ *  $Log: $
+ */
+#include "GaudiKernel/IService.h"
+
+#include "GearSvc/IGearSvc.h"
+#include "gear/BField.h"
+#include "gear/GEAR.h"
+#include "gear/GearParameters.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/TPCParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/LayerLayout.h"
+
+#include "GeometryCreator.h"
+
+#include <DD4hep/Detector.h>
+#include <DDRec/DetectorData.h>
+
+GeometryCreator::GeometryCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+GeometryCreator::~GeometryCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+//pandora::StatusCode GeometryCreator::CreateGeometry() const
+//pandora::StatusCode GeometryCreator::CreateGeometry(ISvcLocator* svcloc) const
+pandora::StatusCode GeometryCreator::CreateGeometry(ISvcLocator* svcloc) 
+{
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+
+
+    IGeoSvc*  Svc = 0;
+    StatusCode sc1 = svcloc->service("GeoSvc", Svc, false);
+    if ( !sc1 )
+    {
+        throw "Failed to find GeoSvc ...";
+    }
+    m_dd4hep = Svc->lcdd();
+    
+
+    //auto _gear = service<IGearSvc>("GearSvc");
+    //if ( !_gear ) 
+    //{
+    //    throw "Failed to find GearSvc ...";
+    //}
+    //_GEAR = _gear->getGearMgr();
+    
+
+    try
+    {
+        SubDetectorTypeMap subDetectorTypeMap;
+        this->SetMandatorySubDetectorParameters(subDetectorTypeMap);
+
+        SubDetectorNameMap subDetectorNameMap;
+        this->SetAdditionalSubDetectorParameters(subDetectorNameMap);
+        
+        if (std::string::npos != _GEAR->getDetectorName().find("ILD"))
+            this->SetILDSpecificGeometry(subDetectorTypeMap, subDetectorNameMap);
+        
+        for (SubDetectorTypeMap::const_iterator iter = subDetectorTypeMap.begin(), iterEnd = subDetectorTypeMap.end(); iter != iterEnd; ++iter)
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::SubDetector::Create(*m_pPandora, iter->second));
+
+        for (SubDetectorNameMap::const_iterator iter = subDetectorNameMap.begin(), iterEnd = subDetectorNameMap.end(); iter != iterEnd; ++iter)
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::SubDetector::Create(*m_pPandora, iter->second));
+    }
+    catch (gear::Exception &exception)
+    {
+        std::cout << "Failure in marlin pandora geometry creator, gear exception: " << exception.what() << std::endl;
+        throw exception;
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetMandatorySubDetectorParameters(SubDetectorTypeMap &subDetectorTypeMap) const
+{
+    std::cout << "Begin SetMandatorySubDetectorParameters:" << std::endl;
+    PandoraApi::Geometry::SubDetector::Parameters eCalBarrelParameters, eCalEndCapParameters, hCalBarrelParameters, hCalEndCapParameters,
+        muonBarrelParameters, muonEndCapParameters;
+
+    this->SetDefaultSubDetectorParameters(m_dd4hep, "CaloDetector", pandora::ECAL_BARREL, eCalBarrelParameters);
+    //this->SetDefaultSubDetectorParameters(_GEAR->getEcalBarrelParameters(), "ECalBarrel", pandora::ECAL_BARREL, eCalBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getEcalEndcapParameters(), "ECalEndCap", pandora::ECAL_ENDCAP, eCalEndCapParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getHcalBarrelParameters(), "HCalBarrel", pandora::HCAL_BARREL, hCalBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getHcalEndcapParameters(), "HCalEndCap", pandora::HCAL_ENDCAP, hCalEndCapParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getYokeBarrelParameters(), "MuonBarrel", pandora::MUON_BARREL, muonBarrelParameters);
+    this->SetDefaultSubDetectorParameters(_GEAR->getYokeEndcapParameters(), "MuonEndCap", pandora::MUON_ENDCAP, muonEndCapParameters);
+
+    subDetectorTypeMap[pandora::ECAL_BARREL] = eCalBarrelParameters;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP] = eCalEndCapParameters;
+    subDetectorTypeMap[pandora::HCAL_BARREL] = hCalBarrelParameters;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP] = hCalEndCapParameters;
+    subDetectorTypeMap[pandora::MUON_BARREL] = muonBarrelParameters;
+    subDetectorTypeMap[pandora::MUON_ENDCAP] = muonEndCapParameters;
+
+    PandoraApi::Geometry::SubDetector::Parameters trackerParameters;
+    const gear::TPCParameters &tpcParameters(_GEAR->getTPCParameters());
+    trackerParameters.m_subDetectorName = "Tracker";
+    trackerParameters.m_subDetectorType = pandora::INNER_TRACKER;
+    trackerParameters.m_innerRCoordinate = tpcParameters.getPadLayout().getPlaneExtent()[0];
+    trackerParameters.m_innerZCoordinate = 0.f;
+    trackerParameters.m_innerPhiCoordinate = 0.f;
+    trackerParameters.m_innerSymmetryOrder = 0;
+    trackerParameters.m_outerRCoordinate = tpcParameters.getPadLayout().getPlaneExtent()[1];
+    trackerParameters.m_outerZCoordinate = tpcParameters.getMaxDriftLength();
+    trackerParameters.m_outerPhiCoordinate = 0.f;
+    trackerParameters.m_outerSymmetryOrder = 0;
+    trackerParameters.m_isMirroredInZ = true;
+    trackerParameters.m_nLayers = 0;
+    subDetectorTypeMap[pandora::INNER_TRACKER] = trackerParameters;
+
+    PandoraApi::Geometry::SubDetector::Parameters coilParameters;
+    const gear::GearParameters &gearParameters(_GEAR->getGearParameters("CoilParameters"));
+    coilParameters.m_subDetectorName = "Coil";
+    coilParameters.m_subDetectorType = pandora::COIL;
+    coilParameters.m_innerRCoordinate = gearParameters.getDoubleVal("Coil_cryostat_inner_radius");
+    coilParameters.m_innerZCoordinate = 0.f;
+    coilParameters.m_innerPhiCoordinate = 0.f;
+    coilParameters.m_innerSymmetryOrder = 0;
+    coilParameters.m_outerRCoordinate = gearParameters.getDoubleVal("Coil_cryostat_outer_radius");
+    coilParameters.m_outerZCoordinate = gearParameters.getDoubleVal("Coil_cryostat_half_z");
+    coilParameters.m_outerPhiCoordinate = 0.f;
+    coilParameters.m_outerSymmetryOrder = 0;
+    coilParameters.m_isMirroredInZ = true;
+    coilParameters.m_nLayers = 0;
+    subDetectorTypeMap[pandora::COIL] = coilParameters;
+    std::cout << "End SetMandatorySubDetectorParameters" << std::endl;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetAdditionalSubDetectorParameters(SubDetectorNameMap &subDetectorNameMap) const
+{
+    std::cout << "Begin SetAdditionalSubDetectorParameters:" << std::endl;
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getEcalPlugParameters(), "ECalPlug", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+        std::cout << " warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getHcalRingParameters(), "HCalRing", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout<< "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getLcalParameters(), "LCal", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout << "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+
+    try
+    {
+        PandoraApi::Geometry::SubDetector::Parameters parameters;
+        this->SetDefaultSubDetectorParameters(_GEAR->getLHcalParameters(), "LHCal", pandora::SUB_DETECTOR_OTHER, parameters);
+        subDetectorNameMap[parameters.m_subDetectorName.Get()] = parameters;
+    }
+    catch (gear::Exception &exception)
+    {
+         std::cout << "warning pandora geometry creator: " << exception.what() << std::endl;
+    }
+    std::cout << "End SetAdditionalSubDetectorParameters" << std::endl;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void GeometryCreator::SetDefaultSubDetectorParameters(const gear::CalorimeterParameters &inputParameters, const std::string &subDetectorName,
+    const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const
+{
+    const gear::LayerLayout &layerLayout = inputParameters.getLayerLayout();
+
+    parameters.m_subDetectorName = subDetectorName;
+    parameters.m_subDetectorType = subDetectorType;
+    parameters.m_innerRCoordinate = inputParameters.getExtent()[0];
+    parameters.m_innerZCoordinate = inputParameters.getExtent()[2];
+    parameters.m_innerPhiCoordinate = inputParameters.getPhi0();
+    parameters.m_innerSymmetryOrder = inputParameters.getSymmetryOrder();
+    parameters.m_outerRCoordinate = inputParameters.getExtent()[1];
+    parameters.m_outerZCoordinate = inputParameters.getExtent()[3];
+    parameters.m_outerPhiCoordinate = inputParameters.getPhi0();
+    parameters.m_outerSymmetryOrder = inputParameters.getSymmetryOrder();
+    parameters.m_isMirroredInZ = true;
+    parameters.m_nLayers = layerLayout.getNLayers();
+    std::cout << "inputParameters.getExtent()[0]="<<inputParameters.getExtent()[0]<<",inputParameters.getExtent()[1]="<<inputParameters.getExtent()[1]<<",inputParameters.getExtent()[2]="<<inputParameters.getExtent()[2]<<",inputParameters.getExtent()[3]="<<inputParameters.getExtent()[3]<< std::endl;
+
+    // ATTN Not always going to be correct for any optional subdetectors, but impact of this is negligible for ILD
+    const float radiationLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+
+    for (int i = 0; i < layerLayout.getNLayers(); ++i)
+    {
+        PandoraApi::Geometry::LayerParameters layerParameters;
+        layerParameters.m_closestDistanceToIp = layerLayout.getDistance(i) + (0.5 * (layerLayout.getThickness(i) + layerLayout.getAbsorberThickness(i)));
+        layerParameters.m_nRadiationLengths = radiationLength * layerLayout.getAbsorberThickness(i);
+        layerParameters.m_nInteractionLengths = interactionLength * layerLayout.getAbsorberThickness(i);
+        parameters.m_layerParametersVector.push_back(layerParameters);
+    }
+}
+
+void GeometryCreator::SetDefaultSubDetectorParameters(const dd4hep::Detector* theDetector , const std::string &subDetectorName,
+    const pandora::SubDetectorType subDetectorType, PandoraApi::Geometry::SubDetector::Parameters &parameters) const
+{
+    //const std::vector< dd4hep::DetElement > &detElements = theDetector.detectors("EcalMatrix", true);
+    const dd4hep::DetElement &detElement = theDetector->detector(subDetectorName);
+    dd4hep::rec::LayeredCalorimeterData* Data = detElement.extension<dd4hep::rec::LayeredCalorimeterData>() ;
+ 
+
+    parameters.m_subDetectorName    = subDetectorName;
+    parameters.m_subDetectorType    = subDetectorType;
+    parameters.m_innerRCoordinate   = Data->extent[0];
+    parameters.m_innerZCoordinate   = Data->extent[2];
+    parameters.m_innerPhiCoordinate = Data->inner_phi0;
+    parameters.m_innerSymmetryOrder = Data->inner_symmetry;
+    parameters.m_outerRCoordinate   = Data->extent[1];
+    parameters.m_outerZCoordinate   = Data->extent[3];
+    parameters.m_outerPhiCoordinate = Data->outer_phi0;
+    parameters.m_outerSymmetryOrder = Data->outer_symmetry;
+    parameters.m_nLayers            = Data->layers.size();
+    parameters.m_isMirroredInZ      = true;
+    const std::vector<dd4hep::rec::LayeredCalorimeterData::Layer>& layers= Data->layers;
+    std::cout << "Extent()[0]="<<Data->extent[0]<<",Extent()[1]="<<Data->extent[1]<<",Extent()[2]="<<Data->extent[2]<<",Extent()[3]="<<Data->extent[3]<< std::endl;
+
+    // ATTN Not always going to be correct for any optional subdetectors, but impact of this is negligible for ILD
+    const float radiationLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberRadLengthHCal : m_settings.m_absorberRadLengthOther);
+    const float interactionLength(((pandora::ECAL_BARREL == subDetectorType) || (pandora::ECAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthECal :
+        ((pandora::HCAL_BARREL == subDetectorType) || (pandora::HCAL_ENDCAP == subDetectorType)) ? m_settings.m_absorberIntLengthHCal : m_settings.m_absorberIntLengthOther);
+   
+    //for (int i = 0; i < layerLayout.getNLayers(); ++i)
+    for (auto const& layer : layers)
+    {
+        PandoraApi::Geometry::LayerParameters layerParameters;
+        //layerParameters.m_closestDistanceToIp = layer.distance + 0.5 * layer.sensitive_thickness;//Thickness of the sensitive element (e.g. scintillator)
+        layerParameters.m_closestDistanceToIp = layer.distance ;
+        layerParameters.m_nRadiationLengths   = radiationLength   * layer.absorberThickness;
+        layerParameters.m_nInteractionLengths = interactionLength * layer.absorberThickness;
+        std::cout<<"m_closestDistanceToIp="<<layerParameters.m_closestDistanceToIp.Get()<<",m_nRadiationLengths="<<layerParameters.m_nRadiationLengths.Get()<<",m_nInteractionLengths="<<layerParameters.m_nInteractionLengths.Get()<<std::endl;
+        parameters.m_layerParametersVector.push_back(layerParameters);
+    }
+}
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::SetILDSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap, SubDetectorNameMap &subDetectorNameMap) const
+{
+    // Set positions of gaps in ILD detector and add information missing from GEAR parameters file
+    try
+    {
+        const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+        subDetectorTypeMap[pandora::HCAL_BARREL].m_outerPhiCoordinate = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_phi0");
+        subDetectorTypeMap[pandora::HCAL_BARREL].m_outerSymmetryOrder = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order");
+    }
+    catch (gear::Exception &)
+    {
+        // aLaVideauGeometry
+        return this->SetILD_SDHCALSpecificGeometry(subDetectorTypeMap);
+    }
+
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_eCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_eCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_eCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_eCalEndCapOuterPhiCoordinate;
+
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_hCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_hCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_hCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_hCalEndCapOuterPhiCoordinate;
+
+    subDetectorNameMap["HCalRing"].m_innerSymmetryOrder = m_settings.m_hCalRingInnerSymmetryOrder;
+    subDetectorNameMap["HCalRing"].m_innerPhiCoordinate = m_settings.m_hCalRingInnerPhiCoordinate;
+    subDetectorNameMap["HCalRing"].m_outerSymmetryOrder = m_settings.m_hCalRingOuterSymmetryOrder;
+    subDetectorNameMap["HCalRing"].m_outerPhiCoordinate = m_settings.m_hCalRingOuterPhiCoordinate;
+
+    // Gaps in detector active material
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalBarrelBoxGaps());
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalEndCapBoxGaps());
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateHCalBarrelConcentricGaps());
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::SetILD_SDHCALSpecificGeometry(SubDetectorTypeMap &subDetectorTypeMap) const
+{
+    // Non-default values (and those missing from GEAR parameters file)...
+    // The following 2 parameters have no sense for Videau Geometry, set them to 0
+    subDetectorTypeMap[pandora::HCAL_BARREL].m_outerPhiCoordinate = 0;
+    subDetectorTypeMap[pandora::HCAL_BARREL].m_outerSymmetryOrder = 0;
+
+    // Endcap is identical to standard ILD geometry, only HCAL barrel is different
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_eCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_eCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_eCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::ECAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_eCalEndCapOuterPhiCoordinate;
+
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerSymmetryOrder = m_settings.m_hCalEndCapInnerSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_innerPhiCoordinate = m_settings.m_hCalEndCapInnerPhiCoordinate;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerSymmetryOrder = m_settings.m_hCalEndCapOuterSymmetryOrder;
+    subDetectorTypeMap[pandora::HCAL_ENDCAP].m_outerPhiCoordinate = m_settings.m_hCalEndCapOuterPhiCoordinate;
+
+    // TODO implement gaps between modules
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalBarrelBoxGaps() const
+{
+    const std::string detectorName(_GEAR->getDetectorName());
+
+    const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+    const unsigned int innerSymmetryOrder(hCalBarrelParameters.getSymmetryOrder());
+    const unsigned int outerSymmetryOrder(hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order"));
+
+    if ((0 == innerSymmetryOrder) || (2 != outerSymmetryOrder / innerSymmetryOrder))
+    {
+        std::cout << " Detector " << detectorName << " doesn't conform to expected ILD-specific geometry" << std::endl;
+        return pandora::STATUS_CODE_INVALID_PARAMETER;
+    }
+
+    const float innerRadius(hCalBarrelParameters.getExtent()[0]);
+    const float outerRadius(hCalBarrelParameters.getExtent()[1]);
+    const float outerZ(hCalBarrelParameters.getExtent()[3]);
+    const float phi0(hCalBarrelParameters.getPhi0());
+
+    const float staveGap(hCalBarrelParameters.getDoubleVal("Hcal_stave_gaps"));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(innerSymmetryOrder, phi0, innerRadius, outerRadius,
+        -outerZ, outerZ, staveGap));
+
+    const float outerPseudoPhi0(M_PI / static_cast<float>(innerSymmetryOrder));
+    const float cosOuterPseudoPhi0(std::cos(outerPseudoPhi0));
+
+    if ((0 == outerPseudoPhi0) || (0.f == cosOuterPseudoPhi0))
+    {
+        std::cout << " Detector " << detectorName << " doesn't conform to expected ILD-specific geometry" << std::endl;
+        return pandora::STATUS_CODE_INVALID_PARAMETER;
+    }
+
+    const float middleStaveGap(hCalBarrelParameters.getDoubleVal("Hcal_middle_stave_gaps"));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(innerSymmetryOrder, outerPseudoPhi0,
+        innerRadius / cosOuterPseudoPhi0, outerRadius, -outerZ, outerZ, middleStaveGap));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalEndCapBoxGaps() const
+{
+    const gear::CalorimeterParameters &hCalEndCapParameters = _GEAR->getHcalEndcapParameters();
+
+    const float staveGap(hCalEndCapParameters.getDoubleVal("Hcal_stave_gaps"));
+    const float innerRadius(hCalEndCapParameters.getExtent()[0]);
+    const float outerRadius(hCalEndCapParameters.getExtent()[1]);
+    const float innerZ(hCalEndCapParameters.getExtent()[2]);
+    const float outerZ(hCalEndCapParameters.getExtent()[3]);
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(m_settings.m_hCalEndCapInnerSymmetryOrder,
+        m_settings.m_hCalEndCapInnerPhiCoordinate, innerRadius, outerRadius, innerZ, outerZ, staveGap,
+        pandora::CartesianVector(-innerRadius, 0, 0)));
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CreateRegularBoxGaps(m_settings.m_hCalEndCapInnerSymmetryOrder,
+        m_settings.m_hCalEndCapInnerPhiCoordinate, innerRadius, outerRadius, -outerZ, -innerZ, staveGap,
+        pandora::CartesianVector(innerRadius, 0, 0)));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateHCalBarrelConcentricGaps() const
+{
+    const gear::CalorimeterParameters &hCalBarrelParameters = _GEAR->getHcalBarrelParameters();
+    const float gapWidth(hCalBarrelParameters.getDoubleVal("Hcal_stave_gaps"));
+
+    PandoraApi::Geometry::ConcentricGap::Parameters gapParameters;
+
+    gapParameters.m_minZCoordinate = -0.5f * gapWidth;
+    gapParameters.m_maxZCoordinate =  0.5f * gapWidth;
+    gapParameters.m_innerRCoordinate = hCalBarrelParameters.getExtent()[0];
+    gapParameters.m_innerPhiCoordinate = hCalBarrelParameters.getPhi0();
+    gapParameters.m_innerSymmetryOrder = hCalBarrelParameters.getSymmetryOrder();
+    gapParameters.m_outerRCoordinate = hCalBarrelParameters.getExtent()[1];
+    gapParameters.m_outerPhiCoordinate = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_phi0");
+    gapParameters.m_outerSymmetryOrder = hCalBarrelParameters.getIntVal("Hcal_outer_polygon_order");
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::ConcentricGap::Create(*m_pPandora, gapParameters));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode GeometryCreator::CreateRegularBoxGaps(unsigned int symmetryOrder, float phi0, float innerRadius, float outerRadius,
+    float minZ, float maxZ, float gapWidth, pandora::CartesianVector vertexOffset) const
+{
+    const pandora::CartesianVector basicGapVertex(pandora::CartesianVector(-0.5f * gapWidth, innerRadius, minZ) + vertexOffset);
+    const pandora::CartesianVector basicSide1(gapWidth, 0, 0);
+    const pandora::CartesianVector basicSide2(0, outerRadius - innerRadius, 0);
+    const pandora::CartesianVector basicSide3(0, 0, maxZ - minZ);
+
+    for (unsigned int i = 0; i < symmetryOrder; ++i)
+    {
+        const float phi = phi0 + (2. * M_PI * static_cast<float>(i) / static_cast<float>(symmetryOrder));
+        const float sinPhi(std::sin(phi));
+        const float cosPhi(std::cos(phi));
+
+        PandoraApi::Geometry::BoxGap::Parameters gapParameters;
+
+        gapParameters.m_vertex = pandora::CartesianVector(cosPhi * basicGapVertex.GetX() + sinPhi * basicGapVertex.GetY(),
+            -sinPhi * basicGapVertex.GetX() + cosPhi * basicGapVertex.GetY(), basicGapVertex.GetZ());
+        gapParameters.m_side1 = pandora::CartesianVector(cosPhi * basicSide1.GetX() + sinPhi * basicSide1.GetY(),
+            -sinPhi * basicSide1.GetX() + cosPhi * basicSide1.GetY(), basicSide1.GetZ());
+        gapParameters.m_side2 = pandora::CartesianVector(cosPhi * basicSide2.GetX() + sinPhi * basicSide2.GetY(),
+            -sinPhi * basicSide2.GetX() + cosPhi * basicSide2.GetY(), basicSide2.GetZ());
+        gapParameters.m_side3 = pandora::CartesianVector(cosPhi * basicSide3.GetX() + sinPhi * basicSide3.GetY(),
+            -sinPhi * basicSide3.GetX() + cosPhi * basicSide3.GetY(), basicSide3.GetZ());
+
+        PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::BoxGap::Create(*m_pPandora, gapParameters));
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+GeometryCreator::Settings::Settings() :
+    m_absorberRadLengthECal(1.f),
+    m_absorberIntLengthECal(1.f),
+    m_absorberRadLengthHCal(1.f),
+    m_absorberIntLengthHCal(1.f),
+    m_absorberRadLengthOther(1.f),
+    m_absorberIntLengthOther(1.f),
+    m_eCalEndCapInnerSymmetryOrder(4),
+    m_eCalEndCapInnerPhiCoordinate(0.f),
+    m_eCalEndCapOuterSymmetryOrder(8),
+    m_eCalEndCapOuterPhiCoordinate(0.f),
+    m_hCalEndCapInnerSymmetryOrder(4),
+    m_hCalEndCapInnerPhiCoordinate(0.f),
+    m_hCalEndCapOuterSymmetryOrder(16),
+    m_hCalEndCapOuterPhiCoordinate(0.f),
+    m_hCalRingInnerSymmetryOrder(8),
+    m_hCalRingInnerPhiCoordinate(0.f),
+    m_hCalRingOuterSymmetryOrder(16),
+    m_hCalRingOuterPhiCoordinate(0.f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/MCParticleCreator.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/MCParticleCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..21a2a741bcc28617dba766d43600ee1f818ded8e
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/MCParticleCreator.cpp
@@ -0,0 +1,372 @@
+/**
+ *  @file   MarlinPandora/src/MCParticleCreator.cc
+ * 
+ *  @brief  Implementation of the mc particle creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "edm4hep/MCParticleConst.h"
+#include "edm4hep/MCParticle.h" 
+#include "edm4hep/MCRecoCaloAssociation.h" 
+#include "edm4hep/SimCalorimeterHitConst.h" 
+#include "edm4hep/CaloHitContributionConst.h" 
+#include "edm4hep/Track.h" 
+#include "edm4hep/MCRecoTrackerAssociation.h" 
+#include "edm4hep/SimTrackerHitConst.h" 
+
+
+
+
+#include "PandoraMatrixAlg.h"
+#include "MCParticleCreator.h"
+
+#include <cmath>
+#include <limits>
+#include <assert.h>
+
+MCParticleCreator::MCParticleCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora),
+    m_bField(settings.m_bField)
+{
+m_id_pMC_map = new std::map<unsigned int, const edm4hep::MCParticle*>;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+MCParticleCreator::~MCParticleCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode MCParticleCreator::CreateMCParticles(const CollectionMaps& collectionMaps ) const
+{
+    for (StringVector::const_iterator iter = m_settings.m_mcParticleCollections.begin(), iterEnd = m_settings.m_mcParticleCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_MC.find(*iter) == collectionMaps.collectionMap_MC.end()) continue;
+        try
+        {
+            const std::vector<edm4hep::MCParticle>& pMCParticleCollection = (collectionMaps.collectionMap_MC.find(*iter))->second;
+            std::cout<<"Do CreateMCParticles, collection:"<<(*iter)<<", size="<<pMCParticleCollection.size()<<std::endl;
+            for (int im = 0; im < pMCParticleCollection.size(); im++)
+            {
+                try
+                {
+                    const edm4hep::MCParticle& pMcParticle = pMCParticleCollection.at(im);
+                    PandoraApi::MCParticle::Parameters mcParticleParameters;
+                    mcParticleParameters.m_energy =   sqrt(pMcParticle.getMomentum()[0] * pMcParticle.getMomentum()[0] + pMcParticle.getMomentum()[1] * pMcParticle.getMomentum()[1] + pMcParticle.getMomentum()[2] * pMcParticle.getMomentum()[2] + pMcParticle.getMass() * pMcParticle.getMass());
+                    mcParticleParameters.m_particleId = pMcParticle.getPDG();
+                    mcParticleParameters.m_mcParticleType = pandora::MC_3D;
+                    mcParticleParameters.m_pParentAddress = &pMcParticle;
+                    unsigned int p_id = pMcParticle.id();
+                    const edm4hep::MCParticle* p_mc = &pMcParticle;
+                    (*m_id_pMC_map) [p_id]   = p_mc;
+                    mcParticleParameters.m_momentum = pandora::CartesianVector(pMcParticle.getMomentum()[0], pMcParticle.getMomentum()[1],
+                        pMcParticle.getMomentum()[2]);
+                    mcParticleParameters.m_vertex = pandora::CartesianVector(pMcParticle.getVertex()[0], pMcParticle.getVertex()[1],
+                        pMcParticle.getVertex()[2]);
+                    mcParticleParameters.m_endpoint = pandora::CartesianVector(pMcParticle.getEndpoint()[0], pMcParticle.getEndpoint()[1],
+                        pMcParticle.getEndpoint()[2]);
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::MCParticle::Create(*m_pPandora, mcParticleParameters));
+
+                    // Create parent-daughter relationships
+                    for(std::vector<edm4hep::ConstMCParticle>::const_iterator itDaughter = pMcParticle.daughters_begin(),
+                        itDaughterEnd = pMcParticle.daughters_end(); itDaughter != itDaughterEnd; ++itDaughter)
+                    {   
+                        for (int ida = 0; ida < pMCParticleCollection.size(); ida++)
+                        {
+                           if(pMCParticleCollection.at(ida).id()==(*itDaughter).id())
+                           {
+                              
+                                const edm4hep::MCParticle& dMcParticle = pMCParticleCollection.at(ida);
+                                if(&pMcParticle == &dMcParticle){std::cout<< "error, mother and daughter are the same mc particle, don't save SetMCParentDaughterRelationship"<<std::endl;}
+                                else PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetMCParentDaughterRelationship(*m_pPandora, &pMcParticle, &dMcParticle));
+                                break;
+                           }
+                        }
+                    }
+                    
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout << "Failed to extract MCParticle: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract MCParticle: " <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract MCParticles collection: " << *iter << ", " <<  std::endl;
+        }
+    }
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode MCParticleCreator::CreateTrackToMCParticleRelationships(const EVENT::LCEvent *const pLCEvent, const TrackVector &trackVector) const
+{
+    for (StringVector::const_iterator iter = m_settings.m_lcTrackRelationCollections.begin(), iterEnd = m_settings.m_lcTrackRelationCollections.end();
+         iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pMCRelationCollection = pLCEvent->getCollection(*iter);
+            UTIL::LCRelationNavigator navigate(pMCRelationCollection);
+
+            for (TrackVector::const_iterator trackIter = trackVector.begin(), trackIterEnd = trackVector.end();
+                trackIter != trackIterEnd; ++trackIter)
+            {
+                try
+                {
+                    EVENT::Track *pTrack = *trackIter;
+                    const EVENT::LCObjectVec &objectVec = navigate.getRelatedToObjects(*trackIter);
+
+                    // Get reconstructed momentum at dca
+                    const pandora::Helix helixFit(pTrack->getPhi(), pTrack->getD0(), pTrack->getZ0(), pTrack->getOmega(), pTrack->getTanLambda(), m_bField);
+                    const float recoMomentum(helixFit.GetMomentum().GetMagnitude());
+
+                    // Use momentum magnitude to identify best mc particle
+                    MCParticle *pBestMCParticle = NULL;
+                    float bestDeltaMomentum(std::numeric_limits<float>::max());
+
+                    for (EVENT::LCObjectVec::const_iterator itRel = objectVec.begin(), itRelEnd = objectVec.end(); itRel != itRelEnd; ++itRel)
+                    {
+                        EVENT::MCParticle *pMCParticle = NULL;
+                        pMCParticle = dynamic_cast<MCParticle *>(*itRel);
+
+                        if (NULL == pMCParticle)
+                            continue;
+
+                        const float trueMomentum(pandora::CartesianVector(pMCParticle->getMomentum()[0], pMCParticle->getMomentum()[1],
+                            pMCParticle->getMomentum()[2]).GetMagnitude());
+
+                        const float deltaMomentum(std::fabs(recoMomentum - trueMomentum));
+
+                        if (deltaMomentum < bestDeltaMomentum)
+                        {
+                            pBestMCParticle = pMCParticle;
+                            bestDeltaMomentum = deltaMomentum;
+                        }
+                    }
+
+                    if (NULL == pBestMCParticle)
+                        continue;
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackToMCParticleRelationship(*m_pPandora, pTrack,
+                        pBestMCParticle));
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    streamlog_out(ERROR) << "Failed to extract track to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract track to mc particle relationship: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract track to mc particle relationships collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode MCParticleCreator::CreateCaloHitToMCParticleRelationships(const EVENT::LCEvent *const pLCEvent, const CalorimeterHitVector &calorimeterHitVector) const
+{
+    typedef std::map<MCParticle *, float> MCParticleToEnergyWeightMap;
+    MCParticleToEnergyWeightMap mcParticleToEnergyWeightMap;
+
+    for (StringVector::const_iterator iter = m_settings.m_lcCaloHitRelationCollections.begin(), iterEnd = m_settings.m_lcCaloHitRelationCollections.end();
+         iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pMCRelationCollection = pLCEvent->getCollection(*iter);
+            UTIL::LCRelationNavigator navigate(pMCRelationCollection);
+
+            for (CalorimeterHitVector::const_iterator caloHitIter = calorimeterHitVector.begin(),
+                caloHitIterEnd = calorimeterHitVector.end(); caloHitIter != caloHitIterEnd; ++caloHitIter)
+            {
+                try
+                {
+                    mcParticleToEnergyWeightMap.clear();
+                    const EVENT::LCObjectVec &objectVec = navigate.getRelatedToObjects(*caloHitIter);
+
+                    for (EVENT::LCObjectVec::const_iterator itRel = objectVec.begin(), itRelEnd = objectVec.end(); itRel != itRelEnd; ++itRel)
+                    {
+                        EVENT::SimCalorimeterHit *pSimHit = dynamic_cast<SimCalorimeterHit *>(*itRel);
+
+                        if (NULL == pSimHit)
+                            continue;
+
+                        for (int iCont = 0, iEnd = pSimHit->getNMCContributions(); iCont < iEnd; ++iCont)
+                        {
+                            mcParticleToEnergyWeightMap[pSimHit->getParticleCont(iCont)] += pSimHit->getEnergyCont(iCont);
+                        }
+                    }
+
+                    for (MCParticleToEnergyWeightMap::const_iterator mcParticleIter = mcParticleToEnergyWeightMap.begin(),
+                        mcParticleIterEnd = mcParticleToEnergyWeightMap.end(); mcParticleIter != mcParticleIterEnd; ++mcParticleIter)
+                    {
+                        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetCaloHitToMCParticleRelationship(*m_pPandora,
+                            *caloHitIter, mcParticleIter->first, mcParticleIter->second));
+                    }
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    streamlog_out(ERROR) << "Failed to extract calo hit to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract calo hit to mc particle relationship: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract calo hit to mc particle relationships collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+
+//-------------- using sim calo hit and digi calo hit, no weight here---------------------------------------------------------------------------------------------------------------
+pandora::StatusCode MCParticleCreator::CreateCaloHitToMCParticleRelationships(const CollectionMaps& collectionMaps, const CalorimeterHitVector &calorimeterHitVector) const
+{
+    std::cout<<"Do CreateCaloHitToMCParticleRelationships"<<std::endl;
+    typedef std::map<const edm4hep::MCParticle *, float> MCParticleToEnergyWeightMap;
+    MCParticleToEnergyWeightMap mcParticleToEnergyWeightMap;
+
+    for (StringVector::const_iterator iter = m_settings.m_CaloHitRelationCollections.begin(), iterEnd = m_settings.m_CaloHitRelationCollections.end();
+         iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_CaloRel.find(*iter) == collectionMaps.collectionMap_CaloRel.end()) continue;
+        try
+        {
+            const std::vector<edm4hep::MCRecoCaloAssociation>& pMCRecoCaloAssociationCollection = (collectionMaps.collectionMap_CaloRel.find(*iter))->second;
+
+            for (unsigned i_calo=0; i_calo < calorimeterHitVector.size(); i_calo++)
+            {
+                try
+                {
+                    mcParticleToEnergyWeightMap.clear();
+                    for(unsigned ic=0; ic < pMCRecoCaloAssociationCollection.size(); ic++)
+                    {
+                        if( pMCRecoCaloAssociationCollection.at(ic).getRec().id() != (*(calorimeterHitVector.at(i_calo))).id() ) continue;
+                        
+                        const edm4hep::ConstSimCalorimeterHit pSimHit = pMCRecoCaloAssociationCollection.at(ic).getSim();
+                        for (int iCont = 0, iEnd = pSimHit.contributions_size(); iCont < iEnd; ++iCont)
+                        {
+                            edm4hep::ConstCaloHitContribution conb = pSimHit.getContributions(iCont);
+                            const edm4hep::ConstMCParticle ipa = conb.getParticle();
+                            float  ien = conb.getEnergy();
+                            if( m_id_pMC_map->find(ipa.id()) == m_id_pMC_map->end() ) continue;
+                            const edm4hep::MCParticle * p_tmp = (*m_id_pMC_map)[ipa.id()]; 
+                            mcParticleToEnergyWeightMap[p_tmp] += ien;
+                        }
+                        
+                    }
+
+                    for (MCParticleToEnergyWeightMap::const_iterator mcParticleIter = mcParticleToEnergyWeightMap.begin(),
+                        mcParticleIterEnd = mcParticleToEnergyWeightMap.end(); mcParticleIter != mcParticleIterEnd; ++mcParticleIter)
+                    {
+                        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetCaloHitToMCParticleRelationship(*m_pPandora,
+                            calorimeterHitVector.at(i_calo), mcParticleIter->first, mcParticleIter->second));
+                    }
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"ERROR Failed to extract calo hit to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout<<"WARNING Failed to extract calo hit to mc particle relationship " << std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<<"DEBUG5 Failed to extract calo hit to mc particle relationships collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+//-------------- using sim tracker hit and tracker hit, no weight here---------------------------------------------------------------------------------------------------------------
+pandora::StatusCode MCParticleCreator::CreateTrackToMCParticleRelationships(const CollectionMaps& collectionMaps, const TrackVector &trackVector) const
+{
+    std::cout<<"Do CreateTrackToMCParticleRelationships"<<std::endl;
+    for (unsigned ik = 0; ik < trackVector.size(); ik++)
+    {
+        const edm4hep::Track *pTrack = trackVector.at(ik);
+        // Get reconstructed momentum at dca
+        const pandora::Helix helixFit(pTrack->getTrackStates(0).phi, pTrack->getTrackStates(0).D0, pTrack->getTrackStates(0).Z0, pTrack->getTrackStates(0).omega, pTrack->getTrackStates(0).tanLambda, m_bField);
+        const float recoMomentum(helixFit.GetMomentum().GetMagnitude());
+        // Use momentum magnitude to identify best mc particle
+        edm4hep::MCParticle *pBestMCParticle = NULL;
+        float bestDeltaMomentum(std::numeric_limits<float>::max());
+        try
+        {
+            for (StringVector::const_iterator iter = m_settings.m_TrackRelationCollections.begin(), iterEnd = m_settings.m_TrackRelationCollections.end(); iter != iterEnd; ++iter)
+            {
+                if(collectionMaps.collectionMap_TrkRel.find(*iter) == collectionMaps.collectionMap_TrkRel.end()) continue;
+                const std::vector<edm4hep::MCRecoTrackerAssociation>& pMCRecoTrackerAssociationCollection = (collectionMaps.collectionMap_TrkRel.find(*iter))->second;
+                for(unsigned ith=0 ; ith<pTrack->trackerHits_size(); ith++)
+                {
+                    for(unsigned ic=0; ic < pMCRecoTrackerAssociationCollection.size(); ic++)
+                    {
+                        if( pMCRecoTrackerAssociationCollection.at(ic).getRec().id() != pTrack->getTrackerHits(ith).id() ) continue;
+                        const edm4hep::ConstSimTrackerHit pSimHit = pMCRecoTrackerAssociationCollection.at(ic).getSim();
+                        const edm4hep::ConstMCParticle ipa = pSimHit.getMCParticle();
+                        if( m_id_pMC_map->find(ipa.id()) == m_id_pMC_map->end() ) continue;
+                        const float trueMomentum(pandora::CartesianVector(ipa.getMomentum()[0], ipa.getMomentum()[1], ipa.getMomentum()[2]).GetMagnitude());
+                        const float deltaMomentum(std::fabs(recoMomentum - trueMomentum));
+                        if (deltaMomentum < bestDeltaMomentum)
+                        {
+                            pBestMCParticle =const_cast<edm4hep::MCParticle*>((*m_id_pMC_map)[ipa.id()]);
+                            bestDeltaMomentum = deltaMomentum;
+                        }
+                    }
+                }
+            }
+            
+            if (NULL == pBestMCParticle) continue;
+            PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackToMCParticleRelationship(*m_pPandora, pTrack, pBestMCParticle));
+        }
+        catch (pandora::StatusCodeException &statusCodeException)
+        {
+            std::cout<<"ERROR Failed to extract track to mc particle relationship: " << statusCodeException.ToString() << std::endl;
+        }
+        catch (...)
+        {
+            std::cout<<"WARNING Failed to extract track to mc particle relationship: " << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+MCParticleCreator::Settings::Settings()
+{
+}
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/PandoraMatrixAlg.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/PandoraMatrixAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..566f61e5b116ba626db23dba934b495e3f2e8b8d
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/PandoraMatrixAlg.cpp
@@ -0,0 +1,958 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+#include "GearSvc/IGearSvc.h"
+#include "PandoraMatrixAlg.h"
+#include "EventSeeder/IEventSeeder.h"
+#include "edm4hep/Vector3f.h"
+#include "edm4hep/Vector3d.h"
+#include "edm4hep/SimCalorimeterHit.h"
+#include "edm4hep/CaloHitContribution.h"
+#include "edm4hep/ClusterConst.h"
+#include "UTIL/ILDConf.h"
+#include <cmath>
+#include <algorithm>
+#include "gear/BField.h"
+#include <gear/GEAR.h>
+
+#include "LCContent.h"
+
+#include "TInterpreter.h"
+
+pandora::Pandora* PandoraMatrixAlg::m_pPandora=0;
+
+DECLARE_COMPONENT( PandoraMatrixAlg )
+
+template<typename T ,typename T1>
+StatusCode getCol(T & t, T1 & t1)
+{
+    try {
+        t1 = t.get();
+    }
+    catch ( GaudiException &e ) {
+        std::cout << "Collection " << t.fullKey() << " is unavailable in event "  << std::endl;
+    }
+    return StatusCode::SUCCESS;
+}
+
+
+
+PandoraMatrixAlg::PandoraMatrixAlg(const std::string& name, ISvcLocator* svcLoc)
+  : GaudiAlgorithm(name, svcLoc),
+    _nEvt(0)
+{
+ m_CollectionMaps = new CollectionMaps();
+  
+ declareProperty("ReadMCParticle"                      , m_mcParCol_r,                        "Handle of the MCParticle    input collection" );
+ declareProperty("ReadECALBarrel"                      , m_ECALBarrel_r,                      "Handle of the ECALBarrel    input collection" );
+ declareProperty("ReadECALEndcap"                      , m_ECALEndcap_r,                      "Handle of the ECALEndcap    input collection" );
+ declareProperty("ReadECALOther"                       , m_ECALOther_r,                       "Handle of the ECALOther     input collection" );
+ declareProperty("ReadHCALBarrel"                      , m_HCALBarrel_r,                      "Handle of the HCALBarrel    input collection" );
+ declareProperty("ReadHCALEndcap"                      , m_HCALEndcap_r,                      "Handle of the HCALEndcap    input collection" );
+ declareProperty("ReadHCALOther"                       , m_HCALOther_r,                       "Handle of the HCALOther     input collection" );
+ declareProperty("ReadMUON"                            , m_MUON_r,                            "Handle of the MUON          input collection" );
+ declareProperty("ReadLCAL"                            , m_LCAL_r,                            "Handle of the LCAL          input collection" );
+ declareProperty("ReadLHCAL"                           , m_LHCAL_r,                           "Handle of the LHCAL         input collection" );
+ declareProperty("ReadBCAL"                            , m_BCAL_r,                            "Handle of the BCAL          input collection" );
+ declareProperty("ReadKinkVertices"                    , m_KinkVertices_r,                    "Handle of the KinkVertices  input collection" );
+ declareProperty("ReadProngVertices"                   , m_ProngVertices_r,                   "Handle of the ProngVertices input collection" );
+ declareProperty("ReadSplitVertices"                   , m_SplitVertices_r,                   "Handle of the SplitVertices input collection" );
+ declareProperty("ReadV0Vertices"                      , m_V0Vertices_r,                      "Handle of the V0Vertices    input collection" );
+ declareProperty("ReadTracks"                          , m_MarlinTrkTracks_r,                 "Handle of the Tracks        input collection" );
+ declareProperty("MCRecoCaloAssociation"               , m_MCRecoCaloAssociation_r,           "Handle of the MCRecoCaloAssociation input collection" );
+ declareProperty("MCRecoTrackerAssociation"            , m_MCRecoTrackerAssociation_r,        "Handle of the MCRecoTrackerAssociation input collection" );
+ declareProperty("WriteClusterCollection"              , m_ClusterCollection_w,               "Handle of the ClusterCollection               output collection" );
+ declareProperty("WriteReconstructedParticleCollection", m_ReconstructedParticleCollection_w, "Handle of the ReconstructedParticleCollection output collection" );
+ declareProperty("WriteVertexCollection"               , m_VertexCollection_w,                "Handle of the VertexCollection                output collection" );
+
+}
+
+
+void PandoraMatrixAlg::FinaliseSteeringParameters(ISvcLocator* svcloc)
+{
+    // ATTN: This function seems to be necessary for operations that cannot easily be performed at construction of the processor,
+    // when the steering file is parsed e.g. the call to GEAR to get the inner bfield
+    
+    m_caloHitCreatorSettings.m_absorberRadLengthECal = m_geometryCreatorSettings.m_absorberRadLengthECal;
+    m_caloHitCreatorSettings.m_absorberIntLengthECal = m_geometryCreatorSettings.m_absorberIntLengthECal;
+    m_caloHitCreatorSettings.m_absorberRadLengthHCal = m_geometryCreatorSettings.m_absorberRadLengthHCal;
+    m_caloHitCreatorSettings.m_absorberIntLengthHCal = m_geometryCreatorSettings.m_absorberIntLengthHCal;
+    m_caloHitCreatorSettings.m_absorberRadLengthOther = m_geometryCreatorSettings.m_absorberRadLengthOther;
+    m_caloHitCreatorSettings.m_absorberIntLengthOther = m_geometryCreatorSettings.m_absorberIntLengthOther;
+
+    m_caloHitCreatorSettings.m_hCalEndCapInnerSymmetryOrder = m_geometryCreatorSettings.m_hCalEndCapInnerSymmetryOrder;
+    m_caloHitCreatorSettings.m_hCalEndCapInnerPhiCoordinate = m_geometryCreatorSettings.m_hCalEndCapInnerPhiCoordinate;
+    
+    m_trackCreatorSettings.m_prongSplitVertexCollections = m_trackCreatorSettings.m_prongVertexCollections;
+    m_trackCreatorSettings.m_prongSplitVertexCollections.insert(m_trackCreatorSettings.m_prongSplitVertexCollections.end(),
+        m_trackCreatorSettings.m_splitVertexCollections.begin(), m_trackCreatorSettings.m_splitVertexCollections.end());
+    
+    //m_settings.m_innerBField = marlin::Global::GEAR->getBField().at(gear::Vector3D(0., 0., 0.)).z();
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    gear::GearMgr* _GEAR = iSvc->getGearMgr();
+    m_settings.m_innerBField = _GEAR->getBField().at(gear::Vector3D(0., 0., 0.)).z();
+    std::cout<<"m_innerBField="<<m_settings.m_innerBField<<std::endl;    
+    m_mcParticleCreatorSettings.m_bField = m_settings.m_innerBField;
+}
+
+
+
+
+StatusCode PandoraMatrixAlg::initialize()
+{
+
+  gInterpreter->GenerateDictionary("vector<vector<float> >", "vector");
+  gInterpreter->GenerateDictionary("vector<vector<int> >", "vector");
+
+  std::cout<<"hi init PandoraMatrixAlg"<<std::endl;
+
+  std::string s_output =m_AnaOutput; 
+  m_fout = new TFile(s_output.c_str(),"RECREATE"); 
+  m_tree = new TTree("evt","tree");
+  m_tree->Branch("m_pReco_PID"   , &m_pReco_PID);
+  m_tree->Branch("m_pReco_mc_id" , &m_pReco_mc_id);
+  m_tree->Branch("m_pReco_mc_weight", &m_pReco_mc_weight);
+  m_tree->Branch("m_pReco_mass"  , &m_pReco_mass);
+  m_tree->Branch("m_pReco_energy", &m_pReco_energy);
+  m_tree->Branch("m_pReco_px"    , &m_pReco_px);
+  m_tree->Branch("m_pReco_py"    , &m_pReco_py);
+  m_tree->Branch("m_pReco_pz"    , &m_pReco_pz);
+  m_tree->Branch("m_pReco_charge", &m_pReco_charge);
+
+  m_tree->Branch("m_mc_id"    , &m_mc_id);
+  m_tree->Branch("m_mc_p_size", &m_mc_p_size);
+  m_tree->Branch("m_mc_pid"   , &m_mc_pid   );
+  m_tree->Branch("m_mc_mass"  , &m_mc_mass  );
+  m_tree->Branch("m_mc_px"    , &m_mc_px    );
+  m_tree->Branch("m_mc_py"    , &m_mc_py    );
+  m_tree->Branch("m_mc_pz"    , &m_mc_pz    );
+  m_tree->Branch("m_mc_charge", &m_mc_charge);
+  m_tree->Branch("m_hasConversion", &m_hasConversion);
+
+
+  m_tree->Branch("m_hits_x", &m_hits_x);
+  m_tree->Branch("m_hits_y", &m_hits_y);
+  m_tree->Branch("m_hits_z", &m_hits_z);
+  m_tree->Branch("m_hits_E", &m_hits_E);
+
+
+  // XML file
+  m_settings.m_pandoraSettingsXmlFile =  m_PandoraSettingsXmlFile ; 
+  // Hadronic energy non-linearity correction
+  m_settings.m_inputEnergyCorrectionPoints = m_InputEnergyCorrectionPoints;
+  m_settings.m_outputEnergyCorrectionPoints = m_OutputEnergyCorrectionPoints;
+  // B-field parameters
+  m_settings.m_muonBarrelBField = m_MuonBarrelBField; 
+  m_settings.m_muonEndCapBField = m_MuonEndCapBField;
+  
+  m_trackCreatorSettings.m_trackCollections = m_TrackCollections ; 
+  m_trackCreatorSettings.m_kinkVertexCollections = m_KinkVertexCollections; 
+  m_trackCreatorSettings.m_prongVertexCollections = m_ProngVertexCollections;
+  m_trackCreatorSettings.m_splitVertexCollections = m_SplitVertexCollections;
+  m_trackCreatorSettings.m_v0VertexCollections = m_V0VertexCollections; 
+  
+  m_caloHitCreatorSettings.m_eCalCaloHitCollections = m_ECalCaloHitCollections;
+  m_caloHitCreatorSettings.m_hCalCaloHitCollections = m_HCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_lCalCaloHitCollections = m_LCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_lHCalCaloHitCollections = m_LHCalCaloHitCollections;
+  m_caloHitCreatorSettings.m_muonCaloHitCollections = m_MuonCaloHitCollections; 
+  m_mcParticleCreatorSettings.m_mcParticleCollections = m_MCParticleCollections;
+  m_mcParticleCreatorSettings.m_CaloHitRelationCollections = m_RelCaloHitCollections; 
+  m_mcParticleCreatorSettings.m_TrackRelationCollections = m_RelTrackCollections;
+  
+  
+  // Absorber properties
+  m_geometryCreatorSettings.m_absorberRadLengthECal = m_AbsorberRadLengthECal;
+  m_geometryCreatorSettings.m_absorberIntLengthECal = m_AbsorberIntLengthECal;
+  m_geometryCreatorSettings.m_absorberRadLengthHCal = m_AbsorberRadLengthHCal;
+  m_geometryCreatorSettings.m_absorberIntLengthHCal = m_AbsorberIntLengthHCal;
+  m_geometryCreatorSettings.m_absorberRadLengthOther = m_AbsorberRadLengthOther;
+  m_geometryCreatorSettings.m_absorberIntLengthOther = m_AbsorberIntLengthOther;
+  
+  // Name of PFO collection written by GaudiPandora
+  
+  m_pfoCreatorSettings.m_clusterCollectionName = m_ClusterCollectionName;// not used  
+  m_pfoCreatorSettings.m_pfoCollectionName = m_PFOCollectionName;//
+  m_pfoCreatorSettings.m_startVertexCollectionName = m_StartVertexCollectionName; //
+  m_pfoCreatorSettings.m_startVertexAlgName = m_StartVertexAlgorithmName;//
+   
+  m_pfoCreatorSettings.m_emStochasticTerm = m_EMStochasticTerm;
+  m_pfoCreatorSettings.m_hadStochasticTerm = m_HadStochasticTerm;
+  m_pfoCreatorSettings.m_emConstantTerm = m_EMConstantTerm;
+  m_pfoCreatorSettings.m_hadConstantTerm = m_HadConstantTerm;
+  
+  // Calibration constants
+  m_caloHitCreatorSettings.m_eCalToMip = m_ECalToMipCalibration; 
+  m_caloHitCreatorSettings.m_hCalToMip = m_HCalToMipCalibration;
+  m_caloHitCreatorSettings.m_eCalMipThreshold = m_ECalMipThreshold; 
+  m_caloHitCreatorSettings.m_muonToMip = m_MuonToMipCalibration;
+  m_caloHitCreatorSettings.m_hCalMipThreshold = m_HCalMipThreshold; 
+  m_caloHitCreatorSettings.m_eCalToEMGeV = m_ECalToEMGeVCalibration;
+  m_caloHitCreatorSettings.m_hCalToEMGeV = m_HCalToEMGeVCalibration;
+  m_caloHitCreatorSettings.m_eCalToHadGeVEndCap = m_ECalToHadGeVCalibrationEndCap;
+  m_caloHitCreatorSettings.m_eCalToHadGeVBarrel = m_ECalToHadGeVCalibrationBarrel; 
+  m_caloHitCreatorSettings.m_hCalToHadGeV = m_HCalToHadGeVCalibration;
+  m_caloHitCreatorSettings.m_muonDigitalHits = m_DigitalMuonHits; 
+  m_caloHitCreatorSettings.m_muonHitEnergy = m_MuonHitEnergy; 
+  m_caloHitCreatorSettings.m_maxHCalHitHadronicEnergy = m_MaxHCalHitHadronicEnergy; 
+  m_caloHitCreatorSettings.m_nOuterSamplingLayers = m_NOuterSamplingLayers; 
+  m_caloHitCreatorSettings.m_layersFromEdgeMaxRearDistance = m_LayersFromEdgeMaxRearDistance; 
+  
+  // Track relationship parameters
+  m_trackCreatorSettings.m_shouldFormTrackRelationships = m_ShouldFormTrackRelationships; 
+  // Initial track hit specifications
+  m_trackCreatorSettings.m_minTrackHits = m_MinTrackHits;
+  m_trackCreatorSettings.m_minFtdTrackHits = m_MinFtdTrackHits; 
+  m_trackCreatorSettings.m_maxTrackHits = m_MaxTrackHits; 
+  ////m_trackCreatorSettings.m_useOldTrackStateCalculation = m_UseOldTrackStateCalculation;
+  // Track PFO usage parameters
+  m_trackCreatorSettings.m_d0TrackCut = m_D0TrackCut; 
+  m_trackCreatorSettings.m_z0TrackCut = m_Z0TrackCut;
+  m_trackCreatorSettings.m_usingNonVertexTracks = m_UseNonVertexTracks;
+  m_trackCreatorSettings.m_usingUnmatchedNonVertexTracks = m_UseUnmatchedNonVertexTracks;
+  m_trackCreatorSettings.m_usingUnmatchedVertexTracks = m_UseUnmatchedVertexTracks;
+  m_trackCreatorSettings.m_unmatchedVertexTrackMaxEnergy = m_UnmatchedVertexTrackMaxEnergy; 
+  m_trackCreatorSettings.m_d0UnmatchedVertexTrackCut = m_D0UnmatchedVertexTrackCut; 
+  m_trackCreatorSettings.m_z0UnmatchedVertexTrackCut = m_Z0UnmatchedVertexTrackCut;
+  m_trackCreatorSettings.m_zCutForNonVertexTracks = m_ZCutForNonVertexTracks;
+  // Track "reaches ecal" parameters
+  m_trackCreatorSettings.m_reachesECalNTpcHits = m_ReachesECalNTpcHits;
+  m_trackCreatorSettings.m_reachesECalNFtdHits = m_ReachesECalNFtdHits;
+  m_trackCreatorSettings.m_reachesECalTpcOuterDistance = m_ReachesECalTpcOuterDistance;
+  m_trackCreatorSettings.m_reachesECalMinFtdLayer = m_ReachesECalMinFtdLayer;
+  m_trackCreatorSettings.m_reachesECalTpcZMaxDistance = m_ReachesECalTpcZMaxDistance;
+  m_trackCreatorSettings.m_reachesECalFtdZMaxDistance = m_ReachesECalFtdZMaxDistance;
+  m_trackCreatorSettings.m_curvatureToMomentumFactor = m_CurvatureToMomentumFactor;
+  m_trackCreatorSettings.m_minTrackECalDistanceFromIp = m_MinTrackECalDistanceFromIp;
+  // Final track quality parameters
+  m_trackCreatorSettings.m_maxTrackSigmaPOverP = m_MaxTrackSigmaPOverP;
+  m_trackCreatorSettings.m_minMomentumForTrackHitChecks = m_MinMomentumForTrackHitChecks;
+  m_trackCreatorSettings.m_tpcMembraneMaxZ = m_TpcMembraneMaxZ;
+  m_trackCreatorSettings.m_minTpcHitFractionOfExpected = m_MinTpcHitFractionOfExpected;
+  m_trackCreatorSettings.m_minFtdHitsForTpcHitFraction = m_MinFtdHitsForTpcHitFraction;
+  m_trackCreatorSettings.m_maxTpcInnerRDistance = m_MaxTpcInnerRDistance;
+  
+  
+  // Additional geometry parameters
+  m_geometryCreatorSettings.m_eCalEndCapInnerSymmetryOrder = m_ECalEndCapInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_eCalEndCapInnerPhiCoordinate = m_ECalEndCapInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_eCalEndCapOuterSymmetryOrder = m_ECalEndCapOuterSymmetryOrder;
+  m_geometryCreatorSettings.m_eCalEndCapOuterPhiCoordinate = m_ECalEndCapOuterPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalEndCapInnerSymmetryOrder = m_HCalEndCapInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalEndCapInnerPhiCoordinate = m_HCalEndCapInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalEndCapOuterSymmetryOrder = m_HCalEndCapOuterSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalEndCapOuterPhiCoordinate = m_HCalEndCapOuterPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalRingInnerSymmetryOrder = m_HCalRingInnerSymmetryOrder;
+  m_geometryCreatorSettings.m_hCalRingInnerPhiCoordinate = m_HCalRingInnerPhiCoordinate;
+  m_geometryCreatorSettings.m_hCalRingOuterSymmetryOrder = m_HCalRingOuterSymmetryOrder; 
+  m_geometryCreatorSettings.m_hCalRingOuterPhiCoordinate = m_HCalRingOuterPhiCoordinate;
+  
+  // For Strip Splitting method and also for hybrid ECAL
+  m_caloHitCreatorSettings.m_stripSplittingOn = m_StripSplittingOn;
+  m_caloHitCreatorSettings.m_useEcalScLayers = m_UseEcalScLayers;
+  // Parameters for hybrid ECAL
+  // Energy to MIP for Si-layers and Sc-layers, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToMip = m_ECalSiToMipCalibration;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToMip = m_ECalScToMipCalibration;
+  // MipThreshold for Si-layers and Sc-layers, respectively.
+  // Si
+  m_caloHitCreatorSettings.m_eCalSiMipThreshold = m_ECalSiMipThreshold;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScMipThreshold = m_ECalScMipThreshold;
+  // EcalToEM for Si-layers and Sc-layers, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToEMGeV = m_ECalSiToEMGeVCalibration;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToEMGeV = m_ECalScToEMGeVCalibration;
+  // EcalToHad for Si-layers and Sc-layers of the endcaps, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToHadGeVEndCap = m_ECalSiToHadGeVCalibrationEndCap;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToHadGeVEndCap = m_ECalScToHadGeVCalibrationEndCap;
+  // EcalToHad for Si-layers and Sc-layers of the barrel, respectively.
+  //Si
+  m_caloHitCreatorSettings.m_eCalSiToHadGeVBarrel = m_ECalSiToHadGeVCalibrationBarrel;
+  //Sc
+  m_caloHitCreatorSettings.m_eCalScToHadGeVBarrel = m_ECalScToHadGeVCalibrationBarrel;
+
+  try
+  {
+      ISvcLocator* svcloc = serviceLocator();
+      this->FinaliseSteeringParameters(svcloc);
+      m_pPandora = new pandora::Pandora();
+      m_pMCParticleCreator = new MCParticleCreator(m_mcParticleCreatorSettings, m_pPandora);
+      m_pGeometryCreator = new GeometryCreator(m_geometryCreatorSettings, m_pPandora);
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pGeometryCreator->CreateGeometry(svcloc));
+      m_pCaloHitCreator = new CaloHitCreator(m_caloHitCreatorSettings, m_pPandora, svcloc, 0);
+      m_pTrackCreator = new TrackCreator(m_trackCreatorSettings, m_pPandora, svcloc);
+      m_pPfoCreator = new PfoCreator(m_pfoCreatorSettings, m_pPandora);
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->RegisterUserComponents());
+      PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::ReadSettings(*m_pPandora, m_settings.m_pandoraSettingsXmlFile));
+  }
+  catch (pandora::StatusCodeException &statusCodeException)
+  {
+      std::cout << "Failed to initialize gaudi pandora: " << statusCodeException.ToString() << std::endl;
+      throw statusCodeException;
+  }
+  catch (...)
+  {
+      std::cout << "Failed to initialize gaudi pandora: unrecognized exception" << std::endl;
+      throw;
+  }
+
+
+  return GaudiAlgorithm::initialize();
+}
+
+StatusCode PandoraMatrixAlg::execute()
+{
+    
+    try
+    {
+        std::cout<<"execute PandoraMatrixAlg"<<std::endl;
+        
+        updateMap();
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateMCParticles(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pCaloHitCreator->CreateCaloHits(*m_CollectionMaps));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateCaloHitToMCParticleRelationships(*m_CollectionMaps, m_pCaloHitCreator->GetCalorimeterHitVector() ));
+        //PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pTrackCreator->CreateTrackAssociations(*m_CollectionMaps));
+        //PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pTrackCreator->CreateTracks(*m_CollectionMaps));
+        //PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pMCParticleCreator->CreateTrackToMCParticleRelationships(*m_CollectionMaps, m_pTrackCreator->GetTrackVector() ));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::ProcessEvent(*m_pPandora));
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, m_pPfoCreator->CreateParticleFlowObjects(*m_CollectionMaps, m_ClusterCollection_w, m_ReconstructedParticleCollection_w, m_VertexCollection_w));
+        
+        StatusCode sc0 = CreateMCRecoParticleAssociation();
+        StatusCode sc = Ana();
+
+        PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Reset(*m_pPandora));
+        this->Reset();
+    }
+    catch (pandora::StatusCodeException &statusCodeException)
+    {
+        std::cout << "Gaudi pandora failed to process event: " << statusCodeException.ToString() << std::endl;
+        throw statusCodeException;
+    }
+    catch (...)
+    {
+        std::cout << "Gaudi pandora failed to process event: unrecognized exception" << std::endl;
+        throw;
+    }
+  
+  info() << "PandoraMatrixAlg Processed " << _nEvt << " events " << endmsg;
+  _nEvt ++ ;
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode PandoraMatrixAlg::finalize()
+{
+  info() << "Finalized. Processed " << _nEvt << " events " <<",saved tree with entries="<<m_tree->GetEntries()<< endmsg;
+  m_fout->cd();
+  m_tree->Write();
+  m_fout->Close();
+  delete m_pPandora;
+  delete m_pGeometryCreator;
+  delete m_pCaloHitCreator;
+  delete m_pTrackCreator;
+  delete m_pMCParticleCreator;
+  delete m_pPfoCreator;
+  return GaudiAlgorithm::finalize();
+}
+
+
+
+
+pandora::StatusCode PandoraMatrixAlg::RegisterUserComponents() const
+{
+    
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterAlgorithms(*m_pPandora));
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterBasicPlugins(*m_pPandora));
+
+    
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterBFieldPlugin(*m_pPandora,
+        m_settings.m_innerBField, m_settings.m_muonBarrelBField, m_settings.m_muonEndCapBField));
+
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, LCContent::RegisterNonLinearityEnergyCorrection(*m_pPandora,
+        "NonLinearity", pandora::HADRONIC, m_settings.m_inputEnergyCorrectionPoints, m_settings.m_outputEnergyCorrectionPoints));
+    
+    
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+
+void PandoraMatrixAlg::Reset()
+{
+    m_pCaloHitCreator->Reset();
+    m_pTrackCreator->Reset();
+    m_pMCParticleCreator->Reset();
+
+    std::vector<int>()  .swap(m_pReco_PID   );
+    std::vector< std::vector<int> >()  .swap(m_pReco_mc_id);
+    std::vector< std::vector<float> >().swap(m_pReco_mc_weight);
+    std::vector<float>().swap(m_pReco_mass);
+    std::vector<float>().swap(m_pReco_energy);
+    std::vector<float>().swap(m_pReco_px);
+    std::vector<float>().swap(m_pReco_py);
+    std::vector<float>().swap(m_pReco_pz);
+    std::vector<float>().swap(m_pReco_charge);
+
+    std::vector<int>()  .swap(m_mc_id);
+    std::vector<int>()  .swap(m_mc_p_size);
+    std::vector<int>()  .swap(m_mc_pid   );
+    std::vector<float>().swap(m_mc_mass  );
+    std::vector<float>().swap(m_mc_px    );
+    std::vector<float>().swap(m_mc_py    );
+    std::vector<float>().swap(m_mc_pz    );
+    std::vector<float>().swap(m_mc_charge);
+
+    std::vector<float>()  .swap(m_hits_x);
+    std::vector<float>()  .swap(m_hits_y);
+    std::vector<float>()  .swap(m_hits_z);
+    std::vector<float>()  .swap(m_hits_E);
+
+    m_hasConversion = 0;
+
+    m_CollectionMaps->clear();
+}
+
+const pandora::Pandora *PandoraMatrixAlg::GetPandora() const
+{
+    if (NULL == m_pPandora)
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+
+    return m_pPandora;
+}
+PandoraMatrixAlg::Settings::Settings() :
+    m_innerBField(3.5f),
+    m_muonBarrelBField(-1.5f),
+    m_muonEndCapBField(0.01f)
+{
+}
+CollectionMaps::CollectionMaps()
+{
+}
+void CollectionMaps::clear()
+{
+CollectionMap_MC.clear();
+CollectionMap_CaloHit.clear();
+CollectionMap_Vertex.clear();
+CollectionMap_Track.clear();
+collectionMap_MC.clear();
+collectionMap_CaloHit.clear();
+collectionMap_Vertex.clear();
+collectionMap_Track.clear();
+collectionMap_CaloRel.clear();
+collectionMap_TrkRel.clear();
+}
+
+StatusCode PandoraMatrixAlg::updateMap()
+{
+        const edm4hep::MCParticleCollection*     MCParticle = nullptr;
+        const edm4hep::CalorimeterHitCollection* ECALBarrel = nullptr;        
+        const edm4hep::CalorimeterHitCollection* ECALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* ECALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALBarrel = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* MUON       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LCAL       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LHCAL      = nullptr; 
+        const edm4hep::CalorimeterHitCollection* BCAL       = nullptr; 
+        const edm4hep::VertexCollection* KinkVertices       = nullptr; 
+        const edm4hep::VertexCollection* ProngVertices      = nullptr; 
+        const edm4hep::VertexCollection* SplitVertices      = nullptr; 
+        const edm4hep::VertexCollection* V0Vertices         = nullptr; 
+        const edm4hep::TrackCollection*  MarlinTrkTracks    = nullptr; 
+        const edm4hep::MCRecoCaloAssociationCollection*  mcRecoCaloAssociation    = nullptr; 
+        const edm4hep::MCRecoTrackerAssociationCollection*  mcRecoTrackerAssociation    = nullptr; 
+        StatusCode sc = StatusCode::SUCCESS;
+        sc =  getCol(m_mcParCol_r  , MCParticle );
+        sc =  getCol(m_ECALBarrel_r, ECALBarrel );
+        sc =  getCol(m_ECALEndcap_r, ECALEndcap );
+        sc =  getCol(m_ECALOther_r , ECALOther  );
+        sc =  getCol(m_HCALBarrel_r, HCALBarrel );
+        sc =  getCol(m_HCALEndcap_r, HCALEndcap );
+        sc =  getCol(m_HCALOther_r , HCALOther  );
+        sc =  getCol(m_MUON_r      , MUON       );
+        sc =  getCol(m_LCAL_r      , LCAL       );
+        sc =  getCol(m_LHCAL_r     , LHCAL      );
+        sc =  getCol(m_BCAL_r      , BCAL       );        
+        sc =  getCol(m_KinkVertices_r  , KinkVertices );        
+        sc =  getCol(m_ProngVertices_r , ProngVertices);        
+        sc =  getCol(m_SplitVertices_r , SplitVertices);        
+        sc =  getCol(m_V0Vertices_r    , V0Vertices   );        
+        sc =  getCol(m_MarlinTrkTracks_r , MarlinTrkTracks   );        
+        sc =  getCol(m_MCRecoCaloAssociation_r , mcRecoCaloAssociation   );        
+        sc =  getCol(m_MCRecoTrackerAssociation_r , mcRecoTrackerAssociation);        
+
+        if (NULL != MCParticle   )  
+        {
+            std::vector<edm4hep::MCParticle> v_mc;
+            m_CollectionMaps->CollectionMap_MC ["MCParticle"] = MCParticle ;
+            m_CollectionMaps->collectionMap_MC ["MCParticle"] = v_mc;
+            for(unsigned int i=0 ; i< MCParticle->size(); i++) m_CollectionMaps->collectionMap_MC ["MCParticle"].push_back(MCParticle->at(i));
+        }
+        if (NULL != ECALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["ECALBarrel"] = ECALBarrel ;
+            m_CollectionMaps->collectionMap_CaloHit["ECALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALBarrel->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALBarrel"].push_back(ECALBarrel->at(i));
+        }
+        if (NULL != ECALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["ECALEndcap"] = ECALEndcap ;
+            m_CollectionMaps->collectionMap_CaloHit["ECALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALEndcap->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALEndcap"].push_back(ECALEndcap->at(i));
+        }
+        if (NULL != ECALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["ECALOther"] = ECALOther ;
+            m_CollectionMaps->collectionMap_CaloHit["ECALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALOther->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["ECALOther"].push_back(ECALOther->at(i));
+        }
+        if (NULL != HCALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["HCALBarrel"] = HCALBarrel ;
+            m_CollectionMaps->collectionMap_CaloHit["HCALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALBarrel->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALBarrel"].push_back(HCALBarrel->at(i));
+        }
+        if (NULL != HCALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["HCALEndcap"] = HCALEndcap ;
+            m_CollectionMaps->collectionMap_CaloHit["HCALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALEndcap->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALEndcap"].push_back(HCALEndcap->at(i));
+        }
+        if (NULL != HCALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["HCALOther"] = HCALOther ;
+            m_CollectionMaps->collectionMap_CaloHit["HCALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALOther->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["HCALOther"].push_back(HCALOther->at(i));
+        }
+        if (NULL != MUON   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["MUON"] = MUON ;
+            m_CollectionMaps->collectionMap_CaloHit["MUON"] = v_cal ;
+            for(unsigned int i=0 ; i< MUON->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["MUON"].push_back(MUON->at(i));
+        }
+        if (NULL != LCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["LCAL"] = LCAL ;
+            m_CollectionMaps->collectionMap_CaloHit["LCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["LCAL"].push_back(LCAL->at(i));
+        }
+        if (NULL != LHCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["LHCAL"] = LHCAL ;
+            m_CollectionMaps->collectionMap_CaloHit["LHCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LHCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["LHCAL"].push_back(LHCAL->at(i));
+        }
+        if (NULL != BCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            m_CollectionMaps->CollectionMap_CaloHit["BCAL"] = BCAL ;
+            m_CollectionMaps->collectionMap_CaloHit["BCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< BCAL->size(); i++) m_CollectionMaps->collectionMap_CaloHit ["BCAL"].push_back(BCAL->at(i));
+        }
+        if (NULL != KinkVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->CollectionMap_Vertex["KinkVertices"] = KinkVertices ;
+            m_CollectionMaps->collectionMap_Vertex["KinkVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< KinkVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["KinkVertices"].push_back(KinkVertices->at(i));
+        }
+        if (NULL != ProngVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->CollectionMap_Vertex["ProngVertices"] = ProngVertices ;
+            m_CollectionMaps->collectionMap_Vertex["ProngVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< ProngVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["ProngVertices"].push_back(ProngVertices->at(i));
+        }
+        if (NULL != SplitVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->CollectionMap_Vertex["SplitVertices"] = SplitVertices ;
+            m_CollectionMaps->collectionMap_Vertex["SplitVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< SplitVertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["SplitVertices"].push_back(SplitVertices->at(i));
+        }
+        if (NULL != V0Vertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            m_CollectionMaps->CollectionMap_Vertex["V0Vertices"] = V0Vertices ;
+            m_CollectionMaps->collectionMap_Vertex["V0Vertices"] = v_cal ;
+            for(unsigned int i=0 ; i< V0Vertices->size(); i++) m_CollectionMaps->collectionMap_Vertex ["V0Vertices"].push_back(V0Vertices->at(i));
+        }
+        if (NULL != MarlinTrkTracks   )
+        {
+            std::vector<edm4hep::Track> v_cal;
+            m_CollectionMaps->CollectionMap_Track["MarlinTrkTracks"] = MarlinTrkTracks ;
+            m_CollectionMaps->collectionMap_Track["MarlinTrkTracks"] = v_cal ;
+            for(unsigned int i=0 ; i< MarlinTrkTracks->size(); i++) m_CollectionMaps->collectionMap_Track ["MarlinTrkTracks"].push_back(MarlinTrkTracks->at(i));
+        }
+        if (NULL != mcRecoCaloAssociation )
+        {
+            std::vector<edm4hep::MCRecoCaloAssociation> v_cal;
+            m_CollectionMaps->collectionMap_CaloRel["RecoCaloAssociation_ECALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoCaloAssociation->size(); i++) m_CollectionMaps->collectionMap_CaloRel ["RecoCaloAssociation_ECALBarrel"].push_back(mcRecoCaloAssociation->at(i));
+        }
+        
+        else
+        {
+            if (NULL != MCParticle   )
+            {
+                for(unsigned int i=0 ; i< MCParticle->size(); i++)
+                {
+                    if(MCParticle->at(i).parents_size()==0)
+                    {
+                        std::cout<<"create recoCaloAssociation by hand now"<<std::endl;
+                        for(std::map<std::string, std::vector<edm4hep::CalorimeterHit> >::iterator iter = m_CollectionMaps->collectionMap_CaloHit.begin(); iter != m_CollectionMaps->collectionMap_CaloHit.end(); iter++)
+                        {
+                            std::string prefix = "RecoCaloAssociation_";
+                            std::string key = prefix + iter->first;
+                            std::cout<<"create for "<<key<<std::endl;
+                            std::vector<edm4hep::MCRecoCaloAssociation> v_cal;
+                            m_CollectionMaps->collectionMap_CaloRel[key] = v_cal ;
+                            for(std::vector<edm4hep::CalorimeterHit>::iterator it=iter->second.begin(); it != iter->second.end(); it ++)
+                            {
+                                edm4hep::SimCalorimeterHit sim_hit( it->getCellID(), it->getEnergy(), it->getPosition() );
+                                edm4hep::CaloHitContribution conb ( MCParticle->at(i).getPDG(), it->getEnergy(), 0, it->getPosition() ); 
+                                conb.setParticle( MCParticle->at(i) );
+                                sim_hit.addToContributions(conb);
+                                edm4hep::MCRecoCaloAssociation calo_association;
+                                calo_association.setRec(*it);
+                                calo_association.setSim(sim_hit);
+                                m_CollectionMaps->collectionMap_CaloRel[key].push_back(calo_association); 
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (NULL != mcRecoTrackerAssociation )
+        {
+            std::vector<edm4hep::MCRecoTrackerAssociation> v_cal;
+            m_CollectionMaps->collectionMap_TrkRel["RecoTrackerAssociation"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoTrackerAssociation->size(); i++) m_CollectionMaps->collectionMap_TrkRel ["RecoTrackerAssociation"].push_back(mcRecoTrackerAssociation->at(i));
+        }
+    return StatusCode::SUCCESS;
+}
+
+
+StatusCode PandoraMatrixAlg::updateMap(CollectionMaps & tmp_map)
+{
+        const edm4hep::MCParticleCollection*     MCParticle = nullptr;
+        const edm4hep::CalorimeterHitCollection* ECALBarrel = nullptr;        
+        const edm4hep::CalorimeterHitCollection* ECALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* ECALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALBarrel = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALEndcap = nullptr; 
+        const edm4hep::CalorimeterHitCollection* HCALOther  = nullptr; 
+        const edm4hep::CalorimeterHitCollection* MUON       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LCAL       = nullptr; 
+        const edm4hep::CalorimeterHitCollection* LHCAL      = nullptr; 
+        const edm4hep::CalorimeterHitCollection* BCAL       = nullptr; 
+        const edm4hep::VertexCollection* KinkVertices       = nullptr; 
+        const edm4hep::VertexCollection* ProngVertices      = nullptr; 
+        const edm4hep::VertexCollection* SplitVertices      = nullptr; 
+        const edm4hep::VertexCollection* V0Vertices         = nullptr; 
+        const edm4hep::TrackCollection*  MarlinTrkTracks    = nullptr; 
+        const edm4hep::MCRecoCaloAssociationCollection*  mcRecoCaloAssociation    = nullptr; 
+        const edm4hep::MCRecoTrackerAssociationCollection*  mcRecoTrackerAssociation    = nullptr; 
+        StatusCode sc = StatusCode::SUCCESS;
+        sc =  getCol(m_mcParCol_r  , MCParticle );
+        sc =  getCol(m_ECALBarrel_r, ECALBarrel );
+        sc =  getCol(m_ECALEndcap_r, ECALEndcap );
+        sc =  getCol(m_ECALOther_r , ECALOther  );
+        sc =  getCol(m_HCALBarrel_r, HCALBarrel );
+        sc =  getCol(m_HCALEndcap_r, HCALEndcap );
+        sc =  getCol(m_HCALOther_r , HCALOther  );
+        sc =  getCol(m_MUON_r      , MUON       );
+        sc =  getCol(m_LCAL_r      , LCAL       );
+        sc =  getCol(m_LHCAL_r     , LHCAL      );
+        sc =  getCol(m_BCAL_r      , BCAL       );        
+        sc =  getCol(m_KinkVertices_r  , KinkVertices );        
+        sc =  getCol(m_ProngVertices_r , ProngVertices);        
+        sc =  getCol(m_SplitVertices_r , SplitVertices);        
+        sc =  getCol(m_V0Vertices_r    , V0Vertices   );        
+        sc =  getCol(m_MarlinTrkTracks_r , MarlinTrkTracks   );        
+        sc =  getCol(m_MCRecoCaloAssociation_r , mcRecoCaloAssociation   );        
+        sc =  getCol(m_MCRecoTrackerAssociation_r , mcRecoTrackerAssociation  );        
+
+        if (NULL != MCParticle   )  
+        {
+            std::vector<edm4hep::MCParticle> v_mc;
+            tmp_map.CollectionMap_MC ["MCParticle"] = MCParticle ;
+            tmp_map.collectionMap_MC ["MCParticle"] = v_mc;
+            for(unsigned int i=0 ; i< MCParticle->size(); i++) tmp_map.collectionMap_MC ["MCParticle"].push_back(MCParticle->at(i));
+        }
+        if (NULL != ECALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["ECALBarrel"] = ECALBarrel ;
+            tmp_map.collectionMap_CaloHit["ECALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALBarrel->size(); i++) tmp_map.collectionMap_CaloHit ["ECALBarrel"].push_back(ECALBarrel->at(i));
+        }
+        if (NULL != ECALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["ECALEndcap"] = ECALEndcap ;
+            tmp_map.collectionMap_CaloHit["ECALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALEndcap->size(); i++) tmp_map.collectionMap_CaloHit ["ECALEndcap"].push_back(ECALEndcap->at(i));
+        }
+        if (NULL != ECALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["ECALOther"] = ECALOther ;
+            tmp_map.collectionMap_CaloHit["ECALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< ECALOther->size(); i++) tmp_map.collectionMap_CaloHit ["ECALOther"].push_back(ECALOther->at(i));
+        }
+        if (NULL != HCALBarrel   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["HCALBarrel"] = HCALBarrel ;
+            tmp_map.collectionMap_CaloHit["HCALBarrel"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALBarrel->size(); i++) tmp_map.collectionMap_CaloHit ["HCALBarrel"].push_back(HCALBarrel->at(i));
+        }
+        if (NULL != HCALEndcap   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["HCALEndcap"] = HCALEndcap ;
+            tmp_map.collectionMap_CaloHit["HCALEndcap"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALEndcap->size(); i++) tmp_map.collectionMap_CaloHit ["HCALEndcap"].push_back(HCALEndcap->at(i));
+        }
+        if (NULL != HCALOther   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["HCALOther"] = HCALOther ;
+            tmp_map.collectionMap_CaloHit["HCALOther"] = v_cal ;
+            for(unsigned int i=0 ; i< HCALOther->size(); i++) tmp_map.collectionMap_CaloHit ["HCALOther"].push_back(HCALOther->at(i));
+        }
+        if (NULL != MUON   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["MUON"] = MUON ;
+            tmp_map.collectionMap_CaloHit["MUON"] = v_cal ;
+            for(unsigned int i=0 ; i< MUON->size(); i++) tmp_map.collectionMap_CaloHit ["MUON"].push_back(MUON->at(i));
+        }
+        if (NULL != LCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["LCAL"] = LCAL ;
+            tmp_map.collectionMap_CaloHit["LCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LCAL->size(); i++) tmp_map.collectionMap_CaloHit ["LCAL"].push_back(LCAL->at(i));
+        }
+        if (NULL != LHCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["LHCAL"] = LHCAL ;
+            tmp_map.collectionMap_CaloHit["LHCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< LHCAL->size(); i++) tmp_map.collectionMap_CaloHit ["LHCAL"].push_back(LHCAL->at(i));
+        }
+        if (NULL != BCAL   )
+        {
+            std::vector<edm4hep::CalorimeterHit> v_cal;
+            tmp_map.CollectionMap_CaloHit["BCAL"] = BCAL ;
+            tmp_map.collectionMap_CaloHit["BCAL"] = v_cal ;
+            for(unsigned int i=0 ; i< BCAL->size(); i++) tmp_map.collectionMap_CaloHit ["BCAL"].push_back(BCAL->at(i));
+        }
+        if (NULL != KinkVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            tmp_map.CollectionMap_Vertex["KinkVertices"] = KinkVertices ;
+            tmp_map.collectionMap_Vertex["KinkVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< KinkVertices->size(); i++) tmp_map.collectionMap_Vertex ["KinkVertices"].push_back(KinkVertices->at(i));
+        }
+        if (NULL != ProngVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            tmp_map.CollectionMap_Vertex["ProngVertices"] = ProngVertices ;
+            tmp_map.collectionMap_Vertex["ProngVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< ProngVertices->size(); i++) tmp_map.collectionMap_Vertex ["ProngVertices"].push_back(ProngVertices->at(i));
+        }
+        if (NULL != SplitVertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            tmp_map.CollectionMap_Vertex["SplitVertices"] = SplitVertices ;
+            tmp_map.collectionMap_Vertex["SplitVertices"] = v_cal ;
+            for(unsigned int i=0 ; i< SplitVertices->size(); i++) tmp_map.collectionMap_Vertex ["SplitVertices"].push_back(SplitVertices->at(i));
+        }
+        if (NULL != V0Vertices   )
+        {
+            std::vector<edm4hep::Vertex> v_cal;
+            tmp_map.CollectionMap_Vertex["V0Vertices"] = V0Vertices ;
+            tmp_map.collectionMap_Vertex["V0Vertices"] = v_cal ;
+            for(unsigned int i=0 ; i< V0Vertices->size(); i++) tmp_map.collectionMap_Vertex ["V0Vertices"].push_back(V0Vertices->at(i));
+        }
+        if (NULL != MarlinTrkTracks   )
+        {
+            std::vector<edm4hep::Track> v_cal;
+            tmp_map.CollectionMap_Track["MarlinTrkTracks"] = MarlinTrkTracks ;
+            tmp_map.collectionMap_Track["MarlinTrkTracks"] = v_cal ;
+            for(unsigned int i=0 ; i< MarlinTrkTracks->size(); i++) tmp_map.collectionMap_Track ["MarlinTrkTracks"].push_back(MarlinTrkTracks->at(i));
+        }
+        if (NULL != mcRecoCaloAssociation )
+        {
+            std::vector<edm4hep::MCRecoCaloAssociation> v_cal;
+            tmp_map.collectionMap_CaloRel["RecoCaloAssociation"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoCaloAssociation->size(); i++) tmp_map.collectionMap_CaloRel ["RecoCaloAssociation"].push_back(mcRecoCaloAssociation->at(i));
+        }
+        if (NULL != mcRecoTrackerAssociation )
+        {
+            std::vector<edm4hep::MCRecoTrackerAssociation> v_cal;
+            tmp_map.collectionMap_TrkRel["RecoTrackerAssociation"] = v_cal ;
+            for(unsigned int i=0 ; i< mcRecoTrackerAssociation->size(); i++) tmp_map.collectionMap_TrkRel ["RecoTrackerAssociation"].push_back(mcRecoTrackerAssociation->at(i));
+        }
+    return StatusCode::SUCCESS;
+}
+
+
+StatusCode PandoraMatrixAlg::Ana()
+{
+    int n_current = m_tree->GetEntries()+1;
+    const edm4hep::ReconstructedParticleCollection* reco_col = m_ReconstructedParticleCollection_w.get();
+    const edm4hep::MCRecoParticleAssociationCollection* reco_associa_col = m_MCRecoParticleAssociation_w.get();
+    std::cout<<"reco_col size="<<reco_col->size()<<std::endl;
+    for(int i=0; i<reco_col->size();i++)
+    {
+        std::cout<<"reco="<<i<<std::endl;
+        const edm4hep::ReconstructedParticle pReco = reco_col->at(i);
+        const float px = pReco.getMomentum()[0];
+        const float py = pReco.getMomentum()[1];
+        const float pz = pReco.getMomentum()[2];
+        const float energy = pReco.getEnergy();
+        const float mass = pReco.getMass();
+        const float charge = pReco.getCharge();
+        const int type = pReco.getType();
+        std::cout<<"MYDBUG evt="<<n_current<<",rec i="<<i<<",particleId="<<type<<",mass="<<mass<<",charge="<<charge<<",energy="<<energy<<",px="<<px<<",py="<<py<<",pz="<<pz<<std::endl;
+        m_pReco_PID.push_back(type);
+        m_pReco_mass.push_back(mass);
+        m_pReco_charge.push_back(charge);
+        m_pReco_energy.push_back(energy);
+        m_pReco_px.push_back(px);
+        m_pReco_py.push_back(py);
+        m_pReco_pz.push_back(pz);
+        std::vector<int> tmp_mc_id;
+        std::vector<float> tmp_mc_weight;
+        for(int j=0; j < reco_associa_col->size(); j++)
+        {
+            if(reco_associa_col->at(j).getRec().id() != pReco.id() ) continue;
+            std::cout<<"MC pid ="<<reco_associa_col->at(j).getSim().getPDG()<<",weight="<<reco_associa_col->at(j).getWeight()<<", px="<<reco_associa_col->at(j).getSim().getMomentum()[0]<<", py="<<reco_associa_col->at(j).getSim().getMomentum()[1]<<",pz="<<reco_associa_col->at(j).getSim().getMomentum()[2]<<std::endl;
+            tmp_mc_id    .push_back(reco_associa_col->at(j).getSim().id());
+            tmp_mc_weight.push_back(reco_associa_col->at(j).getWeight());
+        }
+        m_pReco_mc_id    .push_back(tmp_mc_id);
+        m_pReco_mc_weight.push_back(tmp_mc_weight);
+    }
+    const edm4hep::MCParticleCollection*     MCParticle = nullptr;
+    StatusCode sc = StatusCode::SUCCESS;
+    sc =  getCol(m_mcParCol_r  , MCParticle );
+    if (NULL != MCParticle   )  
+    { 
+        for(unsigned int i=0 ; i< MCParticle->size(); i++)
+        {
+            m_mc_id    .push_back(MCParticle->at(i).id());
+            m_mc_p_size.push_back(MCParticle->at(i).parents_size());
+            m_mc_pid   .push_back(MCParticle->at(i).getPDG());
+            m_mc_mass  .push_back(MCParticle->at(i).getMass());
+            m_mc_px    .push_back(MCParticle->at(i).getMomentum()[0]);
+            m_mc_py    .push_back(MCParticle->at(i).getMomentum()[1]);
+            m_mc_pz    .push_back(MCParticle->at(i).getMomentum()[2]);
+            m_mc_charge.push_back(MCParticle->at(i).getCharge());
+            //for(unsigned int j =0 ; j< MCParticle->at(i).daughters_size(); j++) da_pids.push_back( MCParticle->at(i).getDaughters(j).getPDG());
+            if(MCParticle->at(i).parents_size()==0) std::cout<<"MYDBUG evt="<<n_current<<", mc i="<<i<<",px="<<MCParticle->at(i).getMomentum()[0]<<",py="<<MCParticle->at(i).getMomentum()[1]<<",pz="<<MCParticle->at(i).getMomentum()[2]<<std::endl;
+            if (MCParticle->at(i).getPDG() != 22) continue;
+            int hasEm = 0;
+            int hasEp = 0;
+            for(unsigned int j =0 ; j< MCParticle->at(i).daughters_size(); j++)
+            {
+                if      (MCParticle->at(i).getDaughters(j).getPDG() ==  11 ) hasEm=1;
+                else if (MCParticle->at(i).getDaughters(j).getPDG() == -11 ) hasEp=1;
+            }
+            if(hasEm && hasEp) m_hasConversion=1;
+        }
+    }
+    //sanity check calo info
+    const edm4hep::CalorimeterHitCollection*     CaloCol = nullptr;
+    sc =  getCol(m_ECALBarrel_r, CaloCol);
+    if (NULL != CaloCol   )  
+    { 
+        for(unsigned int i=0 ; i< CaloCol->size(); i++)
+        {
+            m_hits_x.push_back(CaloCol->at(i).getPosition()[0]);
+            m_hits_y.push_back(CaloCol->at(i).getPosition()[1]);
+            m_hits_z.push_back(CaloCol->at(i).getPosition()[2]);
+            m_hits_E.push_back(CaloCol->at(i).getEnergy()     );
+        }
+    }
+
+    m_tree->Fill();
+    return StatusCode::SUCCESS;
+}
+
+// create simple MCRecoParticleAssociation using calorimeter hit only
+StatusCode PandoraMatrixAlg::CreateMCRecoParticleAssociation()
+{
+    edm4hep::MCRecoParticleAssociationCollection* pMCRecoParticleAssociationCollection  = m_MCRecoParticleAssociation_w.createAndPut();
+    const edm4hep::ReconstructedParticleCollection* reco_col = m_ReconstructedParticleCollection_w.get();
+    std::cout<<"CreateMCRecoParticleAssociation, reco_col size="<<reco_col->size()<<std::endl;
+    for(int i=0; i<reco_col->size();i++)
+    {
+        std::map<int, edm4hep::ConstMCParticle> mc_map;
+        std::map<int, float > id_edep_map;
+        float tot_en = 0 ;
+        const edm4hep::ReconstructedParticle pReco = reco_col->at(i);
+        for(int j=0; j < pReco.clusters_size(); j++)
+        {
+            edm4hep::ConstCluster cluster = pReco.getClusters(j);
+            for(int k=0; k < cluster.hits_size(); k++)
+            {
+                edm4hep::ConstCalorimeterHit hit = cluster.getHits(k);
+                for(std::map<std::string, std::vector<edm4hep::MCRecoCaloAssociation> >::iterator iter = m_CollectionMaps->collectionMap_CaloRel.begin(); iter != m_CollectionMaps->collectionMap_CaloRel.end(); iter++)
+                {
+                    for(std::vector<edm4hep::MCRecoCaloAssociation>::iterator it = iter->second.begin(); it != iter->second.end(); it ++)
+                    {
+                        if(it->getRec().id() != hit.id()) continue;
+                        for(std::vector<edm4hep::ConstCaloHitContribution>::const_iterator itc = it->getSim().contributions_begin(); itc != it->getSim().contributions_end(); itc++)
+                        {
+                            if(mc_map.find(itc->getParticle().id()) == mc_map.end()) mc_map[itc->getParticle().id()] = itc->getParticle() ;
+                            if(id_edep_map.find(itc->getParticle().id()) != id_edep_map.end()) id_edep_map[itc->getParticle().id()] = id_edep_map[itc->getParticle().id()] + itc->getEnergy() ;
+                            else                                                               id_edep_map[itc->getParticle().id()] = itc->getEnergy() ;
+                            tot_en += itc->getEnergy() ;
+                        }
+                    }
+                }
+            }
+        }
+        for(std::map<int, edm4hep::ConstMCParticle>::iterator it = mc_map.begin(); it != mc_map.end(); it ++)
+        {      
+            edm4hep::MCRecoParticleAssociation association = pMCRecoParticleAssociationCollection->create();
+            association.setRec(pReco);
+            association.setSim(it->second);
+            if(tot_en==0) 
+            {
+                association.setWeight(0);
+                std::cout<<"Found 0 cluster energy"<<std::endl;
+            }  
+            else if(id_edep_map.find(it->first) != id_edep_map.end()) association.setWeight(id_edep_map[it->first]/tot_en);
+            else std::cout<<"Error in creating MCRecoParticleAssociation"<<std::endl;
+        }
+    }
+    return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/PfoCreator.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/PfoCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b197f2dbb907b3c98597c5e7acf9b700208b155e
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/PfoCreator.cpp
@@ -0,0 +1,429 @@
+/**
+ *  @file   MarlinPandora/src/PfoCreator.cc
+ * 
+ *  @brief  Implementation of the pfo creator class.
+ * 
+ *  $Log: $
+ */
+
+//#include "CalorimeterHitType.h"
+
+#include "Api/PandoraApi.h"
+
+#include "Objects/Cluster.h"
+#include "Objects/ParticleFlowObject.h"
+#include "Objects/Track.h"
+
+#include "Pandora/PdgTable.h"
+#include "PfoCreator.h"
+#include "PandoraMatrixAlg.h"
+
+#include <algorithm>
+#include <cmath>
+
+PfoCreator::PfoCreator(const Settings &settings, const pandora::Pandora *const pPandora) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+PfoCreator::~PfoCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode PfoCreator::CreateParticleFlowObjects(CollectionMaps& collectionMaps, DataHandle<edm4hep::ClusterCollection>& _pClusterCollection, DataHandle<edm4hep::ReconstructedParticleCollection>& _pReconstructedParticleCollection, DataHandle<edm4hep::VertexCollection>& _pStartVertexCollection)
+{
+    m_collectionMaps = &collectionMaps;
+    edm4hep::ClusterCollection* pClusterCollection                              = _pClusterCollection.createAndPut();
+    edm4hep::ReconstructedParticleCollection* pReconstructedParticleCollection  = _pReconstructedParticleCollection.createAndPut();
+    edm4hep::VertexCollection* pStartVertexCollection                           = _pStartVertexCollection.createAndPut();
+ 
+    const pandora::PfoList *pPandoraPfoList = NULL;
+    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::GetCurrentPfoList(*m_pPandora, pPandoraPfoList));
+
+
+    //IMPL::LCFlagImpl lcFlagImpl(pClusterCollection->getFlag());
+    //lcFlagImpl.setBit(LCIO::CLBIT_HITS);
+    //pClusterCollection->setFlag(lcFlagImpl.getFlag());
+
+    pandora::StringVector subDetectorNames;
+    this->InitialiseSubDetectorNames(subDetectorNames);
+    //pClusterCollection->parameters().setValues("ClusterSubdetectorNames", subDetectorNames);
+
+    // Create lcio "reconstructed particles" from the pandora "particle flow objects"
+    std::cout<<"pPandoraPfoList size="<<pPandoraPfoList->size()<<std::endl;
+    for (pandora::PfoList::const_iterator pIter = pPandoraPfoList->begin(), pIterEnd = pPandoraPfoList->end(); pIter != pIterEnd; ++pIter)
+    {
+        const pandora::ParticleFlowObject *const pPandoraPfo(*pIter);
+        //IMPL::ReconstructedParticleImpl *const pReconstructedParticle(new ReconstructedParticleImpl());
+        edm4hep::ReconstructedParticle pReconstructedParticle0 = pReconstructedParticleCollection->create();
+        edm4hep::ReconstructedParticle* pReconstructedParticle = &pReconstructedParticle0;
+
+        const bool hasTrack(!pPandoraPfo->GetTrackList().empty());
+        const pandora::ClusterList &clusterList(pPandoraPfo->GetClusterList());
+
+        //std::cout<<"ClusterList size="<<clusterList.size()<<std::endl;
+        float clustersTotalEnergy(0.f);
+        pandora::CartesianVector referencePoint(0.f, 0.f, 0.f), clustersWeightedPosition(0.f, 0.f, 0.f);
+        for (pandora::ClusterList::const_iterator cIter = clusterList.begin(), cIterEnd = clusterList.end(); cIter != cIterEnd; ++cIter)
+        {
+            const pandora::Cluster *const pPandoraCluster(*cIter);
+            pandora::CaloHitList pandoraCaloHitList;
+            pPandoraCluster->GetOrderedCaloHitList().FillCaloHitList(pandoraCaloHitList);
+            pandoraCaloHitList.insert(pandoraCaloHitList.end(), pPandoraCluster->GetIsolatedCaloHitList().begin(), pPandoraCluster->GetIsolatedCaloHitList().end());
+
+            pandora::FloatVector hitE, hitX, hitY, hitZ;
+            //IMPL::ClusterImpl *const p_Cluster(new ClusterImpl());
+            edm4hep::Cluster p_Cluster0 = pClusterCollection->create();
+            edm4hep::Cluster* p_Cluster = &p_Cluster0;
+            this->SetClusterSubDetectorEnergies(subDetectorNames, p_Cluster, pandoraCaloHitList, hitE, hitX, hitY, hitZ);
+
+            float clusterCorrectEnergy(0.f);
+            this->SetClusterEnergyAndError(pPandoraPfo, pPandoraCluster, p_Cluster, clusterCorrectEnergy);
+
+            pandora::CartesianVector clusterPosition(0.f, 0.f, 0.f);
+            const unsigned int nHitsInCluster(pandoraCaloHitList.size());
+            this->SetClusterPositionAndError(nHitsInCluster, hitE, hitX, hitY, hitZ, p_Cluster, clusterPosition);
+
+            if (!hasTrack)
+            {
+                clustersWeightedPosition += clusterPosition * clusterCorrectEnergy;
+                clustersTotalEnergy += clusterCorrectEnergy;
+            }
+
+            //pClusterCollection->addElement(p_Cluster);
+            edm4hep::ConstCluster p_ClusterCon = *p_Cluster;
+            pReconstructedParticle->addToClusters(p_ClusterCon);
+        }
+
+        if (!hasTrack)
+        {
+            if (clustersTotalEnergy < std::numeric_limits<float>::epsilon())
+            {
+                std::cout<<"WARNING PfoCreator::CreateParticleFlowObjects: invalid cluster energy " << clustersTotalEnergy << std::endl;
+                throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+            }
+            else
+            {
+                referencePoint = clustersWeightedPosition * (1.f / clustersTotalEnergy);
+            }
+        }
+        else
+        {
+            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->CalculateTrackBasedReferencePoint(pPandoraPfo, referencePoint));
+        }
+
+        this->SetRecoParticleReferencePoint(referencePoint, pReconstructedParticle);
+        this->AddTracksToRecoParticle(pPandoraPfo, pReconstructedParticle);
+        this->SetRecoParticlePropertiesFromPFO(pPandoraPfo, pReconstructedParticle);
+
+        edm4hep::Vertex pStartVertex0 = pStartVertexCollection->create();
+        edm4hep::Vertex* pStartVertex = &pStartVertex0;
+        //pStartVertex->setAlgorithmType(m_settings.m_startVertexAlgName.c_str());
+        pStartVertex->setAlgorithmType(0);
+        const float ref_value[3] = {referencePoint.GetX(),referencePoint.GetY(),referencePoint.GetZ()};
+        pStartVertex->setPosition(edm4hep::Vector3f(ref_value));
+        pStartVertex->setAssociatedParticle(*pReconstructedParticle);
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::InitialiseSubDetectorNames(pandora::StringVector &subDetectorNames) const
+{
+    subDetectorNames.push_back("ecal");
+    subDetectorNames.push_back("hcal");
+    subDetectorNames.push_back("yoke");
+    subDetectorNames.push_back("lcal");
+    subDetectorNames.push_back("lhcal");
+    subDetectorNames.push_back("bcal");
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterSubDetectorEnergies(const pandora::StringVector &subDetectorNames, edm4hep::Cluster *const p_Cluster,
+    const pandora::CaloHitList &pandoraCaloHitList, pandora::FloatVector &hitE, pandora::FloatVector &hitX, pandora::FloatVector &hitY,
+    pandora::FloatVector &hitZ) const
+{
+    for (pandora::CaloHitList::const_iterator hIter = pandoraCaloHitList.begin(), hIterEnd = pandoraCaloHitList.end(); hIter != hIterEnd; ++hIter)
+    {
+        const pandora::CaloHit *const pPandoraCaloHit(*hIter);
+        edm4hep::CalorimeterHit *const pCalorimeterHit0 = (edm4hep::CalorimeterHit*)(pPandoraCaloHit->GetParentAddress());
+        const edm4hep::CalorimeterHit pCalorimeterHit = *pCalorimeterHit0;
+        
+        p_Cluster->addToHits(pCalorimeterHit);
+
+        const float caloHitEnergy(pCalorimeterHit.getEnergy());
+        hitE.push_back(caloHitEnergy);
+        hitX.push_back(pCalorimeterHit.getPosition()[0]);
+        hitY.push_back(pCalorimeterHit.getPosition()[1]);
+        hitZ.push_back(pCalorimeterHit.getPosition()[2]);
+        /*
+        std::vector<float> &subDetectorEnergies = p_Cluster->subdetectorEnergies();
+        subDetectorEnergies.resize(subDetectorNames.size());
+
+        switch (CHT(pCalorimeterHit->getType()).caloID())
+        {
+            case CHT::ecal:  subDetectorEnergies[ECAL_INDEX ] += caloHitEnergy; break;
+            case CHT::hcal:  subDetectorEnergies[HCAL_INDEX ] += caloHitEnergy; break;
+            case CHT::yoke:  subDetectorEnergies[YOKE_INDEX ] += caloHitEnergy; break;
+            case CHT::lcal:  subDetectorEnergies[LCAL_INDEX ] += caloHitEnergy; break;
+            case CHT::lhcal: subDetectorEnergies[LHCAL_INDEX] += caloHitEnergy; break;
+            case CHT::bcal:  subDetectorEnergies[BCAL_INDEX ] += caloHitEnergy; break;
+            default: streamlog_out(WARNING) << "PfoCreator::SetClusterSubDetectorEnergies: no subdetector found for hit with type: " << pCalorimeterHit->getType() << std::endl;
+        }
+        */
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterEnergyAndError(const pandora::ParticleFlowObject *const pPandoraPfo, const pandora::Cluster *const pPandoraCluster, 
+    edm4hep::Cluster *const p_Cluster, float &clusterCorrectEnergy) const
+{
+    const bool isEmShower((pandora::PHOTON == pPandoraPfo->GetParticleId()) || (pandora::E_MINUS == std::abs(pPandoraPfo->GetParticleId())));
+    clusterCorrectEnergy = (isEmShower ? pPandoraCluster->GetCorrectedElectromagneticEnergy(*m_pPandora) : pPandoraCluster->GetCorrectedHadronicEnergy(*m_pPandora));
+
+    if (clusterCorrectEnergy < std::numeric_limits<float>::epsilon())
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+
+    const float stochasticTerm(isEmShower ? m_settings.m_emStochasticTerm : m_settings.m_hadStochasticTerm); 
+    const float constantTerm(isEmShower ? m_settings.m_emConstantTerm : m_settings.m_hadConstantTerm);
+    const float energyError(std::sqrt(stochasticTerm * stochasticTerm / clusterCorrectEnergy + constantTerm * constantTerm) * clusterCorrectEnergy);
+
+    p_Cluster->setEnergy(clusterCorrectEnergy);
+    p_Cluster->setEnergyError(energyError);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetClusterPositionAndError(const unsigned int nHitsInCluster, pandora::FloatVector &hitE, pandora::FloatVector &hitX, 
+    pandora::FloatVector &hitY, pandora::FloatVector &hitZ, edm4hep::Cluster *const p_Cluster, pandora::CartesianVector &clusterPositionVec) const
+{
+    ClusterShapes *const pClusterShapes(new ClusterShapes(nHitsInCluster, hitE.data(), hitX.data(), hitY.data(), hitZ.data()));
+
+    try
+    {
+        p_Cluster->setPhi(std::atan2(pClusterShapes->getEigenVecInertia()[1], pClusterShapes->getEigenVecInertia()[0]));
+        p_Cluster->setITheta(std::acos(pClusterShapes->getEigenVecInertia()[2]));
+        p_Cluster->setPosition(pClusterShapes->getCentreOfGravity());
+        //ATTN these two lines below would only compile with ilcsoft HEAD V2015-10-13 and above
+        //p_Cluster->setPositionError(pClusterShapes->getCenterOfGravityErrors());
+        //p_Cluster->setDirectionError(pClusterShapes->getEigenVecInertiaErrors());
+        clusterPositionVec.SetValues(pClusterShapes->getCentreOfGravity()[0], pClusterShapes->getCentreOfGravity()[1], pClusterShapes->getCentreOfGravity()[2]);
+    }
+    catch (...)
+    {
+        std::cout<<"WARNING PfoCreator::SetClusterPositionAndError: unidentified exception caught." << std::endl;
+    }
+
+    delete pClusterShapes;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode PfoCreator::CalculateTrackBasedReferencePoint(const pandora::ParticleFlowObject *const pPandoraPfo, pandora::CartesianVector &referencePoint) const
+{
+    const pandora::TrackList &trackList(pPandoraPfo->GetTrackList());
+
+    float totalTrackMomentumAtDca(0.f), totalTrackMomentumAtStart(0.f);
+    pandora::CartesianVector referencePointAtDCAWeighted(0.f, 0.f, 0.f), referencePointAtStartWeighted(0.f, 0.f, 0.f);
+
+    bool hasSiblings(false);
+    for (pandora::TrackList::const_iterator tIter = trackList.begin(), tIterEnd = trackList.end(); tIter != tIterEnd; ++tIter)
+    {
+        const pandora::Track *const pPandoraTrack(*tIter);
+
+        if (!this->IsValidParentTrack(pPandoraTrack, trackList))
+            continue;
+
+        if (this->HasValidSiblingTrack(pPandoraTrack, trackList))
+        {
+            // Presence of sibling tracks typically represents a conversion
+            const pandora::CartesianVector &trackStartPoint((pPandoraTrack->GetTrackStateAtStart()).GetPosition());
+            const float trackStartMomentum(((pPandoraTrack->GetTrackStateAtStart()).GetMomentum()).GetMagnitude());
+            referencePointAtStartWeighted += trackStartPoint * trackStartMomentum;
+            totalTrackMomentumAtStart += trackStartMomentum;
+            hasSiblings = true;
+        }
+        else
+        {
+            const edm4hep::Track *const pLcioTrack0 = (edm4hep::Track*)(pPandoraTrack->GetParentAddress());
+            const edm4hep::Track pLcioTrack = *pLcioTrack0;
+
+            const float z0(pPandoraTrack->GetZ0());
+            pandora::CartesianVector intersectionPoint(0.f, 0.f, 0.f);
+
+            //intersectionPoint.SetValues(pLcioTrack->getD0() * std::cos(pLcioTrack->getPhi()), pLcioTrack->getD0() * std::sin(pLcioTrack->getPhi()), z0);
+            if(pLcioTrack.trackStates_size()==0) throw "zero trackStates size find";
+            intersectionPoint.SetValues(pLcioTrack.getTrackStates(0).D0 * std::cos(pLcioTrack.getTrackStates(0).phi), pLcioTrack.getTrackStates(0).D0 * std::sin(pLcioTrack.getTrackStates(0).phi), z0);
+            const float trackMomentumAtDca((pPandoraTrack->GetMomentumAtDca()).GetMagnitude());
+            referencePointAtDCAWeighted += intersectionPoint * trackMomentumAtDca;
+            totalTrackMomentumAtDca += trackMomentumAtDca;
+        }
+    }
+
+    if (hasSiblings)
+    {
+        if (totalTrackMomentumAtStart < std::numeric_limits<float>::epsilon())
+        {
+            std::cout<<" WARNING PfoCreator::CalculateTrackBasedReferencePoint: invalid track momentum " << totalTrackMomentumAtStart << std::endl;
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+        }
+        else
+        {
+            referencePoint = referencePointAtStartWeighted * (1.f / totalTrackMomentumAtStart);
+        }
+    }
+    else
+    {
+        if (totalTrackMomentumAtDca < std::numeric_limits<float>::epsilon())
+        {
+            std::cout<<"WARNING PfoCreator::CalculateTrackBasedReferencePoint: invalid track momentum " << totalTrackMomentumAtDca << std::endl;
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_FAILURE);
+        }
+        else
+        {
+            referencePoint = referencePointAtDCAWeighted * (1.f / totalTrackMomentumAtDca);
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::IsValidParentTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &parentTrackList(pPandoraTrack->GetParentList());
+
+    for (pandora::TrackList::const_iterator iter = parentTrackList.begin(), iterEnd = parentTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            continue;
+
+        // ATTN This track must have a parent not in the all track list; still use it if it is the closest to the ip
+        std::cout<<"WARNING PfoCreator::IsValidParentTrack: mismatch in track relationship information, use information as available " << std::endl;
+
+        if (this->IsClosestTrackToIP(pPandoraTrack, allTrackList))
+            return true;
+
+        return false;
+    }
+
+    // Ideal case: All parents are associated to same pfo
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::HasValidSiblingTrack(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &siblingTrackList(pPandoraTrack->GetSiblingList());
+
+    for (pandora::TrackList::const_iterator iter = siblingTrackList.begin(), iterEnd = siblingTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            continue;
+
+        // ATTN This track must have a sibling not in the all track list; still use it if it has a second sibling that is in the list
+        std::cout<<"WARNING PfoCreator::HasValidSiblingTrack: mismatch in track relationship information, use information as available " << std::endl;
+
+        if (this->AreAnyOtherSiblingsInList(pPandoraTrack, allTrackList))
+            return true;
+
+        return false;
+    }
+
+    // Ideal case: All siblings associated to same pfo
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::IsClosestTrackToIP(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const 
+{
+    const pandora::Track *pClosestTrack(NULL);
+    float closestTrackDisplacement(std::numeric_limits<float>::max()); 
+
+    for (pandora::TrackList::const_iterator iter = allTrackList.begin(), iterEnd = allTrackList.end(); iter != iterEnd; ++iter)
+    {
+        const pandora::Track *const pTrack(*iter);
+        const float trialTrackDisplacement(pTrack->GetTrackStateAtStart().GetPosition().GetMagnitude());
+
+        if (trialTrackDisplacement < closestTrackDisplacement)
+        {
+            closestTrackDisplacement = trialTrackDisplacement;
+            pClosestTrack = pTrack;
+        }
+    }
+
+    return (pPandoraTrack == pClosestTrack);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool PfoCreator::AreAnyOtherSiblingsInList(const pandora::Track *const pPandoraTrack, const pandora::TrackList &allTrackList) const
+{
+    const pandora::TrackList &siblingTrackList(pPandoraTrack->GetSiblingList());
+
+    for (pandora::TrackList::const_iterator iter = siblingTrackList.begin(), iterEnd = siblingTrackList.end(); iter != iterEnd; ++iter)
+    {
+        if (allTrackList.end() != std::find(allTrackList.begin(), allTrackList.end(), *iter))
+            return true;
+    }
+
+    return false;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetRecoParticleReferencePoint(const pandora::CartesianVector &referencePoint, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const float referencePointArray[3] = {referencePoint.GetX(), referencePoint.GetY(), referencePoint.GetZ()};
+    pReconstructedParticle->setReferencePoint(referencePointArray);
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::AddTracksToRecoParticle(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const pandora::TrackList &trackList(pPandoraPfo->GetTrackList());
+
+    for (pandora::TrackList::const_iterator tIter = trackList.begin(), tIterEnd = trackList.end(); tIter != tIterEnd; ++tIter)
+    {
+        const pandora::Track *const pTrack(*tIter);
+        const edm4hep::Track *const pLcioTrack0 = (edm4hep::Track*)(pTrack->GetParentAddress());
+        const edm4hep::Track pLcioTrack = *pLcioTrack0;
+        pReconstructedParticle->addToTracks(pLcioTrack);
+
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void PfoCreator::SetRecoParticlePropertiesFromPFO(const pandora::ParticleFlowObject *const pPandoraPfo, edm4hep::ReconstructedParticle *const pReconstructedParticle) const
+{
+    const float momentum[3] = {pPandoraPfo->GetMomentum().GetX(), pPandoraPfo->GetMomentum().GetY(), pPandoraPfo->GetMomentum().GetZ()};
+    pReconstructedParticle->setMomentum(momentum);
+    pReconstructedParticle->setEnergy(pPandoraPfo->GetEnergy());
+    pReconstructedParticle->setMass(pPandoraPfo->GetMass());
+    pReconstructedParticle->setCharge(pPandoraPfo->GetCharge());
+    pReconstructedParticle->setType(pPandoraPfo->GetParticleId());
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+PfoCreator::Settings::Settings():
+    m_emStochasticTerm(0.17f),
+    m_hadStochasticTerm(0.6f),
+    m_emConstantTerm(0.01f),
+    m_hadConstantTerm(0.03f)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/TrackCreator.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/TrackCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a3c0f15a7107e3671d246b80d69918f82c952de
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/TrackCreator.cpp
@@ -0,0 +1,987 @@
+/**
+ *  @file   MarlinPandora/src/TrackCreator.cc
+ * 
+ *  @brief  Implementation of the track creator class.
+ * 
+ *  $Log: $
+ */
+
+
+#include "UTIL/ILDConf.h"
+
+#include "edm4hep/Vertex.h"
+#include "edm4hep/ReconstructedParticle.h"
+
+#include "gear/BField.h"
+#include "gear/CalorimeterParameters.h"
+#include "gear/PadRowLayout2D.h"
+#include "gear/TPCParameters.h"
+#include "gear/FTDParameters.h"
+#include "gear/FTDLayerLayout.h"
+
+#include "GaudiKernel/IService.h"
+#include "GearSvc/IGearSvc.h"
+#include "PandoraMatrixAlg.h"
+
+#include "TrackCreator.h"
+#include "Pandora/PdgTable.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+TrackCreator::TrackCreator(const Settings &settings, const pandora::Pandora *const pPandora, ISvcLocator* svcloc) :
+    m_settings(settings),
+    m_pPandora(pPandora)
+{
+
+    IGearSvc*  iSvc = 0;
+    StatusCode sc = svcloc->service("GearSvc", iSvc, false);
+    if ( !sc ) 
+    {
+        throw "Failed to find GearSvc ...";
+    }
+    _GEAR = iSvc->getGearMgr();
+
+
+    m_bField                  = (_GEAR->getBField().at(gear::Vector3D(0., 0., 0.)).z());
+    m_tpcInnerR               = (_GEAR->getTPCParameters().getPadLayout().getPlaneExtent()[0]);
+    m_tpcOuterR               = (_GEAR->getTPCParameters().getPadLayout().getPlaneExtent()[1]);
+    m_tpcMaxRow               = (_GEAR->getTPCParameters().getPadLayout().getNRows());
+    m_tpcZmax                 = (_GEAR->getTPCParameters().getMaxDriftLength());
+    m_eCalBarrelInnerSymmetry = (_GEAR->getEcalBarrelParameters().getSymmetryOrder());
+    m_eCalBarrelInnerPhi0     = (_GEAR->getEcalBarrelParameters().getPhi0());
+    m_eCalBarrelInnerR        = (_GEAR->getEcalBarrelParameters().getExtent()[0]);
+    m_eCalEndCapInnerZ        = (_GEAR->getEcalEndcapParameters().getExtent()[2]);
+    // fg: FTD description in GEAR has changed ...
+    try
+    {
+        m_ftdInnerRadii = _GEAR->getGearParameters("FTD").getDoubleVals("FTDInnerRadius");
+        m_ftdOuterRadii = _GEAR->getGearParameters("FTD").getDoubleVals("FTDOuterRadius");
+        m_ftdZPositions = _GEAR->getGearParameters("FTD").getDoubleVals("FTDZCoordinate");
+        m_nFtdLayers = m_ftdZPositions.size();
+    }
+    catch (gear::UnknownParameterException &)
+    {
+        const gear::FTDLayerLayout &ftdLayerLayout(_GEAR->getFTDParameters().getFTDLayerLayout());
+        std::cout << " Filling FTD parameters from gear::FTDParameters - n layers: " << ftdLayerLayout.getNLayers() << std::endl;
+
+        for(unsigned int i = 0, N = ftdLayerLayout.getNLayers(); i < N; ++i)
+        {
+            // Create a disk to represent even number petals front side
+            m_ftdInnerRadii.push_back(ftdLayerLayout.getSensitiveRinner(i));
+            m_ftdOuterRadii.push_back(ftdLayerLayout.getMaxRadius(i));
+
+            // Take the mean z position of the staggered petals
+            const double zpos(ftdLayerLayout.getZposition(i));
+            m_ftdZPositions.push_back(zpos);
+            std::cout << "     layer " << i << " - mean z position = " << zpos << std::endl;
+        }
+
+        m_nFtdLayers = m_ftdZPositions.size() ;
+    }
+
+    // Check tpc parameters
+    if ((std::fabs(m_tpcZmax) < std::numeric_limits<float>::epsilon()) || (std::fabs(m_tpcInnerR) < std::numeric_limits<float>::epsilon())
+        || (std::fabs(m_tpcOuterR - m_tpcInnerR) < std::numeric_limits<float>::epsilon()))
+    {
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    m_cosTpc = m_tpcZmax / std::sqrt(m_tpcZmax * m_tpcZmax + m_tpcInnerR * m_tpcInnerR);
+
+    // Check ftd parameters
+    if ((0 == m_nFtdLayers) || (m_nFtdLayers != m_ftdInnerRadii.size()) || (m_nFtdLayers != m_ftdOuterRadii.size()))
+    {
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+    }
+
+    for (unsigned int iFtdLayer = 0; iFtdLayer < m_nFtdLayers; ++iFtdLayer)
+    {
+        if ((std::fabs(m_ftdOuterRadii[iFtdLayer]) < std::numeric_limits<float>::epsilon()) ||
+            (std::fabs(m_ftdInnerRadii[iFtdLayer]) < std::numeric_limits<float>::epsilon()))
+        {
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+        }
+    }
+
+    m_tanLambdaFtd = m_ftdZPositions[0] / m_ftdOuterRadii[0];
+
+    // Calculate etd and set parameters
+    // fg: make SET and ETD optional - as they might not be in the model ...
+    try
+    {
+        const DoubleVector &etdZPositions(_GEAR->getGearParameters("ETD").getDoubleVals("ETDLayerZ"));
+        const DoubleVector &setInnerRadii(_GEAR->getGearParameters("SET").getDoubleVals("SETLayerRadius"));
+
+        if (etdZPositions.empty() || setInnerRadii.empty())
+            throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
+
+        m_minEtdZPosition = *(std::min_element(etdZPositions.begin(), etdZPositions.end()));
+        m_minSetRadius = *(std::min_element(setInnerRadii.begin(), setInnerRadii.end()));
+    }
+    catch(gear::UnknownParameterException &)
+    {
+        std::cout << "Warnning, ETDLayerZ or SETLayerRadius parameters missing from GEAR parameters!" << std::endl
+                               << "     -> both will be set to " << std::numeric_limits<float>::quiet_NaN() << std::endl;
+
+        //fg: Set them to NAN, so that they cannot be used to set   trackParameters.m_reachesCalorimeter = true;
+        m_minEtdZPosition = std::numeric_limits<float>::quiet_NaN();
+        m_minSetRadius = std::numeric_limits<float>::quiet_NaN();
+    }
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+TrackCreator::~TrackCreator()
+{
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::CreateTrackAssociations(const CollectionMaps& collectionMaps)
+{
+//    Don't use it now, because the Vertex.getAssociatedParticle() doesn't work for LCIO to plcio transfer
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractKinks(collectionMaps));
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractProngsAndSplits(const CollectionMaps& collectionMaps));
+//    PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, this->ExtractV0s(const CollectionMaps& collectionMaps));
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode TrackCreator::ExtractKinks(const CollectionMaps& collectionMaps)
+{
+    std::cout<<"start TrackCreator::ExtractKinks:"<<std::endl;
+    for (StringVector::const_iterator iter = m_settings.m_kinkVertexCollections.begin(), iterEnd = m_settings.m_kinkVertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.CollectionMap_Vertex.find(*iter) == collectionMaps.CollectionMap_Vertex.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const edm4hep::VertexCollection *pKinkCollection = (collectionMaps.CollectionMap_Vertex.find(*iter))->second;
+
+            for (int i = 0, iMax = pKinkCollection->size(); i < iMax; ++i)
+            {
+                try
+                {
+                    const edm4hep::Vertex  pVertex0 = pKinkCollection->at(i);
+                    const edm4hep::Vertex* pVertex  = &(pVertex0);
+
+                    if (NULL == pVertex) throw ("Collection type mismatch");
+
+                    std::cout<<"pVertex0 getChi2="<<pVertex0.getChi2()<<std::endl;
+                    std::cout<<"pVertex getChi2="<<pVertex->getChi2()<<std::endl;
+                    std::cout<<"Hi 0 "<<std::endl;
+                    const plcio::ConstReconstructedParticle pReconstructedParticle0 = pVertex0.getAssociatedParticle();
+                    std::cout<<"Hi 1"<<std::endl;
+                    //EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const plcio::ConstReconstructedParticle pReconstructedParticle = pVertex->getAssociatedParticle();
+                    std::cout<<"Hi 2:"<<&pReconstructedParticle<<std::endl;
+                    //const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+                    //plcio::ConstTrack trackVec = pReconstructedParticle.getTracks();
+
+                    std::cout<<"pReconstructedParticle0 en="<<pReconstructedParticle0.getEnergy()<<std::endl;
+                    std::cout<<"pReconstructedParticle en="<<pReconstructedParticle.getEnergy()<<std::endl;
+                    //if (this->IsConflictingRelationship(trackVec))continue;
+                    if (this->IsConflictingRelationship(pReconstructedParticle))continue;
+
+                    //const int vertexPdgCode(pReconstructedParticle->getType());
+                    const int vertexPdgCode(pReconstructedParticle.getType());
+
+                    // Extract the kink vertex information
+                    //for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    //for (unsigned int iTrack = 0, nTracks = trackVec.tracks_size(); iTrack < nTracks; ++iTrack)
+                    for (unsigned int iTrack = 0, nTracks = pReconstructedParticle.tracks_size(); iTrack < nTracks; ++iTrack)
+                    {
+                        //EVENT::Track *pTrack = trackVec[iTrack];
+                        //plcio::ConstTrack pTrack = trackVec.getTracks(iTrack);
+                        plcio::ConstTrack pTrack = pReconstructedParticle.getTracks(iTrack);
+                        //(0 == iTrack) ? m_parentTrackList.insert(pTrack) : m_daughterTrackList.insert(pTrack);
+                        (0 == iTrack) ? m_parentTrackList.insert(pTrack.id()) : m_daughterTrackList.insert(pTrack.id());
+                       //std::cout << "KinkTrack " << iTrack << ", nHits " << pTrack.getTrackerHits().size() << std::endl;
+                       std::cout << "KinkTrack " << iTrack << ", nHits " << pTrack.trackerHits_size() << std::endl;
+
+                        int trackPdgCode = pandora::UNKNOWN_PARTICLE_TYPE;
+
+                        if (0 == iTrack)
+                        {
+                            trackPdgCode = vertexPdgCode;
+                        }
+                        else
+                        {
+                            switch (vertexPdgCode)
+                            {
+                            case pandora::PI_PLUS :
+                            case pandora::K_PLUS :
+                                trackPdgCode = pandora::MU_PLUS;
+                                break;
+                            case pandora::PI_MINUS :
+                            case pandora::K_MINUS :
+                                trackPdgCode = pandora::MU_MINUS;
+                                break;
+                            case pandora::HYPERON_MINUS_BAR :
+                            case pandora::SIGMA_PLUS :
+                                trackPdgCode = pandora::PI_PLUS;
+                                break;
+                            case pandora::SIGMA_MINUS :
+                            case pandora::HYPERON_MINUS :
+                                trackPdgCode = pandora::PI_PLUS;
+                                break;
+                            default :
+                                //(pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                                (pTrack.getTrackStates(0).omega > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                                break;
+                            }
+                        }
+
+                        m_trackToPidMap.insert(TrackToPidMap::value_type(pTrack, trackPdgCode));
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track parent-daughter relationships
+                        if (0 == iTrack)
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, pTrack, trackVec[jTrack]));
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(trackVec.getTracks(jTrack).id()) ) );
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(pReconstructedParticle.getTracks(jTrack).id()) ) );
+                            }
+                        }
+
+                        // Make track sibling relationships
+                        else
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, pTrack, trackVec[jTrack]));
+                                //PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(trackVec.getTracks(jTrack).id()) ));
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora, (int*)(pTrack.id()), (int*)(pReconstructedParticle.getTracks(jTrack).id()) ));
+                            }
+                        }
+                    }
+                }
+                catch (...)
+                {
+                    std::cout << "Failed to extract kink vertex: " <<  std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout << "Failed to extract kink vertex collection: " << *iter <<  std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+/*
+pandora::StatusCode TrackCreator::ExtractProngsAndSplits(const EVENT::LCEvent *const pLCEvent)
+{
+    for (StringVector::const_iterator iter = m_settings.m_prongSplitVertexCollections.begin(), iterEnd = m_settings.m_prongSplitVertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pProngOrSplitCollection = pLCEvent->getCollection(*iter);
+
+            for (int i = 0, iMax = pProngOrSplitCollection->getNumberOfElements(); i < iMax; ++i)
+            {
+                try
+                {
+                    EVENT::Vertex *pVertex = dynamic_cast<Vertex*>(pProngOrSplitCollection->getElementAt(i));
+
+                    if (NULL == pVertex)
+                        throw EVENT::Exception("Collection type mismatch");
+
+                    EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+
+                    if (this->IsConflictingRelationship(trackVec))
+                        continue;
+
+                    // Extract the prong/split vertex information
+                    for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    {
+                        EVENT::Track *pTrack = trackVec[iTrack];
+                        (0 == iTrack) ? m_parentTrackList.insert(pTrack) : m_daughterTrackList.insert(pTrack);
+                        streamlog_out(DEBUG) << "Prong or Split Track " << iTrack << ", nHits " << pTrack->getTrackerHits().size() << std::endl;
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track parent-daughter relationships
+                        if (0 == iTrack)
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackParentDaughterRelationship(*m_pPandora,
+                                    pTrack, trackVec[jTrack]));
+                            }
+                        }
+
+                        // Make track sibling relationships
+                        else
+                        {
+                            for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                            {
+                                PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora,
+                                    pTrack, trackVec[jTrack]));
+                            }
+                        }
+                    }
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract prong/split vertex: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract prong/split vertex collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::ExtractV0s(const EVENT::LCEvent *const pLCEvent)
+{
+    for (StringVector::const_iterator iter = m_settings.m_v0VertexCollections.begin(), iterEnd = m_settings.m_v0VertexCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        try
+        {
+            const EVENT::LCCollection *pV0Collection = pLCEvent->getCollection(*iter);
+
+            for (int i = 0, iMax = pV0Collection->getNumberOfElements(); i < iMax; ++i)
+            {
+                try
+                {
+                    EVENT::Vertex *pVertex = dynamic_cast<Vertex*>(pV0Collection->getElementAt(i));
+
+                    if (NULL == pVertex)
+                        throw EVENT::Exception("Collection type mismatch");
+
+                    EVENT::ReconstructedParticle *pReconstructedParticle = pVertex->getAssociatedParticle();
+                    const EVENT::TrackVec &trackVec(pReconstructedParticle->getTracks());
+
+                    if (this->IsConflictingRelationship(trackVec))
+                        continue;
+
+                    // Extract the v0 vertex information
+                    const int vertexPdgCode(pReconstructedParticle->getType());
+
+                    for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+                    {
+                        EVENT::Track *pTrack = trackVec[iTrack];
+                        m_v0TrackList.insert(pTrack);
+                        streamlog_out(DEBUG) << "V0Track " << iTrack << ", nHits " << pTrack->getTrackerHits().size() << std::endl;
+
+                        int trackPdgCode = pandora::UNKNOWN_PARTICLE_TYPE;
+
+                        switch (vertexPdgCode)
+                        {
+                        case pandora::PHOTON :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::E_PLUS : trackPdgCode = pandora::E_MINUS;
+                            break;
+                        case pandora::LAMBDA :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PROTON : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        case pandora::LAMBDA_BAR :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PROTON_BAR;
+                            break;
+                        case pandora::K_SHORT :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        default :
+                            (pTrack->getOmega() > 0) ? trackPdgCode = pandora::PI_PLUS : trackPdgCode = pandora::PI_MINUS;
+                            break;
+                        }
+
+                        m_trackToPidMap.insert(TrackToPidMap::value_type(pTrack, trackPdgCode));
+
+                        if (0 == m_settings.m_shouldFormTrackRelationships)
+                            continue;
+
+                        // Make track sibling relationships
+                        for (unsigned int jTrack = iTrack + 1; jTrack < nTracks; ++jTrack)
+                        {
+                            PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetTrackSiblingRelationship(*m_pPandora,
+                                pTrack, trackVec[jTrack]));
+                        }
+                    }
+                }
+                catch (EVENT::Exception &exception)
+                {
+                    streamlog_out(WARNING) << "Failed to extract v0 vertex: " << exception.what() << std::endl;
+                }
+            }
+        }
+        catch (EVENT::Exception &exception)
+        {
+            streamlog_out(DEBUG5) << "Failed to extract v0 vertex collection: " << *iter << ", " << exception.what() << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+*/
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool TrackCreator::IsConflictingRelationship(const edm4hep::ConstReconstructedParticle &Particle) const
+{
+    //for (unsigned int iTrack = 0, nTracks = trackVec.size(); iTrack < nTracks; ++iTrack)
+    //for (unsigned int iTrack = 0, nTracks = trackVec.tracks_size(); iTrack < nTracks; ++iTrack)
+    std::cout<<"Particle en="<<Particle.getEnergy()<<std::endl;
+    for (unsigned int iTrack = 0, nTracks = Particle.tracks_size(); iTrack < nTracks; ++iTrack)
+    {
+        //EVENT::Track *pTrack = trackVec[iTrack];
+        edm4hep::ConstTrack pTrack = Particle.getTracks(iTrack) ;
+        unsigned int pTrack_id = pTrack.id() ;
+
+        //if (this->IsDaughter(pTrack) || this->IsParent(pTrack) || this->IsV0(pTrack))
+        if (this->IsDaughter(pTrack_id) || this->IsParent(pTrack_id) || this->IsV0(pTrack_id))
+            return true;
+    }
+
+    return false;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+pandora::StatusCode TrackCreator::CreateTracks(const CollectionMaps& collectionMaps)
+{
+    std::cout<<"start TrackCreator::CreateTracks:"<<std::endl;
+    for (StringVector::const_iterator iter = m_settings.m_trackCollections.begin(), iterEnd = m_settings.m_trackCollections.end();
+        iter != iterEnd; ++iter)
+    {
+        if(collectionMaps.collectionMap_Track.find(*iter) == collectionMaps.collectionMap_Track.end()) { std::cout<<"not find "<<(*iter)<<std::endl; continue;}
+        try
+        {
+            const std::vector<edm4hep::Track>& pTrackCollection = (collectionMaps.collectionMap_Track.find(*iter))->second;
+            std::cout<<(*iter)<<" size="<<pTrackCollection.size()<<std::endl;
+
+            for (int i = 0, iMax = pTrackCollection.size(); i < iMax; ++i)
+            {
+                try
+                {
+                    const edm4hep::Track& pTrack0 = pTrackCollection.at(i);
+                    const edm4hep::Track* pTrack  = (const edm4hep::Track*)(&pTrack0);
+
+                    if (NULL == pTrack) throw ("Collection type mismatch");
+
+                    int minTrackHits = m_settings.m_minTrackHits;
+                    //const float tanLambda(std::fabs(pTrack->getTanLambda()));
+                    //std::cout<<"track states size="<<pTrack->trackStates_size()<<std::endl;
+                    const float tanLambda(std::fabs(pTrack->getTrackStates(0).tanLambda));
+
+                    if (tanLambda > m_tanLambdaFtd)
+                    {
+                        int expectedFtdHits(0);
+
+                        for (unsigned int iFtdLayer = 0; iFtdLayer < m_nFtdLayers; ++iFtdLayer)
+                        {
+                            if ((tanLambda > m_ftdZPositions[iFtdLayer] / m_ftdOuterRadii[iFtdLayer]) &&
+                                (tanLambda < m_ftdZPositions[iFtdLayer] / m_ftdInnerRadii[iFtdLayer]))
+                            {
+                                expectedFtdHits++;
+                            }
+                        }
+
+                        minTrackHits = std::max(m_settings.m_minFtdTrackHits, expectedFtdHits);
+                    }
+
+                    const int nTrackHits(static_cast<int>(pTrack->trackerHits_size()));
+
+                    if ((nTrackHits < minTrackHits) || (nTrackHits > m_settings.m_maxTrackHits))
+                        continue;
+
+                    // Proceed to create the pandora track
+                    PandoraApi::Track::Parameters trackParameters;
+                    //trackParameters.m_d0 = pTrack->getD0();
+                    trackParameters.m_d0 = pTrack->getTrackStates(0).D0;
+                    //trackParameters.m_z0 = pTrack->getZ0();
+                    trackParameters.m_z0 = pTrack->getTrackStates(0).Z0;
+                    trackParameters.m_pParentAddress = pTrack;
+                    // By default, assume tracks are charged pions
+                    const float signedCurvature(pTrack->getTrackStates(0).omega);
+                    trackParameters.m_particleId = (signedCurvature > 0) ? pandora::PI_PLUS : pandora::PI_MINUS;
+                    trackParameters.m_mass = pandora::PdgTable::GetParticleMass(pandora::PI_PLUS);
+
+                    // Use particle id information from V0 and Kink finders
+                    TrackToPidMap::const_iterator iter_t = m_trackToPidMap.find(*pTrack);
+
+                    if(iter_t != m_trackToPidMap.end())
+                    {
+                        trackParameters.m_particleId = (*iter_t).second;
+                        trackParameters.m_mass = pandora::PdgTable::GetParticleMass((*iter_t).second);
+                    }
+
+                    if (std::numeric_limits<float>::epsilon() < std::fabs(signedCurvature))
+                        trackParameters.m_charge = static_cast<int>(signedCurvature / std::fabs(signedCurvature));
+
+                    this->GetTrackStates(pTrack, trackParameters);
+                    this->TrackReachesECAL(pTrack, trackParameters);
+                    this->DefineTrackPfoUsage(pTrack, trackParameters);
+
+                    PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Track::Create(*m_pPandora, trackParameters));
+                    m_trackVector.push_back(pTrack);
+                }
+                catch (pandora::StatusCodeException &statusCodeException)
+                {
+                    std::cout<<"ERROR Failed to extract a track: " << statusCodeException.ToString() << std::endl;
+                }
+                catch (...)
+                {
+                    std::cout << "WARNNING Failed to extract a track "<< std::endl;
+                }
+            }
+        }
+        catch (...)
+        {
+            std::cout<<"WARNING Failed to extract track collection: " << *iter << std::endl;
+        }
+    }
+
+    return pandora::STATUS_CODE_SUCCESS;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::GetTrackStates(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    //const TrackState *pTrackState = pTrack->getTrackState(TrackState::AtIP);
+    edm4hep::TrackState pTrackState = pTrack->getTrackStates(1); // ref  /cvmfs/cepcsw.ihep.ac.cn/prototype/LCIO/include/EVENT/TrackState.h 
+
+    //if (!pTrackState)  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+
+    //const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState->getOmega()));
+    const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState.omega));
+    //trackParameters.m_momentumAtDca = pandora::CartesianVector(std::cos(pTrackState->getPhi()), std::sin(pTrackState->getPhi()), pTrackState->getTanLambda()) * pt;
+    trackParameters.m_momentumAtDca = pandora::CartesianVector(std::cos(pTrackState.phi), std::sin(pTrackState.phi), pTrackState.tanLambda) * pt;
+    //this->CopyTrackState(pTrack->getTrackState(TrackState::AtFirstHit), trackParameters.m_trackStateAtStart);
+    this->CopyTrackState(pTrack->getTrackStates(2), trackParameters.m_trackStateAtStart);
+
+    //fg: curling TPC tracks have pointers to track segments stored -> need to get track states from last segment!
+    //const EVENT::Track *pEndTrack = (pTrack->getTracks().empty() ?  pTrack  :  pTrack->getTracks().back());
+    auto pEndTrack = (pTrack->tracks_size() ==0 ) ?  *pTrack  :  pTrack->getTracks(pTrack->tracks_size()-1);
+
+    //std::cout<<"GetTrackStates 1.6"<<", end track trackStates_size()="<<pEndTrack.trackStates_size()<<std::endl;
+    
+    //this->CopyTrackState(pEndTrack->getTrackState(TrackState::AtLastHit), trackParameters.m_trackStateAtEnd);
+    //this->CopyTrackState(pEndTrack->getTrackState(TrackState::AtCalorimeter), trackParameters.m_trackStateAtCalorimeter);
+    
+    this->CopyTrackState(pEndTrack.getTrackStates(3), trackParameters.m_trackStateAtEnd);
+    //this->CopyTrackState(pEndTrack.getTrackStates(4), trackParameters.m_trackStateAtCalorimeter);
+    //FIXME ? LCIO input only has 4 states, so 4 can't be used.
+    this->CopyTrackState(pEndTrack.getTrackStates(3), trackParameters.m_trackStateAtCalorimeter);
+    
+    
+    trackParameters.m_isProjectedToEndCap = ((std::fabs(trackParameters.m_trackStateAtCalorimeter.Get().GetPosition().GetZ()) < m_eCalEndCapInnerZ) ? false : true);
+
+    // Convert generic time (length from reference point to intersection, divided by momentum) into nanoseconds
+    const float minGenericTime(this->CalculateTrackTimeAtCalorimeter(pTrack));
+    const float particleMass(trackParameters.m_mass.Get());
+    const float particleEnergy(std::sqrt(particleMass * particleMass + trackParameters.m_momentumAtDca.Get().GetMagnitudeSquared()));
+    trackParameters.m_timeAtCalorimeter = minGenericTime * particleEnergy / 299.792f;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+float TrackCreator::CalculateTrackTimeAtCalorimeter(const edm4hep::Track *const pTrack) const
+{
+    //const pandora::Helix helix(pTrack->getPhi(), pTrack->getD0(), pTrack->getZ0(), pTrack->getOmega(), pTrack->getTanLambda(), m_bField);
+    const pandora::Helix helix(pTrack->getTrackStates(0).phi, pTrack->getTrackStates(0).D0, pTrack->getTrackStates(0).Z0, pTrack->getTrackStates(0).omega, pTrack->getTrackStates(0).tanLambda, m_bField);
+    const pandora::CartesianVector &referencePoint(helix.GetReferencePoint());
+
+    // First project to endcap
+    float minGenericTime(std::numeric_limits<float>::max());
+
+    pandora::CartesianVector bestECalProjection(0.f, 0.f, 0.f);
+    const int signPz((helix.GetMomentum().GetZ() > 0.f) ? 1 : -1);
+    (void) helix.GetPointInZ(static_cast<float>(signPz) * m_eCalEndCapInnerZ, referencePoint, bestECalProjection, minGenericTime);
+
+    // Then project to barrel surface(s)
+    pandora::CartesianVector barrelProjection(0.f, 0.f, 0.f);
+    if (m_eCalBarrelInnerSymmetry > 0)
+    {
+        // Polygon
+        float twopi_n = 2. * M_PI / (static_cast<float>(m_eCalBarrelInnerSymmetry));
+
+        for (int i = 0; i < m_eCalBarrelInnerSymmetry; ++i)
+        {
+            float genericTime(std::numeric_limits<float>::max());
+            const float phi(twopi_n * static_cast<float>(i) + m_eCalBarrelInnerPhi0);
+
+            const pandora::StatusCode statusCode(helix.GetPointInXY(m_eCalBarrelInnerR * std::cos(phi), m_eCalBarrelInnerR * std::sin(phi),
+                std::cos(phi + 0.5 * M_PI), std::sin(phi + 0.5 * M_PI), referencePoint, barrelProjection, genericTime));
+
+            if ((pandora::STATUS_CODE_SUCCESS == statusCode) && (genericTime < minGenericTime))
+            {
+                minGenericTime = genericTime;
+                bestECalProjection = barrelProjection;
+            }
+        }
+    }
+    else
+    {
+        // Cylinder
+        float genericTime(std::numeric_limits<float>::max());
+        const pandora::StatusCode statusCode(helix.GetPointOnCircle(m_eCalBarrelInnerR, referencePoint, barrelProjection, genericTime));
+
+        if ((pandora::STATUS_CODE_SUCCESS == statusCode) && (genericTime < minGenericTime))
+        {
+            minGenericTime = genericTime;
+            bestECalProjection = barrelProjection;
+        }
+    }
+
+    if (bestECalProjection.GetMagnitudeSquared() < std::numeric_limits<float>::epsilon())
+        throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+
+    return minGenericTime;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::CopyTrackState(const edm4hep::TrackState & pTrackState, pandora::InputTrackState &inputTrackState) const
+{
+    //if (!pTrackState)  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_INITIALIZED);
+    //const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState->getOmega()));
+    const double pt(m_bField * 2.99792e-4 / std::fabs(pTrackState.omega));
+
+    //const double px(pt * std::cos(pTrackState->getPhi()));
+    const double px(pt * std::cos(pTrackState.phi));
+    //const double py(pt * std::sin(pTrackState->getPhi()));
+    const double py(pt * std::sin(pTrackState.phi));
+    //const double pz(pt * pTrackState->getTanLambda());
+    const double pz(pt * pTrackState.tanLambda);
+
+    const double xs(pTrackState.referencePoint[0]);
+    const double ys(pTrackState.referencePoint[1]);
+    const double zs(pTrackState.referencePoint[2]);
+
+    inputTrackState = pandora::TrackState(xs, ys, zs, px, py, pz);
+}
+
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::TrackReachesECAL(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    
+    // Calculate hit position information
+    float hitZMin(std::numeric_limits<float>::max());
+    float hitZMax(-std::numeric_limits<float>::max());
+    float hitOuterR(-std::numeric_limits<float>::max());
+
+    int maxOccupiedFtdLayer=0;
+    
+    
+    const unsigned int nTrackHits(pTrack->trackerHits_size());
+    for (unsigned int i = 0; i < nTrackHits; ++i)
+    {
+        
+        const edm4hep::ConstTrackerHit Hit ( pTrack->getTrackerHits(i) );
+        const edm4hep::Vector3d pos = Hit.getPosition();
+        
+        float x = float(pos[0]);
+        float y = float(pos[1]);
+        float z = float(pos[2]);
+        float r = std::sqrt(x * x + y * y);
+
+        if (z > hitZMax) hitZMax = z;
+
+        if (z < hitZMin) hitZMin = z;
+
+        if (r > hitOuterR) hitOuterR = r;
+
+        if ((r > m_tpcInnerR) && (r < m_tpcOuterR) && (std::fabs(z) <= m_tpcZmax))  continue;
+
+        for (unsigned int j = 0; j < m_nFtdLayers; ++j)
+        {
+            if ((r > m_ftdInnerRadii[j]) && (r < m_ftdOuterRadii[j]) &&
+                (std::fabs(z) - m_settings.m_reachesECalFtdZMaxDistance < m_ftdZPositions[j]) &&
+                (std::fabs(z) + m_settings.m_reachesECalFtdZMaxDistance > m_ftdZPositions[j]))
+            {
+                //if (static_cast<int>(j) > maxOccupiedFtdLayer) maxOccupiedFtdLayer = static_cast<int>(j);
+                if ( j > maxOccupiedFtdLayer) maxOccupiedFtdLayer = j;
+                break;
+            }
+        }
+    }
+    const int nTpcHits(this->GetNTpcHits(pTrack));
+    const int nFtdHits(this->GetNFtdHits(pTrack));
+
+    // Look to see if there are hits in etd or set, implying track has reached edge of ecal
+    if ((hitOuterR > m_minSetRadius) || (hitZMax > m_minEtdZPosition))
+    {
+        trackParameters.m_reachesCalorimeter = true;
+        return;
+    }
+
+    // Require sufficient hits in tpc or ftd, then compare extremal hit positions with tracker dimensions
+    if ((nTpcHits >= m_settings.m_reachesECalNTpcHits) || (nFtdHits >= m_settings.m_reachesECalNFtdHits))
+    {
+        if ((hitOuterR - m_tpcOuterR > m_settings.m_reachesECalTpcOuterDistance) ||
+            (std::fabs(hitZMax) - m_tpcZmax > m_settings.m_reachesECalTpcZMaxDistance) ||
+            (std::fabs(hitZMin) - m_tpcZmax > m_settings.m_reachesECalTpcZMaxDistance) ||
+            (maxOccupiedFtdLayer >= m_settings.m_reachesECalMinFtdLayer))
+        {
+            trackParameters.m_reachesCalorimeter = true;
+            return;
+        }
+    }
+
+    // If track is lowpt, it may curl up and end inside tpc inner radius
+    const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+    const float cosAngleAtDca(std::fabs(momentumAtDca.GetZ()) / momentumAtDca.GetMagnitude());
+    const float pX(momentumAtDca.GetX()), pY(momentumAtDca.GetY());
+    const float pT(std::sqrt(pX * pX + pY * pY));
+
+    if ((cosAngleAtDca > m_cosTpc) || (pT < m_settings.m_curvatureToMomentumFactor * m_bField * m_tpcOuterR))
+    {
+        trackParameters.m_reachesCalorimeter = true;
+        return;
+    }
+    
+    trackParameters.m_reachesCalorimeter = false;
+    
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+void TrackCreator::DefineTrackPfoUsage(const edm4hep::Track *const pTrack, PandoraApi::Track::Parameters &trackParameters) const
+{
+    bool canFormPfo(false);
+    bool canFormClusterlessPfo(false);
+
+    //if (trackParameters.m_reachesCalorimeter.Get() && !this->IsParent(pTrack))
+    if (trackParameters.m_reachesCalorimeter.Get() && !this->IsParent(pTrack->id()))
+    {
+        //const float d0(std::fabs(pTrack->getD0())), z0(std::fabs(pTrack->getZ0()));
+        const float d0(std::fabs(pTrack->getTrackStates(0).D0)), z0(std::fabs(pTrack->getTrackStates(0).Z0));
+
+        //EVENT::TrackerHitVec trackerHitvec(pTrack->getTrackerHits());
+        float rInner(std::numeric_limits<float>::max()), zMin(std::numeric_limits<float>::max());
+
+        //for (EVENT::TrackerHitVec::const_iterator iter = trackerHitvec.begin(), iterEnd = trackerHitvec.end(); iter != iterEnd; ++iter)
+        for (std::vector<edm4hep::ConstTrackerHit>::const_iterator iter = pTrack->trackerHits_begin(), iterEnd = pTrack->trackerHits_end(); iter != iterEnd; ++iter)
+        {
+            //const double *pPosition((*iter)->getPosition());
+            const edm4hep::Vector3d pPosition = (*iter).getPosition(); 
+            const float x(pPosition[0]), y(pPosition[1]), absoluteZ(std::fabs(pPosition[2]));
+            const float r(std::sqrt(x * x + y * y));
+
+            if (r < rInner)
+                rInner = r;
+
+            if (absoluteZ < zMin)
+                zMin = absoluteZ;
+        }
+
+        if (this->PassesQualityCuts(pTrack, trackParameters))
+        {
+            const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+            const float pX(momentumAtDca.GetX()), pY(momentumAtDca.GetY()), pZ(momentumAtDca.GetZ());
+            const float pT(std::sqrt(pX * pX + pY * pY));
+
+            const float zCutForNonVertexTracks(m_tpcInnerR * std::fabs(pZ / pT) + m_settings.m_zCutForNonVertexTracks);
+            const bool passRzQualityCuts((zMin < zCutForNonVertexTracks) && (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance));
+
+            const bool isV0(this->IsV0(pTrack->id()));
+            const bool isDaughter(this->IsDaughter(pTrack->id()));
+
+            // Decide whether track can be associated with a pandora cluster and used to form a charged PFO
+            if ((d0 < m_settings.m_d0TrackCut) && (z0 < m_settings.m_z0TrackCut) && (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance))
+            {
+                canFormPfo = true;
+            }
+            else if (passRzQualityCuts && (0 != m_settings.m_usingNonVertexTracks))
+            {
+                canFormPfo = true;
+            }
+            else if (isV0 || isDaughter)
+            {
+                canFormPfo = true;
+            }
+
+            // Decide whether track can be used to form a charged PFO, even if track fails to be associated with a pandora cluster
+            const float particleMass(trackParameters.m_mass.Get());
+            const float trackEnergy(std::sqrt(momentumAtDca.GetMagnitudeSquared() + particleMass * particleMass));
+
+            if ((0 != m_settings.m_usingUnmatchedVertexTracks) && (trackEnergy < m_settings.m_unmatchedVertexTrackMaxEnergy))
+            {
+                if ((d0 < m_settings.m_d0UnmatchedVertexTrackCut) && (z0 < m_settings.m_z0UnmatchedVertexTrackCut) &&
+                    (rInner < m_tpcInnerR + m_settings.m_maxTpcInnerRDistance))
+                {
+                    canFormClusterlessPfo = true;
+                }
+                else if (passRzQualityCuts && (0 != m_settings.m_usingNonVertexTracks) && (0 != m_settings.m_usingUnmatchedNonVertexTracks))
+                {
+                    canFormClusterlessPfo = true;
+                }
+                else if (isV0 || isDaughter)
+                {
+                    canFormClusterlessPfo = true;
+                }
+            }
+        }
+        else if (this->IsDaughter(pTrack->id()) || this->IsV0(pTrack->id()))
+        {
+            std::cout<<"WARNING Recovering daughter or v0 track " << trackParameters.m_momentumAtDca.Get().GetMagnitude() << std::endl;
+            canFormPfo = true;
+        }
+    }
+
+    trackParameters.m_canFormPfo = canFormPfo;
+    trackParameters.m_canFormClusterlessPfo = canFormClusterlessPfo;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+bool TrackCreator::PassesQualityCuts(const edm4hep::Track *const pTrack, const PandoraApi::Track::Parameters &trackParameters) const
+{
+    // First simple sanity checks
+    if (trackParameters.m_trackStateAtCalorimeter.Get().GetPosition().GetMagnitude() < m_settings.m_minTrackECalDistanceFromIp)
+        return false;
+
+    //if (std::fabs(pTrack->getOmega()) < std::numeric_limits<float>::epsilon())
+    if (std::fabs(pTrack->getTrackStates(0).omega) < std::numeric_limits<float>::epsilon())
+    {
+        std::cout<<"ERROR Track has Omega = 0 " << std::endl;
+        return false;
+    }
+
+    // Check momentum uncertainty is reasonable to use track
+    const pandora::CartesianVector &momentumAtDca(trackParameters.m_momentumAtDca.Get());
+    //const float sigmaPOverP(std::sqrt(pTrack->getCovMatrix()[5]) / std::fabs(pTrack->getOmega()));
+    const float sigmaPOverP(std::sqrt(pTrack->getTrackStates(0).covMatrix[5]) / std::fabs(pTrack->getTrackStates(0).omega));
+
+    if (sigmaPOverP > m_settings.m_maxTrackSigmaPOverP)
+    {
+        std::cout<<"WARNING Dropping track : " << momentumAtDca.GetMagnitude() << "+-" << sigmaPOverP * (momentumAtDca.GetMagnitude())
+                               << " chi2 = " <<  pTrack->getChi2() << " " << pTrack->getNdf()
+                               << " from " << pTrack->trackerHits_size() << std::endl;
+        return false;
+    }
+
+    // Require reasonable number of TPC hits 
+    if (momentumAtDca.GetMagnitude() > m_settings.m_minMomentumForTrackHitChecks)
+    {
+        const float pX(fabs(momentumAtDca.GetX()));
+        const float pY(fabs(momentumAtDca.GetY()));
+        const float pZ(fabs(momentumAtDca.GetZ()));
+        const float pT(std::sqrt(pX * pX + pY * pY));
+        const float rInnermostHit(pTrack->getRadiusOfInnermostHit());
+
+        if ((std::numeric_limits<float>::epsilon() > std::fabs(pT)) || (std::numeric_limits<float>::epsilon() > std::fabs(pZ)) || (rInnermostHit == m_tpcOuterR))
+        {
+            std::cout<<"ERROR Invalid track parameter, pT " << pT << ", pZ " << pZ << ", rInnermostHit " << rInnermostHit << std::endl;
+            return false;
+        }
+
+        float nExpectedTpcHits(0.);
+
+        if (pZ < m_tpcZmax / m_tpcOuterR * pT)
+        {
+            const float innerExpectedHitRadius(std::max(m_tpcInnerR, rInnermostHit));
+            const float frac((m_tpcOuterR - innerExpectedHitRadius) / (m_tpcOuterR - m_tpcInnerR));
+            nExpectedTpcHits = m_tpcMaxRow * frac;
+        }
+
+        if ((pZ <= m_tpcZmax / m_tpcInnerR * pT) && (pZ >= m_tpcZmax / m_tpcOuterR * pT))
+        {
+            const float innerExpectedHitRadius(std::max(m_tpcInnerR, rInnermostHit));
+            const float frac((m_tpcZmax * pT / pZ - innerExpectedHitRadius) / (m_tpcOuterR - innerExpectedHitRadius));
+            nExpectedTpcHits = frac * m_tpcMaxRow;
+        }
+
+        // TODO Get TPC membrane information from GEAR when available
+        if (std::fabs(pZ) / momentumAtDca.GetMagnitude() < m_settings.m_tpcMembraneMaxZ / m_tpcInnerR)
+            nExpectedTpcHits = 0;
+
+        const int nTpcHits(this->GetNTpcHits(pTrack));
+        const int nFtdHits(this->GetNFtdHits(pTrack));
+
+        const int minTpcHits = static_cast<int>(nExpectedTpcHits * m_settings.m_minTpcHitFractionOfExpected);
+
+        if ((nTpcHits < minTpcHits) && (nFtdHits < m_settings.m_minFtdHitsForTpcHitFraction))
+        {
+            std::cout<<"WARNING Dropping track : " << momentumAtDca.GetMagnitude() << " Number of TPC hits = " << nTpcHits
+                                   << " < " << minTpcHits << " nftd = " << nFtdHits  << std::endl;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+int TrackCreator::GetNTpcHits(const edm4hep::Track *const pTrack) const
+{
+    // ATTN
+    //fg: hit numbers are now given in different order wrt LOI:  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 1 ] =  hitsInFit ;  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 2 ] =  hitCount ;  
+    // ---- use hitsInFit :
+    //return pTrack->getSubdetectorHitNumbers()[ 2 * lcio::ILDDetID::TPC - 1 ];
+    return pTrack->getSubDetectorHitNumbers(2 * lcio::ILDDetID::TPC - 1);// still use LCIO code now
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+int TrackCreator::GetNFtdHits(const edm4hep::Track *const pTrack) const
+{
+    // ATTN
+    //fg: hit numbers are now given in different order wrt LOI:  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 1 ] =  hitsInFit ;  
+    // trk->subdetectorHitNumbers()[ 2 * ILDDetID::TPC - 2 ] =  hitCount ;  
+    // ---- use hitsInFit :
+    //return pTrack->getSubdetectorHitNumbers()[ 2 * lcio::ILDDetID::FTD - 1 ];
+    return pTrack->getSubDetectorHitNumbers( 2 * lcio::ILDDetID::FTD - 1 );
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+TrackCreator::Settings::Settings() :
+    m_shouldFormTrackRelationships(1),
+    m_minTrackHits(5),
+    m_minFtdTrackHits(0),
+    m_maxTrackHits(5000.f),
+    m_d0TrackCut(50.f),
+    m_z0TrackCut(50.f),
+    m_usingNonVertexTracks(1),
+    m_usingUnmatchedNonVertexTracks(0),
+    m_usingUnmatchedVertexTracks(1),
+    m_unmatchedVertexTrackMaxEnergy(5.f),
+    m_d0UnmatchedVertexTrackCut(5.f),
+    m_z0UnmatchedVertexTrackCut(5.f),
+    m_zCutForNonVertexTracks(250.f),
+    m_reachesECalNTpcHits(11),
+    m_reachesECalNFtdHits(4),
+    m_reachesECalTpcOuterDistance(-100.f),
+    m_reachesECalMinFtdLayer(9),
+    m_reachesECalTpcZMaxDistance(-50.f),
+    m_reachesECalFtdZMaxDistance(1.f),
+    m_curvatureToMomentumFactor(0.3f / 2000.f),
+    m_minTrackECalDistanceFromIp(100.f),
+    m_maxTrackSigmaPOverP(0.15f),
+    m_minMomentumForTrackHitChecks(1.f),
+    m_tpcMembraneMaxZ(10.f),
+    m_maxTpcInnerRDistance(50.f),
+    m_minTpcHitFractionOfExpected(0.2f),
+    m_minFtdHitsForTpcHitFraction(2)
+{
+}
diff --git a/Reconstruction/PFA/Pandora/MatrixPandora/src/Utility.cpp b/Reconstruction/PFA/Pandora/MatrixPandora/src/Utility.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..819fa15d4771c80d65e6437d22ebd46120d311de
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/MatrixPandora/src/Utility.cpp
@@ -0,0 +1,7 @@
+#include "Utility.h"
+
+std::string Convert (float number){
+    std::ostringstream buff;
+    buff<<number;
+    return buff.str();   
+}
diff --git a/Reconstruction/PFA/Pandora/PandoraSettingsDefault.xml b/Reconstruction/PFA/Pandora/PandoraSettingsDefault.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8bf0e965b235f94400e68629ec565f5f9fd14db2
--- /dev/null
+++ b/Reconstruction/PFA/Pandora/PandoraSettingsDefault.xml
@@ -0,0 +1,447 @@
+<!-- Pandora settings xml file -->
+
+<pandora>
+    <!-- GLOBAL SETTINGS -->
+    <IsMonitoringEnabled>true</IsMonitoringEnabled>
+    <ShouldDisplayAlgorithmInfo>false</ShouldDisplayAlgorithmInfo>
+    <ShouldCollapseMCParticlesToPfoTarget>true</ShouldCollapseMCParticlesToPfoTarget>
+
+    <!-- PLUGIN SETTINGS -->
+    <!--HadronicEnergyCorrectionPlugins>SoftwareCompensation</HadronicEnergyCorrectionPlugins-->
+    <EmShowerPlugin>LCEmShowerId</EmShowerPlugin>
+    <PhotonPlugin>LCPhotonId</PhotonPlugin>
+    <ElectronPlugin>LCElectronId</ElectronPlugin>
+    <MuonPlugin>LCMuonId</MuonPlugin>
+
+    <!-- ALGORITHM SETTINGS -->
+
+    <!-- Set calo hit properties, then select tracks and hits to use for clustering -->
+    <algorithm type = "CaloHitPreparation"/>
+    <algorithm type = "EventPreparation">
+        <OutputTrackListName>Tracks</OutputTrackListName>
+        <OutputCaloHitListName>CaloHits</OutputCaloHitListName>
+        <OutputMuonCaloHitListName>MuonYokeHits</OutputMuonCaloHitListName>
+        <ReplacementTrackListName>Tracks</ReplacementTrackListName>
+        <ReplacementCaloHitListName>CaloHits</ReplacementCaloHitListName>
+    </algorithm>
+
+    <!-- Standalone muon clustering -->
+    <algorithm type = "MuonReconstruction">
+        <algorithm type = "ConeClustering" description = "MuonClusterFormation">
+            <TanConeAngleCoarse>0.3</TanConeAngleCoarse>
+            <ConeApproachMaxSeparation>2000</ConeApproachMaxSeparation>
+            <MaxClusterDirProjection>2000</MaxClusterDirProjection>
+            <ShouldUseIsolatedHits>true</ShouldUseIsolatedHits>
+            <LayersToStepBackCoarse>30</LayersToStepBackCoarse>
+            <AdditionalPadWidthsCoarse>1</AdditionalPadWidthsCoarse>
+            <SameLayerPadWidthsCoarse>1.8</SameLayerPadWidthsCoarse>
+            <ShouldUseTrackSeed>false</ShouldUseTrackSeed>
+            <MaxTrackSeedSeparation>0</MaxTrackSeedSeparation>
+            <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+            <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+            <TrackPathWidth>0</TrackPathWidth>
+        </algorithm>
+        <!-- Input lists -->
+        <InputTrackListName>Tracks</InputTrackListName>
+        <InputCaloHitListName>CaloHits</InputCaloHitListName>
+        <InputMuonCaloHitListName>MuonYokeHits</InputMuonCaloHitListName>
+        <!-- Output lists -->
+        <OutputTrackListName>MuonRemovedTracks</OutputTrackListName>
+        <OutputCaloHitListName>MuonRemovedCaloHits</OutputCaloHitListName>
+        <OutputMuonCaloHitListName>MuonRemovedYokeHits</OutputMuonCaloHitListName>
+        <OutputMuonClusterListName>MuonClusters</OutputMuonClusterListName>
+        <OutputMuonPfoListName>MuonPfos</OutputMuonPfoListName>
+        <!-- Current list management -->
+        <ReplacementTrackListName>MuonRemovedTracks</ReplacementTrackListName>
+        <ReplacementCaloHitListName>MuonRemovedCaloHits</ReplacementCaloHitListName>
+        <ReplaceCurrentClusterList>false</ReplaceCurrentClusterList>
+        <ReplaceCurrentPfoList>false</ReplaceCurrentPfoList>
+    </algorithm>
+
+    <!-- Standalone photon clustering -->
+    <algorithm type = "PhotonReconstruction">
+        <algorithm type = "ConeClustering" description = "PhotonClusterFormation">
+            <ClusterSeedStrategy>0</ClusterSeedStrategy>
+            <ShouldUseTrackSeed>false</ShouldUseTrackSeed>
+            <ShouldUseOnlyECalHits>true</ShouldUseOnlyECalHits>
+            <ConeApproachMaxSeparation>250.</ConeApproachMaxSeparation>
+        </algorithm>
+        <ClusterListName>PhotonClusters</ClusterListName>
+        <ReplaceCurrentClusterList>false</ReplaceCurrentClusterList>
+        <ShouldMakePdfHistograms>false</ShouldMakePdfHistograms>
+        <HistogramFile>/junofs/users/wxfang/MyGit/MarlinPandora/scripts/PandoraLikelihoodData9EBin.xml</HistogramFile>
+    </algorithm>
+
+    <!-- Clustering parent algorithm runs a daughter clustering algorithm -->
+    <algorithm type = "ClusteringParent">
+        <algorithm type = "ConeClustering" description = "ClusterFormation"/>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation">
+            <associationAlgorithms>
+                <algorithm type = "LoopingTracks"/>
+                <algorithm type = "BrokenTracks"/>
+                <algorithm type = "ShowerMipMerging"/>
+                <algorithm type = "ShowerMipMerging2"/>
+                <algorithm type = "BackscatteredTracks"/>
+                <algorithm type = "BackscatteredTracks2"/>
+                <algorithm type = "ShowerMipMerging3"/>
+                <algorithm type = "ShowerMipMerging4"/>
+                <algorithm type = "ProximityBasedMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "ConeBasedMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "MipPhotonSeparation">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "HighEnergyPhotonRecovery">
+                    <algorithm type = "TrackClusterAssociation"/>
+                    <AdditionalClusterListNames>PhotonClusters</AdditionalClusterListNames>
+                </algorithm>
+                <algorithm type = "SoftClusterMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                    <AdditionalClusterListNames>PhotonClusters</AdditionalClusterListNames>
+                </algorithm>
+                <algorithm type = "IsolatedHitMerging">
+                    <AdditionalClusterListNames>PhotonClusters</AdditionalClusterListNames>
+                </algorithm>
+            </associationAlgorithms>
+        </algorithm>
+        <ClusterListName>PrimaryClusters</ClusterListName>
+        <ReplaceCurrentClusterList>true</ReplaceCurrentClusterList>
+    </algorithm>
+
+    <!-- Reclustering algorithms run multiple clustering algorithms -->
+    <algorithm type = "SplitTrackAssociations" instance = "SplitTrackAssociations1">
+        <clusteringAlgorithms>
+            <algorithm type = "ConeClustering" instance = "Reclustering1">
+                <TanConeAngleFine>0.24</TanConeAngleFine>
+                <TanConeAngleCoarse>0.4</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>2</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>2</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>2.24</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>1.44</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering2">
+                <TanConeAngleFine>0.18</TanConeAngleFine>
+                <TanConeAngleCoarse>0.3</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>1.5</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>1.5</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>1.68</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>1.08</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering3">
+                <TanConeAngleFine>0.15</TanConeAngleFine>
+                <TanConeAngleCoarse>0.25</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>1.25</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>1.25</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>1.4</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.9</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering4">
+                <TanConeAngleFine>0.12</TanConeAngleFine>
+                <TanConeAngleCoarse>0.2</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>1</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>1</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>1.12</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.72</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering5">
+                <TanConeAngleFine>0.09</TanConeAngleFine>
+                <TanConeAngleCoarse>0.15</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>0.75</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>0.75</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>0.84</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.54</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering6">
+                <TanConeAngleFine>0.075</TanConeAngleFine>
+                <TanConeAngleCoarse>0.125</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>0.625</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>0.625</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>0.7</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.45</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering7">
+                <TanConeAngleFine>0.06</TanConeAngleFine>
+                <TanConeAngleCoarse>0.1</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>0.5</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>0.5</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>0.56</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.36</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering8">
+                <TanConeAngleFine>0.045</TanConeAngleFine>
+                <TanConeAngleCoarse>0.075</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>0.375</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>0.375</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>0.42</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.27</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering9">
+                <TanConeAngleFine>0.03</TanConeAngleFine>
+                <TanConeAngleCoarse>0.05</TanConeAngleCoarse>
+                <AdditionalPadWidthsFine>0.25</AdditionalPadWidthsFine>
+                <AdditionalPadWidthsCoarse>0.25</AdditionalPadWidthsCoarse>
+                <SameLayerPadWidthsFine>0.28</SameLayerPadWidthsFine>
+                <SameLayerPadWidthsCoarse>0.18</SameLayerPadWidthsCoarse>
+                <MaxTrackSeedSeparation>100</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering10">
+                <MaxTrackSeedSeparation>250</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>3</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>3</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>2</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering11">
+                <ShouldUseTrackSeed>false</ShouldUseTrackSeed>
+                <MaxTrackSeedSeparation>0</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+            <algorithm type = "ConeClustering" instance = "Reclustering12">
+                <MaxTrackSeedSeparation>1000</MaxTrackSeedSeparation>
+                <MaxLayersToTrackSeed>6</MaxLayersToTrackSeed>
+                <MaxLayersToTrackLikeHit>3</MaxLayersToTrackLikeHit>
+                <TrackPathWidth>0</TrackPathWidth>
+            </algorithm>
+        </clusteringAlgorithms>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation" instance = "reclusterAssociation">
+            <associationAlgorithms>
+                <algorithm type = "LoopingTracks"/>
+                <algorithm type = "BrokenTracks"/>
+                <algorithm type = "ShowerMipMerging"/>
+                <algorithm type = "ShowerMipMerging2"/>
+                <algorithm type = "BackscatteredTracks"/>
+                <algorithm type = "BackscatteredTracks2"/>
+                <algorithm type = "ShowerMipMerging3"/>
+                <algorithm type = "ShowerMipMerging4"/>
+                <algorithm type = "ProximityBasedMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "ConeBasedMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "MipPhotonSeparation">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "SoftClusterMerging">
+                    <algorithm type = "TrackClusterAssociation"/>
+                </algorithm>
+                <algorithm type = "IsolatedHitMerging"/>
+            </associationAlgorithms>
+        </algorithm>
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+        <UsingOrderedAlgorithms>true</UsingOrderedAlgorithms>
+        <ShouldUseForcedClustering>true</ShouldUseForcedClustering>
+        <algorithm type = "ForcedClustering" description = "ForcedClustering"/>
+    </algorithm>
+
+    <algorithm type = "SplitMergedClusters" instance = "SplitMergedClusters1">
+        <clusteringAlgorithms>
+            <algorithm type = "ConeClustering" instance = "Reclustering1"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering2"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering3"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering4"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering5"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering6"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering7"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering8"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering9"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering10"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering11"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering12"/>
+        </clusteringAlgorithms>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation" instance = "reclusterAssociation"></algorithm>
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+        <UsingOrderedAlgorithms>true</UsingOrderedAlgorithms>
+        <ShouldUseForcedClustering>true</ShouldUseForcedClustering>
+        <algorithm type = "ForcedClustering" description = "ForcedClustering"/>
+    </algorithm>
+
+    <algorithm type = "TrackDrivenMerging">
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+    </algorithm>
+
+    <algorithm type = "ResolveTrackAssociations">
+        <clusteringAlgorithms>
+            <algorithm type = "ConeClustering" instance = "Reclustering1"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering2"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering3"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering4"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering5"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering6"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering7"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering8"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering9"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering10"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering11"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering12"/>
+        </clusteringAlgorithms>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation" instance = "reclusterAssociation"></algorithm>
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+        <UsingOrderedAlgorithms>true</UsingOrderedAlgorithms>
+        <ShouldUseForcedClustering>true</ShouldUseForcedClustering>
+        <algorithm type = "ForcedClustering" description = "ForcedClustering"/>
+    </algorithm>
+
+    <algorithm type = "SplitTrackAssociations" instance = "SplitTrackAssociations1"/>
+    <algorithm type = "SplitMergedClusters" instance = "SplitMergedClusters1"/>
+
+    <algorithm type = "TrackDrivenAssociation">
+        <clusteringAlgorithms>
+            <algorithm type = "ConeClustering" instance = "Reclustering1"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering2"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering3"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering4"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering5"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering6"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering7"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering8"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering9"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering10"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering11"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering12"/>
+        </clusteringAlgorithms>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation" instance = "reclusterAssociation"></algorithm>
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+        <UsingOrderedAlgorithms>true</UsingOrderedAlgorithms>
+    </algorithm>
+
+    <algorithm type = "SplitTrackAssociations" instance = "SplitTrackAssociations1"/>
+    <algorithm type = "SplitMergedClusters" instance = "SplitMergedClusters1"/>
+
+    <algorithm type = "ExitingTrack">
+        <clusteringAlgorithms>
+            <algorithm type = "ConeClustering" instance = "Reclustering1"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering2"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering3"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering4"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering5"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering6"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering7"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering8"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering9"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering10"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering11"/>
+            <algorithm type = "ConeClustering" instance = "Reclustering12"/>
+        </clusteringAlgorithms>
+        <algorithm type = "TopologicalAssociationParent" description = "ClusterAssociation" instance = "reclusterAssociation"></algorithm>
+        <algorithm type = "TrackClusterAssociation" description = "TrackClusterAssociation"></algorithm>
+        <UsingOrderedAlgorithms>true</UsingOrderedAlgorithms>
+        <ShouldUseForcedClustering>true</ShouldUseForcedClustering>
+        <algorithm type = "ForcedClustering" description = "ForcedClustering"/>
+    </algorithm>
+
+    <!-- Muon clustering -->
+    <algorithm type = "ClusteringParent">
+        <algorithm type = "ConeClustering" description = "ClusterFormation">
+            <TanConeAngleCoarse>0.75</TanConeAngleCoarse>
+            <AdditionalPadWidthsCoarse>12.5</AdditionalPadWidthsCoarse>
+            <SameLayerPadWidthsCoarse>14</SameLayerPadWidthsCoarse>
+            <ShouldUseTrackSeed>false</ShouldUseTrackSeed>
+            <MaxClusterDirProjection>1000</MaxClusterDirProjection>
+            <MaxTrackSeedSeparation>0</MaxTrackSeedSeparation>
+            <MaxLayersToTrackSeed>0</MaxLayersToTrackSeed>
+            <MaxLayersToTrackLikeHit>0</MaxLayersToTrackLikeHit>
+            <TrackPathWidth>0</TrackPathWidth>
+        </algorithm>
+        <InputCaloHitListName>MuonRemovedYokeHits</InputCaloHitListName>
+        <RestoreOriginalCaloHitList>true</RestoreOriginalCaloHitList>
+        <ClusterListName>MuonRemovedYokeClusters</ClusterListName>
+        <ReplaceCurrentClusterList>false</ReplaceCurrentClusterList>
+    </algorithm>
+
+    <algorithm type = "MuonClusterAssociation">
+        <TargetClusterListName>PrimaryClusters</TargetClusterListName>
+        <MuonClusterListName>MuonRemovedYokeClusters</MuonClusterListName>
+    </algorithm>
+
+    <!-- Photon recovery -->
+    <algorithm type = "PhotonRecovery">
+        <algorithm type = "TrackClusterAssociation"/>
+    </algorithm>
+
+    <algorithm type = "MuonPhotonSeparation">
+        <algorithm type = "TrackClusterAssociation"/>
+    </algorithm>
+
+    <!-- Prepare particle flow objects -->
+    <algorithm type = "TrackPreparation">
+        <CandidateListNames>Input</CandidateListNames>
+        <MergedCandidateListName>PfoCandidates</MergedCandidateListName>
+        <PfoTrackListName>PfoCreation</PfoTrackListName>
+        <trackClusterAssociationAlgorithms>
+            <algorithm type = "TrackClusterAssociation"/>
+            <algorithm type = "LoopingTrackAssociation"/>
+            <algorithm type = "TrackRecovery"/>
+            <algorithm type = "TrackRecoveryHelix"/>
+            <algorithm type = "TrackRecoveryInteractions"/>
+        </trackClusterAssociationAlgorithms>
+    </algorithm>
+
+    <algorithm type = "MainFragmentRemoval"/>
+    <algorithm type = "NeutralFragmentRemoval"/>
+    <algorithm type = "PhotonFragmentRemoval"/>
+
+    <algorithm type = "ClusterPreparation">
+        <CandidateListNames>PrimaryClusters PhotonClusters</CandidateListNames>
+        <MergedCandidateListName>PfoCreation</MergedCandidateListName>
+    </algorithm>
+
+    <algorithm type = "PhotonSplitting"/>
+    <algorithm type = "PhotonFragmentMerging"/>
+
+    <!-- Create particle flow objects -->
+    <algorithm type = "ForceSplitTrackAssociations"/>
+    <algorithm type = "PfoCreation">
+        <OutputPfoListName>PrimaryAndPhotonPfos</OutputPfoListName>
+    </algorithm>
+
+    <algorithm type = "PfoPreparation">
+        <CandidateListNames>PrimaryAndPhotonPfos MuonPfos</CandidateListNames>
+        <MergedCandidateListName>OutputPfos</MergedCandidateListName>
+    </algorithm>
+
+    <!-- Particle flow object modification algorithms -->
+    <algorithm type = "FinalParticleId"/>
+    <algorithm type = "V0PfoCreation"/>
+    <!--algorithm type = "DumpPfosMonitoring"/-->
+    <!--algorithm type = "VisualMonitoring"/-->
+</pandora>
diff --git a/Simulation/DetSimAna/CMakeLists.txt b/Simulation/DetSimAna/CMakeLists.txt
index 9ce9742255109c63a8b3f1898f0c4d945214dfe7..e0c9aca523f0e6f33ffc9b33c40a2d7aca33c971 100644
--- a/Simulation/DetSimAna/CMakeLists.txt
+++ b/Simulation/DetSimAna/CMakeLists.txt
@@ -12,17 +12,33 @@ find_package(DD4hep COMPONENTS DDG4 REQUIRED)
 
 # For EDM & I/O
 find_package(podio REQUIRED)
-find_package(plcio REQUIRED)
+find_package(EDM4HEP REQUIRED)
 # find_package(LCIO REQUIRED)
 
 set(DetSimAna_srcs
-    src/ExampleAnaElemTool.cpp
+#    src/ExampleAnaElemTool.cpp
+    src/Edm4hepWriterAnaElemTool.cpp
 )
 message("podio_LIBRARIES: ${podio_LIBRARIES}")
-message("plcio_LIBRARIES: ${plcio_LIBRARIES}")
 gaudi_add_module(DetSimAna ${DetSimAna_srcs}
-    INCLUDE_DIRS DetSimInterface FWCore DD4hep GaudiKernel Geant4 
-                 ${plcio_INCLUDE_DIRS} ${podio_INCLUDE_DIRS}
-    LINK_LIBRARIES DetSimInterface FWCore DD4hep ${DD4hep_COMPONENT_LIBRARIES} GaudiKernel Geant4
-                 ${plcio_LIBRARIES} ${podio_LIBRARIES}
+    INCLUDE_DIRS
+      # DetSimInterface
+      # FWCore
+      # DD4hep
+      # GaudiKernel
+      # Geant4 
+      # ${plcio_INCLUDE_DIRS}
+      # ${podio_INCLUDE_DIRS}
+    LINK_LIBRARIES
+      # DetSimInterface
+      # FWCore
+      DD4hep
+      ${DD4hep_COMPONENT_LIBRARIES} 
+      GaudiKernel
+      # Geant4
+
+      -Wl,--no-as-needed 
+      EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+      -Wl,--as-needed 
+      # ${podio_LIBRARIES}
 )
diff --git a/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.cpp b/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1efe317dacdd17cacbf796f7bd61241b7c9079b7
--- /dev/null
+++ b/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.cpp
@@ -0,0 +1,293 @@
+#include "Edm4hepWriterAnaElemTool.h"
+
+#include "G4Event.hh"
+#include "G4THitsCollection.hh"
+
+#include "DD4hep/Detector.h"
+#include "DD4hep/Plugins.h"
+#include "DDG4/Geant4Converter.h"
+#include "DDG4/Geant4Mapping.h"
+#include "DDG4/Geant4HitCollection.h"
+#include "DDG4/Geant4Data.h"
+#include "DDG4/Geant4Hits.h"
+
+DECLARE_COMPONENT(Edm4hepWriterAnaElemTool)
+
+void
+Edm4hepWriterAnaElemTool::BeginOfRunAction(const G4Run*) {
+    G4cout << "Begin Run of detector simultion..." << G4endl;
+}
+
+void
+Edm4hepWriterAnaElemTool::EndOfRunAction(const G4Run*) {
+    G4cout << "End Run of detector simultion..." << G4endl;
+}
+
+void
+Edm4hepWriterAnaElemTool::BeginOfEventAction(const G4Event* anEvent) {
+    msg() << "Event " << anEvent->GetEventID() << endmsg;
+
+    // reset
+    m_track2primary.clear();
+
+}
+
+void
+Edm4hepWriterAnaElemTool::EndOfEventAction(const G4Event* anEvent) {
+    auto mcCol = m_mcParCol.get();
+    msg() << "mcCol size: " << mcCol->size() << endmsg;
+    // save all data
+
+    // create collections.
+    auto trackercols = m_trackerCol.createAndPut();
+    auto calorimetercols = m_calorimeterCol.createAndPut();
+    auto calocontribcols = m_caloContribCol.createAndPut();
+
+    auto vxdcols = m_VXDCol.createAndPut();
+    auto ftdcols = m_FTDCol.createAndPut();
+    auto sitcols = m_SITCol.createAndPut();
+    auto tpccols = m_TPCCol.createAndPut();
+    auto setcols = m_SETCol.createAndPut();
+
+    auto ecalbarrelcol            = m_EcalBarrelCol.createAndPut();
+    auto ecalbarrelcontribcols    = m_EcalBarrelContributionCol.createAndPut();
+    auto ecalendcapscol           = m_EcalEndcapsCol.createAndPut();
+    auto ecalendcapscontribcols   = m_EcalEndcapsContributionCol.createAndPut();
+    auto ecalendcapringcol        = m_EcalEndcapRingCol.createAndPut();
+    auto ecalendcapringcontribcol = m_EcalEndcapRingContributionCol.createAndPut();
+
+    // readout defined in DD4hep
+    auto lcdd = &(dd4hep::Detector::getInstance());
+    auto allReadouts = lcdd->readouts();
+
+    for (auto& readout : allReadouts) {
+        info() << "Readout " << readout.first << endmsg;
+    }
+
+    // retrieve the hit collections
+    G4HCofThisEvent* collections = anEvent->GetHCofThisEvent();
+    if (!collections) {
+        warning() << "No collections found. " << endmsg;
+        return;
+    }
+    int Ncol = collections->GetNumberOfCollections();
+    for (int icol = 0; icol < Ncol; ++icol) {
+        G4VHitsCollection* collect = collections->GetHC(icol);
+        if (!collect) {
+            warning() << "Collection iCol " << icol << " is missing" << endmsg;
+            continue;
+        }
+        size_t nhits = collect->GetSize();
+        info() << "Collection " << collect->GetName()
+               << " #" << icol
+               << " has " << nhits << " hits."
+               << endmsg;
+        if (nhits==0) {
+            // just skip this collection.
+            continue;
+        }
+
+        edm4hep::SimTrackerHitCollection* tracker_col_ptr = nullptr;
+        edm4hep::SimCalorimeterHitCollection* calo_col_ptr = nullptr;
+        edm4hep::CaloHitContributionCollection* calo_contrib_col_ptr = nullptr;
+
+        // the mapping between hit collection and the data handler
+        if (collect->GetName() == "VXDCollection") {
+            tracker_col_ptr = vxdcols;
+        } else if (collect->GetName() == "FTDCollection") {
+            tracker_col_ptr = ftdcols;
+        } else if (collect->GetName() == "SITCollection") {
+            tracker_col_ptr = sitcols;
+        } else if (collect->GetName() == "TPCCollection") {
+            tracker_col_ptr = tpccols;
+        } else if (collect->GetName() == "SETCollection") {
+            tracker_col_ptr = setcols;
+        } else if (collect->GetName() == "SETCollection") {
+            tracker_col_ptr = setcols;
+        } else if (collect->GetName() == "CaloHitsCollection") {
+            calo_col_ptr = calorimetercols;
+            calo_contrib_col_ptr = calocontribcols;
+        } else if (collect->GetName() == "EcalBarrelCollection") {
+            calo_col_ptr = ecalbarrelcol;
+            calo_contrib_col_ptr = ecalbarrelcontribcols;
+        } else if (collect->GetName() == "EcalEndcapsCollection") {
+            calo_col_ptr = ecalendcapscol;
+            calo_contrib_col_ptr = ecalendcapscontribcols;
+        } else if (collect->GetName() == "EcalEndcapRingCollection") {
+            calo_col_ptr = ecalendcapringcol;
+            calo_contrib_col_ptr = ecalendcapringcontribcol;
+        } else {
+            warning() << "Unknown collection name: " << collect->GetName()
+                      << ". Please register in Edm4hepWriterAnaElemTool. " << endmsg;
+            continue;
+        }
+
+
+
+        // There are different types (new and old)
+
+        dd4hep::sim::Geant4HitCollection* coll = dynamic_cast<dd4hep::sim::Geant4HitCollection*>(collect);
+        if (coll) {
+            info() << " cast to dd4hep::sim::Geant4HitCollection. " << endmsg;
+            for(size_t i=0; i<nhits; ++i)   {
+
+                dd4hep::sim::Geant4HitData* h = coll->hit(i);
+
+                dd4hep::sim::Geant4Tracker::Hit* trk_hit = dynamic_cast<dd4hep::sim::Geant4Tracker::Hit*>(h);
+                if ( 0 != trk_hit )   {
+                    dd4hep::sim::Geant4HitData::Contribution& t = trk_hit->truth;
+                    int trackID = t.trackID;
+                    // t.trackID = m_truth->particleID(trackID);
+                }
+                // Geant4Calorimeter::Hit* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h);
+                // if ( 0 != cal_hit )   {
+                //     Geant4HitData::Contributions& c = cal_hit->truth;
+                //     for(Geant4HitData::Contributions::iterator j=c.begin(); j!=c.end(); ++j)  {
+                //         Geant4HitData::Contribution& t = *j;
+                //         int trackID = t.trackID;
+                //         // t.trackID = m_truth->particleID(trackID);
+                //     }
+                // }
+            }
+            continue;
+        }
+
+        typedef G4THitsCollection<dd4hep::sim::Geant4Hit> HitCollection;
+        HitCollection* coll2 = dynamic_cast<HitCollection*>(collect);
+
+        if (coll2) {
+            info() << " cast to G4THitsCollection<dd4hep::sim::Geant4Hit>. " << endmsg;
+
+            int n_trk_hit = 0;
+            int n_cal_hit = 0;
+
+            for(size_t i=0; i<nhits; ++i)   {
+                dd4hep::sim::Geant4Hit* h = dynamic_cast<dd4hep::sim::Geant4Hit*>(coll2->GetHit(i));
+                if (!h) {
+                    warning() << "Failed to cast to dd4hep::sim::Geant4Hit. " << endmsg;
+                    continue;
+                }
+
+                dd4hep::sim::Geant4TrackerHit* trk_hit = dynamic_cast<dd4hep::sim::Geant4TrackerHit*>(h);
+                if (trk_hit) {
+                    ++n_trk_hit;
+                    // auto edm_trk_hit = trackercols->create();
+                    auto edm_trk_hit = tracker_col_ptr->create();
+
+                    edm_trk_hit.setCellID(trk_hit->cellID);
+                    edm_trk_hit.setEDep(trk_hit->energyDeposit/CLHEP::GeV);
+                    edm_trk_hit.setTime(trk_hit->truth.time/CLHEP::ns);
+                    edm_trk_hit.setPathLength(trk_hit->length/CLHEP::mm);
+                    // lc_hit->setMCParticle(lc_mcp);
+                    double pos[3] = {trk_hit->position.x()/CLHEP::mm,
+                                     trk_hit->position.y()/CLHEP::mm,
+                                     trk_hit->position.z()/CLHEP::mm};
+                    edm_trk_hit.setPosition(edm4hep::Vector3d(pos));
+
+                    float mom[3] = {trk_hit->momentum.x()/CLHEP::GeV,
+                                    trk_hit->momentum.y()/CLHEP::GeV,
+                                    trk_hit->momentum.z()/CLHEP::GeV};
+                    edm_trk_hit.setMomentum(edm4hep::Vector3f(mom));
+                }
+
+                dd4hep::sim::Geant4CalorimeterHit* cal_hit = dynamic_cast<dd4hep::sim::Geant4CalorimeterHit*>(h);
+                if (cal_hit) {
+                    ++n_cal_hit;
+                    auto edm_calo_hit = calo_col_ptr->create();
+                    edm_calo_hit.setCellID(cal_hit->cellID);
+                    edm_calo_hit.setEnergy(cal_hit->energyDeposit/CLHEP::GeV);
+                    float pos[3] = {cal_hit->position.x()/CLHEP::mm,
+                                    cal_hit->position.y()/CLHEP::mm,
+                                    cal_hit->position.z()/CLHEP::mm};
+                    edm_calo_hit.setPosition(edm4hep::Vector3f(pos));
+
+                    // contribution
+                    typedef dd4hep::sim::Geant4CalorimeterHit::Contributions Contributions;
+                    typedef dd4hep::sim::Geant4CalorimeterHit::Contribution Contribution;
+                    for (Contributions::const_iterator j = cal_hit->truth.begin();
+                         j != cal_hit->truth.end(); ++j) {
+                        const Contribution& c = *j;
+                        // The legacy Hit object does not contains positions of contributions.
+                        // float contrib_pos[] = {float(c.x/mm), float(c.y/mm), float(c.z/mm)};
+                        auto edm_calo_contrib = calo_contrib_col_ptr->create();
+                        edm_calo_contrib.setPDG(c.pdgID);
+                        edm_calo_contrib.setEnergy(c.deposit/CLHEP::GeV);
+                        edm_calo_contrib.setTime(c.time/CLHEP::ns);
+                        edm_calo_contrib.setStepPosition(edm4hep::Vector3f(pos));
+
+                        // from the track id, get the primary track
+                        int pritrkid = m_track2primary[c.trackID];
+                        if (pritrkid<=0) {
+                            error() << "Failed to find the primary track for trackID #" << c.trackID << endmsg;
+                            pritrkid = 1;
+                        }
+
+                        edm_calo_contrib.setParticle(mcCol->at(pritrkid-1)); // todo
+                        edm_calo_hit.addToContributions(edm_calo_contrib);
+                    }
+                }
+
+            }
+
+            info() << n_trk_hit << " hits cast to dd4hep::sim::Geant4TrackerHit. " << endmsg;
+            info() << n_cal_hit << " hits cast to dd4hep::sim::Geant4CalorimeterHit. " << endmsg;
+
+
+            continue;
+        }
+
+        warning() << "Failed to convert to collection "
+                  << collect->GetName()
+                  << endmsg;
+        
+    }
+}
+
+void
+Edm4hepWriterAnaElemTool::PreUserTrackingAction(const G4Track* track) {
+    int curtrkid = track->GetTrackID();
+    int curparid = track->GetParentID();
+    int pritrkid = curparid;
+
+    // try to find the primary track id from the parent track id.
+    if (curparid) {
+        auto it = m_track2primary.find(curparid);
+        if (it == m_track2primary.end()) {
+            error() << "Failed to find primary track for track id " << curparid << endmsg;
+        } else {
+            pritrkid = it->second;
+        }
+    } else {
+        // curparid is 0, it is primary
+        pritrkid = curtrkid;
+    }
+
+
+    m_track2primary[curtrkid] = pritrkid;
+}
+
+void
+Edm4hepWriterAnaElemTool::PostUserTrackingAction(const G4Track*) {
+
+}
+
+void
+Edm4hepWriterAnaElemTool::UserSteppingAction(const G4Step*) {
+
+}
+
+StatusCode
+Edm4hepWriterAnaElemTool::initialize() {
+    StatusCode sc;
+
+    return sc;
+}
+
+StatusCode
+Edm4hepWriterAnaElemTool::finalize() {
+    StatusCode sc;
+
+    return sc;
+}
+
+
diff --git a/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.h b/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..2e69d24e8f6d5858f1efa86a543c2816aefbf83d
--- /dev/null
+++ b/Simulation/DetSimAna/src/Edm4hepWriterAnaElemTool.h
@@ -0,0 +1,100 @@
+#ifndef Edm4hepWriterAnaElemTool_h
+#define Edm4hepWriterAnaElemTool_h
+
+#include <map>
+
+#include "GaudiKernel/AlgTool.h"
+#include "FWCore/DataHandle.h"
+#include "DetSimInterface/IAnaElemTool.h"
+
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/SimTrackerHitCollection.h"
+#include "edm4hep/SimCalorimeterHitCollection.h"
+#include "edm4hep/CaloHitContributionCollection.h"
+
+class Edm4hepWriterAnaElemTool: public extends<AlgTool, IAnaElemTool> {
+
+public:
+
+    using extends::extends;
+
+    /// IAnaElemTool interface
+    // Run
+    virtual void BeginOfRunAction(const G4Run*) override;
+    virtual void EndOfRunAction(const G4Run*) override;
+
+    // Event
+    virtual void BeginOfEventAction(const G4Event*) override;
+    virtual void EndOfEventAction(const G4Event*) override;
+
+    // Tracking
+    virtual void PreUserTrackingAction(const G4Track*) override;
+    virtual void PostUserTrackingAction(const G4Track*) override;
+
+    // Stepping
+    virtual void UserSteppingAction(const G4Step*) override;
+
+
+    /// Overriding initialize and finalize
+    StatusCode initialize() override;
+    StatusCode finalize() override;
+
+private:
+    // In order to associate MCParticle with contribution, we need to access MC Particle.
+    DataHandle<edm4hep::MCParticleCollection> m_mcParCol{"MCParticle", 
+            Gaudi::DataHandle::Writer, this};
+
+    // Generic collections for Tracker and Calorimeter
+    DataHandle<edm4hep::SimTrackerHitCollection> m_trackerCol{"SimTrackerCol", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimCalorimeterHitCollection> m_calorimeterCol{"SimCalorimeterCol", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::CaloHitContributionCollection> m_caloContribCol{"SimCaloContributionCol", 
+            Gaudi::DataHandle::Writer, this};
+
+    // Dedicated collections for CEPC
+    DataHandle<edm4hep::SimTrackerHitCollection> m_VXDCol{"VXDCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimTrackerHitCollection> m_FTDCol{"FTDCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimTrackerHitCollection> m_SITCol{"SITCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimTrackerHitCollection> m_TPCCol{"TPCCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimTrackerHitCollection> m_SETCol{"SETCollection", 
+            Gaudi::DataHandle::Writer, this};
+
+    // Ecal
+    DataHandle<edm4hep::SimCalorimeterHitCollection> m_EcalBarrelCol{"EcalBarrelCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::CaloHitContributionCollection> m_EcalBarrelContributionCol{
+            "EcalBarrelContributionCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimCalorimeterHitCollection> m_EcalEndcapsCol{"EcalEndcapsCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::CaloHitContributionCollection> m_EcalEndcapsContributionCol{
+            "EcalEndcapsContributionCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::SimCalorimeterHitCollection> m_EcalEndcapRingCol{"EcalEndcapRingCollection", 
+            Gaudi::DataHandle::Writer, this};
+    DataHandle<edm4hep::CaloHitContributionCollection> m_EcalEndcapRingContributionCol{
+            "EcalEndcapRingContributionCollection", 
+            Gaudi::DataHandle::Writer, this};
+
+private:
+    // in order to associate the hit contribution with the primary track,
+    // we have a bookkeeping of every track.
+    // The primary track will assign the same key/value.
+
+    // Following is an example:
+    //    1 -> 1,
+    //    2 -> 2,
+    //    3 -> 1,
+    // Now, if parent of trk #4 is trk #3, using the mapping {3->1} could 
+    // locate the primary trk #1.
+
+    std::map<int, int> m_track2primary;
+
+};
+
+#endif
diff --git a/Simulation/DetSimCore/CMakeLists.txt b/Simulation/DetSimCore/CMakeLists.txt
index 95d56bc0fff525e284be32dc355be27c9207a0c9..bf58dded63633952e51bc3400513d450366c60e6 100644
--- a/Simulation/DetSimCore/CMakeLists.txt
+++ b/Simulation/DetSimCore/CMakeLists.txt
@@ -9,7 +9,8 @@ gaudi_depends_on_subdirs(
 find_package(Geant4 REQUIRED ui_all vis_all)
 include(${Geant4_USE_FILE})
 find_package(podio REQUIRED)
-find_package(plcio REQUIRED) 
+find_package(EDM4HEP REQUIRED)
+find_package(DD4hep COMPONENTS DDG4 REQUIRED)
 
 set(DetSimCore_srcs
     src/DetSimAlg.cpp
@@ -24,7 +25,20 @@ set(DetSimCore_srcs
     src/SteppingAction.cpp
 )
 
+message(" Geant4_LIBRARIES: ${Geant4_LIBRARIES}")
+
 gaudi_add_module(DetSimCore ${DetSimCore_srcs}
-    INCLUDE_DIRS DetSimInterface GaudiKernel Geant4 plcio ${plcio_INCLUDE_DIRS} ${podio_INCLUDE_DIRS}
-    LINK_LIBRARIES DetSimInterface GaudiKernel Geant4 plcio podio
+    INCLUDE_DIRS
+      # DetSimInterface
+      # GaudiKernel
+      # Geant4
+      # plcio ${plcio_INCLUDE_DIRS} ${podio_INCLUDE_DIRS}
+    LINK_LIBRARIES
+      DetSimInterface
+      GaudiKernel
+      # Geant4
+      # ${Geant4_LIBRARIES}
+      DD4hep ${DD4hep_COMPONENT_LIBRARIES} 
+      EDM4HEP::edm4hep EDM4HEP::edm4hepDict
+      # podio
 )
diff --git a/Simulation/DetSimCore/src/G4PrimaryCnvTool.cpp b/Simulation/DetSimCore/src/G4PrimaryCnvTool.cpp
index 3a79e9d95bf268bd5777ed88d6321b369b103c66..d725aa27dead84d3b95df9fc66c0c990f9189fe4 100644
--- a/Simulation/DetSimCore/src/G4PrimaryCnvTool.cpp
+++ b/Simulation/DetSimCore/src/G4PrimaryCnvTool.cpp
@@ -24,7 +24,7 @@ bool G4PrimaryCnvTool::mutate(G4Event* anEvent) {
         }
 
         // vertex
-        const plcio::DoubleThree& vertex = p.getVertex();
+        const edm4hep::Vector3d& vertex = p.getVertex();
         double t = p.getTime()*CLHEP::ns;
         G4PrimaryVertex* g4vtx = new G4PrimaryVertex(vertex.x*CLHEP::mm,
                                                      vertex.y*CLHEP::mm,
@@ -36,7 +36,7 @@ bool G4PrimaryCnvTool::mutate(G4Event* anEvent) {
         G4ParticleDefinition* particle_def = particletbl->FindParticle(pdgcode);
 
         // momentum
-        const plcio::FloatThree& momentum = p.getMomentum();
+        const edm4hep::Vector3f& momentum = p.getMomentum();
         G4PrimaryParticle* g4prim = new G4PrimaryParticle(particle_def,
                                                           momentum.x*CLHEP::GeV,
                                                           momentum.y*CLHEP::GeV,
diff --git a/Simulation/DetSimCore/src/G4PrimaryCnvTool.h b/Simulation/DetSimCore/src/G4PrimaryCnvTool.h
index 3aaf2997ceccd780f3b477809db33ba093d791b0..ed0fd4b5ba5453ad229d9e0981eced6e6036c9d4 100644
--- a/Simulation/DetSimCore/src/G4PrimaryCnvTool.h
+++ b/Simulation/DetSimCore/src/G4PrimaryCnvTool.h
@@ -5,8 +5,8 @@
 #include "DetSimInterface/IG4PrimaryCnvTool.h"
 #include "FWCore/DataHandle.h"
 
-#include "plcio/EventHeaderCollection.h"
-#include "plcio/MCParticleCollection.h"
+#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/MCParticleCollection.h"
 
 class G4PrimaryCnvTool: public extends<AlgTool, IG4PrimaryCnvTool> {
 public:
@@ -16,7 +16,7 @@ public:
     bool mutate(G4Event* anEvent) override;
 
 private:
-    DataHandle<plcio::MCParticleCollection> m_mcParCol{"MCParticle", Gaudi::DataHandle::Reader, this};
+    DataHandle<edm4hep::MCParticleCollection> m_mcParCol{"MCParticle", Gaudi::DataHandle::Reader, this};
 
 };
 
diff --git a/Simulation/DetSimGeom/CMakeLists.txt b/Simulation/DetSimGeom/CMakeLists.txt
index fa2c440132cce35f7cbe21f14bbc850f42c2eac7..a3b5f3249132d19400359fd728b2dbe676df34a9 100644
--- a/Simulation/DetSimGeom/CMakeLists.txt
+++ b/Simulation/DetSimGeom/CMakeLists.txt
@@ -16,6 +16,14 @@ set(DetSimGeom_srcs
 )
 
 gaudi_add_module(DetSimGeom ${DetSimGeom_srcs}
-    INCLUDE_DIRS DetSimInterface DetInterface DD4hep GaudiKernel Geant4
-    LINK_LIBRARIES DetSimInterface DD4hep ${DD4hep_COMPONENT_LIBRARIES} GaudiKernel Geant4
+    INCLUDE_DIRS
+    # DetSimInterface
+    # DetInterface
+    # DD4hep
+    # GaudiKernel
+    # Geant4
+    LINK_LIBRARIES
+      DD4hep ${DD4hep_COMPONENT_LIBRARIES} 
+      GaudiKernel 
+      # Geant4
 )
diff --git a/Simulation/DetSimGeom/src/AnExampleDetElemTool.cpp b/Simulation/DetSimGeom/src/AnExampleDetElemTool.cpp
index 8ba60b44292a86bf678bbfe650b1e44078bcbfb9..ff31cdf11c5cf4167272597d227ea9c58a0f997e 100644
--- a/Simulation/DetSimGeom/src/AnExampleDetElemTool.cpp
+++ b/Simulation/DetSimGeom/src/AnExampleDetElemTool.cpp
@@ -92,7 +92,26 @@ AnExampleDetElemTool::ConstructSDandField() {
                << endmsg;
         // continue;
         // Sensitive detectors are deleted in ~G4SDManager
-        G4VSensitiveDetector* g4sd = dd4hep::PluginService::Create<G4VSensitiveDetector*>(typ, nam, lcdd);
+        G4VSensitiveDetector* g4sd = nullptr;
+
+        // try to use SD tool to find the SD
+        if (!g4sd) {
+            if (typ=="calorimeter") {
+                m_calo_sdtool = ToolHandle<ISensDetTool>("CalorimeterSensDetTool");
+                if (m_calo_sdtool) {
+                    info() << "Find the CalorimeterSensDetTool." << endmsg;
+                    g4sd = m_calo_sdtool->createSD(nam);
+                    info() << "create g4SD: " << g4sd << endmsg;
+                }
+            } else if (typ=="tracker") {
+
+            }
+        }
+        
+        if (!g4sd) {
+            g4sd = dd4hep::PluginService::Create<G4VSensitiveDetector*>(typ, nam, lcdd);
+        }
+
         if (g4sd == nullptr) {
             std::string tmp = typ;
             tmp[0] = ::toupper(tmp[0]);
diff --git a/Simulation/DetSimGeom/src/AnExampleDetElemTool.h b/Simulation/DetSimGeom/src/AnExampleDetElemTool.h
index 7c922dad0e2d7c5a44c8c2ea869024b48e913135..b0b22861b892c0817876e9c325853e843acf7dc4 100644
--- a/Simulation/DetSimGeom/src/AnExampleDetElemTool.h
+++ b/Simulation/DetSimGeom/src/AnExampleDetElemTool.h
@@ -3,11 +3,14 @@
 
 #include "GaudiKernel/AlgTool.h"
 #include "GaudiKernel/Property.h"
-#include "DetSimInterface/IDetElemTool.h"
+#include <GaudiKernel/ToolHandle.h>
+
 #include "G4SystemOfUnits.hh"
 #include "G4PhysicalConstants.hh"
 
 #include "DetInterface/IGeoSvc.h"
+#include "DetSimInterface/IDetElemTool.h"
+#include "DetSimInterface/ISensDetTool.h"
 
 
 class AnExampleDetElemTool: public extends<AlgTool, IDetElemTool> {
@@ -29,7 +32,7 @@ private:
     Gaudi::Property<std::string> m_dd4hep_xmls{this, "detxml"};
 
     SmartIF<IGeoSvc> m_geosvc;
-
+    ToolHandle<ISensDetTool> m_calo_sdtool;
 };
 
 #endif
diff --git a/Simulation/DetSimInterface/CMakeLists.txt b/Simulation/DetSimInterface/CMakeLists.txt
index 1eec6f6e84ca919543dcf62995c4ada9937649e4..8950d300d14e0df6f5319d26bd209a2a79a28b31 100644
--- a/Simulation/DetSimInterface/CMakeLists.txt
+++ b/Simulation/DetSimInterface/CMakeLists.txt
@@ -1,6 +1,8 @@
 
 gaudi_subdir(DetSimInterface v0r0)
 
+gaudi_depends_on_subdirs(GaudiKernel)
+
 # DetSimInterface (headers only)
 set(DetSimInterface_srcs
     src/IDetSimSvc.cpp
diff --git a/Simulation/DetSimInterface/DetSimInterface/ISensDetTool.h b/Simulation/DetSimInterface/DetSimInterface/ISensDetTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdba7547e422e2f290e0d306db7fa0a8ad89dac6
--- /dev/null
+++ b/Simulation/DetSimInterface/DetSimInterface/ISensDetTool.h
@@ -0,0 +1,28 @@
+#ifndef ISensDetTool_h
+#define ISensDetTool_h
+/*
+ * ISensDetTool is a tool to configure and create a Geant4's sensitive detector.
+ * After create the SD, the Geant4 will take ownership of the SD.
+ *
+ * This tool is used to replace the DDG4's Geant4SensitiveDetector.
+ * It will be invoked in ConstructSDandField().
+ *
+ * -- 12 June 2020, Tao Lin <lintao@ihep.ac.cn>
+ */
+
+#include "GaudiKernel/IAlgTool.h"
+
+class G4VSensitiveDetector;
+
+class ISensDetTool: virtual public IAlgTool {
+public:
+
+    DeclareInterfaceID(ISensDetTool, 0, 1);
+
+    virtual ~ISensDetTool() {};
+
+    virtual G4VSensitiveDetector* createSD(const std::string& name) = 0;
+
+};
+
+#endif
diff --git a/Simulation/DetSimSD/CMakeLists.txt b/Simulation/DetSimSD/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..10b1a15a3f0d9ed6cf91a635ea6d53eca49daba3
--- /dev/null
+++ b/Simulation/DetSimSD/CMakeLists.txt
@@ -0,0 +1,35 @@
+
+gaudi_subdir(DetSimSD v0r0)
+
+gaudi_depends_on_subdirs(
+    FWCore
+    Detector/DetInterface
+    Simulation/DetSimInterface
+)
+
+find_package(Geant4 REQUIRED ui_all vis_all)
+include(${Geant4_USE_FILE})
+find_package(DD4hep COMPONENTS DDG4 REQUIRED)
+
+set(DetSimSD_srcs
+    src/CalorimeterSensDetTool.cpp
+
+    src/DDG4SensitiveDetector.cpp
+    src/CaloSensitiveDetector.cpp
+)
+
+gaudi_add_module(DetSimSD ${DetSimSD_srcs}
+    INCLUDE_DIRS
+      # DetSimInterface
+      # FWCore
+      # DD4hep
+      # GaudiKernel
+      # Geant4 
+    LINK_LIBRARIES
+      # DetSimInterface
+      # FWCore
+      DD4hep
+      ${DD4hep_COMPONENT_LIBRARIES} 
+      GaudiKernel
+      # Geant4
+)
diff --git a/Simulation/DetSimSD/DetSimSD/CaloSensitiveDetector.h b/Simulation/DetSimSD/DetSimSD/CaloSensitiveDetector.h
new file mode 100644
index 0000000000000000000000000000000000000000..28b3ab3b11f7e48b6f300402e1e9e9edefd986bb
--- /dev/null
+++ b/Simulation/DetSimSD/DetSimSD/CaloSensitiveDetector.h
@@ -0,0 +1,36 @@
+#ifndef CaloSensitiveDetector_h
+#define CaloSensitiveDetector_h
+
+/*
+ * This is an implementation of Calo SD.
+ *
+ * -- 13 June 2020, Tao Lin <lintao@ihep.ac.cn>
+ */
+
+#include "DetSimSD/DDG4SensitiveDetector.h"
+
+class CaloSensitiveDetector: public DDG4SensitiveDetector {
+public:
+    typedef dd4hep::sim::Geant4CalorimeterHit CalorimeterHit;
+    typedef G4THitsCollection<CalorimeterHit> CaloHitCollection;
+
+public:
+    CaloSensitiveDetector(const std::string& name, dd4hep::Detector& description);
+
+public:
+    // Geant4 interface
+
+    virtual void Initialize(G4HCofThisEvent* HCE);
+    virtual G4bool ProcessHits(G4Step* step,G4TouchableHistory* history);
+    virtual void EndOfEvent(G4HCofThisEvent* HCE);
+
+protected:
+    CalorimeterHit* find(const HitCollection*, const dd4hep::sim::HitCompare<CalorimeterHit>&);
+    
+protected:
+
+    HitCollection* m_hc;
+};
+
+
+#endif
diff --git a/Simulation/DetSimSD/DetSimSD/DDG4SensitiveDetector.h b/Simulation/DetSimSD/DetSimSD/DDG4SensitiveDetector.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7806f7de5f97c5cf36a60c6b22e6d1491ccb24e
--- /dev/null
+++ b/Simulation/DetSimSD/DetSimSD/DDG4SensitiveDetector.h
@@ -0,0 +1,71 @@
+#ifndef DDG4SensitiveDetector_h
+#define DDG4SensitiveDetector_h
+
+/*
+ * In order to access ID from DDG4, some utilities are necessary to retrieve information
+ * from DDG4. This base class defines such interfaces and utilities.
+ * 
+ * Refer to the class DDG4/include/DDG4/Geant4SensitiveDetector.h for some APIs usage.
+ *
+ * We keep to reuse some types already defined in DDG4:
+ * - Geant4Hits
+ *
+ * -- 12 June 2020, Tao Lin <lintao@ihep.ac.cn>
+ */
+
+
+#include "DD4hep/Detector.h"
+#include "DDG4/Geant4Hits.h"
+
+#include "G4Step.hh"
+#include "G4HCofThisEvent.hh"
+#include "G4TouchableHistory.hh"
+#include "G4VSensitiveDetector.hh"
+#include "G4THitsCollection.hh"
+
+
+class DDG4SensitiveDetector: public G4VSensitiveDetector {
+public:
+    typedef dd4hep::sim::Geant4Hit                    Geant4Hit;
+    typedef G4THitsCollection<dd4hep::sim::Geant4Hit> HitCollection;
+    typedef dd4hep::sim::Geant4Hit::Contribution      HitContribution;
+
+public:
+    DDG4SensitiveDetector(const std::string& name, dd4hep::Detector& description);
+
+public:
+    // Geant4 interface
+
+    virtual void Initialize(G4HCofThisEvent* HCE);
+    virtual G4bool ProcessHits(G4Step* step,G4TouchableHistory* history);
+    virtual void EndOfEvent(G4HCofThisEvent* HCE);
+
+public:
+    // DDG4 utilities
+    /// Returns the volumeID of the sensitive volume corresponding to the step -
+    /// combining the VolIDS of the complete geometry path (Geant4TouchableHistory)
+    //  from the current sensitive volume to the world volume
+    virtual long long getVolumeID(G4Step* step);
+
+    /// Returns the volumeID of the sensitive volume corresponding to the step -
+    /// combining the VolIDS of the complete geometry path (Geant4TouchableHistory)
+    //  from the current sensitive volume to the world volume
+    virtual long long getCellID(G4Step* step);
+
+
+protected:
+    /// Reference to the detector description object
+    dd4hep::Detector& m_detDesc;
+
+    /// Reference to the detector element describing this sensitive element
+    dd4hep::DetElement m_detector;
+
+    /// Reference to the sensitive detector element
+    dd4hep::SensitiveDetector m_sensitive;
+
+    /// Reference to the readout structure
+    dd4hep::Readout m_readout;
+
+};
+
+#endif
diff --git a/Simulation/DetSimSD/src/CaloSensitiveDetector.cpp b/Simulation/DetSimSD/src/CaloSensitiveDetector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1547f9fe3506be659803ef0d8f5da2e3bcd79fdf
--- /dev/null
+++ b/Simulation/DetSimSD/src/CaloSensitiveDetector.cpp
@@ -0,0 +1,68 @@
+#include "DetSimSD/CaloSensitiveDetector.h"
+
+#include "G4SDManager.hh"
+
+#include <algorithm>
+
+CaloSensitiveDetector::CaloSensitiveDetector(const std::string& name, dd4hep::Detector& description)
+    : DDG4SensitiveDetector(name, description),
+      m_hc(nullptr) {
+    const std::string& coll_name = m_sensitive.hitsCollection();
+    collectionName.insert(coll_name);
+}
+
+void
+CaloSensitiveDetector::Initialize(G4HCofThisEvent* HCE) {
+
+    // the collection name is provided by DD4hep
+    const std::string& coll_name = collectionName[0];
+    // m_hc = new G4THitsCollection<CalorimeterHit>(GetName(), coll_name);
+    m_hc = new HitCollection(GetName(), coll_name);
+
+    int HCID = -1;
+    if(HCID<0) HCID = G4SDManager::GetSDMpointer()->GetCollectionID(m_hc);
+    HCE->AddHitsCollection( HCID, m_hc ); 
+
+}
+
+G4bool
+CaloSensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*) {
+
+    // std::cout << "CaloSensitiveDetector::ProcessHits" << std::endl;
+
+    dd4hep::sim::Geant4StepHandler h(step);
+    dd4hep::Position pos = 0.5 * (h.prePos() + h.postPos());
+    HitContribution contrib = dd4hep::sim::Geant4Hit::extractContribution(step);
+    CalorimeterHit* hit=find(m_hc,dd4hep::sim::HitPositionCompare<CalorimeterHit>(pos));
+
+    //    G4cout << "----------- Geant4GenericSD<Calorimeter>::buildHits : position : " << pos << G4endl;
+    if ( !hit ) {
+        hit = new CalorimeterHit(pos);
+        hit->cellID  = getCellID( step );
+        m_hc->insert(hit);
+    }
+    hit->truth.push_back(contrib);
+    hit->energyDeposit += contrib.deposit;
+
+
+    
+    return true;
+}
+
+void
+CaloSensitiveDetector::EndOfEvent(G4HCofThisEvent* HCE) {
+
+}
+
+CaloSensitiveDetector::CalorimeterHit*
+CaloSensitiveDetector::find(const CaloSensitiveDetector::HitCollection* c,
+                            const dd4hep::sim::HitCompare<CaloSensitiveDetector::CalorimeterHit>& cmp) {
+    typedef std::vector<CalorimeterHit*> _V;
+    const _V* v = (const _V*) c->GetVector();
+    for (_V::const_iterator i = v->begin(); i != v->end(); ++i) {
+        if (cmp(*i)) {
+            return *i;
+        }
+    }
+    return 0;
+}
diff --git a/Simulation/DetSimSD/src/CalorimeterSensDetTool.cpp b/Simulation/DetSimSD/src/CalorimeterSensDetTool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8c30b10e8663a8977f99aa08eefd0113f2c3918
--- /dev/null
+++ b/Simulation/DetSimSD/src/CalorimeterSensDetTool.cpp
@@ -0,0 +1,43 @@
+#include "CalorimeterSensDetTool.h"
+
+#include "G4VSensitiveDetector.hh"
+
+#include "DetSimSD/CaloSensitiveDetector.h"
+
+#include "DD4hep/Detector.h"
+
+DECLARE_COMPONENT(CalorimeterSensDetTool);
+
+StatusCode
+CalorimeterSensDetTool::initialize() {
+    StatusCode sc;
+
+
+    m_geosvc = service<IGeoSvc>("GeoSvc");
+    if (!m_geosvc) {
+        error() << "Failed to find GeoSvc." << endmsg;
+        return StatusCode::FAILURE;
+    }
+
+
+    return sc;
+}
+
+StatusCode
+CalorimeterSensDetTool::finalize() {
+    StatusCode sc;
+
+    return sc;
+}
+
+G4VSensitiveDetector*
+CalorimeterSensDetTool::createSD(const std::string& name) {
+
+    dd4hep::Detector* dd4hep_geo = m_geosvc->lcdd();
+
+    G4VSensitiveDetector* sd = new CaloSensitiveDetector(name, *dd4hep_geo);
+
+    return sd;
+}
+
+
diff --git a/Simulation/DetSimSD/src/CalorimeterSensDetTool.h b/Simulation/DetSimSD/src/CalorimeterSensDetTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..775d24510bba9da061e0a76ae2816cc762f7ada6
--- /dev/null
+++ b/Simulation/DetSimSD/src/CalorimeterSensDetTool.h
@@ -0,0 +1,34 @@
+#ifndef CalorimeterSensDetTool_h
+#define CalorimeterSensDetTool_h
+
+/*
+ * CalorimeterSensDetTool is used to create the Calorimeter SD.
+ *
+ * -- 12 June 2020, Tao Lin <lintao@ihep.ac.cn>
+ */
+
+#include "GaudiKernel/AlgTool.h"
+#include "DetSimInterface/ISensDetTool.h"
+#include "DetInterface/IGeoSvc.h"
+
+class CalorimeterSensDetTool: public extends<AlgTool, ISensDetTool> {
+
+public:
+
+    using extends::extends;
+
+    /// Overriding initialize and finalize
+    StatusCode initialize() override;
+    StatusCode finalize() override;
+
+    /// Override ISensDetTool
+    virtual G4VSensitiveDetector* createSD(const std::string& name) override;
+
+private:
+
+    // in order to initialize SD, we need to get the lcdd()
+    SmartIF<IGeoSvc> m_geosvc;
+
+};
+
+#endif
diff --git a/Simulation/DetSimSD/src/DDG4SensitiveDetector.cpp b/Simulation/DetSimSD/src/DDG4SensitiveDetector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25ce06c0a2da935a1d8d7e4bad09e360962f1985
--- /dev/null
+++ b/Simulation/DetSimSD/src/DDG4SensitiveDetector.cpp
@@ -0,0 +1,76 @@
+#include "DetSimSD/DDG4SensitiveDetector.h"
+
+#include "DDG4/Geant4SensitiveDetector.h"
+#include "DDG4/Geant4Converter.h"
+#include "DDG4/Geant4Hits.h"
+#include "DD4hep/Segmentations.h"
+
+#include "DD4hep/Printout.h"
+#include "DD4hep/Detector.h"
+
+// Geant4 include files
+#include "G4Step.hh"
+#include "G4PVPlacement.hh"
+
+// ROOT include files
+#include "TGeoNode.h"
+
+#include "DD4hep/DD4hepUnits.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// convert from CLHEP to DD4hep
+static const double MM_2_CM = (dd4hep::millimeter/CLHEP::millimeter);
+
+
+DDG4SensitiveDetector::DDG4SensitiveDetector(const std::string& name, dd4hep::Detector& description)
+    : G4VSensitiveDetector(name), m_detDesc(description),
+      m_detector(), m_sensitive(), m_readout() {
+    m_detector = description.detector(name);
+    m_sensitive = description.sensitiveDetector(name);
+    m_readout = m_sensitive.readout();
+
+}
+
+void
+DDG4SensitiveDetector::Initialize(G4HCofThisEvent* HCE) {
+
+}
+
+G4bool
+DDG4SensitiveDetector::ProcessHits(G4Step* step, G4TouchableHistory*) {
+    
+    return true;
+}
+
+void
+DDG4SensitiveDetector::EndOfEvent(G4HCofThisEvent* HCE) {
+
+}
+
+long long
+DDG4SensitiveDetector::getVolumeID(G4Step* aStep) {
+
+    dd4hep::sim::Geant4StepHandler step(aStep);
+    dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager();
+    dd4hep::VolumeID id = volMgr.volumeID(step.preTouchable());
+
+    return id;
+}
+
+long long
+DDG4SensitiveDetector::getCellID(G4Step* step) {
+    dd4hep::sim::Geant4StepHandler h(step);
+    dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager();
+    dd4hep::VolumeID volID  = volMgr.volumeID(h.preTouchable());
+
+    dd4hep::Segmentation        seg    = m_readout.segmentation();
+    if ( seg.isValid() )  {
+        G4ThreeVector global = 0.5 * ( h.prePosG4()+h.postPosG4());
+        G4ThreeVector local  = h.preTouchable()->GetHistory()->GetTopTransform().TransformPoint(global);
+        dd4hep::Position loc(local.x()*MM_2_CM, local.y()*MM_2_CM, local.z()*MM_2_CM);
+        dd4hep::Position glob(global.x()*MM_2_CM, global.y()*MM_2_CM, global.z()*MM_2_CM);
+        dd4hep::VolumeID cID = seg.cellID(loc,glob,volID);
+        return cID;
+    }
+    return volID;
+}