diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b02527456f9d5851e674ad2fafe3ce8ccaf3724c..2a8e44b726fd3929ab64e3a3a2cd96bd67033013 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -104,6 +104,7 @@ build:ubuntu:
     - source SetEnv.sh
     - echo $LD_LIBRARY_PATH
     - cd $CI_PROJECT_DIR
+    - source build/config.sh
     - ./macro/gitlab_test.sh
   allow_failure: true
   <<: *only-default
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2871cee11c0390b70c50ec97c491fcba9db97ab7..3011e32b1b8b04fd794743eec095475affb820e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,11 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
 
 # Set name of our project to “SPDROOT". Has to be done
 # after check of cmake version since this is a new feature                  
-project(SPDROOT)
+PROJECT(SPDROOT)
+
+IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  SET(CMAKE_INSTALL_PREFIX /opt/spdroot/ CACHE PATH "SpdRoot install prefix" FORCE)
+ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 
 #set(CMAKE_VERBOSE_MAKEFILE true)
 include(CMakeParseArguments)
@@ -59,7 +63,7 @@ Check_Compiler()
 set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib")
 set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin")
 set(INCLUDE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/include")
-Set(VMCWORKDIR ${CMAKE_SOURCE_DIR})
+Set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX})
 Option(USE_PATH_INFO "Information from PATH and LD_LIBRARY_PATH are used." OFF)
 If(USE_PATH_INFO)
   Set(PATH "$PATH")
@@ -92,23 +96,8 @@ CHECK_EXTERNAL_PACKAGE_INSTALL_DIR()
 # mandatory
 
 find_package2(PUBLIC ROOT  VERSION 6.10.00  REQUIRED)
-#find_package2(PUBLIC FairLogger VERSION 1.2.0 REQUIRED)
 find_package2(PUBLIC Pythia6)
 find_package2(PUBLIC Pythia8)
-#find_package2(PUBLIC Protobuf)
-#find_package2(PUBLIC msgpack)
-#find_package2(PUBLIC FlatBuffers)
-#find_package(ROOT 5.32.00 REQUIRED)
-#find_package(ROOT REQUIRED)
-#find_package(Pythia8)
-#find_package(Pythia6 REQUIRED)
-#find_package(GENERATORS REQUIRED)
-#find_package(GEANT3)
-#find_package(GEANT4 REQUIRED)
-#find_package(GEANT4DATA)
-#find_package(GEANT4VMC REQUIRED)
-#find_package(CLHEP)
-
 
 find_package2(PUBLIC Geant3)
 if(Geant3_FOUND)
@@ -130,18 +119,6 @@ Set(Geant4_INCLUDE_DIRS "$ENV{SIMPATH}/include/Geant4")
 Set(Geant4VMC_INCLUDE_DIRS "$ENV{SIMPATH}/include/geant4vmc")
 Set(Geant4VMC_LIBRARY_DIR "$ENV{SIMPATH}/lib")
 
-#if(Geant4VMC_FOUND)
-#   Set(Geant4VMC_LIBRARY_DIR "$ENV{SIMPATH}/lib")
-#Endif()
-#if(Geant4VMC_FOUND)
-#  Set(Geant4VMC_LIBRARY_DIR "${Geant4VMC_DIR}/${Geant4VMC_CMAKE_INSTALL_LIBDIR}")
-#  Set(Geant4VMC_SHARE_DIR "${Geant4VMC_DIR}/share")
-#  Find_Path(Geant4VMC_MACRO_DIR NAMES g4libs.C PATHS
-#    ${Geant4VMC_SHARE_DIR}/Geant4VMC-${Geant4VMC_VERSION}/examples/macro
-#    NO_DEFAULT_PATH
-#  )
-#Endif()
-
 Set(Boost_NO_SYSTEM_PATHS TRUE)
 Set(Boost_NO_BOOST_CMAKE TRUE)
 If(${ROOT_LIBRARY_DIR} MATCHES /lib/root)
@@ -174,6 +151,7 @@ Message(":: SYSTEM_INCLUDE_DIR  : ${SYSTEM_INCLUDE_DIRECTORIES}")
 Message(":: BASE_INCLUDE_DIR    : ${BASE_INCLUDE_DIRECTORIES}")
 Message(":: CMAKE_SOURCE_DIR    : ${CMAKE_SOURCE_DIR}")
 Message(":: CMAKE_CURRENT_BINARY_DIR    : ${CMAKE_CURRENT_BINARY_DIR}")
+Message(":: CMAKE_INSTALL_PREFIX    : ${CMAKE_INSTALL_PREFIX}")
 
 # Set the library version in the main CMakeLists.txt
 SET(FAIRROOT_MAJOR_VERSION 0)
@@ -189,9 +167,8 @@ SET(FAIRROOT_LIBRARY_PROPERTIES ${FAIRROOT_LIBRARY_PROPERTIES}
 #Generate_Version_Info()
 
 SET(_LIBDIR ${CMAKE_BINARY_DIR}/lib)
-SET(LD_LIBRARY_PATH  ${_LIBDIR} ${LD_LIBRARY_PATH})
-
-#install(DIRECTORY geometry DESTINATION spd_install )
+SET(LD_LIBRARY_PATH  ${_LIBDIR} ${SIMPATH}/lib ${LD_LIBRARY_PATH})
+SET(PATH ${CMAKE_SOURCE_DIR} ${CMAKE_INSTALL_PREFIX}/bin ${PATH}) 
 
 # Check if the compiler support specific C++11 features
 # Up to now this is only a check since the code does not use
@@ -229,6 +206,7 @@ add_subdirectory (proc)
 add_subdirectory (reco)
 add_subdirectory (spddisplay)
 
+
 ################################################################################
 if(PROJECT_PACKAGE_DEPENDENCIES)
   message(STATUS "  ")
@@ -346,6 +324,70 @@ if(BUILD_DOXYGEN)
 endif(BUILD_DOXYGEN)
 
 WRITE_CONFIG_FILE(config.sh)
+WRITE_CONFIG_FILE(config.sh_install)
+
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh "export VMCWORKDIR=${CMAKE_SOURCE_DIR}\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh "export SPDROOTPATH=${CMAKE_SOURCE_DIR}\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh "export GEOMPATH=${CMAKE_SOURCE_DIR}/geometry\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh "export MAGFPATH=${CMAKE_SOURCE_DIR}/input\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh "export ROOT_INCLUDE_PATH=${CMAKE_SOURCE_DIR}/install:${ROOT_INCLUDE_PATH}\n")
+
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh_install "export SPDROOTPATH=${VMCWORKDIR}\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh_install "export GEOMPATH=${VMCWORKDIR}/share/geometry\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh_install "export MAGFPATH=${VMCWORKDIR}/share/input\n")
+file(APPEND ${CMAKE_BINARY_DIR}/config.sh_install "export ROOT_INCLUDE_PATH=${VMCWORKDIR}/install:${ROOT_INCLUDE_PATH}\n")
+
+Install(FILES ${CMAKE_BINARY_DIR}/config.sh_install
+        DESTINATION bin
+        RENAME SetEnv.sh
+       )
+
+Install(FILES spdroot.py
+        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
+        DESTINATION bin
+	)
+
+Install(FILES macro/rootlogon.C macro/rootlogoff.C
+          DESTINATION macro/
+          )
+
+Install(DIRECTORY gconfig
+          DESTINATION .
+          )
+
+Install(FILES macro/SimuQsl.C
+          DESTINATION share/examples/
+          )
+
+Install(DIRECTORY macro/fullchain macro/primgen macro/tracking macro/vertexrec
+          DESTINATION share/examples
+          PATTERN ".svn" EXCLUDE)
+
+
+Install(DIRECTORY geometry
+          DESTINATION share/
+          PATTERN ".svn" EXCLUDE)
+
+Install(DIRECTORY input
+          DESTINATION share/
+          PATTERN ".svn" EXCLUDE)
+
+Install(FILES ${CMAKE_BINARY_DIR}/check_system.sh
+          DESTINATION bin
+                )
+
+Install(FILES ${CMAKE_BINARY_DIR}/check_system.csh
+          DESTINATION bin
+                )
+
+Install(FILES ${CMAKE_BINARY_DIR}/check_system.sh
+          DESTINATION .
+                )
+
+Install(FILES ${CMAKE_BINARY_DIR}/check_system.csh
+          DESTINATION .
+                )
+
  
 configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake 
                ${CMAKE_BINARY_DIR}/CTestCustom.cmake
diff --git a/SetEnv.sh b/SetEnv.sh
index 24964d4a7337ec96a43b07ab1b67e53105ec5132..a2ffe9e4381df8b102d3fcff6dd89a88e0422239 100644
--- a/SetEnv.sh
+++ b/SetEnv.sh
@@ -6,10 +6,15 @@ export FAIRROOTPATH=/opt/fairroot/install
 export PATH="${SIMPATH}/bin:$PATH"
 export LD_LIBRARY_PATH="${SIMPATH}/lib:$LD_LIBRARY_PATH"
 
-if [ -f build/config.sh ]
-then
-source build/config.sh -a
-fi
+#if [ -f build/config.sh ]
+#then
+#source build/config.sh -a
+#fi
 
-export GEOMPATH="${VMCWORKDIR}/geometry"
+#export GEOMPATH="${VMCWORKDIR}/geometry"
+#export MAGFPATH="${VMCWORKDIR}/input"
 
+#export PATH="${VMCWORKDIR}:$PATH"
+
+#echo actual path to geometry and materials: $GEOMPATH
+#echo actual path to magnetic field maps: $MAGFPATH
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index d53ee8cae32281bd1350f3b611a18233fbdee0d0..1df852a4ed4cd82a1d739a1fb0346c3f4611facd 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -57,7 +57,25 @@ geometry/SpdGeoVVolume.cxx
 region/SpdRegion.cxx
 
 checks/SpdGeoScanner.cxx
+)
 
+set(HEADERS
+checks/SpdGeoScanner.h
+geometry/SpdGeoBuilder.h
+geometry/SpdGeoMapper.h
+geometry/SpdGeoTable.h
+geometry/SpdGeoVolPars.h
+geometry/SpdGeoVVolume.h
+geometry/SpdNodesIdTable.h
+region/SpdRegion.h
+SpdCommonGeoMapper.h
+SpdDetector.h
+SpdGlobals.h
+SpdModulesMap.h
+SpdPassiveModule.h
+SpdRunAna.h
+SpdRunSim.h
+SpdStack.h
 )
 
 set(LINKDEF  SpdCommonLinkDef.h)
diff --git a/common/SpdCommonGeoMapper.cxx b/common/SpdCommonGeoMapper.cxx
index b1dacaa8659a72b3c2dae2c58d737384dde9fd3d..69ab3678e8f0960aafa9083e032475d5d44015ec 100644
--- a/common/SpdCommonGeoMapper.cxx
+++ b/common/SpdCommonGeoMapper.cxx
@@ -8,6 +8,7 @@
 
 #include "FairGeoLoader.h"
 #include "FairGeoInterface.h" 
+#include "FairGeoMedia.h"
 
 #include "SpdCommonGeoMapper.h"
 #include "SpdPassiveModule.h"
@@ -35,7 +36,7 @@ TGeoVolume*  SpdCommonGeoMapper::theMasterVolume  = 0;
 /*==================================================================*/
 
 Int_t    SpdCommonGeoMapper::theNGeoSectors             = 8;     // > 2 and < 13
-Double_t SpdCommonGeoMapper::theSectorClearance         = 5.;    // cm
+Double_t SpdCommonGeoMapper::theSectorClearance         = 2.5;    // cm
 
 /*============================= PIPE ===============================*/
  
@@ -401,16 +402,64 @@ TString SpdCommonGeoMapper::GetMasterVolumeName()
 }
 
 //_____________________________________________________________________________
-void SpdCommonGeoMapper::OpenGeometry()
-{
+void SpdCommonGeoMapper::OpenGeometry(TString media)
+{  
+   if (media.IsWhitespace()) media = "media.geo";
+   
+   Bool_t found = false;
+   
+   TString medfile;
+   while (true) 
+   {
+      // if absolute path
+      if (media.BeginsWith("/") ) {
+         if (!gSystem->AccessPathName(media.Data())) { 
+             medfile = media;
+             found = true; 
+             break; 
+         }
+      }
+      
+      // if GEOMPATH is set
+      TString mpath = getenv("GEOMPATH");
+      mpath.ReplaceAll("//","/");
+      if (!mpath.IsNull() ) {
+          if (!mpath.EndsWith("/")) mpath += "/";
+          medfile = mpath + media;
+          if (!gSystem->AccessPathName(medfile.Data())) { found = true; break; }
+      }
+      
+      // if file was not found look it in the standard path
+      medfile = TString(getenv("VMCWORKDIR"))+"/geometry/";
+      medfile += media;
+      if (!gSystem->AccessPathName(medfile.Data())) { found = true; break; }
+      
+      // if file was not found set default 
+      medfile = TString(getenv("VMCWORKDIR"))+"/geometry/media.geo";
+      cout << "-I- <SpdCommonGeoMapper::OpenGeometry> File " << media << " not found."
+           << " Set default media file. " << endl;
+      break;
+   }
+   
+   cout << "-I- <SpdCommonGeoMapper::OpenGeometry> Media file: " << medfile << endl;
+   
    FairGeoLoader* loader = FairGeoLoader::Instance();
    if (!loader) loader = new FairGeoLoader("TGeo","Geo Loader");
    
    FairGeoInterface* GeoInterface = loader->getGeoInterface();
-   GeoInterface->setMediaFile(TString(gSystem->Getenv("VMCWORKDIR"))+"/geometry/media.geo"); 
+   GeoInterface->setMediaFile(medfile); 
    GeoInterface->readMedia(); 
 }
 
+//_____________________________________________________________________________
+TString SpdCommonGeoMapper::GetActualMediaFileName() const 
+{
+   FairGeoLoader* loader = FairGeoLoader::Instance();
+   if (!loader) return "";
+   FairGeoInterface* GeoInterface = loader->getGeoInterface();
+   return GeoInterface->getMedia()->getInputFile();
+}
+
 //_____________________________________________________________________________
 void SpdCommonGeoMapper::DefineTorGeometrySet(Int_t type)
 {
@@ -789,6 +838,8 @@ void SpdCommonGeoMapper::DefineHybGeometrySet(Int_t type)
    
    if (type == 2) 
    {
+       theHybMagnetDefGeoType    = 2;    
+   
        theTsTBDefGeoType         = 2;    // TsTB
        
        theTsTBLen2               = 236.; // (510) cm 
@@ -813,7 +864,7 @@ void SpdCommonGeoMapper::DefineHybGeometrySet(Int_t type)
        return;
    }
    
-   cout << "-W- <SpdCommonGeoMapper::DefineSolGeometrySet> "
+   cout << "-W- <SpdCommonGeoMapper::DefineHybGeometrySet> "
         << "Unknown geometry set: " << type << endl;
   
    theTsTBDefGeoType         = 0;
@@ -825,6 +876,134 @@ void SpdCommonGeoMapper::DefineHybGeometrySet(Int_t type)
      
 }
 
+//_____________________________________________________________________________
+void SpdCommonGeoMapper::DefineQslGeometrySet()
+{
+   if (!thePassives.empty()) {
+       map <SpdPassiveModule*, module_info*>::iterator it = thePassives.begin();
+       for ( ; it !=  thePassives.end(); it++) {
+            if (it->first->IsGeometryLocked()) {
+                cout << "-W- <SpdCommonGeoMapper::DefineQslGeometrySet>"
+                     << "Geometry is locked (passives)" << endl;
+                return;
+            }
+       }
+   }
+   
+   if (!theDetectors.empty()) {
+       SpdGeoMapper* mapper;
+       map <SpdDetector*, module_info*>::iterator it = theDetectors.begin();    
+       for ( ; it !=  theDetectors.end(); it++) {
+            mapper = it->first->GetMapper();
+            if (mapper && mapper->IsGeometryLocked()) {
+                cout << "-W- <SpdCommonGeoMapper::DefineQslGeometrySet> "
+                     << "Geometry is locked (detectors)" << endl;
+                return;
+            }
+       }
+   }
+   
+   cout << "-I- <SpdCommonGeoMapper::DefineQslGeometrySet> " << endl;
+   
+   theSolMagnetDefGeoType    = 0;
+   theTsSBDefGeoType         = 0;
+   theTsSECDefGeoType        = 0;
+   theEcalSBDefGeoType       = 0; 
+   theEcalSECDefGeoType      = 0;
+   theRsSBDefGeoType         = 0;
+   theRsSECDefGeoType        = 0;     
+  
+    /*=================================================================*/
+   
+   thePipeDefGeoType         = 4;
+   
+   theTorBasketDefGeoType    = 0;
+   theTorMagnetDefGeoType    = 0;
+   
+   /*========================= MAGNET =================================*/
+
+   theHybMagnetDefGeoType     = 3;    
+      
+   theHybMagnetDistToAxis     = 40.;  // cm
+   theHybMagnetDistToAxis1    = 125.; // cm
+   theHybMagnetDistToAxis2    = 185.; // cm
+   
+   theHybMagnetRingSize       = 129.; // cm
+   
+   theHybMagnetCoilThickness  = 8.;   // cm
+   theHybMagnetCoilWidth      = 10.;  // cm
+
+   /*===================== INNER TRACKING SYSTEM ======================*/
+
+   theItsDefGeoType           = 3;      // : 1
+   
+   theItsNLayers              = 5;  
+   
+   theItsMinRadius            = 5.0;    // cm
+   theItsMaxRadius            = 40.;    // (60,TOR) cm
+   theItsMaxLength            = 200.;   // cm
+   
+   /*=========== TSTB (TOROIDAL TRACKING SYSTEM BARREL) ===============*/
+
+   theTsTBDefGeoType         = 2;    // TsTB
+   
+   theTsTBLen2               = 236.; // (510,TOR) cm 
+   theTsTBSize2              = 85.4; // (160,HYB) cm 
+   theTsTBWidth2             = 45.;  // (95,HYB) cm 
+   
+   theTsTBMakeOffset2        = kTRUE;     
+   
+   /*========== TSTEC (TOROIDAL TRACKING SYSTEM ENDCAPS) =============*/
+  
+   theTsTECDefGeoType        = 3;    // TsTEC
+
+   theTsTECMinDist3          = 118.; // (0) cm
+   theTsTECLength3           = 53.6; // (200,HYB) cm
+   
+   theTsTECSize              = 92.4; // (170,HYB) cm -> 85.4/Cos(22.5*DegToRad()) = 92.436293905
+   theTsTECWidth             = 82.4; // (160,HYB) cm
+   
+   /*===== ECALTB (TOROIDAL ELECTROMAGNETIC CALORIMETER BARREL) =======*/
+
+   theEcalTBDefGeoType       = 2;    
+   
+   theEcalTBBaseMaterial    = "air";
+   
+   theEcalTBLen2             = 403.2;  // (510,TOR) cm 
+   theEcalTBSize2            = 175.4;  // (265,TOR) cm
+   theEcalTBWidth2           = 40.0;   // (60,TOR)  cm
+
+   /*===== ECALTEC (TOROIDAL ELECTROMAGNETIC CALORIMETER ENDCAPS) =====*/
+
+   theEcalTECDefGeoType      = 1; 
+   
+   theEcalTECBaseMaterial    = "air";
+
+   theEcalTECMinDist1        = 201.6; // (320,HYB) cm
+
+   theEcalTECSize            = 175.4; // (265,HYB) cm
+   theEcalTECWidth           = 165.4; // (255,HYB) cm
+   theEcalTECThickness       = 45.;   // (60,HYB)  cm
+   
+   /*============ RSTB (TOROIDAL RANGE SYSTEM BARREL) =================*/
+
+   theRsTBDefGeoType         = 2;    
+   
+   theRsTBLen2               = 493.2;  // (510,TOR) cm 
+   theRsTBSize2              = 314.4;  // (340,TOR) cm
+   theRsTBWidth2             = 139.0;  // (60,TOR)  cm
+
+   /*============ RSTEC (TOROIDAL RANGE SYSTEM ENDCAPS) ===============*/
+
+   theRsTECDefGeoType        = 1; 
+
+   theRsTECMinDist1          = 246.6; // (400,HYB) cm
+
+   theRsTECSize              = 314.4;  // (419,HYB) cm
+   theRsTECWidth             = 304.4;  // (409,HYB) cm
+   theRsTECThickness         = 139.0;  // (110.5,HYB) cm
+}
+
 //_____________________________________________________________________________
 void SpdCommonGeoMapper::SetTorHybridGeoPars()
 {
@@ -1051,16 +1230,10 @@ SpdDetector* SpdCommonGeoMapper::SearchForActive(Int_t id) const
 }
 
 //_____________________________________________________________________________
-void SpdCommonGeoMapper::UnsetMaterials(Bool_t precise, TString option)
+void SpdCommonGeoMapper::UnsetMaterials(Bool_t precise, TString option, 
+                                        Bool_t active, Bool_t passive)
 {
-   if (!thePassives.empty()) {
-       map <SpdPassiveModule*, module_info*>::iterator it = thePassives.begin();
-       for ( ; it !=  thePassives.end(); it++) {
-            it->first->UnsetMaterials(precise);
-       }
-   }
-   
-   if (!theDetectors.empty()) {
+   if (active && !theDetectors.empty()) {
        SpdGeoMapper* mapper;
        map <SpdDetector*, module_info*>::iterator it = theDetectors.begin();    
        for ( ; it !=  theDetectors.end(); it++) {
@@ -1068,6 +1241,17 @@ void SpdCommonGeoMapper::UnsetMaterials(Bool_t precise, TString option)
             mapper->UnsetMaterials(precise,option);
        }
    }
+   
+   if (passive && !thePassives.empty()) {
+       map <SpdPassiveModule*, module_info*>::iterator it = thePassives.begin();
+       for ( ; it !=  thePassives.end(); it++) {
+            if (option == "air") it->first->UnsetMaterials("air");
+            else {
+                if (precise) it->first->UnsetMaterials("vacuum2");
+                else it->first->UnsetMaterials("vacuum");
+            }
+       }
+   }
 }
 
 //_____________________________________________________________________________
diff --git a/common/SpdCommonGeoMapper.h b/common/SpdCommonGeoMapper.h
index 35779a5f4c7d9a306432ca9d588f4cb57ea8309e..6daf7410a349eb656ca75035b3501643b12821a9 100644
--- a/common/SpdCommonGeoMapper.h
+++ b/common/SpdCommonGeoMapper.h
@@ -57,7 +57,7 @@ public:
 
     static Int_t    GetItsDefGeoType()          { return theItsDefGeoType;     }
     static TString  GetItsBaseMaterial()        { return theItsBaseMaterial;   }
-    static TString  GetItsLadderMaterial()      { return theItsLadderMaterial;  }
+    static TString  GetItsLadderMaterial()      { return theItsLadderMaterial; }
     static TString  GetItsSensorMaterial()      { return theItsSensorMaterial; } 
     
     static Int_t    GetItsNLayers()             { return theItsNLayers;        }           
@@ -327,19 +327,21 @@ public:
 
     /*==================================================================*/
     
-    void   OpenGeometry();
+    void   OpenGeometry(TString media = "media.geo");
     
     void   DefineTorGeometrySet(Int_t type);
     void   DefineSolGeometrySet(Int_t type);
     void   DefineHybGeometrySet(Int_t type = 2);
+    void   DefineQslGeometrySet();
    
     void   ConstructGeometry();
     
     void   AddPassive(SpdPassiveModule* module);
     void   AddDetector(SpdDetector* detector);
     
-    void   UnsetMaterials(Bool_t precise, TString option = "base");
-    void   SaveEmptyHits(Bool_t savehits = kTRUE);
+    void   UnsetMaterials(Bool_t precise, TString option = "base", 
+                          Bool_t active = true, Bool_t passive = true);
+    void   SaveEmptyHits(Bool_t savehits = true);
    
     void   FillModulesMap();
    
@@ -359,6 +361,8 @@ public:
     SpdDetector**      GetListOfDetectors(Int_t& nd);
     SpdPassiveModule** GetListOfPassives(Int_t& np);
     
+    TString GetActualMediaFileName() const;  
+    
     struct module_info {
       
         module_info(): id_(kSpdUndefined){}
diff --git a/common/SpdDetector.cxx b/common/SpdDetector.cxx
index 3e05caaba26beb0690a27affe886106794fbfa50..519dfcc6bc5e3cc644d5292d018a6c83c18919e0 100644
--- a/common/SpdDetector.cxx
+++ b/common/SpdDetector.cxx
@@ -295,7 +295,7 @@ Bool_t SpdDetector::LoadParsFrom(SpdParSet* params)
    params->GetParameter("Detector/SaveDetIdOption",fSaveDetIdOption);
    
    CreateNodeIdTable(params);
-     
+
    return kTRUE;
 }
 
diff --git a/common/SpdDetector.h b/common/SpdDetector.h
index c39a449bbe78b1e6c465351833822940805ae298..96d22afa7a0a6b050ef1a0a8881fb832372e7701 100644
--- a/common/SpdDetector.h
+++ b/common/SpdDetector.h
@@ -146,8 +146,8 @@ protected:
     
     /* Nodes Table */
     
-    SpdNodesIdTable* fNodesIdTable;       //!table [full node path,id]
-    Bool_t           fNodesIdTableIsOwn;  //!mark if NodesIdTable is own
+    SpdNodesIdTable* fNodesIdTable;       //! table [full node path,id]
+    Bool_t           fNodesIdTableIsOwn;  //! mark if NodesIdTable is own
     
     ClassDef(SpdDetector,1)
 };
diff --git a/common/SpdGlobals.h b/common/SpdGlobals.h
index ed3a112a0f665e7ba244d01116118bac59a43801..2674aeaf31d0e58e46d62b4bcf9e7ea468f21ef7 100644
--- a/common/SpdGlobals.h
+++ b/common/SpdGlobals.h
@@ -6,8 +6,8 @@
 #include "FairVersion.h"
 #include "RVersion.h"
 
-#define SPD_RELEASE                  3.230
-#define SPD_RELEASE_DATE             28081900
+#define SPD_RELEASE                  4.00
+#define SPD_RELEASE_DATE             080920
 
 #define OLD_FAIRROOT_PRIMGEN_VERSION 0
 
diff --git a/common/SpdPassiveModule.cxx b/common/SpdPassiveModule.cxx
index 395e1ed859d84a214d43c0e044184114072345f0..84be51d5b3ab6a40d74575a0c78b59baf7724e45 100644
--- a/common/SpdPassiveModule.cxx
+++ b/common/SpdPassiveModule.cxx
@@ -9,7 +9,8 @@
 
 #include "SpdPassiveModule.h"
 #include "SpdCommonGeoMapper.h"
-#include "SpdPassiveGeoPar.h"
+#include "SpdParSetContFact.h"
+#include "SpdPassiveGeoParSet.h"
 
 #include "FairGeoBuilder.h"
 #include "FairGeoMedia.h"
@@ -24,7 +25,7 @@ ClassImp(SpdPassiveModule)
 
 //_____________________________________________________________________________
 SpdPassiveModule::SpdPassiveModule():FairModule(),fGeoType(-1),fMasterVolume(0),
-fModuleId(-1)
+fModuleId(-1),fUnsetMedia("")
 {
    fName  = ClassName();
    fTitle = "SPD Passive Module";
@@ -34,7 +35,7 @@ fModuleId(-1)
 
 //_____________________________________________________________________________
 SpdPassiveModule::SpdPassiveModule(const char* Name, const char* Prefix, Int_t ModId):
-FairModule(Name,Prefix),fGeoType(-1),fMasterVolume(0),fModuleId(ModId)
+FairModule(Name,Prefix),fGeoType(-1),fMasterVolume(0),fModuleId(ModId),fUnsetMedia("")
 {  
    SpdCommonGeoMapper::Instance()->AddPassive(this);
 }
@@ -49,9 +50,10 @@ SpdPassiveModule::~SpdPassiveModule()
 void SpdPassiveModule::Print(Option_t*) const
 {
    cout << "<SpdPassiveModule::Print>" << endl;
-   cout << " Geometry type: " << fGeoType << endl;
-   cout << " Name:          " << fName << endl;
-   cout << " Id:            " << fModuleId << endl;
+   cout << " Geometry type:   " << fGeoType << endl;
+   cout << " Name:            " << fName << endl;
+   cout << " Id:              " << fModuleId << endl;
+   cout << " Unset material:  " << fUnsetMedia << endl;
 }
 
 //_____________________________________________________________________________
@@ -70,7 +72,6 @@ TString SpdPassiveModule::FullName(TString name, Bool_t add_uscore)
 //_____________________________________________________________________________
 TGeoMedium* SpdPassiveModule::FindMedium(TString& medname, TString default_med) 
 { 
-  
    TGeoMedium* med = 0;
    
    if (medname.IsWhitespace()) return 0;
@@ -106,3 +107,30 @@ TGeoMedium* SpdPassiveModule::FindMedium(TString& medname, TString default_med)
    return FindMedium(medname,"");
 }
 
+//_____________________________________________________________________________
+Bool_t SpdPassiveModule::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!params) return kFALSE;
+
+   params->SetParameter(Form("%s/UnsetMedia",this->ClassName()),fUnsetMedia);
+   
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdPassiveModule::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!params) return kFALSE; 
+   return kTRUE;
+}
+
+//_____________________________________________________________________________________
+SpdPassiveGeoParSet* SpdPassiveModule::GetParameters()
+{
+   FairRun* run = FairRun::Instance();
+   if (!run) return 0;
+   FairRuntimeDb* rtdb = run->GetRuntimeDb(); 
+   if (!rtdb) return 0;
+   SpdPassiveGeoParSet* pars = (SpdPassiveGeoParSet*)(rtdb->getContainer("PassiveGeoParSet"));
+   return pars;
+}
diff --git a/common/SpdPassiveModule.h b/common/SpdPassiveModule.h
index a94e67d361ba41e51bbc513ad5361fcf904f9e31..18a40a25bca2c0827c69cf24bf166b7d37de28fd 100644
--- a/common/SpdPassiveModule.h
+++ b/common/SpdPassiveModule.h
@@ -14,7 +14,7 @@
 //                                                                            //
 ////////////////////////////////////////////////////////////////////////////////
 
-class SpdPassiveGeoPar;
+class SpdPassiveGeoParSet;
 
 class SpdPassiveModule: public FairModule {
 
@@ -32,8 +32,9 @@ public:
     
     virtual void SetGeometryType(Int_t/* type*/) {}
     
-    virtual void UnsetMaterials(Bool_t /*precise = kTRUE*/) {}
-    
+    virtual void UnsetMaterials(TString /*media*/) {}
+    virtual void ResetMaterials(/*set dafault materials*/) {}
+     
     /* ----- getters ------ */
     
     virtual Bool_t IsGeometryLocked() const { return kFALSE;    }
@@ -46,18 +47,24 @@ public:
           
     const Char_t*  GetPrefix() const { return fTitle.Data(); }      
     
-    virtual void Print(Option_t*) const;
+    virtual void   Print(Option_t*) const;
+    
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
     
 protected:
   
-    virtual TString FullName(TString name, Bool_t add_uscore = kFALSE);
+    SpdPassiveGeoParSet* GetParameters();
     
+    virtual TString     FullName(TString name, Bool_t add_uscore = kFALSE);
     virtual TGeoMedium* FindMedium(TString& medname, TString default_med);
     
     Int_t       fGeoType;
     Int_t       fModuleId;
-    TGeoVolume* fMasterVolume;
+    TGeoVolume* fMasterVolume; //!
     
+    TString     fUnsetMedia; //! 
+     
     ClassDef(SpdPassiveModule,1)
 };
 
diff --git a/common/SpdStack.cxx b/common/SpdStack.cxx
index 6706b4b80e82505d1e245bd742a7d9a10695596f..9843179a1489fb448f79a0cec84ce435a8b963de 100644
--- a/common/SpdStack.cxx
+++ b/common/SpdStack.cxx
@@ -72,6 +72,8 @@ SpdStack::~SpdStack()
 //_____________________________________________________________________________________
 void SpdStack::Reset()
 {
+  //cout << "<SpdStack::Reset>" << endl;
+  
   fIndex = 0;
   fCurrentTrack = -1;
   fNPrimaries = 0;
@@ -80,9 +82,13 @@ void SpdStack::Reset()
   
   while (!fStack.empty() ) { fStack.pop(); }
   
-  fParticles->Clear();
-  fTracks->Clear();
+  Int_t nt = fTracks->GetEntriesFast();
+  
+  fParticles->Delete();
+  fTracks->Delete();
   fPointsMap.clear();
+  
+  //cout << "<SpdStack::Reset> " << nt << ", " << fTracks->GetEntriesFast() << endl;
 }
 
 //_____________________________________________________________________________________
@@ -215,7 +221,8 @@ Int_t SpdStack::GetCurrentParentTrackNumber() const
 TParticle* SpdStack::GetParticle(Int_t trackID) const
 {
   if (trackID < 0 || trackID >= fNParticles) {
-      Fatal("SpdStack::GetParticle", "Index out of range");
+      //cout << trackID << "/" << fNParticles << endl;
+      Fatal("GetParticle", "Index out of range");
   }
   return (TParticle*)fParticles->At(trackID);
 }
@@ -287,7 +294,7 @@ void SpdStack::FillTrackArray()
        fStoreIter = fStoreMap.find(iPart);
        
        if (fStoreIter == fStoreMap.end()) {
-           Fatal("SpdStack::FillTrackArray","Particle not found in storage map.");
+           Fatal("FillTrackArray","Particle not found in storage map.");
        }
        
        Bool_t store = (*fStoreIter).second;
@@ -344,7 +351,7 @@ void SpdStack::UpdateTrackIndex(TRefArray* detList)
        fIndexIter = fIndexMap.find(iMotherOld);
        
        if (fIndexIter == fIndexMap.end()) {
-           Fatal("SpdStack::UpdateTrackIndex", "Particle index not found in map");
+           Fatal("UpdateTrackIndex", "Particle index not found in map");
        }
        
        track->SetMotherId((*fIndexIter).second);
@@ -377,7 +384,7 @@ void SpdStack::UpdateTrackIndex(TRefArray* detList)
              fIndexIter = fIndexMap.find(iTrack);
              
              if (fIndexIter == fIndexMap.end()) {
-                 Fatal("SpdStack::UpdateTrackIndex", "Particle index not found in map");
+                 Fatal("UpdateTrackIndex", "Particle index not found in map");
              }
              
              point->SetTrackID((*fIndexIter).second);
diff --git a/common/geometry/SpdGeoMapper.cxx b/common/geometry/SpdGeoMapper.cxx
index 7ffb994677ee9789c60191412b4b9a02abcda263..347ff6edd7a467e3cf1138eac2f0816b7bf6e5e5 100644
--- a/common/geometry/SpdGeoMapper.cxx
+++ b/common/geometry/SpdGeoMapper.cxx
@@ -279,6 +279,12 @@ Bool_t SpdGeoMapper::CheckGeoType(Int_t geotype, TString parname)
 void SpdGeoMapper::FillParametersIn(SpdParSet* params)
 {
    if (!params || !fParams) return; 
+   
+   TString pname = Form("%sUnsetMedia",fGeoPrefix.Data());
+   SpdParameter* par = GetParameter(pname);
+   if (par) *par = fUnsetMedia;
+   else fParams->Add(new SpdParameter(pname,fUnsetMedia));
+          
    params->SetMapperParameters(fParams);
 }
    
@@ -289,6 +295,16 @@ void SpdGeoMapper::LoadParametersFrom(SpdParSet* params)
    params->FillMapperParameters(fParams);
 }
 
+//_____________________________________________________________________________   
+void SpdGeoMapper::ResetMediaFromParams()
+{
+   if (!fParams) return; 
+   TString pname = Form("%sUnsetMedia",fGeoPrefix.Data());
+   SpdParameter* par = GetParameter(pname);
+   if (!par) return;
+   fUnsetMedia = par->Value();
+}
+
 //_____________________________________________________________________________ 
 void SpdGeoMapper::Print(Option_t*) const
 {
diff --git a/common/geometry/SpdGeoMapper.h b/common/geometry/SpdGeoMapper.h
index 1bc9f85de9647c4463fb595c361c4fa2c7569eab..634776b0d8ceca5f23ff3332dc6a6b167b172610 100644
--- a/common/geometry/SpdGeoMapper.h
+++ b/common/geometry/SpdGeoMapper.h
@@ -48,7 +48,8 @@ public:
     virtual void  UnlockGeometry() { fLockGeometry = kFALSE; }
     
     virtual void  UnsetMaterials(Bool_t /*precise = kTRUE*/, TString /*option = "base"*/) {}
-   
+    virtual void  UnsetMaterials(TString option = "base") { UnsetMaterials(0,option); } 
+       
     /* ------ getters ------ */
   
     Int_t         GetGeoType()       const { return fGeoType;    } 
@@ -86,6 +87,8 @@ public:
     virtual void  FillParametersIn(SpdParSet* params);
     virtual void  LoadParametersFrom(SpdParSet* params);
     
+    virtual void  ResetMediaFromParams();
+    
     virtual void  Print(Option_t*) const;
     virtual void  PrintVolPars(Int_t nvolumes = 0) const;
     
diff --git a/common/geometry/SpdGeoTable.cxx b/common/geometry/SpdGeoTable.cxx
index 2a40b6a6e944babff8b6d20394898f9382e5f944..d9f25502bc80ee39e498e0f1d022cfd1ba57b97d 100644
--- a/common/geometry/SpdGeoTable.cxx
+++ b/common/geometry/SpdGeoTable.cxx
@@ -244,6 +244,7 @@ Int_t SpdGeoTable::AddTableRec(Int_t geolevel, TString volname, TString motherna
        rec->fFirstNodeTableNum = rec1->GetLastNodeTableNum()+1;
        level.push_back(fTable->GetLast());
    }
+  return 0;
 }
 
 //_____________________________________________________________________________   
@@ -352,13 +353,13 @@ TString SpdGeoTable::GetNodeGeoPath(Long_t detTID)
         
         n = Long_t((detTID - sumn)/fTableDims[i]);
         
-	if (n < 1) {
-	    fPathLevel = 0;
+        if (n < 1) {
+            fPathLevel = 0;
             return "MASTER";
-	}
-	
+        }
+        
         sumn += n*fTableDims[i];
-	glob_num = n;
+        glob_num = n;
 
         it = std::lower_bound(fTableGlobalNums[i].begin(),fTableGlobalNums[i].end(),glob_num);
         n = it - fTableGlobalNums[i].begin();
@@ -388,14 +389,17 @@ TString SpdGeoTable::GetNodeGeoPath(Long_t detTID)
         fPath[i+1].second = loc_num;
 
         fPathLevel++;
-	xrec = rec;
-	
+        xrec = rec;
+        
         //rec->Prn(rec->GetLocalNodeNum(glob_num),glob_num,loc_num);
    }
  
+   fPathLevel++;
+ 
    TString geopath = GetCurrentPathString();
   
-   //cout << "<GetNodeGeoPath> TID: " << detTID << " PATH: " << geopath << endl;
+   //cout << "-I- <SpdGeoTable::GetNodeGeoPath> TID: " << detTID << " PATH: " << geopath << " Level: " << fPathLevel << endl;
+   //cout << "-I- <SpdGeoTable::GetNodeGeoPath> TID: " << GetNodeTableNum(geopath) << endl;
  
    return geopath;
 }
diff --git a/common/geometry/SpdGeoVVolume.cxx b/common/geometry/SpdGeoVVolume.cxx
index 040781b25baad8a545d8fb17a332d303b1093a00..7640627fa3da07ddd572d75633a5d43114596f98 100644
--- a/common/geometry/SpdGeoVVolume.cxx
+++ b/common/geometry/SpdGeoVVolume.cxx
@@ -181,12 +181,12 @@ Bool_t SpdGeoVVolumeBox2D::GetCellPos(Int_t id, Double_t& x, Double_t& y, Double
 {   
    switch (fAxes) 
    {
-     case 0 : { GetCellPos(id,x,y); z = 0; return kTRUE; } 
-     case 1 : { GetCellPos(id,z,x); y = 0; return kTRUE; } 
-     case 2 : { GetCellPos(id,y,z); x = 0; return kTRUE; } 
-     case 3 : { GetCellPos(id,y,x); z = 0; return kTRUE; } 
-     case 4 : { GetCellPos(id,z,x); y = 0; return kTRUE; } 
-     case 5 : { GetCellPos(id,z,y); x = 0; return kTRUE; } 
+     case 0 : { z = 0; return GetCellPos(id,x,y); } 
+     case 1 : { y = 0; return GetCellPos(id,z,x); } 
+     case 2 : { x = 0; return GetCellPos(id,y,z); } 
+     case 3 : { z = 0; return GetCellPos(id,y,x); } 
+     case 4 : { y = 0; return GetCellPos(id,z,x); } 
+     case 5 : { x = 0; return GetCellPos(id,z,y); } 
   }
   
   GetCellPos(id,x,y);
@@ -195,6 +195,44 @@ Bool_t SpdGeoVVolumeBox2D::GetCellPos(Int_t id, Double_t& x, Double_t& y, Double
   return kFALSE;
 }
 
+//_____________________________________________________________________________
+Bool_t SpdGeoVVolumeBox2D::GetCellPos(Int_t id, Double_t* pos) const
+{
+  switch (fAxes) 
+  {
+     case 0 : { pos[2] = 0; return GetCellPos(id,pos[0],pos[1]); } 
+     case 1 : { pos[1] = 0; return GetCellPos(id,pos[2],pos[0]); } 
+     case 2 : { pos[0] = 0; return GetCellPos(id,pos[1],pos[2]); } 
+     case 3 : { pos[2] = 0; return GetCellPos(id,pos[1],pos[0]); } 
+     case 4 : { pos[1] = 0; return GetCellPos(id,pos[2],pos[0]); } 
+     case 5 : { pos[0] = 0; return GetCellPos(id,pos[2],pos[1]); } 
+  }
+  
+  GetCellPos(id,pos[0],pos[1]);
+  pos[2] = 0; 
+  
+  return kFALSE;   
+}
+
+//_____________________________________________________________________________
+Bool_t SpdGeoVVolumeBox2D::GetPos(Double_t id1, Double_t id2, Double_t* pos) const
+{
+  switch (fAxes) 
+  {
+     case 0 : { pos[2] = 0; return GetPos(id1,id2,pos[0],pos[1]); } 
+     case 1 : { pos[1] = 0; return GetPos(id1,id2,pos[2],pos[0]); } 
+     case 2 : { pos[0] = 0; return GetPos(id1,id2,pos[1],pos[2]); } 
+     case 3 : { pos[2] = 0; return GetPos(id1,id2,pos[1],pos[0]); } 
+     case 4 : { pos[1] = 0; return GetPos(id1,id2,pos[2],pos[0]); } 
+     case 5 : { pos[0] = 0; return GetPos(id1,id2,pos[2],pos[1]); } 
+  }
+  
+  GetPos(id1,id2,pos[0],pos[1]);
+  pos[2] = 0; 
+  
+  return kFALSE;   
+}
+
 //_____________________________________________________________________________
 void SpdGeoVVolumeBox2D::PrintVolume() const
 {
@@ -242,6 +280,22 @@ Bool_t SpdGeoVVolumeBox2D::GetCellPos(Int_t id, Double_t& x1, Double_t& x2) cons
    return kTRUE;
 }
 
+//_____________________________________________________________________________
+Bool_t SpdGeoVVolumeBox2D::GetPos(Double_t id1, Double_t id2, Double_t& x1, Double_t& x2) const
+{
+   x1 = 0; x2 = 0;
+  
+   if (id1 < 0 || !(id1 < Double_t(fN1))) return kFALSE;
+   if (id2 < 0 || !(id2 < Double_t(fN2))) return kFALSE;
+   
+   x1 = -0.5*fL1 + (id1 + 0.5)*fD1;
+   x2 = -0.5*fL2 + (id2 + 0.5)*fD2;
+   
+   //cout << "<SpdGeoVVolumeBox2D::GetPos> " << x1 << " " << x2 << endl;
+   
+   return kTRUE;
+}
+
 //_____________________________________________________________________________
 const Char_t* SpdGeoVVolumeBox2D::GetAxes() const
 {
diff --git a/common/geometry/SpdGeoVVolume.h b/common/geometry/SpdGeoVVolume.h
index 5ca5a4690d06a520b4ccaca0b9d2babc6f127cb6..12e7136fe12d3ac97f0e157673ce9ee6e5ffbbbf 100644
--- a/common/geometry/SpdGeoVVolume.h
+++ b/common/geometry/SpdGeoVVolume.h
@@ -71,10 +71,14 @@ public:
       
     virtual Int_t  GetCellId(Double_t x, Double_t y, Double_t z) const;
     virtual Bool_t GetCellPos(Int_t id, Double_t& x, Double_t& y, Double_t& z) const;
+    virtual Bool_t GetCellPos(Int_t id, Double_t* pos /*3-dim array*/) const;
+    virtual Bool_t GetPos(Double_t id1, Double_t id2, Double_t* pos /*3-dim array*/) const;
             
     Int_t   GetCellId(Double_t x1, Double_t x2) const;
     Bool_t  GetCellPos(Int_t id, Double_t& x1, Double_t& x2) const;
-    
+  
+    Bool_t  GetPos(Double_t id1, Double_t id2, Double_t& x1, Double_t& x2) const;
+  
     inline Int_t CellId(Int_t id1, Int_t id2) const { return fN2 * id1 + id2;} 
     inline void  CellId(Int_t id,  Int_t& id1, Int_t& id2) const { id1 = id/fN2; id2 = id%fN2; }
     
diff --git a/doc/INSTALL_SPECIAL b/doc/INSTALL_SPECIAL
deleted file mode 100644
index 9d5bb3bdc614110f8bf44b2ba887a21da3a0c704..0000000000000000000000000000000000000000
--- a/doc/INSTALL_SPECIAL
+++ /dev/null
@@ -1,121 +0,0 @@
-
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-+  --------------------------------------------------------------- +
-+ | !!!!!!!!!!!!!!!!!! INSTALL (LXPUB) --- !!!!!!!!!!!!!!!!!!!!! | +
-+  --------------------------------------------------------------- +
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-******************
-***  SPDROOT   ***
-******************
-
-cd spdroot/
-
-. SetEnv_lxpub.sh
-
-cat SetEnv_lxpub.sh
------------------------------------------- >>>>>
-
-#!/bin/bash
-
-export CXX=/opt/rh/devtoolset-1.1/root/usr/bin/g++
-export SIMPATH=/scrc/u/fair_install/fairsoft
-export FAIRROOTPATH=/scrc/u/fair_install/fairsoft/FairRoot
-
-source build/config.sh
-
------------------------------------------- <<<<<
-
-(delete build folder: rm -rf build/)
-
-mkdir build
-cd build
-cmake -DUSE_DIFFERENT_COMPILER=TRUE ..
-make
-
-cd ..
-
-. build/config.sh
-
-
-cd macro
-root -l
-root[0] .x run_sim.C 
-
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-+  --------------------------------------------------------------- +
-+ | !!!!!!!!!!!!!!!!!! INSTALL (AFS) --- !!!!!!!!!!!!!!!!!!!!!!! | +
-+  --------------------------------------------------------------- +
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-[I.]
-
-******************
-***  FAIRROOT  ***
-******************
-  
-copy FairRoot ti AFS-dirctory
-
-(decompress *tar.gz : tar xvfz FairRoot.tar.gz)
-
-export CXX=/usr/bin/g++
-export SIMPATH=/afs/.jinr.ru/fairsoft/may16p1_r5
-
-#export CC=/opt/rh/devtoolset-4/root/usr/bin/gcc
-#export CXX=/opt/rh/devtoolset-4/root/usr/bin/g++
-
-#export SIMPATH=/afs/.jinr.ru/fairsoft/may16p1_r6
-
-#export SIMPATH=/afs/.jinr.ru/compass/common/FSinstall
-
-
-cd FairRoot
-
-1. Comment line in CMakeLists.txt: 
-
-   add_subdirectory (example) -> #add_subdirectory (example)
-
-2. mkdir build
-   cd build
-   cmake -DCMAKE_INSTALL_PREFIX="/afs/jinr.ru/user/a/avt/FairRoot/install/" ..
-   make
-   make install
-   
-[II.]
-
-******************
-***  SPDROOT   ***
-******************
-  
-cd spdroot/
-
-. SetEnv_afs.sh
-
-cat SetEnv_afs.sh
------------------------------------------- >>>>>
-
-#!/bin/bash
-
-export CXX=/usr/bin/g++
-export SIMPATH=/afs/jinr.ru/fairsoft/ 
-export FAIRROOTPATH=/afs/jinr.ru/user/a/avt/FairRoot/install
-
-source build/config.sh
-
------------------------------------------- <<<<<
-
-(delete build folder: rm -rf build/)
- 
-mkdir build
-cd build
-cmake ..
-make
-
-cd ..
-
-. build/config.sh
-
-cd macro
-root -l
-root[0] .x run_sim.C 
-
diff --git a/doc/ReleaseNotes.txt b/doc/ReleaseNotes.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9f1837d3a513afc05346580447b69bc5ea9cc778
--- /dev/null
+++ b/doc/ReleaseNotes.txt
@@ -0,0 +1,10 @@
+4.0.0 08.09.2020
+* Current В«CDR-likeВ» SPD geometry 
+* Full set of detectors except TOF, ZDC, BBC 
+* New quasi-solenoid magnetic field
+* Very flexible and easy to change
+* ECAL barrel and endcaps — geometry and simulation
+* RS barrel and endcaps — geometry and simulation
+* Secondary vertex reconstruction
+* Event data model refined, but not final yet
+* New building and installation prcedure (make install)
diff --git a/doc/SPD_en.pdf b/doc/SPD_en.pdf
deleted file mode 100644
index e6373fb34eb1e9c2935410ee5a98ad9f852969ca..0000000000000000000000000000000000000000
Binary files a/doc/SPD_en.pdf and /dev/null differ
diff --git a/doc/SPD_ru.pdf b/doc/SPD_ru.pdf
deleted file mode 100644
index 48e5e98788678854c5715fcb2af54aaa0ff51ba3..0000000000000000000000000000000000000000
Binary files a/doc/SPD_ru.pdf and /dev/null differ
diff --git a/doc/SetEnv_afs.sh b/doc/SetEnv_afs.sh
deleted file mode 100644
index 1a0d8f1ebcef4442d97ff355e3375b4152105fdc..0000000000000000000000000000000000000000
--- a/doc/SetEnv_afs.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-export CXX=/usr/bin/g++
-#export SIMPATH=/afs/.jinr.ru/fairsoft/may16p1_r6
-export SIMPATH=/afs/.jinr.ru/fairsoft/may16p1_r5
-export FAIRROOTPATH=/afs/jinr.ru/user/a/avt/FairRoot/install
-
-source build/config.sh
\ No newline at end of file
diff --git a/doc/SetEnv_lxpub.sh b/doc/SetEnv_lxpub.sh
deleted file mode 100644
index f27dd4640a3f7bae1244b14c94dd126d8e628a2b..0000000000000000000000000000000000000000
--- a/doc/SetEnv_lxpub.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-export CXX=/opt/rh/devtoolset-1.1/root/usr/bin/g++
-export SIMPATH=/scrc/u/fair_install/fairsoft 
-export FAIRROOTPATH=/scrc/u/fair_install/fairsoft/FairRoot
-
-source build/config.sh
\ No newline at end of file
diff --git a/doc/pics/B_qsl.png b/doc/pics/B_qsl.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e8b0eeb3f1dd15c796d81a2ccbacece1b00df15
Binary files /dev/null and b/doc/pics/B_qsl.png differ
diff --git a/doc/pics/B_qsl_old.png b/doc/pics/B_qsl_old.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab2af1f6a1c1e8092da5c643b9c2989a83ed9b6c
Binary files /dev/null and b/doc/pics/B_qsl_old.png differ
diff --git a/doc/pics/Its_top.png b/doc/pics/Its_top.png
deleted file mode 100644
index 704602151a7e5cf5c01a14d7c38d4e461bbd4558..0000000000000000000000000000000000000000
Binary files a/doc/pics/Its_top.png and /dev/null differ
diff --git a/doc/pics/RsBarrel.png b/doc/pics/RsBarrel.png
new file mode 100644
index 0000000000000000000000000000000000000000..05cf4bd58cab6a847c0ab3544aefa488a2cc92d0
Binary files /dev/null and b/doc/pics/RsBarrel.png differ
diff --git a/ecals/CMakeLists.txt b/ecals/CMakeLists.txt
index 1be1dc42bfa07259521685088d3a35bffc93485a..119987f195329facdbdec0c66e55ab9b6e9d0651 100644
--- a/ecals/CMakeLists.txt
+++ b/ecals/CMakeLists.txt
@@ -50,6 +50,23 @@ ecps/SpdEcalSECHitProducer.cxx
 
 )
 
+set(HEADERS
+barrel/SpdEcalSBGeoPar.h
+barrel/SpdEcalSB.h
+barrel/SpdEcalSBHit.h
+barrel/SpdEcalSBHitProducer.h
+barrel/SpdEcalSBParSet.h
+barrel/SpdEcalSBPoint.h
+ecps/SpdEcalSECGeoPar.h
+ecps/SpdEcalSEC.h
+ecps/SpdEcalSECHit.h
+ecps/SpdEcalSECHitProducer.h
+ecps/SpdEcalSECParSet.h
+ecps/SpdEcalSECPoint.h
+SpdEcalSContFact.h
+SpdEcalSPointAn.h
+)
+
 Set(LINKDEF SpdEcalsLinkDef.h)
 Set(LIBRARY_NAME SpdEcals)
 Set(DEPENDENCIES Base SpdData SpdCommon SpdField)
diff --git a/ecalt/CMakeLists.txt b/ecalt/CMakeLists.txt
index a2799993e0df0ec09a6970997df8c4084ddfaeb3..7482c11eab6bc3748ce638eb97dc5b41760b5919 100644
--- a/ecalt/CMakeLists.txt
+++ b/ecalt/CMakeLists.txt
@@ -37,19 +37,43 @@ SpdEcalTContFact.cxx
 SpdEcalTPointAn.cxx
 
 barrel/SpdEcalTB.cxx
+barrel/SpdEcalTB2.cxx
 barrel/SpdEcalTBParSet.cxx
 barrel/SpdEcalTBPoint.cxx
+barrel/SpdEcalTB2Point.cxx
 barrel/SpdEcalTBHit.cxx
 barrel/SpdEcalTBHitProducer.cxx
 
 ecps/SpdEcalTEC.cxx
-ecps/SpdEcalTECParSet.cxx
+ecps/SpdEcalTEC2.cxx
 ecps/SpdEcalTECPoint.cxx
+ecps/SpdEcalTEC2Point.cxx
+ecps/SpdEcalTECParSet.cxx
 ecps/SpdEcalTECHit.cxx
 ecps/SpdEcalTECHitProducer.cxx
 
 )
 
+set(HEADERS
+barrel/SpdEcalTB2.h
+barrel/SpdEcalTB2Point.h
+barrel/SpdEcalTB.h
+barrel/SpdEcalTBHit.h
+barrel/SpdEcalTBHitProducer.h
+barrel/SpdEcalTBParSet.h
+barrel/SpdEcalTBPoint.h
+ecps/SpdEcalTEC2.h
+ecps/SpdEcalTEC2Point.h
+#ecps/SpdEcalTECGeoPar.h
+ecps/SpdEcalTEC.h
+ecps/SpdEcalTECHit.h
+ecps/SpdEcalTECHitProducer.h
+ecps/SpdEcalTECParSet.h
+ecps/SpdEcalTECPoint.h
+SpdEcalTContFact.h
+SpdEcalTPointAn.h
+)
+
 Set(LINKDEF SpdEcaltLinkDef.h)
 Set(LIBRARY_NAME SpdEcalt)
 Set(DEPENDENCIES Base SpdData SpdCommon SpdGeometry SpdField)
diff --git a/ecalt/SpdEcaltLinkDef.h b/ecalt/SpdEcaltLinkDef.h
index 9080fd887760116635a9b8d6221dc58dbd21dde3..2a1f6073d8b8c909e0f9685ac4a515d314a57e2f 100644
--- a/ecalt/SpdEcaltLinkDef.h
+++ b/ecalt/SpdEcaltLinkDef.h
@@ -10,13 +10,17 @@
 
 #pragma link C++ class SpdEcalTBParSet+;
 #pragma link C++ class SpdEcalTB+;
+#pragma link C++ class SpdEcalTB2+;
 #pragma link C++ class SpdEcalTBPoint+;
+#pragma link C++ class SpdEcalTB2Point+;
 #pragma link C++ class SpdEcalTBHit+;
 #pragma link C++ class SpdEcalTBHitProducer+;
 
 #pragma link C++ class SpdEcalTECParSet+;
 #pragma link C++ class SpdEcalTEC+;
+#pragma link C++ class SpdEcalTEC2+;
 #pragma link C++ class SpdEcalTECPoint+;
+#pragma link C++ class SpdEcalTEC2Point+;
 #pragma link C++ class SpdEcalTECHit+;
 #pragma link C++ class SpdEcalTECHitProducer+;
 
diff --git a/ecalt/barrel/SpdEcalTB2.cxx b/ecalt/barrel/SpdEcalTB2.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a94ac56e776f338174c4252fae22de9866dd78cb
--- /dev/null
+++ b/ecalt/barrel/SpdEcalTB2.cxx
@@ -0,0 +1,1326 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#include "SpdEcalTB2.h"
+
+#include "FairVolume.h"
+#include "FairGeoVolume.h"
+#include "FairGeoNode.h"
+#include "FairRootManager.h"
+#include "FairGeoLoader.h"
+#include "FairGeoInterface.h"
+#include "FairGeoLoader.h"
+#include "FairGeoBuilder.h"
+#include "FairGeoMedia.h"
+#include "FairRun.h"
+#include "FairRunSim.h"
+#include "FairRuntimeDb.h"
+
+#include "TRefArray.h"    
+#include "TClonesArray.h"
+#include "TParticle.h"
+#include "TVirtualMC.h"
+#include "TGeoManager.h"
+#include "TGeoBBox.h"
+#include "TGeoPgon.h"
+#include "TGeoCompositeShape.h"
+#include "TGeoTube.h"
+#include "TGeoArb8.h"
+#include "TGeoMaterial.h"
+#include "TGeoMedium.h"
+#include "TMatrixD.h"
+
+#include "SpdEcalTB2.h"
+#include "SpdEcalTB2Point.h"
+#include "SpdEcalTB2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+#include "SpdDetectorList.h"
+#include "SpdStack.h"
+#include "SpdParSet.h"
+#include "SpdGeoFactory.h"
+
+#include <map>
+#include <iostream>
+#include <vector>
+#include <tuple>
+
+using namespace std;
+
+using std::cout;
+using std::endl;
+
+ClassImp(SpdEcalTB2)
+
+//_____________________________________________________________________________________
+SpdEcalTB2::SpdEcalTB2(): 
+
+  SpdDetector("Ecal barrel (tor)", kSpdEcalTB, kTRUE),
+  fTrackID(-1),
+  fDetID(-1),fBasketID(-1),fModuleZID(-1), fModulePhiID(-1), fCellID(-1), fLayerID(-1), fMatID(""),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1.),
+  fPointCollection(0),
+  fEnableWritingPointsScint(kTRUE),
+  fEnableWritingPointsAll(kFALSE),
+  fBasket(0),
+  fModule(0)
+{
+    SetParametersType("EcalTBParSet");
+   
+    fNDataOut = 1;
+    fOutDataPointObject = "SpdEcalTB2Point"; 
+    fUniqueModules.clear();
+    
+}
+
+//_____________________________________________________________________________________
+SpdEcalTB2::SpdEcalTB2(const char* name, Bool_t active):
+
+  SpdDetector(name, kSpdEcalTB, active),
+  fTrackID(-1),
+  fDetID(-1),fBasketID(-1),fModuleZID(-1), fModulePhiID(-1), fCellID(-1), fLayerID(-1), fMatID(""),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1.),
+  fPointCollection(0),
+  fEnableWritingPointsScint(kTRUE),
+  fEnableWritingPointsAll(kFALSE),
+  fBasket(0),
+  fModule(0)
+{
+   SetParametersType("EcalTBParSet");
+   
+   fNDataOut = 1;
+   fOutDataPointObject = "SpdEcalTB2Point";
+   fUniqueModules.clear(); 
+}
+
+//_____________________________________________________________________________________
+SpdEcalTB2::~SpdEcalTB2()
+{
+  if (fPointCollection) {
+      fPointCollection->Delete();
+      delete fPointCollection;
+      fPointCollection = 0;
+  }
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::Initialize()
+{
+  cout << "\n*******************************************************************************" << endl;
+  cout << "************************* SpdEcalTB2::Initialize ******************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+  
+  // data collections
+  fPointCollection = new TClonesArray(fOutDataPointObject);
+  
+  // Initialize cell and fill parameters
+  SpdDetector::Initialize(); 
+ 
+  // SpdParSet* pars = GetParameters();
+  // if (pars) pars->printParams();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::Reset()
+{
+  fPointCollection->Clear();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::Register()
+{
+  if (!fGeoMapper) return;
+  
+  if (fEnableWritingPointsScint) {
+      FairRootManager::Instance()->Register(fOutDataPointObject,"SpdEcalTB2", 
+                                            fPointCollection, kTRUE);
+  }
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdEcalTB2::ProcessHits(FairVolume* vol)
+{
+  //cout << "<SpdEcalTB2::ProcessHits> " << endl;
+  
+  TString nodepath = gMC->CurrentVolPath();
+  
+  //Set parameters at entrance of volume. Reset ELoss.
+  if (gMC->IsTrackEntering()) {
+      //cout << "track entering" << endl;
+      fELoss  = 0.;
+      fTime   = gMC->TrackTime() * 1.e9;  // ns -> s
+      fLength = gMC->TrackLength();
+      gMC->TrackPosition(fPos);
+      gMC->TrackMomentum(fMom);
+  }
+
+  // Sum energy loss for all steps in the active volume
+  fELoss += gMC->Edep();
+
+  // Create SpdEcalTB2Point at exit of active volume
+  if ( gMC->IsTrackExiting()    ||
+       gMC->IsTrackStop()       ||
+       gMC->IsTrackDisappeared()   ) 
+  {
+    
+    if (!fSaveEmptyHits && fELoss == 0.) { return kFALSE; }
+    
+    fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
+    
+    fNodePath = gMC->CurrentVolPath();
+    SpdGeopathParser parser;
+    parser.ParsePath(fNodePath);
+    
+    fDetID = kSpdEcalTB;
+    fBasketID = parser.Num(2, true);
+    
+    if (parser.VNum(3,true) == 0) { //only one unique module: fixed cell size
+        int rawModuleID = parser.Num(3, true);
+        fModuleZID = int(round(double(rawModuleID)/100));
+        fModulePhiID = rawModuleID - fModuleZID*100;
+    }
+    else { //several unique modules
+        fModuleZID = parser.Num(3, true) / 100;
+        if (parser.Num(3,true) % 100 == 1) {
+            fModulePhiID = -parser.VNum(3, true);
+        }
+        else {
+            fModulePhiID = parser.VNum(3, true);
+        }
+    }
+    
+    fCellID  = parser.Num(4, true);
+    fLayerID = parser.Num(5, true);
+    fMatID   = parser.Name(5, true);
+    
+    //cout << " <<< BARREL >>> " << fMatID << " " << gMC->CurrentVolPath() << endl;
+    
+    assert(fMatID == "EcalBLeadCell" || fMatID == "EcalBScintCell");
+    
+    if (fEnableWritingPointsAll) {
+        AddHit();
+    }
+    else if (fEnableWritingPointsScint && fMatID == "EcalBScintCell") {
+        AddHit();
+    }
+        
+    SpdStack* stack = (SpdStack*)gMC->GetStack();
+    stack->AddPoint(kSpdEcalTB);
+  } 
+   
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::AddHit() 
+{
+  static Bool_t addhit = (fOutDataPointObject == "SpdEcalTB2Point") ? kTRUE : kFALSE;
+  
+  if (!addhit) return;
+  
+  TClonesArray& clref = *fPointCollection;
+  Int_t size = clref.GetEntriesFast();
+  
+  //cout << "SpdEcalTB2::AddHit: Adding hit: " << fTrackID << 
+  //                                 fPos.X() << " " << fPos.Y() << " " << fPos.Z() << " " << 
+  //                                 fMom.Px() << " " << fMom.Py() << " " << fMom.Pz() << " " << 
+  //                                fTime << " " << fLength << " " << fELoss << " path = " << fNodePath <<"" << endl;
+  
+  new(clref[size]) SpdEcalTB2Point(fTrackID,fDetID,fBasketID,fModuleZID, fModulePhiID, fCellID, fLayerID, fMatID,
+                                   TVector3(fPos.X(),fPos.Y(),fPos.Z()),
+                                   TVector3(fMom.Px(),fMom.Py(),fMom.Pz()),
+                                   fTime, fLength, fELoss, fNodePath);                                 
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::EndOfEvent()
+{
+  Reset();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::FinishRun() 
+{
+   //SpdDetector::FinishRun();
+   FillNodesTableIn(GetParameters());
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::ConstructGeometry()
+{   
+  fMasterVolume = SpdCommonGeoMapper::Instance()->GetMasterVolume();
+      
+  if (!fMasterVolume) {  
+      cout << "-E- <SpdIts::ConstructGeometry> No MASTER volume " << endl;
+      return;
+  }
+  
+  if (!GetMapper()) return;
+   
+  if (!fGeoMapper->InitGeometry()) return;
+
+  //fGeoMapper->Print("");
+  
+  Int_t geo_type = fGeoMapper->GetGeoType();
+  
+  ConstructGeometry_1();
+  
+  fGeoMapper->LockGeometry(); 
+  
+  cout << "\n*******************************************************************************" << endl;
+  cout << "********************** SpdEcalTB2::ConstructGeometry **************************" << endl;
+  cout << "********************** GEOMETRY TYPE: " << geo_type 
+       << " ***************************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+}
+
+//________________________________________________________________________________
+void SpdEcalTB2::ConstructGeometry_1()
+{ 
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) return; 
+  
+    Bool_t forceCellSize = mapper->IsForceCellSize();
+    
+    BuildBasket();
+    
+    if (forceCellSize) {
+        fModule = BuildModule();
+        fUniqueModules.push_back(fModule);
+        FillBasketFixedCells(fBasket,fModule);
+    }
+    else {
+        FillBasketTightly(fBasket);
+    }
+    
+    BuildBarrel();
+}
+
+//________________________________________________________________________________
+void SpdEcalTB2::FillBasketTightly(TGeoVolume* basketVolume) 
+{
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) return; 
+    
+    Int_t     nSectors = mapper->GetNSectors();
+    Double_t  basketZSize = ((TGeoArb8*)basketVolume->GetShape())->GetDz()*2;
+    Double_t* basketVertices = ((TGeoArb8*)basketVolume->GetShape())->GetVertices();
+    
+    assert(basketVertices[0] > basketVertices[2]);
+    assert(basketVertices[0] == -basketVertices[2]);
+    
+    Double_t basketPhiInnerSize = basketVertices[0] - basketVertices[2];
+    Double_t doubleAngleBasket = 360./nSectors;
+    Double_t layerInnerSizeTheta = mapper->GetLayerInnerSizeTheta();
+    Double_t layerInnerSizePhi = mapper->GetLayerInnerSizePhi();
+    Double_t cellClearance = mapper->GetCellClearance();
+    Double_t moduleClearance = mapper->GetModuleClearance();
+    
+    Int_t    nCellsTheta = int(basketZSize/(2*layerInnerSizeTheta + moduleClearance));
+    Double_t moduleInnerSizeTheta = (basketZSize - nCellsTheta*moduleClearance)/nCellsTheta;
+    Int_t    nCellsPhi = 2*int((basketPhiInnerSize/2)/(2*layerInnerSizePhi + moduleClearance));        
+    
+    cout << "-I- <SpdEcalTB2::FillBasketTightly> : the Z size of ECAL barrel modules is set to " 
+         << (moduleInnerSizeTheta - cellClearance)/2 << " cm" << endl;
+    
+    vector<TGeoCombiTrans*> vectorTrans;
+    
+    for (int iphi = 0; iphi < nCellsPhi/2; ++iphi) { //stack to x+
+        Double_t angleModuleCenter = iphi*(doubleAngleBasket/2)/(nCellsPhi/2);
+        Double_t angleModulePeriph = (iphi+1)*(doubleAngleBasket/2)/(nCellsPhi/2);
+        pair<TGeoCombiTrans*, TGeoVolume*> res = StackModuleInSector(basketVolume, angleModuleCenter, angleModulePeriph, moduleInnerSizeTheta);
+        vectorTrans.push_back(res.first);
+        fUniqueModules.push_back(res.second);
+    }
+    
+    for (int iv = 0; iv < fUniqueModules.size(); ++iv) {
+        fUniqueModules[iv]->SetName(("Module"+to_string(iv+1)).c_str());
+        BuildModule(fUniqueModules[iv]);
+    }
+    
+    fModule = fUniqueModules[0];
+    
+    for (int iv = 0; iv < vectorTrans.size(); ++iv) {
+        Double_t currZ = -basketZSize + moduleClearance/2 + moduleInnerSizeTheta/2;
+        for (int iz = 0; iz < nCellsTheta; ++iz) {
+            TGeoCombiTrans* currTrans = new TGeoCombiTrans(*(vectorTrans[iv]));
+            currTrans->SetDz(currZ);
+            TGeoCombiTrans* currTransMirror = (TGeoCombiTrans*)currTrans->MakeClone();
+            currTransMirror->ReflectX(true);
+            basketVolume->AddNode(fUniqueModules[iv], (iz+1)*100, currTrans);
+            basketVolume->AddNode(fUniqueModules[iv], (iz+1)*100+1, currTransMirror);
+            currZ += moduleClearance + moduleInnerSizeTheta;
+        }
+    }    
+}
+
+//________________________________________________________________________________
+pair<TGeoCombiTrans*, TGeoVolume*> SpdEcalTB2::StackModuleInSector(TGeoVolume* basketVolume, 
+    Double_t angleModuleCenter, Double_t angleModulePeriph, Double_t moduleInnerSizeTheta) 
+{        
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) Fatal("SpdEcalTB2::StackModuleInSector", "no mapper"); 
+    
+    Int_t nLayers = mapper->GetNLayers();
+    Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+    Double_t layer2SizeZ = mapper->GetLayer2SizeZ();
+    Double_t totalZSize = (layer1SizeZ + layer2SizeZ)*nLayers; 
+    TString baseMedium = mapper->GetBaseMedium();
+    TGeoMedium* Air = FindMedium(baseMedium, "");
+    Double_t cellClearance = mapper->GetCellClearance();
+    Double_t moduleClearance = mapper->GetModuleClearance();
+    Bool_t trimModuleLength = mapper->IsTrimModuleLength();
+    
+    Double_t basketZSize = ((TGeoArb8*)basketVolume->GetShape())->GetDz()*2;
+    Double_t* basketVertices = ((TGeoArb8*)basketVolume->GetShape())->GetVertices();
+    assert(basketVertices[0] > basketVertices[2]);
+    assert(basketVertices[0] == -basketVertices[2]);
+    Double_t basketPhiInnerSize = basketVertices[0] - basketVertices[2];
+    assert(basketVertices[5] > basketVertices[3]);
+    Double_t basketHeight = basketVertices[5] - basketVertices[3];
+    assert(basketVertices[6] > basketVertices[4]);
+    Double_t basketPhiOuterSize = basketVertices[6] - basketVertices[4];
+    Double_t yCoordBasketBottom = basketVertices[1];
+    
+    Double_t yRayStart = yCoordBasketBottom - ((basketPhiInnerSize/2)/((basketPhiOuterSize - basketPhiInnerSize)/2))*basketHeight;
+    
+    Int_t stackingXdirection;
+    if (angleModulePeriph > 0) stackingXdirection = 1;
+    else stackingXdirection = -1;
+        
+    TVector3 vectorAtZeroAngle = TVector3(0, 1, 0);
+    TVector3 vectorUnitModuleCenter = vectorAtZeroAngle; vectorUnitModuleCenter.RotateZ(-TMath::DegToRad()*angleModuleCenter);
+    TVector3 vectorUnitModuleMiddle = vectorAtZeroAngle; vectorUnitModuleMiddle.RotateZ(-TMath::DegToRad()*(angleModuleCenter + angleModulePeriph)/2);
+    TVector3 vectorUnitModulePeriph = vectorAtZeroAngle; vectorUnitModulePeriph.RotateZ(-TMath::DegToRad()*angleModulePeriph);
+    
+    struct planeEq { //ax*x + ay*y = c
+        Double_t ax, ay, c;
+    };
+    auto GetDistancePointLine2D = [](planeEq line, Double_t x, Double_t y) {
+        return fabs(line.ax*x + line.ay*y - line.c)/sqrt(line.ax*line.ax + line.ay*line.ay);
+    };
+    
+    //get plane/line equations for left/right edge of module: crosses (0, yRayStart)
+    planeEq planeEqCenter = {vectorUnitModuleCenter.Y(), -vectorUnitModuleCenter.X(), -vectorUnitModuleCenter.X()*yRayStart};
+    planeEq planeEqPeriph = {vectorUnitModulePeriph.Y(), -vectorUnitModulePeriph.X(), -vectorUnitModulePeriph.X()*yRayStart};
+    planeEq planeEqMiddle = {vectorUnitModuleMiddle.Y(), -vectorUnitModuleMiddle.X(), -vectorUnitModuleMiddle.X()*yRayStart};
+    
+    //find intersection with y = yCoordBasketBottom and y = yCoordBasketBottom+basketHeight of lines passing through yRayStart
+    Double_t xBottomPeriph = (planeEqPeriph.c - planeEqPeriph.ay*yCoordBasketBottom)/planeEqPeriph.ax;
+    if (stackingXdirection >= 0) xBottomPeriph -= (moduleClearance/2)/TMath::Cos(TMath::DegToRad()*angleModulePeriph);
+    else xBottomPeriph += (moduleClearance/2)/TMath::Cos(TMath::DegToRad()*angleModulePeriph);
+    
+    Double_t xTopCenter = (planeEqCenter.c - planeEqCenter.ay*(yCoordBasketBottom+basketHeight))/planeEqCenter.ax;
+    if (stackingXdirection >= 0) xTopCenter += (moduleClearance/2)/TMath::Cos(TMath::DegToRad()*angleModuleCenter);
+    else xTopCenter -= (moduleClearance/2)/TMath::Cos(TMath::DegToRad()*angleModuleCenter);
+    Double_t yTopCenter = yCoordBasketBottom + basketHeight;
+    
+    TVector3 vectorUnitBottomPeriphToHeight = TVector3(vectorUnitModuleMiddle.Y(), -vectorUnitModuleMiddle.X(), 0);
+    if (vectorUnitBottomPeriphToHeight.X()*stackingXdirection >= 0) {
+        vectorUnitBottomPeriphToHeight.SetX(-vectorUnitBottomPeriphToHeight.X());
+        vectorUnitBottomPeriphToHeight.SetY(-vectorUnitBottomPeriphToHeight.Y());
+        vectorUnitBottomPeriphToHeight.SetZ(-vectorUnitBottomPeriphToHeight.Z());
+    }
+    
+    //get distance from point (xBottomPeriph, yCoordBasketBottom) to planeEqMiddle
+    Double_t distBottomPeriphToHeight = GetDistancePointLine2D(planeEqMiddle, xBottomPeriph, yCoordBasketBottom);
+    TVector3 vectorScaledInnerPhiToCenter = vectorUnitBottomPeriphToHeight; vectorScaledInnerPhiToCenter.SetMag(distBottomPeriphToHeight*2);
+    Double_t xBottomCenter = xBottomPeriph + vectorScaledInnerPhiToCenter.X();
+    Double_t yBottomCenter = yCoordBasketBottom + vectorScaledInnerPhiToCenter.Y();
+        
+    if (fabs(angleModuleCenter) < 1e-10 && fabs(xBottomCenter - stackingXdirection*moduleClearance/2) > 1e-10) {
+        Fatal("SpdEcalTB2::StackModuleInSector", "oops! for the first filled module, the bottom left x should zero! something is wrong!");
+    }
+    
+    TVector3 vectorUnitTopCenterToHeight = TVector3(vectorUnitModuleMiddle.Y(), -vectorUnitModuleMiddle.X(), 0); //!!!
+    if (vectorUnitTopCenterToHeight.X()*stackingXdirection < 0) {
+        vectorUnitTopCenterToHeight.SetX(-vectorUnitTopCenterToHeight.X());
+        vectorUnitTopCenterToHeight.SetY(-vectorUnitTopCenterToHeight.Y());
+        vectorUnitTopCenterToHeight.SetZ(-vectorUnitTopCenterToHeight.Z());
+    }
+    
+    Double_t distTopCenterToHeight = GetDistancePointLine2D(planeEqMiddle, xTopCenter, yTopCenter);
+    TVector3 vectorScaledOuterPhiToPeriph = vectorUnitTopCenterToHeight; vectorScaledOuterPhiToPeriph.SetMag(distTopCenterToHeight*2);
+    
+    Double_t xMiddleInnerPhi = xBottomPeriph + vectorScaledInnerPhiToCenter.X()/2;
+    Double_t yMiddleInnerPhi = yCoordBasketBottom + vectorScaledInnerPhiToCenter.Y()/2;
+    Double_t xMiddleOuterPhi = xTopCenter + vectorScaledOuterPhiToPeriph.X()/2;
+    Double_t yMiddleOuterPhi = yTopCenter + vectorScaledOuterPhiToPeriph.Y()/2;
+    
+    TVector3 vectorTrapezoidHeightToOuter = TVector3(xMiddleOuterPhi - xMiddleInnerPhi, yMiddleOuterPhi - yMiddleInnerPhi, 0);
+    Double_t trapezoidHeight = vectorTrapezoidHeightToOuter.Mag();
+
+    Double_t moduleOuterSizePhi = 2*distTopCenterToHeight;
+    Double_t moduleInnerSizePhi = 2*distBottomPeriphToHeight;
+    
+    //make a tgeovolume, remembering about all the conventions 
+    //z ->-> from large to small side, X ~ theta, Y ~ phi, +-/--/-+/++
+    
+    Double_t moduleVertices[16];
+    moduleVertices[0] = moduleInnerSizeTheta/2;       moduleVertices[1] = -moduleOuterSizePhi/2;
+    moduleVertices[2] = -moduleInnerSizeTheta/2;      moduleVertices[3] = -moduleOuterSizePhi/2;
+    moduleVertices[4] = -moduleInnerSizeTheta/2;      moduleVertices[5] = moduleOuterSizePhi/2;
+    moduleVertices[6] = moduleInnerSizeTheta/2;       moduleVertices[7] = moduleOuterSizePhi/2;
+    
+    moduleVertices[8] = moduleInnerSizeTheta/2;       moduleVertices[9] = -moduleInnerSizePhi/2;
+    moduleVertices[10] = -moduleInnerSizeTheta/2;     moduleVertices[11] = -moduleInnerSizePhi/2;
+    moduleVertices[12] = -moduleInnerSizeTheta/2;     moduleVertices[13] = moduleInnerSizePhi/2;
+    moduleVertices[14] = moduleInnerSizeTheta/2;      moduleVertices[15] = moduleInnerSizePhi/2;
+    
+    TGeoVolume* moduleVolume = 0;
+    if (trimModuleLength) moduleVolume = gGeoManager->MakeArb8("MODULE", Air, trapezoidHeight/2, moduleVertices);
+    else {
+        Double_t outerPhi = moduleOuterSizePhi/2;
+        Double_t innerPhi = moduleInnerSizePhi/2;
+        Double_t innerPhi2 = outerPhi - (outerPhi - innerPhi)*totalZSize/trapezoidHeight;
+        moduleVertices[9] = -innerPhi;
+        moduleVertices[11] = -innerPhi;
+        moduleVertices[13] = innerPhi;
+        moduleVertices[15] = innerPhi;
+        moduleVolume = gGeoManager->MakeArb8("MODULE", Air, totalZSize/2, moduleVertices);
+    }
+    
+    TMatrixD matrixModule = GetMatrixToEmplaceModule(planeEqCenter.ax, planeEqCenter.ay, false, moduleVolume);
+    if (stackingXdirection < 0) matrixModule = GetMatrixToEmplaceModule(planeEqCenter.ax, planeEqCenter.ay, true, moduleVolume);
+    
+    if (angleModulePeriph > 0 && trimModuleLength) {
+        cout << "-I- <SpdEcalTB2::StackModuleInSector> : module П† size is set to " << (moduleInnerSizePhi - cellClearance)/2 << " cm, module length (in radial direction): " << trapezoidHeight << " cm" << endl;
+    }
+    if (angleModulePeriph > 0 && !trimModuleLength) {
+        cout << "-I- <SpdEcalTB2::StackModuleInSector> : module П† size is set to " << (moduleInnerSizePhi - cellClearance)/2 << " cm, module length (in radial direction): " << totalZSize << " cm" << endl;
+    }
+    
+    moduleVolume->SetLineColor(kBlue);
+    moduleVolume->SetFillColor(kBlue);
+    moduleVolume->SetTransparency(50);
+    
+    if (!trimModuleLength) {
+        vectorTrapezoidHeightToOuter.SetMag(totalZSize);
+    }
+    
+    Double_t xHeightMiddle = xMiddleInnerPhi + vectorTrapezoidHeightToOuter.X()/2;
+    Double_t yHeightMiddle = yMiddleInnerPhi + vectorTrapezoidHeightToOuter.Y()/2;
+    
+    TGeoRotation * rot = new TGeoRotation();
+    rot->SetMatrix(matrixModule.GetMatrixArray());
+    TGeoTranslation * trans = new TGeoTranslation(xHeightMiddle, yHeightMiddle, 0);
+    TGeoCombiTrans * combiTrans = new TGeoCombiTrans(*trans, *rot);
+    return make_pair(combiTrans, moduleVolume);
+}
+
+//________________________________________________________________________________
+void SpdEcalTB2::BuildBasket() {
+    
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) return; 
+   
+    Int_t nLayers = mapper->GetNLayers();
+    Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+    Double_t layer2SizeZ = mapper->GetLayer2SizeZ();  
+    TString baseMedium = mapper->GetBaseMedium();
+    TGeoMedium* Air = FindMedium(baseMedium, "");
+    Double_t lzsize = layer1SizeZ + layer2SizeZ;
+    Double_t tzsize = nLayers * lzsize;
+    Double_t barrelLength = mapper->GetBarrelLength();
+    Double_t barrelRadius = mapper->GetBarrelOuterSize() - mapper->GetBarrelWidth();
+    Double_t basketClearance = mapper->GetBasketClearance();
+    Double_t sectorClearance = mapper->GetSectorClearance();
+    Int_t nSectors = mapper->GetNSectors();
+    Bool_t forceCellSize = mapper->IsForceCellSize();
+    Double_t barrelModuleRadialSize = mapper->GetBarrelModuleRadialSize();
+    
+    //get basket dimensions
+    Double_t basketHeight = (forceCellSize) ? tzsize : barrelModuleRadialSize;
+    Double_t basketZSize = barrelLength/2 - 2*basketClearance;
+    Double_t doubleAngleBasket = 360./nSectors;
+    Double_t angleSmallBasketFoundation = (180.0 - doubleAngleBasket)/2;
+    Double_t basketPhiInnerSize = 2*barrelRadius*TMath::Tan(TMath::DegToRad()*doubleAngleBasket/2) - sectorClearance/TMath::Sin(TMath::DegToRad()*angleSmallBasketFoundation);
+    Double_t basketPhiOuterSize = (basketPhiInnerSize + sectorClearance/TMath::Sin(TMath::DegToRad()*angleSmallBasketFoundation))*(barrelRadius + basketHeight)/barrelRadius - sectorClearance/TMath::Sin(TMath::DegToRad()*angleSmallBasketFoundation);
+    
+    Double_t basketVertices[16];
+    
+    basketVertices[0] = basketPhiInnerSize/2;       basketVertices[1] = barrelRadius;
+    basketVertices[2] = -basketPhiInnerSize/2;      basketVertices[3] = barrelRadius;
+    basketVertices[4] = -basketPhiOuterSize/2;      basketVertices[5] = barrelRadius + basketHeight;
+    basketVertices[6] = basketPhiOuterSize/2;       basketVertices[7] = barrelRadius + basketHeight;
+    
+    basketVertices[8] = basketPhiInnerSize/2;       basketVertices[9] = barrelRadius;
+    basketVertices[10] = -basketPhiInnerSize/2;     basketVertices[11] = barrelRadius;
+    basketVertices[12] = -basketPhiOuterSize/2;     basketVertices[13] = barrelRadius + basketHeight;
+    basketVertices[14] = basketPhiOuterSize/2;      basketVertices[15] = barrelRadius + basketHeight;
+    
+    fBasket = gGeoManager->MakeArb8("EcalBasket", Air, basketZSize/2, basketVertices);
+    
+    fBasket->SetFillColor(kBlue);
+    fBasket->SetLineColor(kBlue);
+    fBasket->SetTransparency(50);
+}
+
+//________________________________________________________________________________
+void SpdEcalTB2::BuildBarrel() {
+    
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) return; 
+     
+    TString baseMedium = mapper->GetBaseMedium();
+    TGeoMedium* Air = FindMedium(baseMedium, "");
+    Int_t nSectors = mapper->GetNSectors();
+    Double_t barrelLength = mapper->GetBarrelLength();
+    
+    Int_t iCurrentBasket = 1;
+    for (int iphi = 0; iphi < nSectors; ++iphi) { 
+        
+        TGeoTranslation* transBasketPos = new TGeoTranslation(0, 0,  barrelLength/2);
+        TGeoTranslation* transBasketNeg = new TGeoTranslation(0, 0, -barrelLength/2);
+        TGeoRotation* rotationZY180 = new TGeoRotation();
+        TGeoRotation* rotationZ = new TGeoRotation();
+        rotationZY180->RotateY(180);
+        rotationZY180->RotateZ(iphi*360.0/nSectors);
+        rotationZ->RotateZ(iphi*360.0/nSectors);
+        TGeoCombiTrans * combiTransBasketY180 = new TGeoCombiTrans(*transBasketNeg, *rotationZY180);
+        TGeoCombiTrans * combiTransBasket = new TGeoCombiTrans(*transBasketPos, *rotationZ);
+        fMasterVolume->AddNode(fBasket, iCurrentBasket++, combiTransBasket);
+        fMasterVolume->AddNode(fBasket, iCurrentBasket++, combiTransBasketY180);
+        
+    }
+    
+}
+
+//________________________________________________________________________________
+TMatrixD SpdEcalTB2::GetMatrixToEmplaceModule(Double_t ax, Double_t ay, 
+                                              Bool_t rotateClockwise, TGeoVolume* moduleVolume) 
+{
+   // 
+   // return rotation matrix for given TGeoVolume (of shape TGeoArb8, trapezoid), such that: 
+   // for module, rotated using this matrix, the projection of the module face, which goes along Z axis, 
+   // on Z = 0 plane is parallel to the line, given by equation ax*x + ay*y = 0, where ax, ay 
+   // are the arguments for this function;
+   // the argument rotateClockwise indicates whether the module should be placed clockwise 
+   // of the line (true) or anti-clockwise (false) it is assumed that the face which will go along Z axis 
+   // in the rotated module, goes along X axis for the unrotated module.
+   // It is assumed the two sides are properly centered around 0.
+   //
+   assert(TString(moduleVolume->GetShape()->ClassName()).CompareTo("TGeoArb8") == 0);
+   
+   TGeoArb8 * moduleShape = (TGeoArb8*)moduleVolume->GetShape();
+   Double_t* moduleVertices = moduleShape->GetVertices();
+   
+   //ASSUMING THE first 4 vertices are larger side
+   assert(fabs(moduleVertices[0]) >= fabs(moduleVertices[8]));
+   assert(fabs(moduleVertices[1]) >= fabs(moduleVertices[9]));
+   
+   //ASSUMING vertex 0 in +-, 1 in --, 2 in -+, 3 in ++ quadrant
+   assert(moduleVertices[0] > moduleVertices[2]);
+   assert(moduleVertices[5] > moduleVertices[3]);
+   assert(moduleVertices[6] > moduleVertices[4]);
+   assert(moduleVertices[7] > moduleVertices[1]);
+   assert(moduleVertices[0] >= moduleVertices[8]);
+   
+   Double_t thetaLargeEdge = moduleVertices[0]  - moduleVertices[2];
+   Double_t thetaSmallEdge = moduleVertices[8]  - moduleVertices[10];
+   Double_t phiLargeEdge   = moduleVertices[7]  - moduleVertices[1];
+   Double_t phiSmallEdge   = moduleVertices[15] - moduleVertices[9];
+   
+   Double_t moduleLength = 2*moduleShape->GetDz();
+
+   //pick some triplet of vectors that go along edges of the unrotated module
+   TVector3 initialVector1 = TVector3(moduleVertices[0] - moduleVertices[8], 
+                                      moduleVertices[1] - moduleVertices[9], 
+                                     -moduleLength);
+   
+   TVector3 initialVector2 = TVector3(moduleVertices[2] - moduleVertices[0], moduleVertices[3] - moduleVertices[1], 0);
+   TVector3 initialVector3 = TVector3(moduleVertices[6] - moduleVertices[0], moduleVertices[7] - moduleVertices[1], 0);
+   TVector3 initialVectorMidfacePhi = TVector3(0, moduleVertices[1] - moduleVertices[9], -moduleLength);
+   TVector3 initialVectorMidfacePhi2 = TVector3(initialVectorMidfacePhi);
+   initialVectorMidfacePhi2.SetY(-initialVectorMidfacePhi2.Y());
+   
+   TVector3 initialVectorMidfaceTheta = TVector3(moduleVertices[0] - moduleVertices[8], 0, -moduleLength);
+   TVector3 initialVectorMidfaceTheta2 = TVector3(initialVectorMidfaceTheta);
+   initialVectorMidfaceTheta2.SetX(-initialVectorMidfaceTheta2.X());
+   
+   Double_t doubleAngleModulePhi = 2*TMath::ATan((0.5*phiLargeEdge - 0.5*phiSmallEdge)/moduleLength);
+   Double_t doubleAngleModuleTheta = 2*TMath::ATan((0.5*thetaLargeEdge - 0.5*thetaSmallEdge)/moduleLength);
+   
+   //get same triplet for rotated module using the plane equation
+   //first vector: bottom-to-top middle-edge at-leanwall vector of the trapezoid + y(x) component
+   TVector3 finalVector1 = TVector3(-ay, ax, 0);
+   finalVector1.SetMag(initialVectorMidfacePhi.Mag());
+   if (rotateClockwise) {
+       finalVector1.SetZ(-moduleVertices[0] + moduleVertices[8]);
+   }
+   else {
+       finalVector1.SetZ(moduleVertices[0] - moduleVertices[8]);
+   }
+   
+   //second vector: pure Z/theta vector
+   TVector3 finalVector2;
+   if (rotateClockwise) finalVector2 = TVector3(0, 0, 1);
+   else finalVector2 = TVector3(0, 0, -1);
+   finalVector2.SetMag(initialVector2.Mag());
+   
+   //second vector: phi+ vector, according to 2d plane equation
+   TVector3 finalVector3 = TVector3(ax, ay, 0);
+   if (rotateClockwise) finalVector3.RotateZ(doubleAngleModulePhi/2);
+   else finalVector3.RotateZ(-doubleAngleModulePhi/2);
+   
+   //save the orientation
+   if (finalVector3.X() > 0 && rotateClockwise) finalVector3 *= -1;
+   finalVector3.SetMag(initialVector3.Mag());
+       
+   TMatrixD rotationMatrix = GetMatrixToRotateVectorTriplet(initialVector1, initialVector2, initialVector3, 
+                                                            finalVector1, finalVector2, finalVector3);
+   
+   return rotationMatrix;    
+}
+
+//_______________________________________________________________________________
+TMatrixD SpdEcalTB2::GetMatrixToRotateVectorTriplet(TVector3 initialVector1, TVector3 initialVector2, TVector3 initialVector3,
+                                                    TVector3 finalVector1, TVector3 finalVector2, TVector3 finalVector3) 
+{
+   Double_t tolerance = 1e-10;  
+   
+   assert(fabs(finalVector1.Mag() - initialVector1.Mag()) < tolerance);
+   assert(fabs(finalVector2.Mag() - initialVector2.Mag()) < tolerance);
+   assert(fabs(finalVector3.Mag() - initialVector3.Mag()) < tolerance);
+   assert(fabs(initialVector1.Angle(initialVector2) - finalVector1.Angle(finalVector2)) < tolerance);
+   assert(fabs(initialVector1.Angle(initialVector3) - finalVector1.Angle(finalVector3)) < tolerance);
+   assert(fabs(initialVector2.Angle(initialVector3) - finalVector2.Angle(finalVector3)) < tolerance);
+   
+   const Double_t finalStateMatrixElements[9] = {
+       finalVector1.X(), finalVector2.X(), finalVector3.X(), 
+       finalVector1.Y(), finalVector2.Y(), finalVector3.Y(), 
+       finalVector1.Z(), finalVector2.Z(), finalVector3.Z()
+   };
+   
+   TMatrixD finalStateMatrix = TMatrixD(3, 3, finalStateMatrixElements); // a[irow,icol] = elements[irow*no_cols+icol]
+   
+   const Double_t initialStateMatrixElements[9] = {
+       initialVector1.X(), initialVector2.X(), initialVector3.X(), 
+       initialVector1.Y(), initialVector2.Y(), initialVector3.Y(), 
+       initialVector1.Z(), initialVector2.Z(), initialVector3.Z()
+   };
+   
+   TMatrixD initialStateMatrix = TMatrixD(3, 3, initialStateMatrixElements); // a[irow,icol] = elements[irow*no_cols+icol]
+   
+   TMatrixD initialStateMatrixInverted = initialStateMatrix.Invert();
+   TMatrixD rotationMatrix = finalStateMatrix*initialStateMatrixInverted;
+   
+   TVector3 vectorColumn1 = TVector3(rotationMatrix[0][0], rotationMatrix[1][0], rotationMatrix[2][0]);
+   TVector3 vectorColumn2 = TVector3(rotationMatrix[0][1], rotationMatrix[1][1], rotationMatrix[2][1]);
+   TVector3 vectorColumn3 = TVector3(rotationMatrix[0][2], rotationMatrix[1][2], rotationMatrix[2][2]);
+   
+   assert(fabs(vectorColumn1.Angle(vectorColumn2) - TMath::Pi()/2) < tolerance);
+   assert(fabs(vectorColumn1.Angle(vectorColumn3) - TMath::Pi()/2) < tolerance);
+   assert(fabs(vectorColumn2.Angle(vectorColumn3) - TMath::Pi()/2) < tolerance);
+   
+   assert(fabs(vectorColumn1.Mag() - 1.) < tolerance);
+   assert(fabs(vectorColumn2.Mag() - 1.) < tolerance);
+   assert(fabs(vectorColumn3.Mag() - 1.) < tolerance);
+   
+   return rotationMatrix;
+}
+
+//________________________________________________________________________________
+void SpdEcalTB2::GetEmplacedModulePosition(TGeoVolume* moduleVolume, 
+                                           Double_t ax, Double_t ay, Double_t arhs, 
+                                           Double_t ax2, Double_t ay2, Double_t arhs2, 
+                                           Double_t & xMiddle, Double_t & yMiddle, 
+                                           Double_t & ax_new, Double_t & ay_new, Double_t & arhs_new, 
+                                           Double_t & xPlane2Bottom, Double_t & yPlane2Bottom, 
+                                           Double_t & xPlane2Top, Double_t & yPlane2Top) 
+{
+   // 
+   // Place a module in its place.
+   // moduleVolume:  module to place
+   // ax/ay/arhs:    the equation that describes the plane that the face of the module should lean on (ax*x + ay*y = arhs)
+   // ax2/ay2/arhs2: this equation describes the plane that an edge (or a face) of the module should stand on, 
+   //                while leaning on the ax/ay/arhs plane.
+   // 
+    
+   if (ax < 0 || ay < 0) {
+       Fatal("SpdEcalTB2::GetEmplacedModulePosition", 
+             "can't stack module: function only valid for plane with ax >=0, ay >= 0");
+   }
+   
+   // deltaXdirection/deltaYdirection: (+1/-1): sign of the X(Y) component of vector 
+   // parallel to the module edge along the Z axis and starting at plane ax/ay/arhs
+   // rotateZdirection: (+1/-1): if +1, the module is placed clockwise of plane ax/ay/arhs. 
+   // Else it is placed anticlockwise.
+   
+   Int_t deltaXdirection = -1;
+   Int_t deltaYdirection = -1;
+   Int_t rotateZdirection = 1;
+   
+   SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+   if (!mapper) Fatal("SpdEcalTB2::GetEmplacedModulePosition", "no mapper");
+   
+   Int_t nLayers = mapper->GetNLayers();
+   Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+   Double_t layer2SizeZ = mapper->GetLayer2SizeZ();
+   Double_t lzsize = layer1SizeZ + layer2SizeZ;
+   Double_t tzsize = nLayers * lzsize;
+   
+   TGeoArb8 * moduleShape = (TGeoArb8*)moduleVolume->GetShape();
+   Double_t* moduleVertices = moduleShape->GetVertices();
+   
+   //ASSUMING THE first 4 vertices are larger side
+   assert(fabs(moduleVertices[0]) >= fabs(moduleVertices[8]));
+   assert(fabs(moduleVertices[1]) >= fabs(moduleVertices[9]));
+   
+   //ASSUMING vertex 0 in +-, 1 in --, 2 in -+, 3 in ++ quadrant
+   assert(moduleVertices[0] > moduleVertices[2]);
+   assert(moduleVertices[5] > moduleVertices[3]);
+   assert(moduleVertices[6] > moduleVertices[4]);
+   assert(moduleVertices[7] > moduleVertices[1]);
+   assert(moduleVertices[0] >= moduleVertices[8]);
+       
+   Double_t thetaLargeEdge = moduleVertices[0]  - moduleVertices[2];
+   Double_t thetaSmallEdge = moduleVertices[8]  - moduleVertices[10];
+   Double_t phiLargeEdge   = moduleVertices[7]  - moduleVertices[1];
+   Double_t phiSmallEdge   = moduleVertices[15] - moduleVertices[9];
+   Double_t moduleLength   = 2*moduleShape->GetDz();
+   
+   Double_t angleTrapezoidPhi = TMath::ATan((0.5*phiLargeEdge - 0.5*phiSmallEdge)/moduleLength);
+   Double_t angleTrapezoidTheta = TMath::ATan((0.5*thetaLargeEdge - 0.5*thetaSmallEdge)/moduleLength);
+   
+   //given the plane equation ax/ay/arhs and the bottom plane, get the module center and the new plane
+   
+   TVector3 vectorMidfaceCenter = TVector3(ay, -ax, 0); //from inner(small) to outer(large) side of the trapezoid
+   if (vectorMidfaceCenter.Y() < 0) vectorMidfaceCenter *= -1;
+   
+   TVector3 vectorTrapezoidHeight = vectorMidfaceCenter; //from inner(small) to outer(large) side of the trapezoid
+   if (rotateZdirection > 0) {
+       vectorTrapezoidHeight.RotateZ(angleTrapezoidPhi); 
+   }
+   else {
+       vectorTrapezoidHeight.RotateZ(-angleTrapezoidPhi);
+   }
+   TVector3 vectorMidfacePeriph(vectorMidfaceCenter); //from inner(small) to outer(large) side of the trapezoid
+   if (rotateZdirection > 0) {
+       vectorMidfacePeriph.RotateZ(2*angleTrapezoidPhi);
+   }
+   else {
+       vectorMidfacePeriph.RotateZ(-2*angleTrapezoidPhi);
+   }
+   
+   // !!! here +/- means in which quadrant we want to stick the module. All 4 +- combinations are solutions.
+   
+   Double_t deltaY = deltaYdirection*phiSmallEdge/sqrt(1 + vectorTrapezoidHeight.Y()*vectorTrapezoidHeight.Y()/(vectorTrapezoidHeight.X()*vectorTrapezoidHeight.X()));
+   Double_t deltaX;
+   if (deltaXdirection < 0) {
+       deltaX = -phiSmallEdge/sqrt(1 + vectorTrapezoidHeight.X()*vectorTrapezoidHeight.X()/(vectorTrapezoidHeight.Y()*vectorTrapezoidHeight.Y()));
+   }
+   else {
+       deltaX = phiSmallEdge/sqrt(1 + vectorTrapezoidHeight.X()*vectorTrapezoidHeight.X()/(vectorTrapezoidHeight.Y()*vectorTrapezoidHeight.Y()));
+   }
+   
+   //lower point at plane1. Weird expression but oh well
+   
+   Double_t yPlane1 = (arhs*(-ax2) - (-ax)*(arhs2 - deltaY*ay2 - (-deltaX)*(-ax2)))/(ay*(-ax2) - (-ax)*ay2);
+   Double_t xPlane1 = -(arhs*ay2 - ay*(arhs2 - deltaY*ay2 - (-deltaX)*(-ax2)))/((-ax)*ay2 - ay*(-ax2));
+   
+   Double_t yInnerSideMiddle = yPlane1 + deltaY/2;
+   Double_t xInnerSideMiddle = xPlane1 + deltaX/2;
+   
+   // (0,0) -> (zInnerSideMiddle, xInnerSideMiddle) && plane2, 
+   // x*zInnerSideMiddle - z*xInnerSideMiddle = 0 && plane2.ax*x + plane2.az*z = plane2.arhs
+       
+   yMiddle = yInnerSideMiddle + vectorTrapezoidHeight.Unit().Y()*tzsize/2;
+   xMiddle = xInnerSideMiddle + vectorTrapezoidHeight.Unit().X()*tzsize/2;
+   
+   yPlane2Bottom = yPlane1 + deltaY;
+   xPlane2Bottom = xPlane1 + deltaX;
+       
+   //get plane equation for peripheral side of the module -> will be used to place the next module
+   
+   ax_new = vectorMidfacePeriph.Y();
+   ay_new = -vectorMidfacePeriph.X();
+   arhs_new = ax_new*xPlane2Bottom + ay_new*yPlane2Bottom;
+       
+   Double_t sizePhiSide = tzsize/TMath::Cos(angleTrapezoidPhi);
+   vectorMidfacePeriph.SetMag(sizePhiSide);
+   
+   yPlane2Top = yPlane2Bottom + vectorMidfacePeriph.Y();
+   xPlane2Top = xPlane2Bottom + vectorMidfacePeriph.X();
+}
+
+//________________________________________________________________________________   
+void SpdEcalTB2::FillBasketFixedCells(TGeoVolume* basketVolume, TGeoVolume* moduleVolume) 
+{ 
+   SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+   if (!mapper) return; 
+   
+   Double_t barrelInnerSize = mapper->GetBarrelOuterSize() - mapper->GetBarrelWidth();
+   Double_t moduleClearance = mapper->GetModuleClearance();
+   Int_t nSectors = mapper->GetNSectors();
+   
+   TGeoArb8* moduleShape = (TGeoArb8*)moduleVolume->GetShape();
+   Double_t* moduleVertices = moduleShape->GetVertices();
+   Double_t moduleInnerSizeTheta = fabs(moduleVertices[0] - moduleVertices[2]);
+   Double_t moduleOuterSizeTheta = fabs(moduleVertices[8] - moduleVertices[10]);
+   assert(moduleInnerSizeTheta == moduleOuterSizeTheta); //non-projective geometry
+   
+   Double_t basketZSize = ((TGeoArb8*)basketVolume->GetShape())->GetDz()*2;
+   
+   Double_t* basketVertices = ((TGeoArb8*)basketVolume->GetShape())->GetVertices();
+   
+   assert(basketVertices[0] > basketVertices[2]);
+   
+   Double_t basketPhiInnerSize = basketVertices[0] - basketVertices[2];
+   
+   assert(basketVertices[5] > basketVertices[3]);
+   
+   Double_t basketHeight = basketVertices[5] - basketVertices[3];
+   
+   assert(basketVertices[6] > basketVertices[4]);
+   
+   Double_t basketPhiOuterSize = basketVertices[6] - basketVertices[4];
+   Double_t doubleAngleBasket = 360./nSectors;
+   
+   Double_t nmodulesZ = 0; //number of modules in a basket in Z direction
+   Double_t basketFilledZSize = moduleOuterSizeTheta;
+   
+   while (basketFilledZSize < basketZSize) {
+       nmodulesZ += 1;
+       basketFilledZSize += moduleOuterSizeTheta + moduleClearance;
+   }
+   
+   basketFilledZSize -= moduleOuterSizeTheta + moduleClearance;
+   nmodulesZ -= 1;
+   
+   Int_t iPhiModule = 1;
+   
+   struct planeEqY { //plane(line) equation of the form y = ax*x + c
+       Double_t ax;
+       Double_t c;
+   };
+   
+   planeEqY basketRightEdge; 
+   basketRightEdge.ax = basketHeight/(basketPhiOuterSize/2 - basketPhiInnerSize/2);
+   basketRightEdge.c = barrelInnerSize - (basketPhiInnerSize/2)*basketHeight/(basketPhiOuterSize/2 - basketPhiInnerSize/2);
+   planeEqY basketLeftEdge;
+   basketLeftEdge.ax = -basketRightEdge.ax;
+   basketLeftEdge.c = basketRightEdge.c;
+   
+   Double_t ax = 1;
+   Double_t ay = 0;
+   Double_t arhs = -moduleClearance/2;
+   
+   Double_t ax2 = 0;
+   Double_t ay2 = 1;
+   Double_t arhs2 = barrelInnerSize;
+   
+   Bool_t moduleInBasket = true;
+   while (moduleInBasket) {
+   
+       Double_t xMiddle, yMiddle, ax_new, ay_new, arhs_new, xPlane2Bottom, yPlane2Bottom, xPlane2Top, yPlane2Top;
+       
+       TMatrixD rotationMatrix = GetMatrixToEmplaceModule(ax, ay, true, moduleVolume);
+       
+       GetEmplacedModulePosition(moduleVolume, ax, ay, arhs, ax2, ay2, arhs2, 
+                                 xMiddle, yMiddle, ax_new, ay_new, arhs_new, 
+                                 xPlane2Bottom, yPlane2Bottom, xPlane2Top, yPlane2Top);
+                   
+       ax = ax_new;
+       ay = ay_new;
+       arhs = arhs_new;
+       
+       //add clearance between modules and change arhs accordingly
+       Double_t angleBorderPlane = TMath::ATan(-ay/ax);
+       arhs += -ax*moduleClearance/TMath::Cos(angleBorderPlane);
+       
+       Bool_t bottomCornerInBasket = yPlane2Bottom > (basketLeftEdge.ax*xPlane2Bottom + basketLeftEdge.c);
+       Bool_t topCornerInBasket = yPlane2Top > (basketLeftEdge.ax*xPlane2Top + basketLeftEdge.c);
+       moduleInBasket = bottomCornerInBasket && topCornerInBasket;
+       
+       Double_t currZcenter = -basketZSize/2 + moduleOuterSizeTheta/2;
+       
+       if (moduleInBasket) {
+       
+           TGeoRotation * rot = new TGeoRotation();
+           rot->SetMatrix(rotationMatrix.GetMatrixArray());
+               
+           for (int iz = 0; iz < nmodulesZ; ++iz) {
+               TGeoTranslation * trans = new TGeoTranslation(xMiddle, yMiddle, currZcenter);
+               TGeoCombiTrans * combiTrans = new TGeoCombiTrans(*trans, *rot);
+               basketVolume->AddNode(moduleVolume, 100*(iz+1) + iPhiModule, combiTrans);
+               TGeoCombiTrans* combiTransMirror = (TGeoCombiTrans*)combiTrans->MakeClone(); 
+               combiTransMirror->ReflectX(true);
+               basketVolume->AddNode(moduleVolume, 100*(iz+1) - iPhiModule, combiTransMirror);
+               currZcenter += moduleClearance + moduleOuterSizeTheta;
+           }
+       }
+       iPhiModule += 1;
+   }
+}
+
+//_____________________________________________________________________________________
+Double_t SpdEcalTB2::LinearInterp(Double_t x1, Double_t x2, Double_t t) 
+{
+    assert(t >= 0 && t <= 1);
+    return (t*x2 + (1-t)*x1);
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2::BuildModule(TGeoVolume* module) 
+{        
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) return; 
+    
+    TString baseMedium = mapper->GetBaseMedium();
+    TString absorberMedium = mapper->GetAbsorberMedium();
+    TString scintMedium = mapper->GetScintMedium();
+    TGeoMedium* Air = FindMedium(baseMedium, "");
+    TGeoMedium* Lead = FindMedium(absorberMedium, baseMedium);
+    TGeoMedium* Scint = FindMedium(scintMedium, baseMedium);
+    Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+    Double_t layer2SizeZ = mapper->GetLayer2SizeZ();
+    Double_t cellClearance = mapper->GetCellClearance();
+    
+    Double_t moduleZsize = ((TGeoArb8*)module->GetShape())->GetDz()*2;
+    Double_t* moduleVertices = ((TGeoArb8*)module->GetShape())->GetVertices();
+    
+    assert(moduleVertices[0] == -moduleVertices[2]);
+    assert(moduleVertices[4] == -moduleVertices[6]);
+    assert(moduleVertices[1] == -moduleVertices[7]);
+    assert(moduleVertices[3] == -moduleVertices[5]);
+    
+    Double_t layerZSize = layer1SizeZ + layer2SizeZ;
+    
+    //build quarter of module into (+,-) quadrant
+    Double_t cellVertices[16];
+    
+    cellVertices[0] = moduleVertices[0];        cellVertices[1] = moduleVertices[1];
+    cellVertices[2] = cellClearance/2;          cellVertices[3] = moduleVertices[3];
+    cellVertices[4] = cellClearance/2;          cellVertices[5] = -cellClearance/2;
+    cellVertices[6] = moduleVertices[6];        cellVertices[7] = -cellClearance/2;
+    
+    cellVertices[8] = moduleVertices[8];        cellVertices[9] = moduleVertices[9];
+    cellVertices[10] = cellClearance/2;         cellVertices[11] = moduleVertices[11];
+    cellVertices[12] = cellClearance/2;         cellVertices[13] = -cellClearance/2;
+    cellVertices[14] = moduleVertices[14];      cellVertices[15] = -cellClearance/2;
+
+    TGeoVolume* cellVolume = gGeoManager->MakeArb8("Cell", Air, moduleZsize/2, cellVertices); 
+    cellVolume->SetFillColor(kAzure+1);
+    cellVolume->SetLineColor(kAzure+1);
+    cellVolume->SetTransparency(50);
+    
+    Int_t currNlayers = floor(moduleZsize/layerZSize);
+    Double_t moduleZbegin = -moduleZsize/2;
+    Double_t moduleZend = moduleZsize/2;
+    
+    for (Int_t ilayer = 0; ilayer < currNlayers; ++ilayer) {
+        
+        Double_t layerZbegin = moduleZbegin + ilayer*(layerZSize);
+        Double_t layerZend = layerZbegin + layerZSize;
+        
+        Double_t layer1Zbegin = layerZbegin;
+        Double_t layer1Zend = layerZbegin + layer1SizeZ;
+        Double_t layer2Zbegin = layerZbegin + layer1SizeZ;
+        Double_t layer2Zend = layerZend;
+        
+        Double_t layer1Vertices[16];
+        for (int iv = 0; iv < 8; ++iv) {
+            Double_t interpT = (layer1Zbegin - moduleZbegin)/(moduleZend - moduleZbegin);
+            if (ilayer == 0) interpT = 0.;
+            layer1Vertices[iv] = LinearInterp(cellVertices[iv], cellVertices[iv+8], interpT);
+        }
+        for (int iv = 8; iv < 16; ++iv) {
+            Double_t interpT = (layer1Zend - moduleZbegin)/(moduleZend - moduleZbegin);
+            layer1Vertices[iv] = LinearInterp(cellVertices[iv-8], cellVertices[iv], interpT);
+        }
+        
+        TGeoVolume* mat1layerVolume = gGeoManager->MakeArb8("EcalBLeadCell", Lead, layer1SizeZ/2, layer1Vertices); 
+        
+        Double_t layer2Vertices[16];
+        for (int iv = 0; iv < 8; ++iv) {
+            Double_t interpT = (layer2Zbegin - moduleZbegin)/(moduleZend - moduleZbegin);
+            layer2Vertices[iv] = LinearInterp(cellVertices[iv], cellVertices[iv+8], interpT);
+        }
+        for (int iv = 8; iv < 16; ++iv) {
+            Double_t interpT = (layer2Zend - moduleZbegin)/(moduleZend - moduleZbegin);
+            if (ilayer == currNlayers - 1) interpT = 1.;
+            layer2Vertices[iv] = LinearInterp(cellVertices[iv-8], cellVertices[iv], interpT);
+        }
+        TGeoVolume* mat2layerVolume = gGeoManager->MakeArb8("EcalBScintCell", Scint, layer2SizeZ/2, layer2Vertices); 
+        
+        mat1layerVolume->SetFillColor(kBlue+2);
+        mat1layerVolume->SetLineColor(kBlue+2);
+        mat1layerVolume->SetTransparency(50);
+        
+        mat2layerVolume->SetFillColor(kCyan);
+        mat2layerVolume->SetLineColor(kCyan);
+        mat2layerVolume->SetTransparency(0); 
+
+        Double_t centerLayer = moduleZbegin + layerZSize/2 + ilayer*layerZSize;
+        Double_t centerMat1 = centerLayer - (layer1SizeZ+layer2SizeZ)/2 + layer1SizeZ/2;
+        Double_t centerMat2 = centerLayer + (layer1SizeZ+layer2SizeZ)/2 - layer2SizeZ/2;
+        cellVolume->AddNode(mat1layerVolume, ilayer+1, new TGeoTranslation(0, 0, centerMat1));
+        cellVolume->AddNode(mat2layerVolume, ilayer+1, new TGeoTranslation(0, 0, centerMat2));
+        
+        
+        if (fEnableWritingPointsAll) AddSensitiveVolume(mat1layerVolume);
+        if (fEnableWritingPointsScint) AddSensitiveVolume(mat2layerVolume);
+    }
+    
+    TGeoRotation* rotMirrorY = new TGeoRotation(); rotMirrorY->ReflectY(true);
+    TGeoRotation* rotMirrorX = new TGeoRotation(); rotMirrorX->ReflectX(true);
+    TGeoRotation* rotMirrorXY = new TGeoRotation(); rotMirrorXY->ReflectX(true); rotMirrorXY->ReflectY(true);
+    module->AddNode(cellVolume, 1, rotMirrorXY);
+    module->AddNode(cellVolume, 2, rotMirrorX);
+    module->AddNode(cellVolume, 3, rotMirrorY);
+    module->AddNode(cellVolume, 4, 0);
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdEcalTB2::BuildModule() 
+{    
+    SpdEcalTB2GeoMapper* mapper = dynamic_cast<SpdEcalTB2GeoMapper*>(fGeoMapper);
+    if (!mapper) Fatal("SpdEcalTB2::BuildModule", "no mapper"); 
+    
+    TString baseMedium     = mapper->GetBaseMedium();
+    TString absorberMedium = mapper->GetAbsorberMedium();
+    TString scintMedium    = mapper->GetScintMedium();
+    
+    TGeoMedium* Air   = FindMedium(baseMedium, "");
+    TGeoMedium* Lead  = FindMedium(absorberMedium, baseMedium);
+    TGeoMedium* Scint = FindMedium(scintMedium, baseMedium);
+    
+    Double_t layerInnerSizeTheta = mapper->GetLayerInnerSizeTheta();
+    Double_t layerInnerSizePhi = mapper->GetLayerInnerSizePhi();
+    Double_t layerOuterSizeTheta = mapper->GetLayerOuterSizeTheta();
+    Double_t layerOuterSizePhi = mapper->GetLayerOuterSizePhi();
+    Double_t cellClearance = mapper->GetCellClearance();
+    
+    Int_t    nLayers = mapper->GetNLayers();
+    Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+    Double_t layer2SizeZ = mapper->GetLayer2SizeZ();
+    Double_t layerZSize = layer1SizeZ + layer2SizeZ;
+    Double_t totalZSize = nLayers * layerZSize;
+    
+    //build quarter of module into (+,+) quadrant
+    Double_t cellVertices[16];
+    
+    cellVertices[0] = layerOuterSizeTheta + cellClearance/2;   cellVertices[1] = cellClearance/2;
+    cellVertices[2] = cellClearance/2;                         cellVertices[3] = cellClearance/2;
+    cellVertices[4] = cellClearance/2;                         cellVertices[5] = layerOuterSizePhi + cellClearance/2;
+    cellVertices[6] = layerOuterSizeTheta + cellClearance/2;   cellVertices[7] = layerOuterSizePhi + cellClearance/2;
+    
+    cellVertices[8] =  layerInnerSizeTheta + cellClearance/2;  cellVertices[9]  = cellClearance/2;
+    cellVertices[10] = cellClearance/2;                        cellVertices[11] = cellClearance/2;
+    cellVertices[12] = cellClearance/2;                        cellVertices[13] = layerInnerSizePhi + cellClearance/2;
+    cellVertices[14] = layerInnerSizeTheta + cellClearance/2;  cellVertices[15] = layerInnerSizePhi + cellClearance/2;
+
+    TGeoVolume* cellVolume = gGeoManager->MakeArb8("Cell", Lead, totalZSize/2, cellVertices); 
+
+    // z ->-> from large to small side, X ~ theta, Y ~ phi
+    // dz (3rd argument) - half length in Z;
+    // xy[8][2] (4th argument) - vector of (x,y) coordinates of vertices:
+    // first four points (xy[i][j], i<4,  j<2) are the (x,y) coordinates of the vertices sitting on the -dz plane;
+    // last four points  (xy[i][j], i>=4, j<2) are the (x,y) coordinates of the vertices sitting on the +dz plane;
+    
+    Double_t moduleZbegin = -totalZSize/2;
+    Double_t moduleZend   =  totalZSize/2;
+    
+    for (Int_t ilayer = 0; ilayer < nLayers; ++ilayer) {
+        
+        Double_t layerZbegin = moduleZbegin + ilayer*(layerZSize);
+        Double_t layerZend = layerZbegin + layerZSize;
+        Double_t currZcenter = (layer1SizeZ + layer2SizeZ)*(-float(nLayers)/2 + 0.5 + ilayer);        
+        
+        Double_t layer1Zbegin = layerZbegin;
+        Double_t layer1Zend = layerZbegin + layer1SizeZ;
+        Double_t layer2Zbegin = layerZbegin + layer1SizeZ;
+        Double_t layer2Zend = layerZend;
+        
+        Double_t layer1Vertices[16];
+        for (int iv = 0; iv < 8; ++iv) {
+            Double_t interpT = (layer1Zbegin - moduleZbegin)/(moduleZend - moduleZbegin);
+            if (ilayer == 0) interpT = 0.;
+            layer1Vertices[iv] = LinearInterp(cellVertices[iv], cellVertices[iv+8], interpT);
+        }
+        for (int iv = 8; iv < 16; ++iv) {
+            Double_t interpT = (layer1Zend - moduleZbegin)/(moduleZend - moduleZbegin);
+            layer1Vertices[iv] = LinearInterp(cellVertices[iv-8], cellVertices[iv], interpT);
+        }
+        
+        TGeoVolume* mat1layerVolume = gGeoManager->MakeArb8("EcalBLeadCell", Lead, layer1SizeZ/2, layer1Vertices); 
+            
+        Double_t layer2Vertices[16];
+        for (int iv = 0; iv < 8; ++iv) {
+            Double_t interpT = (layer2Zbegin - moduleZbegin)/(moduleZend - moduleZbegin);
+            layer2Vertices[iv] = LinearInterp(cellVertices[iv], cellVertices[iv+8], interpT);
+        }
+        for (int iv = 8; iv < 16; ++iv) {
+            Double_t interpT = (layer2Zend - moduleZbegin)/(moduleZend - moduleZbegin);
+            if (ilayer == nLayers - 1) interpT = 1.;
+            layer2Vertices[iv] = LinearInterp(cellVertices[iv-8], cellVertices[iv], interpT);
+        }
+        TGeoVolume* mat2layerVolume = gGeoManager->MakeArb8("EcalBScintCell", Scint, layer2SizeZ/2, layer2Vertices); 
+        
+        mat1layerVolume->SetFillColor(kBlue+4);
+        mat1layerVolume->SetLineColor(kBlue+4);
+        mat1layerVolume->SetTransparency(50);
+        
+        mat2layerVolume->SetFillColor(kCyan);
+        mat2layerVolume->SetLineColor(kCyan);
+        mat2layerVolume->SetTransparency(0); 
+        
+        cellVolume->AddNode(mat1layerVolume, ilayer+1, 
+                            new TGeoTranslation(0, 0, currZcenter-(layer1SizeZ+layer2SizeZ)/2 + layer1SizeZ/2));
+        cellVolume->AddNode(mat2layerVolume, ilayer+1, 
+                            new TGeoTranslation(0, 0, currZcenter+(layer1SizeZ+layer2SizeZ)/2 - layer2SizeZ/2));
+        
+        if (fEnableWritingPointsAll)   AddSensitiveVolume(mat1layerVolume);
+        if (fEnableWritingPointsScint) AddSensitiveVolume(mat2layerVolume);
+    }
+    
+    cellVolume->SetFillColor(kAzure+1);
+    cellVolume->SetLineColor(kAzure+1);
+    cellVolume->SetTransparency(50);
+    
+    Double_t moduleVertices[16];
+    
+    moduleVertices[0] =  layerOuterSizeTheta + cellClearance/2;   moduleVertices[1] = -layerOuterSizePhi - cellClearance/2;
+    moduleVertices[2] = -layerOuterSizeTheta - cellClearance/2;   moduleVertices[3] = -layerOuterSizePhi - cellClearance/2;
+    moduleVertices[4] = -layerOuterSizeTheta - cellClearance/2;   moduleVertices[5] =  layerOuterSizePhi + cellClearance/2;
+    moduleVertices[6] =  layerOuterSizeTheta + cellClearance/2;   moduleVertices[7] =  layerOuterSizePhi + cellClearance/2;
+    
+    moduleVertices[8]  =  layerInnerSizeTheta + cellClearance/2;  moduleVertices[9]  = -layerInnerSizePhi - cellClearance/2;
+    moduleVertices[10] = -layerInnerSizeTheta - cellClearance/2;  moduleVertices[11] = -layerInnerSizePhi - cellClearance/2;
+    moduleVertices[12] = -layerInnerSizeTheta - cellClearance/2;  moduleVertices[13] =  layerInnerSizePhi + cellClearance/2;
+    moduleVertices[14] =  layerInnerSizeTheta + cellClearance/2;  moduleVertices[15] =  layerInnerSizePhi + cellClearance/2;
+
+    TGeoVolume* moduleVolume = gGeoManager->MakeArb8("Module", Air, totalZSize/2, moduleVertices); 
+    
+    //maintain convention left-to-right top-to-bottom
+    
+    TGeoRotation* rotMirrorY = new TGeoRotation(); rotMirrorY->ReflectY(true);
+    TGeoRotation* rotMirrorX = new TGeoRotation(); rotMirrorX->ReflectX(true);
+    TGeoRotation* rotMirrorXY = new TGeoRotation(); rotMirrorXY->ReflectX(true); rotMirrorXY->ReflectY(true);
+    moduleVolume->AddNode(cellVolume, 1, rotMirrorX);
+    moduleVolume->AddNode(cellVolume, 2, 0);
+    moduleVolume->AddNode(cellVolume, 3, rotMirrorXY);
+    moduleVolume->AddNode(cellVolume, 4, rotMirrorY);
+    
+    moduleVolume->SetTransparency(50);
+    moduleVolume->SetFillColor(kBlue);
+    moduleVolume->SetLineColor(kBlue);
+    
+    return moduleVolume;
+}
+
+//_____________________________________________________________________________________
+SpdGeoMapper* SpdEcalTB2::GetMapper() 
+{
+  if (fGeoMapper) return fGeoMapper;
+  
+  SpdGeoFactory* factory = SpdGeoFactory::Instance();
+ 
+  // search for mapper
+  fGeoMapper = factory->SearchForMapper("SpdEcalTB2GeoMapper");
+  
+  // create default mapper
+  if (!fGeoMapper) fGeoMapper = factory->Mapper("SpdEcalTB2GeoMapper");
+  
+  return fGeoMapper;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTB2::LoadParsFrom(SpdParSet* params) 
+{
+  if (!params) return kFALSE;
+ 
+  if (!SpdDetector::LoadParsFrom(params)) return kFALSE;
+  
+  TString mapper;
+  params->GetParameter("Mapper",mapper); 
+  fGeoMapper = SpdGeoFactory::Instance()->Mapper(mapper);  
+  if (fGeoMapper) fGeoMapper->LoadParametersFrom(params);
+   
+  fOutDataPointObject = "unknown";
+
+  if (fNDataOut < 1) return kTRUE;
+
+  params->GetParameter("Detector/NOutData_1",fOutDataPointObject);
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+TString SpdEcalTB2::GetDataOut(Int_t n) const 
+{ 
+  if (n < 0 || n >= fNDataOut) return "unknown";
+  return fOutDataPointObject;
+}
+
+//_____________________________________________________________________________________
+TClonesArray* SpdEcalTB2::GetCollection(Int_t iColl) const 
+{ 
+   return (iColl == 0) ? fPointCollection : 0; 
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________
+Int_t SpdEcalTB2::CreateMedium(const char* name) 
+{
+  FairGeoLoader* geoLoad = FairGeoLoader::Instance();
+  if (!geoLoad) return 0;
+  
+  FairGeoInterface* geoFace = geoLoad->getGeoInterface();
+  if (!geoFace) return 0;
+  
+  FairGeoBuilder* geobuild = geoLoad->getGeoBuilder(); 
+  if (!geobuild) return 0;
+      
+  FairGeoMedia* Media = geoFace->getMedia();
+  if (!Media) return 0;
+  
+  return geobuild->createMedium(Media->getMedium(name));
+}
+   
+//_____________________________________________________________________________
+TGeoVolume* SpdEcalTB2::GetModule(Int_t i = 0) const {
+    
+  if (i >= fUniqueModules.size()) {
+      cout << "-W- <SpdEcalTB2::GetModule> : module with id " << i << " not found, returning zero pointer" << endl;
+      return 0;
+  }
+  
+  return fUniqueModules[i]; 
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2::Print(Option_t*) const
+{
+   SpdDetector::Print("");
+   
+   if (!fGeoMapper) return;
+   
+   TString divider('-',150);
+   
+   cout << "\n";
+
+   fGeoMapper->Print("");
+   
+   cout << "\n";
+   cout <<"\tNumber of unique modules:  " << fUniqueModules.size() << endl;
+   cout << "\n";
+   cout <<"\tCapacity (total):    " << GetCapacity()*1e-6 << " [m^3] " << endl;
+   cout <<"\tMass (total):        " << GetMass()*1e-3 << " [kg] " << endl;
+   cout <<"\tDensity (averaged):  " << GetDensity() << " [g/cm^3] " << endl;
+   cout << "\n";
+   
+   cout << "\n";
+}
+
diff --git a/ecalt/barrel/SpdEcalTB2.h b/ecalt/barrel/SpdEcalTB2.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ca6bb7bc8004ab13e795ee1ac721997125adb6b
--- /dev/null
+++ b/ecalt/barrel/SpdEcalTB2.h
@@ -0,0 +1,149 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#ifndef __SPDECALTB2_H__
+#define __SPDECALTB2_H__
+
+#include <TLorentzVector.h>
+#include <TString.h>
+#include "FairDetector.h"
+#include "SpdDetector.h"
+#include "TGeoManager.h"
+#include "TMatrixD.h"
+#include <vector>
+#include <tuple>
+#include <set>
+
+using std::vector;
+using std::set;
+using std::tuple;
+using std::pair;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTB2                                                                 //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdEcalTB2Point;
+class SpdEcalTB2Hits;
+
+class FairVolume;
+class TClonesArray;
+class TGeoMedium;
+class TParticle;
+
+
+class SpdEcalTB2: public SpdDetector { 
+
+public:
+
+    SpdEcalTB2(const char* Name, Bool_t Active);
+    SpdEcalTB2();
+  
+    virtual ~SpdEcalTB2();
+  
+    virtual void  Initialize();
+    virtual void  Reset();
+    virtual void  Register();
+    
+    virtual Bool_t ProcessHits(FairVolume* v = 0);
+    
+    virtual TString GetDataOut(Int_t n) const;
+    virtual TClonesArray* GetCollection(Int_t iColl) const;
+        
+    virtual SpdGeoMapper* GetMapper();
+
+    virtual void ConstructGeometry();
+     
+    virtual void  EndOfEvent();
+    virtual void  FinishRun(); 
+    
+    virtual Bool_t LoadParsFrom(SpdParSet* params);
+    
+    virtual void  Print(Option_t*) const;
+    
+    void EnableWritingPointsScint(Bool_t enable = true) { fEnableWritingPointsScint = enable; }
+    void EnableWritingPointsAll(Bool_t enable = true)   { fEnableWritingPointsScint = enable; 
+                                                          fEnableWritingPointsAll   = enable; }
+        
+    TGeoVolume* GetBasket() const { return fBasket; }
+    TGeoVolume* GetModule(Int_t i) const;
+    Int_t GetNModules() { return fUniqueModules.size(); }
+      
+private:
+       
+    void AddHit();
+  
+    /* Track information to be stored until the track leaves the active volume. */
+    
+    Int_t          fTrackID;           //!  track index
+    Int_t          fDetID;             //!  detector id
+    Int_t          fBasketID;          //!  basket id
+    Int_t          fModuleZID;         //!  module Zid
+    Int_t          fModulePhiID;       //!  module phi id
+    Int_t          fCellID;            //!  cell id
+    Int_t          fLayerID;           //!  layer number
+    TString        fMatID;             //!  material
+    TLorentzVector fPos;               //!  position at entrance
+    TLorentzVector fMom;               //!  momentum at entrance
+    Double32_t     fTime;              //!  time
+    Double32_t     fLength;            //!  length
+    Double32_t     fELoss;             //!  energy loss
+    TString        fNodePath;          //!
+
+    Bool_t fEnableWritingPointsScint;
+    Bool_t fEnableWritingPointsAll;
+    
+    /* containers for data  */
+    
+    TString        fOutDataPointObject; //!
+    TClonesArray*  fPointCollection;    //!
+    
+    SpdEcalTB2(const SpdEcalTB2&);
+    SpdEcalTB2& operator=(const SpdEcalTB2&);
+    
+    /* GEOMETRY */
+    
+    void     ConstructGeometry_1();
+
+    Int_t    CreateMedium(const char* name);
+        
+    TMatrixD GetMatrixToRotateVectorTriplet(TVector3 initialVector1, TVector3 initialVector2, TVector3 initialVector3, 
+                                            TVector3 finalVector1,   TVector3 finalVector2,   TVector3 finalVector3);
+    
+    TMatrixD GetMatrixToEmplaceModule(Double_t ax, Double_t ay, Bool_t rotateClockwise, TGeoVolume* moduleVolume);
+    
+    void     GetEmplacedModulePosition(TGeoVolume* moduleVolume, 
+                                       Double_t ax, Double_t ay, Double_t arhs, 
+                                       Double_t ax2, Double_t ay2, Double_t arhs2, 
+                                       Double_t & xMiddle, Double_t & yMiddle, 
+                                       Double_t & ax_new, Double_t & ay_new, Double_t & arhs_new, 
+                                       Double_t & xPlane2Bottom, Double_t & yPlane2Bottom, 
+                                       Double_t & xPlane2Top, Double_t & yPlane2Top);
+    
+    void FillBasketFixedCells(TGeoVolume* basketVolume, TGeoVolume* moduleVolume);
+    void FillBasketTightly(TGeoVolume* basketVolume);
+    
+    pair <TGeoCombiTrans*, TGeoVolume*> StackModuleInSector(TGeoVolume* basketVolume, 
+                        Double_t angleModuleCenter, Double_t angleModulePeriph, Double_t moduleInnerSizeTheta);
+
+    TGeoVolume* BuildModule();
+    
+    void BuildModule(TGeoVolume* module);
+    void BuildBasket();
+    void BuildBarrel();
+    
+    Double_t LinearInterp(Double_t x1, Double_t x2, Double_t t);
+
+    TGeoVolume* fBasket;                //!
+    TGeoVolume* fModule;                //!
+    vector<TGeoVolume*> fUniqueModules; //!
+    
+    ClassDef(SpdEcalTB2,1)
+};
+
+
+#endif /* __SPDECALTB2_H__ */
diff --git a/ecalt/barrel/SpdEcalTB2Point.cxx b/ecalt/barrel/SpdEcalTB2Point.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..251b83bbbcac117056d50cd84244bda085353d63
--- /dev/null
+++ b/ecalt/barrel/SpdEcalTB2Point.cxx
@@ -0,0 +1,58 @@
+// $Id$
+// Author: andre   2020/07/31
+
+#include "SpdEcalTB2Point.h"
+
+#include <iostream>
+using std::cout;
+using std::endl;
+
+ClassImp(SpdEcalTB2Point)
+
+
+//_____________________________________________________________________________________
+SpdEcalTB2Point::SpdEcalTB2Point():FairMCPoint(),
+fBasketID(0),fModuleZID(0),fModulePhiID(0),fCellID(0),fLayerID(0),
+fMatID(""),fNodePath("")
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdEcalTB2Point::SpdEcalTB2Point(Int_t trackID, Int_t detID, 
+                                 Int_t basketID, Int_t moduleZID, Int_t modulePhiID, Int_t cellID, Int_t layerID,
+                                 TString matID,
+                                 TVector3 pos, TVector3 mom, Double_t tof, 
+                                 Double_t length, Double_t eLoss, TString nodePath)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fBasketID(basketID), fModuleZID(moduleZID), fModulePhiID(modulePhiID), fCellID(cellID), fLayerID(layerID), 
+fMatID(matID), fNodePath(nodePath)
+{
+    
+}
+
+//_____________________________________________________________________________________
+SpdEcalTB2Point::~SpdEcalTB2Point() 
+{ 
+  
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTB2Point::Print(const Option_t* opt) const
+{
+  cout << "<SpdEcalTB2Point::Print> " << endl; 
+  cout << "\n";
+  cout << " Track/DetectorID: " << fTrackID << "/" << fDetectorID << endl;
+  cout << " Basket:           " << fBasketID << endl;
+  cout << " Module Z/П† ID:    " << fModuleZID << "/" << fModulePhiID << endl;
+  cout << " Cell/Layer:       " << fCellID << "/" << fLayerID  << endl;
+  cout << " Material:         " << fMatID << endl;
+  cout << " Node path:        " << fNodePath << endl;
+  cout << " Position, Time:   " << fX << ", " << fY << ", " << fZ << " [cm]  " 
+                                << fTime << " [ns] " << endl;
+  cout << " Momentum:         " << fPx << ", " << fPy << ", " << fPz << " [GeV]" << endl;
+  cout << " Energy loss:      " << fELoss*1.0e06 << " [keV] " << endl;
+  cout << "\n";
+}
+
+
diff --git a/ecalt/barrel/SpdEcalTB2Point.h b/ecalt/barrel/SpdEcalTB2Point.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7f413a5521896ee8b08721fdc7d284fe49c2fb3
--- /dev/null
+++ b/ecalt/barrel/SpdEcalTB2Point.h
@@ -0,0 +1,82 @@
+// $Id$
+// Author: andre   2020/07/31
+
+#ifndef __SPDECALTB2POINT_H__
+#define __SPDECALTB2POINT_H__ 
+
+#include <TVector3.h>
+#include "FairMCPoint.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTB2GeoPoint                                                         //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdEcalTB2Point : public FairMCPoint {
+
+public:
+  
+   /** Constructor with arguments
+   *@param trackID  Index of MCTrack
+   *@param detID    Detector ID
+   *@param cellID    Cell ID 
+   *@param submodID SubModule ID 
+   *@param pos      Coordinates at entrance to active volume [cm]
+   *@param mom      Momentum of track at entrance [GeV]
+   *@param tof      Time since event start [ns]
+   *@param length   Track length since creation [cm]
+   *@param ELoss    Energy deposit [GeV]
+   *@param nodePath Node Path (TString)
+   **/
+  
+  SpdEcalTB2Point();
+  
+  SpdEcalTB2Point(Int_t fTrackID, Int_t fDetID, 
+                  Int_t fBasketID, Int_t fModuleZID, Int_t fModulePhiID, Int_t fCellID, Int_t fLayerID, 
+                  TString fMatID,
+                  TVector3 pos, TVector3 mom, 
+                  Double_t tof, Double_t length, Double_t ELoss, 
+                  TString nodePath);
+
+  SpdEcalTB2Point(const SpdEcalTB2Point& point) { *this = point; };
+
+  virtual ~SpdEcalTB2Point();
+  
+  inline Int_t GetBasketID()        const { return fBasketID;    }
+  inline Int_t GetModuleZID()       const { return fModuleZID;   }
+  inline Int_t GetModulePhiID()     const { return fModulePhiID; }
+  inline Int_t GetCellID()          const { return fCellID;      }
+  inline Int_t GetLayerID()         const { return fLayerID;     }
+  
+  inline TString GetMaterialID()    const { return fMatID; }
+  
+  inline Double_t GetEloss()        const { return fELoss;  } //->FairMCPoint
+  inline Double_t GetTime()         const { return fTime;   } //->FairMCPoint
+  inline Double_t GetLength()       const { return fLength; } //->FairMCPoint
+  
+  TVector3 GetPosition()            const { return TVector3(fPx,fPy,fPz); }
+  TVector3 GetMomentum()            const { return TVector3(fX,fY,fZ); }
+  
+  TString  GetNodePath()            const { return fNodePath; }
+
+  virtual void Print(const Option_t* opt) const;
+  
+private:
+
+  Int_t   fBasketID; 
+  Int_t   fModuleZID; 
+  Int_t   fModulePhiID; 
+  Int_t   fCellID;
+  Int_t   fLayerID;
+  
+  TString fMatID;
+  
+  TString fNodePath;
+
+  ClassDef(SpdEcalTB2Point,1)
+};
+
+#endif /* __SPDECALTB2POINT_H__ */
diff --git a/ecalt/ecps/SpdEcalTEC.cxx b/ecalt/ecps/SpdEcalTEC.cxx
index f9119227222f3a1d92fd5c54bacfcfac5a54c905..ce9cad9fbbaf2260ad5b95051f295ad69b73f1bb 100644
--- a/ecalt/ecps/SpdEcalTEC.cxx
+++ b/ecalt/ecps/SpdEcalTEC.cxx
@@ -40,7 +40,7 @@ ClassImp(SpdEcalTEC)
 //_____________________________________________________________________________________
 SpdEcalTEC::SpdEcalTEC(): 
 
-  SpdDetector("Ecal endcaps (tor)", kSpdEcalTEC, kTRUE),
+  SpdDetector("Ecal endcaps (qsl)", kSpdEcalTEC, kTRUE),
   fTrackID(-1),
   fVolumeID1(-1),fVolumeID2(-1),fVolumeID3(-1),
   fPos(),
diff --git a/ecalt/ecps/SpdEcalTEC2.cxx b/ecalt/ecps/SpdEcalTEC2.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..55ecbed765625bbc048e3129ede9f094a5bf9c56
--- /dev/null
+++ b/ecalt/ecps/SpdEcalTEC2.cxx
@@ -0,0 +1,552 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#include "SpdEcalTEC2.h"
+
+#include "FairVolume.h"
+#include "FairGeoVolume.h"
+#include "FairGeoNode.h"
+#include "FairRootManager.h"
+#include "FairGeoLoader.h"
+#include "FairGeoInterface.h"
+#include "FairGeoLoader.h"
+#include "FairGeoBuilder.h"
+#include "FairGeoMedia.h"
+#include "FairRun.h"
+#include "FairRunSim.h"
+#include "FairRuntimeDb.h"
+
+#include "TRefArray.h"    
+#include "TClonesArray.h"
+#include "TParticle.h"
+#include "TVirtualMC.h"
+#include "TGeoManager.h"
+#include "TGeoBBox.h"
+#include "TGeoPgon.h"
+#include "TGeoCompositeShape.h"
+#include "TGeoTube.h"
+#include "TGeoMaterial.h"
+#include "TGeoMedium.h"
+#include "TMatrixD.h"
+
+#include "SpdEcalTEC2.h"
+#include "SpdEcalTEC2Point.h"
+#include "SpdEcalTEC2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+#include "SpdDetectorList.h"
+#include "SpdStack.h"
+#include "SpdParSet.h"
+#include "SpdGeoFactory.h"
+
+#include <map>
+#include <iostream>
+#include <vector>
+
+using namespace std;
+
+using std::cout;
+using std::endl;
+
+ClassImp(SpdEcalTEC2)
+
+//_____________________________________________________________________________________
+SpdEcalTEC2::SpdEcalTEC2(): 
+
+  SpdDetector("Ecal endcaps (tor)", kSpdEcalTEC, kTRUE),
+  fTrackID(-1),
+  fDetID(-1),fEndcapID(-1),fModuleID(-1), fCellID(-1), fLayerID(-1), fMatID(""),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fEnableWritingPointsScint(kTRUE),
+  fEnableWritingPointsAll(kFALSE),
+  fPointCollection(0),
+  fEndcap(0),
+  fModule(0),
+  fCell(0)
+{
+    SetParametersType("EcalTECParSet");
+   
+    fNDataOut = 1;
+    fOutDataPointObject = "SpdEcalTEC2Point"; 
+}
+
+//_____________________________________________________________________________________
+SpdEcalTEC2::SpdEcalTEC2(const char* name, Bool_t active):
+
+  SpdDetector(name, kSpdEcalTEC, active),
+  fTrackID(-1),
+  fDetID(-1),fEndcapID(-1),fModuleID(-1), fCellID(-1), fLayerID(-1), fMatID(""),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fEnableWritingPointsScint(kTRUE),
+  fEnableWritingPointsAll(kFALSE),
+  fPointCollection(0),
+  fEndcap(0),
+  fModule(0),
+  fCell(0)
+{
+    SetParametersType("EcalTECParSet");
+   
+    fNDataOut = 1;
+    fOutDataPointObject = "SpdEcalTEC2Point"; 
+}
+
+//_____________________________________________________________________________________
+SpdEcalTEC2::~SpdEcalTEC2()
+{
+  if (fPointCollection) {
+      fPointCollection->Delete();
+      delete fPointCollection;
+      fPointCollection = 0;
+  }
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::Initialize()
+{
+  cout << "\n*******************************************************************************" << endl;
+  cout << "************************* SpdEcalTEC2::Initialize *****************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+  
+  // data collections
+  fPointCollection = new TClonesArray(fOutDataPointObject);
+  
+  // Initialize module and fill parameters
+  SpdDetector::Initialize(); 
+ 
+  // SpdParSet* pars = GetParameters();
+  // if (pars) pars->printParams();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::Reset()
+{
+  fPointCollection->Clear();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::Register()
+{
+  if (!fGeoMapper) return;
+  
+  if (!fEnableWritingPointsScint) return;
+  
+  FairRootManager::Instance()->Register(fOutDataPointObject,"SpdEcalTEC2", 
+                                        fPointCollection, kTRUE);
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdEcalTEC2::ProcessHits(FairVolume* vol)
+{
+  //cout << "<SpdEcalTEC2::ProcessHits> " << endl;
+  
+  //Set parameters at entrance of volume. Reset ELoss.
+  if (gMC->IsTrackEntering()) {
+      //cout << "track entering\n";
+      fELoss  = 0.;
+      fTime   = gMC->TrackTime() * 1.e9;  // ns -> s
+      fLength = gMC->TrackLength();
+      gMC->TrackPosition(fPos);
+      gMC->TrackMomentum(fMom);
+  }
+
+  // Sum energy loss for all steps in the active volume
+  fELoss += gMC->Edep();
+
+  // Create SpdEcalTEC2Point at exit of active volume
+  if ( gMC->IsTrackExiting()    ||
+       gMC->IsTrackStop()       ||
+       gMC->IsTrackDisappeared()   ) 
+  {
+    
+    if (!fSaveEmptyHits && fELoss == 0.) { return kFALSE; }
+    
+    fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
+    
+    fNodePath = gMC->CurrentVolPath();
+    SpdGeopathParser parser;
+    parser.ParsePath(fNodePath);
+    
+    //cave: 1, endcap: 2, module:3, cell:4, layer:5, lead/scint:6
+    fDetID =  kSpdEcalTEC;
+    fEndcapID = parser.Num(2, true)*2 - 3; //-1: negative Z, +1: positive Z
+    fModuleID = parser.Num(3, true);
+    fCellID = parser.Num(4, true);
+    fLayerID = parser.Num(5, true);
+    fMatID = parser.Name(6, true);
+    
+    //cout << " <<< ENDCAP >>> " << fMatID << " " << gMC->CurrentVolPath() << endl;
+    
+    assert(fMatID == "EcalECLeadCell" || fMatID == "EcalECScintCell");
+    
+    if (fEnableWritingPointsAll) AddHit();
+    else if (fEnableWritingPointsScint && fMatID == "EcalECScintCell") AddHit();
+   
+    SpdStack* stack = (SpdStack*)gMC->GetStack();
+    stack->AddPoint(kSpdEcalTEC);
+  } 
+   
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::AddHit() 
+{
+  static Bool_t addhit = (fOutDataPointObject == "SpdEcalTEC2Point") ? kTRUE : kFALSE;
+  
+  if (!addhit) return;
+  
+  TClonesArray& clref = *fPointCollection;
+  Int_t size = clref.GetEntriesFast();
+  
+  //cout << "SpdEcalTEC2::AddHit: Adding hit: " << fTrackID << " " << fDetID << " " << fEndcapID << " " << fVolumeID3 << " " << 
+  //                                 fPos.X() << " " << fPos.Y() << " " << fPos.Z() << " " << 
+  //                                 fMom.Px() << " " << fMom.Py() << " " << fMom.Pz() << " " << 
+  //                                 fTime << " " << fLength << " " << fELoss << " path = " << fNodePath <<"\n";
+  
+  new(clref[size]) SpdEcalTEC2Point(fTrackID,fDetID,fEndcapID,fModuleID, fCellID, fLayerID, fMatID,
+                                   TVector3(fPos.X(),fPos.Y(),fPos.Z()),
+                                   TVector3(fMom.Px(),fMom.Py(),fMom.Pz()),
+                                   fTime, fLength, fELoss, fNodePath);                                 
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::EndOfEvent()
+{
+  Reset();
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::FinishRun() 
+{
+   //SpdDetector::FinishRun();
+   FillNodesTableIn(GetParameters());
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::ConstructGeometry()
+{   
+   fMasterVolume = SpdCommonGeoMapper::Instance()->GetMasterVolume();
+
+   if (!fMasterVolume) {  
+       cout << "-E- <SpdIts::ConstructGeometry> No MASTER volume " << endl;
+       return;
+   }
+   
+   if (!GetMapper()) return;
+   
+   if (!fGeoMapper->InitGeometry()) return;
+
+   //fGeoMapper->Print("");
+   
+   Int_t geo_type = fGeoMapper->GetGeoType();
+   
+   BuildGeometry();
+   
+   fGeoMapper->LockGeometry(); 
+   
+   cout << "\n*******************************************************************************" << endl;
+   cout << "********************** SpdEcalTEC2::ConstructGeometry *************************" << endl;
+   cout << "********************** GEOMETRY TYPE: " << geo_type 
+        << " ***************************************" << endl;
+   cout << "*******************************************************************************\n" << endl;
+}
+
+//________________________________________________________________________________
+void SpdEcalTEC2::BuildGeometry()
+{ 
+   BuildEndcap();
+   
+   SpdEcalTEC2GeoMapper* mapper = dynamic_cast<SpdEcalTEC2GeoMapper*>(fGeoMapper);
+   if (!mapper) return;
+  
+   Double_t zshift = mapper->GetEndcapMinDist() + 0.5*mapper->GetEndcapThickness();
+   
+   fMasterVolume->AddNode(fEndcap, 1, new TGeoTranslation(0, 0,-zshift));
+   fMasterVolume->AddNode(fEndcap, 2, new TGeoTranslation(0, 0, zshift));
+}
+
+//________________________________________________________________________________
+void SpdEcalTEC2::BuildEndcap()
+{
+   BuildModule();
+   
+   SpdEcalTEC2GeoMapper* mapper = dynamic_cast<SpdEcalTEC2GeoMapper*>(fGeoMapper);
+   if (!mapper) return;
+   
+   Double_t endcapThickness = mapper->GetEndcapThickness();
+   Double_t endCapHoleRadius = mapper->GetEndcapSize() - mapper->GetEndcapWidth();
+   Double_t layerEndcapSize = mapper->GetCellSize();
+   Double_t cellClearance = mapper->GetCellClearance();
+   Double_t moduleClearance = mapper->GetModuleClearance();
+   Double_t endcapSize = mapper->GetEndcapSize();
+   TString baseMedium = mapper->GetBaseMedium();
+   
+   TGeoMedium* Air = FindMedium(baseMedium, "");
+   
+   fEndcap = gGeoManager->MakePgon("Endcap", Air, 22.5, 360, 8, 2);
+   
+   TGeoPgon* pgonOuter = (TGeoPgon*)(fEndcap->GetShape());
+   pgonOuter->DefineSection(0, -endcapThickness/2, endCapHoleRadius, endcapSize);
+   pgonOuter->DefineSection(1,  endcapThickness/2, endCapHoleRadius, endcapSize);
+   
+   Double_t cellSize = 2*layerEndcapSize + cellClearance;
+   Double_t nCellsXY = 1;
+   Double_t totalXFilled = cellSize;
+   
+   while (totalXFilled < 2*endcapSize) {
+      totalXFilled += cellSize + moduleClearance;
+      nCellsXY += 1;
+   }
+   
+   nCellsXY -= 1;
+   totalXFilled -= (cellSize + moduleClearance);
+   
+   if (nCellsXY >= 1000) {
+       cout << "-E- <SpdEcalTEC2::ConstructGeometry_1> "
+            << "Number of modules >= 1000. Decrease cell size or remake the module naming scheme." << endl;
+       exit(1);
+   }
+   
+   Double_t gridLeftX   = -totalXFilled/2;
+   Double_t gridBottomY = -totalXFilled/2;
+   
+   TGeoTranslation* currentModuleTrans;
+   
+   Double_t corner[3] = {0,0,0};
+   
+   for (Int_t ix = 0; ix < nCellsXY; ++ix) {
+        for (Int_t iy = 0; iy < nCellsXY; ++iy) {
+        
+             corner[0] = gridLeftX   + ix*(cellSize + moduleClearance);
+             corner[1] = gridBottomY + iy*(cellSize + moduleClearance);
+         
+             if (!fEndcap->Contains(corner)) continue; 
+             corner[1] += cellSize;
+             if (!fEndcap->Contains(corner)) continue; 
+             corner[0] += cellSize;
+             if (!fEndcap->Contains(corner)) continue; 
+             corner[1] -= cellSize;
+             if (!fEndcap->Contains(corner)) continue; 
+             corner[0] -= cellSize;
+              
+             currentModuleTrans = new TGeoTranslation(corner[0] + cellSize/2, corner[1] + cellSize/2, corner[2]); 
+                       
+             fEndcap->AddNode(fModule, (iy+1)*1000 + ix+1, currentModuleTrans);
+       }
+   }
+   
+   fEndcap->SetLineColor(kBlue);
+   fEndcap->SetFillColor(kBlue);
+   fEndcap->SetTransparency(50);
+}
+
+//________________________________________________________________________________
+void SpdEcalTEC2::BuildModule() 
+{
+   BuildCell();
+   
+   SpdEcalTEC2GeoMapper* mapper = dynamic_cast<SpdEcalTEC2GeoMapper*>(fGeoMapper);
+   if (!mapper) return; 
+   
+   TString baseMedium = mapper->GetBaseMedium();
+   TGeoMedium* Air = FindMedium(baseMedium, "");
+ 
+   Double_t halfsizeModule = mapper->GetCellSize() + 0.5*mapper->GetCellClearance();
+   Double_t shift = 0.5*mapper->GetCellSize() + 0.5*mapper->GetCellClearance();
+      
+   fModule = gGeoManager->MakeBox("Module", Air, halfsizeModule, halfsizeModule, 0.5*mapper->GetEndcapThickness()); 
+          
+   fModule->AddNode(fCell, 1, new TGeoTranslation(-shift,  shift, 0));
+   fModule->AddNode(fCell, 2, new TGeoTranslation( shift,  shift, 0));
+   fModule->AddNode(fCell, 3, new TGeoTranslation(-shift, -shift, 0));
+   fModule->AddNode(fCell, 4, new TGeoTranslation( shift, -shift, 0));
+    
+   fModule->SetFillColor(kBlue);
+   fModule->SetLineColor(kBlue);
+   fModule->SetTransparency(50);
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2::BuildCell()
+{
+   SpdEcalTEC2GeoMapper* mapper = dynamic_cast<SpdEcalTEC2GeoMapper*>(fGeoMapper);
+   if (!mapper) return; 
+
+   TString baseMedium = mapper->GetBaseMedium();
+   TString absorberMedium = mapper->GetAbsorberMedium();
+   TString scintMedium = mapper->GetScintMedium();
+   Double_t layerEndcapSize = mapper->GetCellSize();
+   Double_t endcapThickness = mapper->GetEndcapThickness();
+   Double_t layer1SizeZ = mapper->GetLayer1SizeZ();
+   Double_t layer2SizeZ = mapper->GetLayer2SizeZ();
+   TGeoMedium* Air   = FindMedium(baseMedium, "");
+   TGeoMedium* Lead  = FindMedium(absorberMedium, baseMedium);
+   TGeoMedium* Scint = FindMedium(scintMedium, baseMedium);
+    
+   // construct active volumes
+   TGeoVolume* mat1layer = gGeoManager->MakeBox("EcalECLeadCell",   Lead, 
+                                                layerEndcapSize/2, layerEndcapSize/2, layer1SizeZ/2); 
+   TGeoVolume* mat2layer = gGeoManager->MakeBox("EcalECScintCell", Scint, 
+                                                layerEndcapSize/2, layerEndcapSize/2, layer2SizeZ/2); 
+   
+   if (fEnableWritingPointsScint) AddSensitiveVolume(mat2layer);  // ATTENTION
+   if (fEnableWritingPointsAll)   AddSensitiveVolume(mat1layer);  // ATTENTION
+   
+   // construct layer
+   TGeoVolume* layer = gGeoManager->MakeBox("Layer", Air, layerEndcapSize/2, layerEndcapSize/2, (layer1SizeZ+layer2SizeZ)/2); 
+   
+   layer->AddNode(mat1layer, 1, new TGeoTranslation(0, 0, -(layer1SizeZ+layer2SizeZ)/2 + layer1SizeZ/2));
+   layer->AddNode(mat2layer, 1, new TGeoTranslation(0, 0,  (layer1SizeZ+layer2SizeZ)/2 - layer2SizeZ/2));
+
+   // construct cell
+   fCell = gGeoManager->MakeBox("Cell", Lead, layerEndcapSize/2, layerEndcapSize/2, endcapThickness/2); 
+   
+   Int_t nLayers = floor(endcapThickness/(layer1SizeZ + layer2SizeZ));
+   Double_t currZcenter;
+
+   for (Int_t ilayer = 0; ilayer < nLayers; ++ilayer) {
+        currZcenter = (layer1SizeZ + layer2SizeZ) * (-nLayers/2. + 0.5 + ilayer);
+        fCell->AddNode(layer, ilayer+1, new TGeoTranslation(0, 0, currZcenter));
+   }
+      
+   layer->SetFillColor(kAzure+1); 
+   layer->SetLineColor(kAzure+1); 
+   layer->SetTransparency(50);
+   
+   mat1layer->SetFillColor(kBlue+4);
+   mat1layer->SetLineColor(kBlue+4);
+   mat1layer->SetTransparency(50);
+   
+   mat2layer->SetFillColor(kCyan);
+   mat2layer->SetLineColor(kCyan);
+   mat2layer->SetTransparency(50);
+   
+   fCell->SetFillColor(kAzure+1);
+   fCell->SetLineColor(kAzure+1);
+   fCell->SetTransparency(50);
+}
+ 
+//_____________________________________________________________________________________
+SpdGeoMapper* SpdEcalTEC2::GetMapper() 
+{
+   if (fGeoMapper) return fGeoMapper;
+   
+   SpdGeoFactory* factory = SpdGeoFactory::Instance();
+ 
+   // search for mapper
+   fGeoMapper = factory->SearchForMapper("SpdEcalTEC2GeoMapper");
+   
+   // create default mapper
+   if (!fGeoMapper) fGeoMapper = factory->Mapper("SpdEcalTEC2GeoMapper");
+    
+   return fGeoMapper;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTEC2::LoadParsFrom(SpdParSet* params) 
+{
+   if (!params) return kFALSE;
+ 
+   if (!SpdDetector::LoadParsFrom(params)) return kFALSE;
+   
+   TString mapper;
+   params->GetParameter("Mapper",mapper); 
+   fGeoMapper = SpdGeoFactory::Instance()->Mapper(mapper);  
+   if (fGeoMapper) fGeoMapper->LoadParametersFrom(params);
+    
+   fOutDataPointObject = "unknown";
+
+   if (fNDataOut < 1) return kTRUE;
+
+   params->GetParameter("Detector/NOutData_1",fOutDataPointObject);
+   
+   return kTRUE;
+}
+
+//_____________________________________________________________________________________
+TString SpdEcalTEC2::GetDataOut(Int_t n) const 
+{ 
+   if (n < 0 || n >= fNDataOut) return "unknown";
+   return fOutDataPointObject;
+}
+
+//_____________________________________________________________________________________
+TClonesArray* SpdEcalTEC2::GetCollection(Int_t iColl) const 
+{ 
+   return (iColl == 0) ? fPointCollection : 0; 
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+Double_t SpdEcalTEC2::GetCapacity() const 
+{ 
+   // return (fEndcap) ? fEndcap->GetShape()->Capacity() : 0;
+   return 0;
+}
+   
+//_____________________________________________________________________________________
+Double_t SpdEcalTEC2::GetMass() const 
+{ 
+   return (fEndcap) ? GetCapacity()*GetDensity() : 0;
+}
+
+//_____________________________________________________________________________________
+Double_t SpdEcalTEC2::GetDensity() const 
+{   
+   return (fEndcap) ? fEndcap->GetMaterial()->GetDensity() : 0; 
+} 
+
+//_____________________________________________________________________________
+void SpdEcalTEC2::Print(Option_t*) const
+{
+   SpdDetector::Print("");
+   
+   if (!fGeoMapper) return;
+   
+   TString divider('-',150);
+   
+   cout << "\n";
+
+   fGeoMapper->Print("");
+
+   cout << "\n";
+   cout <<"\tCapacity (total):    " << GetCapacity()*1e-6 << " [m^3] " << endl;
+   cout <<"\tMass (total):        " << GetMass()*1e-3 << " [kg] " << endl;
+   cout <<"\tDensity (averaged):  " << GetDensity() << " [g/cm^3] " << endl;
+   cout << "\n";
+   
+   cout << "\n" << divider.Data() << "\n";       
+   printf("%6s %4s %15s %14s %14s %14s \n\n","Type","N","Material","Dens [g/cm^3]","Volume [m^3]","Mass [kg]");       
+   
+   if (!fEndcap) {        
+       cout << "\n";        
+       return;    
+   }
+
+   printf("%6d %4d %15s %14.6f %14.6f %14.6f \n",            
+           1, 1, fEndcap->GetMaterial()->GetName(),            
+           GetDensity(), GetCapacity()*1e-6, GetMass()*1e-3);     
+   printf("%6d %4d %15s %14.6f %14.6f %14.6f \n",            
+           1, 2, fEndcap->GetMaterial()->GetName(),            
+           GetDensity(), GetCapacity()*1e-6, GetMass()*1e-3);     
+   
+   cout << divider.Data() << "\n";       
+   
+   printf("%6s %35s %14.3e %14.3e \n","TOTAL:","",2*GetCapacity()*1e-6,2*GetMass()*1e-3);        
+   
+   cout << divider.Data() << "\n";       
+   
+   cout << "\n";
+   
+}
+
diff --git a/ecalt/ecps/SpdEcalTEC2.h b/ecalt/ecps/SpdEcalTEC2.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6a20deab23b6fc78689f22fc8248b8bf54fc85e
--- /dev/null
+++ b/ecalt/ecps/SpdEcalTEC2.h
@@ -0,0 +1,120 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#ifndef __SPDECALTEC2_H__
+#define __SPDECALTEC2_H__
+
+#include <TLorentzVector.h>
+#include <TString.h>
+#include "FairDetector.h"
+#include "SpdDetector.h"
+#include "TGeoManager.h"
+#include "TMatrixD.h"
+#include <vector>
+
+using std::vector;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTEC2                                                                //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdEcalTEC2Point;
+class SpdEcalTEC2Hits;
+
+class FairVolume;
+class TClonesArray;
+class TGeoMedium;
+class TParticle;
+
+class SpdEcalTEC2: public SpdDetector { 
+
+public:
+
+    SpdEcalTEC2(const char* Name, Bool_t Active);
+    SpdEcalTEC2();
+  
+    virtual ~SpdEcalTEC2();
+  
+    virtual void  Initialize();
+    virtual void  Reset();
+    virtual void  Register();
+    
+    virtual Bool_t ProcessHits(FairVolume* v = 0);
+    
+    virtual TString GetDataOut(Int_t n) const;
+    virtual TClonesArray* GetCollection(Int_t iColl) const;
+    
+    virtual Double_t GetCapacity() const;  // cm^3
+    virtual Double_t GetMass()     const;  // g
+    virtual Double_t GetDensity()  const;  // g/cm^3
+     
+    virtual SpdGeoMapper* GetMapper();
+
+    virtual void  ConstructGeometry();
+     
+    virtual void  EndOfEvent();
+    virtual void  FinishRun(); 
+    
+    virtual Bool_t LoadParsFrom(SpdParSet* params);
+    
+    virtual void  Print(Option_t*) const;
+    
+    void EnableWritingPointsScint(Bool_t enable = true) { fEnableWritingPointsScint = enable; }
+    void EnableWritingPointsAll(Bool_t enable = true)   { fEnableWritingPointsScint = enable; 
+                                                          fEnableWritingPointsAll   = enable; }
+    
+    TGeoVolume* GetEndcap() const { return fEndcap; } 
+    TGeoVolume* GetModule() const { return fModule; }
+    TGeoVolume* GetCell()   const { return fCell;   }
+    
+private:
+       
+    void AddHit();
+  
+    /* Track information to be stored until the track leaves the active volume. */
+    
+    Int_t          fTrackID;           //!  track index
+    Int_t          fDetID;             //!  detector ID
+    Int_t          fEndcapID;          //!  endcap ID (+1 for +Z, -1 for -Z)
+    Int_t          fModuleID;          //!  module ID
+    Int_t          fCellID;            //!  cell ID
+    Int_t          fLayerID;           //!  layer ID
+    TString        fMatID;             //!  material name ("LEAD" etc. - if writing points in absorber is enabled or "SCINT" etc.)
+    TLorentzVector fPos;               //!  position at entrance
+    TLorentzVector fMom;               //!  momentum at entrance
+    Double32_t     fTime;              //!  time
+    Double32_t     fLength;            //!  length
+    Double32_t     fELoss;             //!  energy loss
+    TString        fNodePath;          //!
+
+    Bool_t  fEnableWritingPointsScint;
+    Bool_t  fEnableWritingPointsAll;
+    
+    /* containers for data  */
+    
+    TString        fOutDataPointObject; //!
+    TClonesArray*  fPointCollection;    //!
+    
+    SpdEcalTEC2(const SpdEcalTEC2&);
+    SpdEcalTEC2& operator=(const SpdEcalTEC2&);
+    
+    /* GEOMETRY */
+    
+    void BuildGeometry();
+    
+    void BuildEndcap();
+    void BuildModule();
+    void BuildCell();
+
+    TGeoVolume* fEndcap;  //!
+    TGeoVolume* fModule;  //!
+    TGeoVolume* fCell;    //!
+
+    ClassDef(SpdEcalTEC2,1)
+};
+
+#endif /* __SPDECALTEC2_H__ */
diff --git a/ecalt/ecps/SpdEcalTEC2Point.cxx b/ecalt/ecps/SpdEcalTEC2Point.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9ed66a0077a6db6607e62a046a83a07354b2cbae
--- /dev/null
+++ b/ecalt/ecps/SpdEcalTEC2Point.cxx
@@ -0,0 +1,53 @@
+// $Id$
+// Author: andre   2020/07/31
+
+#include "SpdEcalTEC2Point.h"
+
+#include <iostream>
+using std::cout;
+using std::endl;
+
+ClassImp(SpdEcalTEC2Point)
+
+//_____________________________________________________________________________________
+SpdEcalTEC2Point::SpdEcalTEC2Point():FairMCPoint(),
+fEndcapID(0),fModuleID(0),fCellID(0),fLayerID(0),fMatID(""),fNodePath("")
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdEcalTEC2Point::SpdEcalTEC2Point(Int_t trackID, Int_t detID, Int_t endcapID, Int_t moduleID, Int_t cellID, Int_t layerID, 
+                                   TString matID,
+                                   TVector3 pos, TVector3 mom, Double_t tof, Double_t length, Double_t eLoss, 
+                                   TString nodePath)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fEndcapID(endcapID),fModuleID(moduleID),fCellID(cellID),fLayerID(layerID),
+fMatID(matID),fNodePath(nodePath)
+{
+
+}
+
+//_____________________________________________________________________________________
+SpdEcalTEC2Point::~SpdEcalTEC2Point() 
+{ 
+  
+}
+
+//_____________________________________________________________________________________
+void SpdEcalTEC2Point::Print(const Option_t* opt) const
+{
+  cout << "<SpdEcalTEC2Point::Print> " << endl; 
+  cout << "\n";
+  cout << " EventID:                  " << fEventId << endl;
+  cout << " Track/DetectorID:         " << fTrackID  << "/" << fDetectorID << endl;
+  cout << " Endcap/Module:            " << fEndcapID << "/" << fModuleID << endl;
+  cout << " Cell/Layer:               " << fCellID  << "/" << fLayerID  << endl;
+  cout << " Material:                 " << fMatID << endl;
+  cout << " Node path:                " << fNodePath << endl;
+  cout << " Position, Time:           " << fX << ", " << fY << ", " << fZ << " [cm]  " << fTime << " [ns] " << endl;
+  cout << " Momentum:                 " << fPx << ", " << fPy << ", " << fPz << " [GeV]" << endl;
+  cout << " Energy loss:              " << fELoss*1.0e06 << " [keV] " << endl;
+  cout << "\n";
+}
+
diff --git a/ecalt/ecps/SpdEcalTEC2Point.h b/ecalt/ecps/SpdEcalTEC2Point.h
new file mode 100644
index 0000000000000000000000000000000000000000..d4de049d223235e98bcdb33211d6cfad4a532af8
--- /dev/null
+++ b/ecalt/ecps/SpdEcalTEC2Point.h
@@ -0,0 +1,84 @@
+// $Id$
+// Author: andre   2020/07/31
+
+#ifndef __SpdEcalTEC2ECPOINT_H__
+#define __SpdEcalTEC2ECPOINT_H__ 
+
+#include <TVector3.h>
+#include "FairMCPoint.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTEC2GeoPoint                                                        //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdEcalTEC2Point : public FairMCPoint {
+
+public:
+  
+   /** Constructor with arguments
+   *@param trackID  Index of MCTrack
+   *@param detID    Detector ID
+   *@param endcapID Endcap ID
+   *@param moduleID Module ID 
+   *@param cellID   Cell ID
+   *@param layerID  Layer ID
+   *@param matID    Node material 
+   *@param pos      Coordinates at entrance to active volume [cm]
+   *@param mom      Momentum of track at entrance [GeV]
+   *@param tof      Time since event start [ns]
+   *@param length   Track length since creation [cm]
+   *@param ELoss    Energy deposit [GeV]
+   *@param nodePath Full node geopath 
+   **/
+  
+  SpdEcalTEC2Point();
+  
+  SpdEcalTEC2Point(Int_t trackID, Int_t detID, Int_t endcapID, Int_t moduleID, Int_t cellID, Int_t layerID, 
+                   TString matID,
+                   TVector3 pos, TVector3 mom, Double_t tof, Double_t length, Double_t ELoss, 
+                   TString nodePath);
+
+  SpdEcalTEC2Point(const SpdEcalTEC2Point& point) { *this = point; };
+
+  virtual ~SpdEcalTEC2Point();
+ 
+  // Int_t FairMCPoint::GetDetectorID() const;
+  // Int_t FairMCPoint::GetTrackID() const;
+  
+  inline Int_t    GetEndcapID()     const { return fEndcapID;   }
+  inline Int_t    GetModuleID()     const { return fModuleID;   }
+  inline Int_t    GetCellID()       const { return fCellID;     }
+  inline Int_t    GetLayerID()      const { return fLayerID;    }
+  
+  inline TString  GetMaterialID()   const { return fMatID;    }
+  
+  inline Double_t GetEloss()        const { return fELoss;    } //->FairMCPoint
+  inline Double_t GetTime()         const { return fTime;     } //->FairMCPoint
+  inline Double_t GetLength()       const { return fLength;   } //->FairMCPoint
+  
+  TVector3 GetPosition() const { return TVector3(fPx,fPy,fPz); }
+  TVector3 GetMomentum() const { return TVector3(fX,fY,fZ);    }
+  
+  TString  GetNodePath() const { return fNodePath; }
+
+  virtual void Print(const Option_t* opt) const;
+  
+private:
+    
+  Int_t      fEndcapID; 
+  Int_t      fModuleID; 
+  Int_t      fCellID;
+  Int_t      fLayerID;
+  
+  TString    fMatID;
+  TString    fNodePath;
+  
+  ClassDef(SpdEcalTEC2Point,1)
+
+};
+
+#endif /* __SpdEcalTEC2ECPOINT_H__ */
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 8c1318ed9fedccf5984c15bbcf36adc3693bbc5c..b6ac6f4e290e283de13bba90360213f91cc81100 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -7,3 +7,5 @@ ELSE()
     SET(GENFIT2_IS_DEFINED true CACHE BOOL "GENFIT2_IS_DEFINED" FORCE)
 ENDIF()
 
+add_subdirectory (KFParticle)
+
diff --git a/external/GenFit2/core/src/MeasuredStateOnPlane.cc b/external/GenFit2/core/src/MeasuredStateOnPlane.cc
index 794b5bd5aef7634864096440bd39750b9011963d..a5fa0dca10e88d748bd6318650a20e1025637abb 100644
--- a/external/GenFit2/core/src/MeasuredStateOnPlane.cc
+++ b/external/GenFit2/core/src/MeasuredStateOnPlane.cc
@@ -142,11 +142,17 @@ MeasuredStateOnPlane calcAverageState(const MeasuredStateOnPlane& forwardState,
   // averaging.
   TDecompChol d1(forwardState.getCov());
   bool success = d1.Decompose();
+  //printf("success (1): %d \n",success);
   TDecompChol d2(backwardState.getCov());
   success &= d2.Decompose();
+  //printf("success (2): %d \n",success);
 
   if (!success) {
     Exception e("KalmanFitterInfo::calcAverageState: ill-conditioned covariance matrix.", __LINE__,__FILE__);
+    //std::cout << "--------------------" << std::endl;
+    //backwardState.Print();
+    //std::cout << "--------------------" << std::endl;
+    //d2.Print();
     throw e;
   }
 
diff --git a/external/KFParticle/CMakeLists.txt b/external/KFParticle/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..327d4c59a80543733e7270b8a6b1d30173d06998
--- /dev/null
+++ b/external/KFParticle/CMakeLists.txt
@@ -0,0 +1,56 @@
+
+# 
+# Create a library called "KFParticle" 
+# 
+
+set(INCLUDE_DIRECTORIES
+${SYSTEM_INCLUDE_DIRECTORIES}
+${BASE_INCLUDE_DIRECTORIES}
+${ROOT_INCLUDE_DIR} 
+${CMAKE_SOURCE_DIR}/external/KFParticle
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticle
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticlePerformance
+)
+
+include_directories( ${INCLUDE_DIRECTORIES})
+
+set(LINK_DIRECTORIES
+${ROOT_LIBRARY_DIR}
+${FAIRROOT_LIBRARY_DIR}
+)
+ 
+link_directories( ${LINK_DIRECTORIES})
+
+set (SRCS
+  KFParticle/KFParticleTopoReconstructor.cxx
+  KFParticle/KFVertex.cxx
+  KFParticle/KFPTrack.cxx
+  KFParticle/KFPTrackVector.cxx
+  KFParticle/KFPVertex.cxx
+  KFParticle/KFParticlePVReconstructor.cxx
+  KFParticle/KFParticleDatabase.cxx
+  KFParticle/KFParticleBase.cxx
+  KFParticle/KFParticleBaseSIMD.cxx
+  KFParticle/KFParticle.cxx
+  KFParticle/KFParticleSIMD.cxx
+  KFParticle/KFParticleFinder.cxx
+  KFParticle/KFPEmcCluster.cxx
+  KFParticlePerformance/KFMCParticle.cxx
+  KFParticlePerformance/KFMCVertex.cxx
+  KFParticlePerformance/KFParticlePerformanceBase.cxx
+  KFParticlePerformance/KFTopoPerformance.cxx
+  KFParticlePerformance/KFPartEfficiencies.cxx
+)
+
+ADD_DEFINITIONS(-DHomogeneousField)
+#ADD_DEFINITIONS(-DNonhomogeneousField)
+
+set(LINKDEF KFParticleLinkDef.h)
+set(LIBRARY_NAME KFParticle)
+
+set(DEPENDENCIES Vc)
+
+GENERATE_LIBRARY()
+
+
+
diff --git a/external/KFParticle/KFParticle/KFPEmcCluster.cxx b/external/KFParticle/KFParticle/KFPEmcCluster.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3798ce9d92c4302ea94c60bb10811af04752c2ba
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPEmcCluster.cxx
@@ -0,0 +1,176 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPEmcCluster.h"
+#include <iostream>
+
+void KFPEmcCluster::SetParameter(const float_v& value, int iP, int iTr)
+{ 
+  /** Copies the SIMD vector "value" to the parameter vector KFPEmcCluster::fP[iP]
+   ** starting at the position "iTr".
+   ** \param[in] value - SIMD vector with the values to be stored
+   ** \param[in] iP - number of the parameter vector
+   ** \param[in] iTr - starting position in the parameter vector where the values should be stored
+   **/
+  if( (iTr+float_vLen) < Size())
+    reinterpret_cast<float_v&>(fP[iP][iTr]) = value;
+  else
+  {
+    const uint_v index(uint_v::IndexesFromZero());
+    (reinterpret_cast<float_v&>(fP[iP][iTr])).gather(reinterpret_cast<const float*>(&value), index, simd_cast<float_m>(index<(Size() - iTr)));
+  }
+}
+void KFPEmcCluster::SetCovariance(const float_v& value, int iC, int iTr) 
+{ 
+  /** Copies the SIMD vector "value" to the element of the covariance matrix vector KFPEmcCluster::fC[iC]
+   ** starting at the position "iTr".
+   ** \param[in] value - SIMD vector with the values to be stored
+   ** \param[in] iC - number of the element of the covariance matrix
+   ** \param[in] iTr - starting position in the parameter vector where the values should be stored
+   **/
+  if( (iTr+float_vLen) < Size())
+    reinterpret_cast<float_v&>(fC[iC][iTr]) = value;
+  else
+  {
+    const uint_v index(uint_v::IndexesFromZero());
+    (reinterpret_cast<float_v&>(fC[iC][iTr])).gather(reinterpret_cast<const float*>(&value), index, simd_cast<float_m>(index<(Size() - iTr)));
+  }
+}
+
+void KFPEmcCluster::Resize(const int n)
+{
+  /** Resizes all vectors in the class to a given value.
+   ** \param[in] n - new size of the vector
+   **/
+  for(int i=0; i<4; i++)
+    fP[i].resize(n);
+  for(int i=0; i<10; i++)
+    fC[i].resize(n);
+  fId.resize(n);
+}
+
+void KFPEmcCluster::Set(KFPEmcCluster& v, int vSize, int offset)
+{
+  /** Copies "vSize" clusters from the KFPEmcCluster "v" to the current object.
+   ** Tracks are put starting from the "offset" position.
+   ** \param[in] v - external KFPEmcCluster with input clusters to be copied
+   ** \param[in] vSize - number of clusters to be copied from "v"
+   ** \param[in] offset - offset position in the current object, starting from which input clusters will be stored
+   **/
+  for(int iV=0; iV<vSize; iV++)
+  {
+    for(int i=0; i<4; i++)
+      fP[i][offset+iV] = v.fP[i][iV];
+    for(int i=0; i<10; i++)
+      fC[i][offset+iV] = v.fC[i][iV];
+    fId[offset+iV] = v.fId[iV];
+  }
+}
+
+void KFPEmcCluster::SetTracks(const KFPEmcCluster& track, const kfvector_uint& trackIndex, const int nIndexes)
+{
+  /** The current object is resised to "nIndexes", clusters with indices "trackIndex" are copied to the current object.
+   ** \param[in] track - input vector of clusters
+   ** \param[in] trackIndex - indices of clusters in a vector "track", which should be stored to the current object
+   ** \param[in] nIndexes - number of clusters to be copied, defines the new size of the current object
+   **/
+
+  if(nIndexes == 0) return;
+  
+  Resize(nIndexes);
+
+  for(int iP=0; iP<4; iP++)
+  {
+    int iElement = 0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      float_v& vec = reinterpret_cast<float_v&>(fP[iP][iElement]);
+      vec.gather(&(track.fP[iP][0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    float_v& vec = reinterpret_cast<float_v&>(fP[iP][iElement]);
+    vec.gather(&(track.fP[iP][0]), index, simd_cast<float_m>(iElement+uint_v::IndexesFromZero()<nIndexes));
+    
+  }
+  for(int iC=0; iC<10; iC++)
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      float_v& vec = reinterpret_cast<float_v&>(fC[iC][iElement]);
+      vec.gather(&(track.fC[iC][0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    float_v& vec = reinterpret_cast<float_v&>(fC[iC][iElement]);
+    vec.gather(&(track.fC[iC][0]), index, simd_cast<float_m>(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fId[iElement]);
+      vec.gather(&(track.fId[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fId[iElement]);
+    vec.gather(&(track.fId[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+}
+
+void KFPEmcCluster::PrintTrack(int n)
+{
+  /** Prints parameters of the cluster with index "n".
+   ** \param[in] n - index of cluster to be printed
+   **/
+  for(int i=0; i<4; i++)
+    std::cout << fP[i][n] << " ";
+  std::cout << std::endl;
+  for(int i=0; i<10; i++)
+    std::cout << fC[i][n] << " ";
+  std::cout << std::endl;
+  
+  std::cout << fId[n] << std::endl;
+}
+
+void KFPEmcCluster::PrintTracks()
+{
+  /** Prints all field of the current object. **/
+    
+  std::cout << "NTracks " << Size() << std::endl;
+  if( Size()==0 ) return;
+  
+  std::cout << "Parameters: " << std::endl;
+  for(int iP=0; iP<4; iP++)
+  {
+    std::cout << "  iP " << iP << ": ";
+    for(int iTr=0; iTr<Size(); iTr++)
+      std::cout << Parameter(iP)[iTr]<< " ";
+    std::cout << std::endl;
+  }
+
+  std::cout << "Cov matrix: " << std::endl;
+  for(int iC=0; iC<10; iC++)
+  {
+    std::cout << "  iC " << iC << ": ";
+    for(int iTr=0; iTr<Size(); iTr++)
+      std::cout << Covariance(iC)[iTr]<< " ";
+    std::cout << std::endl;
+  }
+  
+  std::cout << "Id: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  Id()[iTr] << " ";
+  std::cout << std::endl;
+}
+  
\ No newline at end of file
diff --git a/external/KFParticle/KFParticle/KFPEmcCluster.h b/external/KFParticle/KFParticle/KFPEmcCluster.h
new file mode 100644
index 0000000000000000000000000000000000000000..329c7496239af085c3453024a4e0aea7cc03f016
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPEmcCluster.h
@@ -0,0 +1,123 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPEmcCluster_H
+#define KFPEmcCluster_H
+
+#include "KFParticleDef.h"
+
+/** @class KFPEmcCluster
+ ** @brief A class to store vectors of input cluster from the electro-magnetic calorimeter.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** A cluster is described with the state vector { X, Y, Z, E }
+ ** and the corresponding covariance matrix. Also contains a unique id.
+ ** The data model implemented in the class is "Structure Of Arrays":
+ ** each parameter is stroed in a separate vector. Such data structure
+ ** allows fast vectorised access to the aligned data providing the
+ ** maximum possible speed for data reading, and at the same time easy
+ ** random access to the data members.
+ **/
+
+class KFPEmcCluster
+{
+ public:
+  KFPEmcCluster():fP(), fC(), fId() { }
+  ~KFPEmcCluster() { }
+
+  /**Returns size of the vectors. All data vectors have the same size. */
+  int Size() const { return fP[0].size(); }
+  
+  void Resize(const int n);
+  void Set(KFPEmcCluster& v, int vSize, int offset);
+  void SetTracks(const KFPEmcCluster& track, const kfvector_uint& trackIndex, const int nIndexes);
+  
+  const kfvector_float& X()  const { return fP[0]; } ///< Returns constant reference to the vector with X coordinates.
+  const kfvector_float& Y()  const { return fP[1]; } ///< Returns constant reference to the vector with Y coordinates.
+  const kfvector_float& Z()  const { return fP[2]; } ///< Returns constant reference to the vector with Z coordinates.
+  const kfvector_float& E() const { return fP[3]; }  ///< Returns constant reference to the vector with energy of the cluster.
+
+  const kfvector_float& Parameter(const int i)  const { return fP[i]; }  ///< Returns constant reference to the parameter vector with index "i".
+  const kfvector_float& Covariance(const int i)  const { return fC[i]; } ///< Returns constant reference to the vector of the covariance matrix elements with index "i".
+  const kfvector_int& Id()    const { return fId; }                      ///< Returns constant reference to the vector with unique id of the clusters.
+
+  //modifiers 
+  void SetParameter (float value, int iP, int iTr) { fP[iP][iTr] = value; } ///< Sets the "value" of the parameter "iP" of the cluster with index "iTr".
+  void SetCovariance(float value, int iC, int iTr) { fC[iC][iTr] = value; } ///< Sets the "value" of the element of covariance matrix "iC" of the cluster with index "iTr".
+
+  void SetParameter (const float_v& value, int iP, int iTr);  
+  void SetCovariance(const float_v& value, int iC, int iTr);
+
+  void SetId        (int value, int iTr)           { fId[iTr] = value; } ///< Sets the "value" of the id of the cluster with index "iTr".
+  
+  void PrintTrack(int n);
+  void PrintTracks();
+  
+  KFPEmcCluster(const KFPEmcCluster& clusters): fId()
+  {
+    /** Copy-constructor. Makes one-to-one copy.*/
+    const int localSize = clusters.Size();
+    
+    for(int i=0; i<4; i++)
+    {
+      fP[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fP[i][n] = clusters.fP[i][n];
+    }
+
+    for(int i=0; i<10; i++)
+    {
+      fC[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fC[i][n] = clusters.fC[i][n];
+    }
+    
+    fId.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fId[n] = clusters.fId[n];    
+  }
+  
+  const KFPEmcCluster& operator = (const KFPEmcCluster& clusters)
+  {
+    /** Operator to copy one KFPEmcCluster object to another. Makes one-to-one copy.*/
+    const int localSize = clusters.Size();
+    
+    for(int i=0; i<4; i++)
+    {
+      fP[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fP[i][n] = clusters.fP[i][n];
+    }
+
+    for(int i=0; i<10; i++)
+    {
+      fC[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fC[i][n] = clusters.fC[i][n];
+    }
+    
+    fId.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fId[n] = clusters.fId[n];
+    
+    return *this;
+  }
+  
+ private:  
+  kfvector_float fP[4];  ///< Coordinates of the cluster and energy: X, Y, Z, E.
+  kfvector_float fC[10]; ///< Covariance matrix of the parameters of the cluster.
+
+  kfvector_int fId; ///< Vector with unique ids of the clusters.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFPInputData.h b/external/KFParticle/KFParticle/KFPInputData.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f01801be089d93acab9f53ec3d355b9c111da5f
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPInputData.h
@@ -0,0 +1,370 @@
+//----------------------------------------------------------------------------
+// Structures with input data for KF Particle Finder
+// .
+// @author  M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPINPUTDATA_H
+#define KFPINPUTDATA_H
+
+#include "KFPTrackVector.h"
+#include "KFParticle.h"
+
+#include <vector>
+#include <string>
+#include <fstream>
+
+/** @class KFPTrackIndex
+ ** @brief Helper structure to sort tracks in the KFPTrackVector object.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The structure is used in the KFParticleTopoReconstructor::SortTracks() function.
+ ** Tracks are sorted according to their pdg hypothesis: electrons, muons, pions,
+ ** tracks without pdg (-1), kaons, protons, deuterons, tritons, He3, He4.
+ ** Teh structure contains pdg hypothesis of the track and its index in the 
+ ** KFPTrackVector object.
+ **/
+
+struct KFPTrackIndex
+{
+  int fIndex; ///< index of the track in the KFPTrackVector object.
+  int fPdg;   ///< PDG hypothesis of the track
+  
+  static bool Compare(const KFPTrackIndex& a, const KFPTrackIndex& b)
+  {
+    /** Static sorting function for comparison of the two input objects of class KFPTrackIndex.
+     ** Objects are sorted according to the PDG hypothesis: electrons, muons, pions,
+     ** tracks without pdg (-1), kaons, protons, deuterons, tritons, He3, He4.
+     ** Return "true" if a.fPdg < b.fPdg, otherwise returns "false". 
+     ** \param[in] a - first object
+     ** \param[in] b - second object
+     **/
+    int pdg1 = a.fPdg == -1 ? 250 : a.fPdg;
+    int pdg2 = b.fPdg == -1 ? 250 : b.fPdg;
+
+    return (abs(pdg1) < abs(pdg2));
+  }
+};
+
+
+/** @class KFPInputData
+ ** @brief Class with the input data for KF Particle Finder: tracks, primary vertex and magnetic field.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to transfer the data between devices: CPU and Intel Xeon Phi. The memory is aligned
+ ** with the size of the SIMD vectors.
+ **/
+
+class KFPInputData
+{
+ public:
+   
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(float_v)); }      ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(float_v)); }    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);}  ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                         ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                       ///< delete operator for the SIMD-alligned dynamic memory release
+  
+  KFPInputData():fPV(0),fBz(0.f) {};
+  ~KFPInputData() {};
+
+  bool ReadDataFromFile( std::string prefix )
+  {
+    /** Reads the input data from the input file with the name defined by "prefix".
+     ** \param[in] prefix - string with the name of the input file
+     **/ 
+    std::ifstream ifile(prefix.data());
+    if ( !ifile.is_open() ) return 0;
+    int nSets;
+    ifile >> fBz;
+    ifile >> nSets;
+    for(int iSet=0; iSet<nSets; iSet++)
+    {
+      int nTracks = 0;
+      ifile >> nTracks;
+      fTracks[iSet].Resize(nTracks);
+      
+      for(int iP=0; iP<6; iP++)
+      {
+        float value;
+        for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+        {
+          ifile >> value;
+          fTracks[iSet].SetParameter(value, iP, iTr);
+        }
+      }
+
+      for(int iC=0; iC<21; iC++)
+      {
+        float value;
+        for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+        {
+          ifile >> value;
+          fTracks[iSet].SetCovariance(value, iC, iTr);
+        }
+      }
+
+      int tmpInt;
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      {
+        ifile >> tmpInt;
+        fTracks[iSet].SetId(tmpInt, iTr);
+      }
+      
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      {
+        ifile >> tmpInt;
+        fTracks[iSet].SetPDG(tmpInt, iTr);
+      }
+
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      {
+        ifile >> tmpInt;
+        fTracks[iSet].SetQ(tmpInt, iTr);
+      }
+      
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      {
+        ifile >> tmpInt;
+        fTracks[iSet].SetPVIndex(tmpInt, iTr);
+      }
+      
+      ifile >> tmpInt;
+      fTracks[iSet].SetLastElectron(tmpInt);
+      ifile >> tmpInt;
+      fTracks[iSet].SetLastMuon    (tmpInt);
+      ifile >> tmpInt;
+      fTracks[iSet].SetLastPion    (tmpInt);
+      ifile >> tmpInt;
+      fTracks[iSet].SetLastKaon    (tmpInt);
+      ifile >> tmpInt;
+      fTracks[iSet].SetLastProton  (tmpInt);
+    }
+
+    int nPV;
+    ifile>>nPV;
+    fPV.resize(nPV);
+    for(unsigned int iPV=0; iPV < fPV.size(); iPV++)
+    {
+      for(int iP=0; iP<3; iP++)
+        ifile >> fPV[iPV].Parameter(iP);
+  
+      for(int iC=0; iC<6; iC++)
+        ifile >> fPV[iPV].Covariance(iC);
+    }
+    
+    ifile.close();
+    return 1;
+  }
+  
+  void SetDataToVector(int* data, int& dataSize)
+  {
+    /** Stores information to the memory under pointer "data".
+     ** \param[out] data - memory, where input information will be stored
+     ** \param[out] dataSize - size of the stored memory in "int" (or bloks of 4 bytes, or 32 bits)
+     **/
+    dataSize = NInputSets + 1 + 1; //sizes of the track vectors and pv vector, and field
+    for(int iSet=0; iSet<NInputSets; iSet++)
+      dataSize += fTracks[iSet].DataSize();
+    dataSize += fPV.size() * 9;
+        
+    for(int iSet=0; iSet<NInputSets; iSet++)
+      data[iSet] = fTracks[iSet].Size();
+    data[NInputSets] = fPV.size();
+    
+    float& field = reinterpret_cast<float&>(data[NInputSets+1]);
+    field = fBz;
+    
+    int offset = NInputSets+2;
+        
+    for(int iSet=0; iSet<NInputSets; iSet++)
+      fTracks[iSet].SetDataToVector(data, offset);
+    
+    for(int iP=0; iP<3; iP++)
+    {
+      for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      {
+        float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+        tmpFloat = fPV[iPV].Parameter(iP);
+      }
+      offset += fPV.size();
+    }
+    
+    for(int iC=0; iC<6; iC++)
+    {
+      for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      {
+        float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+        tmpFloat = fPV[iPV].Covariance(iC);
+      }
+      offset += fPV.size();
+    }    
+  }
+
+  void ReadDataFromVector(int* data)
+  {
+    /** Reads input data from the given memory.
+     ** \param[in] data - pointer to the memory with the input data
+     **/
+    int offset = NInputSets+2;
+    for(int iSet=0; iSet<NInputSets; iSet++)
+    {
+      fTracks[iSet].Resize(data[iSet]);
+      fTracks[iSet].ReadDataFromVector(data, offset);
+    }
+    
+    float& field = reinterpret_cast<float&>(data[NInputSets+1]);
+    fBz = field;
+    
+    fPV.resize(data[NInputSets]);
+                
+    for(int iP=0; iP<3; iP++)
+    {
+      for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      {
+        float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+        fPV[iPV].Parameter(iP) = tmpFloat;
+      }
+      offset += fPV.size();
+    }
+    
+    for(int iC=0; iC<6; iC++)
+    {
+      for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      {
+        float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+        fPV[iPV].Covariance(iC) = tmpFloat;
+      }
+      offset += fPV.size();
+    }        
+  }
+  
+  void Print()
+  {
+    /**Prints all fields of the current object.*/
+    for(int iSet=0; iSet<NInputSets; iSet++)
+      fTracks[iSet].Print();
+    std::cout << "N PV: " << fPV.size() << std::endl;
+    
+    std::cout << "X: ";
+    for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      std::cout << fPV[iPV].X() <<" ";
+    std::cout << std::endl;
+        std::cout << "Y: ";
+    for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      std::cout << fPV[iPV].Y() <<" ";
+    std::cout << std::endl;
+    std::cout << "Z: ";
+    for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+      std::cout << fPV[iPV].Z() <<" ";
+    std::cout << std::endl;
+
+    std::cout << "Cov matrix: " << std::endl;
+    for(int iC=0; iC<6; iC++)
+    {
+      std::cout << "  iC " << iC << ":  ";
+      for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+        std::cout << fPV[iPV].Covariance(iC) <<" ";
+      std::cout << std::endl;
+    }
+    
+    std::cout << "Field: " << fBz << std::endl;
+  }
+  
+  KFPTrackVector* GetTracks()  { return fTracks; } ///< Returns pointer to the array with track vectors.
+  float GetBz() const { return fBz; } ///< Returns value of the constant field Bz.
+  const std::vector<KFParticle>& GetPV() const { return fPV; } ///< Returns vector with primary vertices.
+
+  const KFPInputData& operator = (const KFPInputData& data)
+  {
+    /** Copies input data from object "data" to the current object. Returns the current object. \param[in] data - input data*/
+    for(int i=0; i<NInputSets; i++)
+      fTracks[i] = data.fTracks[i];
+    fPV = data.fPV;
+    fBz = data.fBz;
+    
+    return *this;
+  }
+  KFPInputData(const KFPInputData& data):fPV(0),fBz(0.f)
+  {
+    /** Copies input data from object "data" to the current object. \param[in] data - input data */
+    for(int i=0; i<NInputSets; i++)
+      fTracks[i] = data.fTracks[i];
+    fPV = data.fPV;
+    fBz = data.fBz;
+  }
+  
+ protected:
+  /** Array of track vectors: \n
+   ** 0 - positive secondary tracks stored at the first point; \n
+   ** 1 - negative secondary tracks stored at the first point; \n
+   ** 2 - positive primary tracks stored at the first point; \n
+   ** 3 - positive primary tracks stored at the first point; \n
+   ** 4 - positive secondary tracks stored at the last point; \n
+   ** 5 - negative secondary tracks stored at the last point; \n
+   ** 6 - positive primary tracks stored at the last point; \n
+   ** 7 - positive primary tracks stored at the last point.
+   ** \see KFPTrackVector for documentation.
+   **/
+  KFPTrackVector fTracks[NInputSets]__attribute__((aligned(sizeof(float_v)))); 
+  std::vector<KFParticle> fPV; ///< Vector with primary vertices.
+  float fBz; ///< Constant homogenious one-component magnetic field Bz.
+} __attribute__((aligned(sizeof(float_v))));
+
+/** @class KFPInputDataArray
+ ** @brief Structure with the set of the input data for KF Particle Finder.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The structure contains pointer to array of KFPInputData objects. Copying of the 
+ ** objects of this structure is disabled.
+ **/
+
+struct KFPInputDataArray{
+  KFPInputDataArray():fInput(0){};
+  ~KFPInputDataArray() { if(fInput) delete [] fInput; }
+
+  KFPInputData *fInput; ///< Pointer to the array of the input data objects.
+  
+ private:
+   const KFPInputDataArray& operator = (const KFPInputDataArray&);
+   KFPInputDataArray(const KFPInputDataArray&);
+};
+
+
+/** @class KFPLinkedList
+ ** @brief Structure to creat a linked list of the input data.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The structure contains pointer to array of KFPInputData objects. Copying of the 
+ ** objects of this structure is disabled. The list is used to create a queue for processing
+ ** at the device side (Intel Xeon Phi).
+ **/
+
+struct KFPLinkedList
+{
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(float_v)); }      ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(float_v)); }    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);}  ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                         ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                       ///< delete operator for the SIMD-alligned dynamic memory release
+  
+  KFPInputData data __attribute__((aligned(sizeof(float_v)))); ///< Input data for KF Particle Finder \see KFPInputData.
+  KFPLinkedList* next; ///< Link to the nex object in the linked list.
+} __attribute__((aligned(sizeof(float_v))));
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFPSimdAllocator.h b/external/KFParticle/KFParticle/KFPSimdAllocator.h
new file mode 100644
index 0000000000000000000000000000000000000000..9baf6001fc29d51c67b5dedce5083edfa28a56f6
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPSimdAllocator.h
@@ -0,0 +1,109 @@
+//----------------------------------------------------------------------------
+// Allocator for SIMDised KF Particle
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPSimdAllocator_H
+#define KFPSimdAllocator_H
+
+#include <Vc/Vc>
+
+/** @class KFPSimdAllocator
+ ** @brief Allocator which is needed to allocate memory in std::vector aligned by the size of SIMD vectors.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **/
+
+template <class T>
+class KFPSimdAllocator {
+ public:
+ // type definitions
+  typedef T        value_type;
+  typedef T*       pointer;
+  typedef const T* const_pointer;
+  typedef T&       reference;
+  typedef const T& const_reference;
+  typedef std::size_t    size_type;
+  typedef std::ptrdiff_t difference_type;
+
+  /** @class rebind
+   ** @brief Rebind allocator to type U of the SIMD allocator.
+   ** @author  M.Zyzak, I.Kisel
+   ** @date 05.02.2019
+   ** @version 1.0
+   **/
+  template <class U>
+  struct rebind {
+    typedef KFPSimdAllocator<U> other;
+  };
+
+  /** Return address of "value". */
+  pointer address (reference value) const {
+    return &value;
+  }
+  /** Return address of "value". */
+  const_pointer address (const_reference value) const {
+    return &value;
+  }
+
+  /* constructors and destructor
+        * - nothing to do because the allocator has no state
+  */
+  KFPSimdAllocator() throw() { }
+  KFPSimdAllocator(const KFPSimdAllocator&) throw() {  }
+  template <class U>
+  KFPSimdAllocator (const KFPSimdAllocator<U>&) throw() {  }
+  ~KFPSimdAllocator() throw() {  }
+
+  /** Return maximum number of elements that can be allocated. */
+  size_type max_size () const throw() {
+    return std::numeric_limits<std::size_t>::max() / sizeof(T);
+  }
+
+  /** Allocate but don't initialize num elements of type T. */
+  pointer allocate (size_type num, const void* = 0) {
+//               print message and allocate memory with global new
+    pointer ret = reinterpret_cast<pointer>( /*T::*/operator new(num*sizeof(T)) );
+    return ret;
+  }
+
+  /** Initialize elements of allocated storage "p" with an empty element. */
+  void construct (pointer p) {
+  // initialize memory with placement new
+    new(p) T();
+  }
+  
+  /** Initialize elements of allocated storage "p" with value "value". */
+  void construct (pointer p, const T& value) {
+    new(p) T(value);
+  }
+
+  /** Destroy elements of initialized storage "p". */
+  void destroy (pointer p) {
+  // destroy objects by calling their destructor
+    p->~T();
+  }
+
+  /** Deallocate storage p of deleted elements. */
+  void deallocate (pointer p, size_type num) {
+  // print message and deallocate memory with global delete
+    /*T::*/operator delete(static_cast<void*>(p), num*sizeof(T));
+
+  }
+
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}      ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);}    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(Vc::float_v)); }    ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(Vc::float_v)); }  ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                           ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                         ///< delete operator for the SIMD-alligned dynamic memory release
+}; // KFPSimdAllocator
+      
+#endif //KFPSimdAllocator
diff --git a/external/KFParticle/KFParticle/KFPTrack.cxx b/external/KFParticle/KFParticle/KFPTrack.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8e636cdc9d8d599ee97b5ad47f88834de0ea86c1
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPTrack.cxx
@@ -0,0 +1,84 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPTrack.h"
+
+#ifdef __ROOT__
+ClassImp(KFPTrack);
+#endif
+
+void KFPTrack::RotateXY( float alpha )
+{
+  /** Rotates the parameters of the track on an angle alpha in the XY plane.
+   ** Can be used in case of the transforamtion of the coordinate system.
+   ** The rotation matrix is:
+   ** \verbatim
+   {  cos(A), -sin(A),  0,        0,        0,   0 }
+   {  sin(A),  cos(A),  0,        0,        0,   0 }
+   {       0,       0,  1,        0,        0,   0 }
+   {       0,       0,  0,   cos(A),  -sin(A),   0 }
+   {       0,       0,  0,   sin(A),   cos(A),   0 }
+   {       0,       0,  0,        0,        0,   1 } 
+   \endverbatim
+   ** \param[in] alpha - rotation angle
+   **/
+  const float cA = cos( alpha );
+  const float sA = sin( alpha );
+
+  //float J[6][6] = { {  cA, -sA,  0,    0,    0,   0 }, // X
+  //                  {  sA,  cA,  0,    0,    0,   0 }, // Y
+  //                  {  0,   0,   1,    0,    0,   0 }, // Z
+  //                  {  0,   0,   0,   cA,  -sA,   0 }, // Px
+  //                  {  0,   0,   0,   sA,   cA,   0 }, // Py
+  //                  {  0,   0,   0,    0,    0,   1 } }; // Pz
+
+  const float x  = GetX(),  y = GetY();
+
+  SetX( -(x*sA +  y*cA) );
+  SetY( x*cA -  y*sA );
+
+  const float px  = GetPx(),  py = GetPy();
+
+  SetPx( -(px*sA + py*cA)  );
+  SetPy( px*cA - py*sA );
+
+  float cov[21];
+  for(int iC=0; iC<21; iC++)
+    cov[iC] = fC[iC];
+
+  fC[0] = cA*cA*  cov[2] + 2* cA* cov[1]* sA + cov[0]*sA* sA;
+  
+  fC[1] = -(cA*cA * cov[1]) + cA* (-cov[0] + cov[2])* sA + cov[1]*sA* sA;
+  fC[2] = cA*cA*  cov[0] - 2* cA* cov[1]* sA + cov[2]*sA* sA; 
+  
+  fC[3] = -(cA* cov[4]) - cov[3]* sA;
+  fC[4] = cA* cov[3] - cov[4]* sA;
+  fC[5] = cov[5]; 
+  
+  fC[6] = cA*cA*  cov[11] + cA *(cov[10] + cov[7])* sA + cov[6]*sA* sA;
+  fC[7] = -(cA*cA * cov[10]) + cA* (cov[11] - cov[6])* sA + cov[7] *sA*sA;
+  fC[8] = -(cA *cov[12]) - cov[8] *sA;
+  fC[9] = cA*cA*  cov[14] + 2 *cA* cov[13]* sA + cov[9]* sA*sA;
+
+  fC[10] = -(cA*cA*  cov[7]) + cA* (cov[11] - cov[6])* sA + cov[10]*sA* sA; 
+  fC[11] = cA*cA*  cov[6] - cA* (cov[10] + cov[7]) *sA + cov[11]*sA* sA;
+  fC[12] = cA* cov[8] - cov[12]* sA; 
+  fC[13] = -(cA*cA*  cov[13]) + cA* (cov[14] - cov[9])* sA + cov[13]* sA*sA;
+  fC[14] = cA*cA*  cov[9] - 2* cA* cov[13]* sA + cov[14]* sA*sA;
+  
+  fC[15] = -(cA* cov[16]) - cov[15]* sA;
+  fC[16] = cA* cov[15] - cov[16]* sA;
+  fC[17] = cov[17]; 
+  fC[18] = -(cA* cov[19]) - cov[18]* sA;
+  fC[19] = cA* cov[18] - cov[19]* sA;
+  fC[20] = cov[20];
+
+}
diff --git a/external/KFParticle/KFParticle/KFPTrack.h b/external/KFParticle/KFParticle/KFPTrack.h
new file mode 100644
index 0000000000000000000000000000000000000000..37f9bb1f1108c3b6ab644a119486c9ca9cec5070
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPTrack.h
@@ -0,0 +1,220 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPTrack_H
+#define KFPTrack_H
+
+/** @class KFPTrack
+ ** @brief A scalar class for storage of the track in the cartesian parametrisation.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** A track is described with the state vector { X, Y, Z, Px, Py, Pz }
+ ** and the corresponding covariance matrix. Also contains charge of the
+ ** track, chi2 of the track fit, the corresponding number of degrees of freedom,
+ ** the unique Id of the track and the field approximation along the track trajectory.
+ **/
+
+#include <cmath>
+#include "TObject.h"
+class KFPTrack 
+#ifdef __ROOT__
+: public TObject
+#endif
+{
+
+public:
+  KFPTrack():fChi2(-1.f), fQ(0), fNDF(-1), fId(-1) { }
+  ~KFPTrack() { }
+
+  int    GetID() const { return fId; } ///< Returns Id of the track.
+  
+  bool   GetXYZPxPyPz(float *p) const 
+  {
+    /** Fills an array p with the parameters of the track.
+     ** \param[out] p - array where { X, Y, Z, Px, Py, Pz } are copied
+     **/
+    for(int i=0; i<6; i++)
+      p[i] = fP[i];
+    return 1;
+  }
+  bool   GetCovarianceXYZPxPyPz(float cv[21]) const
+  {
+    /** Copies the covariance matrix of the track to the array of floats.
+     ** \param[out] cv[21] - the output array, where the covariance matrix is copied
+     **/
+    for (int i=0; i<21; i++)
+      cv[i] = fC[i];
+    return 1;
+  }
+  bool   GetCovarianceXYZPxPyPz(double cv[21]) const
+  {
+    /** Copies the covariance matrix of the track to the array of doubles.
+     ** \param[out] cv[21] - the output array, where the covariance matrix is copied
+     **/
+    for (int i=0; i<21; i++)
+      cv[i] = fC[i];
+    return 1;
+  }
+
+  /** Copies position of the track to the output array of floats. \param[out] position - the output array with the position of the track **/
+  void   GetXYZ(float *position)    const {position[0] = fP[0]; position[1] = fP[1]; position[2] = fP[2];}
+  /** Copies 3 momentum components of the track to the output array of floats. \param[out] position - the output array with the momentum of the track **/
+  void   GetPxPyPz(float *position) const {position[0] = fP[3]; position[1] = fP[4]; position[2] = fP[5];}
+  /** Copies position of the track to the output array of floats. \param[out] position - the output array with the position of the track **/
+  void   XvYvZv(float *position)    const {position[0] = fP[0]; position[1] = fP[1]; position[2] = fP[2];}
+  /** Copies 3 momentum components of the track to the output array of floats. \param[out] position - the output array with the momentum of the track **/
+  void   PxPyPz(float *position) const {position[0] = fP[3]; position[1] = fP[4]; position[2] = fP[5];}
+  /** Copies position of the track to the output array of doubles. \param[out] position - the output array with the position of the track **/
+  void   XvYvZv(double *position)    const {position[0] = fP[0]; position[1] = fP[1]; position[2] = fP[2];}
+  /** Copies 3 momentum components of the track to the output array of doubles. \param[out] position - the output array with the momentum of the track **/
+  void   PxPyPz(double *position) const {position[0] = fP[3]; position[1] = fP[4]; position[2] = fP[5];}
+
+  float GetX() const { return fP[0]; }  ///< Returns X coordinate of the track.
+  float GetY() const { return fP[1]; }  ///< Returns Y coordinate of the track.
+  float GetZ() const { return fP[2]; }  ///< Returns Z coordinate of the track.
+  float GetPx() const { return fP[3]; } ///< Returns Px component of the momentum of the track.
+  float GetPy() const { return fP[4]; } ///< Returns Py component of the momentum of the track.
+  float GetPz() const { return fP[5]; } ///< Returns Pz component of the momentum of the track.
+
+  float GetPt() const { return sqrt(fP[3]*fP[3]+fP[4]*fP[4]); } ///< Returns Pt - transverse momentum of the track.
+  float GetP()  const { return sqrt(fP[3]*fP[3]+fP[4]*fP[4]+fP[5]*fP[5]); } ///< Returns P - momentum of the track.
+
+  void GetCovarianceMatrix(float *covmatrix)
+  {
+    /** Copies the covariance matrix of the track to the array of floats.
+     ** \param[out] covmatrix[21] - the output array, where the covariance matrix is copied
+     **/
+    for (int i=0; i<21; i++)
+      covmatrix[i] = fC[i];
+  }
+  float GetParameter(int i) const { return fP[i]; }  ///< Returns parameter "i" of the track. \param[in] i - index of the parameter to be returned
+  float GetCovariance(int i) const { return fC[i]; } ///< Returns element of the covariance matrix "i" of the track. \param[in] i - index of the element to be returned
+
+  int    Charge()        const { return fQ; }        ///< Returns charge of the track.
+  float GetChi2perNDF() const { return fChi2/fNDF; } ///< Returns Chi2/NDF of the track, NDF is a number of degrees of freedom.
+  float GetChi2()       const { return fChi2;      } ///< Returns Chi2 of the track.
+  int    GetNDF()        const { return fNDF; }      ///< Returns number of degrees of freedom of the track.
+
+  const float * GetTrack() const { return fP; }     ///< Returns a pointer to the array of track parameters.
+  const float * GetCovMatrix() const { return fC; } ///< Returns a pointer to the array of the covariance matrix elements stored in a lower triangular form.
+
+  void SetParameters(const float *position) 
+  {
+    /** Sets parameters { X, Y, Z, Px, Py, Pz } of the track from the input array of floats.
+     ** \param[in] position - input array with the track parameters
+     **/
+    for(int i=0; i<6; i++)
+      fP[i] = position[i];
+  }
+  void SetParameters(double *position) 
+  { 
+    /** Sets parameters { X, Y, Z, Px, Py, Pz } of the track from the input array of doubles.
+     ** \param[in] position - input array with the track parameters
+     **/
+    for(int i=0; i<6; i++)
+      fP[i] = position[i];
+  }
+  void SetParameters(float x, float y, float z, float px, float py, float pz) 
+  { 
+    /** Sets parameters { X, Y, Z, Px, Py, Pz } of the track.
+     ** \param[in] x - X coordinate to be set
+     ** \param[in] y - Y coordinate to be set
+     ** \param[in] z - Z coordinate to be set
+     ** \param[in] Px - Px momentum component to be set
+     ** \param[in] Py - Py momentum component to be set
+     ** \param[in] Pz - Pz momentum component to be set
+     **/
+    fP[0] = x;  fP[1] = y;  fP[2] = z;
+    fP[3] = px; fP[4] = py; fP[5] = pz;
+  }
+  void SetXYZ(float x, float y, float z) 
+  { 
+    /** Sets position { X, Y, Z } of the track.
+     ** \param[in] x - X coordinate to be set
+     ** \param[in] y - Y coordinate to be set
+     ** \param[in] z - Z coordinate to be set
+     **/
+    fP[0] = x;  fP[1] = y;  fP[2] = z;
+  }
+  void SetPxPyPz(float px, float py, float pz) 
+  { 
+    /** Sets momentum { Px, Py, Pz } of the track.
+     ** \param[in] Px - Px momentum component to be set
+     ** \param[in] Py - Py momentum component to be set
+     ** \param[in] Pz - Pz momentum component to be set
+     **/
+    fP[3] = px; fP[4] = py; fP[5] = pz;
+  }
+  void SetID(int id)       {fId = id;}      ///< Sets Id of the track.
+
+  void SetX(float x)      { fP[0] = x; }    ///< Sets X coordinate of the track.
+  void SetY(float y)      { fP[1] = y; }    ///< Sets Y coordinate of the track.
+  void SetZ(float z)      { fP[2] = z; }    ///< Sets Z coordinate of the track.
+  void SetPx(float px)      { fP[3] = px; } ///< Sets Px component of the track momentum.
+  void SetPy(float py)      { fP[4] = py; } ///< Sets Py component of the track momentum.
+  void SetPz(float pz)      { fP[5] = pz; } ///< Sets Pz component of the track momentum.
+  void SetCharge(int q) { fQ = q; }         ///< Sets charge of the track.
+  void SetChi2(float chi) { fChi2 = chi; }  ///< Sets a value of the track Chi2.
+  void SetNDF(int ndf)     { fNDF = ndf; }  ///< Sets a value of the number of degrees of freedom.
+
+  void SetCovarianceMatrix(const float *C)
+  {
+    /** Sets the covariance matrix from the input array of floats.
+     ** \param[in] C[21] - array with the input elements of the covariance matrix stored in the lower triangular form
+     **/
+    for (int i=0; i<21; i++)
+      fC[i] = C[i];
+  }
+  void SetCovarianceMatrix(const double *C)
+  {
+    /** Sets the covariance matrix from the input array of doubles.
+     ** \param[in] C[21] - array with the input elements of the covariance matrix stored in the lower triangular form
+     **/
+    for (int i=0; i<21; i++)
+      fC[i] = C[i];
+  }
+  
+  /** Sets an element of the covariance matrix with index "i". \param[in] c - value to be set \param[in] i - index of the element */
+  void SetCovariance(const int i, const float c) { fC[i]=c; } 
+  
+  void RotateXY( float alpha ); // rotate on alpha in XY plane. Should be useful for CS change
+
+  int Id() const { return fId; }    ///< Returns Id of the track.
+  void SetId( int id ){ fId = id; } ///< Sets Id of the track.
+
+#ifdef NonhomogeneousField
+  const float* GetFieldCoeff() const { return fieldRegion; } ///< Returns array of the coefficients for field approximation.
+  /** Sets a field coefficient with index "i". \param[in] c - value to be set \param[in] i - index of the element */
+  void SetFieldCoeff(float c, int i) { fieldRegion[i] = c; } 
+#endif
+ private:
+
+  float fP[6];  ///< Parameters of the track: { X, Y, Z, Px, Py, Pz }.
+  float fC[21]; ///< Covariance matrix of the track parameters. Stored in the lower triangular form.
+  float fChi2;  ///< Chi-square of the track fit.
+  char fQ;      ///< Charge of the track.
+  short fNDF;   ///< Number of degree of freedom of the fit.
+  int fId;      ///< Id of the track.
+  
+#ifdef NonhomogeneousField
+  /** \brief Approximation of the magnetic field along the track trajectory.
+   ** Each component (Bx, By, Bz) is approximated with the parabola depending on Z coordinate. Is defined in case of #ifdef NonhomogeneousField.
+   **/
+  float fieldRegion[10];
+#endif
+#ifdef __ROOT__
+  ClassDef(KFPTrack,1)
+#endif
+};
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFPTrackVector.cxx b/external/KFParticle/KFParticle/KFPTrackVector.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..24ff12365092410799313d151c5f387105a59b5c
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPTrackVector.cxx
@@ -0,0 +1,412 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPTrackVector.h"
+#include <iostream>
+
+void KFPTrackVector::SetParameter(const float_v& value, int iP, int iTr)
+{ 
+  /** Copies the SIMD vector "value" to the parameter vector KFPTrackVector::fP[iP]
+   ** starting at the position "iTr".
+   ** \param[in] value - SIMD vector with the values to be stored
+   ** \param[in] iP - number of the parameter vector
+   ** \param[in] iTr - starting position in the parameter vector where the values should be stored
+   **/
+// gather caused errors at XeonPhi, temporarly replaced with the simple copying
+//   if( (iTr+float_vLen) < Size())
+//     reinterpret_cast<float_v&>(fP[iP][iTr]) = value;
+//   else
+//   {
+//     const uint_v index(uint_v::IndexesFromZero());
+//     (reinterpret_cast<float_v&>(fP[iP][iTr])).gather(reinterpret_cast<const float*>(&value), index, float_m(index<(Size() - iTr)));
+//   }
+  
+  if( (iTr+float_vLen) < Size())
+    reinterpret_cast<float_v&>(fP[iP][iTr]) = value;
+  else
+    for(int i=0; i<float_v::Size; i++)
+    {
+      if(iTr + i >= Size()) continue;
+      fP[iP][iTr+i] = value[i];
+    } 
+}
+void KFPTrackVector::SetCovariance(const float_v& value, int iC, int iTr) 
+{ 
+  /** Copies the SIMD vector "value" to the element of the covariance matrix vector KFPTrackVector::fC[iC]
+   ** starting at the position "iTr".
+   ** \param[in] value - SIMD vector with the values to be stored
+   ** \param[in] iC - number of the element of the covariance matrix
+   ** \param[in] iTr - starting position in the parameter vector where the values should be stored
+   **/
+// gather caused errors at XeonPhi, temporarly replaced with the simple copying
+//   if( (iTr+float_vLen) < Size())
+//     reinterpret_cast<float_v&>(fC[iC][iTr]) = value;
+//   else
+//   {
+//     const uint_v index(uint_v::IndexesFromZero());
+//     (reinterpret_cast<float_v&>(fC[iC][iTr])).gather(reinterpret_cast<const float*>(&value), index, float_m(index<(Size() - iTr)));
+//   }
+  
+  if( (iTr+float_vLen) < Size())
+    reinterpret_cast<float_v&>(fC[iC][iTr]) = value;
+  else
+    for(int i=0; i<float_v::Size; i++)
+    {
+      if(iTr + i >= Size()) continue;
+      fC[iC][iTr+i] = value[i];
+    } 
+}
+  
+
+void KFPTrackVector::Resize(const int n)
+{
+  /** Resizes all vectors in the class to a given value.
+   ** \param[in] n - new size of the vector
+   **/
+  for(int i=0; i<6; i++)
+    fP[i].resize(n);
+  for(int i=0; i<21; i++)
+    fC[i].resize(n);
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    fField[i].resize(n);
+#endif
+//     fChi2.resize(n);
+//     fNDF.resize(n);
+  fId.resize(n);
+  fPDG.resize(n);
+  fQ.resize(n);
+  fPVIndex.resize(n);
+  fNPixelHits.resize(n);
+}
+
+void KFPTrackVector::Set(KFPTrackVector& v, int vSize, int offset)
+{
+  /** Copies "vSize" tracks from the KFPTrackVector "v" to the current object.
+   ** Tracks are put starting from the "offset" position.
+   ** \param[in] v - external KFPTrackVector with input tracks to be copied
+   ** \param[in] vSize - number of tracks to be copied from "v"
+   ** \param[in] offset - offset position in the current object, starting from which input tracks will be stored
+   **/
+  for(int iV=0; iV<vSize; iV++)
+  {
+    for(int i=0; i<6; i++)
+      fP[i][offset+iV] = v.fP[i][iV];
+    for(int i=0; i<21; i++)
+      fC[i][offset+iV] = v.fC[i][iV];
+#ifdef NonhomogeneousField
+    for(int i=0; i<10; i++)
+      fField[i][offset+iV] = v.fField[i][iV];
+#endif
+//       fChi2[offset+iV] = v.fChi2[iV];
+//       fNDF[offset+iV] = v.fNDF[iV];
+    fId[offset+iV] = v.fId[iV];
+    fPDG[offset+iV] = v.fPDG[iV];
+    fQ[offset+iV] = v.fQ[iV];
+    fPVIndex[offset+iV] = v.fPVIndex[iV];
+    fNPixelHits[offset+iV] = v.fNPixelHits[iV];
+  }
+}
+
+void KFPTrackVector::SetTracks(const KFPTrackVector& track, const kfvector_uint& trackIndex, const int nIndexes)
+{
+  /** The current object is resised to "nIndexes", tracks with indices "trackIndex" are copied to the current object.
+   ** \param[in] track - input vector of tracks
+   ** \param[in] trackIndex - indices of tracks in a vector "track", which should be stored to the current object
+   ** \param[in] nIndexes - number of tracks to be copied, defines the new size of the current object
+   **/
+  if(nIndexes == 0) return;
+  
+  Resize(nIndexes);
+
+  for(int iP=0; iP<6; iP++)
+  {
+    int iElement = 0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      float_v& vec = reinterpret_cast<float_v&>(fP[iP][iElement]);
+      vec.gather(&(track.fP[iP][0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    float_v& vec = reinterpret_cast<float_v&>(fP[iP][iElement]);
+    vec.gather(&(track.fP[iP][0]), index, simd_cast<float_m>(iElement+uint_v::IndexesFromZero()<nIndexes));
+    
+  }
+  for(int iC=0; iC<21; iC++)
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      float_v& vec = reinterpret_cast<float_v&>(fC[iC][iElement]);
+      vec.gather(&(track.fC[iC][0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    float_v& vec = reinterpret_cast<float_v&>(fC[iC][iElement]);
+    vec.gather(&(track.fC[iC][0]), index, simd_cast<float_m>(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+#ifdef NonhomogeneousField
+  for(int iP=0; iP<10; iP++)
+  {
+    int iElement = 0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      float_v& vec = reinterpret_cast<float_v&>(fField[iP][iElement]);
+      vec.gather(&(track.fField[iP][0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    float_v& vec = reinterpret_cast<float_v&>(fField[iP][iElement]);
+    vec.gather(&(track.fField[iP][0]), index, simd_cast<float_m>(iElement+uint_v::IndexesFromZero()<nIndexes)); 
+  }
+#endif
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fId[iElement]);
+      vec.gather(&(track.fId[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fId[iElement]);
+    vec.gather(&(track.fId[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fPDG[iElement]);
+      vec.gather(&(track.fPDG[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fPDG[iElement]);
+    vec.gather(&(track.fPDG[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fQ[iElement]);
+      vec.gather(&(track.fQ[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fQ[iElement]);
+    vec.gather(&(track.fQ[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fPVIndex[iElement]);
+      vec.gather(&(track.fPVIndex[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fPVIndex[iElement]);
+    vec.gather(&(track.fPVIndex[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+  {
+    int iElement=0;
+    for(iElement=0; iElement<nIndexes-float_vLen; iElement += float_vLen)
+    {
+      const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+      int_v& vec = reinterpret_cast<int_v&>(fNPixelHits[iElement]);
+      vec.gather(&(track.fNPixelHits[0]), index);
+    }
+    const uint_v& index = reinterpret_cast<const uint_v&>(trackIndex[iElement]);
+    int_v& vec = reinterpret_cast<int_v&>(fNPixelHits[iElement]);
+    vec.gather(&(track.fNPixelHits[0]), index, int_m(iElement+uint_v::IndexesFromZero()<nIndexes));
+  }
+}
+
+void KFPTrackVector::GetTrack(KFPTrack& track, const int n)
+{ 
+  /** Copies track with index "n" for the current object to the KFPTrack object "track".
+   ** \param[out] track - KFPTrack object, where track with index "n" is copied
+   ** \param[in] n - index of the track to be copied
+   **/
+  track.SetParameters(fP[0][n],fP[1][n],fP[2][n],fP[3][n],fP[4][n],fP[5][n]);
+  for(int i=0; i<21; i++)
+    track.SetCovariance(i,fC[i][n]);
+//     track.SetChi2(fChi2[n]);
+//     track.SetNDF(fNDF[n]);
+  track.SetId(fId[n]);
+  track.SetCharge(fQ[n]);
+  
+#ifdef NonhomogeneousField
+    for(int i=0; i<10; i++)
+      track.SetFieldCoeff( fField[i][n], i);
+#endif
+}
+
+void KFPTrackVector::RotateXY( float_v alpha, int firstElement )
+{
+  /** Rotates SIMD vector of tracks starting from the position "firstElement" onto the angles "alpha" in the XY plane.
+   ** Rotation matrix is:
+   \verbatim
+   {  cos(A), -sin(A),  0,        0,        0,   0 }
+   {  sin(A),  cos(A),  0,        0,        0,   0 }
+   {       0,       0,  1,        0,        0,   0 }
+   {       0,       0,  0,   cos(A),  -sin(A),   0 }
+   {       0,       0,  0,   sin(A),   cos(A),   0 }
+   {       0,       0,  0,        0,        0,   1 }
+   \endverbatim
+   ** \param[in] alpha - rotation angles
+   ** \param[in] firstElement - track index, starting from which SIMD vector of tracks will be rotated
+   **/
+  
+  const float_v cA = KFPMath::Cos( alpha );
+  const float_v sA = KFPMath::Sin( alpha );
+
+  const float_v xInit = reinterpret_cast<const float_v&>(fP[0][firstElement]);
+  const float_v yInit = reinterpret_cast<const float_v&>(fP[1][firstElement]);
+
+  float_v& x = reinterpret_cast<float_v&>(fP[0][firstElement]);
+  float_v& y = reinterpret_cast<float_v&>(fP[1][firstElement]);
+  
+  x = -(xInit*sA +  yInit*cA);
+  y = xInit*cA -  yInit*sA;
+
+  const float_v pxInit = reinterpret_cast<const float_v&>(fP[3][firstElement]);
+  const float_v pyInit = reinterpret_cast<const float_v&>(fP[4][firstElement]);
+
+  float_v& px = reinterpret_cast<float_v&>(fP[3][firstElement]);
+  float_v& py = reinterpret_cast<float_v&>(fP[4][firstElement]);
+  
+  px = -(pxInit*sA +  pyInit*cA);
+  py = pxInit*cA -  pyInit*sA;
+
+  float_v cov[21];
+  for(int iC=0; iC<21; iC++)
+    cov[iC] = reinterpret_cast<const float_v&>(fC[iC][firstElement]);
+
+  reinterpret_cast<float_v&>(fC[0][firstElement]) = cA*cA*  cov[2] + 2* cA* cov[1]* sA + cov[0]*sA* sA;
+  
+  reinterpret_cast<float_v&>(fC[1][firstElement]) = -(cA*cA * cov[1]) + cA* (-cov[0] + cov[2])* sA + cov[1]*sA* sA;
+  reinterpret_cast<float_v&>(fC[2][firstElement]) = cA*cA*  cov[0] - 2* cA* cov[1]* sA + cov[2]*sA* sA; 
+  
+  reinterpret_cast<float_v&>(fC[3][firstElement]) = -(cA* cov[4]) - cov[3]* sA;
+  reinterpret_cast<float_v&>(fC[4][firstElement]) = cA* cov[3] - cov[4]* sA;
+//  reinterpret_cast<float_v&>(fC[5][firstElement]) = cov[5]; 
+  
+  reinterpret_cast<float_v&>(fC[6][firstElement]) = cA*cA*  cov[11] + cA *(cov[10] + cov[7])* sA + cov[6]*sA* sA;
+  reinterpret_cast<float_v&>(fC[7][firstElement]) = -(cA*cA * cov[10]) + cA* (cov[11] - cov[6])* sA + cov[7] *sA*sA;
+  reinterpret_cast<float_v&>(fC[8][firstElement]) = -(cA *cov[12]) - cov[8] *sA;
+  reinterpret_cast<float_v&>(fC[9][firstElement]) = cA*cA*  cov[14] + 2 *cA* cov[13]* sA + cov[9]* sA*sA;
+
+  reinterpret_cast<float_v&>(fC[10][firstElement]) = -(cA*cA*  cov[7]) + cA* (cov[11] - cov[6])* sA + cov[10]*sA* sA; 
+  reinterpret_cast<float_v&>(fC[11][firstElement]) = cA*cA*  cov[6] - cA* (cov[10] + cov[7]) *sA + cov[11]*sA* sA;
+  reinterpret_cast<float_v&>(fC[12][firstElement]) = cA* cov[8] - cov[12]* sA; 
+  reinterpret_cast<float_v&>(fC[13][firstElement]) = -(cA*cA*  cov[13]) + cA* (cov[14] - cov[9])* sA + cov[13]* sA*sA;
+  reinterpret_cast<float_v&>(fC[14][firstElement]) = cA*cA*  cov[9] - 2* cA* cov[13]* sA + cov[14]* sA*sA;
+  
+  reinterpret_cast<float_v&>(fC[15][firstElement]) = -(cA* cov[16]) - cov[15]* sA;
+  reinterpret_cast<float_v&>(fC[16][firstElement]) = cA* cov[15] - cov[16]* sA;
+//  reinterpret_cast<float_v&>(fC[17][firstElement]) = cov[17]; 
+  reinterpret_cast<float_v&>(fC[18][firstElement]) = -(cA* cov[19]) - cov[18]* sA;
+  reinterpret_cast<float_v&>(fC[19][firstElement]) = cA* cov[18] - cov[19]* sA;
+//  reinterpret_cast<float_v&>(fC[20][firstElement]) = cov[20];
+} // RotateXY
+
+
+void KFPTrackVector::PrintTrack(int n)
+{
+  /** Prints parameters of the track with index "n".
+   ** \param[in] n - index of track to be printed
+   **/
+  for(int i=0; i<6; i++)
+    std::cout << fP[i][n] << " ";
+  std::cout << std::endl;
+  
+  for(int i=0; i<21; i++)
+    std::cout << fC[i][n] << " ";
+  std::cout << std::endl;
+  
+  std::cout  <<  fId[n] << " " << fPDG[n] << " " << fQ[n] << " " << fPVIndex[n]  << " " << fNPixelHits[n] << std::endl;
+}
+
+void KFPTrackVector::Print()
+{
+  /** Prints all field of the current object. **/
+  
+  std::cout << "NTracks " << Size() << std::endl;
+  if( Size()==0 ) return;
+  
+  std::cout << "Parameters: " << std::endl;
+  for(int iP=0; iP<6; iP++)
+  {
+    std::cout << "  iP " << iP << ": ";
+    for(int iTr=0; iTr<Size(); iTr++)
+      std::cout << Parameter(iP)[iTr]<< " ";
+    std::cout << std::endl;
+  }
+  
+  std::cout << "Cov matrix: " << std::endl;
+  for(int iC=0; iC<21; iC++)
+  {
+    std::cout << "  iC " << iC << ": ";
+    for(int iTr=0; iTr<Size(); iTr++)
+      std::cout << Covariance(iC)[iTr]<< " ";
+    std::cout << std::endl;
+  }
+
+  std::cout << "Id: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  Id()[iTr] << " ";
+  std::cout << std::endl;
+  
+  std::cout << "Pdg: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  PDG()[iTr] << " ";
+  std::cout << std::endl;
+
+  std::cout << "Q: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  Q()[iTr] << " ";
+  std::cout << std::endl;
+  
+  std::cout << "PV index: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  PVIndex()[iTr] << " ";
+  std::cout << std::endl;
+  
+  std::cout << "fNPixelHits: " << std::endl;
+  for(int iTr=0; iTr<Size(); iTr++)
+    std::cout <<  NPixelHits()[iTr] << " ";
+  std::cout << std::endl;
+  
+#ifdef NonhomogeneousField
+  std::cout << "Field: " << std::endl;
+  for(int iF=0; iF<6; iF++)
+  {
+    std::cout << "  iF " << iF << ": ";
+    for(int iTr=0; iTr<Size(); iTr++)
+      std::cout << FieldCoefficient(iF)[iTr]<< " ";
+    std::cout << std::endl;
+  }
+#endif
+  
+  std::cout << "Last particle index: " << std::endl;
+  std::cout << LastElectron() << " "
+            << LastMuon() << " "
+            << LastPion() << " "
+            << LastKaon() << " "
+            << LastProton() << " "
+            << LastDeuteron() << " "
+            << LastTritium() << " "
+            << LastHe3() << " "
+            << LastHe4() << std::endl;
+}
+  
\ No newline at end of file
diff --git a/external/KFParticle/KFParticle/KFPTrackVector.h b/external/KFParticle/KFParticle/KFPTrackVector.h
new file mode 100644
index 0000000000000000000000000000000000000000..827b46ab456cd0db2b21316c4b4bdcc4462eca5b
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPTrackVector.h
@@ -0,0 +1,396 @@
+//----------------------------------------------------------------------------
+// SIMDised vector approach for track representation
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPTrackVector_H
+#define KFPTrackVector_H
+
+#include "KFPTrack.h"
+#include "KFParticleDef.h"
+
+/** @class KFPTrackVector
+ ** @brief A class to store vectors of input tracks in the cartesian parametrisation.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** A track is described with the state vector { X, Y, Z, Px, Py, Pz }
+ ** and the corresponding covariance matrix. Also contains charge of the track,
+ ** unique Id, assigned PDG hypothesis, charge, index of the corresponding
+ ** primary vertex in case of primary track, number of hits from precise
+ ** detectors (like MVD in CBM, HFT in STAR, ITS in ALICE, etc.) 
+ ** and the magnetic field approximation along the track trajectory 
+ ** (in case of nonhomogeneous CBM-like field). \n
+ ** The data model implemented in the class is "Structure Of Arrays":
+ ** each parameter is stroed in a separate vector. Such data structure
+ ** allows fast vectorised access to the aligned data providing the
+ ** maximum possible speed for data reading, and at the same time easy
+ ** random access to the data members. Tracks are sorted by KFParticleTopoReconstructor::SortTracks():
+ ** electrons, muons, pions, tracks without PID, kaons, protons, deuterons, tritons, He3, He4.
+ **/
+
+class KFPTrackVector
+{
+  friend class KFParticleTopoReconstructor;
+ public:
+  KFPTrackVector():fId(), fPDG(), fQ(), fPVIndex(), fNPixelHits(), fNE(0), fNMu(0), fNPi(0), fNK(0), fNP(0), fND(0), fNT(0), fNHe3(0), fNHe4(0) { }
+  ~KFPTrackVector() { }
+
+  /**Returns size of the vectors. All data vectors have the same size. */
+  int Size() const { return fP[0].size(); }
+  int DataSize() const { 
+    /**Returns size of the memory in floats (4 bytes or 32 bits) allocated by the current object. */
+    const int& size = fP[0].size();
+    
+    const int dataSize = size * 32 
+#ifdef NonhomogeneousField
+                       + size * 10
+#endif
+                       + 9;
+    return dataSize; 
+  }
+  
+  void Resize(const int n);
+  void Set(KFPTrackVector& v, int vSize, int offset);
+  void SetTracks(const KFPTrackVector& track, const kfvector_uint& trackIndex, const int nIndexes);
+  void GetTrack(KFPTrack& track, const int n);
+  
+  const kfvector_float& X()  const { return fP[0]; } ///< Returns constant reference to the vector with X coordinates.
+  const kfvector_float& Y()  const { return fP[1]; } ///< Returns constant reference to the vector with Y coordinates.
+  const kfvector_float& Z()  const { return fP[2]; } ///< Returns constant reference to the vector with Z coordinates.
+  const kfvector_float& Px() const { return fP[3]; } ///< Returns constant reference to the vector with Px components of momentum.
+  const kfvector_float& Py() const { return fP[4]; } ///< Returns constant reference to the vector with Py components of momentum.
+  const kfvector_float& Pz() const { return fP[5]; } ///< Returns constant reference to the vector with Pz components of momentum.
+
+  const kfvector_float& Parameter(const int i)  const { return fP[i]; }  ///< Returns constant reference to the track parameter vector with index "i".
+  const kfvector_float& Covariance(const int i)  const { return fC[i]; } ///< Returns constant reference to the vector of the covariance matrix elements with index "i".
+#ifdef NonhomogeneousField
+  const kfvector_float& FieldCoefficient(const int i)  const { return fField[i]; } ///< Returns constant reference to the magnetic field coefficient with index "i".
+#endif
+
+  const kfvector_int& Id()         const { return fId; }      ///< Returns constant reference to the vector with track Id KFPTrackVector::fId.
+  const kfvector_int& PDG()        const { return fPDG; }     ///< Returns constant reference to the vector with assigned PDG hypothesis KFPTrackVector::fPDG.
+  const kfvector_int& Q()          const { return fQ; }       ///< Returns constant reference to the vector with charge KFPTrackVector::fQ.
+  const kfvector_int& PVIndex()    const { return fPVIndex; } ///< Returns constant reference to the vector with indices of corresponding primary vertex KFPTrackVector::fPVIndex.
+  const kfvector_int& NPixelHits() const { return fNPixelHits; } ///< Returns constant reference to the vector with the number of precise measurements KFPTrackVector::fNPixelHits.
+
+  float Pt(const int n) const { return sqrt(fP[3][n]*fP[3][n]+fP[4][n]*fP[4][n]); } ///< Returns transverse momentum of the track with index "n".
+  float P(const int n)  const { return sqrt(fP[3][n]*fP[3][n]+fP[4][n]*fP[4][n]+fP[5][n]*fP[5][n]); } ///< Returns momentum of the track with index "n".
+
+  //modifiers 
+  void SetParameter (float value, int iP, int iTr) { fP[iP][iTr] = value; } ///< Sets the "value" of the parameter "iP" of the track with index "iTr".
+  void SetCovariance(float value, int iC, int iTr) { fC[iC][iTr] = value; } ///< Sets the "value" of the element of covariance matrix "iC" of the track with index "iTr".
+  
+  void SetParameter (const float_v& value, int iP, int iTr);
+  void SetCovariance(const float_v& value, int iC, int iTr);
+  
+#ifdef NonhomogeneousField
+  void SetFieldCoefficient(float value, int iP, int iTr) { fField[iP][iTr] = value; } ///< Sets the "value" of the field coefficient "iP" of the track with index "iTr".
+#endif
+  void SetId          (int value, int iTr) { fId[iTr] = value; }         ///< Sets Id of the track with index "iTr".
+  void SetPDG         (int value, int iTr) { fPDG[iTr] = value; }        ///< Sets PDG hypothesis of the track with index "iTr".
+  void SetQ           (int value, int iTr) { fQ[iTr] = value; }          ///< Sets charge of the track with index "iTr".
+  void SetPVIndex     (int value, int iTr) { fPVIndex[iTr] = value; }    ///< Sets index of the corresponding primary vertex of the track with index "iTr".
+  void SetNPixelHits  (int value, int iTr) { fNPixelHits[iTr] = value; } ///< Sets number of precise measurement of the track with index "iTr".
+  void SetLastElectron(int n)              { fNE = n; }                  ///< Sets index of the last electron.
+  void SetLastMuon    (int n)              { fNMu = n; }                 ///< Sets index of the last muon.
+  void SetLastPion    (int n)              { fNPi = n; }                 ///< Sets index of the last pion.
+  void SetLastKaon    (int n)              { fNK = n; }                  ///< Sets index of the last kaon.
+  void SetLastProton  (int n)              { fNP = n; }                  ///< Sets index of the last proton.
+  void SetLastDeuteron(int n)              { fND = n; }                  ///< Sets index of the last deuteron.
+  void SetLastTritium (int n)              { fNT = n; }                  ///< Sets index of the last triton.
+  void SetLastHe3     (int n)              { fNHe3 = n; }                ///< Sets index of the last He3.
+  void SetLastHe4     (int n)              { fNHe4 = n; }                ///< Sets index of the last He4.
+  
+  void RecalculateLastIndex()
+  {
+    /** Recalculate the last index of each track specie. Should be called after track sorting. */
+    fNE = 0; fNMu = 0; fNPi = 0; fNK = 0; fNP = 0; fND = 0; fNT = 0; fNHe3 = 0; fNHe4 = 0;
+    for(int i=0; i<Size(); i++)
+    {
+      switch (abs(fPDG[i]))
+      {
+        case         11: fNE++; break;
+        case         13: fNMu++; break;
+        case         19: fNMu++; break;
+        case        211: fNPi++; break;
+        case          1: fNPi++; break;
+        case          3: fNPi++; break;
+        case        321: fNK++; break;
+        case       2212: fNP++; break;
+        case 1000010020: fND++; break;
+        case 1000010030: fNT++; break;
+        case 1000020030: fNHe3++; break;
+        case 1000020040: fNHe4++; break;
+      }
+    }
+    
+    fNMu += fNE; fNPi += fNMu; fNK  += fNPi; fNP  += fNK;
+    fND += fNP; fNT += fND; fNHe3 += fNT; fNHe4 += fNHe3;
+  }
+  
+  int FirstElectron()  { return 0; } ///< Returns index of the first electron.
+  const int& LastElectron()  const { return fNE; } ///< Returns index of the last electron.
+  int NElectrons() { return fNE; } ///< Returns number of electrons.
+  int FirstMuon()  { return int(fNE/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first muon.
+  const int& LastMuon()  const { return fNMu; } ///< Returns index of the last muon.
+  int NMuons() { return fNMu - fNE; } ///< Returns number of muons.
+  int FirstPion()  { return int(fNMu/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first pion.
+  const int& LastPion()  const { return fNPi; } ///< Returns index of the last pion.
+  int NPions() { return fNPi - fNMu; } ///< Returns number of pions.
+  int FirstKaon()  { return int(fNPi/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first kaon.
+  const int& LastKaon()  const { return fNK; } ///< Returns index of the last kaon.
+  int NKaons() { return fNK - fNPi; } ///< Returns number of kaons.
+  int FirstProton()  { return int(fNK/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first proton.
+  const int& LastProton()  const { return fNP; } ///< Returns index of the last proton.
+  int NProtons() { return fNP - fNK; } ///< Returns number of protons.
+  int FirstDeuteron()  { return int(fNP/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first deuteron.
+  const int& LastDeuteron()  const { return fND; } ///< Returns index of the last deuteron.
+  int NDeuterons() { return fND - fNP; } ///< Returns number of deuterons.
+  int FirstTritium()  { return int(fND/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first triton.
+  const int& LastTritium()  const { return fNT; } ///< Returns index of the last triton.
+  int NTritiums() { return fNT - fND; } ///< Returns number of tritons.
+  int FirstHe3()  { return int(fNT/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first He3.
+  const int& LastHe3()  const { return fNHe3; } ///< Returns index of the last He3.
+  int NHe3s() { return fNHe3 - fNT; } ///< Returns number of He3 tracks.
+  int FirstHe4()  { return int(fNHe3/float_vLen)*float_vLen; } ///< Returns index of the first element of the SIMD vector with the first He4.
+  const int& LastHe4()  const { return fNHe4; } ///< Returns index of the last He4.
+  int NHe4s() { return fNHe4 - fNHe3; } ///< Returns number of He4 tracks.
+  
+  void AddElectron() {fNE++;}   ///< Increases by one index of the last electron.
+  void AddMuon()     {fNMu++;}  ///< Increases by one index of the last muon.
+  void AddPion()     {fNPi++;}  ///< Increases by one index of the last pion.
+  void AddKaon()     {fNK++;}   ///< Increases by one index of the last kaon.
+  void AddProton()   {fNP++;}   ///< Increases by one index of the last proton.
+  void AddDeuteron() {fND++;}   ///< Increases by one index of the last deuteron.
+  void AddTririum()  {fNT++;}   ///< Increases by one index of the last triton.
+  void AddHe3()      {fNHe3++;} ///< Increases by one index of the last He3.
+  void AddHe4()      {fNHe4++;} ///< Increases by one index of the last He4.
+
+  void RotateXY( float_v alpha, int firstElement );
+  
+  void PrintTrack(int n);
+  void Print();
+  
+  const KFPTrackVector& operator = (const KFPTrackVector& track)
+  {
+    /** Operator to copy one KFPTrackVector object to another. Makes one-to-one copy.*/
+    const int localSize = track.Size();
+    
+    for(int i=0; i<6; i++)
+    {
+      fP[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fP[i][n] = track.fP[i][n];
+    }
+    
+    for(int i=0; i<21; i++)
+    {
+      fC[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fC[i][n] = track.fC[i][n];
+    }
+
+#ifdef NonhomogeneousField
+    for(int i=0; i<10; i++)
+    {
+      fField[i].resize(localSize);
+      for(int n=0; n<localSize; n++)
+        fField[i][n] = track.fField[i][n];
+    }
+#endif
+
+    fId.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fId[n] = track.fId[n];
+
+    fPDG.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fPDG[n] = track.fPDG[n];
+
+    fQ.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fQ[n] = track.fQ[n];
+
+    fPVIndex.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fPVIndex[n] = track.fPVIndex[n];
+    
+    fNPixelHits.resize(localSize);
+    for(int n=0; n<localSize; n++)
+      fNPixelHits[n] = track.fNPixelHits[n];
+    
+    fNE   = track.fNE;
+    fNMu  = track.fNMu;
+    fNPi  = track.fNPi;
+    fNK   = track.fNK;
+    fNP   = track.fNP;
+    fND   = track.fND;
+    fNT   = track.fNT;
+    fNHe3 = track.fNHe3;
+    fNHe4 = track.fNHe4;
+    
+    return *this;
+  }
+  
+  void SetDataToVector(int* data, int& offset)
+  {
+    /** Copies entire vector to the provided memory starting form the position "offset".
+     ** The function is used in KFPInputData::SetDataToVector().
+     ** \param[out] data - pointer to the memory where the track vectors should be copied; since all fields of
+     ** KFPTrackVector are of the same size (int or float) pointer can be safely casted to int*
+     ** \param[in,out] offset - starting position in "data" where vectors should be copied; after all vectors are
+     ** copied the offset is shifted on the size of the written object so the next KFPTrackVector object
+     ** can be copied to the "data"
+     **/
+    for(int iP=0; iP<6; iP++)
+    {
+      memcpy( &(data[offset]), &(fP[iP][0]), Size()*sizeof(float));
+      offset += Size();
+    }
+    
+    for(int iC=0; iC<21; iC++)
+    {
+      memcpy( &(data[offset]), &(fC[iC][0]), Size()*sizeof(float));
+      offset += Size();
+    }
+    
+    memcpy( &(data[offset]), &(fId[0]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(data[offset]), &(fPDG[0]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(data[offset]), &(fQ[0]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(data[offset]), &(fPVIndex[0]), Size()*sizeof(float));
+    offset += Size();
+
+    memcpy( &(data[offset]), &(fNPixelHits[0]), Size()*sizeof(float));
+    offset += Size();
+    
+#ifdef NonhomogeneousField
+    for(int iF=0; iF<10; iF++)
+    {
+      memcpy( &(data[offset]), &(fField[iF][0]), Size()*sizeof(float));
+      offset += Size();
+    }
+#endif
+
+    data[offset] = fNE;   offset++;
+    data[offset] = fNMu;  offset++;
+    data[offset] = fNPi;  offset++;
+    data[offset] = fNK;   offset++;
+    data[offset] = fNP;   offset++;
+    data[offset] = fND;   offset++;
+    data[offset] = fNT;   offset++;
+    data[offset] = fNHe3; offset++;
+    data[offset] = fNHe4; offset++;
+  }
+  
+  void ReadDataFromVector(int* data, int& offset)
+  {
+    /** Copies entire vector from the provided memory starting form the position "offset".
+     ** The function is used in KFPInputData::ReadDataFromVector().
+     ** \param[in] data - pointer to the memory with the track vectors; since all fields of
+     ** KFPTrackVector are of the same size (int or float) pointer can be safely casted to int*
+     ** \param[in,out] offset - starting position of the memory to be copied; after all vectors are
+     ** copied the offset is shifted on the size of the read object so the next KFPTrackVector object
+     ** can be copied 
+     **/
+    for(int iP=0; iP<6; iP++)
+    {
+      memcpy( &(fP[iP][0]), &(data[offset]), Size()*sizeof(float));
+      offset += Size();
+    }
+    
+    for(int iC=0; iC<21; iC++)
+    {
+      memcpy( &(fC[iC][0]), &(data[offset]), Size()*sizeof(float));
+      offset += Size();
+    }
+    
+    memcpy( &(fId[0]), &(data[offset]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(fPDG[0]), &(data[offset]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(fQ[0]), &(data[offset]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(fPVIndex[0]), &(data[offset]), Size()*sizeof(float));
+    offset += Size();
+    
+    memcpy( &(fNPixelHits[0]), &(data[offset]), Size()*sizeof(float));
+    offset += Size();
+    
+#ifdef NonhomogeneousField
+    for(int iF=0; iF<10; iF++)
+    {
+      memcpy( &(fField[iF][0]), &(data[offset]), Size()*sizeof(float));
+      offset += Size();
+    }
+#endif
+
+    fNE = data[offset];   offset++;
+    fNMu = data[offset];  offset++;
+    fNPi = data[offset];  offset++;
+    fNK = data[offset];   offset++;
+    fNP = data[offset];   offset++;
+    fND = data[offset];   offset++;
+    fNT = data[offset];   offset++;
+    fNHe3 = data[offset]; offset++;
+    fNHe4 = data[offset]; offset++;
+  }
+  
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(float_v)); }     ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(float_v)); }   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);} ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                        ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                      ///< delete operator for the SIMD-alligned dynamic memory release
+  
+ private:  
+  kfvector_float fP[6];  ///< Vectors with parameters of the track : X, Y, Z, Px, Py, Pz.
+  kfvector_float fC[21]; ///< Vectors with covariance matrix of the track parameters stroed in a lower triangular form.
+
+  kfvector_int fId;         ///< Vector with the unique Id of tracks.
+  kfvector_int fPDG;        ///< Vector with the PDG hypothesis.
+  kfvector_int fQ;          ///< Vector with the charge of the tracks.
+  kfvector_int fPVIndex;    ///< Vector with the index of the corresponding primary vertex. If track is considered secondary "-1" is stored.
+  kfvector_int fNPixelHits; ///< Vector with the number of hits from precise detectors (like MVD in CBM, HFT in STAR, ITS in ALICE, etc.) 
+  
+  /** The coefficients of the field approximation of each field component along the track trajectory using parabolas: \n
+   ** cx0 = fField[0], cx1 = fField[1], cx2 = fField[2] - coefficients of the Bx approximation; \n
+   ** cy0 = fField[3], cy1 = fField[4], cy2 = fField[5] - coefficients of the By approximation; \n
+   ** cz0 = fField[6], cz1 = fField[7], cz2 = fField[8] - coefficients of the Bz approximation; \n
+   ** z0 = fField[9] - reference Z coordinate. \n
+   ** Bx(z) = cx0 + cx1*(z-z0) + cx2*(z-z0)^2 \n
+   ** By(z) = cy0 + cy1*(z-z0) + cy2*(z-z0)^2 \n
+   ** Bz(z) = cz0 + cz1*(z-z0) + cz2*(z-z0)^2
+   **/
+#ifdef NonhomogeneousField
+  kfvector_float fField[10];
+#endif
+  
+  int fNE;   ///< Index of the last electron.
+  int fNMu;  ///< Index of the last muon.
+  int fNPi;  ///< Index of the last pion (plus tracks without PID).
+  int fNK;   ///< Index of the last kaon.
+  int fNP;   ///< Index of the last proton.
+  int fND;   ///< Index of the last deuteron.
+  int fNT;   ///< Index of the last triton.
+  int fNHe3; ///< Index of the last He3.
+  int fNHe4; ///< Index of the last He4.
+} __attribute__((aligned(sizeof(float_v))));
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFPVertex.cxx b/external/KFParticle/KFParticle/KFPVertex.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..76815675afcb21d2e014e5a8aa79ec8848239ff6
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPVertex.cxx
@@ -0,0 +1,20 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPVertex.h"
+
+KFPVertex::KFPVertex():fChi2(-1.f), fNContributors(0), fNDF(-1)  
+{ 
+  for(int iP=0; iP<3; iP++)
+    fP[iP] = 0;
+  for(int iC=0; iC<6; iC++)
+    fC[iC] = 0;
+}
diff --git a/external/KFParticle/KFParticle/KFPVertex.h b/external/KFParticle/KFParticle/KFPVertex.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0ca45bb398a578c185575ae92adbde4ea1e45a0
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFPVertex.h
@@ -0,0 +1,124 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPVertex_H
+#define KFPVertex_H
+
+/** @class KFPVertex
+ ** @brief A scalar class for storage of the vertex in the cartesian parametrisation.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** A vertex is described with the state vector { X, Y, Z }
+ ** and the corresponding covariance matrix. Also contains chi2 of the fit,
+ ** corresponding number of degrees of freedom,
+ ** and number of tracks which were used to construct current vertex.
+ ** The class is used to provide an external vertex through the interfaces
+ ** to the KF Particle package.
+ **/
+
+class KFPVertex
+{
+ public:
+  KFPVertex();
+  ~KFPVertex() { }
+
+/*  KFPVertex(const KFPVertex& vVert); 
+  KFPVertex& operator=(const KFPVertex& vVert);*/
+
+  float GetX() const { return fP[0]; } ///< Returns X coordinate of the vertex.
+  float GetY() const { return fP[1]; } ///< Returns Y coordinate of the vertex.
+  float GetZ() const { return fP[2]; } ///< Returns Z coordinate of the vertex.
+  
+  /** Copies position of the vertex to the output array of floats. \param[out] position - the output array with the position of the vertex **/
+  void GetXYZ(float *position) const {position[0] = fP[0]; position[1] = fP[1]; position[2] = fP[2];}
+  /** Copies position of the vertex to the output array of doubles. \param[out] position - the output array with the position of the vertex **/
+  void GetXYZ(double *position) const {position[0] = fP[0]; position[1] = fP[1]; position[2] = fP[2];}
+  void GetCovarianceMatrix(float *covmatrix) const
+  {
+    /** Copies the covariance matrix of the vertex to the array of floats.
+     ** \param[out] covmatrix[6] - the output array, where the covariance matrix is copied
+     **/
+    for (int i=0; i<6; i++)
+      covmatrix[i] = fC[i];
+  }
+  void GetCovarianceMatrix(double *covmatrix) const
+  {
+    /** Copies the covariance matrix of the vertex to the array of doubles.
+     ** \param[out] covmatrix[6] - the output array, where the covariance matrix is copied
+     **/
+    for (int i=0; i<6; i++)
+      covmatrix[i] = fC[i];
+  }
+
+  float GetChi2perNDF() const { return fChi2/fNDF; } ///< Returns Chi2/NDF of the vertex, NDF is a number of degrees of freedom.
+  float GetChi2()       const { return fChi2;      } ///< Returns Chi2 of the vertex fit.
+  int   GetNDF()        const { return fNDF; }       ///< Returns number of degrees of freedom of the vertex.
+  int   GetNContributors() const { return fNContributors; } ///< Returns number of tracks which were used for construction of the vertex
+  
+  float GetParameter(int i) const { return fP[i]; }  ///< Returns parameter "i" of the vertex. \param[in] i - index of the parameter to be returned
+  float GetCovariance(int i) const { return fC[i]; } ///< Returns element of the covariance matrix "i" of the vertex. \param[in] i - index of the element to be returned
+
+  /** Sets position { X, Y, Z } of the vertex from the input array of doubles.
+    ** \param[in] position - input array with the vertex parameters
+    **/
+  void SetXYZ(float *position) { fP[0] = position[0]; fP[1] = position[1]; fP[2] = position[2]; }
+  /** Sets position { X, Y, Z } of the vertex.
+   ** \param[in] x - X coordinate to be set
+   ** \param[in] y - Y coordinate to be set
+   ** \param[in] z - Z coordinate to be set
+   **/
+  void SetXYZ(float x, float y, float z) { fP[0] = x; fP[1] = y; fP[2] = z; }
+  void SetX(float x)      { fP[0] = x; } ///< Sets X coordinate of the vertex
+  void SetY(float y)      { fP[1] = y; } ///< Sets Y coordinate of the vertex
+  void SetZ(float z)      { fP[2] = z; } ///< Sets Z coordinate of the vertex
+  void SetChi2(float chi) { fChi2 = chi; } ///< Sets Chi2 of the vertex
+  void SetNDF(int ndf)    { fNDF = ndf; } ///< Sets number of degrees of freedom of the vertex
+  void SetNContributors(int nc) { fNContributors = nc; } ///< Sets number of tracks which were used for construction of the vertex
+
+  void SetCovarianceMatrix(float *C)
+  {
+    /** Sets the covariance matrix from the input array of floats.
+     ** \param[in] C[6] - array with the input elements of the covariance matrix stored in the lower triangular form
+     **/
+    for (int i=0; i<6; i++)
+      fC[i] = C[i];
+  }
+
+  void SetCovarianceMatrix(float C00,float C10,float C11,float C20,float C21,float C22)
+  {
+    /** Sets the covariance matrix from the input array of floats.
+     ** \param[in] C00 - Cxx
+     ** \param[in] C10 - Cxy = Cyx
+     ** \param[in] C11 - Cyy
+     ** \param[in] C20 - Cxz = Czx
+     ** \param[in] C21 - Cyz = Czy
+     ** \param[in] C22 - Czz
+     **/
+    fC[0] = C00;
+    fC[1] = C10;
+    fC[2] = C11;
+    fC[3] = C20;
+    fC[4] = C21;
+    fC[5] = C22;
+  }
+
+ private:
+
+  float fP[3];  ///< Coordinates of the vertex.
+  float fC[6];  ///< Covariance matrix of the vertex parameters.
+  float fChi2;  ///< Chi-square of the vertex fit.
+  int fNContributors; ///< Number of tracks, from which the vertex was built.
+  int fNDF;  ///< Number of degrees of freedom of the vertex fit.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFParticle.cxx b/external/KFParticle/KFParticle/KFParticle.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..afe68599c2b34aafcd4ec732b90f6adb1bb316d2
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticle.cxx
@@ -0,0 +1,492 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  S.Gorbunov, I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class is ALICE interface to general mathematics in KFParticleCore
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#include "KFParticle.h"
+#include "KFParticleDatabase.h"
+
+#include "KFPTrack.h"
+#include "KFPVertex.h"
+
+#ifndef KFParticleStandalone
+ClassImp(KFParticle);
+#endif
+
+
+#ifdef HomogeneousField
+float KFParticle::fgBz = -5.;  //* Bz compoment of the magnetic field
+#endif
+
+KFParticle::KFParticle( const KFParticle &d1, const KFParticle &d2 ): KFParticleBase()
+{
+  /** Constructs a particle from two input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   **/
+  KFParticle mother;
+  mother+= d1;
+  mother+= d2;
+  *this = mother;
+}
+
+void KFParticle::Create( const float Param[], const float Cov[], Int_t Charge, float mass )
+{
+  /** Constructor from a "cartesian" track, mass hypothesis should be provided
+   ** \param[in] Param[6] = { X, Y, Z, Px, Py, Pz } - position and momentum
+   ** \param[in] Cov[21]  - lower-triangular part of the covariance matrix:@n
+   ** \verbatim
+             (  0  .  .  .  .  . )
+             (  1  2  .  .  .  . )
+   Cov[21] = (  3  4  5  .  .  . )
+             (  6  7  8  9  .  . )
+             ( 10 11 12 13 14  . )
+             ( 15 16 17 18 19 20 )
+   \endverbatim
+   ** \param[in] Charge - charge of the particle in elementary charge units
+   ** \param[in] mass - the mass hypothesis
+   **/
+  float C[21];
+  for( int i=0; i<21; i++ ) C[i] = Cov[i];
+  
+  KFParticleBase::Initialize( Param, C, Charge, mass );
+}
+
+void KFParticle::Create( const Double_t Param[], const Double_t Cov[], Int_t Charge, float mass )
+{
+  /** Constructor from a "cartesian" track, mass hypothesis should be provided
+   ** \param[in] Param[6] = { X, Y, Z, Px, Py, Pz } - position and momentum
+   ** \param[in] Cov[21]  - lower-triangular part of the covariance matrix:@n
+   ** \verbatim
+             (  0  .  .  .  .  . )
+             (  1  2  .  .  .  . )
+   Cov[21] = (  3  4  5  .  .  . )
+             (  6  7  8  9  .  . )
+             ( 10 11 12 13 14  . )
+             ( 15 16 17 18 19 20 )
+   \endverbatim
+   ** \param[in] Charge - charge of the particle in elementary charge units
+   ** \param[in] mass - the mass hypothesis
+   **/
+  float P[6];
+  for(int i=0; i<6; i++ ) P[i] = Param[i];
+  float C[21];
+  for( int i=0; i<21; i++ ) C[i] = Cov[i];
+    
+  KFParticleBase::Initialize( P, C, Charge, mass );
+}
+
+KFParticle::KFParticle( const KFPTrack &track, const int PID ): KFParticleBase()
+{
+  /** Constructor from a track in the KF Particle format, PID hypothesis should be provided
+   ** \param[in] track - KFPTrack containing 6 parameters: { X, Y, Z, Px, Py, Pz } and their errors
+   ** \param[in] PID - PID hypothesis, needed to assign mass to a particle and calculate the energy
+   **/
+
+  track.XvYvZv(fP);
+  track.PxPyPz(fP+3);
+  fQ = track.Charge();
+  track.GetCovarianceXYZPxPyPz( fC );
+
+  float mass = KFParticleDatabase::Instance()->GetMass(PID);
+
+  Create(fP,fC,fQ,mass);
+  fChi2 = track.GetChi2();
+  fNDF = track.GetNDF();
+  SetPDG(PID);
+#ifdef NonhomogeneousField
+  for(int iF=0; iF<10; iF++)
+    SetFieldCoeff( track.GetFieldCoeff()[iF], iF);
+#endif
+}
+
+KFParticle::KFParticle( const KFPVertex &vertex ): KFParticleBase()
+{
+  /** Constructor from a vertex in the KF Particle format
+   ** \param[in] vertex - KFPVertex containing 3 parameters: { X, Y, Z } and their errors
+   **/
+
+  vertex.GetXYZ( fP );
+  vertex.GetCovarianceMatrix( fC );  
+  fChi2 = vertex.GetChi2();
+  fNDF = 2*vertex.GetNContributors() - 3;
+  fQ = 0;
+  fAtProductionVertex = 0;
+  fSFromDecay = 0;
+}
+
+Bool_t KFParticle::GetDistanceFromVertexXY( const float vtx[], const float Cv[], float &val, float &err ) const
+{
+  /** Calculates the DCA distance from a vertex together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[in] Cv[3] - lower-triangular part of the covariance matrix of the vertex
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+
+  Bool_t ret = 0;
+  
+  float mP[8];
+  float mC[36];
+  float dsdr[6] = {0.f};
+  const float dS = GetDStoPoint(vtx, dsdr);
+  Transport( dS, dsdr, mP, mC );  
+
+  float dx = mP[0] - vtx[0];
+  float dy = mP[1] - vtx[1];
+  float px = mP[3];
+  float py = mP[4];
+  float pt = sqrt(px*px + py*py);
+  float ex=0, ey=0;
+  if( pt<1.e-4 ){
+    ret = 1;
+    pt = 1.;
+    val = 1.e4;
+  } else{
+    ex = px/pt;
+    ey = py/pt;
+    val = dy*ex - dx*ey;
+  }
+
+  float h0 = -ey;
+  float h1 = ex;
+  float h3 = (dy*ey + dx*ex)*ey/pt;
+  float h4 = -(dy*ey + dx*ex)*ex/pt;
+  
+  err = 
+    h0*(h0*GetCovariance(0,0) + h1*GetCovariance(0,1) + h3*GetCovariance(0,3) + h4*GetCovariance(0,4) ) +
+    h1*(h0*GetCovariance(1,0) + h1*GetCovariance(1,1) + h3*GetCovariance(1,3) + h4*GetCovariance(1,4) ) +
+    h3*(h0*GetCovariance(3,0) + h1*GetCovariance(3,1) + h3*GetCovariance(3,3) + h4*GetCovariance(3,4) ) +
+    h4*(h0*GetCovariance(4,0) + h1*GetCovariance(4,1) + h3*GetCovariance(4,3) + h4*GetCovariance(4,4) );
+
+  if( Cv ){
+    err+= h0*(h0*Cv[0] + h1*Cv[1] ) + h1*(h0*Cv[1] + h1*Cv[2] ); 
+  }
+
+  err = sqrt(fabs(err));
+
+  return ret;
+}
+
+Bool_t KFParticle::GetDistanceFromVertexXY( const float vtx[], float &val, float &err ) const
+{
+  /** Calculates the DCA distance from a vertex together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle only
+   **/
+  return GetDistanceFromVertexXY( vtx, 0, val, err );
+}
+
+
+Bool_t KFParticle::GetDistanceFromVertexXY( const KFParticle &Vtx, float &val, float &err ) const 
+{
+  /** Calculates the DCA distance from a vertex in the KFParticle format together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+
+  return GetDistanceFromVertexXY( Vtx.fP, Vtx.fC, val, err );
+}
+
+#ifdef HomogeneousField
+Bool_t KFParticle::GetDistanceFromVertexXY( const KFPVertex &Vtx, float &val, float &err ) const 
+{
+  /** Calculates the DCA distance from a vertex in the KFPVertex format together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+
+  return GetDistanceFromVertexXY( KFParticle(Vtx), val, err );
+}
+#endif
+
+float KFParticle::GetDistanceFromVertexXY( const float vtx[] ) const
+{
+  /** Returns the DCA distance from a vertex in the XY plane.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   **/
+
+  float val, err;
+  GetDistanceFromVertexXY( vtx, 0, val, err );
+  return val;
+}
+
+float KFParticle::GetDistanceFromVertexXY( const KFParticle &Vtx ) const 
+{
+  /** Returns the DCA distance from a vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+
+  return GetDistanceFromVertexXY( Vtx.fP );
+}
+
+#ifdef HomogeneousField
+float KFParticle::GetDistanceFromVertexXY( const KFPVertex &Vtx ) const 
+{
+  /** Returns the DCA distance from a vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   **/
+
+  return GetDistanceFromVertexXY( KFParticle(Vtx).fP );
+}
+#endif
+
+float KFParticle::GetDistanceFromParticleXY( const KFParticle &p ) const 
+{
+  /** Returns the DCA distance between the current and the second particles in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+  float dx = mP[0]-mP1[0]; 
+  float dy = mP[1]-mP1[1]; 
+  return sqrt(dx*dx+dy*dy);
+}
+
+float KFParticle::GetDeviationFromParticleXY( const KFParticle &p ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from other particle in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+
+  float d[2]={ mP[0]-mP1[0], mP[1]-mP1[1] };
+
+  float sigmaS = .1+10.*sqrt( (d[0]*d[0]+d[1]*d[1] )/
+					(mP1[3]*mP1[3]+mP1[4]*mP1[4] )  );
+
+  float h[2] = { mP1[3]*sigmaS, mP1[4]*sigmaS };       
+  
+  mC1[0] +=h[0]*h[0];
+  mC1[1] +=h[1]*h[0]; 
+  mC1[2] +=h[1]*h[1]; 
+
+  return GetDeviationFromVertexXY( mP1, mC1 )*sqrt(2./1.);
+}
+
+
+float KFParticle::GetDeviationFromVertexXY( const float vtx[], const float Cv[] ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the XY plane.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[in] Cv[3] - lower-triangular part of the covariance matrix of the vertex
+   **/
+
+  float val, err;
+  Bool_t problem = GetDistanceFromVertexXY( vtx, Cv, val, err );
+  if( problem || err<1.e-20 ) return 1.e4;
+  else return val/err;
+}
+
+
+float KFParticle::GetDeviationFromVertexXY( const KFParticle &Vtx ) const  
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+
+  return GetDeviationFromVertexXY( Vtx.fP, Vtx.fC );
+}
+
+#ifdef HomogeneousField
+float KFParticle::GetDeviationFromVertexXY( const KFPVertex &Vtx ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the KFPVertex format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   **/
+
+  KFParticle v(Vtx);
+  return GetDeviationFromVertexXY( v.fP, v.fC );
+}
+#endif
+
+void KFParticle::GetParametersAtPoint(const float* point, const float* pointCov, float* m, float* mV)
+{
+  /** Transports particle to the DCA of the given point and stores obtained parameters and covariance matrix
+   ** \param[in] point[3] - the point to which particle is transported
+   ** \param[in] pointCov[6] - the covariance matrix of the point
+   ** \param[out] m[8] - the parameters of the particle at the DCA point
+   ** \param[out] mV[36] - the covariance matrix of the particle at the DCA point, accounts the covariance matrix of the point as well
+   **/
+    
+  float dsdr[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+  float dS = GetDStoPoint(point, dsdr);
+  float dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0, 0, 0};
+    
+  float F[36], F1[36];
+  for(int i2=0; i2<36; i2++){
+    mV[i2] = 0.f;
+    F[i2]  = 0.f;
+    F1[i2] = 0.f;
+  }
+  Transport(dS, dsdr, m, mV, dsdp, F, F1);
+    
+  float V1Tmp[36];
+  for(int i=0; i<36; i++)
+    V1Tmp[i] = 0.f;
+  KFParticle::MultQSQt(F1, pointCov, V1Tmp, 6);
+    
+  for(int iC=0; iC<21; iC++)
+    mV[iC] += V1Tmp[iC];
+}
+
+float KFParticle::GetAngle  ( const KFParticle &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in 3D.
+   ** \param[in] p - the second particle
+   **/
+  
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );   
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+  float n = sqrt( mP[3]*mP[3] + mP[4]*mP[4] + mP[5]*mP[5] );
+  float n1= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4] + mP1[5]*mP1[5] );
+  n*=n1;
+  float a = 0;
+  if( n>1.e-8 ) a = ( mP[3]*mP1[3] + mP[4]*mP1[4] + mP[5]*mP1[5] )/n;
+  if (fabs(a)<1.) a = acos(a);
+  else a = (a>=0) ?0 :3.14;
+  return a;
+}
+
+float KFParticle::GetAngleXY( const KFParticle &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );   
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+  float n = sqrt( mP[3]*mP[3] + mP[4]*mP[4] );
+  float n1= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4] );
+  n*=n1;
+  float a = 0;
+  if( n>1.e-8 ) a = ( mP[3]*mP1[3] + mP[4]*mP1[4] )/n;
+  if (fabs(a)<1.) a = acos(a);
+  else a = (a>=0) ?0 :3.14;
+  return a;
+}
+
+float KFParticle::GetAngleRZ( const KFParticle &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in the RZ plane, R = sqrt(X*X+Y*Y).
+   ** \param[in] p - the second particle
+   **/
+
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );   
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 );  
+  float nr = sqrt( mP[3]*mP[3] + mP[4]*mP[4] );
+  float n1r= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4]  );
+  float n = sqrt( nr*nr + mP[5]*mP[5] );
+  float n1= sqrt( n1r*n1r + mP1[5]*mP1[5] );
+  n*=n1;
+  float a = 0;
+  if( n>1.e-8 ) a = ( nr*n1r +mP[5]*mP1[5])/n; 
+  if (fabs(a)<1.) a = acos(a);
+  else a = (a>=0) ?0 :3.14;
+  return a;
+}
+
+float KFParticle::GetPseudoProperDecayTime( const KFParticle &pV, const float& mass, float* timeErr2 ) const
+{ 
+  /** Returns the Pseudo Proper Time of the decay = (r*pt) / |pt| * M/|pt|
+   ** \param[in] pV - the creation point of the particle
+   ** \param[in] mass - the mass of the particle
+   ** \param[out] timeErr2 - error of the returned value, if null pointer is provided - is not calculated
+   **/
+  
+  const float ipt2 = 1/( Px()*Px() + Py()*Py() );
+  const float mipt2 = mass*ipt2;
+  const float dx = X() - pV.X();
+  const float dy = Y() - pV.Y();
+
+  if ( timeErr2 ) {
+      // -- calculate error = sigma(f(r)) = f'Cf'
+      // r = {x,y,px,py,x_pV,y_pV}
+      // df/dr = { px*m/pt^2,
+      //     py*m/pt^2,
+      //    ( x - x_pV )*m*(1/pt^2 - 2(px/pt^2)^2),
+      //    ( y - y_pV )*m*(1/pt^2 - 2(py/pt^2)^2),
+      //     -px*m/pt^2,
+      //     -py*m/pt^2 }
+    const float f0 = Px()*mipt2;
+    const float f1 = Py()*mipt2;
+    const float mipt2derivative = mipt2*(1-2*Px()*Px()*ipt2);
+    const float f2 = dx*mipt2derivative;
+    const float f3 = -dy*mipt2derivative;
+    const float f4 = -f0;
+    const float f5 = -f1;
+
+    const float& mC00 =    GetCovariance(0,0);
+    const float& mC10 =    GetCovariance(0,1);
+    const float& mC11 =    GetCovariance(1,1);
+    const float& mC20 =    GetCovariance(3,0);
+    const float& mC21 =    GetCovariance(3,1);
+    const float& mC22 =    GetCovariance(3,3);
+    const float& mC30 =    GetCovariance(4,0);
+    const float& mC31 =    GetCovariance(4,1);
+    const float& mC32 =    GetCovariance(4,3);
+    const float& mC33 =    GetCovariance(4,4);
+    const float& mC44 = pV.GetCovariance(0,0);
+    const float& mC54 = pV.GetCovariance(1,0);
+    const float& mC55 = pV.GetCovariance(1,1);
+
+    *timeErr2 =
+      f5*mC55*f5 +
+      f5*mC54*f4 +
+      f4*mC44*f4 +
+      f3*mC33*f3 +
+      f3*mC32*f2 +
+      f3*mC31*f1 +
+      f3*mC30*f0 +
+      f2*mC22*f2 +
+      f2*mC21*f1 +
+      f2*mC20*f0 +
+      f1*mC11*f1 +
+      f1*mC10*f0 +
+      f0*mC00*f0;
+  }
+  return ( dx*Px() + dy*Py() )*mipt2;
+}
diff --git a/external/KFParticle/KFParticle/KFParticle.h b/external/KFParticle/KFParticle/KFParticle.h
new file mode 100644
index 0000000000000000000000000000000000000000..76b84f467b7cc74a4127ee2fc7028c6a81d2d8c0
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticle.h
@@ -0,0 +1,1020 @@
+//---------------------------------------------------------------------------------
+// The KFParticle class
+// .
+// @author  S.Gorbunov, I.Kisel
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class is ALICE interface to general mathematics in KFParticleBase
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+//#define NonhomogeneousField
+// #define HomogeneousField
+
+#ifndef KFPARTICLE_H
+#define KFPARTICLE_H
+
+#include "KFParticleBase.h"
+#include <cmath>
+
+class KFPTrack;
+class KFPVertex;
+
+/** @class KFParticle
+ ** @brief The main scalar class of KF Particle package, describes particle objects.
+ ** @author  S.Gorbunov, I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The main scalar class of KF Particle pacakge, describes particle objects.
+ ** The particle is described with the state vector { X, Y, Z, Px, Py, Pz, E }
+ ** and the corresponding covariance matrix.
+ ** It contains functionality to create particle-object from track, to construct 
+ ** short-lived particles from other tracks or particles. The mathematics is 
+ ** based on the Kalman filter method. It also allows to subtract particles from 
+ ** the already constructed object,
+ ** to transport particles, get parameters together with their errors, get distance 
+ ** to other particles and vertices, get deviations from them in terms of errors, etc.
+ **/
+
+class KFParticle :public KFParticleBase
+{
+  
+ public:
+
+  //*
+  //*  INITIALIZATION
+  //*
+
+  //* Set magnetic field for all particles
+#ifdef HomogeneousField
+  static void SetField( float Bz );
+#endif
+  //* Constructor (empty)
+
+  KFParticle():KFParticleBase(){ ; }
+
+  //* Destructor (empty)
+
+  ~KFParticle(){ ; }
+
+  //* Construction of mother particle by its 2-3-4 daughters
+
+  KFParticle( const KFParticle &d1, const KFParticle &d2 );
+
+  KFParticle( const KFParticle &d1, const KFParticle &d2, 
+              const KFParticle &d3 );
+
+  KFParticle( const KFParticle &d1, const KFParticle &d2, 
+              const KFParticle &d3, const KFParticle &d4 );
+ 
+ //* Initialisation from "cartesian" coordinates ( X Y Z Px Py Pz )
+ //* Parameters, covariance matrix, charge and PID hypothesis should be provided 
+
+  void Create( const float Param[], const float Cov[], Int_t Charge, float mass /*Int_t PID*/ );
+  void Create( const Double_t Param[], const Double_t Cov[], Int_t Charge, float mass /*Int_t PID*/ );
+
+ //* Initialisation from ALICE track, PID hypothesis shoould be provided 
+
+  KFParticle( const KFPTrack &track, const int PID );
+
+
+  //* Initialisation from VVertex 
+
+  KFParticle( const KFPVertex &vertex );
+
+  //* Initialise covariance matrix and set current parameters to 0.0 
+
+  void Initialize();
+
+  //*
+  //*  ACCESSORS
+  //*
+
+  //* Simple accessors 
+
+  float GetX    () const ; ///< Retruns X coordinate of the particle, fP[0].
+  float GetY    () const ; ///< Retruns Y coordinate of the particle, fP[1].
+  float GetZ    () const ; ///< Retruns Z coordinate of the particle, fP[2].
+  float GetPx   () const ; ///< Retruns X component of the momentum, fP[3].
+  float GetPy   () const ; ///< Retruns Y component of the momentum, fP[4].
+  float GetPz   () const ; ///< Retruns Z component of the momentum, fP[5].
+  float GetE    () const ; ///< Returns energy of the particle, fP[6].
+  float GetS    () const ; ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  char  GetQ    () const ; ///< Returns charge of the particle.
+  float GetChi2 () const ; ///< Returns Chi2 of the fit.
+  Int_t GetNDF  () const ; ///< Returns number of decrease of freedom.
+
+  Bool_t GetAtProductionVertex() const { return fAtProductionVertex; } ///< Returns a flag which shows if the particle is located at the production point
+  void SetAtProductionVertex(Bool_t b) { fAtProductionVertex = b; } ///< Set a flag that particle is at the production point
+
+#ifdef NonhomogeneousField
+  const float* GetFieldCoeff() const { return fieldRegion; } ///< Returns the field approximation for the current particle
+  void SetFieldCoeff(float c, int i) { fieldRegion[i] = c; } ///< Sets the field coefficient with index i.
+#endif
+
+  const float& X    () const { return fP[0]; } ///< Retruns X coordinate of the particle, fP[0].
+  const float& Y    () const { return fP[1]; } ///< Retruns Y coordinate of the particle, fP[1].
+  const float& Z    () const { return fP[2]; } ///< Retruns Z coordinate of the particle, fP[2].
+  const float& Px   () const { return fP[3]; } ///< Retruns X component of the momentum, fP[3].
+  const float& Py   () const { return fP[4]; } ///< Retruns Y component of the momentum, fP[4].
+  const float& Pz   () const { return fP[5]; } ///< Retruns Z component of the momentum, fP[5].
+  const float& E    () const { return fP[6]; } ///< Returns energy of the particle, fP[6].
+  const float& S    () const { return fP[7]; } ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  const char&  Q    () const { return fQ;    } ///< Returns charge of the particle.
+  const float& Chi2 () const { return fChi2; } ///< Returns Chi2 of the fit.
+  const Int_t& NDF  () const { return fNDF;  } ///< Returns number of decrease of freedom.
+  
+  float GetParameter ( int i ) const ;        ///< Returns P[i] parameter.
+  float GetCovariance( int i ) const ;        ///< Returns C[i] element of the covariance matrix in the lower triangular form.
+  float GetCovariance( int i, int j ) const ; ///< Returns C[i,j] element of the covariance matrix.
+
+  //* Accessors with calculations, value returned w/o error flag
+  
+  float GetP             () const; ///< Returns momentum
+  float GetPt            () const; ///< Returns transverse momentum
+  float GetEta           () const; ///< Returns pseudorapidity
+  float GetPhi           () const; ///< Returns the azimuthal angle phi 
+  float GetMomentum      () const; ///< Returns momentum
+  float GetMass          () const; ///< Returns mass
+  float GetDecayLength   () const; ///< Returns decay length
+  float GetDecayLengthXY () const; ///< Returns decay length in XY
+  float GetLifeTime      () const; ///< Returns life time ctau [cm]
+  float GetR             () const; ///< Returns distance to the origin of the coordinate system {0,0,0}
+
+  //* Accessors to estimated errors
+
+  float GetErrX             () const ; ///< Returns the error of X of current position 
+  float GetErrY             () const ; ///< Returns the error of Y of current position
+  float GetErrZ             () const ; ///< Returns the error of Z of current position
+  float GetErrPx            () const ; ///< Returns the error of X-compoment of the particle momentum
+  float GetErrPy            () const ; ///< Returns the error of Y-compoment of the particle momentum
+  float GetErrPz            () const ; ///< Returns the error of Z-compoment of the particle momentum
+  float GetErrE             () const ; ///< Returns the error of energy
+  float GetErrS             () const ; ///< Returns the error of decay length / momentum
+  float GetErrP             () const ; ///< Returns the error of momentum
+  float GetErrPt            () const ; ///< Returns the error of transverse momentum
+  float GetErrEta           () const ; ///< Returns the error of pseudorapidity
+  float GetErrPhi           () const ; ///< Returns the error of the azimuthal angle phi 
+  float GetErrMomentum      () const ; ///< Returns the error of momentum
+  float GetErrMass          () const ; ///< Returns the error of mass
+  float GetErrDecayLength   () const ; ///< Returns the error of decay length
+  float GetErrDecayLengthXY () const ; ///< Returns the error of decay length in XY
+  float GetErrLifeTime      () const ; ///< Returns the error of life time
+  float GetErrR             () const ; ///< Returns the error of distance to the origin of the coordinate system {0,0,0}
+
+  //* Accessors with calculations( &value, &estimated sigma )
+  //* error flag returned (0 means no error during calculations) 
+
+  int GetP             ( float &P, float &SigmaP ) const ;     //* momentum
+  int GetPt            ( float &Pt, float &SigmaPt ) const ;   //* transverse momentum
+  int GetEta           ( float &Eta, float &SigmaEta ) const ; //* pseudorapidity
+  int GetPhi           ( float &Phi, float &SigmaPhi ) const ; //* phi
+  int GetMomentum      ( float &P, float &SigmaP ) const ;     //* momentum
+  int GetMass          ( float &M, float &SigmaM ) const ;     //* mass
+  int GetDecayLength   ( float &L, float &SigmaL ) const ;     //* decay length
+  int GetDecayLengthXY ( float &L, float &SigmaL ) const ;     //* decay length in XY
+  int GetLifeTime      ( float &T, float &SigmaT ) const ;     //* life time
+  int GetR             ( float &R, float &SigmaR ) const ;     //* R
+  float GetRapidity() const { return 0.5*log((fP[6] + fP[5])/(fP[6] - fP[5])); } ///< Returns rapidity of the particle
+  float GetTheta()    const { return atan2(GetPt(),fP[5]); } ///< Returns the polar angle in RZ
+
+
+  //*
+  //*  MODIFIERS
+  //*
+  
+  float & X    () ; ///< Modifier of X coordinate of the particle, fP[0].
+  float & Y    () ; ///< Modifier of Y coordinate of the particle, fP[1].
+  float & Z    () ; ///< Modifier of Z coordinate of the particle, fP[2].
+  float & Px   () ; ///< Modifier of X component of the momentum, fP[3].
+  float & Py   () ; ///< Modifier of Y component of the momentum, fP[4].
+  float & Pz   () ; ///< Modifier of Z component of the momentum, fP[5].
+  float & E    () ; ///< Modifier of energy of the particle, fP[6].
+  float & S    () ; ///< Modifier of dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  char  & Q    () ; ///< Modifier of charge of the particle.
+  float & Chi2 () ; ///< Modifier of Chi2 of the fit.
+  Int_t & NDF  () ; ///< Modifier of number of decrease of freedom.
+
+  float & Parameter ( int i ) ;        ///< Modifier of P[i] parameter.
+  float & Covariance( int i ) ;        ///< Modifier of C[i] element of the covariance matrix in the lower triangular form.
+  float & Covariance( int i, int j ) ; ///< Modifier of C[i,j] element of the covariance matrix.
+  float * Parameters () ;              ///< Returns pointer to the parameters fP
+  float * CovarianceMatrix() ;         ///< Returns pointer to the covariance matrix fC
+
+  //* 
+  //* CONSTRUCTION OF THE PARTICLE BY ITS DAUGHTERS AND MOTHER
+  //* USING THE KALMAN FILTER METHOD
+  //*
+
+
+  //* Add daughter to the particle 
+
+  void AddDaughter( const KFParticle &Daughter );
+
+  //* Add daughter via += operator: ex.{ D0; D0+=Pion; D0+= Kaon; }
+
+  void operator +=( const KFParticle &Daughter );  
+
+  //* Everything in one go  
+
+  void Construct( const KFParticle *vDaughters[], int nDaughters, 
+		  const KFParticle *ProdVtx=0,   float Mass=-1 );
+
+  //*
+  //*                   TRANSPORT
+  //* 
+  //*  ( main transportation parameter is S = SignedPath/Momentum )
+  //*  ( parameters of decay & production vertices are stored locally )
+  //*
+
+  //* Transport the particle close to xyz[] point 
+
+  void TransportToPoint( const float xyz[] );
+
+  //* Transport the particle close to VVertex  
+#ifdef HomogeneousField
+  void TransportToVertex( const KFPVertex &v );
+#endif
+  //* Transport the particle close to another particle p 
+  void TransportToParticle( const KFParticle &p );
+
+  //* Get dS to a certain space point 
+  float GetDStoPoint( const float xyz[3], float dsdr[6] ) const ;
+  
+  //* Get dS to other particle p (dSp for particle p also returned) 
+  void GetDStoParticle( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const ;
+  
+  
+  //* 
+  //* OTHER UTILITIES
+  //*
+ 
+  //* Calculate distance from another object [cm] in XY-plane
+
+  Bool_t GetDistanceFromVertexXY( const float vtx[], float &val, float &err ) const ;
+  Bool_t GetDistanceFromVertexXY( const float vtx[], const float Cv[], float &val, float &err ) const ;
+  Bool_t GetDistanceFromVertexXY( const KFParticle &Vtx, float &val, float &err ) const ;
+#ifdef HomogeneousField
+  Bool_t GetDistanceFromVertexXY( const KFPVertex &Vtx, float &val, float &err ) const ;
+#endif
+
+  float GetDistanceFromVertexXY( const float vtx[] ) const ;
+  float GetDistanceFromVertexXY( const KFParticle &Vtx ) const ;
+#ifdef HomogeneousField
+  float GetDistanceFromVertexXY( const KFPVertex &Vtx ) const ;
+#endif
+  float GetDistanceFromParticleXY( const KFParticle &p ) const ;
+
+  //* Calculate sqrt(Chi2/ndf) deviation from another object in XY plane
+  //* ( v = [xyz]-vertex, Cv=[Cxx,Cxy,Cyy,Cxz,Cyz,Czz]-covariance matrix )
+
+  float GetDeviationFromVertexXY( const float v[], const float Cv[]=0 ) const ;
+  float GetDeviationFromVertexXY( const KFParticle &Vtx ) const ;
+#ifdef HomogeneousField
+  float GetDeviationFromVertexXY( const KFPVertex &Vtx ) const ;
+#endif
+  float GetDeviationFromParticleXY( const KFParticle &p ) const ;
+
+  //* Get parameters at an arbitrary reconstructed point taking into account its errors
+  void GetParametersAtPoint(const float* point, const float* pointCov, float* m, float* mV);
+  
+  //* Calculate opennig angle between two particles
+
+  float GetAngle  ( const KFParticle &p ) const ;
+  float GetAngleXY( const KFParticle &p ) const ;
+  float GetAngleRZ( const KFParticle &p ) const ;
+
+  float GetPseudoProperDecayTime( const KFParticle &primVertex, const float& mass, float* timeErr2 = 0 ) const;
+
+  void GetFieldValue( const float xyz[], float B[] ) const ;
+
+  void Transport( float dS, const float* dsdr, float P[], float C[], float* dsdr1=0, float* F=0, float* F1=0 ) const ;
+
+ protected: 
+  
+  //*
+  //*  INTERNAL STUFF
+  //* 
+
+  //* Method to access ALICE field 
+#ifdef HomogeneousField
+  static float GetFieldAlice();
+#endif
+  
+ private:
+#ifdef HomogeneousField
+  static float fgBz;  ///< Bz compoment of the magnetic field (is defined in case of #ifdef HomogeneousField)
+#endif
+#ifdef NonhomogeneousField
+  /** \brief Approximation of the magnetic field along the track trajectory.
+   ** Each component (Bx, By, Bz) is approximated with the parabola depending on Z coordinate. Is defined in case of #ifdef NonhomogeneousField.
+   **/
+  float fieldRegion[10];
+#endif
+  
+#ifndef KFParticleStandalone
+  ClassDef( KFParticle, 3 )
+#endif
+};
+
+
+
+//---------------------------------------------------------------------
+//
+//     Inline implementation of the KFParticle methods
+//
+//---------------------------------------------------------------------
+
+#ifdef HomogeneousField
+inline void KFParticle::SetField( float Bz )
+{ 
+  /** Sets the constant homogemeous one-component magnetic field Bz (is defined in case of #ifdef HomogeneousField).
+   ** \param[in] Bz - Z-component of the magnetic field
+   **/
+  fgBz = Bz;
+}
+#endif
+
+inline KFParticle::KFParticle( const KFParticle &d1, 
+                               const KFParticle &d2, 
+                               const KFParticle &d3 )
+{
+  /** Constructs a particle from three input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   ** \param[in] d3 - the third daughter particle
+   **/
+  KFParticle mother;
+  mother+= d1;
+  mother+= d2;
+  mother+= d3;
+  *this = mother;
+}
+
+inline KFParticle::KFParticle( const KFParticle &d1, 
+                               const KFParticle &d2, 
+                               const KFParticle &d3, 
+                               const KFParticle &d4 )
+{
+  /** Constructs a particle from four input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   ** \param[in] d3 - the third daughter particle
+   ** \param[in] d4 - the fourth daughter particle
+   **/
+  KFParticle mother;
+  mother+= d1;
+  mother+= d2;
+  mother+= d3;
+  mother+= d4;
+  *this = mother;
+}
+
+
+inline void KFParticle::Initialize()
+{ 
+  /** Calls KFParticleBase::Initialize()*/
+  KFParticleBase::Initialize(); 
+}
+
+inline float KFParticle::GetX    () const 
+{ 
+  return KFParticleBase::GetX();    
+}
+
+inline float KFParticle::GetY    () const 
+{ 
+  return KFParticleBase::GetY();    
+}
+
+inline float KFParticle::GetZ    () const 
+{ 
+  return KFParticleBase::GetZ();    
+}
+
+inline float KFParticle::GetPx   () const 
+{ 
+  return KFParticleBase::GetPx();   
+}
+
+inline float KFParticle::GetPy   () const 
+{ 
+  return KFParticleBase::GetPy();   
+}
+
+inline float KFParticle::GetPz   () const 
+{ 
+  return KFParticleBase::GetPz();   
+}
+
+inline float KFParticle::GetE    () const 
+{ 
+  return KFParticleBase::GetE();    
+}
+
+inline float KFParticle::GetS    () const 
+{ 
+  return KFParticleBase::GetS();    
+}
+
+inline char    KFParticle::GetQ    () const 
+{ 
+  return KFParticleBase::GetQ();    
+}
+
+inline float KFParticle::GetChi2 () const 
+{ 
+  return KFParticleBase::GetChi2(); 
+}
+
+inline Int_t    KFParticle::GetNDF  () const 
+{ 
+  return KFParticleBase::GetNDF();  
+}
+
+inline float KFParticle::GetParameter ( int i ) const 
+{ 
+  return KFParticleBase::GetParameter(i);  
+}
+
+inline float KFParticle::GetCovariance( int i ) const 
+{ 
+  return KFParticleBase::GetCovariance(i); 
+}
+
+inline float KFParticle::GetCovariance( int i, int j ) const 
+{ 
+  return KFParticleBase::GetCovariance(i,j);
+}
+
+
+inline float KFParticle::GetP    () const
+{
+  float par, err;
+  if( KFParticleBase::GetMomentum( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetPt   () const
+{
+  float par, err;
+  if( KFParticleBase::GetPt( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetEta   () const
+{
+  float par, err;
+  if( KFParticleBase::GetEta( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetPhi   () const
+{
+  float par, err;
+  if( KFParticleBase::GetPhi( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetMomentum    () const
+{
+  float par, err;
+  if( KFParticleBase::GetMomentum( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetMass        () const
+{
+  float par, err;
+  if( KFParticleBase::GetMass( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetDecayLength () const
+{
+  float par, err;
+  if( KFParticleBase::GetDecayLength( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetDecayLengthXY () const
+{
+  float par, err;
+  if( KFParticleBase::GetDecayLengthXY( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetLifeTime    () const
+{
+  float par, err;
+  if( KFParticleBase::GetLifeTime( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetR   () const
+{
+  float par, err;
+  if( KFParticleBase::GetR( par, err ) ) return 0;
+  else return par;
+}
+
+inline float KFParticle::GetErrX           () const 
+{
+  return sqrt(fabs( GetCovariance(0,0) ));
+}
+
+inline float KFParticle::GetErrY           () const 
+{
+  return sqrt(fabs( GetCovariance(1,1) ));
+}
+
+inline float KFParticle::GetErrZ           () const 
+{
+  return sqrt(fabs( GetCovariance(2,2) ));
+}
+
+inline float KFParticle::GetErrPx          () const 
+{
+  return sqrt(fabs( GetCovariance(3,3) ));
+}
+
+inline float KFParticle::GetErrPy          () const 
+{
+  return sqrt(fabs( GetCovariance(4,4) ));
+}
+
+inline float KFParticle::GetErrPz          () const 
+{
+  return sqrt(fabs( GetCovariance(5,5) ));
+}
+
+inline float KFParticle::GetErrE           () const 
+{
+  return sqrt(fabs( GetCovariance(6,6) ));
+}
+
+inline float KFParticle::GetErrS           () const 
+{
+  return sqrt(fabs( GetCovariance(7,7) ));
+}
+
+inline float KFParticle::GetErrP    () const
+{
+  float par, err;
+  if( KFParticleBase::GetMomentum( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrPt    () const
+{
+  float par, err;
+  if( KFParticleBase::GetPt( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrEta    () const
+{
+  float par, err;
+  if( KFParticleBase::GetEta( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrPhi    () const
+{
+  float par, err;
+  if( KFParticleBase::GetPhi( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrMomentum    () const
+{
+  float par, err;
+  if( KFParticleBase::GetMomentum( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrMass        () const
+{
+  float par, err;
+  if( KFParticleBase::GetMass( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrDecayLength () const
+{
+  float par, err;
+  if( KFParticleBase::GetDecayLength( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrDecayLengthXY () const
+{
+  float par, err;
+  if( KFParticleBase::GetDecayLengthXY( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrLifeTime    () const
+{
+  float par, err;
+  if( KFParticleBase::GetLifeTime( par, err ) ) return 1.e10;
+  else return err;
+}
+
+inline float KFParticle::GetErrR    () const
+{
+  float par, err;
+  if( KFParticleBase::GetR( par, err ) ) return 1.e10;
+  else return err;
+}
+
+
+inline int KFParticle::GetP( float &P, float &SigmaP ) const 
+{
+  /** Calculates particle momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] P - momentum of the particle
+   ** \param[out] SigmaP - its error
+   **/
+  return KFParticleBase::GetMomentum( P, SigmaP );
+}
+
+inline int KFParticle::GetPt( float &Pt, float &SigmaPt ) const 
+{
+  /** Calculates particle transverse  momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Pt - transverse momentum of the particle
+   ** \param[out] SigmaPt - its error
+   **/
+  return KFParticleBase::GetPt( Pt, SigmaPt );
+}
+
+inline int KFParticle::GetEta( float &Eta, float &SigmaEta ) const 
+{
+  /** Calculates particle pseudorapidity and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Eta - pseudorapidity of the particle
+   ** \param[out] SigmaEta - its error
+   **/
+  return KFParticleBase::GetEta( Eta, SigmaEta );
+}
+
+inline int KFParticle::GetPhi( float &Phi, float &SigmaPhi ) const 
+{
+  /** Calculates particle polar angle at the current point and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Phi - polar angle of the particle
+   ** \param[out] SigmaPhi - its error
+   **/
+  return KFParticleBase::GetPhi( Phi, SigmaPhi );
+}
+
+inline int KFParticle::GetMomentum( float &P, float &SigmaP ) const 
+{
+  /** Calculates particle momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] P - momentum of the particle
+   ** \param[out] SigmaP - its error
+   **/
+  return KFParticleBase::GetMomentum( P, SigmaP );
+}
+
+inline int KFParticle::GetMass( float &M, float &SigmaM ) const 
+{
+  /** Calculates the mass of the particle and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] M - mass of the particle
+   ** \param[out] SigmaM - its error
+   **/
+  return KFParticleBase::GetMass( M, SigmaM );
+}
+
+inline int KFParticle::GetDecayLength( float &L, float &SigmaL ) const 
+{
+  /** Calculates the decay length of the particle in the laboratory system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] L - the decay length
+   ** \param[out] SigmaL - its error
+   **/
+  return KFParticleBase::GetDecayLength( L, SigmaL );
+}
+
+inline int KFParticle::GetDecayLengthXY( float &L, float &SigmaL ) const 
+{
+  /** Calculates the projection in the XY plane of the decay length of the particle in the laboratory 
+   ** system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] L - the decay length
+   ** \param[out] SigmaL - its error
+   **/
+  return KFParticleBase::GetDecayLengthXY( L, SigmaL );
+}
+
+inline int KFParticle::GetLifeTime( float &T, float &SigmaT ) const 
+{
+  /** Calculates the lifetime times speed of life (ctau) [cm] of the particle in the  
+   ** center of mass frame and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] T - lifetime of the particle [cm]
+   ** \param[out] SigmaT - its error
+   **/
+  return KFParticleBase::GetLifeTime( T, SigmaT );
+}
+
+inline int KFParticle::GetR( float &R, float &SigmaR ) const 
+{
+  /** Calculates the distance to the point {0,0,0} and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] R - polar angle of the particle
+   ** \param[out] SigmaR - its error
+   **/
+  return KFParticleBase::GetR( R, SigmaR );
+}
+
+inline float & KFParticle::X() 
+{ 
+  return KFParticleBase::X();    
+}
+
+inline float & KFParticle::Y()
+{ 
+  return KFParticleBase::Y();    
+}
+
+inline float & KFParticle::Z() 
+{ 
+  return KFParticleBase::Z();    
+}
+
+inline float & KFParticle::Px() 
+{ 
+  return KFParticleBase::Px();   
+}
+
+inline float & KFParticle::Py() 
+{ 
+  return KFParticleBase::Py();   
+}
+
+inline float & KFParticle::Pz() 
+{ 
+  return KFParticleBase::Pz();   
+}
+
+inline float & KFParticle::E() 
+{ 
+  return KFParticleBase::E();    
+}
+
+inline float & KFParticle::S() 
+{ 
+  return KFParticleBase::S();    
+}
+
+inline char    & KFParticle::Q() 
+{ 
+  return KFParticleBase::Q();    
+}
+
+inline float & KFParticle::Chi2() 
+{ 
+  return KFParticleBase::Chi2(); 
+}
+
+inline Int_t    & KFParticle::NDF() 
+{ 
+  return KFParticleBase::NDF();  
+}
+
+inline float & KFParticle::Parameter ( int i )        
+{ 
+  return KFParticleBase::Parameter(i);
+}
+
+inline float & KFParticle::Covariance( int i )        
+{ 
+  return KFParticleBase::Covariance(i);
+}
+
+inline float & KFParticle::Covariance( int i, int j ) 
+{ 
+  return KFParticleBase::Covariance(i,j); 
+}
+
+inline float * KFParticle::Parameters ()
+{
+  return fP;
+}
+
+inline float * KFParticle::CovarianceMatrix()
+{
+  return fC;
+}
+
+
+inline void KFParticle::operator +=( const KFParticle &Daughter )
+{
+  /** Operator to add daughter to the current particle. Calls AddDaughter() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    SetFieldCoeff(Daughter.GetFieldCoeff()[i], i);
+#endif
+  KFParticleBase::operator +=( Daughter );
+}
+  
+
+inline void KFParticle::AddDaughter( const KFParticle &Daughter )
+{
+  /** Adds daughter to the current particle. Depending on the selected construction method uses: \n
+   ** 1) Either simplifyed fast mathematics which consideres momentum and energy as
+   ** independent variables and thus ignores constraint on the fixed mass (fConstructMethod = 0).
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold. Implemented in the 
+   ** AddDaughterWithEnergyFit() function \n
+   ** 2) Or slower but correct mathematics which requires that the masses of daughter particles 
+   ** stays fixed in the construction process (fConstructMethod = 2). Implemented in the
+   ** AddDaughterWithEnergyFitMC() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    SetFieldCoeff(Daughter.GetFieldCoeff()[i], i);
+#endif
+  KFParticleBase::AddDaughter( Daughter );
+}
+
+inline void KFParticle::Construct( const KFParticle *vDaughters[], int nDaughters, 
+                                   const KFParticle *ProdVtx,   float Mass )
+{    
+  /** Constructs a short-lived particle from a set of daughter particles:\n
+   ** 1) all parameters of the "this" objects are initialised;\n
+   ** 2) daughters are added one after another;\n
+   ** 3) if Parent pointer is not null, the production vertex is set to it;\n
+   ** 4) if Mass hypothesis >=0 the mass constraint is set.
+   ** \param[in] vDaughters - array of daughter particles
+   ** \param[in] nDaughters - number of daughter particles in the input array
+   ** \param[in] Parent - optional parrent particle
+   ** \param[in] Mass - optional mass hypothesis
+   **/  
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    SetFieldCoeff(vDaughters[0]->GetFieldCoeff()[i], i);
+#endif
+  KFParticleBase::Construct( ( const KFParticleBase**)vDaughters, nDaughters, 
+                             ( const KFParticleBase*)ProdVtx, Mass );
+}
+
+inline void KFParticle::TransportToPoint( const float xyz[] )
+{ 
+  /** Transports particle to the distance of closest approach to the point xyz.
+   ** \param[in] xyz[3] - point, where particle should be transported
+   **/
+  float dsdr[6] = {0.f};
+  float dS = GetDStoPoint(xyz, dsdr);
+  TransportToDS( dS, dsdr );
+}
+#ifdef HomogeneousField
+inline void KFParticle::TransportToVertex( const KFPVertex &v )
+{ 
+  /** Transports particle to the distance of closest approach to the vertex v.
+   ** \param[in] v - vertex, where particle should be transported
+   **/
+  TransportToPoint( KFParticle(v).fP );
+}
+#endif
+inline void KFParticle::TransportToParticle( const KFParticle &p )
+{ 
+  /** Transports particle to the distance of closest approach to the particle p.
+   ** \param[in] p - particle, to which the current particle should be transported.
+   **/
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );
+  TransportToDS( dS[0], dsdr[0] );
+}
+
+inline float KFParticle::GetDStoPoint( const float xyz[], float* dsdr ) const 
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** If "HomogeneousField" is defined KFParticleBase::GetDStoPointBz() is called,
+   ** if "NonhomogeneousField" is defined - KFParticleBase::GetDStoPointCBM()
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[in] param - optional parameter, is used in case if the parameters of the particle are rotated
+   ** to other coordinate system (see GetDStoPointBy() function), otherwise fP are used
+   **/
+#ifdef HomogeneousField
+  return KFParticleBase::GetDStoPointBz( GetFieldAlice(), xyz, dsdr );
+#endif
+#ifdef NonhomogeneousField
+  return KFParticleBase::GetDStoPointCBM( xyz, dsdr );
+#endif
+  return 0.;
+}
+
+#ifdef HomogeneousField
+inline float KFParticle::GetFieldAlice()
+{ 
+  /** Returns value of the constant homogemeous one-component magnetic field Bz, (is defined in case of #ifdef HomogeneousField). */
+  return fgBz; 
+}
+#endif
+
+#ifdef HomogeneousField
+inline void KFParticle::GetFieldValue( const float * /*xyz*/, float B[] ) const 
+{    
+  /** Calculates the Bx, By, Bz components at the point xyz using approximation of the
+   ** magnetic field along the particle trajectory.
+   ** \param[in] xyz[3] - X, Y, Z coordiantes of the point where the magnetic field should be calculated
+   ** \param[out] B[3] - value of X, Y, Z components of the calculated magnetic field at the given point
+   **/
+  
+  B[0] = B[1] = 0;
+  B[2] = GetFieldAlice();
+}
+#endif
+
+#ifdef NonhomogeneousField
+inline void KFParticle::GetFieldValue( const float xyz[], float B[] ) const 
+{
+  /** Calculates the Bx, By, Bz components at the point xyz using approximation of the
+   ** magnetic field along the particle trajectory.
+   ** \param[in] xyz[3] - X, Y, Z coordiantes of the point where the magnetic field should be calculated
+   ** \param[out] B[3] - value of X, Y, Z components of the calculated magnetic field at the given point
+   **/
+  
+  const float dz = (xyz[2]-fieldRegion[9]);
+  const float dz2 = dz*dz;
+
+  B[0] = fieldRegion[0] + fieldRegion[1]*dz + fieldRegion[2]*dz2;
+  B[1] = fieldRegion[3] + fieldRegion[4]*dz + fieldRegion[5]*dz2;
+  B[2] = fieldRegion[6] + fieldRegion[7]*dz + fieldRegion[8]*dz2;
+}
+#endif
+
+inline void KFParticle::GetDStoParticle( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const
+{ 
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle \n
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP. If "HomogeneousField" is defined KFParticleBase::GetDStoParticleBz() is called,
+   ** if "NonhomogeneousField" is defined - KFParticleBase::GetDStoParticleCBM()
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+#ifdef HomogeneousField
+  KFParticleBase::GetDStoParticleBz( GetFieldAlice(), p, dS, dsdr ) ;
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBase::GetDStoParticleCBM( p, dS, dsdr ) ;
+#endif
+}
+
+inline void KFParticle::Transport( float dS, const float* dsdr, float P[], float C[], float* dsdr1, float* F, float* F1 ) const 
+{
+  /** Transports the parameters and their covariance matrix of the current particle
+   ** on a length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. If "HomogeneousField" is defined KFParticleBase::TransportBz()
+   ** is called, if "NonhomogeneousField" - KFParticleBase::TransportCBM().
+   ** The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/ 
+#ifdef HomogeneousField
+  KFParticleBase::TransportBz( GetFieldAlice(), dS, dsdr, P, C, dsdr1, F, F1 );
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBase::TransportCBM( dS, dsdr, P, C, dsdr1, F, F1 );
+#endif
+}
+
+#endif 
diff --git a/external/KFParticle/KFParticle/KFParticleBase.cxx b/external/KFParticle/KFParticle/KFParticleBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f139c22ce935ec9e769954d09676e5963bfcbc80
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleBase.cxx
@@ -0,0 +1,3455 @@
+//---------------------------------------------------------------------------------
+// Implementation of the KFParticleBase class
+// .
+// @author  S.Gorbunov, I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class describes general mathematics which is used by KFParticle class
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+
+#include "KFParticleBase.h"
+#include <cmath>
+
+#ifndef KFParticleStandalone
+ClassImp(KFParticleBase)
+#endif
+
+#ifdef __ROOT__
+#include "TClass.h"
+#include "TRSymMatrix.h"
+#include "TRVector.h"
+#include <iostream>
+
+KFParticleBase::KFParticleBase() :fChi2(0), fSFromDecay(0), SumDaughterMass(0), fMassHypo(-1), fNDF(-3), 
+                                  fId(-1), fParentID(0), fIdTruth(0), fQuality(0), fIdParentMcVx(0), fAtProductionVertex(0),  
+                                  fQ(0), fConstructMethod(0), fPDG(0), fDaughtersIds()
+{ 
+  static Bool_t first = kTRUE;
+  if (first) {
+    first = kFALSE;
+    KFParticleBase::Class()->IgnoreTObjectStreamer();
+  }
+  //* Constructor 
+  Clear();
+}
+
+void KFParticleBase::Clear(Option_t *option) {
+  Initialize();
+  fIdTruth = 0;
+  fQuality = 0;
+  fIdParentMcVx = 0;
+  fParentID = 0;
+}
+
+void KFParticleBase::Print(Option_t *opt) const {
+  std::cout << *this << std::endl;
+  if (opt && (opt[0] == 'a' || opt[0] == 'A')) {
+    TRVector P(8,fP); std::cout << "par. " << P << std::endl;
+    TRSymMatrix C(8,fC); std::cout << "cov. " << C << std::endl;
+    
+  }
+}
+
+std::ostream&  operator<<(std::ostream& os, const KFParticleBase& particle) {
+  static const Char_t *vn[14] = {"x","y","z","px","py","pz","E","S","M","t","p","Q","Chi2","NDF"};
+  os << Form("p(%4i,%4i,%4i)",particle.Id(),particle.GetParentID(),particle.IdParentMcVx());
+  for (Int_t i = 0; i < 8; i++) {
+    if (i == 6) continue;                                    // E
+    if (i == 7 && particle.GetParameter(i) <= 0.0) continue; // S
+    if (particle.GetParameter(i) == 0. && particle.GetCovariance(i,i) == 0) continue;
+    if (particle.GetCovariance(i,i) > 0) 
+      os << Form(" %s:%8.3f+/-%6.3f", vn[i], particle.GetParameter(i), TMath::Sqrt(particle.GetCovariance(i,i)));
+    else 
+      os << Form(" %s:%8.3f", vn[i], particle.GetParameter(i));
+  }
+  float Mtp[3] = {0.f, 0.f, 0.f}, MtpErr[3] = {0.f, 0.f, 0.f};
+  particle.GetMass(Mtp[0], MtpErr[0]);     if (MtpErr[0] < 1e-7 || MtpErr[0] > 1e10) MtpErr[0] = -13;
+  particle.GetLifeTime(Mtp[1], MtpErr[1]); if (MtpErr[1] <=   0 || MtpErr[1] > 1e10) MtpErr[1] = -13;
+  particle.GetMomentum(Mtp[2], MtpErr[2]); if (MtpErr[2] <=   0 || MtpErr[2] > 1e10) MtpErr[2] = -13;
+  for (Int_t i = 8; i < 11; i++) {
+    if (i == 9 && Mtp[i-8] <= 0.0) continue; // t
+    if (MtpErr[i-8] > 0 && MtpErr[i-8] <  9e2) os << Form(" %s:%8.3f+/-%7.3f", vn[i],Mtp[i-8],MtpErr[i-8]);
+    else                                       os << Form(" %s:%8.3f", vn[i],Mtp[i-8]);
+  }
+  os << Form(" pdg:%5i Q:%2i  chi2/NDF :%8.2f/%2i",particle.GetPDG(),particle.GetQ(),particle.GetChi2(),particle.GetNDF());
+  if (particle.IdTruth()) os << Form(" IdT:%4i/%3i",particle.IdTruth(),particle.QaTruth());
+  int nd = particle.NDaughters();
+  if (nd > 1) {
+    os << " ND: " << nd << ":";
+    if (nd > 3) nd = 3;
+    for (int d = 0; d < nd; d++) {
+      os << particle.DaughterIds()[d];
+      if (d < nd-1) os << ",";
+    }
+  }
+  return os;
+}
+#endif
+
+#ifndef __ROOT__
+KFParticleBase::KFParticleBase() : fChi2(0), fSFromDecay(0), 
+   SumDaughterMass(0), fMassHypo(-1), fNDF(-3), fId(-1), fAtProductionVertex(0), fQ(0), fConstructMethod(0), fPDG(0), fDaughtersIds()
+{ 
+  /** The default constructor, initialises the parameters by: \n
+   ** 1) all parameters are set to 0; \n
+   ** 2) all elements of the covariance matrix are set to 0 except Cxx=Cyy=Czz=100; \n
+   ** 3) Q = 0; \n
+   ** 4) chi2 is set to 0; \n
+   ** 5) NDF = -3, since 3 parameters should be fitted: X, Y, Z. 
+   **/
+  Initialize();
+}
+#endif
+
+void KFParticleBase::Initialize( const float Param[], const float Cov[], Int_t Charge, float Mass )
+{
+  /** Sets the parameters of the particle:
+   **
+   ** \param[in] Param[6] = { X, Y, Z, Px, Py, Pz } - position and momentum
+   ** \param[in] Cov[21]  - lower-triangular part of the covariance matrix:@n
+   ** \verbatim
+             (  0  .  .  .  .  . )
+             (  1  2  .  .  .  . )
+   Cov[21] = (  3  4  5  .  .  . )
+             (  6  7  8  9  .  . )
+             ( 10 11 12 13 14  . )
+             ( 15 16 17 18 19 20 )
+   \endverbatim
+   ** \param[in] Charge - charge of the particle in elementary charge units
+   ** \param[in] mass - the mass hypothesis
+   **/
+
+
+  for( Int_t i=0; i<6 ; i++ ) fP[i] = Param[i];
+  for( Int_t i=0; i<21; i++ ) fC[i] = Cov[i];
+
+  float energy = sqrt( Mass*Mass + fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]);
+  fP[6] = energy;
+  fP[7] = 0;
+  fQ = Charge;
+  fNDF = 0;
+  fChi2 = 0;
+  fAtProductionVertex = 0;
+  fSFromDecay = 0;
+
+  float energyInv = 1./energy;
+  float 
+    h0 = fP[3]*energyInv,
+    h1 = fP[4]*energyInv,
+    h2 = fP[5]*energyInv;
+
+  fC[21] = h0*fC[ 6] + h1*fC[10] + h2*fC[15];
+  fC[22] = h0*fC[ 7] + h1*fC[11] + h2*fC[16];
+  fC[23] = h0*fC[ 8] + h1*fC[12] + h2*fC[17];
+  fC[24] = h0*fC[ 9] + h1*fC[13] + h2*fC[18];
+  fC[25] = h0*fC[13] + h1*fC[14] + h2*fC[19];
+  fC[26] = h0*fC[18] + h1*fC[19] + h2*fC[20];
+  fC[27] = ( h0*h0*fC[ 9] + h1*h1*fC[14] + h2*h2*fC[20] 
+	     + 2*(h0*h1*fC[13] + h0*h2*fC[18] + h1*h2*fC[19] ) );
+  for( Int_t i=28; i<36; i++ ) fC[i] = 0;
+  fC[35] = 1.;
+
+  SumDaughterMass = Mass;
+  fMassHypo = Mass;
+}
+
+void KFParticleBase::Initialize()
+{
+  /** Initialises the parameters by default: \n
+   ** 1) all parameters are set to 0; \n
+   ** 2) all elements of the covariance matrix are set to 0 except Cxx=Cyy=Czz=100; \n
+   ** 3) Q = 0; \n
+   ** 4) chi2 is set to 0; \n
+   ** 5) NDF = -3, since 3 parameters should be fitted: X, Y, Z. 
+   **/
+
+  for( Int_t i=0; i<8; i++) fP[i] = 0;
+  for(Int_t i=0;i<36;++i) fC[i]=0.;
+  fC[0] = fC[2] = fC[5] = 100.;
+  fC[35] = 1.;
+  fNDF  = -3;
+  fChi2 =  0.;
+  fQ = 0;
+  fSFromDecay = 0;
+  fAtProductionVertex = 0;
+  SumDaughterMass = 0;
+  fMassHypo = -1;
+}
+
+Int_t KFParticleBase::GetMomentum( float &p, float &error )  const 
+{
+  /** Calculates particle momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] p - momentum of the particle
+   ** \param[out] error - its error
+   **/
+
+  float x = fP[3];
+  float y = fP[4];
+  float z = fP[5];
+  float x2 = x*x;
+  float y2 = y*y;
+  float z2 = z*z;
+  float p2 = x2+y2+z2;
+  p = sqrt(p2);
+  error = (x2*fC[9]+y2*fC[14]+z2*fC[20] + 2*(x*y*fC[13]+x*z*fC[18]+y*z*fC[19]) );
+  if( error>1.e-16 && p>1.e-4 ){
+    error = sqrt(error)/p;
+    return 0;
+  }
+  error = 1.e8;
+  return 1;
+}
+
+Int_t KFParticleBase::GetPt( float &pt, float &error )  const 
+{
+  /** Calculates particle transverse  momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] pt - transverse momentum of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float px = fP[3];
+  float py = fP[4];
+  float px2 = px*px;
+  float py2 = py*py;
+  float pt2 = px2+py2;
+  pt = sqrt(pt2);
+  error = (px2*fC[9] + py2*fC[14] + 2*px*py*fC[13] );
+  if( error>0 && pt>1.e-4 ){
+    error = sqrt(error)/pt;
+    return 0;
+  }
+  error = 1.e10;
+  return 1;
+}
+
+Int_t KFParticleBase::GetEta( float &eta, float &error )  const 
+{
+  /** Calculates particle pseudorapidity and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] eta - pseudorapidity of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float px = fP[3];
+  float py = fP[4];
+  float pz = fP[5];
+  float pt2 = px*px + py*py;
+  float p2 = pt2 + pz*pz;
+  float p = sqrt(p2);
+  float a = p + pz;
+  float b = p - pz;
+  eta = 1.e10;
+  if( b > 1.e-8 ){
+    float c = a/b;
+    if( c>1.e-8 ) eta = 0.5*log(c);
+  }
+  float h3 = -px*pz;
+  float h4 = -py*pz;  
+  float pt4 = pt2*pt2;
+  float p2pt4 = p2*pt4;
+  error = (h3*h3*fC[9] + h4*h4*fC[14] + pt4*fC[20] + 2*( h3*(h4*fC[13] + fC[18]*pt2) + pt2*h4*fC[19] ) );
+
+  if( error>0 && p2pt4>1.e-10 ){
+    error = sqrt(error/p2pt4);
+    return 0;
+  }
+
+  error = 1.e10;
+  return 1;
+}
+
+Int_t KFParticleBase::GetPhi( float &phi, float &error )  const 
+{
+  /** Calculates particle polar angle at the current point and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] phi - polar angle of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float px = fP[3];
+  float py = fP[4];
+  float px2 = px*px;
+  float py2 = py*py;
+  float pt2 = px2 + py2;
+  phi = atan2(py,px);
+  error = (py2*fC[9] + px2*fC[14] - 2*px*py*fC[13] );
+  if( error>0 && pt2>1.e-4 ){
+    error = sqrt(error)/pt2;
+    return 0;
+  }
+  error = 1.e10;
+  return 1;
+}
+
+Int_t KFParticleBase::GetR( float &r, float &error )  const 
+{
+  /** Calculates the distance to the point {0,0,0} and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] r - polar angle of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float x = fP[0];
+  float y = fP[1];
+  float x2 = x*x;
+  float y2 = y*y;
+  r = sqrt(x2 + y2);
+  error = (x2*fC[0] + y2*fC[2] - 2*x*y*fC[1] );
+  if( error>0 && r>1.e-4 ){
+    error = sqrt(error)/r;
+    return 0;
+  }
+  error = 1.e10;
+  return 1;
+}
+
+Int_t KFParticleBase::GetMass( float &m, float &error ) const 
+{
+  /** Calculates the mass of the particle and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] m - mass of the particle
+   ** \param[out] error - its error
+   **/
+  
+  // s = sigma^2 of m2/2
+
+  float s = (  fP[3]*fP[3]*fC[9] + fP[4]*fP[4]*fC[14] + fP[5]*fP[5]*fC[20] 
+             + fP[6]*fP[6]*fC[27] 
+             + 2*( + fP[3]*fP[4]*fC[13] + fP[5]*(fP[3]*fC[18] + fP[4]*fC[19]) 
+             - fP[6]*( fP[3]*fC[24] + fP[4]*fC[25] + fP[5]*fC[26] )  ) 
+            ); 
+
+  float m2 = (fP[6]*fP[6] - fP[3]*fP[3] - fP[4]*fP[4] - fP[5]*fP[5]);
+
+  if(m2<0.)
+  {
+    error = 1.e3;
+    m = -sqrt(-m2);
+    return 1;
+  }
+
+  m  = sqrt(m2);
+  if( m>1.e-6 ){
+    if( s >= 0 ) {
+      error = sqrt(s)/m;
+      return 0;
+    }
+  }
+  else {
+    error = 0.;
+    return 0;
+  }
+  error = 1.e3;
+
+  return 1;
+}
+
+
+Int_t KFParticleBase::GetDecayLength( float &l, float &error ) const 
+{
+  /** Calculates the decay length of the particle in the laboratory system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] l - the decay length
+   ** \param[out] error - its error
+   **/
+  
+  float x = fP[3];
+  float y = fP[4];
+  float z = fP[5];
+  float t = fP[7];
+  float x2 = x*x;
+  float y2 = y*y;
+  float z2 = z*z;
+  float p2 = x2+y2+z2;
+  l = t*sqrt(p2);
+  if( p2>1.e-4){
+    error = p2*fC[35] + t*t/p2*(x2*fC[9]+y2*fC[14]+z2*fC[20]
+				+ 2*(x*y*fC[13]+x*z*fC[18]+y*z*fC[19]) )
+      + 2*t*(x*fC[31]+y*fC[32]+z*fC[33]);
+    error = sqrt(fabs(error));
+    return 0;
+  }
+  error = 1.e20;
+  return 1;
+}
+
+Int_t KFParticleBase::GetDecayLengthXY( float &l, float &error ) const 
+{
+  /** Calculates the projection in the XY plane of the decay length of the particle in the laboratory 
+   ** system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] l - the decay length
+   ** \param[out] error - its error
+   **/
+  
+  float x = fP[3];
+  float y = fP[4];
+  float t = fP[7];
+  float x2 = x*x;
+  float y2 = y*y;
+  float pt2 = x2+y2;
+  l = t*sqrt(pt2);
+  if( pt2>1.e-4){
+    error = pt2*fC[35] + t*t/pt2*(x2*fC[9]+y2*fC[14] + 2*x*y*fC[13] )
+      + 2*t*(x*fC[31]+y*fC[32]);
+    error = sqrt(fabs(error));
+    return 0;
+  }
+  error = 1.e20;
+  return 1;
+}
+
+
+Int_t KFParticleBase::GetLifeTime( float &ctau, float &error ) const 
+{
+  /** Calculates the lifetime times speed of life (ctau) [cm] of the particle in the  
+   ** center of mass frame and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] ctau - lifetime of the particle [cm]
+   ** \param[out] error - its error
+   **/
+  
+  float m, dm;
+  GetMass( m, dm );
+  float cTM = (-fP[3]*fC[31] - fP[4]*fC[32] - fP[5]*fC[33] + fP[6]*fC[34]);
+  ctau = fP[7]*m;
+  error = m*m*fC[35] + 2*fP[7]*cTM + fP[7]*fP[7]*dm*dm;
+  if( error > 0 ){
+    error = sqrt( error );
+    return 0;
+  }
+  error = 1.e20;
+  return 1;
+}
+
+
+void KFParticleBase::operator +=( const KFParticleBase &Daughter )
+{
+  /** Operator to add daughter to the current particle. Calls AddDaughter() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+  
+  AddDaughter( Daughter );
+}
+
+bool KFParticleBase::GetMeasurement( const KFParticleBase& daughter, float m[], float V[], float D[3][3] )
+{
+  /** Obtains the measurements from the current particle and the daughter to be added for the Kalman filter
+   ** mathematics. If these are two first daughters they are transported to the point of the closest approach,
+   ** if the third or higher daughter is added it is transported to the DCA point of the already constructed
+   ** vertex. The correlations are taken into account in the covariance matrices of both measurements,
+   ** the correlation matrix of two measurements is also calculated. Parameters of the current particle are
+   ** modified by this function, the daughter is not changed, its parameters are stored to the output arrays
+   ** after modifications.
+   ** \param[in] daughter - the daughter particle to be added, stays unchanged
+   ** \param[out] m[8] - the output parameters of the daughter particle at the DCA point
+   ** \param[out] V[36] - the output covariance matrix of the daughter parameters, takes into account the correlation
+   ** \param[out] D[3][3] - the correlation matrix between the current and daughter particles
+   **/
+  
+  if(fNDF == -1)
+  {
+    float ds[2] = {0.f,0.f};
+    float dsdr[4][6];
+    float F1[36], F2[36], F3[36], F4[36];
+    for(int i1=0; i1<36; i1++)
+    {
+      F1[i1] = 0;
+      F2[i1] = 0;
+      F3[i1] = 0;
+      F4[i1] = 0;
+    }
+    GetDStoParticle( daughter, ds, dsdr );
+    
+    if( fabs(ds[0]*fP[5]) > 1000.f || fabs(ds[1]*daughter.fP[5]) > 1000.f)
+      return 0;
+
+    float V0Tmp[36] = {0.};
+    float V1Tmp[36] = {0.};
+
+    float C[36];
+    for(int iC=0; iC<36; iC++)
+      C[iC] = fC[iC];
+          
+             Transport(ds[0], dsdr[0], fP, fC, dsdr[1], F1, F2);
+    daughter.Transport(ds[1], dsdr[3],  m,  V, dsdr[2], F4, F3);
+    
+    MultQSQt(F2, daughter.fC, V0Tmp, 6);
+    MultQSQt(F3, C, V1Tmp, 6);
+        
+    for(int iC=0; iC<21; iC++)
+    {
+      fC[iC] += V0Tmp[iC];
+      V[iC]  += V1Tmp[iC];
+    }
+    
+    float C1F1T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        C1F1T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          C1F1T[i][j] +=  C[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+    float F3C1F1T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        F3C1F1T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          F3C1F1T[i][j] += F3[i*6+k] * C1F1T[k][j];
+        }
+      }
+    float C2F2T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        C2F2T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          C2F2T[i][j] +=  daughter.fC[IJ(i,k)] * F2[j*6+k];
+        }
+      }
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = F3C1F1T[i][j];
+        for(int k=0; k<6; k++)
+        {
+          D[i][j] += F4[i*6+k] * C2F2T[k][j];
+        }
+      }    
+  }
+  else
+  {
+    float dsdr[6];
+    float dS = daughter.GetDStoPoint(fP, dsdr);
+    
+    float dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0, 0, 0};
+    
+    float F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0;
+      F1[i2] = 0;
+    }
+    daughter.Transport(dS, dsdr, m, V, dsdp, F, F1);
+    
+//     float V1Tmp[36] = {0.};
+//     MultQSQt(F1, fC, V1Tmp, 6);
+    
+//     for(int iC=0; iC<21; iC++)
+//       V[iC] += V1Tmp[iC];
+    
+    float VFT[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<6; j++)
+      {
+        VFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          VFT[i][j] +=  fC[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+    
+    float FVFT[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        FVFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          FVFT[i][j] += F1[i*6+k] * VFT[k][j];
+        }
+      }
+      
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          D[i][j] +=  fC[IJ(j,k)] * F1[i*6+k];
+        }
+      }
+      
+    V[0] += FVFT[0][0];
+    V[1] += FVFT[1][0];
+    V[2] += FVFT[1][1];
+    V[3] += FVFT[2][0];
+    V[4] += FVFT[2][1];
+    V[5] += FVFT[2][2];
+    
+//     if(fNDF > 100)
+//     {
+//       float dx = fP[0] - m[0];
+//       float dy = fP[1] - m[1];
+//       float dz = fP[2] - m[2];
+//       float sigmaS = 3.f*sqrt( (dx*dx + dy*dy + dz*dz) / (m[3]*m[3] + m[4]*m[4] + m[5]*m[5]) );
+//     
+//       float h[3] = { m[3]*sigmaS, m[4]*sigmaS, m[5]*sigmaS };
+//       V[0]+= h[0]*h[0];
+//       V[1]+= h[1]*h[0];
+//       V[2]+= h[1]*h[1];
+//       V[3]+= h[2]*h[0];
+//       V[4]+= h[2]*h[1];
+//       V[5]+= h[2]*h[2];
+//     }
+  }
+  
+  return 1;
+}
+
+void KFParticleBase::AddDaughter( const KFParticleBase &Daughter )
+{
+  /** Adds daughter to the current particle. Depending on the selected construction method uses: \n
+   ** 1) Either simplifyed fast mathematics which consideres momentum and energy as
+   ** independent variables and thus ignores constraint on the fixed mass (fConstructMethod = 0).
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold. Implemented in the 
+   ** AddDaughterWithEnergyFit() function \n
+   ** 2) Or slower but correct mathematics which requires that the masses of daughter particles 
+   ** stays fixed in the construction process (fConstructMethod = 2). Implemented in the
+   ** AddDaughterWithEnergyFitMC() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+    
+  if( fNDF<-1 ){ // first daughter -> just copy
+    fNDF   = -1;
+    fQ     =  Daughter.GetQ();
+    for( Int_t i=0; i<7; i++) fP[i] = Daughter.fP[i];
+    for( Int_t i=0; i<28; i++) fC[i] = Daughter.fC[i];
+    fSFromDecay = 0;
+    fMassHypo = Daughter.fMassHypo;
+    SumDaughterMass = Daughter.SumDaughterMass;
+    return;
+  }
+
+  if(static_cast<int>(fConstructMethod) == 0)
+    AddDaughterWithEnergyFit(Daughter);
+  else if(static_cast<int>(fConstructMethod) == 2)
+    AddDaughterWithEnergyFitMC(Daughter);
+
+  SumDaughterMass += Daughter.SumDaughterMass;
+  fMassHypo = -1;
+}
+
+void KFParticleBase::AddDaughterWithEnergyFit( const KFParticleBase &Daughter )
+{
+  /** Adds daughter to the current particle. Uses simplifyed fast mathematics which consideres momentum 
+   ** and energy as independent variables and thus ignores constraint on the fixed mass.
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold.
+   ** \param[in] Daughter - the daughter particle
+   **/
+
+  Int_t maxIter = 1;
+
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+
+    float m[8], mV[36];
+
+    float D[3][3];
+    if(! GetMeasurement(Daughter, m, mV, D) )
+      return;
+    
+    float mS[6]= { fC[0]+mV[0], 
+                   fC[1]+mV[1], fC[2]+mV[2], 
+                   fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };
+                   
+    InvertCholetsky3(mS);
+
+    //* Residual (measured - estimated)
+
+    float zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+    float dChi2 = (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+           +      (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+           +      (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]; 
+    if (dChi2 > 1e9) return;
+//     if(fNDF > 100 && dChi2 > 9) return;
+    
+    float K[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        K[i][j] = 0;
+        for(int k=0; k<3; k++)
+          K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+      }
+    
+    //* CHt = CH' - D'
+    float mCHt0[7], mCHt1[7], mCHt2[7];
+
+    mCHt0[0]=fC[ 0] ;       mCHt1[0]=fC[ 1] ;       mCHt2[0]=fC[ 3] ;
+    mCHt0[1]=fC[ 1] ;       mCHt1[1]=fC[ 2] ;       mCHt2[1]=fC[ 4] ;
+    mCHt0[2]=fC[ 3] ;       mCHt1[2]=fC[ 4] ;       mCHt2[2]=fC[ 5] ;
+    mCHt0[3]=fC[ 6]-mV[ 6]; mCHt1[3]=fC[ 7]-mV[ 7]; mCHt2[3]=fC[ 8]-mV[ 8];
+    mCHt0[4]=fC[10]-mV[10]; mCHt1[4]=fC[11]-mV[11]; mCHt2[4]=fC[12]-mV[12];
+    mCHt0[5]=fC[15]-mV[15]; mCHt1[5]=fC[16]-mV[16]; mCHt2[5]=fC[17]-mV[17];
+    mCHt0[6]=fC[21]-mV[21]; mCHt1[6]=fC[22]-mV[22]; mCHt2[6]=fC[23]-mV[23];
+  
+    //* Kalman gain K = mCH'*S
+    
+    float k0[7], k1[7], k2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+      k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+      k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+    }
+
+    //* Add the daughter momentum to the particle momentum
+    
+    fP[ 3] += m[ 3];
+    fP[ 4] += m[ 4];
+    fP[ 5] += m[ 5];
+    fP[ 6] += m[ 6];
+  
+    fC[ 9] += mV[ 9];
+    fC[13] += mV[13];
+    fC[14] += mV[14];
+    fC[18] += mV[18];
+    fC[19] += mV[19];
+    fC[20] += mV[20];
+    fC[24] += mV[24];
+    fC[25] += mV[25];
+    fC[26] += mV[26];
+    fC[27] += mV[27];
+    
+ 
+   //* New estimation of the vertex position r += K*zeta
+    
+    for(Int_t i=0;i<7;++i) 
+      fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+    
+    //* New covariance matrix C -= K*(mCH')'
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+	fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+      }
+    }
+
+    float K2[3][3];
+    for(int i=0; i<3; i++)
+    {
+      for(int j=0; j<3; j++)
+        K2[i][j] = -K[j][i];
+      K2[i][i] += 1;
+    }
+
+    float A[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        A[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          A[i][j] += D[i][k] * K2[k][j];
+        }
+      }
+    
+    double M[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        M[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          M[i][j] += K[i][k] * A[k][j];
+        }
+      }
+
+    fC[0] += 2*M[0][0];
+    fC[1] += M[0][1] + M[1][0];
+    fC[2] += 2*M[1][1];
+    fC[3] += M[0][2] + M[2][0];
+    fC[4] += M[1][2] + M[2][1];
+    fC[5] += 2*M[2][2];
+  
+    //* Calculate Chi^2 
+
+    fNDF  += 2;
+    fQ    +=  Daughter.GetQ();
+    fSFromDecay = 0;    
+    fChi2 += dChi2;    
+
+  }
+}
+
+void KFParticleBase::SubtractDaughter( const KFParticleBase &Daughter )
+{
+  /** Subtracts a daughter particle from the mother particle. The mathematics is
+   ** similar to AddDaughterWithEnergyFit() but momentum is subtracted.
+   ** \param[in] Daughter - the daughter particle
+   **/
+
+  float m[8], mV[36];
+
+  float D[3][3];
+  if(! GetMeasurement(Daughter, m, mV, D) )
+    return;
+  
+  float mS[6]= { fC[0]+mV[0], 
+                 fC[1]+mV[1], fC[2]+mV[2], 
+                 fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };
+  
+  InvertCholetsky3(mS);
+
+  //* Residual (measured - estimated)
+
+  float zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+  float dChi2 = (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+              + (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+              + (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]; 
+  
+  float K[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      K[i][j] = 0;
+      for(int k=0; k<3; k++)
+        K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+    }
+  
+  //* CHt = CH' - D'
+  float mCHt0[7], mCHt1[7], mCHt2[7];
+
+  mCHt0[0]=fC[ 0] ;       mCHt1[0]=fC[ 1] ;       mCHt2[0]=fC[ 3] ;
+  mCHt0[1]=fC[ 1] ;       mCHt1[1]=fC[ 2] ;       mCHt2[1]=fC[ 4] ;
+  mCHt0[2]=fC[ 3] ;       mCHt1[2]=fC[ 4] ;       mCHt2[2]=fC[ 5] ;
+  mCHt0[3]=fC[ 6]+mV[ 6]; mCHt1[3]=fC[ 7]+mV[ 7]; mCHt2[3]=fC[ 8]+mV[ 8];
+  mCHt0[4]=fC[10]+mV[10]; mCHt1[4]=fC[11]+mV[11]; mCHt2[4]=fC[12]+mV[12];
+  mCHt0[5]=fC[15]+mV[15]; mCHt1[5]=fC[16]+mV[16]; mCHt2[5]=fC[17]+mV[17];
+  mCHt0[6]=fC[21]+mV[21]; mCHt1[6]=fC[22]+mV[22]; mCHt2[6]=fC[23]+mV[23];
+
+  //* Kalman gain K = mCH'*S
+  
+  float k0[7], k1[7], k2[7];
+  
+  for(Int_t i=0;i<7;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+
+  //* Add the daughter momentum to the particle momentum
+  
+  fP[ 3] -= m[ 3];
+  fP[ 4] -= m[ 4];
+  fP[ 5] -= m[ 5];
+  fP[ 6] -= m[ 6];
+
+  fC[ 9] += mV[ 9];
+  fC[13] += mV[13];
+  fC[14] += mV[14];
+  fC[18] += mV[18];
+  fC[19] += mV[19];
+  fC[20] += mV[20];
+  fC[24] += mV[24];
+  fC[25] += mV[25];
+  fC[26] += mV[26];
+  fC[27] += mV[27];
+  
+
+  //* New estimation of the vertex position r += K*zeta
+  
+  for(Int_t i=0;i<7;++i) 
+    fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+  
+  //* New covariance matrix C -= K*(mCH')'
+
+  for(Int_t i=0, k=0;i<7;++i){
+    for(Int_t j=0;j<=i;++j,++k){
+      fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+    }
+  }
+
+  float K2[3][3];
+  for(int i=0; i<3; i++)
+  {
+    for(int j=0; j<3; j++)
+      K2[i][j] = -K[j][i];
+    K2[i][i] += 1;
+  }
+
+  float A[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      A[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+	A[i][j] += D[i][k] * K2[k][j];
+      }
+    }
+  
+  double M[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      M[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+	M[i][j] += K[i][k] * A[k][j];
+      }
+    }
+
+  fC[0] += 2*M[0][0];
+  fC[1] += M[0][1] + M[1][0];
+  fC[2] += 2*M[1][1];
+  fC[3] += M[0][2] + M[2][0];
+  fC[4] += M[1][2] + M[2][1];
+  fC[5] += 2*M[2][2];
+
+  //* Calculate Chi^2 
+
+  fNDF  += 2;
+  fQ    +=  Daughter.GetQ();
+  fSFromDecay = 0;    
+  fChi2 += dChi2;    
+}
+
+
+void KFParticleBase::AddDaughterWithEnergyFitMC( const KFParticleBase &Daughter )
+{
+  /** Adds daughter to the current particle. Uses slower but correct mathematics 
+   ** which requires that the masses of daughter particles 
+   ** stays fixed in the construction process.
+   ** \param[in] Daughter - the daughter particle
+   **/
+
+  Int_t maxIter = 1;
+
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+
+    float m[8], mV[36];
+
+    float D[3][3];
+    GetMeasurement(Daughter, m, mV, D);
+    
+    float mS[6]= { fC[0]+mV[0], 
+                   fC[1]+mV[1], fC[2]+mV[2], 
+                   fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };
+    InvertCholetsky3(mS);
+    //* Residual (measured - estimated)
+
+    float zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+    float K[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        K[i][j] = 0;
+        for(int k=0; k<3; k++)
+          K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+      }
+
+    
+    //* CHt = CH'
+    
+    float mCHt0[7], mCHt1[7], mCHt2[7];
+    
+    mCHt0[0]=fC[ 0] ; mCHt1[0]=fC[ 1] ; mCHt2[0]=fC[ 3] ;
+    mCHt0[1]=fC[ 1] ; mCHt1[1]=fC[ 2] ; mCHt2[1]=fC[ 4] ;
+    mCHt0[2]=fC[ 3] ; mCHt1[2]=fC[ 4] ; mCHt2[2]=fC[ 5] ;
+    mCHt0[3]=fC[ 6] ; mCHt1[3]=fC[ 7] ; mCHt2[3]=fC[ 8] ;
+    mCHt0[4]=fC[10] ; mCHt1[4]=fC[11] ; mCHt2[4]=fC[12] ;
+    mCHt0[5]=fC[15] ; mCHt1[5]=fC[16] ; mCHt2[5]=fC[17] ;
+    mCHt0[6]=fC[21] ; mCHt1[6]=fC[22] ; mCHt2[6]=fC[23] ;
+  
+    //* Kalman gain K = mCH'*S
+    
+    float k0[7], k1[7], k2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+      k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+      k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+    }
+
+    // last itearation -> update the particle
+
+    //* VHt = VH'
+    
+    float mVHt0[7], mVHt1[7], mVHt2[7];
+    
+    mVHt0[0]=mV[ 0] ; mVHt1[0]=mV[ 1] ; mVHt2[0]=mV[ 3] ;
+    mVHt0[1]=mV[ 1] ; mVHt1[1]=mV[ 2] ; mVHt2[1]=mV[ 4] ;
+    mVHt0[2]=mV[ 3] ; mVHt1[2]=mV[ 4] ; mVHt2[2]=mV[ 5] ;
+    mVHt0[3]=mV[ 6] ; mVHt1[3]=mV[ 7] ; mVHt2[3]=mV[ 8] ;
+    mVHt0[4]=mV[10] ; mVHt1[4]=mV[11] ; mVHt2[4]=mV[12] ;
+    mVHt0[5]=mV[15] ; mVHt1[5]=mV[16] ; mVHt2[5]=mV[17] ;
+    mVHt0[6]=mV[21] ; mVHt1[6]=mV[22] ; mVHt2[6]=mV[23] ;
+  
+    //* Kalman gain Km = mCH'*S
+    
+    float km0[7], km1[7], km2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      km0[i] = mVHt0[i]*mS[0] + mVHt1[i]*mS[1] + mVHt2[i]*mS[3];
+      km1[i] = mVHt0[i]*mS[1] + mVHt1[i]*mS[2] + mVHt2[i]*mS[4];
+      km2[i] = mVHt0[i]*mS[3] + mVHt1[i]*mS[4] + mVHt2[i]*mS[5];
+    }
+
+    for(Int_t i=0;i<7;++i) 
+      fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+
+    for(Int_t i=0;i<7;++i) 
+      m[i] = m[i] - km0[i]*zeta[0] - km1[i]*zeta[1] - km2[i]*zeta[2];
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+	fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+      }
+    }
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+	mV[k] = mV[k] - (km0[i]*mVHt0[j] + km1[i]*mVHt1[j] + km2[i]*mVHt2[j] );
+      }
+    }
+
+    float mDf[7][7];
+
+    for(Int_t i=0;i<7;++i){
+      for(Int_t j=0;j<7;++j){
+	mDf[i][j] = (km0[i]*mCHt0[j] + km1[i]*mCHt1[j] + km2[i]*mCHt2[j] );
+      }
+    }
+
+    float mJ1[7][7], mJ2[7][7];
+    for(Int_t iPar1=0; iPar1<7; iPar1++)
+    {
+      for(Int_t iPar2=0; iPar2<7; iPar2++)
+      {
+        mJ1[iPar1][iPar2] = 0;
+        mJ2[iPar1][iPar2] = 0;
+      }
+    }
+
+    float mMassParticle  = fP[6]*fP[6] - (fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]);
+    float mMassDaughter  = m[6]*m[6] - (m[3]*m[3] + m[4]*m[4] + m[5]*m[5]);
+    if(mMassParticle > 0) mMassParticle = sqrt(mMassParticle);
+    if(mMassDaughter > 0) mMassDaughter = sqrt(mMassDaughter);
+
+    if( fMassHypo > -0.5)
+      SetMassConstraint(fP,fC,mJ1,fMassHypo);
+    else if((mMassParticle < SumDaughterMass) || (fP[6]<0) )
+      SetMassConstraint(fP,fC,mJ1,SumDaughterMass);
+
+    if(Daughter.fMassHypo > -0.5)
+      SetMassConstraint(m,mV,mJ2,Daughter.fMassHypo);
+    else if((mMassDaughter < Daughter.SumDaughterMass) || (m[6] < 0) )
+      SetMassConstraint(m,mV,mJ2,Daughter.SumDaughterMass);
+
+    float mDJ[7][7];
+
+    for(Int_t i=0; i<7; i++) {
+      for(Int_t j=0; j<7; j++) {
+        mDJ[i][j] = 0;
+        for(Int_t k=0; k<7; k++) {
+          mDJ[i][j] += mDf[i][k]*mJ1[j][k];
+        }
+      }
+    }
+
+    for(Int_t i=0; i<7; ++i){
+      for(Int_t j=0; j<7; ++j){
+        mDf[i][j]=0;
+        for(Int_t l=0; l<7; l++){
+          mDf[i][j] += mJ2[i][l]*mDJ[l][j];
+        }
+      }
+    }
+
+    //* Add the daughter momentum to the particle momentum
+
+    fP[ 3] += m[ 3];
+    fP[ 4] += m[ 4];
+    fP[ 5] += m[ 5];
+    fP[ 6] += m[ 6];
+
+    fC[ 9] += mV[ 9];
+    fC[13] += mV[13];
+    fC[14] += mV[14];
+    fC[18] += mV[18];
+    fC[19] += mV[19];
+    fC[20] += mV[20];
+    fC[24] += mV[24];
+    fC[25] += mV[25];
+    fC[26] += mV[26];
+    fC[27] += mV[27];
+
+    fC[6 ] += mDf[3][0]; fC[7 ] += mDf[3][1]; fC[8 ] += mDf[3][2];
+    fC[10] += mDf[4][0]; fC[11] += mDf[4][1]; fC[12] += mDf[4][2];
+    fC[15] += mDf[5][0]; fC[16] += mDf[5][1]; fC[17] += mDf[5][2];
+    fC[21] += mDf[6][0]; fC[22] += mDf[6][1]; fC[23] += mDf[6][2];
+
+    fC[9 ] += mDf[3][3] + mDf[3][3];
+    fC[13] += mDf[4][3] + mDf[3][4]; fC[14] += mDf[4][4] + mDf[4][4];
+    fC[18] += mDf[5][3] + mDf[3][5]; fC[19] += mDf[5][4] + mDf[4][5]; fC[20] += mDf[5][5] + mDf[5][5];
+    fC[24] += mDf[6][3] + mDf[3][6]; fC[25] += mDf[6][4] + mDf[4][6]; fC[26] += mDf[6][5] + mDf[5][6]; fC[27] += mDf[6][6] + mDf[6][6];
+
+    
+    float K2[3][3];
+    for(int i=0; i<3; i++)
+    {
+      for(int j=0; j<3; j++)
+        K2[i][j] = -K[j][i];
+      K2[i][i] += 1;
+    }
+
+    float A[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        A[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          A[i][j] += D[i][k] * K2[k][j];
+        }
+      }
+    
+    double M[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        M[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          M[i][j] += K[i][k] * A[k][j];
+        }
+      }
+
+    fC[0] += 2*M[0][0];
+    fC[1] += M[0][1] + M[1][0];
+    fC[2] += 2*M[1][1];
+    fC[3] += M[0][2] + M[2][0];
+    fC[4] += M[1][2] + M[2][1];
+    fC[5] += 2*M[2][2];
+    
+    //* Calculate Chi^2 
+
+    fNDF  += 2;
+    fQ    +=  Daughter.GetQ();
+    fSFromDecay = 0;    
+    fChi2 += (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+      +      (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+      +      (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2];
+  }
+}
+
+void KFParticleBase::SetProductionVertex( const KFParticleBase &Vtx )
+{
+  /** Adds a vertex as a point-like measurement to the current particle.
+   ** The eights parameter of the state vector is filled with the decay
+   ** length to the momentum ratio (s = l/p). The corresponding covariances
+   ** are calculated as well. The parameters of the particle are stored
+   ** at the position of the production vertex.
+   ** \param[in] Vtx - the assumed producation vertex
+   **/
+  
+  const float *m = Vtx.fP, *mV = Vtx.fC;
+
+  float decayPoint[3] = {fP[0], fP[1], fP[2]};
+  float decayPointCov[6] = { fC[0], fC[1], fC[2], fC[3], fC[4], fC[5] };
+
+  float D[6][6];
+  for(int iD1=0; iD1<6; iD1++)
+    for(int iD2=0; iD2<6; iD2++)
+      D[iD1][iD2] = 0.f;
+
+  Bool_t noS = ( fC[35]<=0 ); // no decay length allowed
+
+  if( noS ){ 
+    TransportToDecayVertex();
+    fP[7] = 0;
+    fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0;
+  }
+  else
+  {
+    float dsdr[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+    float dS = GetDStoPoint(Vtx.fP, dsdr);
+    
+    float dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0, 0, 0};
+    
+    float F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0;
+      F1[i2] = 0;
+    }
+    Transport( dS, dsdr, fP, fC, dsdp, F, F1 );
+    
+    float CTmp[36] = {0.};
+    MultQSQt(F1, mV, CTmp, 6);
+    
+    for(int iC=0; iC<6; iC++)
+      fC[iC] += CTmp[iC];
+          
+    for(int i=0; i<6; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          D[i][j] +=  mV[IJ(j,k)] * F1[i*6+k];
+        }
+      }
+  }
+
+  float mS[6] = { fC[0] + mV[0],
+                  fC[1] + mV[1], fC[2] + mV[2],
+                  fC[3] + mV[3], fC[4] + mV[4], fC[5] + mV[5] };                 
+  InvertCholetsky3(mS);
+  
+  float res[3] = { m[0] - X(), m[1] - Y(), m[2] - Z() };
+  
+  float K[3][6];  
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      K[i][j] = 0;
+      for(int k=0; k<3; k++)
+        K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+    }
+  
+  float mCHt0[7], mCHt1[7], mCHt2[7];
+  mCHt0[0]=fC[ 0];        mCHt1[0]=fC[ 1];        mCHt2[0]=fC[ 3];
+  mCHt0[1]=fC[ 1];        mCHt1[1]=fC[ 2];        mCHt2[1]=fC[ 4];
+  mCHt0[2]=fC[ 3];        mCHt1[2]=fC[ 4];        mCHt2[2]=fC[ 5];
+  mCHt0[3]=fC[ 6];        mCHt1[3]=fC[ 7];        mCHt2[3]=fC[ 8];
+  mCHt0[4]=fC[10];        mCHt1[4]=fC[11];        mCHt2[4]=fC[12];
+  mCHt0[5]=fC[15];        mCHt1[5]=fC[16];        mCHt2[5]=fC[17];
+  mCHt0[6]=fC[21];        mCHt1[6]=fC[22];        mCHt2[6]=fC[23];
+  
+  float k0[7], k1[7], k2[7];
+  for(Int_t i=0;i<7;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+  
+  for(Int_t i=0;i<7;++i) 
+    fP[i] = fP[i] + k0[i]*res[0] + k1[i]*res[1] + k2[i]*res[2];
+
+  for(Int_t i=0, k=0;i<7;++i){
+    for(Int_t j=0;j<=i;++j,++k){
+      fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+    }
+  }
+
+  float K2[3][3];
+  for(int i=0; i<3; i++)
+  {
+    for(int j=0; j<3; j++)
+      K2[i][j] = -K[j][i];
+    K2[i][i] += 1;
+  }
+
+  float A[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      A[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+        A[i][j] += D[k][i] * K2[k][j];
+      }
+    }
+  
+  double M[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      M[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+        M[i][j] += K[i][k] * A[k][j];
+      }
+    }
+    
+  fC[0] += 2*M[0][0];
+  fC[1] += M[0][1] + M[1][0];
+  fC[2] += 2*M[1][1];
+  fC[3] += M[0][2] + M[2][0];
+  fC[4] += M[1][2] + M[2][1];
+  fC[5] += 2*M[2][2];
+  
+  fChi2 += (mS[0]*res[0] + mS[1]*res[1] + mS[3]*res[2])*res[0]
+        +  (mS[1]*res[0] + mS[2]*res[1] + mS[4]*res[2])*res[1]
+        +  (mS[3]*res[0] + mS[4]*res[1] + mS[5]*res[2])*res[2];
+  fNDF += 2;
+   
+  if( noS ){ 
+    fP[7] = 0;
+    fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0;
+    fSFromDecay = 0;
+  }
+  else
+  {
+    float dsdr[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+    fP[7] = GetDStoPoint(decayPoint, dsdr);   
+    
+    float dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0, 0, 0};
+
+    float F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0;
+      F1[i2] = 0;
+    }
+    float tmpP[8], tmpC[36]; 
+    Transport( fP[7], dsdr, tmpP, tmpC, dsdp, F, F1 );
+          
+    fC[35] = 0;
+    for(int iDsDr=0; iDsDr<6; iDsDr++)
+    {
+      float dsdrC = 0, dsdpV = 0;
+      
+      for(int k=0; k<6; k++)
+        dsdrC += dsdr[k] * fC[IJ(k,iDsDr)]; // (-dsdr[k])*fC[k,j]
+      
+      fC[iDsDr+28] = dsdrC;
+      fC[35] += dsdrC*dsdr[iDsDr] ;
+      if(iDsDr < 3)
+      {
+        for(int k=0; k<3; k++)
+          dsdpV -= dsdr[k] * decayPointCov[IJ(k,iDsDr)];  //
+        fC[35] -= dsdpV*dsdr[iDsDr];
+      }
+    }  
+    fSFromDecay = -fP[7];
+  }
+  
+  fAtProductionVertex = 1;
+}
+
+void KFParticleBase::SetMassConstraint( float *mP, float *mC, float mJ[7][7], float mass )
+{
+  /** Sets the exact nonlinear mass constraint on the state vector mP with the covariance matrix mC.
+   ** \param[in,out] mP - the state vector to be modified
+   ** \param[in,out] mC - the corresponding covariance matrix
+   ** \param[in,out] mJ - the Jacobian between initial and modified parameters
+   ** \param[in] mass - the mass to be set on the state vector mP
+   **/
+    
+  //* Set nonlinear mass constraint (Mass) on the state vector mP with a covariance matrix mC.
+  
+  const float energy2 = mP[6]*mP[6], p2 = mP[3]*mP[3]+mP[4]*mP[4]+mP[5]*mP[5], mass2 = mass*mass;
+
+  const float a = energy2 - p2 + 2.*mass2;
+  const float b = -2.*(energy2 + p2);
+  const float c = energy2 - p2 - mass2;
+
+  float lambda = 0;
+  if(fabs(b) > 1.e-10) lambda = -c / b;
+
+  float d = 4.*energy2*p2 - mass2*(energy2-p2-2.*mass2);
+  if(d>=0 && fabs(a) > 1.e-10) lambda = (energy2 + p2 - sqrt(d))/a;
+
+  if(mP[6] < 0) //If energy < 0 we need a lambda < 0
+    lambda = -1000000.; //Empirical, a better solution should be found
+
+  Int_t iIter=0;
+  for(iIter=0; iIter<100; iIter++)
+  {
+    float lambda2 = lambda*lambda;
+    float lambda4 = lambda2*lambda2;
+
+    float lambda0 = lambda;
+
+    float f  = -mass2 * lambda4 + a*lambda2 + b*lambda + c;
+    float df = -4.*mass2 * lambda2*lambda + 2.*a*lambda + b;
+    if(fabs(df) < 1.e-10) break;
+    lambda -= f/df;
+    if(fabs(lambda0 - lambda) < 1.e-8) break;
+  }
+
+  const float lpi = 1./(1. + lambda);
+  const float lmi = 1./(1. - lambda);
+  const float lp2i = lpi*lpi;
+  const float lm2i = lmi*lmi;
+
+  float lambda2 = lambda*lambda;
+
+  float dfl  = -4.*mass2 * lambda2*lambda + 2.*a*lambda + b;
+  float dfx[7] = {0};//,0,0,0};
+  dfx[0] = -2.*(1. + lambda)*(1. + lambda)*mP[3];
+  dfx[1] = -2.*(1. + lambda)*(1. + lambda)*mP[4];
+  dfx[2] = -2.*(1. + lambda)*(1. + lambda)*mP[5];
+  dfx[3] = 2.*(1. - lambda)*(1. - lambda)*mP[6];
+  float dlx[4] = {1,1,1,1};
+  if(fabs(dfl) > 1.e-10 )
+  {
+    for(int i=0; i<4; i++)
+      dlx[i] = -dfx[i] / dfl;
+  }
+
+  float dxx[4] = {mP[3]*lm2i, mP[4]*lm2i, mP[5]*lm2i, -mP[6]*lp2i};
+
+  for(Int_t i=0; i<7; i++)
+    for(Int_t j=0; j<7; j++)
+      mJ[i][j]=0;
+  mJ[0][0] = 1.;
+  mJ[1][1] = 1.;
+  mJ[2][2] = 1.;
+
+  for(Int_t i=3; i<7; i++)
+    for(Int_t j=3; j<7; j++)
+      mJ[i][j] = dlx[j-3]*dxx[i-3];
+
+  for(Int_t i=3; i<6; i++)
+    mJ[i][i] += lmi;
+  mJ[6][6] += lpi;
+
+  float mCJ[7][7];
+
+  for(Int_t i=0; i<7; i++) {
+    for(Int_t j=0; j<7; j++) {
+      mCJ[i][j] = 0;
+      for(Int_t k=0; k<7; k++) {
+        mCJ[i][j] += mC[IJ(i,k)]*mJ[j][k];
+      }
+    }
+  }
+
+  for(Int_t i=0; i<7; ++i){
+    for(Int_t j=0; j<=i; ++j){
+      mC[IJ(i,j)]=0;
+      for(Int_t l=0; l<7; l++){
+        mC[IJ(i,j)] += mJ[i][l]*mCJ[l][j];
+      }
+    }
+  }
+
+  mP[3] *= lmi;
+  mP[4] *= lmi;
+  mP[5] *= lmi;
+  mP[6] *= lpi;
+}
+
+void KFParticleBase::SetNonlinearMassConstraint( float mass )
+{
+  /** Sets the exact nonlinear mass constraint on the current particle.
+   ** \param[in] mass - the mass to be set on the particle
+   **/
+
+  const float& px = fP[3];
+  const float& py = fP[4];
+  const float& pz = fP[5];
+  const float& energy  = fP[6];
+  
+  const float residual = (energy*energy - px*px - py*py - pz*pz) - mass*mass;
+  const float dm2 = float(4.f) * ( fC[9]*px*px + fC[14]*py*py + fC[20]*pz*pz + fC[27]*energy*energy +
+                      float(2.f) * ( (fC[13]*py + fC[18]*pz - fC[24]*energy)*px + (fC[19]*pz - fC[25]*energy)*py - fC[26]*pz*energy) );
+  const float dChi2 = residual*residual / dm2;
+  fChi2 += dChi2;
+  fNDF  += 1;
+  
+  float mJ[7][7];
+  SetMassConstraint( fP, fC, mJ, mass );
+  fMassHypo = mass;
+  SumDaughterMass = mass;
+}
+
+void KFParticleBase::SetMassConstraint( float Mass, float SigmaMass )
+{  
+  /** Sets linearised mass constraint on the current particle. The constraint can be set with
+   ** an uncertainty.
+   ** \param[in] Mass - the mass to be set on the state vector mP
+   ** \param[in] SigmaMass - uncertainty of the constraint
+   **/
+
+  fMassHypo = Mass;
+  SumDaughterMass = Mass;
+
+  float m2 = Mass*Mass;            // measurement, weighted by Mass 
+  float s2 = m2*SigmaMass*SigmaMass; // sigma^2
+
+  float p2 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]; 
+  float e0 = sqrt(m2+p2);
+
+  float mH[8];
+  mH[0] = mH[1] = mH[2] = 0.;
+  mH[3] = -2*fP[3]; 
+  mH[4] = -2*fP[4]; 
+  mH[5] = -2*fP[5]; 
+  mH[6] =  2*fP[6];//e0;
+  mH[7] = 0; 
+
+  float zeta = e0*e0 - e0*fP[6];
+  zeta = m2 - (fP[6]*fP[6]-p2);
+  
+  float mCHt[8], s2_est=0;
+  for( Int_t i=0; i<8; ++i ){
+    mCHt[i] = 0.0;
+    for (Int_t j=0;j<8;++j) mCHt[i] += Cij(i,j)*mH[j];
+    s2_est += mH[i]*mCHt[i];
+  }
+  
+  if( s2_est<1.e-20 ) return; // calculated mass error is already 0, 
+                              // the particle can not be constrained on mass
+
+  float w2 = 1./( s2 + s2_est );
+  fChi2 += zeta*zeta*w2;
+  fNDF  += 1;
+  for( Int_t i=0, ii=0; i<8; ++i ){
+    float ki = mCHt[i]*w2;
+    fP[i]+= ki*zeta;
+    for(Int_t j=0;j<=i;++j) fC[ii++] -= ki*mCHt[j];    
+  }
+}
+
+
+void KFParticleBase::SetNoDecayLength()
+{  
+  /** Sets constraint on the zero decay length. When the production point is set 
+   ** the measurement from this particle is created at the decay point.
+   **/
+  
+  TransportToDecayVertex();
+
+  float h[8];
+  h[0] = h[1] = h[2] = h[3] = h[4] = h[5] = h[6] = 0;
+  h[7] = 1; 
+
+  float zeta = 0 - fP[7];
+  for(Int_t i=0;i<8;++i) zeta -= h[i]*(fP[i]-fP[i]);
+  
+  float s = fC[35];   
+  if( s>1.e-20 ){
+    s = 1./s;
+    fChi2 += zeta*zeta*s;
+    fNDF  += 1;
+    for( Int_t i=0, ii=0; i<7; ++i ){
+      float ki = fC[28+i]*s;
+      fP[i]+= ki*zeta;
+      for(Int_t j=0;j<=i;++j) fC[ii++] -= ki*fC[28+j];    
+    }
+  }
+  fP[7] = 0;
+  fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0;
+}
+
+
+void KFParticleBase::Construct( const KFParticleBase* vDaughters[], Int_t nDaughters,
+                                const KFParticleBase *Parent,  float Mass )
+{ 
+  /** Constructs a short-lived particle from a set of daughter particles:\n
+   ** 1) all parameters of the "this" objects are initialised;\n
+   ** 2) daughters are added one after another;\n
+   ** 3) if Parent pointer is not null, the production vertex is set to it;\n
+   ** 4) if Mass hypothesis >=0 the mass constraint is set.
+   ** \param[in] vDaughters - array of daughter particles
+   ** \param[in] nDaughters - number of daughter particles in the input array
+   ** \param[in] Parent - optional parrent particle
+   ** \param[in] Mass - optional mass hypothesis
+   **/
+
+  const int maxIter = 1;
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+    fAtProductionVertex = 0;
+    fSFromDecay = 0;
+    SumDaughterMass = 0;
+
+    for(Int_t i=0;i<36;++i) fC[i]=0.;
+    fC[35] = 1.;
+    
+    fNDF  = -3;
+    fChi2 =  0.;
+    fQ = 0;
+    
+    for( Int_t itr =0; itr<nDaughters; itr++ ){
+      AddDaughter( *vDaughters[itr] );    
+    }
+  }
+
+  if( Mass>=0 ) SetMassConstraint( Mass );
+  if( Parent ) SetProductionVertex( *Parent );
+}
+
+void KFParticleBase::TransportToDecayVertex()
+{
+  /** Transports the particle to its decay vertex */
+  float dsdr[6] = {0.f};
+  if( fSFromDecay != 0 ) TransportToDS( -fSFromDecay, dsdr );
+  fAtProductionVertex = 0;
+}
+
+void KFParticleBase::TransportToProductionVertex()
+{
+  /** Transports the particle to its production vertex */
+  float dsdr[6] = {0.f}; 
+  if( fSFromDecay != -fP[7] ) TransportToDS( -fSFromDecay-fP[7], dsdr );
+  fAtProductionVertex = 1;
+}
+
+
+void KFParticleBase::TransportToDS( float dS, const float* dsdr )
+{ 
+  /** Transport the particle on a certain distane. The distance is defined by the dS=l/p parameter, where \n
+   ** 1) l - signed distance;\n
+   ** 2) p - momentum of the particle. \n
+   ** \param[in] dS = l/p - distance normalised to the momentum of the particle to be transported on
+   ** \param[in] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+ 
+  Transport( dS, dsdr, fP, fC );
+  fSFromDecay+= dS;
+}
+
+
+float KFParticleBase::GetDStoPointLine( const float xyz[3], float dsdr[6] ) const 
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** assuming the straigth line trajectory. Is used for particles with charge 0 or in case of zero magnetic field.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** \param[in] xyz[3] - point where particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  float p2 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5];  
+  if( p2<1.e-4 ) p2 = 1;
+  
+  const float& a = fP[3]*(xyz[0]-fP[0]) + fP[4]*(xyz[1]-fP[1]) + fP[5]*(xyz[2]-fP[2]);
+  dsdr[0] = -fP[3]/p2;
+  dsdr[1] = -fP[4]/p2;
+  dsdr[2] = -fP[5]/p2;
+  dsdr[3] = ((xyz[0]-fP[0])*p2 - 2.f* fP[3]*a)/(p2*p2);
+  dsdr[4] = ((xyz[1]-fP[1])*p2 - 2.f* fP[4]*a)/(p2*p2);
+  dsdr[5] = ((xyz[2]-fP[2])*p2 - 2.f* fP[5]*a)/(p2*p2);
+  
+  return a/p2;
+}
+
+
+float KFParticleBase::GetDStoPointBz( float B, const float xyz[3], float dsdr[6], const float* param) const
+{ 
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field Bz.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** \param[in] B - magnetic field Bz
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[in] param - optional parameter, is used in case if the parameters of the particle are rotated
+   ** to other coordinate system (see GetDStoPointBy() function), otherwise fP are used
+   **/
+  
+  if(!param)
+    param = fP;
+  
+  const float& x  = param[0];
+  const float& y  = param[1];
+  const float& z  = param[2];
+  const float& px = param[3];
+  const float& py = param[4];
+  const float& pz = param[5];
+  
+  const float kCLight = 0.000299792458f;
+  float bq = B*fQ*kCLight;
+  float pt2 = px*px + py*py;
+  float p2 = pt2 + pz*pz;  
+  
+  float dx = xyz[0] - x;
+  float dy = xyz[1] - y; 
+  float dz = xyz[2] - z; 
+  float a = dx*px+dy*py;
+  float dS(0.f);
+  
+  float abq = bq*a;
+
+  const float LocalSmall = 1.e-8f;
+  bool mask = ( fabs(bq)<LocalSmall );
+  if(mask && p2>1.e-4f)
+  {
+    dS = (a + dz*pz)/p2;
+    
+    dsdr[0] = -px/p2;
+    dsdr[1] = -py/p2;
+    dsdr[2] = -pz/p2;
+    dsdr[3] = (dx*p2 - 2.f* px *(a + dz *pz))/(p2*p2);
+    dsdr[4] = (dy*p2 - 2.f* py *(a + dz *pz))/(p2*p2);
+    dsdr[5] = (dz*p2 - 2.f* pz *(a + dz *pz))/(p2*p2);
+  }
+  if(mask)
+  { 
+    return dS;
+  }
+  
+  dS = atan2( abq, pt2 + bq*(dy*px -dx*py) )/bq;
+
+  float bs= bq*dS;
+
+  float s = sin(bs), c = cos(bs);
+
+  if(fabs(bq) < LocalSmall)
+    bq = LocalSmall;
+  float bbq = bq*(dx*py - dy*px) - pt2;
+  
+  dsdr[0] = (px*bbq - py*abq)/(abq*abq + bbq*bbq);
+  dsdr[1] = (px*abq + py*bbq)/(abq*abq + bbq*bbq);
+  dsdr[2] = 0;
+  dsdr[3] = -(dx*bbq + dy*abq + 2.f*px*a)/(abq*abq + bbq*bbq);
+  dsdr[4] = (dx*abq - dy*bbq - 2.f*py*a)/(abq*abq + bbq*bbq);
+  dsdr[5] = 0;
+  
+  float sz(0.f);
+  float cCoeff =  (bbq*c - abq*s) - pz*pz ;
+  if(fabs(cCoeff) > 1.e-8f)
+    sz = (dS*pz - dz)*pz / cCoeff;
+
+  float dcdr[6] = {0.f};
+  dcdr[0] = -bq*py*c - bbq*s*bq*dsdr[0] + px*bq*s - abq*c*bq*dsdr[0];
+  dcdr[1] =  bq*px*c - bbq*s*bq*dsdr[1] + py*bq*s - abq*c*bq*dsdr[1];
+  dcdr[3] = (-bq*dy-2*px)*c - bbq*s*bq*dsdr[3] - dx*bq*s - abq*c*bq*dsdr[3];
+  dcdr[4] = ( bq*dx-2*py)*c - bbq*s*bq*dsdr[4] - dy*bq*s - abq*c*bq*dsdr[4];
+  dcdr[5] = -2*pz;
+  
+  for(int iP=0; iP<6; iP++)
+    dsdr[iP] += pz*pz/cCoeff*dsdr[iP] - sz/cCoeff*dcdr[iP];
+  dsdr[2] += pz/cCoeff;
+  dsdr[5] += (2.f*pz*dS - dz)/cCoeff;
+  
+  dS += sz;
+  
+  bs= bq*dS;
+  s = sin(bs), c = cos(bs);
+  
+  float sB, cB;
+  const float kOvSqr6 = 1.f/sqrt(float(6.f));
+
+  if(LocalSmall < fabs(bs))
+  {
+    sB = s/bq;
+    cB = (1.f-c)/bq;
+  }
+  else
+  {
+    sB = (1.f-bs*kOvSqr6)*(1.f+bs*kOvSqr6)*dS;
+    cB = .5f*sB*bs;
+  }
+
+  float p[5];
+  p[0] = x + sB*px + cB*py;
+  p[1] = y - cB*px + sB*py;
+  p[2] = z +  dS*pz;
+  p[3] =          c*px + s*py;
+  p[4] =         -s*px + c*py;
+
+  dx = xyz[0] - p[0];
+  dy = xyz[1] - p[1];
+  dz = xyz[2] - p[2];
+  a = dx*p[3]+dy*p[4] + dz*pz;
+  abq = bq*a;
+
+  dS += atan2( abq, p2 + bq*(dy*p[3] -dx*p[4]) )/bq;
+  
+  return dS;
+}
+
+float KFParticleBase::GetDStoPointBy( float By, const float xyz[3], float dsdr[6] ) const
+{ 
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** The particle parameters are transformed to the coordinate system, where the main component of the magnetic field
+   ** By is directed along the Z axis: x->x, y->-z, z->y, and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] By - magnetic field By
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  const float param[6] = { fP[0], -fP[2], fP[1], fP[3], -fP[5], fP[4] };
+  const float point[3] = { xyz[0], -xyz[2], xyz[1] };
+  
+  float dsdrBz[6] = {0.f};
+  
+  const float dS = GetDStoPointBz(By, point, dsdrBz, param);
+  dsdr[0] =  dsdrBz[0];
+  dsdr[1] =  dsdrBz[2];
+  dsdr[2] = -dsdrBz[1];
+  dsdr[3] =  dsdrBz[3];
+  dsdr[4] =  dsdrBz[5];
+  dsdr[5] = -dsdrBz[4];
+  
+  return dS;
+}
+
+float KFParticleBase::GetDStoPointB( const float* B, const float xyz[3], float dsdr[6] ) const
+{ 
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field B.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** The particle parameters are transformed to the coordinate system, where the magnetic field B
+   ** is directed along the Z axis and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] B[3] - three components of the magnetic field at the current position of the particle
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+
+  const float& Bx = B[0];
+  const float& By = B[1];
+  const float& Bz = B[2];
+  
+  const float& Bxz = sqrt(Bx*Bx + Bz*Bz);
+  const float& Br = sqrt(Bx*Bx + By*By + Bz*Bz);
+    
+  float cosA = 1;
+  float sinA = 0;
+  if(fabs(Bxz) > 1.e-8f)
+  {
+    cosA = Bz/Bxz;
+    sinA = Bx/Bxz;
+  }
+  
+  const float& sinP = By/Br;
+  const float& cosP = Bxz/Br;
+  
+  const float param[6] = { cosA*fP[0] - sinA*fP[2], 
+                          -sinA*sinP*fP[0] + cosP*fP[1] - cosA*sinP*fP[2], 
+                           cosP*sinA*fP[0] + sinP*fP[1] + cosA*cosP*fP[2],
+                           cosA*fP[3] - sinA*fP[5], 
+                          -sinA*sinP*fP[3] + cosP*fP[4] - cosA*sinP*fP[5], 
+                           cosP*sinA*fP[3] + sinP*fP[4] + cosA*cosP*fP[5]};
+  const float point[3] = { cosA*xyz[0] - sinA*xyz[2], 
+                          -sinA*sinP*xyz[0] + cosP*xyz[1] - cosA*sinP*xyz[2], 
+                           cosP*sinA*xyz[0] + sinP*xyz[1] + cosA*cosP*xyz[2] };
+  
+  float dsdrBz[6] = {0.f};
+  
+  const float dS = GetDStoPointBz(Br, point, dsdrBz, param);
+  dsdr[0] =  dsdrBz[0]*cosA - dsdrBz[1]*sinA*sinP + dsdrBz[2]*sinA*cosP;
+  dsdr[1] =                   dsdrBz[1]*cosP      + dsdrBz[2]*sinP;
+  dsdr[2] = -dsdrBz[0]*sinA - dsdrBz[1]*cosA*sinP + dsdrBz[2]*cosA*cosP;
+  dsdr[3] =  dsdrBz[3]*cosA - dsdrBz[4]*sinA*sinP + dsdrBz[5]*sinA*cosP;
+  dsdr[4] =                   dsdrBz[4]*cosP      + dsdrBz[5]*sinP;
+  dsdr[5] = -dsdrBz[3]*sinA - dsdrBz[4]*cosA*sinP + dsdrBz[5]*cosA*cosP;
+  
+  return dS;
+}
+
+float KFParticleBase::GetDStoPointCBM( const float xyz[3], float dsdr[6] ) const
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** in case of the CBM-like nonhomogeneous magnetic field.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** For this the y-component of the magnetic field at the current position of the particle is obtained and
+   ** the GetDStoPointBy() is called.
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+
+  float dS = 0;
+  float fld[3];
+  GetFieldValue( fP, fld );
+  dS = GetDStoPointBy( fld[1], xyz, dsdr );
+  
+  return dS;
+}
+
+void KFParticleBase::GetDStoParticleBz( float Bz, const KFParticleBase &p, float dS[2], float dsdr[4][6], const float* param1, const float* param2 )  const
+{ 
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field Bz. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle (if the pointer is not provided it is initialised with fP) and
+   ** param2 are parameters of the second particle "p" (if the pointer is not provided it is initialised with p.fP). Parameters
+   ** param1 and param2 should be either provided both or both set to null pointers.
+   ** \param[in] Bz - magnetic field Bz
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   ** \param[in] param1 - optional parameter, is used in case if the parameters of the current particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise fP are used
+   ** \param[in] param2 - optional parameter, is used in case if the parameters of the second particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise p.fP are used
+   **/
+    
+  if(!param1)
+  {
+    param1 = fP;
+    param2 = p.fP;
+  }
+
+  //* Get dS to another particle for Bz field
+  const float kOvSqr6 = 1.f/sqrt(float(6.f));
+  const float kCLight = 0.000299792458f;
+
+  //in XY plane
+  //first root    
+  const float& bq1 = Bz*fQ*kCLight;
+  const float& bq2 = Bz*p.fQ*kCLight;
+
+  const bool& isStraight1 = fabs(bq1) < 1.e-8f;
+  const bool& isStraight2 = fabs(bq2) < 1.e-8f;
+  
+  if( isStraight1 && isStraight2 )
+  {
+    GetDStoParticleLine(p, dS, dsdr);
+    return;
+  }
+    
+  const float& px1 = param1[3];
+  const float& py1 = param1[4];
+  const float& pz1 = param1[5];
+
+  const float& px2 = param2[3];
+  const float& py2 = param2[4];
+  const float& pz2 = param2[5];
+
+  const float& pt12 = px1*px1 + py1*py1;
+  const float& pt22 = px2*px2 + py2*py2;
+
+  const float& x01 = param1[0];
+  const float& y01 = param1[1];
+  const float& z01 = param1[2];
+
+  const float& x02 = param2[0];
+  const float& y02 = param2[1];
+  const float& z02 = param2[2];
+
+  float dS1[2] = {0.f}, dS2[2]={0.f};
+  
+  const float& dx0 = (x01 - x02);
+  const float& dy0 = (y01 - y02);
+  const float& dr02 = dx0*dx0 + dy0*dy0;
+  const float& drp1  = dx0*px1 + dy0*py1;
+  const float& dxyp1 = dx0*py1 - dy0*px1;
+  const float& drp2  = dx0*px2 + dy0*py2;
+  const float& dxyp2 = dx0*py2 - dy0*px2;
+  const float& p1p2 = px1*px2 + py1*py2;
+  const float& dp1p2 = px1*py2 - px2*py1;
+  
+  const float& k11 = (bq2*drp1 - dp1p2);
+  const float& k21 = (bq1*(bq2*dxyp1 - p1p2) + bq2*pt12);
+  const float& k12 = ((bq1*drp2 - dp1p2));
+  const float& k22 = (bq2*(bq1*dxyp2 + p1p2) - bq1*pt22);
+  
+  const float& kp = (dxyp1*bq2 - dxyp2*bq1 - p1p2);
+  const float& kd = dr02/2.f*bq1*bq2 + kp;
+  const float& c1 = -(bq1*kd + pt12*bq2);
+  const float& c2 = bq2*kd + pt22*bq1; 
+  
+  float d1 = pt12*pt22 - kd*kd;
+  if(d1<0.f)
+    d1 = float(0.f);
+  d1 = sqrt( d1 );
+  float d2 = pt12*pt22 - kd*kd;
+  if(d2<0.f)
+    d2 = float(0.f);
+  d2 = sqrt( d2 );
+  
+  // find two points of closest approach in XY plane
+  
+  float dS1dR1[2][6];
+  float dS2dR2[2][6];
+
+  float dS1dR2[2][6];
+  float dS2dR1[2][6];
+
+  float dk11dr1[6] = {bq2*px1, bq2*py1, 0, bq2*dx0 - py2, bq2*dy0 + px2, 0};
+  float dk11dr2[6] = {-bq2*px1, -bq2*py1, 0, py1, -px1, 0};
+  float dk12dr1[6] = {bq1*px2, bq1*py2, 0, -py2, px2, 0};
+  float dk12dr2[6] = {-bq1*px2, -bq1*py2, 0, bq1*dx0 + py1, bq1*dy0 - px1, 0};
+  float dk21dr1[6] = {bq1*bq2*py1, -bq1*bq2*px1, 0, 2*bq2*px1 + bq1*(-(bq2*dy0) - px2), 2*bq2*py1 + bq1*(bq2*dx0 - py2), 0};
+  float dk21dr2[6] = {-(bq1*bq2*py1), bq1*bq2*px1, 0, -(bq1*px1), -(bq1*py1), 0};
+  float dk22dr1[6] = {bq1*bq2*py2, -(bq1*bq2*px2), 0, bq2*px2, bq2*py2, 0};
+  float dk22dr2[6] = {-(bq1*bq2*py2), bq1*bq2*px2, 0, bq2*(-(bq1*dy0) + px1) - 2*bq1*px2, bq2*(bq1*dx0 + py1) - 2*bq1*py2, 0};
+  
+  float dkddr1[6] = {bq1*bq2*dx0 + bq2*py1 - bq1*py2, bq1*bq2*dy0 - bq2*px1 + bq1*px2, 0, -bq2*dy0 - px2, bq2*dx0 - py2, 0};
+  float dkddr2[6] = {-bq1*bq2*dx0 - bq2*py1 + bq1*py2, -bq1*bq2*dy0 + bq2*px1 - bq1*px2, 0, bq1*dy0 - px1, -bq1*dx0 - py1, 0};
+  
+  float dc1dr1[6] = {-(bq1*(bq1*bq2*dx0 + bq2*py1 - bq1*py2)), -(bq1*(bq1*bq2*dy0 - bq2*px1 + bq1*px2)), 0, -2*bq2*px1 - bq1*(-(bq2*dy0) - px2), -2*bq2*py1 - bq1*(bq2*dx0 - py2), 0};
+  float dc1dr2[6] = {-(bq1*(-(bq1*bq2*dx0) - bq2*py1 + bq1*py2)), -(bq1*(-(bq1*bq2*dy0) + bq2*px1 - bq1*px2)), 0, -(bq1*(bq1*dy0 - px1)), -(bq1*(-(bq1*dx0) - py1)), 0};
+  
+  float dc2dr1[6] = {bq2*(bq1*bq2*dx0 + bq2*py1 - bq1*py2), bq2*(bq1*bq2*dy0 - bq2*px1 + bq1*px2), 0, bq2*(-(bq2*dy0) - px2), bq2*(bq2*dx0 - py2), 0};
+  float dc2dr2[6] = {bq2*(-(bq1*bq2*dx0) - bq2*py1 + bq1*py2), bq2*(-(bq1*bq2*dy0) + bq2*px1 - bq1*px2), 0, bq2*(bq1*dy0 - px1) + 2*bq1*px2, bq2*(-(bq1*dx0) - py1) + 2*bq1*py2, 0};
+  
+  float dd1dr1[6] = {0,0,0,0,0,0};
+  float dd1dr2[6] = {0,0,0,0,0,0};
+  if(d1>0)
+  {
+    for(int i=0; i<6; i++)
+    {
+      dd1dr1[i] = -kd/d1*dkddr1[i];
+      dd1dr2[i] = -kd/d1*dkddr2[i];
+    }
+    dd1dr1[3] += px1/d1*pt22; dd1dr1[4] += py1/d1*pt22;
+    dd1dr2[3] += px2/d1*pt12; dd1dr2[4] += py2/d1*pt12;
+  }
+
+  if(!isStraight1)
+  {    
+    dS1[0] = atan2( bq1*(k11*c1 + k21*d1), (bq1*k11*d1*bq1 - k21*c1) )/bq1;
+    dS1[1] = atan2( bq1*(k11*c1 - k21*d1), (-bq1*k11*d1*bq1 - k21*c1) )/bq1;
+    
+    float a = bq1*(k11*c1 + k21*d1);
+    float b = bq1*k11*d1*bq1 - k21*c1;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(( b*b + a*a ) > 0)
+      {
+        const float dadr1 = bq1*( dk11dr1[iP]*c1 + k11*dc1dr1[iP] + dk21dr1[iP]*d1 + k21*dd1dr1[iP] );
+        const float dadr2 = bq1*( dk11dr2[iP]*c1 + k11*dc1dr2[iP] + dk21dr2[iP]*d1 + k21*dd1dr2[iP] );
+        const float dbdr1 = bq1*bq1*( dk11dr1[iP]*d1 + k11*dd1dr1[iP] ) - ( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+        const float dbdr2 = bq1*bq1*( dk11dr2[iP]*d1 + k11*dd1dr2[iP] ) - ( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+      
+        dS1dR1[0][iP] = 1/bq1 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+        dS1dR2[0][iP] = 1/bq1 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+      }
+      else
+      {
+        dS1dR1[0][iP] = 0;
+        dS1dR2[0][iP] = 0;
+      }
+    }
+    
+    a = bq1*(k11*c1 - k21*d1);
+    b = -bq1*k11*d1*bq1 - k21*c1;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(( b*b + a*a ) > 0)
+      {
+        const float dadr1 = bq1*( dk11dr1[iP]*c1 + k11*dc1dr1[iP] - (dk21dr1[iP]*d1 + k21*dd1dr1[iP]) );
+        const float dadr2 = bq1*( dk11dr2[iP]*c1 + k11*dc1dr2[iP] - (dk21dr2[iP]*d1 + k21*dd1dr2[iP]) );
+        const float dbdr1 = -bq1*bq1*( dk11dr1[iP]*d1 + k11*dd1dr1[iP] ) - ( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+        const float dbdr2 = -bq1*bq1*( dk11dr2[iP]*d1 + k11*dd1dr2[iP] ) - ( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+      
+        dS1dR1[1][iP] = 1/bq1 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+        dS1dR2[1][iP] = 1/bq1 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+      }
+      else
+      {
+        dS1dR1[1][iP] = 0;
+        dS1dR2[1][iP] = 0;
+      }
+    }
+  }
+  if(!isStraight2)
+  {
+    dS2[0] = atan2( (bq2*k12*c2 + k22*d2*bq2), (bq2*k12*d2*bq2 - k22*c2) )/bq2;
+    dS2[1] = atan2( (bq2*k12*c2 - k22*d2*bq2), (-bq2*k12*d2*bq2 - k22*c2) )/bq2;
+    
+    float a = bq2*(k12*c2 + k22*d2);
+    float b = bq2*k12*d2*bq2 - k22*c2;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(( b*b + a*a ) > 0)
+      {
+        const float dadr1 = bq2*( dk12dr1[iP]*c2 + k12*dc2dr1[iP] + dk22dr1[iP]*d1 + k22*dd1dr1[iP] );
+        const float dadr2 = bq2*( dk12dr2[iP]*c2 + k12*dc2dr2[iP] + dk22dr2[iP]*d1 + k22*dd1dr2[iP] );
+        const float dbdr1 = bq2*bq2*( dk12dr1[iP]*d1 + k12*dd1dr1[iP] ) - (dk22dr1[iP]*c2 + k22*dc2dr1[iP]);
+        const float dbdr2 = bq2*bq2*( dk12dr2[iP]*d1 + k12*dd1dr2[iP] ) - (dk22dr2[iP]*c2 + k22*dc2dr2[iP]);
+      
+        dS2dR1[0][iP] = 1/bq2 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+        dS2dR2[0][iP] = 1/bq2 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+      }
+      else
+      {
+        dS2dR1[0][iP] = 0;
+        dS2dR2[0][iP] = 0;
+      }
+    }
+    
+    a = bq2*(k12*c2 - k22*d2);
+    b = -bq2*k12*d2*bq2 - k22*c2;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(( b*b + a*a ) > 0)
+      {
+        const float dadr1 = bq2*( dk12dr1[iP]*c2 + k12*dc2dr1[iP] - (dk22dr1[iP]*d1 + k22*dd1dr1[iP]) );
+        const float dadr2 = bq2*( dk12dr2[iP]*c2 + k12*dc2dr2[iP] - (dk22dr2[iP]*d1 + k22*dd1dr2[iP]) );
+        const float dbdr1 = -bq2*bq2*( dk12dr1[iP]*d1 + k12*dd1dr1[iP] ) - (dk22dr1[iP]*c2 + k22*dc2dr1[iP]);
+        const float dbdr2 = -bq2*bq2*( dk12dr2[iP]*d1 + k12*dd1dr2[iP] ) - (dk22dr2[iP]*c2 + k22*dc2dr2[iP]);
+      
+        dS2dR1[1][iP] = 1/bq2 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+        dS2dR2[1][iP] = 1/bq2 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+      }
+      else
+      {
+        dS2dR1[1][iP] = 0;
+        dS2dR2[1][iP] = 0;
+      }
+    }
+  }
+  if(isStraight1 && (pt12>0.f) )
+  {
+    dS1[0] = (k11*c1 + k21*d1)/(- k21*c1);
+    dS1[1] = (k11*c1 - k21*d1)/(- k21*c1);
+    
+    float a = k11*c1 + k21*d1;
+    float b = -k21*c1;
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      if(b*b > 0)
+      {
+        const float dadr1 = ( dk11dr1[iP]*c1 + k11*dc1dr1[iP] + dk21dr1[iP]*d1 + k21*dd1dr1[iP] );
+        const float dadr2 = ( dk11dr2[iP]*c1 + k11*dc1dr2[iP] + dk21dr2[iP]*d1 + k21*dd1dr2[iP] );
+        const float dbdr1 = -( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+        const float dbdr2 = -( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+    
+        dS1dR1[0][iP] = dadr1/b - dbdr1*a/(b*b) ;
+        dS1dR2[0][iP] = dadr2/b - dbdr2*a/(b*b) ;
+      }
+      else
+      {
+        dS1dR1[0][iP] = 0;
+        dS1dR2[0][iP] = 0;
+      }
+    }
+    
+    a = k11*c1 - k21*d1;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(b*b > 0)
+      {
+        const float dadr1 = ( dk11dr1[iP]*c1 + k11*dc1dr1[iP] - dk21dr1[iP]*d1 - k21*dd1dr1[iP] );
+        const float dadr2 = ( dk11dr2[iP]*c1 + k11*dc1dr2[iP] - dk21dr2[iP]*d1 - k21*dd1dr2[iP] );
+        const float dbdr1 = -( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+        const float dbdr2 = -( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+       
+        dS1dR1[1][iP] = dadr1/b - dbdr1*a/(b*b) ;
+        dS1dR2[1][iP] = dadr2/b - dbdr2*a/(b*b) ;
+      }
+      else
+      {
+        dS1dR1[1][iP] = 0;
+        dS1dR2[1][iP] = 0;
+      }
+    }
+  }
+  if(isStraight2 && (pt22>0.f) )
+  {
+    dS2[0] = (k12*c2 + k22*d2)/(- k22*c2);
+    dS2[1] = (k12*c2 - k22*d2)/(- k22*c2);  
+    
+    float a = k12*c2 + k22*d1;
+    float b = -k22*c2;
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      if(b*b > 0)
+      {
+        const float dadr1 = ( dk12dr1[iP]*c2 + k12*dc2dr1[iP] + dk22dr1[iP]*d1 + k22*dd1dr1[iP] );
+        const float dadr2 = ( dk12dr2[iP]*c2 + k12*dc2dr2[iP] + dk22dr2[iP]*d1 + k22*dd1dr2[iP] );
+        const float dbdr1 = -( dk22dr1[iP]*c2 + k22*dc2dr1[iP] );
+        const float dbdr2 = -( dk22dr2[iP]*c2 + k22*dc2dr2[iP] );
+    
+        dS2dR1[0][iP] = dadr1/b - dbdr1*a/(b*b) ;
+        dS2dR2[0][iP] = dadr2/b - dbdr2*a/(b*b) ;
+      }
+      else
+      {
+        dS2dR1[0][iP] = 0;
+        dS2dR2[0][iP] = 0;
+      }
+    }
+    
+    a = k12*c2 - k22*d1;
+    for(int iP=0; iP<6; iP++)
+    {
+      if(b*b > 0)
+      {
+        const float dadr1 = ( dk12dr1[iP]*c2 + k12*dc2dr1[iP] - dk22dr1[iP]*d1 - k22*dd1dr1[iP] );
+        const float dadr2 = ( dk12dr2[iP]*c2 + k12*dc2dr2[iP] - dk22dr2[iP]*d1 - k22*dd1dr2[iP] );
+        const float dbdr1 = -( dk22dr1[iP]*c2 + k22*dc2dr1[iP] );
+        const float dbdr2 = -( dk22dr2[iP]*c2 + k22*dc2dr2[iP] );
+    
+        dS2dR1[1][iP] = dadr1/b - dbdr1*a/(b*b) ;
+        dS2dR2[1][iP] = dadr2/b - dbdr2*a/(b*b) ;
+      }
+      else
+      {
+        dS2dR1[1][iP] = 0;
+        dS2dR2[1][iP] = 0;
+      }
+    }
+  }
+  
+  //select a point which is close to the primary vertex (with the smallest r)
+  
+  float dr2[2];
+  for(int iP = 0; iP<2; iP++)
+  {
+    const float& bs1 = bq1*dS1[iP];
+    const float& bs2 = bq2*dS2[iP];
+    float sss = sin(bs1), ccc = cos(bs1);
+    
+    const bool& bs1Big = fabs(bs1) > 1.e-8f;
+    const bool& bs2Big = fabs(bs2) > 1.e-8f;
+    
+    float sB(0.f), cB(0.f);
+    if(bs1Big)
+    {
+      sB = sss/bq1;
+      cB = (1.f-ccc)/bq1;
+    }
+    else
+    {
+      sB = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS1[iP]);
+      cB = .5f*sB*bs1;
+    }
+  
+    const float& x1 = param1[0] + sB*px1 + cB*py1;
+    const float& y1 = param1[1] - cB*px1 + sB*py1;
+    const float& z1 = param1[2] + dS1[iP]*param1[5];
+
+    sss = sin(bs2), ccc = cos(bs2);
+
+    if(bs2Big)
+    {
+      sB = sss/bq2;
+      cB = (1.f-ccc)/bq2;
+    }
+    else
+    {
+      sB = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS2[iP]);
+      cB = .5f*sB*bs2;
+    }
+
+    const float& x2 = param2[0] + sB*px2 + cB*py2;
+    const float& y2 = param2[1] - cB*px2 + sB*py2;
+    const float& z2 = param2[2] + dS2[iP]*param2[5];
+
+    float dx = (x1-x2);
+    float dy = (y1-y2);
+    float dz = (z1-z2);
+    
+    dr2[iP] = dx*dx + dy*dy + dz*dz;
+  }
+  
+  const bool isFirstRoot = dr2[0] < dr2[1];
+  if(isFirstRoot)
+  {
+    dS[0]  = dS1[0];
+    dS[1] = dS2[0];
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      dsdr[0][iP] = dS1dR1[0][iP];
+      dsdr[1][iP] = dS1dR2[0][iP];
+      dsdr[2][iP] = dS2dR1[0][iP];
+      dsdr[3][iP] = dS2dR2[0][iP];
+    }
+  }
+  else
+  {
+    dS[0]  = dS1[1];
+    dS[1] = dS2[1];
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      dsdr[0][iP] = dS1dR1[1][iP];
+      dsdr[1][iP] = dS1dR2[1][iP];
+      dsdr[2][iP] = dS2dR1[1][iP];      
+      dsdr[3][iP] = dS2dR2[1][iP];
+    }    
+  }
+    
+  //find correct parts of helices
+  int n1(0);
+  int n2(0);
+  float dzMin = fabs( (z01-z02) + dS[0]*pz1 - dS[1]*pz2 );
+  const float pi2(6.283185307f);
+  
+  //TODO optimise for loops for neutral particles
+  const float& i1Float = -bq1/pi2*(z01/pz1+dS[0]);
+  for(int di1=-1; di1<=1; di1++)
+  {
+    int i1(0);
+    if(!isStraight1)
+      i1 = int(i1Float) + di1;
+    
+    const float& i2Float = ( ((z01-z02) + (dS[0]+pi2*i1/bq1)*pz1)/pz2 - dS[1]) * bq2/pi2;
+    for(int di2 = -1; di2<=1; di2++)
+    {
+      int i2(0);
+      if(!isStraight2)
+        i2 = int(i2Float) + di2;
+      
+      const float& z1 = z01 + (dS[0]+pi2*i1/bq1)*pz1;
+      const float& z2 = z02 + (dS[1]+pi2*i2/bq2)*pz2;
+      const float& dz = fabs( z1-z2 );
+    
+      if(dz < dzMin)
+      {
+        n1 = i1;
+        n2 = i2;
+        dzMin = dz;
+      }
+    }
+  }
+
+  if(!isStraight1)
+    dS[0] += float(n1)*pi2/bq1;
+  if(!isStraight2)
+    dS[1] += float(n2)*pi2/bq2;
+
+  //Line correction
+  {
+    const float& bs1 = bq1*dS[0];
+    const float& bs2 = bq2*dS[1];
+    float sss = sin(bs1), ccc = cos(bs1);
+    
+    const bool& bs1Big = fabs(bs1) > 1.e-8f;
+    const bool& bs2Big = fabs(bs2) > 1.e-8f;
+    
+    float sB(0.f), cB(0.f);
+    if(bs1Big)
+    {
+      sB = sss/bq1;
+      cB = (1.f-ccc)/bq1;
+    }
+    else
+    {
+      sB = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS[0]);
+      cB = .5f*sB*bs1;
+    }
+  
+    const float& x1 = x01 + sB*px1 + cB*py1;
+    const float& y1 = y01 - cB*px1 + sB*py1;
+    const float& z1 = z01 + dS[0]*pz1;
+    const float& ppx1 =  ccc*px1 + sss*py1;
+    const float& ppy1 = -sss*px1 + ccc*py1;
+    const float& ppz1 = pz1;
+    
+    float sss1 = sin(bs2), ccc1 = cos(bs2);
+
+    float sB1(0.f), cB1(0.f);
+    if(bs2Big)
+    {
+      sB1 = sss1/bq2;
+      cB1 = (1.f-ccc1)/bq2;
+    }
+    else
+    {
+      sB1 = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS[1]);
+      cB1 = .5f*sB1*bs2;
+    }
+
+    const float& x2 = x02 + sB1*px2 + cB1*py2;
+    const float& y2 = y02 - cB1*px2 + sB1*py2;
+    const float& z2 = z02 + dS[1]*pz2;
+    const float& ppx2 =  ccc1*px2 + sss1*py2;
+    const float& ppy2 = -sss1*px2 + ccc1*py2;    
+    const float& ppz2 = pz2;
+
+    const float& p12  = ppx1*ppx1 + ppy1*ppy1 + ppz1*ppz1;
+    const float& p22  = ppx2*ppx2 + ppy2*ppy2 + ppz2*ppz2;
+    const float& lp1p2 = ppx1*ppx2 + ppy1*ppy2 + ppz1*ppz2;
+
+    const float& dx = (x2 - x1);
+    const float& dy = (y2 - y1);
+    const float& dz = (z2 - z1);
+    
+    const float& ldrp1 = ppx1*dx + ppy1*dy + ppz1*dz;
+    const float& ldrp2 = ppx2*dx + ppy2*dy + ppz2*dz;
+
+    float detp =  lp1p2*lp1p2 - p12*p22;
+    if( fabs(detp)<1.e-4 ) detp = 1; //TODO correct!!!
+    
+    //dsdr calculation
+    const float a1 = ldrp2*lp1p2 - ldrp1*p22;
+    const float a2 = ldrp2*p12 - ldrp1*lp1p2;
+    const float lp1p2_ds0 = bq1*( ppx2*ppy1 - ppy2*ppx1);
+    const float lp1p2_ds1 = bq2*( ppx1*ppy2 - ppy1*ppx2);
+    const float ldrp1_ds0 = -p12 + bq1*(ppy1*dx - ppx1*dy);
+    const float ldrp1_ds1 =  lp1p2;
+    const float ldrp2_ds0 = -lp1p2;
+    const float ldrp2_ds1 =  p22 + bq2*(ppy2*dx - ppx2*dy);
+    const float detp_ds0 = 2*lp1p2*lp1p2_ds0;
+    const float detp_ds1 = 2*lp1p2*lp1p2_ds1;
+    const float a1_ds0 = ldrp2_ds0*lp1p2 + ldrp2*lp1p2_ds0 - ldrp1_ds0*p22;
+    const float a1_ds1 = ldrp2_ds1*lp1p2 + ldrp2*lp1p2_ds1 - ldrp1_ds1*p22;
+    const float a2_ds0 = ldrp2_ds0*p12 - ldrp1_ds0*lp1p2 - ldrp1*lp1p2_ds0;
+    const float a2_ds1 = ldrp2_ds1*p12 - ldrp1_ds1*lp1p2 - ldrp1*lp1p2_ds1;
+    
+    const float dsl1ds0 = a1_ds0/detp - a1*detp_ds0/(detp*detp);
+    const float dsl1ds1 = a1_ds1/detp - a1*detp_ds1/(detp*detp);
+    const float dsl2ds0 = a2_ds0/detp - a2*detp_ds0/(detp*detp);
+    const float dsl2ds1 = a2_ds1/detp - a2*detp_ds1/(detp*detp);
+    
+    float dsldr[4][6];
+    for(int iP=0; iP<6; iP++)
+    {
+      dsldr[0][iP] = dsl1ds0*dsdr[0][iP] + dsl1ds1*dsdr[2][iP];
+      dsldr[1][iP] = dsl1ds0*dsdr[1][iP] + dsl1ds1*dsdr[3][iP];
+      dsldr[2][iP] = dsl2ds0*dsdr[0][iP] + dsl2ds1*dsdr[2][iP];
+      dsldr[3][iP] = dsl2ds0*dsdr[1][iP] + dsl2ds1*dsdr[3][iP];
+    }
+    
+    for(int iDS=0; iDS<4; iDS++)
+      for(int iP=0; iP<6; iP++)
+        dsdr[iDS][iP] += dsldr[iDS][iP];
+      
+    const float lp1p2_dr0[6] = {0, 0, 0, ccc*ppx2 - ppy2*sss, ccc*ppy2 + ppx2*sss, pz2};
+    const float lp1p2_dr1[6] = {0, 0, 0, ccc1*ppx1 - ppy1*sss1, ccc1*ppy1 + ppx1*sss1, pz1};
+    const float ldrp1_dr0[6] = {-ppx1, -ppy1, -pz1,  cB*ppy1 - ppx1*sB + ccc*dx - sss*dy, -cB*ppx1-ppy1*sB + sss*dx + ccc*dy, -dS[0]*pz1 + dz};
+    const float ldrp1_dr1[6] = { ppx1,  ppy1,  pz1, -cB1*ppy1 + ppx1*sB1, cB1*ppx1 + ppy1*sB1, dS[1]*pz1};
+    const float ldrp2_dr0[6] = {-ppx2, -ppy2, -pz2, cB*ppy2 - ppx2*sB, -cB*ppx2-ppy2*sB, -dS[0]*pz2};
+    const float ldrp2_dr1[6] = {ppx2, ppy2, pz2, -cB1*ppy2 + ppx2*sB1 + ccc1*dx- sss1*dy, cB1*ppx2 + ppy2*sB1 + sss1*dx + ccc1*dy, dz + dS[1]*pz2};
+    const float p12_dr0[6] = {0, 0, 0, 2*px1, 2*py1, 2*pz1};
+    const float p22_dr1[6] = {0, 0, 0, 2*px2, 2*py2, 2*pz2};
+    float a1_dr0[6], a1_dr1[6], a2_dr0[6], a2_dr1[6], detp_dr0[6], detp_dr1[6];
+    for(int iP=0; iP<6; iP++)
+    {
+      a1_dr0[iP] = ldrp2_dr0[iP]*lp1p2 + ldrp2*lp1p2_dr0[iP] - ldrp1_dr0[iP]*p22;
+      a1_dr1[iP] = ldrp2_dr1[iP]*lp1p2 + ldrp2*lp1p2_dr1[iP] - ldrp1_dr1[iP]*p22 - ldrp1*p22_dr1[iP];
+      a2_dr0[iP] = ldrp2_dr0[iP]*p12 + ldrp2*p12_dr0[iP] - ldrp1_dr0[iP]*lp1p2 - ldrp1*lp1p2_dr0[iP];
+      a2_dr1[iP] = ldrp2_dr1[iP]*p12 - ldrp1_dr1[iP]*lp1p2 - ldrp1*lp1p2_dr1[iP];
+      detp_dr0[iP] = 2*lp1p2*lp1p2_dr0[iP] - p12_dr0[iP]*p22;
+      detp_dr1[iP] = 2*lp1p2*lp1p2_dr1[iP] - p12*p22_dr1[iP];
+      
+      dsdr[0][iP] += a1_dr0[iP]/detp - a1*detp_dr0[iP]/(detp*detp);
+      dsdr[1][iP] += a1_dr1[iP]/detp - a1*detp_dr1[iP]/(detp*detp);
+      dsdr[2][iP] += a2_dr0[iP]/detp - a2*detp_dr0[iP]/(detp*detp);
+      dsdr[3][iP] += a2_dr1[iP]/detp - a2*detp_dr1[iP]/(detp*detp);
+    }
+    
+    dS[0] += (ldrp2*lp1p2 - ldrp1*p22) /detp;
+    dS[1] += (ldrp2*p12 - ldrp1*lp1p2)/detp;    
+  }  
+}
+
+void KFParticleBase::GetDStoParticleBy( float B,  const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const
+{ 
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** The particle parameters are transformed to the coordinate system, where the main component of the magnetic field
+   ** By is directed along the Z axis: x->x, y->-z, z->y, and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] B - magnetic field By
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  const float param1[6] = { fP[0], -fP[2], fP[1], fP[3], -fP[5], fP[4] };
+  const float param2[6] = { p.fP[0], -p.fP[2], p.fP[1], p.fP[3], -p.fP[5], p.fP[4] };
+  
+  float dsdrBz[4][6];
+  for(int i1=0; i1<4; i1++)
+    for(int i2=0; i2<6; i2++)
+      dsdrBz[i1][i2] = 0;
+  
+  GetDStoParticleBz(B, p, dS, dsdrBz, param1, param2);
+  
+  for(int iDs=0; iDs<4; iDs++)
+  {
+    dsdr[iDs][0] =  dsdrBz[iDs][0];
+    dsdr[iDs][1] =  dsdrBz[iDs][2];
+    dsdr[iDs][2] = -dsdrBz[iDs][1];
+    dsdr[iDs][3] =  dsdrBz[iDs][3];
+    dsdr[iDs][4] =  dsdrBz[iDs][5];
+    dsdr[iDs][5] = -dsdrBz[iDs][4];
+  }
+}
+
+void KFParticleBase::GetDStoParticleLine( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the straight line trajectory. Is used for particles with charge 0 or in case of zero magnetic field.
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  float p12 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5];
+  float p22 = p.fP[3]*p.fP[3] + p.fP[4]*p.fP[4] + p.fP[5]*p.fP[5];
+  float p1p2 = fP[3]*p.fP[3] + fP[4]*p.fP[4] + fP[5]*p.fP[5];
+
+  float drp1 = fP[3]*(p.fP[0]-fP[0]) + fP[4]*(p.fP[1]-fP[1]) + fP[5]*(p.fP[2]-fP[2]);
+  float drp2 = p.fP[3]*(p.fP[0]-fP[0]) + p.fP[4]*(p.fP[1]-fP[1]) + p.fP[5]*(p.fP[2]-fP[2]);
+
+  float detp =  p1p2*p1p2 - p12*p22;
+  if( fabs(detp)<1.e-4 ) detp = 1; //TODO correct!!!
+
+  dS[0]  = (drp2*p1p2 - drp1*p22) /detp;
+  dS[1] = (drp2*p12  - drp1*p1p2)/detp;
+  
+  const float x01 = fP[0];
+  const float y01 = fP[1];
+  const float z01 = fP[2];
+  const float px1 = fP[3];
+  const float py1 = fP[4];
+  const float pz1 = fP[5];
+
+  const float x02 = p.fP[0];
+  const float y02 = p.fP[1];
+  const float z02 = p.fP[2];
+  const float px2 = p.fP[3];
+  const float py2 = p.fP[4];
+  const float pz2 = p.fP[5];
+  
+  const float drp1_dr1[6] = {-px1, -py1, -pz1, -x01 + x02, -y01 + y02, -z01 + z02};
+  const float drp1_dr2[6] = {px1, py1, pz1, 0, 0, 0};
+  const float drp2_dr1[6] = {-px2, -py2, -pz2, 0, 0, 0};
+  const float drp2_dr2[6] = {px2, py2, pz2, -x01 + x02, -y01 + y02, -z01 + z02};
+  const float dp1p2_dr1[6] = {0, 0, 0, px2, py2, pz2};
+  const float dp1p2_dr2[6] = {0, 0, 0, px1, py1, pz1};
+  const float dp12_dr1[6] = {0, 0, 0, 2*px1, 2*py1, 2*pz1};
+  const float dp12_dr2[6] = {0, 0, 0, 0, 0, 0};
+  const float dp22_dr1[6] = {0, 0, 0, 0, 0, 0};
+  const float dp22_dr2[6] = {0, 0, 0, 2*px2, 2*py2, 2*pz2};
+  const float ddetp_dr1[6] = {0, 0, 0, -2*p22*px1 + 2*p1p2*px2, -2*p22*py1 + 2*p1p2*py2, -2*p22*pz1 + 2*p1p2*pz2};
+  const float ddetp_dr2[6] = {0, 0, 0, 2*p1p2*px1 - 2*p12*px2,   2*p1p2*py1 - 2*p12*py2, 2*p1p2*pz1 - 2*p12*pz2};
+  
+  
+  float da1_dr1[6], da1_dr2[6], da2_dr1[6], da2_dr2[6];
+  
+  const float a1 = drp2*p1p2 - drp1*p22;
+  const float a2 = drp2*p12  - drp1*p1p2;
+  for(int i=0; i<6; i++)
+  {
+    da1_dr1[i] = drp2_dr1[i]*p1p2 + drp2*dp1p2_dr1[i] - drp1_dr1[i]*p22 - drp1*dp22_dr1[i];
+    da1_dr2[i] = drp2_dr2[i]*p1p2 + drp2*dp1p2_dr2[i] - drp1_dr2[i]*p22 - drp1*dp22_dr2[i];
+    
+    da2_dr1[i] = drp2_dr1[i]*p12 + drp2*dp12_dr1[i] - drp1_dr1[i]*p1p2 - drp1*dp1p2_dr1[i];
+    da2_dr2[i] = drp2_dr2[i]*p12 + drp2*dp12_dr2[i] - drp1_dr2[i]*p1p2 - drp1*dp1p2_dr2[i];
+    
+    dsdr[0][i] = da1_dr1[i]/detp - a1/(detp*detp)*ddetp_dr1[i];
+    dsdr[1][i] = da1_dr2[i]/detp - a1/(detp*detp)*ddetp_dr2[i];
+    
+    dsdr[2][i] = da2_dr1[i]/detp - a2/(detp*detp)*ddetp_dr1[i];
+    dsdr[3][i] = da2_dr2[i]/detp - a2/(detp*detp)*ddetp_dr2[i];
+  }
+}
+
+void KFParticleBase::GetDStoParticleCBM( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** in case of the CBM-like nonhomogeneous magnetic field. 
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** For this the y-component of the magnetic field at the position of the current particle is obtained and
+   ** the GetDStoParticleBy() is called. It is assumed that particles are already close to each other and that the difference 
+   ** in magnetic field approximation between two particles can be neglected. If the charge of both particles 
+   ** is zero or if the magnetic field is zero the function GetDStoParticleLine() is called.
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  float fld[3];
+  GetFieldValue( fP, fld );
+  
+  const float& bq1 = fld[1]*fQ;
+  const float& bq2 = fld[1]*p.fQ;
+  const bool& isStraight1 = fabs(bq1) < 1.e-8f;
+  const bool& isStraight2 = fabs(bq2) < 1.e-8f;
+  
+  if( isStraight1 && isStraight2 )
+    GetDStoParticleLine(p, dS, dsdr);
+  else
+    GetDStoParticleBy(fld[1], p, dS, dsdr);
+}
+
+void KFParticleBase::TransportCBM( float dS, const float* dsdr, float P[], float C[], float* dsdr1, float* F, float* F1) const
+{
+  /** Transports the parameters and their covariance matrix of the current particle assuming CBM-like nonhomogeneous 
+   ** magnetic field on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/
+
+  if( fQ==0 ){
+    TransportLine( dS, dsdr, P, C, dsdr1, F, F1 );
+    return;
+  }
+
+  if( fabs(dS*fP[5]) > 1000.f ) dS = 0;
+  
+  const float kCLight = 0.000299792458;
+
+  float c = fQ*kCLight;
+
+  // construct coefficients 
+
+  float 
+    px   = fP[3],
+    py   = fP[4],
+    pz   = fP[5];
+      
+  float sx=0, sy=0, sz=0, syy=0, syz=0, syyy=0, ssx=0, ssy=0, ssz=0, ssyy=0, ssyz=0, ssyyy=0;
+
+  { // get field integrals
+
+    float fld[3][3];   
+    float p0[3], p1[3], p2[3];
+
+    // line track approximation
+
+    p0[0] = fP[0];
+    p0[1] = fP[1];
+    p0[2] = fP[2];
+  
+    p2[0] = fP[0] + px*dS;
+    p2[1] = fP[1] + py*dS;
+    p2[2] = fP[2] + pz*dS;
+  
+    p1[0] = 0.5*(p0[0]+p2[0]);
+    p1[1] = 0.5*(p0[1]+p2[1]);
+    p1[2] = 0.5*(p0[2]+p2[2]);
+
+    // first order track approximation
+    {
+      GetFieldValue( p0, fld[0] );
+      GetFieldValue( p1, fld[1] );
+      GetFieldValue( p2, fld[2] );
+
+      float ssy1 = ( 7*fld[0][1] + 6*fld[1][1]-fld[2][1] )*c*dS*dS/96.;
+      float ssy2 = (   fld[0][1] + 2*fld[1][1]         )*c*dS*dS/6.;
+
+      p1[0] -= ssy1*pz;
+      p1[2] += ssy1*px;
+      p2[0] -= ssy2*pz;
+      p2[2] += ssy2*px;   
+    }
+
+    GetFieldValue( p0, fld[0] );
+    GetFieldValue( p1, fld[1] );
+    GetFieldValue( p2, fld[2] );
+
+    sx = c*( fld[0][0] + 4*fld[1][0] + fld[2][0] )*dS/6.;
+    sy = c*( fld[0][1] + 4*fld[1][1] + fld[2][1] )*dS/6.;
+    sz = c*( fld[0][2] + 4*fld[1][2] + fld[2][2] )*dS/6.;
+
+    ssx = c*( fld[0][0] + 2*fld[1][0])*dS*dS/6.;
+    ssy = c*( fld[0][1] + 2*fld[1][1])*dS*dS/6.;
+    ssz = c*( fld[0][2] + 2*fld[1][2])*dS*dS/6.;
+
+    float c2[3][3]    =   { {  5, -4, -1},{  44,  80,  -4},{ 11, 44, 5} }; // /=360.    
+    float cc2[3][3]    =   { { 38,  8, -4},{ 148, 208, -20},{  3, 36, 3} }; // /=2520.
+    for(Int_t n=0; n<3; n++)
+      for(Int_t m=0; m<3; m++) 
+      {
+        syz += c2[n][m]*fld[n][1]*fld[m][2];
+        ssyz += cc2[n][m]*fld[n][1]*fld[m][2];
+      }
+ 
+    syz  *= c*c*dS*dS/360.;
+    ssyz  *= c*c*dS*dS*dS/2520.;
+    
+    syy  = c*( fld[0][1] + 4*fld[1][1] + fld[2][1] )*dS;
+    syyy = syy*syy*syy / 1296;
+    syy  = syy*syy/72;
+
+    ssyy = ( fld[0][1]*( 38*fld[0][1] + 156*fld[1][1]  -   fld[2][1] )+
+             fld[1][1]*(                208*fld[1][1]  +16*fld[2][1] )+
+             fld[2][1]*(                                 3*fld[2][1] )  
+           )*dS*dS*dS*c*c/2520.;
+    ssyyy = 
+      (
+       fld[0][1]*( fld[0][1]*( 85*fld[0][1] + 526*fld[1][1]  - 7*fld[2][1] )+
+                   fld[1][1]*(               1376*fld[1][1]  +84*fld[2][1] )+
+                   fld[2][1]*(                                19*fld[2][1] )  )+
+       fld[1][1]*( fld[1][1]*(             1376*fld[1][1] +256*fld[2][1] )+
+                   fld[2][1]*(                              62*fld[2][1] )  )+
+       fld[2][1]*fld[2][1]  *(                               3*fld[2][1] )       
+      )*dS*dS*dS*dS*c*c*c/90720.;    
+ 
+  }
+
+  float mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  mJ[0][0]=1; mJ[0][1]=0; mJ[0][2]=0; mJ[0][3]=dS-ssyy;  mJ[0][4]=ssx;  mJ[0][5]=ssyyy-ssy;
+  mJ[1][0]=0; mJ[1][1]=1; mJ[1][2]=0; mJ[1][3]=-ssz;     mJ[1][4]=dS;  mJ[1][5]=ssx+ssyz;
+  mJ[2][0]=0; mJ[2][1]=0; mJ[2][2]=1; mJ[2][3]=ssy-ssyyy; mJ[2][4]=-ssx; mJ[2][5]=dS-ssyy;
+  
+  mJ[3][0]=0; mJ[3][1]=0; mJ[3][2]=0; mJ[3][3]=1-syy;   mJ[3][4]=sx;  mJ[3][5]=syyy-sy;
+  mJ[4][0]=0; mJ[4][1]=0; mJ[4][2]=0; mJ[4][3]=-sz;     mJ[4][4]=1;   mJ[4][5]=sx+syz;
+  mJ[5][0]=0; mJ[5][1]=0; mJ[5][2]=0; mJ[5][3]=sy-syyy; mJ[5][4]=-sx; mJ[5][5]=1-syy;
+  mJ[6][6] = mJ[7][7] = 1;
+  
+  P[0] = fP[0] + mJ[0][3]*px + mJ[0][4]*py + mJ[0][5]*pz;
+  P[1] = fP[1] + mJ[1][3]*px + mJ[1][4]*py + mJ[1][5]*pz;
+  P[2] = fP[2] + mJ[2][3]*px + mJ[2][4]*py + mJ[2][5]*pz;
+  P[3] =         mJ[3][3]*px + mJ[3][4]*py + mJ[3][5]*pz;
+  P[4] =         mJ[4][3]*px + mJ[4][4]*py + mJ[4][5]*pz;
+  P[5] =         mJ[5][3]*px + mJ[5][4]*py + mJ[5][5]*pz;
+  P[6] = fP[6];
+  P[7] = fP[7];
+
+  float mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+
+  if(fabs(dS)>0)
+  {
+    mJds[0][3]= 1 - 3*ssyy/dS;          mJds[0][4]= 2*ssx/dS; mJds[0][5]= (4.f*ssyyy-2*ssy)/dS;
+    mJds[1][3]= -2.f*ssz/dS;            mJds[1][4]= 1;        mJds[1][5]= (2.f*ssx + 3.*ssyz)/dS;
+    mJds[2][3]= (2.f*ssy-4.f*ssyyy)/dS; mJds[2][4]=-2*ssx/dS; mJds[2][5]= 1 - 3.f*ssyy/dS;
+  
+    mJds[3][3]= -2.f*syy/dS;            mJds[3][4]= sx/dS;    mJds[3][5]= 3.f*syyy/dS - sy/dS;
+    mJds[4][3]= -sz/dS;                 mJds[4][4]=0;         mJds[4][5] = sx/dS + 2.f*syz/dS;
+    mJds[5][3]= sy/dS - 3.f*syyy/dS;    mJds[5][4]=-sx/dS;    mJds[5][5]= -2.f*syy/dS;
+  }
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+  
+  MultQSQt( mJ[0], fC, C, 8);
+  
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+
+void KFParticleBase::TransportBz( float Bz, float dS, const float* dsdr, float P[], float C[], float* dsdr1, float* F, float* F1 ) const 
+{ 
+  /** Transports the parameters and their covariance matrix of the current particle assuming constant homogeneous 
+   ** magnetic field Bz on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] Bz - z-component of the constant homogeneous magnetic field Bz
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/  
+  
+  const float kCLight = 0.000299792458;
+  Bz = Bz*fQ*kCLight;
+  float bs= Bz*dS;
+  float s = sin(bs), c = cos(bs);
+  float sB, cB;
+  if( fabs(bs)>1.e-10){
+    sB= s/Bz;
+    cB= (1-c)/Bz;
+  }else{
+    const float kOvSqr6 = 1./sqrt(6.);
+    sB = (1.-bs*kOvSqr6)*(1.+bs*kOvSqr6)*dS;
+    cB = .5*sB*bs;
+  }
+  
+  float px = fP[3];
+  float py = fP[4];
+  float pz = fP[5];
+
+  P[0] = fP[0] + sB*px + cB*py;
+  P[1] = fP[1] - cB*px + sB*py;
+  P[2] = fP[2] +  dS*pz;
+  P[3] =          c*px + s*py;
+  P[4] =         -s*px + c*py;
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];
+
+  float mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  for(int i=0; i<8; i++) mJ[i][i]=1;
+  mJ[0][3] =  sB; mJ[0][4] = cB;
+  mJ[1][3] = -cB; mJ[1][4] = sB;
+  mJ[2][5] = dS;
+  mJ[3][3] =  c; mJ[3][4] = s;
+  mJ[4][3] = -s; mJ[4][4] = c;
+  
+  
+  float mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+  mJds[0][3] =  c; mJds[0][4] = s;
+  mJds[1][3] = -s; mJds[1][4] = c;
+  mJds[2][5] = 1;
+  mJds[3][3] = -Bz*s; mJds[3][4] =  Bz*c;
+  mJds[4][3] = -Bz*c; mJds[4][4] = -Bz*s;
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+  
+  MultQSQt( mJ[0], fC, C, 8);
+  
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+
+float KFParticleBase::GetDistanceFromVertex( const KFParticleBase &Vtx ) const
+{
+  /** Returns the DCA distance from vertex in the KFParticle format in 3D.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+
+  return GetDistanceFromVertex( Vtx.fP );
+}
+
+float KFParticleBase::GetDistanceFromVertex( const float vtx[] ) const
+{
+  /** Returns the DCA distance from vertex in 3D.
+   ** \param[in] vtx[3] - the vertex coordinates {X, Y, Z}
+   **/
+  
+  float mP[8], mC[36];  
+  
+  float dsdr[6] = {0.f};
+  const float dS = GetDStoPoint(vtx, dsdr);
+  
+  Transport( dS, dsdr, mP, mC );
+  float d[3]={ vtx[0]-mP[0], vtx[1]-mP[1], vtx[2]-mP[2]};
+  return sqrt( d[0]*d[0]+d[1]*d[1]+d[2]*d[2] );
+}
+
+float KFParticleBase::GetDistanceFromParticle( const KFParticleBase &p ) 
+  const
+{ 
+  /** Returns the DCA distance from another particle p.
+   ** \param[in] p - the second particle
+   **/
+  
+  float dsdr[4][6];
+  float dS[2];
+  GetDStoParticle( p, dS, dsdr );   
+  float mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+  float dx = mP[0]-mP1[0]; 
+  float dy = mP[1]-mP1[1]; 
+  float dz = mP[2]-mP1[2]; 
+  return sqrt(dx*dx+dy*dy+dz*dz);
+}
+
+float KFParticleBase::GetDeviationFromVertex( const KFParticleBase &Vtx ) const
+{
+  /** Returns Chi2 deviation of the current particle from the vertex in the KFParticle format in 3D.
+   ** \param[in] Vtx - the vertex in KFPartcile format
+   **/
+
+  return GetDeviationFromVertex( Vtx.fP, Vtx.fC );
+}
+
+
+float KFParticleBase::GetDeviationFromVertex( const float v[], const float Cv[] ) const
+{
+  /** Returns Chi2 deviation of the current particle from the vertex v with the covariance matrix Cv in 3D.
+   ** \param[in] v[3] - coordinates of the vertex {X, Y, Z}
+   ** \param[in] Cv[6] - covariance matrix of the vertex {Cxx, Cxy, Cyy, Cxz, Czy, Czz}
+   **/
+
+  float mP[8];
+  float mC[36];
+  float dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float dS = GetDStoPoint(v, dsdr);
+  float dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0, 0, 0};
+  float F[36], F1[36];
+  for(int i2=0; i2<36; i2++)
+  {
+    F[i2]  = 0;
+    F1[i2] = 0;
+  }
+  Transport( dS, dsdr, mP, mC, dsdp, F, F1 );  
+
+  if(Cv)
+  {
+    float VFT[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<6; j++)
+      {
+        VFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          VFT[i][j] +=  Cv[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+  
+    float FVFT[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        FVFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          FVFT[i][j] += F1[i*6+k] * VFT[k][j];
+        }
+      }
+    mC[0] += FVFT[0][0] + Cv[0];
+    mC[1] += FVFT[1][0] + Cv[1];
+    mC[2] += FVFT[1][1] + Cv[2];
+    mC[3] += FVFT[2][0] + Cv[3];
+    mC[4] += FVFT[2][1] + Cv[4];
+    mC[5] += FVFT[2][2] + Cv[5];
+  }
+  
+  InvertCholetsky3(mC);
+  
+  float d[3]={ v[0]-mP[0], v[1]-mP[1], v[2]-mP[2]};
+
+  return ( ( mC[0]*d[0] + mC[1]*d[1] + mC[3]*d[2])*d[0]
+           +(mC[1]*d[0] + mC[2]*d[1] + mC[4]*d[2])*d[1]
+           +(mC[3]*d[0] + mC[4]*d[1] + mC[5]*d[2])*d[2] );
+}
+
+
+float KFParticleBase::GetDeviationFromParticle( const KFParticleBase &p ) const
+{ 
+  /** Returns Chi2 deviation of the current particle from another particle in 3D.
+   ** \param[in] p - the second particle
+   **/
+  
+  float ds[2] = {0.f,0.f};
+  float dsdr[4][6];
+  float F1[36], F2[36], F3[36], F4[36];
+  for(int i1=0; i1<36; i1++)
+  {
+    F1[i1] = 0;
+    F2[i1] = 0;
+    F3[i1] = 0;
+    F4[i1] = 0;
+  }
+  GetDStoParticle( p, ds, dsdr );
+  
+  float V0Tmp[36] = {0.};
+  float V1Tmp[36] = {0.};
+
+  
+  float mP1[8], mC1[36];
+  float mP2[8], mC2[36]; 
+  
+    Transport(ds[0], dsdr[0], mP1, mC1, dsdr[1], F1, F2);
+  p.Transport(ds[1], dsdr[3], mP2, mC2, dsdr[2], F4, F3);
+  
+  MultQSQt(F2, p.fC, V0Tmp, 6);
+  MultQSQt(F3,   fC, V1Tmp, 6);
+      
+  for(int iC=0; iC<6; iC++)
+    mC1[iC] += V0Tmp[iC] + mC2[iC] + V1Tmp[iC];
+
+  float d[3]={ mP2[0]-mP1[0], mP2[1]-mP1[1], mP2[2]-mP1[2]};
+  
+  return ( ( mC1[0]*d[0] + mC1[1]*d[1] + mC1[3]*d[2])*d[0]
+           +(mC1[1]*d[0] + mC1[2]*d[1] + mC1[4]*d[2])*d[1]
+           +(mC1[3]*d[0] + mC1[4]*d[1] + mC1[5]*d[2])*d[2] );
+}
+
+
+
+void KFParticleBase::SubtractFromVertex(  KFParticleBase &Vtx ) const
+{
+  /** Subtract the current particle from vertex Vtx using the Kalman filter mathematics.
+   ** \param[in] Vtx - vertex from which particle should be subtracted
+   **/
+  
+  float m[8];
+  float mCm[36];
+  float D[3][3];
+  Vtx.GetMeasurement( *this, m, mCm, D );
+  //* 
+	    
+  float mS[6] = { mCm[0] - Vtx.fC[0] + (D[0][0] + D[0][0]), 
+                  mCm[1] - Vtx.fC[1] + (D[1][0] + D[0][1]), mCm[2] - Vtx.fC[2] + (D[1][1] + D[1][1]), 
+                  mCm[3] - Vtx.fC[3] + (D[2][0] + D[0][2]), mCm[4] - Vtx.fC[4] + (D[1][2] + D[2][1]), mCm[5] - Vtx.fC[5] + (D[2][2] + D[2][2]) };
+  InvertCholetsky3(mS);   
+    
+  //* Residual (measured - estimated)
+    
+  float zeta[3] = { m[0]-Vtx.fP[0], m[1]-Vtx.fP[1], m[2]-Vtx.fP[2] };
+        
+  //* mCHt = mCH' - D'
+    
+  float mCHt0[3], mCHt1[3], mCHt2[3];
+    
+  mCHt0[0]=Vtx.fC[ 0] ;      mCHt1[0]=Vtx.fC[ 1] ;      mCHt2[0]=Vtx.fC[ 3] ;
+  mCHt0[1]=Vtx.fC[ 1] ;      mCHt1[1]=Vtx.fC[ 2] ;      mCHt2[1]=Vtx.fC[ 4] ;
+  mCHt0[2]=Vtx.fC[ 3] ;      mCHt1[2]=Vtx.fC[ 4] ;      mCHt2[2]=Vtx.fC[ 5] ;
+  
+  //* Kalman gain K = mCH'*S
+    
+  float k0[3], k1[3], k2[3];
+    
+  for(Int_t i=0;i<3;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+    
+  //* New estimation of the vertex position r += K*zeta
+    
+  float dChi2 = ((mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+              +  (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+              +  (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]);
+
+  for(Int_t i=0;i<3;++i) 
+    Vtx.fP[i] -= k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];       
+    
+  //* New covariance matrix C -= K*(mCH')'
+    
+  for(Int_t i=0, k=0;i<3;++i){
+    for(Int_t j=0;j<=i;++j,++k) 
+      Vtx.fC[k] += k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j];
+  }
+    
+  //* Calculate Chi^2 
+
+  Vtx.fNDF  -= 2;
+  Vtx.fChi2 -= dChi2;
+}
+
+void KFParticleBase::SubtractFromParticle(  KFParticleBase &Vtx ) const
+{
+  /** Subtract the current particle from another particle Vtx using the Kalman filter mathematics. 
+   ** The function is depricated and is kept for compatibility reasons. Should be replaced with SubtractDaughter().
+   ** \param[in] Vtx - particle from which the current particle should be subtracted
+   **/
+
+  float m[8];
+  float mV[36];
+
+  float D[3][3];
+  Vtx.GetMeasurement( *this, m, mV, D );
+
+  float mS[6] = { mV[0] - Vtx.fC[0] + (D[0][0] + D[0][0]), 
+                  mV[1] - Vtx.fC[1] + (D[1][0] + D[0][1]), mV[2] - Vtx.fC[2] + (D[1][1] + D[1][1]), 
+                  mV[3] - Vtx.fC[3] + (D[2][0] + D[0][2]), mV[4] - Vtx.fC[4] + (D[1][2] + D[2][1]), mV[5] - Vtx.fC[5] + (D[2][2] + D[2][2]) };
+  InvertCholetsky3(mS);
+
+  //* Residual (measured - estimated)
+
+  float zeta[3] = { m[0]-Vtx.fP[0], m[1]-Vtx.fP[1], m[2]-Vtx.fP[2] };    
+
+  //* CHt = CH' - D'
+
+  float mCHt0[7], mCHt1[7], mCHt2[7];
+
+  mCHt0[0]=mV[ 0] ;           mCHt1[0]=mV[ 1] ;           mCHt2[0]=mV[ 3] ;
+  mCHt0[1]=mV[ 1] ;           mCHt1[1]=mV[ 2] ;           mCHt2[1]=mV[ 4] ;
+  mCHt0[2]=mV[ 3] ;           mCHt1[2]=mV[ 4] ;           mCHt2[2]=mV[ 5] ;
+  mCHt0[3]=Vtx.fC[ 6]-mV[ 6]; mCHt1[3]=Vtx.fC[ 7]-mV[ 7]; mCHt2[3]=Vtx.fC[ 8]-mV[ 8];
+  mCHt0[4]=Vtx.fC[10]-mV[10]; mCHt1[4]=Vtx.fC[11]-mV[11]; mCHt2[4]=Vtx.fC[12]-mV[12];
+  mCHt0[5]=Vtx.fC[15]-mV[15]; mCHt1[5]=Vtx.fC[16]-mV[16]; mCHt2[5]=Vtx.fC[17]-mV[17];
+  mCHt0[6]=Vtx.fC[21]-mV[21]; mCHt1[6]=Vtx.fC[22]-mV[22]; mCHt2[6]=Vtx.fC[23]-mV[23];
+
+  //* Kalman gain K = mCH'*S
+    
+  float k0[7], k1[7], k2[7];
+    
+  for(Int_t i=0;i<7;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+
+    //* Add the daughter momentum to the particle momentum
+    
+  Vtx.fP[ 3] -= m[ 3];
+  Vtx.fP[ 4] -= m[ 4];
+  Vtx.fP[ 5] -= m[ 5];
+  Vtx.fP[ 6] -= m[ 6];
+  
+  Vtx.fC[ 9] -= mV[ 9];
+  Vtx.fC[13] -= mV[13];
+  Vtx.fC[14] -= mV[14];
+  Vtx.fC[18] -= mV[18];
+  Vtx.fC[19] -= mV[19];
+  Vtx.fC[20] -= mV[20];
+  Vtx.fC[24] -= mV[24];
+  Vtx.fC[25] -= mV[25];
+  Vtx.fC[26] -= mV[26];
+  Vtx.fC[27] -= mV[27];
+
+   //* New estimation of the vertex position r += K*zeta
+    
+  for(Int_t i=0;i<3;++i) 
+    Vtx.fP[i] = m[i] - (k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2]);
+  for(Int_t i=3;i<7;++i) 
+    Vtx.fP[i] = Vtx.fP[i] - (k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2]);
+
+    //* New covariance matrix C -= K*(mCH')'
+
+  float ffC[28] = {-mV[ 0],
+                   -mV[ 1], -mV[ 2],
+                   -mV[ 3], -mV[ 4], -mV[ 5],
+                    mV[ 6],  mV[ 7],  mV[ 8], Vtx.fC[ 9],
+                    mV[10],  mV[11],  mV[12], Vtx.fC[13], Vtx.fC[14],
+                    mV[15],  mV[16],  mV[17], Vtx.fC[18], Vtx.fC[19], Vtx.fC[20],
+                    mV[21],  mV[22],  mV[23], Vtx.fC[24], Vtx.fC[25], Vtx.fC[26], Vtx.fC[27] };
+
+  for(Int_t i=0, k=0;i<7;++i){
+    for(Int_t j=0;j<=i;++j,++k){
+      Vtx.fC[k] = ffC[k] + (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+    }
+  }
+
+    //* Calculate Chi^2 
+  Vtx.fNDF  -= 2;
+  Vtx.fQ    -= GetQ();
+  Vtx.fSFromDecay = 0;    
+  Vtx.fChi2 -= ((mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+             +  (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+             +  (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]);     
+}
+
+void KFParticleBase::TransportLine( float dS, const float* dsdr, float P[], float C[], float* dsdr1, float* F, float* F1 ) const 
+{
+  /** Transports the parameters and their covariance matrix of the current particle assuming the straight line trajectory
+   ** on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/
+  
+  float mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  mJ[0][0]=1; mJ[0][1]=0; mJ[0][2]=0; mJ[0][3]=dS;  mJ[0][4]=0;  mJ[0][5]=0;
+  mJ[1][0]=0; mJ[1][1]=1; mJ[1][2]=0; mJ[1][3]=0;     mJ[1][4]=dS;  mJ[1][5]=0;
+  mJ[2][0]=0; mJ[2][1]=0; mJ[2][2]=1; mJ[2][3]=0; mJ[2][4]=0; mJ[2][5]=dS;
+  
+  mJ[3][0]=0; mJ[3][1]=0; mJ[3][2]=0; mJ[3][3]=1;   mJ[3][4]=0;  mJ[3][5]=0;
+  mJ[4][0]=0; mJ[4][1]=0; mJ[4][2]=0; mJ[4][3]=0;     mJ[4][4]=1;   mJ[4][5]=0;
+  mJ[5][0]=0; mJ[5][1]=0; mJ[5][2]=0; mJ[5][3]=0; mJ[5][4]=0; mJ[5][5]=1;
+  mJ[6][6] = mJ[7][7] = 1;
+  
+  float px = fP[3], py = fP[4], pz = fP[5];
+  
+  P[0] = fP[0] + dS*fP[3];
+  P[1] = fP[1] + dS*fP[4];
+  P[2] = fP[2] + dS*fP[5];
+  P[3] = fP[3];
+  P[4] = fP[4];
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];
+  
+  float mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+  
+  mJds[0][3]= 1; 
+  mJds[1][4]= 1;
+  mJds[2][5]= 1;
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+  MultQSQt( mJ[0], fC, C, 8);
+  
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+void KFParticleBase::GetArmenterosPodolanski(KFParticleBase& positive, KFParticleBase& negative, float QtAlfa[2] )
+{
+  /** Calculates parameters for the Armenteros-Podolanski plot for two particles. 
+   ** Example how to use:\n
+   ** KFParticle PosParticle(...) \n
+   ** KFParticle NegParticle(...) \n
+   ** Gamma.ConstructGamma(PosParticle, NegParticle); \n
+   ** float VertexGamma[3] = {Gamma.GetX(), Gamma.GetY(), Gamma.GetZ()}; \n
+   ** PosParticle.TransportToPoint(VertexGamma); \n
+   ** NegParticle.TransportToPoint(VertexGamma); \n
+   ** float armenterosQtAlfa[2] = {0.}; \n
+   ** KFParticle::GetArmenterosPodolanski(PosParticle, NegParticle, armenterosQtAlfa ); \n
+   ** \param[in] positive - first particle, positive or neutral
+   ** \param[in] negative - second particle, negative or neutral
+   ** \param[out] QtAlfa[2] - parameters for the Armenteros-Podolanski plot: QtAlfa[0] = qt - projection of the 
+   ** momenta of the particles on the transverse direction with respect to the total momentum, same for both particles;
+   ** QtAlfa[1] = (Pl+ - Pl-)/(Pl+ + Pl-) - combination of the longitudinal components.
+   **/
+
+  float alpha = 0., qt = 0.;
+  float spx = positive.GetPx() + negative.GetPx();
+  float spy = positive.GetPy() + negative.GetPy();
+  float spz = positive.GetPz() + negative.GetPz();
+  float sp  = sqrt(spx*spx + spy*spy + spz*spz);
+  if( sp == 0.0) return;
+  float pn, pln, plp;
+
+  pn = sqrt(negative.GetPx()*negative.GetPx() + negative.GetPy()*negative.GetPy() + negative.GetPz()*negative.GetPz());
+//   pp = sqrt(positive.GetPx()*positive.GetPx() + positive.GetPy()*positive.GetPy() + positive.GetPz()*positive.GetPz());
+  pln  = (negative.GetPx()*spx+negative.GetPy()*spy+negative.GetPz()*spz)/sp;
+  plp  = (positive.GetPx()*spx+positive.GetPy()*spy+positive.GetPz()*spz)/sp;
+
+  if( pn == 0.0) return;
+  float ptm  = (1.-((pln/pn)*(pln/pn)));
+  qt= (ptm>=0.)?  pn*sqrt(ptm) :0;
+  alpha = (plp-pln)/(plp+pln);
+
+  QtAlfa[0] = qt;
+  QtAlfa[1] = alpha;
+}
+
+void KFParticleBase::RotateXY(float angle, float Vtx[3])
+{
+  /** Rotates the KFParticle object around OZ axis, OZ axis is set by the vertex position.
+   ** \param[in] angle - angle of rotation in XY plane in [rad]
+   ** \param[in] Vtx[3] - position of the vertex in [cm]
+   **/
+
+  // Before rotation the center of the coordinat system should be moved to the vertex position; move back after rotation
+  X() = X() - Vtx[0];
+  Y() = Y() - Vtx[1];
+  Z() = Z() - Vtx[2];
+
+  // Rotate the kf particle
+  float c = cos(angle);
+  float s = sin(angle);
+
+  float mA[8][ 8];
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<8; j++){
+      mA[i][j] = 0;
+    }
+  }
+  for( int i=0; i<8; i++ ){
+    mA[i][i] = 1;
+  }
+  mA[0][0] =  c;  mA[0][1] = s;
+  mA[1][0] = -s;  mA[1][1] = c;
+  mA[3][3] =  c;  mA[3][4] = s;
+  mA[4][3] = -s;  mA[4][4] = c;
+
+  float mAC[8][8];
+  float mAp[8];
+
+  for( Int_t i=0; i<8; i++ ){
+    mAp[i] = 0;
+    for( Int_t k=0; k<8; k++){
+      mAp[i]+=mA[i][k] * fP[k];
+    }
+  }
+
+  for( Int_t i=0; i<8; i++){
+    fP[i] = mAp[i];
+  }
+
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<8; j++ ){
+      mAC[i][j] = 0;
+      for( Int_t k=0; k<8; k++ ){
+        mAC[i][j]+= mA[i][k] * GetCovariance(k,j);
+      }
+    }
+  }
+
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<=i; j++ ){
+      float xx = 0;
+      for( Int_t k=0; k<8; k++){
+        xx+= mAC[i][k]*mA[j][k];
+      }
+      Covariance(i,j) = xx;
+    }
+  }
+
+  X() = GetX() + Vtx[0];
+  Y() = GetY() + Vtx[1];
+  Z() = GetZ() + Vtx[2];
+}
+
+void KFParticleBase::InvertCholetsky3(float a[6])
+{
+  /** Inverts symmetric 3x3 matrix a using modified Choletsky decomposition. The result is stored to the same matrix a.
+   ** \param[in,out] a - 3x3 symmetric matrix
+   **/
+  
+  float d[3], uud, u[3][3];
+  for(int i=0; i<3; i++) 
+  {
+    d[i]=0;
+    for(int j=0; j<3; j++) 
+      u[i][j]=0;
+  }
+
+  for(int i=0; i<3 ; i++)
+  {
+    uud=0;
+    for(int j=0; j<i; j++) 
+      uud += u[j][i]*u[j][i]*d[j];
+    uud = a[i*(i+3)/2] - uud;
+
+    if(fabs(uud)<1.e-12f) uud = 1.e-12f;
+
+    d[i] = uud/fabs(uud);
+    u[i][i] = sqrt(fabs(uud));
+
+    for(int j=i+1; j<3; j++) 
+    {
+      uud = 0;
+      for(int k=0; k<i; k++)
+        uud += u[k][i]*u[k][j]*d[k];
+      uud = a[j*(j+1)/2+i] - uud;
+      u[i][j] = d[i]/u[i][i]*uud;
+    }
+  }
+
+  float u1[3];
+
+  for(int i=0; i<3; i++)
+  {
+    u1[i] = u[i][i];
+    u[i][i] = 1/u[i][i];
+  }
+  for(int i=0; i<2; i++)
+  {
+    u[i][i+1] = - u[i][i+1]*u[i][i]*u[i+1][i+1];
+  }
+  for(int i=0; i<1; i++)
+  {
+    u[i][i+2] = u[i][i+1]*u1[i+1]*u[i+1][i+2]-u[i][i+2]*u[i][i]*u[i+2][i+2];
+  }
+
+  for(int i=0; i<3; i++)
+    a[i+3] = u[i][2]*u[2][2]*d[2];
+  for(int i=0; i<2; i++)
+    a[i+1] = u[i][1]*u[1][1]*d[1] + u[i][2]*u[1][2]*d[2];
+  a[0] = u[0][0]*u[0][0]*d[0] + u[0][1]*u[0][1]*d[1] + u[0][2]*u[0][2]*d[2];
+}
+
+void KFParticleBase::MultQSQt( const float Q[], const float S[], float SOut[], const int kN )
+{
+  /** Matrix multiplication SOut = Q*S*Q^T, where Q - square matrix, S - symmetric matrix.
+   ** \param[in] Q - square matrix
+   ** \param[in] S - input symmetric matrix
+   ** \param[out] SOut - output symmetric matrix
+   ** \param[in] kN - dimensionality of the matrices
+   **/
+
+  float* mA = new float[kN*kN];
+  
+  for( Int_t i=0, ij=0; i<kN; i++ ){
+    for( Int_t j=0; j<kN; j++, ++ij ){
+      mA[ij] = 0 ;
+      for( Int_t k=0; k<kN; ++k ) mA[ij]+= S[( k<=i ) ? i*(i+1)/2+k :k*(k+1)/2+i] * Q[ j*kN+k];
+    }
+  }
+    
+  for( Int_t i=0; i<kN; i++ ){
+    for( Int_t j=0; j<=i; j++ ){
+      Int_t ij = ( j<=i ) ? i*(i+1)/2+j :j*(j+1)/2+i;
+      SOut[ij] = 0 ;
+      for( Int_t k=0; k<kN; k++ )  SOut[ij] += Q[ i*kN+k ] * mA[ k*kN+j ];
+    }
+  }
+  
+  if(mA) delete [] mA;
+}
+
+// 72-charachters line to define the printer border
+//3456789012345678901234567890123456789012345678901234567890123456789012
+
diff --git a/external/KFParticle/KFParticle/KFParticleBase.h b/external/KFParticle/KFParticle/KFParticleBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..c233cee36b157d45e54090a724a2aaa81143d5b8
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleBase.h
@@ -0,0 +1,297 @@
+//---------------------------------------------------------------------------------
+// The KFParticleBase class
+// .
+// @author  S.Gorbunov, I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class describes general mathematics which is used by KFParticle class
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+
+#ifndef KFPARTICLEBASE_H
+#define KFPARTICLEBASE_H
+
+#ifdef __ROOT__ //for the STAR experiment
+#define HomogeneousField
+#endif
+
+#ifdef HLTCA_STANDALONE
+#include "RootTypesDef.h"
+#else
+#include "TObject.h"
+#endif
+
+#include <vector>
+
+/** @class KFParticleBase
+ ** @brief The base of KFParticle class, describes particle objects.
+ ** @author  S.Gorbunov, I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** Contains the main mathematics of the KF Particle . Will be merged with the KFParticle class.
+ **/
+
+class KFParticleBase :public TObject {
+  
+ public:
+
+  /**
+   ** Abstract methods are defined in the KFParticle class
+   **/ 
+
+  /** Virtual method to access the magnetic field**/
+  virtual void GetFieldValue(const float xyz[], float B[]) const = 0;
+  
+  /** Virtual method to get extrapolation parameter dS=l/p to . Is defined in KFParticle.**/
+  virtual float GetDStoPoint( const float xyz[3], float dsdr[6] ) const = 0;
+  
+  float GetDStoPointLine( const float xyz[3], float dsdr[6] ) const;
+  float GetDStoPointBz( float B, const float xyz[3], float dsdr[6], const float* param=0) const;
+  float GetDStoPointBy( float By, const float xyz[3], float dsdr[6] ) const;
+  float GetDStoPointB( const float* B, const float xyz[3], float dsdr[6] ) const;
+  float GetDStoPointCBM( const float xyz[3], float dsdr[6] ) const;
+
+  /** Virtual method to get extrapolation parameter dS=l/p to another particle. Is defined in KFParticle.**/
+  virtual void GetDStoParticle( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const = 0;
+  
+  void GetDStoParticleLine( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const ;
+  void GetDStoParticleBz( float Bz, const KFParticleBase &p, float dS[2], float dsdr[4][6], const float* param1=0, const float* param2=0 ) const ;
+  void GetDStoParticleBy( float B,  const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const ;
+  void GetDStoParticleCBM( const KFParticleBase &p, float dS[2], float dsdr[4][6] ) const ;
+  
+  /** Virtual method to transport a particle on a certain distance along the trajectory. Is defined in KFParticle.**/
+  virtual void Transport( float dS, const float dsdr[6], float P[], float C[], float* dsdr1=0, float* F=0, float* F1=0 ) const = 0;
+
+
+  KFParticleBase();
+  virtual ~KFParticleBase() { ; } ///< The default destructor.
+
+  void Initialize( const float Param[], const float Cov[], Int_t Charge, float Mass );
+  void Initialize();
+
+  void SetConstructMethod(Int_t m) {fConstructMethod = m;} ///< Defines the construction method for the current particle (see description of fConstructMethod).
+  void SetMassHypo(float m) { fMassHypo = m;} ///< Sets the mass hypothesis to the particle, is used when fConstructMethod = 2.
+  const float& GetMassHypo() const { return fMassHypo; } ///< Returns the mass hypothesis.
+  const float& GetSumDaughterMass() const {return SumDaughterMass;} ///< Returns the sum of masses of the daughters.
+
+  //*
+  //*  ACCESSORS
+  //*
+
+  //* Simple accessors 
+
+  float GetX    () const { return fP[0]; } ///< Retruns X coordinate of the particle, fP[0].
+  float GetY    () const { return fP[1]; } ///< Retruns Y coordinate of the particle, fP[1].
+  float GetZ    () const { return fP[2]; } ///< Retruns Z coordinate of the particle, fP[2].
+  float GetPx   () const { return fP[3]; } ///< Retruns X component of the momentum, fP[3].
+  float GetPy   () const { return fP[4]; } ///< Retruns Y component of the momentum, fP[4].
+  float GetPz   () const { return fP[5]; } ///< Retruns Z component of the momentum, fP[5].
+  float GetE    () const { return fP[6]; } ///< Returns energy of the particle, fP[6].
+  float GetS    () const { return fP[7]; } ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  char  GetQ    () const { return fQ;    } ///< Returns charge of the particle.
+  float GetChi2 () const { return fChi2; } ///< Returns Chi2 of the fit.
+  Int_t GetNDF  () const { return fNDF;  } ///< Returns number of decrease of freedom.
+
+  const float& X    () const { return fP[0]; } ///< Retruns X coordinate of the particle, fP[0].
+  const float& Y    () const { return fP[1]; } ///< Retruns Y coordinate of the particle, fP[1].
+  const float& Z    () const { return fP[2]; } ///< Retruns Z coordinate of the particle, fP[2].
+  const float& Px   () const { return fP[3]; } ///< Retruns X component of the momentum, fP[3].
+  const float& Py   () const { return fP[4]; } ///< Retruns Y component of the momentum, fP[4].
+  const float& Pz   () const { return fP[5]; } ///< Retruns Z component of the momentum, fP[5].
+  const float& E    () const { return fP[6]; } ///< Returns energy of the particle, fP[6].
+  const float& S    () const { return fP[7]; } ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  const char& Q     () const { return fQ;    } ///< Returns charge of the particle.
+  const float& Chi2 () const { return fChi2; } ///< Returns Chi2 of the fit.
+  const Int_t& NDF  () const { return fNDF;  } ///< Returns number of decrease of freedom.
+  
+  float GetParameter ( Int_t i )          const { return fP[i];       } ///< Returns P[i] parameter.
+  float GetCovariance( Int_t i )          const { return fC[i];       } ///< Returns C[i] element of the covariance matrix in the lower triangular form.
+  float GetCovariance( Int_t i, Int_t j ) const { return fC[IJ(i,j)]; } ///< Returns C[i,j] element of the covariance matrix.
+
+  //* Accessors with calculations( &value, &estimated sigma )
+  //* error flag returned (0 means no error during calculations) 
+
+  Int_t GetMomentum      ( float &p,   float &error ) const ;
+  Int_t GetPt            ( float &pt,  float &error ) const ;
+  Int_t GetEta           ( float &eta, float &error ) const ;
+  Int_t GetPhi           ( float &phi, float &error ) const ;
+  Int_t GetMass          ( float &m,   float &error ) const ;
+  Int_t GetDecayLength   ( float &l,   float &error ) const ;
+  Int_t GetDecayLengthXY ( float &l,   float &error ) const ;
+  Int_t GetLifeTime      ( float &ctau,float &error ) const ;
+  Int_t GetR             ( float &r,   float &error ) const ;
+
+  //*
+  //*  MODIFIERS
+  //*
+  
+  float & X    () { return fP[0]; } ///< Modifier of X coordinate of the particle, fP[0].
+  float & Y    () { return fP[1]; } ///< Modifier of Y coordinate of the particle, fP[1].
+  float & Z    () { return fP[2]; } ///< Modifier of Z coordinate of the particle, fP[2].
+  float & Px   () { return fP[3]; } ///< Modifier of X component of the momentum, fP[3].
+  float & Py   () { return fP[4]; } ///< Modifier of Y component of the momentum, fP[4].
+  float & Pz   () { return fP[5]; } ///< Modifier of Z component of the momentum, fP[5].
+  float & E    () { return fP[6]; } ///< Modifier of energy of the particle, fP[6].
+  float & S    () { return fP[7]; } ///< Modifier of dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  char  & Q    () { return fQ;    } ///< Modifier of charge of the particle.
+  float & Chi2 () { return fChi2; } ///< Modifier of Chi2 of the fit.
+  Int_t & NDF  () { return fNDF;  } ///< Modifier of number of decrease of freedom.
+
+  float & Parameter ( Int_t i )          { return fP[i];       } ///< Modifier of P[i] parameter.
+  float & Covariance( Int_t i )          { return fC[i];       } ///< Modifier of C[i] element of the covariance matrix in the lower triangular form.
+  float & Covariance( Int_t i, Int_t j ) { return fC[IJ(i,j)]; } ///< Modifier of C[i,j] element of the covariance matrix.
+
+
+  //* 
+  //* CONSTRUCTION OF THE PARTICLE BY ITS DAUGHTERS AND MOTHER
+  //* USING THE KALMAN FILTER METHOD
+  //*
+
+
+  //* Simple way to add daughter ex. D0+= Pion; 
+
+  void operator +=( const KFParticleBase &Daughter );  
+
+  //* Add daughter track to the particle 
+
+  void AddDaughter( const KFParticleBase &Daughter );
+  void SubtractDaughter( const KFParticleBase &Daughter );
+
+  void AddDaughterWithEnergyFit( const KFParticleBase &Daughter );
+  void AddDaughterWithEnergyFitMC( const KFParticleBase &Daughter );
+
+  //* Set production vertex 
+
+  void SetProductionVertex( const KFParticleBase &Vtx );
+
+  //* Set mass constraint 
+
+  void SetNonlinearMassConstraint( float Mass );
+  void SetMassConstraint( float Mass, float SigmaMass = 0 );
+
+  //* Set no decay length for resonances
+
+  void SetNoDecayLength();
+
+
+  //* Everything in one go  
+
+  void Construct( const KFParticleBase *vDaughters[], Int_t nDaughters, const KFParticleBase *ProdVtx=0,   float Mass=-1 );
+
+  //Transport functions
+  void TransportToDecayVertex();
+  void TransportToProductionVertex();
+  void TransportToDS( float dS, const float* dsdr );
+  void TransportBz( float Bz, float dS, const float* dsdr, float P[], float C[], float* dsdr1=0, float* F=0, float* F1=0 ) const;
+  void TransportCBM( float dS, const float* dsdr, float P[], float C[], float* dsdr1=0, float* F=0, float* F1=0 ) const;  
+
+  //* 
+  //* OTHER UTILITIES
+  //*
+
+  //* Calculate distance from another object [cm]
+
+  float GetDistanceFromVertex( const float vtx[] ) const;
+  float GetDistanceFromVertex( const KFParticleBase &Vtx ) const;
+  float GetDistanceFromParticle( const KFParticleBase &p ) const;
+
+  //* Calculate sqrt(Chi2/ndf) deviation from vertex
+  //* v = [xyz], Cv=[Cxx,Cxy,Cyy,Cxz,Cyz,Czz]-covariance matrix
+
+  float GetDeviationFromVertex( const float v[], const float Cv[]=0 ) const;
+  float GetDeviationFromVertex( const KFParticleBase &Vtx ) const;
+  float GetDeviationFromParticle( const KFParticleBase &p ) const;  
+
+  void SubtractFromVertex( KFParticleBase &Vtx ) const;
+  void SubtractFromParticle( KFParticleBase &Vtx ) const;
+
+  static void GetArmenterosPodolanski(KFParticleBase& positive, KFParticleBase& negative, float QtAlfa[2] );
+  void RotateXY(float angle, float Vtx[3]);
+
+  int Id() const { return fId; } ///< Returns Id of the particle.
+  int NDaughters() const { return fDaughtersIds.size(); } ///< Returns number of daughter particles.
+  const std::vector<int>& DaughterIds() const { return fDaughtersIds; } ///< Returns the vector with the indices of daughter particles.
+  void CleanDaughtersId() { fDaughtersIds.clear(); } ///< Cleans the vector with the indices of daughter particles.
+  
+  void SetId( int id ) { fId = id; } ///< Sets the Id of the particle. After the construction of a particle should be set by user.
+  void AddDaughterId( int id ) { fDaughtersIds.push_back(id); } ///< Adds index of the daughter particle. 
+
+  void SetPDG ( int pdg ) { fPDG = pdg; } ///< Sets the PDG hypothesis.
+  int GetPDG () const { return fPDG; } ///< Returns the PDG hypothesis.
+
+#ifdef __ROOT__ //for the STAR experiment
+  virtual void Print(Option_t *opt="") const;
+  Int_t        IdTruth() const { return fIdTruth;}
+  Int_t        QaTruth() const { return fQuality; }
+  Int_t        IdParentMcVx() const {return fIdParentMcVx;}
+  Int_t        IdParentVx()   const {return IdParentMcVx();}
+  void         SetParentID(Int_t id=0) {fParentID = id;}
+  Int_t        GetParentID() const {return fParentID;}
+  void         SetIdParentMcVx(Int_t id) {fIdParentMcVx = id;}
+  void         SetIdTruth(Int_t idtru,Int_t qatru=0) {fIdTruth = (UShort_t) idtru; fQuality = (UShort_t) qatru;}
+  virtual void Clear(Option_t * /*option*/ ="");
+#endif
+
+  static void InvertCholetsky3(float a[6]);
+  static void MultQSQt( const float Q[], const float S[], float SOut[], const int kN );
+
+ protected:
+  /** Converts a pair of indices {i,j} of the covariance matrix to one index corresponding to the triangular form. */
+  static Int_t IJ( Int_t i, Int_t j ){ 
+    return ( j<=i ) ? i*(i+1)/2+j :j*(j+1)/2+i;
+  }
+  /** Return an element of the covariance matrix with {i,j} indices. */
+  float & Cij( Int_t i, Int_t j ){ return fC[IJ(i,j)]; }
+  void TransportLine( float S, const float* dsdr, float P[], float C[], float* dsdr1, float* F, float* F1 ) const ;
+  bool GetMeasurement( const KFParticleBase& daughter, float m[], float V[], float D[3][3] ) ;
+  void SetMassConstraint( float *mP, float *mC, float mJ[7][7], float mass );
+
+  float fP[8];           ///< Particle parameters { X, Y, Z, Px, Py, Pz, E, S[=DecayLength/P]}.
+  float fC[36];          ///< Low-triangle covariance matrix of fP.
+  float fChi2;           ///< Chi^2.
+  float fSFromDecay;     ///< Distance from the decay vertex to the current position.
+  float SumDaughterMass; ///< Sum of the daughter particles masses. Needed to set the constraint on the minimum mass during particle construction.
+  float fMassHypo;       ///< The mass hypothesis, used for the constraints during particle construction.
+  Int_t fNDF;            ///< Number of degrees of freedom.
+  int   fId;             ///< Id of the particle.
+#ifdef __ROOT__ //for the STAR experiment
+  Short_t    fParentID;     ///< Id of the parent particle.
+  Short_t    fIdTruth;      ///< MC track id.
+  Short_t    fQuality;      ///< quality of this information (percentage of hits coming from the above MC track).
+  Short_t    fIdParentMcVx; ///< for track and McTrack for vertex.
+#endif
+  Bool_t fAtProductionVertex; ///< Flag shows if particle is at the production point.
+  char fQ; ///< The charge of the particle in the units of the elementary charge.
+  
+  /** \brief Determines the method for the particle construction. \n
+   ** 0 - Energy considered as an independent veriable, fitted independently from momentum, without any constraints on mass \n
+   ** 2 - Energy considered as an independent variable, fitted independently from momentum, with constraints on mass of daughter particle
+   **/
+  char fConstructMethod; 
+  int fPDG; ///< The PDG hypothesis assigned to the particle.
+  
+  /** \brief A vector with ids of the daughter particles: \n
+   ** 1) if particle is created from a track - the index of the track, in this case the size of the vector is always equal to one; \n
+   ** 2) if particle is constructed from other particles - indices of these particles in the same array.
+   **/
+  std::vector<int> fDaughtersIds;
+ 
+#ifndef KFParticleStandalone
+  ClassDef( KFParticleBase, 2 )
+#endif
+};
+
+#ifdef __ROOT__ //for the STAR experiment
+std::ostream&  operator<<(std::ostream& os, KFParticleBase const & particle);
+#endif
+
+#endif 
diff --git a/external/KFParticle/KFParticle/KFParticleBaseSIMD.cxx b/external/KFParticle/KFParticle/KFParticleBaseSIMD.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..87ee17e019283570e311bc59bf399c02b8af0101
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleBaseSIMD.cxx
@@ -0,0 +1,4121 @@
+//---------------------------------------------------------------------------------
+// Implementation of the KFParticleBaseSIMD class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class describes general mathematics which is used by KFParticle class
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+
+#include "KFParticleBaseSIMD.h"
+#include <iostream>
+
+static const float_v small = 1.e-20f;
+
+KFParticleBaseSIMD::KFParticleBaseSIMD() :fQ(0), fNDF(-3), fChi2(0.f), fSFromDecay(0.f),
+  SumDaughterMass(0.f), fMassHypo(-1.f), fId(-1), fAtProductionVertex(0), fPDG(0), fConstructMethod(0), fDaughterIds()
+{ 
+  /** The default constructor, initialises the parameters by: \n
+   ** 1) all parameters are set to 0; \n
+   ** 2) all elements of the covariance matrix are set to 0 except Cxx=Cyy=Czz=100; \n
+   ** 3) Q = 0; \n
+   ** 4) chi2 is set to 0; \n
+   ** 5) NDF = -3, since 3 parameters should be fitted: X, Y, Z. 
+   **/
+  Initialize();
+}
+
+void KFParticleBaseSIMD::Initialize( const float_v Param[], const float_v Cov[], int_v Charge, float_v Mass )
+{
+  /** Sets the parameters of the particle:
+   ** \param[in] Param[6] = { X, Y, Z, Px, Py, Pz } - position and momentum
+   ** \param[in] Cov[21]  - lower-triangular part of the covariance matrix:@n
+   ** \verbatim
+             (  0  .  .  .  .  . )
+             (  1  2  .  .  .  . )
+   Cov[21] = (  3  4  5  .  .  . )
+             (  6  7  8  9  .  . )
+             ( 10 11 12 13 14  . )
+             ( 15 16 17 18 19 20 )
+   \endverbatim
+   ** \param[in] Charge - charge of the particle in elementary charge units
+   ** \param[in] mass - the mass hypothesis
+   **/
+
+  for( Int_t i=0; i<6 ; i++ ) fP[i] = Param[i];
+  for( Int_t i=0; i<21; i++ ) fC[i] = Cov[i];
+
+  float_v energy = sqrt( Mass*Mass + fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]);
+  fP[6] = energy;
+  fP[7] = 0;
+  fQ = Charge;
+  fNDF = 0;
+  fChi2 = 0;
+  fAtProductionVertex = 0;
+  fSFromDecay = 0;
+
+  float_v energyInv = 1.f/energy;
+  float_v 
+    h0 = fP[3]*energyInv,
+    h1 = fP[4]*energyInv,
+    h2 = fP[5]*energyInv;
+
+  fC[21] = h0*fC[ 6] + h1*fC[10] + h2*fC[15];
+  fC[22] = h0*fC[ 7] + h1*fC[11] + h2*fC[16];
+  fC[23] = h0*fC[ 8] + h1*fC[12] + h2*fC[17];
+  fC[24] = h0*fC[ 9] + h1*fC[13] + h2*fC[18];
+  fC[25] = h0*fC[13] + h1*fC[14] + h2*fC[19];
+  fC[26] = h0*fC[18] + h1*fC[19] + h2*fC[20];
+  fC[27] = ( h0*h0*fC[ 9] + h1*h1*fC[14] + h2*h2*fC[20] 
+	     + 2*(h0*h1*fC[13] + h0*h2*fC[18] + h1*h2*fC[19] ) );
+  for( Int_t i=28; i<36; i++ ) fC[i] = 0.f;
+  fC[35] = 1.f;
+
+  SumDaughterMass = Mass;
+  fMassHypo = Mass;
+}
+
+void KFParticleBaseSIMD::Initialize()
+{
+  /** Initialises the parameters by default: \n
+   ** 1) all parameters are set to 0; \n
+   ** 2) all elements of the covariance matrix are set to 0 except Cxx=Cyy=Czz=100; \n
+   ** 3) Q = 0; \n
+   ** 4) chi2 is set to 0; \n
+   ** 5) NDF = -3, since 3 parameters should be fitted: X, Y, Z. 
+   **/
+  
+  for( Int_t i=0; i<8; i++) fP[i] = 0.f;
+  for(Int_t i=0;i<36;++i) fC[i]=0.f;
+  fC[0] = fC[2] = fC[5] = 100.f;
+  fC[35] = 1.f;
+  fNDF  = -3;
+  fChi2 =  0.f;
+  fQ = 0;
+  fSFromDecay = 0.f;
+  fAtProductionVertex = 0;
+  SumDaughterMass = 0.f;
+  fMassHypo = -1;
+}
+
+float_m KFParticleBaseSIMD::GetMomentum( float_v &p, float_v &error )  const 
+{
+  /** Calculates particle momentum and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] p - momentum of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float_v x = fP[3];
+  float_v y = fP[4];
+  float_v z = fP[5];
+  float_v x2 = x*x;
+  float_v y2 = y*y;
+  float_v z2 = z*z;
+  float_v p2 = x2+y2+z2;
+  p = sqrt(p2);
+  error = (x2*fC[9]+y2*fC[14]+z2*fC[20] + 2*(x*y*fC[13]+x*z*fC[18]+y*z*fC[19]) );
+  const float_v LocalSmall = 1.e-4f;
+  float_m mask = (0.f < error) && (LocalSmall < abs(p));
+  error(!mask) = 1.e20f;
+  error = sqrt(error);
+  return (!mask);
+}
+
+float_m KFParticleBaseSIMD::GetPt( float_v &pt, float_v &error )  const 
+{
+  /** Calculates particle transverse  momentum and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] pt - transverse momentum of the particle
+   ** \param[out] error - its error
+   **/
+
+  float_v px = fP[3];
+  float_v py = fP[4];
+  float_v px2 = px*px;
+  float_v py2 = py*py;
+  float_v pt2 = px2+py2;
+  pt = sqrt(pt2);
+  error = (px2*fC[9] + py2*fC[14] + 2*px*py*fC[13] );
+  const float_v LocalSmall = 1.e-4f;
+  float_m mask = ( (0.f < error) && (LocalSmall < abs(pt)));
+  error(!mask) = 1.e20f;
+  error = sqrt(error);
+  return (!mask);
+}
+
+float_m KFParticleBaseSIMD::GetEta( float_v &eta, float_v &error )  const 
+{
+  /** Calculates particle pseudorapidity and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] eta - pseudorapidity of the particle
+   ** \param[out] error - its error
+   **/
+  
+  const float_v BIG = 1.e8f;
+  const float_v LocalSmall = 1.e-8f;
+
+  float_v px = fP[3];
+  float_v py = fP[4];
+  float_v pz = fP[5];
+  float_v pt2 = px*px + py*py;
+  float_v p2 = pt2 + pz*pz;
+  float_v p = sqrt(p2);
+  float_v a = p + pz;
+  float_v b = p - pz;
+  eta = BIG;
+  float_v c = 0.f;
+  c(b > LocalSmall) = (a/b);
+  float_v logc = 0.5f*KFPMath::Log(c);
+  eta(LocalSmall<abs(c)) = logc;
+
+  float_v h3 = -px*pz;
+  float_v h4 = -py*pz;  
+  float_v pt4 = pt2*pt2;
+  float_v p2pt4 = p2*pt4;
+  error = (h3*h3*fC[9] + h4*h4*fC[14] + pt4*fC[20] + 2*( h3*(h4*fC[13] + fC[18]*pt2) + pt2*h4*fC[19] ) );
+
+  float_m mask = ((LocalSmall < abs(p2pt4)) && (0.f < error));
+  error(mask) = sqrt(error/p2pt4);
+  error(!mask) = BIG;
+
+  return (!mask);
+}
+
+float_m KFParticleBaseSIMD::GetPhi( float_v &phi, float_v &error )  const 
+{
+  /** Calculates particle polar angle at the current point and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] phi - polar angle of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float_v px = fP[3];
+  float_v py = fP[4];
+  float_v px2 = px*px;
+  float_v py2 = py*py;
+  float_v pt2 = px2 + py2;
+  phi = KFPMath::ATan2(py,px);
+  error = (py2*fC[9] + px2*fC[14] - float_v(2.f)*px*py*fC[13] );
+
+  float_m mask = (0.f < error) && (1.e-4f < pt2);
+  error(mask) = sqrt(error)/pt2;
+  error(!mask) = 1.e10f;
+  return !mask;
+}
+
+float_m KFParticleBaseSIMD::GetR( float_v &r, float_v &error )  const 
+{
+  /** Calculates the distance to the point {0,0,0} and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] r - polar angle of the particle
+   ** \param[out] error - its error
+   **/
+  
+  float_v x = fP[0];
+  float_v y = fP[1];
+  float_v x2 = x*x;
+  float_v y2 = y*y;
+  r = sqrt(x2 + y2);
+  error = (x2*fC[0] + y2*fC[2] - float_v(2.f)*x*y*fC[1] );
+
+  float_m mask = (0.f < error) && (1.e-4f < r);
+  error(mask) = sqrt(error)/r;
+  error(!mask ) = 1.e10f;
+  return !mask;
+}
+
+float_m KFParticleBaseSIMD::GetMass( float_v &m, float_v &error ) const 
+{
+  /** Calculates the mass of the particle and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** \param[out] m - mass of the particle
+   ** \param[out] error - its error
+   **/  
+
+  const float_v BIG = 1.e8f;
+  const float_v LocalSmall = 1.e-8f;
+
+  float_v s = (  fP[3]*fP[3]*fC[9] + fP[4]*fP[4]*fC[14] + fP[5]*fP[5]*fC[20] 
+               + fP[6]*fP[6]*fC[27] 
+               + float_v(2.f)*( + fP[3]*fP[4]*fC[13] + fP[5]*(fP[3]*fC[18] + fP[4]*fC[19]) 
+               - fP[6]*( fP[3]*fC[24] + fP[4]*fC[25] + fP[5]*fC[26] )   )
+              ); 
+
+  float_v m2 = (fP[6]*fP[6] - fP[3]*fP[3] - fP[4]*fP[4] - fP[5]*fP[5]);
+
+  float_m mask = 0.f <= m2;
+  m(mask) = sqrt(m2);
+  m(!mask) = -sqrt(-m2);
+
+  mask = (mask && (0.f <= s) && (LocalSmall < m));
+  error(mask) = sqrt(s)/m;
+  error(!mask) = BIG;
+
+  return !mask;
+}
+
+
+float_m KFParticleBaseSIMD::GetDecayLength( float_v &l, float_v &error ) const 
+{
+  /** Calculates the decay length of the particle in the laboratory system and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] l - the decay length
+   ** \param[out] error - its error
+   **/
+  
+  const float_v BIG = 1.e20f;
+
+  float_v x = fP[3];
+  float_v y = fP[4];
+  float_v z = fP[5];
+  float_v t = fP[7];
+  float_v x2 = x*x;
+  float_v y2 = y*y;
+  float_v z2 = z*z;
+  float_v p2 = x2+y2+z2;
+  l = t*sqrt(p2);
+
+  error = p2*fC[35] + t*t/p2*(x2*fC[9]+y2*fC[14]+z2*fC[20]
+        + float_v(2.f)*(x*y*fC[13]+x*z*fC[18]+y*z*fC[19]) )
+        + float_v(2.f)*t*(x*fC[31]+y*fC[32]+z*fC[33]);
+
+  float_m mask = ((1.e-4f) < p2);
+  error(mask) = sqrt(abs(error));
+  error(!mask) = BIG;
+  return !mask;
+}
+
+float_m KFParticleBaseSIMD::GetDecayLengthXY( float_v &l, float_v &error ) const 
+{
+  /** Calculates the projection in the XY plane of the decay length of the particle in the laboratory 
+   ** system and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] l - the decay length
+   ** \param[out] error - its error
+   **/
+  
+  const float_v BIG = 1.e8f;
+  float_v x = fP[3];
+  float_v y = fP[4];
+  float_v t = fP[7];
+  float_v x2 = x*x;
+  float_v y2 = y*y;
+  float_v pt2 = x2+y2;
+  l = t*sqrt(pt2);
+
+  error = pt2*fC[35] + t*t/pt2*(x2*fC[9]+y2*fC[14] + 2*x*y*fC[13] )
+        + float_v(2.f)*t*(x*fC[31]+y*fC[32]);
+  float_m mask = ((1.e-4f) < pt2);
+  error(mask) = sqrt(abs(error));
+  error(!mask) = BIG;
+  return !mask;
+}
+
+
+float_m KFParticleBaseSIMD::GetLifeTime( float_v &tauC, float_v &error ) const 
+{
+  /** Calculates the lifetime times speed of life (ctau) [cm] of the particle in the  
+   ** center of mass frame and its error. If they are well defined the corresponding element of the 
+   ** return mask is set to 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] ctau - lifetime of the particle [cm]
+   ** \param[out] error - its error
+   **/
+  
+  const float_v BIG = 1.e20f;
+
+  float_v m, dm;
+  GetMass( m, dm );
+  float_v cTM = (-fP[3]*fC[31] - fP[4]*fC[32] - fP[5]*fC[33] + fP[6]*fC[34]);
+  tauC = fP[7]*m;
+  error = m*m*fC[35] + 2*fP[7]*cTM + fP[7]*fP[7]*dm*dm;
+  float_m mask = (0.f < error);
+  error(mask) = sqrt(error);
+  error(!mask) = BIG;
+  return !mask;
+}
+
+
+void KFParticleBaseSIMD::operator +=( const KFParticleBaseSIMD &Daughter )
+{
+  /** Operator to add daughter to the current particle. Calls AddDaughter() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+  
+  AddDaughter( Daughter );
+}
+
+void KFParticleBaseSIMD::GetMeasurement( const KFParticleBaseSIMD& daughter, float_v m[], float_v V[], float_v D[3][3] )
+{
+  /** Obtains the measurements from the current particle and the daughter to be added for the Kalman filter
+   ** mathematics. If these are two first daughters they are transported to the point of the closest approach,
+   ** if the third or higher daughter is added it is transported to the DCA point of the already constructed
+   ** vertex. The correlations are taken into account in the covariance matrices of both measurements,
+   ** the correlation matrix of two measurements is also calculated. Parameters of the current particle are
+   ** modified by this function, the daughter is not changed, its parameters are stored to the output arrays
+   ** after modifications.
+   ** \param[in] daughter - the daughter particle to be added, stays unchanged
+   ** \param[out] m[8] - the output parameters of the daughter particle at the DCA point
+   ** \param[out] V[36] - the output covariance matrix of the daughter parameters, takes into account the correlation
+   ** \param[out] D[3][3] - the correlation matrix between the current and daughter particles
+   **/
+  
+  if(fNDF[0] == -1)
+  {
+    float_v ds[2] = {0.f,0.f};
+    float_v dsdr[4][6];
+    float_v F1[36], F2[36], F3[36], F4[36];
+    for(int i1=0; i1<36; i1++)
+    {
+      F1[i1] = 0;
+      F2[i1] = 0;
+      F3[i1] = 0;
+      F4[i1] = 0;
+    }
+    GetDStoParticle( daughter, ds, dsdr );
+    
+    float_v V0Tmp[36] ;
+    float_v V1Tmp[36] ;
+
+    float_v C[36];
+    for(int iC=0; iC<36; iC++)
+      C[iC] = fC[iC];
+    
+             Transport(ds[0], dsdr[0], fP, fC, dsdr[1], F1, F2);
+    daughter.Transport(ds[1], dsdr[3],  m,  V, dsdr[2], F4, F3);
+
+    MultQSQt(F2, daughter.fC, V0Tmp, 6);
+    MultQSQt(F3, C, V1Tmp, 6);
+        
+    for(int iC=0; iC<21; iC++)
+    {
+      fC[iC] += V0Tmp[iC];
+      V[iC]  += V1Tmp[iC];
+    }
+    
+    float_v C1F1T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        C1F1T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          C1F1T[i][j] +=  C[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+    float_v F3C1F1T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        F3C1F1T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          F3C1F1T[i][j] += F3[i*6+k] * C1F1T[k][j];
+        }
+      }
+    float_v C2F2T[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        C2F2T[i][j] = 0;
+        for(int k=0; k<6; k++)
+        {
+          C2F2T[i][j] +=  daughter.fC[IJ(i,k)] * F2[j*6+k];
+        }
+      }
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = F3C1F1T[i][j];
+        for(int k=0; k<6; k++)
+        {
+          D[i][j] += F4[i*6+k] * C2F2T[k][j];
+        }
+      }    
+  }
+  else
+  {
+    float_v dsdr[6];
+    float_v dS = daughter.GetDStoPoint(fP, dsdr);
+    
+    float_v dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0.f, 0.f, 0.f};
+    
+    float_v F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0;
+      F1[i2] = 0;
+    }
+    daughter.Transport(dS, dsdr, m, V, dsdp, F, F1);
+    
+//     float_v V1Tmp[36] = {0.};
+//     MultQSQt(F1, fC, V1Tmp, 6);
+    
+//     for(int iC=0; iC<21; iC++)
+//       V[iC] += V1Tmp[iC];
+    
+    float_v VFT[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<6; j++)
+      {
+        VFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          VFT[i][j] +=  fC[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+    
+    float_v FVFT[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        FVFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          FVFT[i][j] += F1[i*6+k] * VFT[k][j];
+        }
+      }
+      
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          D[i][j] +=  fC[IJ(j,k)] * F1[i*6+k];
+        }
+      }
+      
+    V[0] += FVFT[0][0];
+    V[1] += FVFT[1][0];
+    V[2] += FVFT[1][1];
+    V[3] += FVFT[2][0];
+    V[4] += FVFT[2][1];
+    V[5] += FVFT[2][2];
+  }
+}
+
+void KFParticleBaseSIMD::AddDaughter( const KFParticleBaseSIMD &Daughter )
+{
+  /** Adds daughter to the current particle. Depending on the selected construction method uses: \n
+   ** 1) Either simplifyed fast mathematics which consideres momentum and energy as
+   ** independent variables and thus ignores constraint on the fixed mass (fConstructMethod = 0).
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold. Implemented in the 
+   ** AddDaughterWithEnergyFit() function \n
+   ** 2) Or slower but correct mathematics which requires that the masses of daughter particles 
+   ** stays fixed in the construction process (fConstructMethod = 2). Implemented in the
+   ** AddDaughterWithEnergyFitMC() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+  
+  AddDaughterId( Daughter.Id() );
+
+  if( int(fNDF[0])<-1 ){ // first daughter -> just copy
+    fNDF   = -1;
+    fQ     =  Daughter.GetQ();
+    for( Int_t i=0; i<7; i++ ) fP[i] = Daughter.fP[i];
+    for( Int_t i=0; i<28; i++ ) fC[i] = Daughter.fC[i];
+    fSFromDecay = 0;
+    fMassHypo = Daughter.fMassHypo;
+    SumDaughterMass = Daughter.SumDaughterMass;
+    return;
+  }
+
+  if(fConstructMethod == 0)
+    AddDaughterWithEnergyFit(Daughter);
+  else if(fConstructMethod == 2)
+    AddDaughterWithEnergyFitMC(Daughter);
+
+  SumDaughterMass += Daughter.SumDaughterMass;
+  fMassHypo = -1.f;
+}
+
+void KFParticleBaseSIMD::AddDaughterWithEnergyFit( const KFParticleBaseSIMD &Daughter )
+{
+  /** Adds daughter to the current particle. Uses simplifyed fast mathematics which consideres momentum 
+   ** and energy as independent variables and thus ignores constraint on the fixed mass.
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold.
+   ** \param[in] Daughter - the daughter particle
+   **/
+
+  Int_t maxIter = 1;
+
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+
+    float_v m[8], mV[36];
+
+    float_v D[3][3];
+    GetMeasurement(Daughter, m, mV, D);
+
+    float_v mS[6]= { fC[0]+mV[0], 
+                     fC[1]+mV[1], fC[2]+mV[2], 
+                     fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };    
+    InvertCholetsky3(mS);
+    //* Residual (measured - estimated)
+    
+    float_v zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+    float_v K[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        K[i][j] = 0;
+        for(int k=0; k<3; k++)
+          K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+      }
+    
+    //* CHt = CH' - D'
+    float_v mCHt0[7], mCHt1[7], mCHt2[7];
+
+    mCHt0[0]=fC[ 0] ;       mCHt1[0]=fC[ 1] ;       mCHt2[0]=fC[ 3] ;
+    mCHt0[1]=fC[ 1] ;       mCHt1[1]=fC[ 2] ;       mCHt2[1]=fC[ 4] ;
+    mCHt0[2]=fC[ 3] ;       mCHt1[2]=fC[ 4] ;       mCHt2[2]=fC[ 5] ;
+    mCHt0[3]=fC[ 6]-mV[ 6]; mCHt1[3]=fC[ 7]-mV[ 7]; mCHt2[3]=fC[ 8]-mV[ 8];
+    mCHt0[4]=fC[10]-mV[10]; mCHt1[4]=fC[11]-mV[11]; mCHt2[4]=fC[12]-mV[12];
+    mCHt0[5]=fC[15]-mV[15]; mCHt1[5]=fC[16]-mV[16]; mCHt2[5]=fC[17]-mV[17];
+    mCHt0[6]=fC[21]-mV[21]; mCHt1[6]=fC[22]-mV[22]; mCHt2[6]=fC[23]-mV[23];
+  
+    //* Kalman gain K = mCH'*S
+    
+    float_v k0[7], k1[7], k2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+      k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+      k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+    }
+
+    //* Add the daughter momentum to the particle momentum
+    
+    fP[ 3] += m[ 3];
+    fP[ 4] += m[ 4];
+    fP[ 5] += m[ 5];
+    fP[ 6] += m[ 6];
+  
+    fC[ 9] += mV[ 9];
+    fC[13] += mV[13];
+    fC[14] += mV[14];
+    fC[18] += mV[18];
+    fC[19] += mV[19];
+    fC[20] += mV[20];
+    fC[24] += mV[24];
+    fC[25] += mV[25];
+    fC[26] += mV[26];
+    fC[27] += mV[27];
+    
+ 
+   //* New estimation of the vertex position r += K*zeta
+    
+    for(Int_t i=0;i<7;++i) 
+      fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+    
+    //* New covariance matrix C -= K*(mCH')'
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+        fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+      }
+    }
+
+    float_v K2[3][3];
+    for(int i=0; i<3; i++)
+    {
+      for(int j=0; j<3; j++)
+        K2[i][j] = -K[j][i];
+      K2[i][i] += 1;
+    }
+
+    float_v A[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        A[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          A[i][j] += D[i][k] * K2[k][j];
+        }
+      }
+    
+    float_v M[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        M[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          M[i][j] += K[i][k] * A[k][j];
+        }
+      }
+
+    fC[0] += 2.f*M[0][0];
+    fC[1] += M[0][1] + M[1][0];
+    fC[2] += 2.f*M[1][1];
+    fC[3] += M[0][2] + M[2][0];
+    fC[4] += M[1][2] + M[2][1];
+    fC[5] += 2.f*M[2][2];
+  
+    //* Calculate Chi^2 
+
+    fNDF  += 2;
+    fQ    +=  Daughter.GetQ();
+    fSFromDecay = 0;    
+    fChi2 += (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+      +      (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+      +      (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2];
+  }
+}
+
+void KFParticleBaseSIMD::AddDaughterWithEnergyFitMC( const KFParticleBaseSIMD &Daughter )
+{
+  /** Adds daughter to the current particle. Uses slower but correct mathematics 
+   ** which requires that the masses of daughter particles 
+   ** stays fixed in the construction process.
+   ** \param[in] Daughter - the daughter particle
+   **/
+
+  Int_t maxIter = 1;
+
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+
+    float_v m[8], mV[36];
+
+    float_v D[3][3];
+    GetMeasurement(Daughter, m, mV, D);
+    
+    float_v mS[6]= { fC[0]+mV[0], 
+                   fC[1]+mV[1], fC[2]+mV[2], 
+                   fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };
+    InvertCholetsky3(mS);
+    //* Residual (measured - estimated)
+
+    float_v zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+    float_v K[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        K[i][j] = 0;
+        for(int k=0; k<3; k++)
+          K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+      }
+
+    
+    //* CHt = CH'
+    
+    float_v mCHt0[7], mCHt1[7], mCHt2[7];
+    
+    mCHt0[0]=fC[ 0] ; mCHt1[0]=fC[ 1] ; mCHt2[0]=fC[ 3] ;
+    mCHt0[1]=fC[ 1] ; mCHt1[1]=fC[ 2] ; mCHt2[1]=fC[ 4] ;
+    mCHt0[2]=fC[ 3] ; mCHt1[2]=fC[ 4] ; mCHt2[2]=fC[ 5] ;
+    mCHt0[3]=fC[ 6] ; mCHt1[3]=fC[ 7] ; mCHt2[3]=fC[ 8] ;
+    mCHt0[4]=fC[10] ; mCHt1[4]=fC[11] ; mCHt2[4]=fC[12] ;
+    mCHt0[5]=fC[15] ; mCHt1[5]=fC[16] ; mCHt2[5]=fC[17] ;
+    mCHt0[6]=fC[21] ; mCHt1[6]=fC[22] ; mCHt2[6]=fC[23] ;
+  
+    //* Kalman gain K = mCH'*S
+    
+    float_v k0[7], k1[7], k2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+      k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+      k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+    }
+
+    // last itearation -> update the particle
+
+    //* VHt = VH'
+    
+    float_v mVHt0[7], mVHt1[7], mVHt2[7];
+    
+    mVHt0[0]=mV[ 0] ; mVHt1[0]=mV[ 1] ; mVHt2[0]=mV[ 3] ;
+    mVHt0[1]=mV[ 1] ; mVHt1[1]=mV[ 2] ; mVHt2[1]=mV[ 4] ;
+    mVHt0[2]=mV[ 3] ; mVHt1[2]=mV[ 4] ; mVHt2[2]=mV[ 5] ;
+    mVHt0[3]=mV[ 6] ; mVHt1[3]=mV[ 7] ; mVHt2[3]=mV[ 8] ;
+    mVHt0[4]=mV[10] ; mVHt1[4]=mV[11] ; mVHt2[4]=mV[12] ;
+    mVHt0[5]=mV[15] ; mVHt1[5]=mV[16] ; mVHt2[5]=mV[17] ;
+    mVHt0[6]=mV[21] ; mVHt1[6]=mV[22] ; mVHt2[6]=mV[23] ;
+  
+    //* Kalman gain Km = mCH'*S
+    
+    float_v km0[7], km1[7], km2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      km0[i] = mVHt0[i]*mS[0] + mVHt1[i]*mS[1] + mVHt2[i]*mS[3];
+      km1[i] = mVHt0[i]*mS[1] + mVHt1[i]*mS[2] + mVHt2[i]*mS[4];
+      km2[i] = mVHt0[i]*mS[3] + mVHt1[i]*mS[4] + mVHt2[i]*mS[5];
+    }
+
+    for(Int_t i=0;i<7;++i) 
+      fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+
+    for(Int_t i=0;i<7;++i) 
+      m[i] = m[i] - km0[i]*zeta[0] - km1[i]*zeta[1] - km2[i]*zeta[2];
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+        fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+      }
+    }
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+        mV[k] = mV[k] - (km0[i]*mVHt0[j] + km1[i]*mVHt1[j] + km2[i]*mVHt2[j] );
+      }
+    }
+
+    float_v mDf[7][7];
+
+    for(Int_t i=0;i<7;++i){
+      for(Int_t j=0;j<7;++j){
+        mDf[i][j] = (km0[i]*mCHt0[j] + km1[i]*mCHt1[j] + km2[i]*mCHt2[j] );
+      }
+    }
+
+    float_v mJ1[7][7], mJ2[7][7];
+    for(Int_t iPar1=0; iPar1<7; iPar1++)
+    {
+      for(Int_t iPar2=0; iPar2<7; iPar2++)
+      {
+        mJ1[iPar1][iPar2] = 0;
+        mJ2[iPar1][iPar2] = 0;
+      }
+    }
+
+    float_v mMassParticle  = fP[6]*fP[6] - (fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]);
+    float_v mMassDaughter  = m[6]*m[6] - (m[3]*m[3] + m[4]*m[4] + m[5]*m[5]);
+    mMassParticle(mMassParticle > 0.f) = sqrt(mMassParticle);
+    mMassParticle(mMassParticle <= 0.f) = 0.f;
+    mMassDaughter(mMassDaughter > 0.f) = sqrt(mMassDaughter);
+    mMassDaughter(mMassDaughter <= 0.f) = 0.f;
+
+    float_m mask1 = fMassHypo > -0.5f;
+    float_m mask2 = (!mask1) && ( (mMassParticle < SumDaughterMass) || (fP[6]<0.f)) ;
+    SetMassConstraint(fP,fC,mJ1,fMassHypo, mask1);
+    SetMassConstraint(fP,fC,mJ1,SumDaughterMass, mask2);
+
+    float_m mask3 = Daughter.fMassHypo > -0.5f;
+    float_m mask4 = ( (!mask3) && ( (mMassDaughter<Daughter.SumDaughterMass) || (m[6]<0.f)) );
+    SetMassConstraint(m,mV,mJ2,Daughter.fMassHypo, mask3);
+    SetMassConstraint(m,mV,mJ2,Daughter.SumDaughterMass, mask4);
+
+    float_v mDJ[7][7];
+
+    for(Int_t i=0; i<7; i++) {
+      for(Int_t j=0; j<7; j++) {
+        mDJ[i][j] = 0;
+        for(Int_t k=0; k<7; k++) {
+          mDJ[i][j] += mDf[i][k]*mJ1[j][k];
+        }
+      }
+    }
+
+    for(Int_t i=0; i<7; ++i){
+      for(Int_t j=0; j<7; ++j){
+        mDf[i][j]=0;
+        for(Int_t l=0; l<7; l++){
+          mDf[i][j] += mJ2[i][l]*mDJ[l][j];
+        }
+      }
+    }
+
+    //* Add the daughter momentum to the particle momentum
+
+    fP[ 3] += m[ 3];
+    fP[ 4] += m[ 4];
+    fP[ 5] += m[ 5];
+    fP[ 6] += m[ 6];
+
+    fC[ 9] += mV[ 9];
+    fC[13] += mV[13];
+    fC[14] += mV[14];
+    fC[18] += mV[18];
+    fC[19] += mV[19];
+    fC[20] += mV[20];
+    fC[24] += mV[24];
+    fC[25] += mV[25];
+    fC[26] += mV[26];
+    fC[27] += mV[27];
+
+    fC[6 ] += mDf[3][0]; fC[7 ] += mDf[3][1]; fC[8 ] += mDf[3][2];
+    fC[10] += mDf[4][0]; fC[11] += mDf[4][1]; fC[12] += mDf[4][2];
+    fC[15] += mDf[5][0]; fC[16] += mDf[5][1]; fC[17] += mDf[5][2];
+    fC[21] += mDf[6][0]; fC[22] += mDf[6][1]; fC[23] += mDf[6][2];
+
+    fC[9 ] += mDf[3][3] + mDf[3][3];
+    fC[13] += mDf[4][3] + mDf[3][4]; fC[14] += mDf[4][4] + mDf[4][4];
+    fC[18] += mDf[5][3] + mDf[3][5]; fC[19] += mDf[5][4] + mDf[4][5]; fC[20] += mDf[5][5] + mDf[5][5];
+    fC[24] += mDf[6][3] + mDf[3][6]; fC[25] += mDf[6][4] + mDf[4][6]; fC[26] += mDf[6][5] + mDf[5][6]; fC[27] += mDf[6][6] + mDf[6][6];
+
+    
+    float_v K2[3][3];
+    for(int i=0; i<3; i++)
+    {
+      for(int j=0; j<3; j++)
+        K2[i][j] = -K[j][i];
+      K2[i][i] += 1;
+    }
+
+    float_v A[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        A[i][j] = 0.f;
+        for(int k=0; k<3; k++)
+        {
+          A[i][j] += D[i][k] * K2[k][j];
+        }
+      }
+    
+    float_v M[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        M[i][j] = 0.f;
+        for(int k=0; k<3; k++)
+        {
+          M[i][j] += K[i][k] * A[k][j];
+        }
+      }
+
+    fC[0] += 2*M[0][0];
+    fC[1] += M[0][1] + M[1][0];
+    fC[2] += 2*M[1][1];
+    fC[3] += M[0][2] + M[2][0];
+    fC[4] += M[1][2] + M[2][1];
+    fC[5] += 2*M[2][2];
+    
+    //* Calculate Chi^2 
+
+    fNDF  += 2;
+    fQ    +=  Daughter.GetQ();
+    fSFromDecay = 0;    
+    fChi2 += (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+      +      (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+      +      (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2];
+  }
+}
+
+void KFParticleBaseSIMD::SubtractDaughter( const KFParticleBaseSIMD &Daughter )
+{
+  /** Subtracts a daughter particle from the mother particle. The mathematics is
+   ** similar to AddDaughterWithEnergyFit() but momentum is subtracted.
+   ** \param[in] Daughter - the daughter particle
+   **/
+  
+  AddDaughterId( Daughter.Id() );
+
+  float_v m[8], mV[36];
+
+  float_v D[3][3];
+  GetMeasurement(Daughter, m, mV, D);
+    
+  float_v mS[6]= { fC[0]+mV[0], 
+                     fC[1]+mV[1], fC[2]+mV[2], 
+                     fC[3]+mV[3], fC[4]+mV[4], fC[5]+mV[5] };    
+    InvertCholetsky3(mS);
+    //* Residual (measured - estimated)
+    
+    float_v zeta[3] = { m[0]-fP[0], m[1]-fP[1], m[2]-fP[2] };    
+
+    float_v K[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        K[i][j] = 0;
+        for(int k=0; k<3; k++)
+          K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+      }
+    
+    //* CHt = CH' - D'
+    float_v mCHt0[7], mCHt1[7], mCHt2[7];
+
+    mCHt0[0]=fC[ 0] ;       mCHt1[0]=fC[ 1] ;       mCHt2[0]=fC[ 3] ;
+    mCHt0[1]=fC[ 1] ;       mCHt1[1]=fC[ 2] ;       mCHt2[1]=fC[ 4] ;
+    mCHt0[2]=fC[ 3] ;       mCHt1[2]=fC[ 4] ;       mCHt2[2]=fC[ 5] ;
+    mCHt0[3]=fC[ 6]+mV[ 6]; mCHt1[3]=fC[ 7]+mV[ 7]; mCHt2[3]=fC[ 8]+mV[ 8];
+    mCHt0[4]=fC[10]+mV[10]; mCHt1[4]=fC[11]+mV[11]; mCHt2[4]=fC[12]+mV[12];
+    mCHt0[5]=fC[15]+mV[15]; mCHt1[5]=fC[16]+mV[16]; mCHt2[5]=fC[17]+mV[17];
+    mCHt0[6]=fC[21]+mV[21]; mCHt1[6]=fC[22]+mV[22]; mCHt2[6]=fC[23]+mV[23];
+  
+    //* Kalman gain K = mCH'*S
+    
+    float_v k0[7], k1[7], k2[7];
+    
+    for(Int_t i=0;i<7;++i){
+      k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+      k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+      k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+    }
+
+    //* Add the daughter momentum to the particle momentum
+    
+    fP[ 3] -= m[ 3];
+    fP[ 4] -= m[ 4];
+    fP[ 5] -= m[ 5];
+    fP[ 6] -= m[ 6];
+  
+    fC[ 9] += mV[ 9];
+    fC[13] += mV[13];
+    fC[14] += mV[14];
+    fC[18] += mV[18];
+    fC[19] += mV[19];
+    fC[20] += mV[20];
+    fC[24] += mV[24];
+    fC[25] += mV[25];
+    fC[26] += mV[26];
+    fC[27] += mV[27];
+    
+ 
+   //* New estimation of the vertex position r += K*zeta
+    
+    for(Int_t i=0;i<7;++i) 
+      fP[i] = fP[i] + k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];
+    
+    //* New covariance matrix C -= K*(mCH')'
+
+    for(Int_t i=0, k=0;i<7;++i){
+      for(Int_t j=0;j<=i;++j,++k){
+        fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+      }
+    }
+
+    float_v K2[3][3];
+    for(int i=0; i<3; i++)
+    {
+      for(int j=0; j<3; j++)
+        K2[i][j] = -K[j][i];
+      K2[i][i] += 1;
+    }
+
+    float_v A[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        A[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          A[i][j] += D[i][k] * K2[k][j];
+        }
+      }
+    
+    float_v M[3][3];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<3; j++)
+      {
+        M[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          M[i][j] += K[i][k] * A[k][j];
+        }
+      }
+
+    fC[0] += 2.f*M[0][0];
+    fC[1] += M[0][1] + M[1][0];
+    fC[2] += 2.f*M[1][1];
+    fC[3] += M[0][2] + M[2][0];
+    fC[4] += M[1][2] + M[2][1];
+    fC[5] += 2.f*M[2][2];
+  
+    //* Calculate Chi^2 
+
+    fNDF  += 2;
+    fQ    -=  Daughter.GetQ();
+    fSFromDecay = 0;    
+    fChi2 += (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+      +      (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+      +      (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2];
+}
+
+void KFParticleBaseSIMD::SetProductionVertex( const KFParticleBaseSIMD &Vtx )
+{
+  /** Adds a vertex as a point-like measurement to the current particle.
+   ** The eights parameter of the state vector is filled with the decay
+   ** length to the momentum ratio (s = l/p). The corresponding covariances
+   ** are calculated as well. The parameters of the particle are stored
+   ** at the position of the production vertex.
+   ** \param[in] Vtx - the assumed producation vertex
+   **/
+  
+  const float_v *m = Vtx.fP, *mV = Vtx.fC;
+
+  float_v decayPoint[3] = {fP[0], fP[1], fP[2]};
+  float_v decayPointCov[6] = { fC[0], fC[1], fC[2], fC[3], fC[4], fC[5] };
+
+  float_v D[6][6];
+  for(int iD1=0; iD1<6; iD1++)
+    for(int iD2=0; iD2<6; iD2++)
+      D[iD1][iD2] = 0.f;
+
+  Bool_t noS = ( fC[35][0]<=0.f ); // no decay length allowed
+
+  if( noS ){ 
+    TransportToDecayVertex();
+    fP[7] = 0.f;
+    fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0.f;
+  }
+  else
+  {
+    float_v dsdr[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+    float_v dS = GetDStoPoint(Vtx.fP, dsdr);
+    
+    float_v dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0.f, 0.f, 0.f };
+    
+    float_v F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0.f;
+      F1[i2] = 0.f;
+    }
+    Transport( dS, dsdr, fP, fC, dsdp, F, F1 );
+    
+    float_v CTmp[36];
+    MultQSQt(F1, mV, CTmp, 6);
+    
+    for(int iC=0; iC<21; iC++)
+      fC[iC] += CTmp[iC];
+          
+    for(int i=0; i<6; i++)
+      for(int j=0; j<3; j++)
+      {
+        D[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          D[i][j] +=  mV[IJ(j,k)] * F1[i*6+k];
+        }
+      }
+  }
+
+  float_v mS[6] = { fC[0] + mV[0],
+                    fC[1] + mV[1], fC[2] + mV[2],
+                    fC[3] + mV[3], fC[4] + mV[4], fC[5] + mV[5] };                 
+  InvertCholetsky3(mS);
+  
+  float_v res[3] = { m[0] - X(), m[1] - Y(), m[2] - Z() };
+  
+  float_v K[3][6];  
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      K[i][j] = 0;
+      for(int k=0; k<3; k++)
+        K[i][j] += fC[IJ(i,k)] * mS[IJ(k,j)];
+    }
+  
+  float_v mCHt0[7], mCHt1[7], mCHt2[7];
+  mCHt0[0]=fC[ 0];        mCHt1[0]=fC[ 1];        mCHt2[0]=fC[ 3];
+  mCHt0[1]=fC[ 1];        mCHt1[1]=fC[ 2];        mCHt2[1]=fC[ 4];
+  mCHt0[2]=fC[ 3];        mCHt1[2]=fC[ 4];        mCHt2[2]=fC[ 5];
+  mCHt0[3]=fC[ 6];        mCHt1[3]=fC[ 7];        mCHt2[3]=fC[ 8];
+  mCHt0[4]=fC[10];        mCHt1[4]=fC[11];        mCHt2[4]=fC[12];
+  mCHt0[5]=fC[15];        mCHt1[5]=fC[16];        mCHt2[5]=fC[17];
+  mCHt0[6]=fC[21];        mCHt1[6]=fC[22];        mCHt2[6]=fC[23];
+  
+  float_v k0[7], k1[7], k2[7];
+  for(Int_t i=0;i<7;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+  
+  for(Int_t i=0;i<7;++i) 
+    fP[i] = fP[i] + k0[i]*res[0] + k1[i]*res[1] + k2[i]*res[2];
+
+  for(Int_t i=0, k=0;i<7;++i){
+    for(Int_t j=0;j<=i;++j,++k){
+      fC[k] = fC[k] - (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+    }
+  }
+
+  float_v K2[3][3];
+  for(int i=0; i<3; i++)
+  {
+    for(int j=0; j<3; j++)
+      K2[i][j] = -K[j][i];
+    K2[i][i] += 1;
+  }
+
+  float_v A[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      A[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+        A[i][j] += D[k][i] * K2[k][j];
+      }
+    }
+  
+  float_v M[3][3];
+  for(int i=0; i<3; i++)
+    for(int j=0; j<3; j++)
+    {
+      M[i][j] = 0;
+      for(int k=0; k<3; k++)
+      {
+        M[i][j] += K[i][k] * A[k][j];
+      }
+    }
+    
+  fC[0] += 2*M[0][0];
+  fC[1] += M[0][1] + M[1][0];
+  fC[2] += 2*M[1][1];
+  fC[3] += M[0][2] + M[2][0];
+  fC[4] += M[1][2] + M[2][1];
+  fC[5] += 2*M[2][2];
+  
+  fChi2 += (mS[0]*res[0] + mS[1]*res[1] + mS[3]*res[2])*res[0]
+        +  (mS[1]*res[0] + mS[2]*res[1] + mS[4]*res[2])*res[1]
+        +  (mS[3]*res[0] + mS[4]*res[1] + mS[5]*res[2])*res[2];
+  fNDF += 2;
+   
+  if( noS ){ 
+    fP[7] = 0;
+    fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0.f;
+    fSFromDecay = 0;
+  }
+  else
+  {
+    float_v dsdr[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+    fP[7] = GetDStoPoint(decayPoint, dsdr);   
+    
+    float_v dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0.f, 0.f, 0.f};
+
+    float_v F[36], F1[36];
+    for(int i2=0; i2<36; i2++)
+    {
+      F[i2]  = 0.f;
+      F1[i2] = 0.f;
+    }
+    float_v tmpP[8], tmpC[36]; 
+    Transport( fP[7], dsdr, tmpP, tmpC, dsdp, F, F1 );
+          
+    fC[35] = 0.f;
+    for(int iDsDr=0; iDsDr<6; iDsDr++)
+    {
+      float_v dsdrC = 0.f, dsdpV = 0.f;
+      
+      for(int k=0; k<6; k++)
+        dsdrC += dsdr[k] * fC[IJ(k,iDsDr)]; // (-dsdr[k])*fC[k,j]
+      
+      fC[iDsDr+28] = dsdrC;
+      fC[35] += dsdrC*dsdr[iDsDr] ;
+      if(iDsDr < 3)
+      {
+        for(int k=0; k<3; k++)
+          dsdpV -= dsdr[k] * decayPointCov[IJ(k,iDsDr)];  //
+        fC[35] -= dsdpV*dsdr[iDsDr];
+      }
+    }  
+    fSFromDecay = -fP[7];
+  }
+  
+  fAtProductionVertex = 1;
+}
+
+void KFParticleBaseSIMD::SetMassConstraint( float_v *mP, float_v *mC, float_v mJ[7][7], float_v mass, float_m mask )
+{
+  /** Sets the exact nonlinear mass constraint on the state vector mP with the covariance matrix mC.
+   ** \param[in,out] mP - the state vector to be modified
+   ** \param[in,out] mC - the corresponding covariance matrix
+   ** \param[in,out] mJ - the Jacobian between initial and modified parameters
+   ** \param[in] mass - the mass to be set on the state vector mP
+   ** \param[in] mask - mask defines entries of the SIMD vector, for which the constraint should be applied
+   **/
+  
+  const float_v energy2 = mP[6]*mP[6], p2 = mP[3]*mP[3]+mP[4]*mP[4]+mP[5]*mP[5], mass2 = mass*mass;
+  
+  const float_v a = energy2 - p2 + 2.f*mass2;
+  const float_v b = -2.f*(energy2 + p2);
+  const float_v c = energy2 - p2 - mass2;
+
+  float_v lambda(Vc::Zero);
+  lambda(abs(b) > float_v(1.e-10f)) = -c/b ;
+
+  float_v d = 4.f*energy2*p2 - mass2*(energy2-p2-2.f*mass2);
+  float_m qMask = (d >= 0.f) && (abs(a) > (1.e-10f)) ;
+  lambda(qMask) = (energy2 + p2 - sqrt(d))/a;
+
+  lambda(mP[6]<0.f) = -1000000.f;
+
+  Int_t iIter=0;
+  for(iIter=0; iIter<100; iIter++)
+  {
+    float_v lambda2 = lambda*lambda;
+    float_v lambda4 = lambda2*lambda2;
+
+//    float_v lambda0 = lambda;
+
+    float_v f  = -mass2 * lambda4 + a*lambda2 + b*lambda + c;
+    float_v df = -4.f*mass2 * lambda2*lambda + 2.f*a*lambda + b;
+    lambda(abs(df) > float_v(1.e-10f)) -= f/df;
+//    if(TMath::Abs(lambda0 - lambda) < 1.e-8) break;
+  }
+
+  const float_v lpi = 1.f/(1.f + lambda);
+  const float_v lmi = 1.f/(1.f - lambda);
+  const float_v lp2i = lpi*lpi;
+  const float_v lm2i = lmi*lmi;
+
+  float_v lambda2 = lambda*lambda;
+
+  float_v dfl  = -4.f*mass2 * lambda2*lambda + 2.f*a*lambda + b;
+  float_v dfx[4] = {0.f,0.f,0.f,0.f};
+  dfx[0] = -2.f*(1.f + lambda)*(1.f + lambda)*mP[3];
+  dfx[1] = -2.f*(1.f + lambda)*(1.f + lambda)*mP[4];
+  dfx[2] = -2.f*(1.f + lambda)*(1.f + lambda)*mP[5];
+  dfx[3] = 2.f*(1.f - lambda)*(1.f - lambda)*mP[6];
+  float_v dlx[4] = {1.f,1.f,1.f,1.f};
+
+  for(int i=0; i<4; i++)
+    dlx[i](abs(dfl) > float_v(1.e-10f)) = -dfx[i] / dfl;
+
+  float_v dxx[4] = {mP[3]*lm2i, mP[4]*lm2i, mP[5]*lm2i, -mP[6]*lp2i};
+
+  for(Int_t i=0; i<7; i++)
+    for(Int_t j=0; j<7; j++)
+      mJ[i][j]=0;
+  mJ[0][0] = 1.;
+  mJ[1][1] = 1.;
+  mJ[2][2] = 1.;
+
+  for(Int_t i=3; i<7; i++)
+    for(Int_t j=3; j<7; j++)
+      mJ[i][j] = dlx[j-3]*dxx[i-3];
+
+  for(Int_t i=3; i<6; i++)
+    mJ[i][i] += lmi;
+  mJ[6][6] += lpi;
+
+  float_v mCJ[7][7];
+
+  for(Int_t i=0; i<7; i++) {
+    for(Int_t j=0; j<7; j++) {
+      mCJ[i][j] = 0;
+      for(Int_t k=0; k<7; k++) {
+        mCJ[i][j] += mC[IJ(i,k)]*mJ[j][k];
+      }
+    }
+  }
+
+  for(Int_t i=0; i<7; ++i){
+    for(Int_t j=0; j<=i; ++j){
+      mC[IJ(i,j)](mask) = 0.f;
+      for(Int_t l=0; l<7; l++){
+        mC[IJ(i,j)](mask) += mJ[i][l]*mCJ[l][j];
+      }
+    }
+  }
+
+  mP[3](mask) *= lmi;
+  mP[4](mask) *= lmi;
+  mP[5](mask) *= lmi;
+  mP[6](mask) *= lpi;
+}
+
+void KFParticleBaseSIMD::SetNonlinearMassConstraint( float_v mass )
+{
+  /** Sets the exact nonlinear mass constraint on the current particle.
+   ** \param[in] mass - the mass to be set on the particle
+   **/
+  
+  const float_v& px = fP[3];
+  const float_v& py = fP[4];
+  const float_v& pz = fP[5];
+  const float_v& energy  = fP[6];
+  
+  const float_v residual = (energy*energy - px*px - py*py - pz*pz) - mass*mass;
+  const float_v dm2 = float_v(4.f) * ( fC[9]*px*px + fC[14]*py*py + fC[20]*pz*pz + fC[27]*energy*energy +
+                      float_v(2.f) * ( (fC[13]*py + fC[18]*pz - fC[24]*energy)*px + (fC[19]*pz - fC[25]*energy)*py - fC[26]*pz*energy) );
+  const float_v dChi2 = residual*residual / dm2;
+  fChi2 += dChi2;
+  fNDF  += 1;
+  
+  float_v mJ[7][7];
+  SetMassConstraint( fP, fC, mJ, mass, float_m(true) );
+  fMassHypo = mass;
+  SumDaughterMass = mass;
+}
+
+void KFParticleBaseSIMD::SetMassConstraint( float_v Mass, float_v SigmaMass )
+{  
+  /** Sets linearised mass constraint on the current particle. The constraint can be set with
+   ** an uncertainty.
+   ** \param[in] Mass - the mass to be set on the state vector mP
+   ** \param[in] SigmaMass - uncertainty of the constraint
+   **/
+  
+  fMassHypo = Mass;
+  SumDaughterMass = Mass;
+
+  float_v m2 = Mass*Mass;            // measurement, weighted by Mass 
+  float_v s2 = m2*SigmaMass*SigmaMass; // sigma^2
+
+  float_v p2 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5]; 
+  float_v e0 = sqrt(m2+p2);
+
+  float_v mH[8];
+  mH[0] = mH[1] = mH[2] = 0.f;
+  mH[3] = -2.f*fP[3]; 
+  mH[4] = -2.f*fP[4]; 
+  mH[5] = -2.f*fP[5]; 
+  mH[6] =  2.f*fP[6];//e0;
+  mH[7] = 0.f; 
+
+  float_v zeta = e0*e0 - e0*fP[6];
+  zeta = m2 - (fP[6]*fP[6]-p2);
+  
+  float_v mCHt[8], s2_est=0.f;
+  for( Int_t i=0; i<8; ++i ){
+    mCHt[i] = 0.0f;
+    for (Int_t j=0;j<8;++j) mCHt[i] += Cij(i,j)*mH[j];
+    s2_est += mH[i]*mCHt[i];
+  }
+  
+//TODO add protection
+//  if( s2_est<1.e-20 ) return; // calculated mass error is already 0, 
+                              // the particle can not be constrained on mass
+
+  float_v w2 = 1.f/( s2 + s2_est );
+  fChi2 += zeta*zeta*w2;
+  fNDF  += 1;
+  for( Int_t i=0, ii=0; i<8; ++i ){
+    float_v ki = mCHt[i]*w2;
+    fP[i]+= ki*zeta;
+    for(Int_t j=0;j<=i;++j) fC[ii++] -= ki*mCHt[j];    
+  }
+}
+
+
+void KFParticleBaseSIMD::SetNoDecayLength()
+{  
+  /** Sets constraint on the zero decay length. When the production point is set 
+   ** the measurement from this particle is created at the decay point.
+   **/
+  
+  TransportToDecayVertex();
+
+  float_v h[8];
+  h[0] = h[1] = h[2] = h[3] = h[4] = h[5] = h[6] = 0.f;
+  h[7] = 1.f; 
+
+  float_v zeta = 0.f - fP[7];
+  for(Int_t i=0;i<8;++i) zeta -= h[i]*(fP[i]-fP[i]);
+  
+  float_v s = fC[35];   
+//  if( s>1.e-20 ) //TODO add protection
+  {
+    s = 1.f/s;
+    fChi2 += zeta*zeta*s;
+    fNDF  += 1;
+    for( Int_t i=0, ii=0; i<7; ++i ){
+      float_v ki = fC[28+i]*s;
+      fP[i]+= ki*zeta;
+      for(Int_t j=0;j<=i;++j) fC[ii++] -= ki*fC[28+j];    
+    }
+  }
+  fP[7] = 0.f;
+  fC[28] = fC[29] = fC[30] = fC[31] = fC[32] = fC[33] = fC[34] = fC[35] = 0.f;
+}
+
+void KFParticleBaseSIMD::Construct( const KFParticleBaseSIMD* vDaughters[], Int_t nDaughters, 
+                                    const KFParticleBaseSIMD *Parent,  Float_t Mass )
+{ 
+  /** Constructs a short-lived particle from a set of daughter particles:\n
+   ** 1) all parameters of the "this" objects are initialised;\n
+   ** 2) daughters are added one after another;\n
+   ** 3) if Parent pointer is not null, the production vertex is set to it;\n
+   ** 4) if Mass hypothesis >=0 the mass constraint is set.
+   ** \param[in] vDaughters - array of daughter particles
+   ** \param[in] nDaughters - number of daughter particles in the input array
+   ** \param[in] Parent - optional parrent particle
+   ** \param[in] Mass - optional mass hypothesis
+   **/
+  
+  const int maxIter = 1;
+  for( Int_t iter=0; iter<maxIter; iter++ ){
+    
+    CleanDaughtersId();
+    SetNDaughters(nDaughters);
+    
+    fAtProductionVertex = 0;
+    fSFromDecay = float_v(Vc::Zero);
+    SumDaughterMass = float_v(Vc::Zero);
+
+    for(Int_t i=0;i<36;++i) fC[i]=0.;
+    fC[35] = 1.;
+    
+    fNDF  = -3;
+    fChi2 =  0.;
+    fQ = 0;
+
+    for( Int_t itr =0; itr<nDaughters; itr++ ){
+      AddDaughter( *vDaughters[itr] );    
+    }
+  }
+
+  if( Mass>=0 ) SetMassConstraint( Mass );
+  if( Parent ) SetProductionVertex( *Parent );
+}
+
+void KFParticleBaseSIMD::TransportToDecayVertex()
+{
+  /** Transports the particle to its decay vertex */ 
+  float_v dsdr[6] = {float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero)};
+  if( !( (abs(fSFromDecay) < float_v(1.e-6f)).isFull() ) ) TransportToDS( -fSFromDecay, dsdr );
+  fAtProductionVertex = 0;
+}
+
+void KFParticleBaseSIMD::TransportToProductionVertex()
+{
+  /** Transports the particle to its production vertex */
+  float_v dsdr[6] = {float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero),float_v(Vc::Zero)}; 
+  if( !( (abs(fSFromDecay + fP[7]) < float_v(1.e-6f)).isFull() )  ) TransportToDS( -fSFromDecay-fP[7], dsdr );
+  fAtProductionVertex = 1;
+}
+
+
+void KFParticleBaseSIMD::TransportToDS( float_v dS, const float_v* dsdr )
+{ 
+  /** Transport the particle on a certain distane. The distance is defined by the dS=l/p parameter, where \n
+   ** 1) l - signed distance;\n
+   ** 2) p - momentum of the particle. \n
+   ** \param[in] dS = l/p - distance normalised to the momentum of the particle to be transported on
+   ** \param[in] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  Transport( dS, dsdr, fP, fC );
+  fSFromDecay+= dS;
+}
+
+void KFParticleBaseSIMD::TransportToDSLine( float_v dS, const float_v* dsdr )
+{ 
+  /** Transport the particle on a certain distane assuming the linear trajectory. 
+   ** The distance is defined by the dS=l/p parameter, where \n
+   ** 1) l - signed distance;\n
+   ** 2) p - momentum of the particle. \n
+   ** \param[in] dS = l/p - distance normalised to the momentum of the particle to be transported on
+   ** \param[in] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  TransportLine( dS, dsdr, fP, fC );
+  fSFromDecay+= dS;
+}
+
+void KFParticleBaseSIMD::GetDistanceToVertexLine( const KFParticleBaseSIMD &Vertex, float_v &l, float_v &dl, float_m *isParticleFromVertex ) const 
+{
+  /** Calculates the distance between the particle position and the vertex together with the error.
+   ** Errors of both particle and vertex are taken into account. Also optionally checks if partcile
+   ** is pointing flying from the vertex, not in the direction to the vertex if the pointer to the
+   ** mask isParticleFromVertex is provided.
+   ** \param[in] Vertex - vertex to which the distance should be calculated
+   ** \param[out] l - distance between the current position of the particle and a vertex
+   ** \param[out] dl - the error of the calculated distance
+   ** \param[out] isParticleFromVertex - mask which shows if particle is flying in the direction from the vertex
+   **/
+
+  float_v c[6] = {Vertex.fC[0]+fC[0], Vertex.fC[1]+fC[1], Vertex.fC[2]+fC[2],
+               Vertex.fC[3]+fC[3], Vertex.fC[4]+fC[4], Vertex.fC[5]+fC[5]};
+
+  float_v dx = (Vertex.fP[0]-fP[0]);
+  float_v dy = (Vertex.fP[1]-fP[1]);
+  float_v dz = (Vertex.fP[2]-fP[2]);
+
+  l = sqrt( dx*dx + dy*dy + dz*dz );
+  dl = c[0]*dx*dx + c[2]*dy*dy + c[5]*dz*dz + 2*(c[1]*dx*dy + c[3]*dx*dz + c[4]*dy*dz);
+
+  l(abs(l) < 1.e-8f) = 1.e-8f;
+  float_m ok = float_v(Vc::Zero)<=dl;
+  dl(!ok) = 1.e8f;
+  dl(ok) = sqrt( dl )/l;
+
+  if(isParticleFromVertex)
+  {
+    *isParticleFromVertex = ok && ( l<float_v(3.f*dl) );
+    float_v cosV = dx*fP[3] + dy*fP[4] + dz*fP[5];
+//     float_v dCos = dy*dy*fC[14] + dz*dz*fC[20] + dx*dx*fC[9] + 2*dz*fC[15]*fP[3] + c[0]* fP[3]*fP[3] + 
+//             2*dz*fC[16]* fP[4] + 2 *c[1] *fP[3] *fP[4] + c[2] *fP[4]*fP[4] + 2 *dz *fC[17]* fP[5] + 
+//             2*c[3] *fP[3]* fP[5] + 2 *c[4] *fP[4] *fP[5] + c[5]*fP[5] *fP[5] + 
+//             2*dy *(dz *fC[19] + fC[10] *fP[3] + fC[11]* fP[4] + fC[12]* fP[5]) + 
+//             2*dx *(dy *fC[13] + dz *fC[18] + fC[6]* fP[3] + fC[7]* fP[4] + fC[8]* fP[5]);
+//     ok = float_v(float_v(0)<dCos);
+//     dCos = float_v(ok & ( dCos ));
+//     dCos = sqrt(dCos);
+    *isParticleFromVertex = (*isParticleFromVertex) || (!(*isParticleFromVertex) && (cosV<0.f) ) ;
+  }
+}
+
+float_v KFParticleBaseSIMD::GetDStoPointLine( const float_v xyz[3], float_v dsdr[6] ) const 
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** assuming the straigth line trajectory. Is used for particles with charge 0 or in case of zero magnetic field.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** \param[in] xyz[3] - point where particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  float_v p2 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5];  
+  p2( p2 < float_v(1.e-4f) )  = float_v(1.f);
+  
+  const float_v& a = fP[3]*(xyz[0]-fP[0]) + fP[4]*(xyz[1]-fP[1]) + fP[5]*(xyz[2]-fP[2]);
+  dsdr[0] = -fP[3]/p2;
+  dsdr[1] = -fP[4]/p2;
+  dsdr[2] = -fP[5]/p2;
+  dsdr[3] = ((xyz[0]-fP[0])*p2 - 2.f* fP[3]*a)/(p2*p2);
+  dsdr[4] = ((xyz[1]-fP[1])*p2 - 2.f* fP[4]*a)/(p2*p2);
+  dsdr[5] = ((xyz[2]-fP[2])*p2 - 2.f* fP[5]*a)/(p2*p2);
+  
+  return a/p2;
+}
+
+float_v KFParticleBaseSIMD::GetDStoPointBz( float_v B, const float_v xyz[3], float_v dsdr[6], const float_v* param) const
+{ 
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field Bz.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** \param[in] B - magnetic field Bz
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[in] param - optional parameter, is used in case if the parameters of the particle are rotated
+   ** to other coordinate system (see GetDStoPointBy() function), otherwise fP are used
+   **/
+
+  if(!param)
+    param = fP;
+  //* Get dS to a certain space point for Bz field
+  
+  const float_v& x  = param[0];
+  const float_v& y  = param[1];
+  const float_v& z  = param[2];
+  const float_v& px = param[3];
+  const float_v& py = param[4];
+  const float_v& pz = param[5];
+  
+  const float_v kCLight = 0.000299792458f;
+  float_v bq = B*simd_cast<float_v>(fQ)*kCLight;
+  float_v pt2 = param[3]*param[3] + param[4]*param[4];
+  float_v p2 = pt2 + param[5]*param[5];  
+  
+  float_v dx = xyz[0] - param[0];
+  float_v dy = xyz[1] - param[1]; 
+  float_v dz = xyz[2] - param[2]; 
+  float_v a = dx*param[3]+dy*param[4];
+  float_v dS(Vc::Zero);
+  
+  float_v abq = bq*a;
+
+  const float_v LocalSmall = 1.e-8f;
+  float_m mask = ( abs(bq)<LocalSmall );
+  if( !( (!mask).isFull() ) )
+  {
+    dS(mask && float_m(p2>1.e-4f)) = (a + dz*pz)/p2;
+    
+    dsdr[0](mask && float_m(p2>1.e-4f)) = -px/p2;
+    dsdr[1](mask && float_m(p2>1.e-4f)) = -py/p2;
+    dsdr[2](mask && float_m(p2>1.e-4f)) = -pz/p2;
+    dsdr[3](mask && float_m(p2>1.e-4f)) = (dx*p2 - 2.f* px *(a + dz *pz))/(p2*p2);
+    dsdr[4](mask && float_m(p2>1.e-4f)) = (dy*p2 - 2.f* py *(a + dz *pz))/(p2*p2);
+    dsdr[5](mask && float_m(p2>1.e-4f)) = (dz*p2 - 2.f* pz *(a + dz *pz))/(p2*p2);
+    
+    if(mask.isFull())
+      return dS;
+  }
+  
+  dS(!mask) = KFPMath::ATan2( abq, pt2 + bq*(dy*px -dx*py) )/bq;
+
+  float_v bs= bq*dS;
+
+  float_v s = sin(bs), c = cos(bs);
+
+  bq(abs(bq) < LocalSmall) = LocalSmall;
+  float_v bbq = bq*(dx*py - dy*px) - pt2;
+  
+  dsdr[0](!mask) = (px*bbq - py*abq)/(abq*abq + bbq*bbq);
+  dsdr[1](!mask) = (px*abq + py*bbq)/(abq*abq + bbq*bbq);
+  dsdr[2](!mask) = 0;
+  dsdr[3](!mask) = -(dx*bbq + dy*abq + 2.f*px*a)/(abq*abq + bbq*bbq);
+  dsdr[4](!mask) = (dx*abq - dy*bbq - 2.f*py*a)/(abq*abq + bbq*bbq);
+  dsdr[5](!mask) = 0;
+  
+  float_v sz(Vc::Zero);
+  float_v cCoeff = (bbq*c - abq*s) - pz*pz ;
+  sz(abs(cCoeff) > 1.e-8f) = (dS*pz - dz)*pz / cCoeff;
+  
+  float_v dcdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  dcdr[0] = -bq*py*c - bbq*s*bq*dsdr[0] + px*bq*s - abq*c*bq*dsdr[0];
+  dcdr[1] =  bq*px*c - bbq*s*bq*dsdr[1] + py*bq*s - abq*c*bq*dsdr[1];
+  dcdr[3] = (-bq*dy-2*px)*c - bbq*s*bq*dsdr[3] - dx*bq*s - abq*c*bq*dsdr[3];
+  dcdr[4] = ( bq*dx-2*py)*c - bbq*s*bq*dsdr[4] - dy*bq*s - abq*c*bq*dsdr[4];
+  dcdr[5] = -2*pz;
+  
+  for(int iP=0; iP<6; iP++)
+    dsdr[iP](!mask) += pz*pz/cCoeff*dsdr[iP] - sz/cCoeff*dcdr[iP];
+
+  dsdr[2](!mask) += pz/cCoeff;
+  dsdr[5](!mask) += (2.f*pz*dS - dz)/cCoeff;
+  
+  dS(!mask) += sz;
+  
+  bs= bq*dS;
+  s = sin(bs);
+  c = cos(bs);
+  
+  float_v sB, cB;
+  const float_v kOvSqr6 = 1.f/sqrt(float_v(6.f));
+
+  sB(LocalSmall < abs(bs)) = s/bq;
+  sB(LocalSmall >= abs(bs)) = (1.f-bs*kOvSqr6)*(1.f+bs*kOvSqr6)*dS;
+  cB(LocalSmall < abs(bs)) = (1.f-c)/bq;
+  cB(LocalSmall >= abs(bs)) = .5f*sB*bs;
+
+  float_v p[5];
+  p[0] = x + sB*px + cB*py;
+  p[1] = y - cB*px + sB*py;
+  p[2] = z +  dS*pz;
+  p[3] =      c*px + s*py;
+  p[4] =     -s*px + c*py;
+
+  dx = xyz[0] - p[0];
+  dy = xyz[1] - p[1];
+  dz = xyz[2] - p[2];
+  a = dx*p[3]+dy*p[4] + dz*pz;
+
+  abq = bq*a;
+
+  dS(!mask) += KFPMath::ATan2( abq, p2 + bq*(dy*p[3] -dx*p[4]) )/bq;
+  
+  return dS;
+}
+
+float_v KFParticleBaseSIMD::GetDStoPointBy( float_v By, const float_v xyz[3], float_v dsdr[6] ) 
+  const
+{ 
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** The particle parameters are transformed to the coordinate system, where the main component of the magnetic field
+   ** By is directed along the Z axis: x->x, y->-z, z->y, and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] By - magnetic field By
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  const float_v param[6] = { fP[0], -fP[2], fP[1], fP[3], -fP[5], fP[4] };
+  const float_v point[3] = { xyz[0], -xyz[2], xyz[1] };
+  
+  float_v dsdrBz[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+
+  const float_v dS = GetDStoPointBz(By, point, dsdrBz, param);
+  dsdr[0] =  dsdrBz[0];
+  dsdr[1] =  dsdrBz[2];
+  dsdr[2] = -dsdrBz[1];
+  dsdr[3] =  dsdrBz[3];
+  dsdr[4] =  dsdrBz[5];
+  dsdr[5] = -dsdrBz[4];
+  
+  return dS;
+}
+
+float_v KFParticleBaseSIMD::GetDStoPointCBM( const float_v xyz[3], float_v dsdr[6] ) const
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** in case of the CBM-like nonhomogeneous magnetic field.
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** For this the y-component of the magnetic field at the current position of the particle is obtained and
+   ** the GetDStoPointBy() is called.
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   **/
+  
+  float_v dS(Vc::Zero);
+
+  float_v fld[3];
+  GetFieldValue( fP, fld );
+  dS = GetDStoPointBy( fld[1],xyz, dsdr );
+  
+  dS(abs(dS)>1.E3f) = 0.f;
+
+  return dS;
+}
+
+void KFParticleBaseSIMD::GetDStoParticleBz( float_v B, const KFParticleBaseSIMD &p, 
+                                            float_v dS[2], float_v dsdr[4][6], const float_v* param1, const float_v* param2 ) const
+{ 
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field Bz. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle (if the pointer is not provided it is initialised with fP) and
+   ** param2 are parameters of the second particle "p" (if the pointer is not provided it is initialised with p.fP). Parameters
+   ** param1 and param2 should be either provided both or both set to null pointers.
+   ** \param[in] B - magnetic field Bz
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   ** \param[in] param1 - optional parameter, is used in case if the parameters of the current particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise fP are used
+   ** \param[in] param2 - optional parameter, is used in case if the parameters of the second particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise p.fP are used
+   **/
+  
+  if(!param1)
+  {
+    param1 = fP;
+    param2 = p.fP;
+  }
+
+  //* Get dS to another particle for Bz field
+  const float_v kOvSqr6 = 1.f/sqrt(float_v(6.f));
+  const float_v kCLight = 0.000299792458f;
+
+  //in XY plane
+  //first root    
+  const float_v& bq1 = B*simd_cast<float_v>(fQ)*kCLight;
+  const float_v& bq2 = B*simd_cast<float_v>(p.fQ)*kCLight;
+
+  const float_m& isStraight1 = abs(bq1) < float_v(1.e-8f);
+  const float_m& isStraight2 = abs(bq2) < float_v(1.e-8f);
+  
+  if( isStraight1.isFull() && isStraight2.isFull() )
+  {
+    GetDStoParticleLine(p, dS, dsdr);
+    return;
+  }
+    
+  const float_v& px1 = param1[3];
+  const float_v& py1 = param1[4];
+  const float_v& pz1 = param1[5];
+
+  const float_v& px2 = param2[3];
+  const float_v& py2 = param2[4];
+  const float_v& pz2 = param2[5];
+
+  const float_v& pt12 = px1*px1 + py1*py1;
+  const float_v& pt22 = px2*px2 + py2*py2;
+
+  const float_v& x01 = param1[0];
+  const float_v& y01 = param1[1];
+  const float_v& z01 = param1[2];
+
+  const float_v& x02 = param2[0];
+  const float_v& y02 = param2[1];
+  const float_v& z02 = param2[2];
+
+  float_v dS1[2] = {0.f, 0.f}, dS2[2]={0.f, 0.f};
+  
+  const float_v& dx0 = (x01 - x02);
+  const float_v& dy0 = (y01 - y02);
+  const float_v& dr02 = dx0*dx0 + dy0*dy0;
+  const float_v& drp1  = dx0*px1 + dy0*py1;
+  const float_v& dxyp1 = dx0*py1 - dy0*px1;
+  const float_v& drp2  = dx0*px2 + dy0*py2;
+  const float_v& dxyp2 = dx0*py2 - dy0*px2;
+  const float_v& p1p2 = px1*px2 + py1*py2;
+  const float_v& dp1p2 = px1*py2 - px2*py1;
+  
+  const float_v& k11 = (bq2*drp1 - dp1p2);
+  const float_v& k21 = (bq1*(bq2*dxyp1 - p1p2) + bq2*pt12);
+  const float_v& k12 = ((bq1*drp2 - dp1p2));
+  const float_v& k22 = (bq2*(bq1*dxyp2 + p1p2) - bq1*pt22);
+  
+  const float_v& kp = (dxyp1*bq2 - dxyp2*bq1 - p1p2);
+  const float_v& kd = dr02/2.f*bq1*bq2 + kp;
+  const float_v& c1 = -(bq1*kd + pt12*bq2);
+  const float_v& c2 = bq2*kd + pt22*bq1; 
+  
+  float_v d1 = pt12*pt22 - kd*kd;
+  d1(d1 < float_v(Vc::Zero)) = float_v(Vc::Zero);
+  d1 = sqrt( d1 );
+  float_v d2 = pt12*pt22 - kd*kd;
+  d2(d2 < float_v(Vc::Zero)) = float_v(Vc::Zero);
+  d2 = sqrt( d2 );
+    
+  float_v dS1dR1[2][6];
+  float_v dS2dR2[2][6];
+
+  float_v dS1dR2[2][6];
+  float_v dS2dR1[2][6];
+
+  float_v dk11dr1[6] = {bq2*px1, bq2*py1, 0.f, bq2*dx0 - py2, bq2*dy0 + px2, 0.f};
+  float_v dk11dr2[6] = {-bq2*px1, -bq2*py1, 0.f, py1, -px1, 0.f};
+  float_v dk12dr1[6] = {bq1*px2, bq1*py2, 0.f, -py2, px2, 0.f};
+  float_v dk12dr2[6] = {-bq1*px2, -bq1*py2, 0.f, bq1*dx0 + py1, bq1*dy0 - px1, 0.f};
+  float_v dk21dr1[6] = {bq1*bq2*py1, -bq1*bq2*px1, 0.f, 2.f*bq2*px1 + bq1*(-(bq2*dy0) - px2), 2.f*bq2*py1 + bq1*(bq2*dx0 - py2), 0.f};
+  float_v dk21dr2[6] = {-(bq1*bq2*py1), bq1*bq2*px1, 0.f, -(bq1*px1), -(bq1*py1), 0.f};
+  float_v dk22dr1[6] = {bq1*bq2*py2, -(bq1*bq2*px2), 0.f, bq2*px2, bq2*py2, 0.f};
+  float_v dk22dr2[6] = {-(bq1*bq2*py2), bq1*bq2*px2, 0.f, bq2*(-(bq1*dy0) + px1) - 2.f*bq1*px2, bq2*(bq1*dx0 + py1) - 2.f*bq1*py2, 0.f};
+  
+  float_v dkddr1[6] = {bq1*bq2*dx0 + bq2*py1 - bq1*py2, bq1*bq2*dy0 - bq2*px1 + bq1*px2, 0.f, -bq2*dy0 - px2, bq2*dx0 - py2, 0.f};
+  float_v dkddr2[6] = {-bq1*bq2*dx0 - bq2*py1 + bq1*py2, -bq1*bq2*dy0 + bq2*px1 - bq1*px2, 0.f, bq1*dy0 - px1, -bq1*dx0 - py1, 0.f};
+  
+  float_v dc1dr1[6] = {-(bq1*(bq1*bq2*dx0 + bq2*py1 - bq1*py2)), -(bq1*(bq1*bq2*dy0 - bq2*px1 + bq1*px2)), 0.f, -2.f*bq2*px1 - bq1*(-(bq2*dy0) - px2), -2.f*bq2*py1 - bq1*(bq2*dx0 - py2), 0.f};
+  float_v dc1dr2[6] = {-(bq1*(-(bq1*bq2*dx0) - bq2*py1 + bq1*py2)), -(bq1*(-(bq1*bq2*dy0) + bq2*px1 - bq1*px2)), 0.f, -(bq1*(bq1*dy0 - px1)), -(bq1*(-(bq1*dx0) - py1)), 0.f};
+  
+  float_v dc2dr1[6] = {bq2*(bq1*bq2*dx0 + bq2*py1 - bq1*py2), bq2*(bq1*bq2*dy0 - bq2*px1 + bq1*px2), 0.f, bq2*(-(bq2*dy0) - px2), bq2*(bq2*dx0 - py2), 0.f};
+  float_v dc2dr2[6] = {bq2*(-(bq1*bq2*dx0) - bq2*py1 + bq1*py2), bq2*(-(bq1*bq2*dy0) + bq2*px1 - bq1*px2), 0.f, bq2*(bq1*dy0 - px1) + 2.f*bq1*px2, bq2*(-(bq1*dx0) - py1) + 2.f*bq1*py2, 0.f};
+  
+  float_v dd1dr1[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  float_v dd1dr2[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  {
+    for(int i=0; i<6; i++)
+    {
+      dd1dr1[i](d1>0.f) = -kd/d1*dkddr1[i];
+      dd1dr2[i](d1>0.f) = -kd/d1*dkddr2[i];
+    }
+    dd1dr1[3](d1>0.f) += px1/d1*pt22; dd1dr1[4](d1>0.f) += py1/d1*pt22;
+    dd1dr2[3](d1>0.f) += px2/d1*pt12; dd1dr2[4](d1>0.f) += py2/d1*pt12;
+  }
+
+  // find two points of closest approach in XY plane
+  if( ! ( (!isStraight1).isEmpty() ) )
+  {
+    dS1[0](!isStraight1) = KFPMath::ATan2( (bq1*k11*c1 + k21*d1*bq1), (bq1*k11*d1*bq1 - k21*c1) )/bq1;
+    dS1[1](!isStraight1) = KFPMath::ATan2( (bq1*k11*c1 - k21*d1*bq1), (-bq1*k11*d1*bq1 - k21*c1) )/bq1;
+    
+    float_v a = bq1*(k11*c1 + k21*d1);
+    float_v b = bq1*k11*d1*bq1 - k21*c1;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = bq1*( dk11dr1[iP]*c1 + k11*dc1dr1[iP] + dk21dr1[iP]*d1 + k21*dd1dr1[iP] );
+      const float_v dadr2 = bq1*( dk11dr2[iP]*c1 + k11*dc1dr2[iP] + dk21dr2[iP]*d1 + k21*dd1dr2[iP] );
+      const float_v dbdr1 = bq1*bq1*( dk11dr1[iP]*d1 + k11*dd1dr1[iP] ) - ( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+      const float_v dbdr2 = bq1*bq1*( dk11dr2[iP]*d1 + k11*dd1dr2[iP] ) - ( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+      
+      dS1dR1[0][iP](!isStraight1) = 1/bq1 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+      dS1dR2[0][iP](!isStraight1) = 1/bq1 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+    }
+    
+    a = bq1*(k11*c1 - k21*d1);
+    b = -bq1*k11*d1*bq1 - k21*c1;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = bq1*( dk11dr1[iP]*c1 + k11*dc1dr1[iP] - (dk21dr1[iP]*d1 + k21*dd1dr1[iP]) );
+      const float_v dadr2 = bq1*( dk11dr2[iP]*c1 + k11*dc1dr2[iP] - (dk21dr2[iP]*d1 + k21*dd1dr2[iP]) );
+      const float_v dbdr1 = -bq1*bq1*( dk11dr1[iP]*d1 + k11*dd1dr1[iP] ) - ( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+      const float_v dbdr2 = -bq1*bq1*( dk11dr2[iP]*d1 + k11*dd1dr2[iP] ) - ( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+      
+      dS1dR1[1][iP](!isStraight1) = 1/bq1 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+      dS1dR2[1][iP](!isStraight1) = 1/bq1 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+    }
+  }
+  if( ! ( (!isStraight2).isEmpty() ) )
+  {
+    dS2[0](!isStraight2) = KFPMath::ATan2( (bq2*k12*c2 + k22*d2*bq2), (bq2*k12*d2*bq2 - k22*c2) )/bq2;
+    dS2[1](!isStraight2) = KFPMath::ATan2( (bq2*k12*c2 - k22*d2*bq2), (-bq2*k12*d2*bq2 - k22*c2) )/bq2;
+    
+    float_v a = bq2*(k12*c2 + k22*d2);
+    float_v b = bq2*k12*d2*bq2 - k22*c2;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = bq2*( dk12dr1[iP]*c2 + k12*dc2dr1[iP] + dk22dr1[iP]*d1 + k22*dd1dr1[iP] );
+      const float_v dadr2 = bq2*( dk12dr2[iP]*c2 + k12*dc2dr2[iP] + dk22dr2[iP]*d1 + k22*dd1dr2[iP] );
+      const float_v dbdr1 = bq2*bq2*( dk12dr1[iP]*d1 + k12*dd1dr1[iP] ) - (dk22dr1[iP]*c2 + k22*dc2dr1[iP]);
+      const float_v dbdr2 = bq2*bq2*( dk12dr2[iP]*d1 + k12*dd1dr2[iP] ) - (dk22dr2[iP]*c2 + k22*dc2dr2[iP]);
+      
+      dS2dR1[0][iP](!isStraight2) = 1/bq2 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+      dS2dR2[0][iP](!isStraight2) = 1/bq2 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+    }
+    
+    a = bq2*(k12*c2 - k22*d2);
+    b = -bq2*k12*d2*bq2 - k22*c2;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = bq2*( dk12dr1[iP]*c2 + k12*dc2dr1[iP] - (dk22dr1[iP]*d1 + k22*dd1dr1[iP]) );
+      const float_v dadr2 = bq2*( dk12dr2[iP]*c2 + k12*dc2dr2[iP] - (dk22dr2[iP]*d1 + k22*dd1dr2[iP]) );
+      const float_v dbdr1 = -bq2*bq2*( dk12dr1[iP]*d1 + k12*dd1dr1[iP] ) - (dk22dr1[iP]*c2 + k22*dc2dr1[iP]);
+      const float_v dbdr2 = -bq2*bq2*( dk12dr2[iP]*d1 + k12*dd1dr2[iP] ) - (dk22dr2[iP]*c2 + k22*dc2dr2[iP]);
+      
+      dS2dR1[1][iP](!isStraight2) = 1/bq2 * 1/( b*b + a*a ) * ( dadr1*b - dbdr1*a );
+      dS2dR2[1][iP](!isStraight2) = 1/bq2 * 1/( b*b + a*a ) * ( dadr2*b - dbdr2*a );
+    }
+  }
+  if( ! ( isStraight1.isEmpty() ) )
+  {
+    dS1[0](isStraight1 && (pt12>float_v(Vc::Zero)) ) = (k11*c1 + k21*d1)/(- k21*c1);
+    dS1[1](isStraight1 && (pt12>float_v(Vc::Zero)) ) = (k11*c1 - k21*d1)/(- k21*c1);
+    
+    float_v a = k11*c1 + k21*d1;
+    float_v b = -k21*c1;
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = ( dk11dr1[iP]*c1 + k11*dc1dr1[iP] + dk21dr1[iP]*d1 + k21*dd1dr1[iP] );
+      const float_v dadr2 = ( dk11dr2[iP]*c1 + k11*dc1dr2[iP] + dk21dr2[iP]*d1 + k21*dd1dr2[iP] );
+      const float_v dbdr1 = -( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+      const float_v dbdr2 = -( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+    
+      dS1dR1[0][iP](isStraight1 && (pt12>float_v(Vc::Zero)) ) = dadr1/b - dbdr1*a/(b*b) ;
+      dS1dR2[0][iP](isStraight1 && (pt12>float_v(Vc::Zero)) ) = dadr2/b - dbdr2*a/(b*b) ;
+    }
+    
+    a = k11*c1 - k21*d1;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = ( dk11dr1[iP]*c1 + k11*dc1dr1[iP] - dk21dr1[iP]*d1 - k21*dd1dr1[iP] );
+      const float_v dadr2 = ( dk11dr2[iP]*c1 + k11*dc1dr2[iP] - dk21dr2[iP]*d1 - k21*dd1dr2[iP] );
+      const float_v dbdr1 = -( dk21dr1[iP]*c1 + k21*dc1dr1[iP] );
+      const float_v dbdr2 = -( dk21dr2[iP]*c1 + k21*dc1dr2[iP] );
+      
+      dS1dR1[1][iP](isStraight1 && (pt12>float_v(Vc::Zero)) ) = dadr1/b - dbdr1*a/(b*b) ;
+      dS1dR2[1][iP](isStraight1 && (pt12>float_v(Vc::Zero)) ) = dadr2/b - dbdr2*a/(b*b) ;
+    }
+  }
+  if( ! ( isStraight2.isEmpty() ) )
+  {
+    dS2[0](isStraight2 && (pt22>float_v(Vc::Zero)) ) = (k12*c2 + k22*d2)/(- k22*c2);
+    dS2[1](isStraight2 && (pt22>float_v(Vc::Zero)) ) = (k12*c2 - k22*d2)/(- k22*c2);  
+    
+    float_v a = k12*c2 + k22*d1;
+    float_v b = -k22*c2;
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = ( dk12dr1[iP]*c2 + k12*dc2dr1[iP] + dk22dr1[iP]*d1 + k22*dd1dr1[iP] );
+      const float_v dadr2 = ( dk12dr2[iP]*c2 + k12*dc2dr2[iP] + dk22dr2[iP]*d1 + k22*dd1dr2[iP] );
+      const float_v dbdr1 = -( dk22dr1[iP]*c2 + k22*dc2dr1[iP] );
+      const float_v dbdr2 = -( dk22dr2[iP]*c2 + k22*dc2dr2[iP] );
+    
+      dS2dR1[0][iP](isStraight2 && (pt22>float_v(Vc::Zero)) ) = dadr1/b - dbdr1*a/(b*b) ;
+      dS2dR2[0][iP](isStraight2 && (pt22>float_v(Vc::Zero)) ) = dadr2/b - dbdr2*a/(b*b) ;
+    }
+    
+    a = k12*c2 - k22*d1;
+    for(int iP=0; iP<6; iP++)
+    {
+      const float_v dadr1 = ( dk12dr1[iP]*c2 + k12*dc2dr1[iP] - dk22dr1[iP]*d1 - k22*dd1dr1[iP] );
+      const float_v dadr2 = ( dk12dr2[iP]*c2 + k12*dc2dr2[iP] - dk22dr2[iP]*d1 - k22*dd1dr2[iP] );
+      const float_v dbdr1 = -( dk22dr1[iP]*c2 + k22*dc2dr1[iP] );
+      const float_v dbdr2 = -( dk22dr2[iP]*c2 + k22*dc2dr2[iP] );
+    
+      dS2dR1[1][iP](isStraight2 && (pt22>float_v(Vc::Zero)) ) = dadr1/b - dbdr1*a/(b*b) ;
+      dS2dR2[1][iP](isStraight2 && (pt22>float_v(Vc::Zero)) ) = dadr2/b - dbdr2*a/(b*b) ;
+    }
+  }
+  
+  //select a point which is close to the primary vertex (with the smallest r)
+  
+  float_v dr2[2];
+  for(int iP = 0; iP<2; iP++)
+  {
+    const float_v& bs1 = bq1*dS1[iP];
+    const float_v& bs2 = bq2*dS2[iP];
+    float_v sss = sin(bs1), ccc = cos(bs1);
+    
+    const float_m& bs1Big = abs(bs1) > 1.e-8f;
+    const float_m& bs2Big = abs(bs2) > 1.e-8f;
+    
+    float_v sB(Vc::Zero), cB(Vc::Zero);
+    sB(bs1Big) = sss/bq1;
+    sB(!bs1Big) = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS1[iP]);
+    cB(bs1Big) = (1.f-ccc)/bq1;
+    cB(!bs1Big) = .5f*sB*bs1;
+  
+    const float_v& x1 = param1[0] + sB*px1 + cB*py1;
+    const float_v& y1 = param1[1] - cB*px1 + sB*py1;
+    const float_v& z1 = param1[2] + dS1[iP]*param1[5];
+
+    sss = sin(bs2); ccc = cos(bs2);
+
+    sB(bs2Big) = sss/bq2;
+    sB(!bs2Big) = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS2[iP]);
+    cB(bs2Big) = (1.f-ccc)/bq2;
+    cB(!bs2Big) = .5f*sB*bs2;
+
+    const float_v& x2 = param2[0] + sB*px2 + cB*py2;
+    const float_v& y2 = param2[1] - cB*px2 + sB*py2;
+    const float_v& z2 = param2[2] + dS2[iP]*param2[5];
+
+    float_v dx = (x1-x2);
+    float_v dy = (y1-y2);
+    float_v dz = (z1-z2);
+    
+    dr2[iP] = dx*dx + dy*dy + dz*dz;
+  }
+  
+  float_v pointParam[2][8];
+  float_v pointCov[2][36];
+  
+  float_v dsdrM1[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  for(int iP=0; iP<6; iP++)
+    dsdrM1[iP] = (dS1dR1[0][iP] + dS1dR1[1][iP])/2.f;
+  Transport((dS1[0] + dS1[1]) / 2.f, dsdrM1, pointParam[0], pointCov[0]);
+  float_v dsdrM2[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  for(int iP=0; iP<6; iP++)
+    dsdrM2[iP] = (dS2dR2[0][iP] + dS2dR2[1][iP])/2.f;
+  p.Transport((dS2[0] + dS2[1]) / 2.f, dsdrM2, pointParam[1], pointCov[1]);
+  
+  const float_v drPoint[3] = { pointParam[0][0] - pointParam[1][0], pointParam[0][1] - pointParam[1][1], pointParam[0][2] - pointParam[1][2] } ;
+  const float_v covPoint[6] = { pointCov[0][0] + pointCov[1][0],
+                                pointCov[0][1] + pointCov[1][1],
+                                pointCov[0][2] + pointCov[1][2],
+                                pointCov[0][3] + pointCov[1][3],
+                                pointCov[0][4] + pointCov[1][4],
+                                pointCov[0][5] + pointCov[1][5]  };
+  float_v dr2Points = drPoint[0]*drPoint[0] + drPoint[1]*drPoint[1] + drPoint[2]*drPoint[2];
+  float_v dr2PointCov = drPoint[0]*drPoint[0]*covPoint[0] + drPoint[1]*drPoint[1]*covPoint[2] + drPoint[2]*drPoint[2]*covPoint[5] +
+                        2.f*( drPoint[0]*drPoint[1]*covPoint[1] + drPoint[0]*drPoint[2]*covPoint[3] + drPoint[1]*drPoint[2]*covPoint[4] );
+  const float_m isMiddlePoint = (dr2Points*dr2Points < 25.f*dr2PointCov);// && (abs(fPDG)==int_v(11)) && (abs(p.fPDG)==int_v(11));
+  const float_m isFirstRoot = (dr2[0] < dr2[1]) & (!isMiddlePoint);
+  
+ // if(!(isFirstRoot.isEmpty()))
+  {
+    dS[0](isFirstRoot)  = dS1[0];
+    dS[1](isFirstRoot) = dS2[0];
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      dsdr[0][iP](isFirstRoot) = dS1dR1[0][iP];
+      dsdr[1][iP](isFirstRoot) = dS1dR2[0][iP];
+      dsdr[2][iP](isFirstRoot) = dS2dR1[0][iP];
+      dsdr[3][iP](isFirstRoot) = dS2dR2[0][iP];
+    }
+  }
+ // if( !( (!isFirstRoot).isEmpty() ) )
+  {
+    dS[0](!isFirstRoot)  = dS1[1];
+    dS[1](!isFirstRoot) = dS2[1];    
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      dsdr[0][iP](!isFirstRoot) = dS1dR1[1][iP];
+      dsdr[1][iP](!isFirstRoot) = dS1dR2[1][iP];
+      dsdr[2][iP](!isFirstRoot) = dS2dR1[1][iP];      
+      dsdr[3][iP](!isFirstRoot) = dS2dR2[1][iP];
+    }    
+  }
+ // if(!(isMiddlePoint.isEmpty()))
+  {
+    dS[0](isMiddlePoint) = (dS1[0] + dS1[1]) / 2.f;
+    dS[1](isMiddlePoint) = (dS2[0] + dS2[1]) / 2.f;
+    
+    for(int iP=0; iP<6; iP++)
+    {
+      dsdr[0][iP](isMiddlePoint) = (dS1dR1[1][iP] + dS1dR1[0][iP])/2.f;
+      dsdr[1][iP](isMiddlePoint) = (dS1dR2[1][iP] + dS1dR2[0][iP])/2.f;
+      dsdr[2][iP](isMiddlePoint) = (dS2dR1[1][iP] + dS2dR1[0][iP])/2.f;      
+      dsdr[3][iP](isMiddlePoint) = (dS2dR2[1][iP] + dS2dR2[0][iP])/2.f;
+    }  
+  }
+        
+  //find correct parts of helices
+  int_v n1(Vc::Zero);
+  int_v n2(Vc::Zero);
+//  float_v dzMin = abs( (z01-z02) + dS[0]*pz1 - dS[1]*pz2 );
+  const float_v pi2(6.283185307f);
+  
+//   //TODO optimise for loops for neutral particles
+//   const float_v& i1Float = -bq1/pi2*(z01/pz1+dS[0]);
+//   for(int di1=-1; di1<=1; di1++)
+//   {
+//     int_v i1(Vc::Zero);
+//     i1(int_m(!isStraight1)) = int_v(i1Float) + di1;
+//     
+//     const float_v& i2Float = ( ((z01-z02) + (dS[0]+pi2*i1/bq1)*pz1)/pz2 - dS[1]) * bq2/pi2;
+//     for(int di2 = -1; di2<=1; di2++)
+//     {
+//       int_v i2(Vc::Zero);
+//       i2(int_m(!isStraight2)) = int_v(i2Float) + di2;
+//       
+//       const float_v& z1 = z01 + (dS[0]+pi2*i1/bq1)*pz1;
+//       const float_v& z2 = z02 + (dS[1]+pi2*i2/bq2)*pz2;
+//       const float_v& dz = abs( z1-z2 );
+//     
+//       n1(int_m(dz < dzMin)) = i1;
+//       n2(int_m(dz < dzMin)) = i2;
+//       dzMin(dz < dzMin) = dz;
+//     }
+//   }
+// 
+//   dS[0](!isStraight1) += float_v(n1)*pi2/bq1;
+//   dS[1](!isStraight2) += float_v(n2)*pi2/bq2;
+
+  //add a correction on z-coordinate
+#if 0
+  {
+    const float_v& bs1 = bq1*dS[0];
+    const float_v& bs2 = bq2*dS[1];
+    
+    float_v sss = KFPMath::Sin(bs1), ccc = KFPMath::Cos(bs1);
+    const float_v& xr1 = sss*px1 - ccc*py1;
+    const float_v& yr1 = ccc*px1 + sss*py1;
+
+    float_v sss1 = KFPMath::Sin(bs2), ccc1 = KFPMath::Cos(bs2);
+    const float_v& xr2 = sss1*px2 - ccc1*py2;
+    const float_v& yr2 = ccc1*px2 + sss1*py2;
+    
+    const float_v& br = xr1*xr2 + yr1*yr2;
+    const float_v& dx0mod = dx0*bq1*bq2 + py1*bq2 - py2*bq1;
+    const float_v& dy0mod = dy0*bq1*bq2 - px1*bq2 + px2*bq1;
+    const float_v& ar1 = dx0mod*xr1 + dy0mod*yr1;
+    const float_v& ar2 = dx0mod*xr2 + dy0mod*yr2;
+    const float_v& cz = (z01 - z02) + dS[0]*pz1 - dS[1]*pz2;
+    
+    float_v kz11 =  - ar1 + bq1*br + bq2*pz1*pz1;
+    float_v kz12 =  -bq2*(br+pz1*pz2);
+    float_v kz21 =   bq1*(br+pz1*pz2);
+    float_v kz22 =  - ar2 - bq2*br - bq1*pz2*pz2;
+    
+    kz11(isStraight2) = pz1*pz1 + (px1*px1+py1*py1)*ccc + bq1*( (px2*dS[1] - dx0)*xr1 + (py2*dS[1] - dy0)*yr1 );
+    kz12(isStraight2) = -(br + pz1*pz2);
+    kz21(isStraight1) = (br + pz1*pz2);
+    kz22(isStraight1) = -pz2*pz2 - (px2*px2+py2*py2)*ccc1 - bq2*( (px1*dS[0] + dx0)*xr2 + (py1*dS[0] + dy0)*yr2 );
+
+    const float_v& delta = kz11*kz22 - kz12*kz21;
+    float_v sz1(Vc::Zero);
+    float_v sz2(Vc::Zero);
+    
+    {
+      float_v aaa1 = -cz*(pz1*bq2*kz22 - pz2*bq1*kz12);
+      float_v aaa2 = -cz*(pz2*bq1*kz11 - pz1*bq2*kz21);
+      
+      aaa1(isStraight2) = -cz*(pz1*kz22 - pz2*bq1*kz12);
+      aaa2(isStraight2) = -cz*(pz2*bq1*kz11 - pz1*kz21);
+
+      aaa1(isStraight1) = -cz*(pz1*bq2*kz22 - pz2*kz12);
+      aaa2(isStraight1) = -cz*(pz2*kz11 - pz1*bq2*kz21);
+      
+      sz1( abs(delta) > 1.e-16f ) = aaa1 / delta;
+      sz2( abs(delta) > 1.e-16f ) = aaa2 / delta;
+      
+      float_v dkz11dr1[6] = {-(bq1*bq2*xr1), -(bq1*bq2*yr1), 0.f, 
+                                   -ccc*dy0mod - dx0mod*sss + bq2*yr1 + bq1*(sss*xr2 + ccc*yr2), 
+                                    ccc*dx0mod - dy0mod*sss - bq2*xr1 + bq1*(-ccc*xr2 + sss*yr2), 2.f*bq2*pz1};
+              dkz11dr1[0](isStraight2) = -bq1*xr1;
+              dkz11dr1[1](isStraight2) = -bq1*yr1;
+              dkz11dr1[3](isStraight2) = 2.f*ccc*px1 + bq1*(sss*(dS[1]*px2 - x01 + x02) + ccc*(dS[1]*py2 - y01 + y02));
+              dkz11dr1[4](isStraight2) = 2.f*ccc*py1 + bq1*(-(ccc*(dS[1]*px2 - x01 + x02)) + sss*(dS[1]*py2 - y01 + y02));
+              dkz11dr1[5](isStraight2) = 2.f*pz1;
+      float_v dkz11dr2[6] = {bq1*bq2*xr1, bq1*bq2*yr1, 0.f, -bq1*yr1 + bq1*(sss1*xr1 + ccc1*yr1), bq1*xr1 + bq1*(-ccc1*xr1 + sss1*yr1), 0.f};
+              dkz11dr2[0](isStraight2) = bq1*xr1;
+              dkz11dr2[1](isStraight2) = bq1*yr1;
+              dkz11dr2[3](isStraight2) = bq1*dS[1]*xr1;
+              dkz11dr2[4](isStraight2) = bq1*dS[1]*yr1;
+
+      float_v dkz12dr1[6] = {0.f, 0.f, 0.f, -bq2*(sss*xr2 + ccc*yr2), -bq2*(-ccc*xr2 + sss*yr2), -bq2*pz2};
+              dkz12dr1[3](isStraight2) = -(sss*xr2 + ccc*yr2);
+              dkz12dr1[4](isStraight2) = -(-ccc*xr2 + sss*yr2);
+              dkz12dr1[5](isStraight2) = -pz2;
+      float_v dkz12dr2[6] = {0.f, 0.f, 0.f, -bq2*(sss1*xr1 + ccc1*yr1), -bq2*(-ccc1*xr1 + sss1*yr1), -bq2*pz1};
+              dkz12dr2[3](isStraight2) = -(sss1*xr1 + ccc1*yr1);
+              dkz12dr2[4](isStraight2) = -(-ccc1*xr1 + sss1*yr1);
+              dkz12dr2[5](isStraight2) = -pz1;
+      float_v dkz21dr1[6] = {0.f, 0.f, 0.f, bq1*(sss*xr2 + ccc*yr2), bq1*(-ccc*xr2 + sss*yr2), bq1*pz2};
+              dkz21dr1[3](isStraight1) = yr2;
+              dkz21dr1[4](isStraight1) = -xr2;
+              dkz21dr1[5](isStraight1) =  pz2;
+      float_v dkz21dr2[6] = {0.f, 0.f, 0.f, bq1*(sss1*xr1 + ccc1*yr1), bq1*(-ccc1*xr1 + sss1*yr1), bq1*pz1};
+              dkz21dr2[3](isStraight1) = (sss1*xr1 + ccc1*yr1);
+              dkz21dr2[4](isStraight1) = (-ccc1*xr1 + sss1*yr1);
+              dkz21dr2[5](isStraight1) = pz1;
+      float_v dkz22dr1[6] = {-bq1*bq2*xr2, -bq1*bq2*yr2, 0.f, bq2*yr2 - bq2*(sss*xr2 + ccc*yr2), -bq2*xr2 - bq2*(-ccc*xr2 + sss*yr2), 0.f};
+              dkz22dr1[0](isStraight1) = -(bq2*xr2);
+              dkz22dr1[1](isStraight1) = -(bq2*yr2);
+              dkz22dr1[3](isStraight1) = -(bq2*dS[0]*xr2);
+              dkz22dr1[4](isStraight1) = -(bq2*dS[0]*yr2);
+      float_v dkz22dr2[6] = {bq1*bq2*xr2, bq1*bq2*yr2, 0.f, 
+                             -ccc1*dy0mod - dx0mod*sss1 - bq2*(sss1*xr1 + ccc1*yr1) - bq1*yr2, 
+                              ccc1*dx0mod - dy0mod*sss1 + bq1*xr2 - bq2*(-ccc1*xr1 + sss1*yr1), -2.f*bq1*pz2};
+              dkz22dr2[0](isStraight1) = bq2*xr2;
+              dkz22dr2[1](isStraight1) = bq2*yr2;
+              dkz22dr2[3](isStraight1) = -2.f*ccc1*px2 - bq2*(ccc1*(dy0 + dS[0]*py1) + (dx0 + dS[0]*px1)*sss1);
+              dkz22dr2[4](isStraight1) = -2.f*ccc1*py2 - bq2*(-(ccc1*(dx0 + dS[0]*px1)) + (dy0 + dS[0]*py1)*sss1);
+              dkz22dr2[5](isStraight1) = -2.f*pz2;
+      
+      float_v dczdr1[6] = {0.f, 0.f, 1.f, 0.f, 0.f, dS[0]};
+      float_v dczdr2[6] = {0.f, 0.f, -1.f, 0.f, 0.f, -dS[1]};
+      
+      float_v daaa1dr1[6];
+      float_v daaa1dr2[6];
+      float_v daaa2dr2[6];
+      float_v daaa2dr1[6];
+      float_v dDeltadr1[6];
+      float_v dDeltadr2[6];
+      for(int iP=0; iP<6; iP++)
+      {
+        daaa1dr1[iP] = -( dczdr1[iP]*(pz1*bq2*kz22 - pz2*bq1*kz12) + cz*( bq2*pz1*dkz22dr1[iP] - bq1*pz2*dkz12dr1[iP] ) );
+        daaa1dr2[iP] = -( dczdr2[iP]*(pz1*bq2*kz22 - pz2*bq1*kz12) + cz*( bq2*pz1*dkz22dr2[iP] - bq1*pz2*dkz12dr2[iP] ) );
+
+        daaa2dr2[iP] = -( dczdr2[iP]*(pz2*bq1*kz11 - pz1*bq2*kz21) + cz*( bq1*pz2*dkz11dr2[iP] - bq2*pz1*dkz21dr2[iP] ) );
+        daaa2dr1[iP] = -( dczdr1[iP]*(pz2*bq1*kz11 - pz1*bq2*kz21) + cz*( bq1*pz2*dkz11dr1[iP] - bq2*pz1*dkz21dr1[iP] ) );
+        
+        dDeltadr1[iP] = kz11*dkz22dr1[iP] + dkz11dr1[iP]*kz11 - kz12*dkz21dr1[iP] - dkz12dr1[iP]*kz21;
+        dDeltadr2[iP] = kz11*dkz22dr2[iP] + dkz11dr2[iP]*kz11 - kz12*dkz21dr2[iP] - dkz12dr2[iP]*kz21;
+      }
+      daaa1dr1[5] -= cz*bq2*kz22;
+      daaa1dr2[5] += cz*bq1*kz12;
+      daaa2dr2[5] -= cz*bq1*kz11;
+      daaa2dr1[5] += cz*bq2*kz21;
+      
+      //derivatives by s0 and s1
+      float_v dkz11ds0 = bq1*(dy0mod*xr1 - dx0mod*yr1 +  bq1*(xr2*yr1 - xr1*yr2));
+      dkz11ds0(isStraight2) = -(bq1*(px1*px1 + py1*py1)*sss) + bq1*(bq1*yr1*(dS[1]*px2 - x01 + x02) -bq1*xr1*(dS[1]*py2 - y01 + y02));
+      float_v dkz11ds1 = bq1*bq2*( xr1*yr2 - xr2*yr1 );
+      dkz11ds1(isStraight2) = bq1*(px2*xr1 + py2*yr1);
+      float_v dkz12ds0 = bq2*bq1*( xr1*yr2 - xr2*yr1 );
+      dkz12ds0(isStraight2) = bq1*( xr1*yr2 - xr2*yr1 );
+      float_v dkz12ds1 = bq2*bq2*( xr2*yr1 - xr1*yr2 );
+      dkz12ds1(isStraight2) = 0;
+      float_v dkz21ds0 = bq1*bq1*( xr2*yr1 - xr1*yr2 );
+      dkz21ds0(isStraight1) = 0.f;
+      float_v dkz21ds1 = bq1*bq2*( xr1*yr2 - xr2*yr1 );
+      dkz21ds1(isStraight1) = px1*(bq2*ccc1*py2 - bq2*px2*sss1) - py1*(bq2*ccc1*px2 + bq2*py2*sss1);
+      float_v dkz22ds0 = bq1*bq2*( xr1*yr2 - xr2*yr1 );      
+      dkz22ds0(isStraight1) = -bq2*(px1*xr2 + py1*yr2);
+      float_v dkz22ds1 = -bq2*( dy0mod*xr2 - dx0mod*yr2 - bq2*(xr2*yr1 - xr1*yr2) );
+      dkz22ds1(isStraight1) = bq2*(px2*px2 + py2*py2)*sss1 - bq2*((dy0 + dS[0]*py1)*(bq2*ccc1*py2 - bq2*px2*sss1) + (dx0 + dS[0]*px1)*(bq2*ccc1*px2 + bq2*py2*sss1));
+      const float_v dczds0   = pz1;
+      const float_v dczds1   = -pz2;
+      const float_v da1ds0   = -( dczds0*(pz1*bq2*kz22 - pz2*bq1*kz12) + cz*(pz1*bq2*dkz22ds0 - pz2*bq1*dkz12ds0));
+      const float_v da1ds1   = -( dczds1*(pz1*bq2*kz22 - pz2*bq1*kz12) + cz*(pz1*bq2*dkz22ds1 - pz2*bq1*dkz12ds1));
+      const float_v da2ds0   = -( dczds0*(pz2*bq1*kz11 - pz1*bq2*kz21) + cz*(pz2*bq1*dkz11ds0 - pz1*bq2*dkz21ds0));
+      const float_v da2ds1   = -( dczds1*(pz2*bq1*kz11 - pz1*bq2*kz21) + cz*(pz2*bq1*dkz11ds1 - pz1*bq2*dkz21ds1));
+      const float_v dDeltads0 = kz11*dkz22ds0 + dkz11ds0*kz11 - kz12*dkz21ds0 - dkz12ds0*kz21;
+      const float_v dDeltads1 = kz11*dkz22ds1 + dkz11ds1*kz11 - kz12*dkz21ds1 - dkz12ds1*kz21;
+      
+      const float_v dsz1ds0 = da1ds0/delta - aaa1*dDeltads0/(delta*delta);
+      const float_v dsz1ds1 = da1ds1/delta - aaa1*dDeltads1/(delta*delta);
+      const float_v dsz2ds0 = da2ds0/delta - aaa2*dDeltads0/(delta*delta);
+      const float_v dsz2ds1 = da2ds1/delta - aaa2*dDeltads1/(delta*delta);
+      
+      float_v dszdr[4][6];
+      for(int iP=0; iP<6; iP++)
+      {
+        dszdr[0][iP] = dsz1ds0*dsdr[0][iP] + dsz1ds1*dsdr[2][iP];
+        dszdr[1][iP] = dsz1ds0*dsdr[1][iP] + dsz1ds1*dsdr[3][iP];
+        dszdr[2][iP] = dsz2ds0*dsdr[0][iP] + dsz2ds1*dsdr[2][iP];
+        dszdr[3][iP] = dsz2ds0*dsdr[1][iP] + dsz2ds1*dsdr[3][iP];
+      }
+      
+      for(int iP=0; iP<6; iP++)
+      {
+        dsdr[0][iP]( abs(delta) > 1.e-16f ) += daaa1dr1[iP]/delta - aaa1*dDeltadr1[iP]/(delta*delta) + dszdr[0][iP];
+        dsdr[1][iP]( abs(delta) > 1.e-16f ) += daaa1dr2[iP]/delta - aaa1*dDeltadr2[iP]/(delta*delta) + dszdr[1][iP];
+        dsdr[2][iP]( abs(delta) > 1.e-16f ) += daaa2dr1[iP]/delta - aaa2*dDeltadr1[iP]/(delta*delta) + dszdr[2][iP];
+        dsdr[3][iP]( abs(delta) > 1.e-16f ) += daaa2dr2[iP]/delta - aaa2*dDeltadr2[iP]/(delta*delta) + dszdr[3][iP];
+      }
+    }
+
+    dS[0] += sz1;
+    dS[1] += sz2;
+  }
+#endif
+
+  //Line correction
+  {
+    const float_v& bs1 = bq1*dS[0];
+    const float_v& bs2 = bq2*dS[1];
+    float_v sss = sin(bs1), ccc = cos(bs1);
+    
+    const float_m& bs1Big = abs(bs1) > 1.e-8f;
+    const float_m& bs2Big = abs(bs2) > 1.e-8f;
+    
+    float_v sB(0.f), cB(0.f);
+    sB(bs1Big) = sss/bq1;
+    cB(bs1Big) = (1.f-ccc)/bq1;
+    sB(!bs1Big) = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS[0]);
+    cB(!bs1Big) = .5f*sB*bs1;
+  
+    const float_v& x1 = x01 + sB*px1 + cB*py1;
+    const float_v& y1 = y01 - cB*px1 + sB*py1;
+    const float_v& z1 = z01 + dS[0]*pz1;
+    const float_v& ppx1 =  ccc*px1 + sss*py1;
+    const float_v& ppy1 = -sss*px1 + ccc*py1;
+    const float_v& ppz1 = pz1;
+    
+    float_v sss1 = sin(bs2), ccc1 = cos(bs2);
+
+    float_v sB1(0.f), cB1(0.f);
+    sB1(bs2Big) = sss1/bq2;
+    cB1(bs2Big) = (1.f-ccc1)/bq2;
+    sB1(!bs2Big) = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS[1]);
+    cB1(!bs2Big) = .5f*sB1*bs2;
+
+    const float_v& x2 = x02 + sB1*px2 + cB1*py2;
+    const float_v& y2 = y02 - cB1*px2 + sB1*py2;
+    const float_v& z2 = z02 + dS[1]*pz2;
+    const float_v& ppx2 =  ccc1*px2 + sss1*py2;
+    const float_v& ppy2 = -sss1*px2 + ccc1*py2;    
+    const float_v& ppz2 = pz2;
+
+    const float_v& p12  = ppx1*ppx1 + ppy1*ppy1 + ppz1*ppz1;
+    const float_v& p22  = ppx2*ppx2 + ppy2*ppy2 + ppz2*ppz2;
+    const float_v& lp1p2 = ppx1*ppx2 + ppy1*ppy2 + ppz1*ppz2;
+
+    const float_v& dx = (x2 - x1);
+    const float_v& dy = (y2 - y1);
+    const float_v& dz = (z2 - z1);
+    
+    const float_v& ldrp1 = ppx1*dx + ppy1*dy + ppz1*dz;
+    const float_v& ldrp2 = ppx2*dx + ppy2*dy + ppz2*dz;
+
+    float_v detp =  lp1p2*lp1p2 - p12*p22;
+    detp(abs(detp)<1.e-4f) = 1; //TODO correct!!!
+    
+    //dsdr calculation
+    const float_v a1 = ldrp2*lp1p2 - ldrp1*p22;
+    const float_v a2 = ldrp2*p12 - ldrp1*lp1p2;
+    const float_v lp1p2_ds0 = bq1*( ppx2*ppy1 - ppy2*ppx1);
+    const float_v lp1p2_ds1 = bq2*( ppx1*ppy2 - ppy1*ppx2);
+    const float_v ldrp1_ds0 = -p12 + bq1*(ppy1*dx - ppx1*dy);
+    const float_v ldrp1_ds1 =  lp1p2;
+    const float_v ldrp2_ds0 = -lp1p2;
+    const float_v ldrp2_ds1 =  p22 + bq2*(ppy2*dx - ppx2*dy);
+    const float_v detp_ds0 = 2.f*lp1p2*lp1p2_ds0;
+    const float_v detp_ds1 = 2.f*lp1p2*lp1p2_ds1;
+    const float_v a1_ds0 = ldrp2_ds0*lp1p2 + ldrp2*lp1p2_ds0 - ldrp1_ds0*p22;
+    const float_v a1_ds1 = ldrp2_ds1*lp1p2 + ldrp2*lp1p2_ds1 - ldrp1_ds1*p22;
+    const float_v a2_ds0 = ldrp2_ds0*p12 - ldrp1_ds0*lp1p2 - ldrp1*lp1p2_ds0;
+    const float_v a2_ds1 = ldrp2_ds1*p12 - ldrp1_ds1*lp1p2 - ldrp1*lp1p2_ds1;
+    
+    const float_v dsl1ds0 = a1_ds0/detp - a1*detp_ds0/(detp*detp);
+    const float_v dsl1ds1 = a1_ds1/detp - a1*detp_ds1/(detp*detp);
+    const float_v dsl2ds0 = a2_ds0/detp - a2*detp_ds0/(detp*detp);
+    const float_v dsl2ds1 = a2_ds1/detp - a2*detp_ds1/(detp*detp);
+    
+    float_v dsldr[4][6];
+    for(int iP=0; iP<6; iP++)
+    {
+      dsldr[0][iP] = dsl1ds0*dsdr[0][iP] + dsl1ds1*dsdr[2][iP];
+      dsldr[1][iP] = dsl1ds0*dsdr[1][iP] + dsl1ds1*dsdr[3][iP];
+      dsldr[2][iP] = dsl2ds0*dsdr[0][iP] + dsl2ds1*dsdr[2][iP];
+      dsldr[3][iP] = dsl2ds0*dsdr[1][iP] + dsl2ds1*dsdr[3][iP];
+    }
+    
+    for(int iDS=0; iDS<4; iDS++)
+      for(int iP=0; iP<6; iP++)
+        dsdr[iDS][iP] += dsldr[iDS][iP];
+      
+    const float_v lp1p2_dr0[6] = {0.f, 0.f, 0.f, ccc*ppx2 - ppy2*sss, ccc*ppy2 + ppx2*sss, pz2};
+    const float_v lp1p2_dr1[6] = {0.f, 0.f, 0.f, ccc1*ppx1 - ppy1*sss1, ccc1*ppy1 + ppx1*sss1, pz1};
+    const float_v ldrp1_dr0[6] = {-ppx1, -ppy1, -pz1,  cB*ppy1 - ppx1*sB + ccc*dx - sss*dy, -cB*ppx1-ppy1*sB + sss*dx + ccc*dy, -dS[0]*pz1 + dz};
+    const float_v ldrp1_dr1[6] = { ppx1,  ppy1,  pz1, -cB1*ppy1 + ppx1*sB1, cB1*ppx1 + ppy1*sB1, dS[1]*pz1};
+    const float_v ldrp2_dr0[6] = {-ppx2, -ppy2, -pz2, cB*ppy2 - ppx2*sB, -cB*ppx2-ppy2*sB, -dS[0]*pz2};
+    const float_v ldrp2_dr1[6] = { ppx2, ppy2, pz2, -cB1*ppy2 + ppx2*sB1 + ccc1*dx- sss1*dy, cB1*ppx2 + ppy2*sB1 + sss1*dx + ccc1*dy, dz + dS[1]*pz2};
+    const float_v p12_dr0[6] = {0.f, 0.f, 0.f, 2.f*px1, 2.f*py1, 2.f*pz1};
+    const float_v p22_dr1[6] = {0.f, 0.f, 0.f, 2.f*px2, 2.f*py2, 2.f*pz2};
+    float_v a1_dr0[6], a1_dr1[6], a2_dr0[6], a2_dr1[6], detp_dr0[6], detp_dr1[6];
+    for(int iP=0; iP<6; iP++)
+    {
+      a1_dr0[iP] = ldrp2_dr0[iP]*lp1p2 + ldrp2*lp1p2_dr0[iP] - ldrp1_dr0[iP]*p22;
+      a1_dr1[iP] = ldrp2_dr1[iP]*lp1p2 + ldrp2*lp1p2_dr1[iP] - ldrp1_dr1[iP]*p22 - ldrp1*p22_dr1[iP];
+      a2_dr0[iP] = ldrp2_dr0[iP]*p12 + ldrp2*p12_dr0[iP] - ldrp1_dr0[iP]*lp1p2 - ldrp1*lp1p2_dr0[iP];
+      a2_dr1[iP] = ldrp2_dr1[iP]*p12 - ldrp1_dr1[iP]*lp1p2 - ldrp1*lp1p2_dr1[iP];
+      detp_dr0[iP] = 2.f*lp1p2*lp1p2_dr0[iP] - p12_dr0[iP]*p22;
+      detp_dr1[iP] = 2.f*lp1p2*lp1p2_dr1[iP] - p12*p22_dr1[iP];
+      
+      dsdr[0][iP] += a1_dr0[iP]/detp - a1*detp_dr0[iP]/(detp*detp);
+      dsdr[1][iP] += a1_dr1[iP]/detp - a1*detp_dr1[iP]/(detp*detp);
+      dsdr[2][iP] += a2_dr0[iP]/detp - a2*detp_dr0[iP]/(detp*detp);
+      dsdr[3][iP] += a2_dr1[iP]/detp - a2*detp_dr1[iP]/(detp*detp);
+    }
+    
+    dS[0] += (ldrp2*lp1p2 - ldrp1*p22) /detp;
+    dS[1] += (ldrp2*p12 - ldrp1*lp1p2)/detp;    
+  }
+}
+
+void KFParticleBaseSIMD::GetDStoParticleBz( float_v B, const KFParticleBaseSIMD &p, 
+                                            float_v dS[2], const float_v* param1, const float_v* param2 ) const
+{ 
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field Bz. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Parameters param1 and param2 should be either provided both or both set to null pointers.
+   ** \param[in] B - magnetic field Bz
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[in] param1 - optional parameter, is used in case if the parameters of the current particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise fP are used
+   ** \param[in] param2 - optional parameter, is used in case if the parameters of the second particles are rotated
+   ** to other coordinate system (see GetDStoParticleBy() function), otherwise p.fP are used
+   **/
+  
+  if(!param1)
+  {
+    param1 = fP;
+    param2 = p.fP;
+  }
+
+  //* Get dS to another particle for Bz field
+  const float_v kOvSqr6 = 1.f/sqrt(float_v(6.f));
+  const float_v kCLight = 0.000299792458f;
+
+  //in XY plane
+  //first root    
+  const float_v& bq1 = B*simd_cast<float_v>(fQ)*kCLight;
+  const float_v& bq2 = B*simd_cast<float_v>(p.fQ)*kCLight;
+
+  const float_m& isStraight1 = abs(bq1) < float_v(1.e-8f);
+  const float_m& isStraight2 = abs(bq2) < float_v(1.e-8f);
+  
+  if( isStraight1.isFull() && isStraight2.isFull() )
+  {
+    GetDStoParticleLine(p, dS);
+    return;
+  }
+    
+  const float_v& px1 = param1[3];
+  const float_v& py1 = param1[4];
+  const float_v& pz1 = param1[5];
+
+  const float_v& px2 = param2[3];
+  const float_v& py2 = param2[4];
+  const float_v& pz2 = param2[5];
+
+  const float_v& pt12 = px1*px1 + py1*py1;
+  const float_v& pt22 = px2*px2 + py2*py2;
+
+  const float_v& x01 = param1[0];
+  const float_v& y01 = param1[1];
+  const float_v& z01 = param1[2];
+
+  const float_v& x02 = param2[0];
+  const float_v& y02 = param2[1];
+  const float_v& z02 = param2[2];
+
+  float_v dS1[2] = {0.f, 0.f}, dS2[2]={0.f, 0.f};
+  
+  const float_v& dx0 = (x01 - x02);
+  const float_v& dy0 = (y01 - y02);
+  const float_v& dr02 = dx0*dx0 + dy0*dy0;
+  const float_v& drp1  = dx0*px1 + dy0*py1;
+  const float_v& dxyp1 = dx0*py1 - dy0*px1;
+  const float_v& drp2  = dx0*px2 + dy0*py2;
+  const float_v& dxyp2 = dx0*py2 - dy0*px2;
+  const float_v& p1p2 = px1*px2 + py1*py2;
+  const float_v& dp1p2 = px1*py2 - px2*py1;
+  
+  const float_v& k11 = (bq2*drp1 - dp1p2);
+  const float_v& k21 = (bq1*(bq2*dxyp1 - p1p2) + bq2*pt12);
+  const float_v& k12 = ((bq1*drp2 - dp1p2));
+  const float_v& k22 = (bq2*(bq1*dxyp2 + p1p2) - bq1*pt22);
+  
+  const float_v& kp = (dxyp1*bq2 - dxyp2*bq1 - p1p2);
+  const float_v& kd = dr02/2.f*bq1*bq2 + kp;
+  const float_v& c1 = -(bq1*kd + pt12*bq2);
+  const float_v& c2 = bq2*kd + pt22*bq1; 
+  
+  float_v d1 = pt12*pt22 - kd*kd;
+  d1(d1 < float_v(Vc::Zero)) = float_v(Vc::Zero);
+  d1 = sqrt( d1 );
+  float_v d2 = pt12*pt22 - kd*kd;
+  d2(d2 < float_v(Vc::Zero)) = float_v(Vc::Zero);
+  d2 = sqrt( d2 );
+
+  // find two points of closest approach in XY plane
+  if( ! ( (!isStraight1).isEmpty() ) )
+  {
+    dS1[0](!isStraight1) = KFPMath::ATan2( (bq1*k11*c1 + k21*d1*bq1), (bq1*k11*d1*bq1 - k21*c1) )/bq1;
+    dS1[1](!isStraight1) = KFPMath::ATan2( (bq1*k11*c1 - k21*d1*bq1), (-bq1*k11*d1*bq1 - k21*c1) )/bq1;    
+  }
+  if( ! ( (!isStraight2).isEmpty() ) )
+  {
+    dS2[0](!isStraight2) = KFPMath::ATan2( (bq2*k12*c2 + k22*d2*bq2), (bq2*k12*d2*bq2 - k22*c2) )/bq2;
+    dS2[1](!isStraight2) = KFPMath::ATan2( (bq2*k12*c2 - k22*d2*bq2), (-bq2*k12*d2*bq2 - k22*c2) )/bq2;
+  }
+  if( ! ( isStraight1.isEmpty() ) )
+  {
+    dS1[0](isStraight1 && (pt12>float_v(Vc::Zero)) ) = (k11*c1 + k21*d1)/(- k21*c1);
+    dS1[1](isStraight1 && (pt12>float_v(Vc::Zero)) ) = (k11*c1 - k21*d1)/(- k21*c1);
+  }
+  if( ! ( isStraight2.isEmpty() ) )
+  {
+    dS2[0](isStraight2 && (pt22>float_v(Vc::Zero)) ) = (k12*c2 + k22*d2)/(- k22*c2);
+    dS2[1](isStraight2 && (pt22>float_v(Vc::Zero)) ) = (k12*c2 - k22*d2)/(- k22*c2);      
+  }
+  
+  //select a point which is close to the primary vertex (with the smallest r)
+  
+  float_v dr2[2];
+  for(int iP = 0; iP<2; iP++)
+  {
+    const float_v& bs1 = bq1*dS1[iP];
+    const float_v& bs2 = bq2*dS2[iP];
+    float_v sss = KFPMath::Sin(bs1), ccc = KFPMath::Cos(bs1);
+    
+    const float_m& bs1Big = abs(bs1) > 1.e-8f;
+    const float_m& bs2Big = abs(bs2) > 1.e-8f;
+    
+    float_v sB(Vc::Zero), cB(Vc::Zero);
+    sB(bs1Big) = sss/bq1;
+    sB(!bs1Big) = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS1[iP]);
+    cB(bs1Big) = (1.f-ccc)/bq1;
+    cB(!bs1Big) = .5f*sB*bs1;
+  
+    const float_v& x1 = param1[0] + sB*px1 + cB*py1;
+    const float_v& y1 = param1[1] - cB*px1 + sB*py1;
+    const float_v& z1 = param1[2] + dS1[iP]*param1[5];
+
+    sss = KFPMath::Sin(bs2); ccc = KFPMath::Cos(bs2);
+
+    sB(bs2Big) = sss/bq2;
+    sB(!bs2Big) = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS2[iP]);
+    cB(bs2Big) = (1.f-ccc)/bq2;
+    cB(!bs2Big) = .5f*sB*bs2;
+
+    const float_v& x2 = param2[0] + sB*px2 + cB*py2;
+    const float_v& y2 = param2[1] - cB*px2 + sB*py2;
+    const float_v& z2 = param2[2] + dS2[iP]*param2[5];
+
+    float_v dx = (x1-x2);
+    float_v dy = (y1-y2);
+    float_v dz = (z1-z2);
+    
+    dr2[iP] = dx*dx + dy*dy + dz*dz;
+  }
+  
+  
+  const float_m isFirstRoot = (dr2[0] < dr2[1]);
+  
+ // if(!(isFirstRoot.isEmpty()))
+  {
+    dS[0](isFirstRoot)  = dS1[0];
+    dS[1](isFirstRoot) = dS2[0];    
+  }
+ // if( !( (!isFirstRoot).isEmpty() ) )
+  {
+    dS[0](!isFirstRoot)  = dS1[1];
+    dS[1](!isFirstRoot) = dS2[1];    
+  }
+        
+  //find correct parts of helices
+  int_v n1(Vc::Zero);
+  int_v n2(Vc::Zero);
+//  float_v dzMin = abs( (z01-z02) + dS[0]*pz1 - dS[1]*pz2 );
+  const float_v pi2(6.283185307f);
+  
+//   //TODO optimise for loops for neutral particles
+//   const float_v& i1Float = -bq1/pi2*(z01/pz1+dS[0]);
+//   for(int di1=-1; di1<=1; di1++)
+//   {
+//     int_v i1(Vc::Zero);
+//     i1(int_m(!isStraight1)) = int_v(i1Float) + di1;
+//     
+//     const float_v& i2Float = ( ((z01-z02) + (dS[0]+pi2*i1/bq1)*pz1)/pz2 - dS[1]) * bq2/pi2;
+//     for(int di2 = -1; di2<=1; di2++)
+//     {
+//       int_v i2(Vc::Zero);
+//       i2(int_m(!isStraight2)) = int_v(i2Float) + di2;
+//       
+//       const float_v& z1 = z01 + (dS[0]+pi2*i1/bq1)*pz1;
+//       const float_v& z2 = z02 + (dS[1]+pi2*i2/bq2)*pz2;
+//       const float_v& dz = abs( z1-z2 );
+//     
+//       n1(int_m(dz < dzMin)) = i1;
+//       n2(int_m(dz < dzMin)) = i2;
+//       dzMin(dz < dzMin) = dz;
+//     }
+//   }
+// 
+//   dS[0](!isStraight1) += float_v(n1)*pi2/bq1;
+//   dS[1](!isStraight2) += float_v(n2)*pi2/bq2;
+
+  //Line correction
+  {
+    const float_v& bs1 = bq1*dS[0];
+    const float_v& bs2 = bq2*dS[1];
+    float_v sss = KFPMath::Sin(bs1), ccc = KFPMath::Cos(bs1);
+    
+    const float_m& bs1Big = abs(bs1) > 1.e-8f;
+    const float_m& bs2Big = abs(bs2) > 1.e-8f;
+    
+    float_v sB(0.f), cB(0.f);
+    sB(bs1Big) = sss/bq1;
+    cB(bs1Big) = (1.f-ccc)/bq1;
+    sB(!bs1Big) = ((1.f-bs1*kOvSqr6)*(1.f+bs1*kOvSqr6)*dS[0]);
+    cB(!bs1Big) = .5f*sB*bs1;
+  
+    const float_v& x1 = x01 + sB*px1 + cB*py1;
+    const float_v& y1 = y01 - cB*px1 + sB*py1;
+    const float_v& z1 = z01 + dS[0]*pz1;
+    const float_v& ppx1 =  ccc*px1 + sss*py1;
+    const float_v& ppy1 = -sss*px1 + ccc*py1;
+    const float_v& ppz1 = pz1;
+    
+    float_v sss1 = KFPMath::Sin(bs2), ccc1 = KFPMath::Cos(bs2);
+
+    float_v sB1(0.f), cB1(0.f);
+    sB1(bs2Big) = sss1/bq2;
+    cB1(bs2Big) = (1.f-ccc1)/bq2;
+    sB1(!bs2Big) = ((1.f-bs2*kOvSqr6)*(1.f+bs2*kOvSqr6)*dS[1]);
+    cB1(!bs2Big) = .5f*sB1*bs2;
+
+    const float_v& x2 = x02 + sB1*px2 + cB1*py2;
+    const float_v& y2 = y02 - cB1*px2 + sB1*py2;
+    const float_v& z2 = z02 + dS[1]*pz2;
+    const float_v& ppx2 =  ccc1*px2 + sss1*py2;
+    const float_v& ppy2 = -sss1*px2 + ccc1*py2;    
+    const float_v& ppz2 = pz2;
+
+    const float_v& p12  = ppx1*ppx1 + ppy1*ppy1 + ppz1*ppz1;
+    const float_v& p22  = ppx2*ppx2 + ppy2*ppy2 + ppz2*ppz2;
+    const float_v& lp1p2 = ppx1*ppx2 + ppy1*ppy2 + ppz1*ppz2;
+
+    const float_v& dx = (x2 - x1);
+    const float_v& dy = (y2 - y1);
+    const float_v& dz = (z2 - z1);
+    
+    const float_v& ldrp1 = ppx1*dx + ppy1*dy + ppz1*dz;
+    const float_v& ldrp2 = ppx2*dx + ppy2*dy + ppz2*dz;
+
+    float_v detp =  lp1p2*lp1p2 - p12*p22;
+    detp(abs(detp)<1.e-4f) = 1; //TODO correct!!!
+    
+    dS[0] += (ldrp2*lp1p2 - ldrp1*p22) /detp;
+    dS[1] += (ldrp2*p12 - ldrp1*lp1p2)/detp;    
+  }
+}
+
+void KFParticleBaseSIMD::GetDStoParticleBy( float_v B, const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** The particle parameters are transformed to the coordinate system, where the main component of the magnetic field
+   ** By is directed along the Z axis: x->x, y->-z, z->y, and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] B - magnetic field By
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  const float_v param1[6] = { fP[0], -fP[2], fP[1], fP[3], -fP[5], fP[4] };
+  const float_v param2[6] = { p.fP[0], -p.fP[2], p.fP[1], p.fP[3], -p.fP[5], p.fP[4] };
+  
+  float_v dsdrBz[4][6];
+  for(int i1=0; i1<4; i1++)
+    for(int i2=0; i2<6; i2++)
+      dsdrBz[i1][i2] = 0.f;
+  
+  GetDStoParticleBz(B, p, dS, dsdrBz, param1, param2);
+  
+  for(int iDs=0; iDs<4; iDs++)
+  {
+    dsdr[iDs][0] =  dsdrBz[iDs][0];
+    dsdr[iDs][1] =  dsdrBz[iDs][2];
+    dsdr[iDs][2] = -dsdrBz[iDs][1];
+    dsdr[iDs][3] =  dsdrBz[iDs][3];
+    dsdr[iDs][4] =  dsdrBz[iDs][5];
+    dsdr[iDs][5] = -dsdrBz[iDs][4];
+  }
+}
+
+void KFParticleBaseSIMD::GetDStoParticleBy( float_v B, const KFParticleBaseSIMD &p, float_v dS[2] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** The particle parameters are transformed to the coordinate system, where the main component of the magnetic field
+   ** By is directed along the Z axis: x->x, y->-z, z->y, and the function GetDStoPointBz() is called. 
+   ** \param[in] B - magnetic field By
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   **/
+  
+  const float_v param1[6] = { fP[0], -fP[2], fP[1], fP[3], -fP[5], fP[4] };
+  const float_v param2[6] = { p.fP[0], -p.fP[2], p.fP[1], p.fP[3], -p.fP[5], p.fP[4] };
+  
+  GetDStoParticleBz(B, p, dS, param1, param2);
+}
+
+void KFParticleBaseSIMD::GetDStoParticleB( float_v B[3], const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** The particle parameters are transformed to the coordinate system, where the magnetic field B
+   ** is directed along the Z axis and the function GetDStoPointBz() is called. Derivatives dsdr are transformed back
+   ** to the coordinate system of the particle.
+   ** \param[in] B - magnetic field By
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  const float_v& Bx = B[0];
+  const float_v& By = B[1];
+  const float_v& Bz = B[2];
+  
+  const float_v& Bxz = sqrt(Bx*Bx + Bz*Bz);
+  const float_v& Br = sqrt(Bx*Bx + By*By + Bz*Bz);
+    
+  float_v cosA = 1.f;
+  float_v sinA = 0.f;
+
+  cosA( abs(Bxz) > 1.e-8f ) = Bz/Bxz;
+  sinA( abs(Bxz) > 1.e-8f ) = Bx/Bxz;
+  
+  const float_v& sinP = By/Br;
+  const float_v& cosP = Bxz/Br;
+
+  
+  const float_v param1[6] = { cosA*fP[0] - sinA*fP[2], 
+                             -sinA*sinP*fP[0] + cosP*fP[1] - cosA*sinP*fP[2], 
+                              cosP*sinA*fP[0] + sinP*fP[1] + cosA*cosP*fP[2],
+                              cosA*fP[3] - sinA*fP[5], 
+                             -sinA*sinP*fP[3] + cosP*fP[4] - cosA*sinP*fP[5], 
+                              cosP*sinA*fP[3] + sinP*fP[4] + cosA*cosP*fP[5]};
+  const float_v param2[6] = { cosA*p.fP[0] - sinA*p.fP[2], 
+                             -sinA*sinP*p.fP[0] + cosP*p.fP[1] - cosA*sinP*p.fP[2], 
+                              cosP*sinA*p.fP[0] + sinP*p.fP[1] + cosA*cosP*p.fP[2],
+                              cosA*p.fP[3] - sinA*p.fP[5], 
+                             -sinA*sinP*p.fP[3] + cosP*p.fP[4] - cosA*sinP*p.fP[5], 
+                              cosP*sinA*p.fP[3] + sinP*p.fP[4] + cosA*cosP*p.fP[5]};
+
+  float_v dsdrBz[4][6];
+  for(int i1=0; i1<4; i1++)
+    for(int i2=0; i2<6; i2++)
+      dsdrBz[i1][i2] = 0.f;
+    
+  GetDStoParticleBz(Br, p, dS, dsdrBz, param1, param2);
+  
+  for(int iDs=0; iDs<4; iDs++)
+  {
+    dsdr[iDs][0] =  dsdrBz[iDs][0]*cosA - dsdrBz[iDs][1]*sinA*sinP + dsdrBz[iDs][2]*sinA*cosP;
+    dsdr[iDs][1] =                        dsdrBz[iDs][1]*cosP      + dsdrBz[iDs][2]*sinP;
+    dsdr[iDs][2] = -dsdrBz[iDs][0]*sinA - dsdrBz[iDs][1]*cosA*sinP + dsdrBz[iDs][2]*cosA*cosP;
+    dsdr[iDs][3] =  dsdrBz[iDs][3]*cosA - dsdrBz[iDs][4]*sinA*sinP + dsdrBz[iDs][5]*sinA*cosP;
+    dsdr[iDs][4] =                        dsdrBz[iDs][4]*cosP      + dsdrBz[iDs][5]*sinP;
+    dsdr[iDs][5] = -dsdrBz[iDs][3]*sinA - dsdrBz[iDs][4]*cosA*sinP + dsdrBz[iDs][5]*cosA*cosP;
+  }
+}
+
+void KFParticleBaseSIMD::GetDStoParticleB( float_v B[3], const KFParticleBaseSIMD &p, float_v dS[2] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the constant homogeneous field By. dS[0] is the transport parameter for the current particle,
+   ** dS[1] - for the particle "p".
+   ** The particle parameters are transformed to the coordinate system, where the magnetic field B
+   ** is directed along the Z axis and the function GetDStoPointBz() is called.
+   ** \param[in] B - magnetic field By
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   **/
+  
+  const float_v& Bx = B[0];
+  const float_v& By = B[1];
+  const float_v& Bz = B[2];
+  
+  const float_v& Bxz = sqrt(Bx*Bx + Bz*Bz);
+  const float_v& Br = sqrt(Bx*Bx + By*By + Bz*Bz);
+    
+  float_v cosA = 1.f;
+  float_v sinA = 0.f;
+
+  cosA( abs(Bxz) > 1.e-8f ) = Bz/Bxz;
+  sinA( abs(Bxz) > 1.e-8f ) = Bx/Bxz;
+  
+  const float_v& sinP = By/Br;
+  const float_v& cosP = Bxz/Br;
+
+  
+  const float_v param1[6] = { cosA*fP[0] - sinA*fP[2], 
+                             -sinA*sinP*fP[0] + cosP*fP[1] - cosA*sinP*fP[2], 
+                              cosP*sinA*fP[0] + sinP*fP[1] + cosA*cosP*fP[2],
+                              cosA*fP[3] - sinA*fP[5], 
+                             -sinA*sinP*fP[3] + cosP*fP[4] - cosA*sinP*fP[5], 
+                              cosP*sinA*fP[3] + sinP*fP[4] + cosA*cosP*fP[5]};
+  const float_v param2[6] = { cosA*p.fP[0] - sinA*p.fP[2], 
+                             -sinA*sinP*p.fP[0] + cosP*p.fP[1] - cosA*sinP*p.fP[2], 
+                              cosP*sinA*p.fP[0] + sinP*p.fP[1] + cosA*cosP*p.fP[2],
+                              cosA*p.fP[3] - sinA*p.fP[5], 
+                             -sinA*sinP*p.fP[3] + cosP*p.fP[4] - cosA*sinP*p.fP[5], 
+                              cosP*sinA*p.fP[3] + sinP*p.fP[4] + cosA*cosP*p.fP[5]};
+
+  GetDStoParticleBz(Br, p, dS, param1, param2);
+}
+
+void KFParticleBaseSIMD::GetDStoParticleLine( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the straight line trajectory. Is used for particles with charge 0 or in case of zero magnetic field.
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  float_v p12 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5];
+  float_v p22 = p.fP[3]*p.fP[3] + p.fP[4]*p.fP[4] + p.fP[5]*p.fP[5];
+  float_v p1p2 = fP[3]*p.fP[3] + fP[4]*p.fP[4] + fP[5]*p.fP[5];
+
+  float_v drp1 = fP[3]*(p.fP[0]-fP[0]) + fP[4]*(p.fP[1]-fP[1]) + fP[5]*(p.fP[2]-fP[2]);
+  float_v drp2 = p.fP[3]*(p.fP[0]-fP[0]) + p.fP[4]*(p.fP[1]-fP[1]) + p.fP[5]*(p.fP[2]-fP[2]);
+
+  float_v detp =  p1p2*p1p2 - p12*p22;
+  detp( abs(detp)<float_v(1.e-4f) ) = float_v(1.f); //TODO correct!!!
+
+  dS[0]  = (drp2*p1p2 - drp1*p22) /detp;
+  dS[1] = (drp2*p12  - drp1*p1p2)/detp;
+  
+  const float_v x01 = fP[0];
+  const float_v y01 = fP[1];
+  const float_v z01 = fP[2];
+  const float_v px1 = fP[3];
+  const float_v py1 = fP[4];
+  const float_v pz1 = fP[5];
+
+  const float_v x02 = p.fP[0];
+  const float_v y02 = p.fP[1];
+  const float_v z02 = p.fP[2];
+  const float_v px2 = p.fP[3];
+  const float_v py2 = p.fP[4];
+  const float_v pz2 = p.fP[5];
+  
+  const float_v drp1_dr1[6]  = {-px1, -py1, -pz1, -x01 + x02, -y01 + y02, -z01 + z02};
+  const float_v drp1_dr2[6]  = {px1, py1, pz1, 0.f, 0.f, 0.f};
+  const float_v drp2_dr1[6]  = {-px2, -py2, -pz2, 0.f, 0.f, 0.f};
+  const float_v drp2_dr2[6]  = {px2, py2, pz2, -x01 + x02, -y01 + y02, -z01 + z02};
+  const float_v dp1p2_dr1[6] = {0.f, 0.f, 0.f, px2, py2, pz2};
+  const float_v dp1p2_dr2[6] = {0.f, 0.f, 0.f, px1, py1, pz1};
+  const float_v dp12_dr1[6]  = {0.f, 0.f, 0.f, 2.f*px1, 2.f*py1, 2.f*pz1};
+  const float_v dp12_dr2[6]  = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+  const float_v dp22_dr1[6]  = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+  const float_v dp22_dr2[6]  = {0.f, 0.f, 0.f, 2.f*px2, 2.f*py2, 2.f*pz2};
+  const float_v ddetp_dr1[6] = {0.f, 0.f, 0.f, -2.f*p22*px1 + 2.f*p1p2*px2, -2.f*p22*py1 + 2.f*p1p2*py2, -2.f*p22*pz1 + 2.f*p1p2*pz2};
+  const float_v ddetp_dr2[6] = {0.f, 0.f, 0.f, 2.f*p1p2*px1 - 2.f*p12*px2,   2.f*p1p2*py1 - 2.f*p12*py2, 2.f*p1p2*pz1 - 2.f*p12*pz2};
+  
+  
+  float_v da1_dr1[6], da1_dr2[6], da2_dr1[6], da2_dr2[6];
+  
+  const float_v a1 = drp2*p1p2 - drp1*p22;
+  const float_v a2 = drp2*p12  - drp1*p1p2;
+  for(int i=0; i<6; i++)
+  {
+    da1_dr1[i] = drp2_dr1[i]*p1p2 + drp2*dp1p2_dr1[i] - drp1_dr1[i]*p22 - drp1*dp22_dr1[i];
+    da1_dr2[i] = drp2_dr2[i]*p1p2 + drp2*dp1p2_dr2[i] - drp1_dr2[i]*p22 - drp1*dp22_dr2[i];
+    
+    da2_dr1[i] = drp2_dr1[i]*p12 + drp2*dp12_dr1[i] - drp1_dr1[i]*p1p2 - drp1*dp1p2_dr1[i];
+    da2_dr2[i] = drp2_dr2[i]*p12 + drp2*dp12_dr2[i] - drp1_dr2[i]*p1p2 - drp1*dp1p2_dr2[i];
+    
+    dsdr[0][i] = da1_dr1[i]/detp - a1/(detp*detp)*ddetp_dr1[i];
+    dsdr[1][i] = da1_dr2[i]/detp - a1/(detp*detp)*ddetp_dr2[i];
+    
+    dsdr[2][i] = da2_dr1[i]/detp - a2/(detp*detp)*ddetp_dr1[i];
+    dsdr[3][i] = da2_dr2[i]/detp - a2/(detp*detp)*ddetp_dr2[i];
+  }
+}
+
+void KFParticleBaseSIMD::GetDStoParticleLine( const KFParticleBaseSIMD &p, float_v dS[2] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** under the assumption of the straight line trajectory. Is used for particles with charge 0 or in case of zero magnetic field.
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   **/
+  
+  float_v p12 = fP[3]*fP[3] + fP[4]*fP[4] + fP[5]*fP[5];
+  float_v p22 = p.fP[3]*p.fP[3] + p.fP[4]*p.fP[4] + p.fP[5]*p.fP[5];
+  float_v p1p2 = fP[3]*p.fP[3] + fP[4]*p.fP[4] + fP[5]*p.fP[5];
+
+  float_v drp1 = fP[3]*(p.fP[0]-fP[0]) + fP[4]*(p.fP[1]-fP[1]) + fP[5]*(p.fP[2]-fP[2]);
+  float_v drp2 = p.fP[3]*(p.fP[0]-fP[0]) + p.fP[4]*(p.fP[1]-fP[1]) + p.fP[5]*(p.fP[2]-fP[2]);
+
+  float_v detp =  p1p2*p1p2 - p12*p22;
+  detp( abs(detp)<float_v(1.e-4f) ) = float_v(1.f); //TODO correct!!!
+
+  dS[0]  = (drp2*p1p2 - drp1*p22) /detp;
+  dS[1] = (drp2*p12  - drp1*p1p2)/detp;
+}
+
+void KFParticleBaseSIMD::GetDStoParticleCBM( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** in case of the CBM-like nonhomogeneous magnetic field. 
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP.
+   ** For this the y-component of the magnetic field at the position of the current particle is obtained and
+   ** the GetDStoParticleBy() is called. It is assumed that particles are already close to each other and that the difference 
+   ** in magnetic field approximation between two particles can be neglected. If the charge of both particles 
+   ** is zero or if the magnetic field is zero the function GetDStoParticleLine() is called.
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+  
+  float_v fld[3];
+  GetFieldValue( fP, fld );
+
+  const float_v& bq1 = fld[1]*simd_cast<float_v>(fQ);
+  const float_v& bq2 = fld[1]*simd_cast<float_v>(p.fQ);
+  const float_m& isStraight1 = abs(bq1) < float_v(1.e-8f);
+  const float_m& isStraight2 = abs(bq2) < float_v(1.e-8f);
+  
+  if( isStraight1.isFull() && isStraight2.isFull() )
+    GetDStoParticleLine(p, dS, dsdr);
+  else
+    GetDStoParticleBy(fld[1], p, dS, dsdr);
+}
+
+void KFParticleBaseSIMD::GetDStoParticleCBM( const KFParticleBaseSIMD &p, float_v dS[2] ) const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particle; \n
+   ** in case of the CBM-like nonhomogeneous magnetic field. 
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** For this the y-component of the magnetic field at the position of the current particle is obtained and
+   ** the GetDStoParticleBy() is called. It is assumed that particles are already close to each other and that the difference 
+   ** in magnetic field approximation between two particles can be neglected. If the charge of both particles 
+   ** is zero or if the magnetic field is zero the function GetDStoParticleLine() is called.
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   **/
+  
+  float_v fld[3];
+  GetFieldValue( fP, fld );
+
+  const float_v& bq1 = fld[1]*simd_cast<float_v>(fQ);
+  const float_v& bq2 = fld[1]*simd_cast<float_v>(p.fQ);
+  const float_m& isStraight1 = abs(bq1) < float_v(1.e-8f);
+  const float_m& isStraight2 = abs(bq2) < float_v(1.e-8f);
+  
+  if( isStraight1.isFull() && isStraight2.isFull() )
+    GetDStoParticleLine(p, dS);
+  else
+    GetDStoParticleBy(fld[1], p, dS);
+}
+
+void KFParticleBaseSIMD::TransportCBM( float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1, float_v* F, float_v* F1 ) const
+{  
+  /** Transports the parameters and their covariance matrix of the current particle assuming CBM-like nonhomogeneous 
+   ** magnetic field on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/
+  
+  if( (fQ == int_v(Vc::Zero)).isFull() ){
+    TransportLine( dS, dsdr, P, C, dsdr1, F, F1 );
+    return;
+  }
+
+  const float_v kCLight = 0.000299792458f;
+
+  float_v c = simd_cast<float_v>(fQ)*kCLight;
+
+  // construct coefficients 
+
+  float_v 
+    px   = fP[3],
+    py   = fP[4],
+    pz   = fP[5];
+      
+  float_v sx=0.f, sy=0.f, sz=0.f, syy=0.f, syz=0.f, syyy=0.f, ssx=0.f, ssy=0.f, ssz=0.f, ssyy=0.f, ssyz=0.f, ssyyy=0.f;
+
+  { // get field integrals
+
+    float_v fld[3][3];   
+    float_v p0[3], p1[3], p2[3];
+
+    // line track approximation
+
+    p0[0] = fP[0];
+    p0[1] = fP[1];
+    p0[2] = fP[2];
+  
+    p2[0] = fP[0] + px*dS;
+    p2[1] = fP[1] + py*dS;
+    p2[2] = fP[2] + pz*dS;
+  
+    p1[0] = 0.5f*(p0[0]+p2[0]);
+    p1[1] = 0.5f*(p0[1]+p2[1]);
+    p1[2] = 0.5f*(p0[2]+p2[2]);
+
+    // first order track approximation
+    {
+      GetFieldValue( p0, fld[0] );
+      GetFieldValue( p1, fld[1] );
+      GetFieldValue( p2, fld[2] );
+
+      float_v ssy1 = ( 7.f*fld[0][1] + 6.f*fld[1][1]-fld[2][1] )*c*dS*dS/96.f;
+      float_v ssy2 = (   fld[0][1] + 2.f*fld[1][1]         )*c*dS*dS/6.f;
+
+      p1[0] -= ssy1*pz;
+      p1[2] += ssy1*px;
+      p2[0] -= ssy2*pz;
+      p2[2] += ssy2*px;   
+    }
+
+    GetFieldValue( p0, fld[0] );
+    GetFieldValue( p1, fld[1] );
+    GetFieldValue( p2, fld[2] );
+
+    for(int iF1=0; iF1<3; iF1++)
+      for(int iF2=0; iF2<3; iF2++)
+        fld[iF1][iF2](abs(fld[iF1][iF2]) > float_v(100.f)) = 0.f;
+
+    sx = c*( fld[0][0] + 4*fld[1][0] + fld[2][0] )*dS/6.f;
+    sy = c*( fld[0][1] + 4*fld[1][1] + fld[2][1] )*dS/6.f;
+    sz = c*( fld[0][2] + 4*fld[1][2] + fld[2][2] )*dS/6.f;
+
+    ssx = c*( fld[0][0] + 2*fld[1][0])*dS*dS/6.f;
+    ssy = c*( fld[0][1] + 2*fld[1][1])*dS*dS/6.f;
+    ssz = c*( fld[0][2] + 2*fld[1][2])*dS*dS/6.f;
+
+    float_v c2[3][3]    =   { {  5.f, -4.f, -1.f},{  44.f,  80.f,  -4.f},{ 11.f, 44.f, 5.f} }; // /=360.    
+    float_v cc2[3][3]    =   { { 38.f,  8.f, -4.f},{ 148.f, 208.f, -20.f},{  3.f, 36.f, 3.f} }; // /=2520.
+    for(Int_t n=0; n<3; n++)
+      for(Int_t m=0; m<3; m++) 
+	{
+	  syz += c2[n][m]*fld[n][1]*fld[m][2];
+	  ssyz += cc2[n][m]*fld[n][1]*fld[m][2];
+	}
+ 
+    syz  *= c*c*dS*dS/360.f;
+    ssyz  *= c*c*dS*dS*dS/2520.f;
+    
+    syy  = c*( fld[0][1] + 4.f*fld[1][1] + fld[2][1] )*dS;
+    syyy = syy*syy*syy / 1296.f;
+    syy  = syy*syy/72.f;
+
+    ssyy = ( fld[0][1]*( 38.f*fld[0][1] + 156.f*fld[1][1]  -   fld[2][1] )+
+	    fld[1][1]*(              208.f*fld[1][1]  +16.f*fld[2][1] )+
+	    fld[2][1]*(                             3.f*fld[2][1] )  
+	    )*dS*dS*dS*c*c/2520.f;
+    ssyyy = 
+      (
+       fld[0][1]*( fld[0][1]*( 85.f*fld[0][1] + 526.f*fld[1][1]  - 7.f*fld[2][1] )+
+		 fld[1][1]*(             1376.f*fld[1][1]  +84.f*fld[2][1] )+
+		 fld[2][1]*(                            19.f*fld[2][1] )  )+
+       fld[1][1]*( fld[1][1]*(             1376.f*fld[1][1] +256.f*fld[2][1] )+
+		 fld[2][1]*(                            62.f*fld[2][1] )  )+
+       fld[2][1]*fld[2][1]  *(                             3.f*fld[2][1] )       
+       )*dS*dS*dS*dS*c*c*c/90720.f;    
+ 
+  }
+
+//   float_v mJ[11];
+// 
+//   mJ[0]=dS-ssyy;  mJ[1]=ssx;  mJ[2]=ssyyy-ssy;
+//   mJ[3]=-ssz;     mJ[4]=dS;  mJ[5]=ssx+ssyz;
+// 
+//   mJ[6]=1-syy;   mJ[7]=sx;  mJ[8]=syyy-sy;
+//   mJ[9]=-sz;                mJ[10]=sx+syz;
+// 
+// 
+// 
+//   P[0] = fP[0] + mJ[0]*px + mJ[1]*py + mJ[2]*pz;
+//   P[1] = fP[1] + mJ[3]*px + mJ[4]*py + mJ[5]*pz;
+//   P[2] = fP[2] - mJ[2]*px - mJ[1]*py + mJ[0]*pz;
+//   P[3] =  mJ[6]*px + mJ[7]*py + mJ[8]*pz;
+//   P[4] =  mJ[9]*px +       py + mJ[10]*pz;
+//   P[5] = -mJ[8]*px - mJ[7]*py + mJ[6]*pz;
+//   P[6] = fP[6];
+//   P[7] = fP[7];
+
+//   if(C!=fC)
+//   {
+//     for(int iC=0; iC<36; iC++)
+//       C[iC] = fC[iC];
+//   }
+// 
+//   multQSQt1( mJ, C);
+
+  float_v mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  mJ[0][0]=1; mJ[0][1]=0; mJ[0][2]=0; mJ[0][3]=dS-ssyy;  mJ[0][4]=ssx;  mJ[0][5]=ssyyy-ssy;
+  mJ[1][0]=0; mJ[1][1]=1; mJ[1][2]=0; mJ[1][3]=-ssz;     mJ[1][4]=dS;  mJ[1][5]=ssx+ssyz;
+  mJ[2][0]=0; mJ[2][1]=0; mJ[2][2]=1; mJ[2][3]=ssy-ssyyy; mJ[2][4]=-ssx; mJ[2][5]=dS-ssyy;
+  
+  mJ[3][0]=0; mJ[3][1]=0; mJ[3][2]=0; mJ[3][3]=1-syy;   mJ[3][4]=sx;  mJ[3][5]=syyy-sy;
+  mJ[4][0]=0; mJ[4][1]=0; mJ[4][2]=0; mJ[4][3]=-sz;     mJ[4][4]=1;   mJ[4][5]=sx+syz;
+  mJ[5][0]=0; mJ[5][1]=0; mJ[5][2]=0; mJ[5][3]=sy-syyy; mJ[5][4]=-sx; mJ[5][5]=1-syy;
+  mJ[6][6] = mJ[7][7] = 1;
+  
+  P[0] = fP[0] + mJ[0][3]*px + mJ[0][4]*py + mJ[0][5]*pz;
+  P[1] = fP[1] + mJ[1][3]*px + mJ[1][4]*py + mJ[1][5]*pz;
+  P[2] = fP[2] + mJ[2][3]*px + mJ[2][4]*py + mJ[2][5]*pz;
+  P[3] =         mJ[3][3]*px + mJ[3][4]*py + mJ[3][5]*pz;
+  P[4] =         mJ[4][3]*px + mJ[4][4]*py + mJ[4][5]*pz;
+  P[5] =         mJ[5][3]*px + mJ[5][4]*py + mJ[5][5]*pz;
+  P[6] = fP[6];
+  P[7] = fP[7];
+
+  float_v mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+
+  mJds[0][3]= 1.f;
+  mJds[1][4]= 1.f;
+  mJds[2][5]= 1.f;
+  
+  mJds[0][3](abs(dS)>0.f)= 1.f - 3.f*ssyy/dS;      mJds[0][4](abs(dS)>0.f)= 2.f*ssx/dS; mJds[0][5](abs(dS)>0.f)= (4.f*ssyyy-2.f*ssy)/dS;
+  mJds[1][3](abs(dS)>0.f)= -2.f*ssz/dS;            mJds[1][4](abs(dS)>0.f)= 1.f;        mJds[1][5](abs(dS)>0.f)= (2.f*ssx + 3.f*ssyz)/dS;
+  mJds[2][3](abs(dS)>0.f)= (2.f*ssy-4.f*ssyyy)/dS; mJds[2][4](abs(dS)>0.f)=-2.f*ssx/dS; mJds[2][5](abs(dS)>0.f)= 1.f - 3.f*ssyy/dS;
+  
+  mJds[3][3](abs(dS)>0.f)= -2.f*syy/dS;         mJds[3][4](abs(dS)>0.f)= sx/dS;  mJds[3][5](abs(dS)>0.f)= 3.f*syyy/dS - sy/dS;
+  mJds[4][3](abs(dS)>0.f)= -sz/dS;              mJds[4][4](abs(dS)>0.f)=0.f;     mJds[4][5](abs(dS)>0.f) = sx/dS + 2.f*syz/dS;
+  mJds[5][3](abs(dS)>0.f)= sy/dS - 3.f*syyy/dS; mJds[5][4](abs(dS)>0.f)=-sx/dS;  mJds[5][5](abs(dS)>0.f)= -2.f*syy/dS;
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+    
+  MultQSQt( mJ[0], fC, C, 8);
+
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+void KFParticleBaseSIMD::TransportCBM( float_v dS, float_v P[] ) const
+{  
+  /** Transports the parameters of the current particle assuming CBM-like nonhomogeneous 
+   ** magnetic field on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the array P. 
+   ** P can be set to the parameters fP. In this
+   ** case the particle parameters will be modified.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   **/ 
+  if( (fQ == int_v(Vc::Zero)).isFull() ){
+    TransportLine( dS, P );
+    return;
+  }
+
+  const float_v kCLight = 0.000299792458f;
+
+  float_v c = simd_cast<float_v>(fQ)*kCLight;
+
+  // construct coefficients 
+
+  float_v 
+    px   = fP[3],
+    py   = fP[4],
+    pz   = fP[5];
+      
+  float_v sx=0.f, sy=0.f, sz=0.f, syy=0.f, syz=0.f, syyy=0.f, ssx=0.f, ssy=0.f, ssz=0.f, ssyy=0.f, ssyz=0.f, ssyyy=0.f;
+
+  { // get field integrals
+
+    float_v fld[3][3];   
+    float_v p0[3], p1[3], p2[3];
+
+    // line track approximation
+
+    p0[0] = fP[0];
+    p0[1] = fP[1];
+    p0[2] = fP[2];
+  
+    p2[0] = fP[0] + px*dS;
+    p2[1] = fP[1] + py*dS;
+    p2[2] = fP[2] + pz*dS;
+  
+    p1[0] = 0.5f*(p0[0]+p2[0]);
+    p1[1] = 0.5f*(p0[1]+p2[1]);
+    p1[2] = 0.5f*(p0[2]+p2[2]);
+
+    // first order track approximation
+    {
+      GetFieldValue( p0, fld[0] );
+      GetFieldValue( p1, fld[1] );
+      GetFieldValue( p2, fld[2] );
+
+      float_v ssy1 = ( 7.f*fld[0][1] + 6.f*fld[1][1]-fld[2][1] )*c*dS*dS/96.f;
+      float_v ssy2 = (   fld[0][1] + 2.f*fld[1][1]         )*c*dS*dS/6.f;
+
+      p1[0] -= ssy1*pz;
+      p1[2] += ssy1*px;
+      p2[0] -= ssy2*pz;
+      p2[2] += ssy2*px;   
+    }
+
+    GetFieldValue( p0, fld[0] );
+    GetFieldValue( p1, fld[1] );
+    GetFieldValue( p2, fld[2] );
+
+    for(int iF1=0; iF1<3; iF1++)
+      for(int iF2=0; iF2<3; iF2++)
+        fld[iF1][iF2](abs(fld[iF1][iF2]) > float_v(100.f)) = 0.f;
+
+    sx = c*( fld[0][0] + 4*fld[1][0] + fld[2][0] )*dS/6.f;
+    sy = c*( fld[0][1] + 4*fld[1][1] + fld[2][1] )*dS/6.f;
+    sz = c*( fld[0][2] + 4*fld[1][2] + fld[2][2] )*dS/6.f;
+
+    ssx = c*( fld[0][0] + 2*fld[1][0])*dS*dS/6.f;
+    ssy = c*( fld[0][1] + 2*fld[1][1])*dS*dS/6.f;
+    ssz = c*( fld[0][2] + 2*fld[1][2])*dS*dS/6.f;
+
+    float_v c2[3][3]    =   { {  5.f, -4.f, -1.f},{  44.f,  80.f,  -4.f},{ 11.f, 44.f, 5.f} }; // /=360.    
+    float_v cc2[3][3]    =   { { 38.f,  8.f, -4.f},{ 148.f, 208.f, -20.f},{  3.f, 36.f, 3.f} }; // /=2520.
+    for(Int_t n=0; n<3; n++)
+      for(Int_t m=0; m<3; m++) 
+        {
+          syz += c2[n][m]*fld[n][1]*fld[m][2];
+          ssyz += cc2[n][m]*fld[n][1]*fld[m][2];
+        }
+ 
+    syz  *= c*c*dS*dS/360.f;
+    ssyz  *= c*c*dS*dS*dS/2520.f;
+    
+    syy  = c*( fld[0][1] + 4.f*fld[1][1] + fld[2][1] )*dS;
+    syyy = syy*syy*syy / 1296.f;
+    syy  = syy*syy/72.f;
+
+    ssyy = ( fld[0][1]*( 38.f*fld[0][1] + 156.f*fld[1][1]  -   fld[2][1] )+
+            fld[1][1]*(              208.f*fld[1][1]  +16.f*fld[2][1] )+
+            fld[2][1]*(                             3.f*fld[2][1] )  
+            )*dS*dS*dS*c*c/2520.f;
+    ssyyy = 
+      (
+       fld[0][1]*( fld[0][1]*( 85.f*fld[0][1] + 526.f*fld[1][1]  - 7.f*fld[2][1] )+
+                 fld[1][1]*(             1376.f*fld[1][1]  +84.f*fld[2][1] )+
+                 fld[2][1]*(                            19.f*fld[2][1] )  )+
+       fld[1][1]*( fld[1][1]*(             1376.f*fld[1][1] +256.f*fld[2][1] )+
+                 fld[2][1]*(                            62.f*fld[2][1] )  )+
+       fld[2][1]*fld[2][1]  *(                             3.f*fld[2][1] )       
+       )*dS*dS*dS*dS*c*c*c/90720.f;    
+ 
+  }
+
+  float_v mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  mJ[0][0]=1; mJ[0][1]=0; mJ[0][2]=0; mJ[0][3]=dS-ssyy;  mJ[0][4]=ssx;  mJ[0][5]=ssyyy-ssy;
+  mJ[1][0]=0; mJ[1][1]=1; mJ[1][2]=0; mJ[1][3]=-ssz;     mJ[1][4]=dS;  mJ[1][5]=ssx+ssyz;
+  mJ[2][0]=0; mJ[2][1]=0; mJ[2][2]=1; mJ[2][3]=ssy-ssyyy; mJ[2][4]=-ssx; mJ[2][5]=dS-ssyy;
+  
+  mJ[3][0]=0; mJ[3][1]=0; mJ[3][2]=0; mJ[3][3]=1-syy;   mJ[3][4]=sx;  mJ[3][5]=syyy-sy;
+  mJ[4][0]=0; mJ[4][1]=0; mJ[4][2]=0; mJ[4][3]=-sz;     mJ[4][4]=1;   mJ[4][5]=sx+syz;
+  mJ[5][0]=0; mJ[5][1]=0; mJ[5][2]=0; mJ[5][3]=sy-syyy; mJ[5][4]=-sx; mJ[5][5]=1-syy;
+  mJ[6][6] = mJ[7][7] = 1;
+  
+  P[0] = fP[0] + mJ[0][3]*px + mJ[0][4]*py + mJ[0][5]*pz;
+  P[1] = fP[1] + mJ[1][3]*px + mJ[1][4]*py + mJ[1][5]*pz;
+  P[2] = fP[2] + mJ[2][3]*px + mJ[2][4]*py + mJ[2][5]*pz;
+  P[3] =         mJ[3][3]*px + mJ[3][4]*py + mJ[3][5]*pz;
+  P[4] =         mJ[4][3]*px + mJ[4][4]*py + mJ[4][5]*pz;
+  P[5] =         mJ[5][3]*px + mJ[5][4]*py + mJ[5][5]*pz;
+  P[6] = fP[6];
+  P[7] = fP[7];
+}
+
+void KFParticleBaseSIMD::TransportBz( float_v Bz, float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1, float_v* F, float_v* F1 ) const 
+{ 
+  /** Transports the parameters and their covariance matrix of the current particle assuming constant homogeneous 
+   ** magnetic field Bz on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] Bz - z-component of the constant homogeneous magnetic field Bz
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/ 
+  
+  const float_v kCLight = 0.000299792458f;
+  Bz = Bz*simd_cast<float_v>(fQ)*kCLight;
+  float_v bs= Bz*dS;
+  float_v s = sin(bs), c = cos(bs);
+
+  float_v sB(Vc::Zero), cB(Vc::Zero);
+
+  const float_v kOvSqr6 = 1.f/sqrt(float_v(6.f));
+  const float_v LocalSmall = 1.e-10f;
+
+  Bz(abs(bs) <= LocalSmall) = LocalSmall;
+  sB(LocalSmall < abs(bs)) = s/Bz;
+  sB(LocalSmall >= abs(bs)) = (1.f-bs*kOvSqr6)*(1.f+bs*kOvSqr6)*dS;
+  cB(LocalSmall < abs(bs)) = (1.f-c)/Bz;
+  cB(LocalSmall >= abs(bs)) = .5f*sB*bs;
+  
+  float_v px = fP[3];
+  float_v py = fP[4];
+  float_v pz = fP[5];
+
+  P[0] = fP[0] + sB*px + cB*py;
+  P[1] = fP[1] - cB*px + sB*py;
+  P[2] = fP[2] +  dS*pz;
+  P[3] =          c*px + s*py;
+  P[4] =         -s*px + c*py;
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];
+
+  float_v mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  for(int i=0; i<8; i++) mJ[i][i]=1;
+  mJ[0][3] =  sB; mJ[0][4] = cB;
+  mJ[1][3] = -cB; mJ[1][4] = sB;
+  mJ[2][5] = dS;
+  mJ[3][3] =  c; mJ[3][4] = s;
+  mJ[4][3] = -s; mJ[4][4] = c;
+  
+  
+  float_v mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+  mJds[0][3] =  c; mJds[0][4] = s;
+  mJds[1][3] = -s; mJds[1][4] = c;
+  mJds[2][5] = 1;
+  mJds[3][3] = -Bz*s; mJds[3][4] =  Bz*c;
+  mJds[4][3] = -Bz*c; mJds[4][4] = -Bz*s;
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+  
+  MultQSQt( mJ[0], fC, C, 8);
+  
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+void KFParticleBaseSIMD::TransportBz( float_v Bz, float_v dS, float_v P[] ) const 
+{ 
+  /** Transports the parameters of the current particle assuming constant homogeneous 
+   ** magnetic field Bz on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters are stored to the array P. 
+   ** P be set to the parameters fP of the current particle. In this
+   ** case the particle parameters will be modified. 
+   ** \param[in] Bz - z-component of the constant homogeneous magnetic field Bz
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   **/ 
+  
+  const float_v kCLight = 0.000299792458f;
+  Bz = Bz*simd_cast<float_v>(fQ)*kCLight;
+  float_v bs= Bz*dS;
+  float_v s = KFPMath::Sin(bs), c = KFPMath::Cos(bs);
+
+  float_v sB(Vc::Zero), cB(Vc::Zero);
+
+  const float_v kOvSqr6 = 1.f/sqrt(float_v(6.f));
+  const float_v LocalSmall = 1.e-10f;
+
+  Bz(abs(bs) <= LocalSmall) = LocalSmall;
+  sB(LocalSmall < abs(bs)) = s/Bz;
+  sB(LocalSmall >= abs(bs)) = (1.f-bs*kOvSqr6)*(1.f+bs*kOvSqr6)*dS;
+  cB(LocalSmall < abs(bs)) = (1.f-c)/Bz;
+  cB(LocalSmall >= abs(bs)) = .5f*sB*bs;
+  
+  float_v px = fP[3];
+  float_v py = fP[4];
+  float_v pz = fP[5];
+
+  P[0] = fP[0] + sB*px + cB*py;
+  P[1] = fP[1] - cB*px + sB*py;
+  P[2] = fP[2] +  dS*pz;
+  P[3] =          c*px + s*py;
+  P[4] =         -s*px + c*py;
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];
+}
+
+
+
+float_v KFParticleBaseSIMD::GetDistanceFromVertex( const KFParticleBaseSIMD &Vtx ) const
+{
+  /** Returns the DCA distance from vertex in the KFParticle format in 3D.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+  
+  return GetDistanceFromVertex( Vtx.fP );
+}
+
+float_v KFParticleBaseSIMD::GetDistanceFromVertex( const float_v vtx[] ) const
+{
+  /** Returns the DCA distance from vertex in 3D.
+   ** \param[in] vtx[3] - the vertex coordinates {X, Y, Z}
+   **/
+  
+  float_v mP[8], mC[36];  
+  float_v dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float_v dS = GetDStoPoint(vtx, dsdr);
+  Transport( dS, dsdr, mP, mC );
+  float_v d[3]={ vtx[0]-mP[0], vtx[1]-mP[1], vtx[2]-mP[2]};
+  return sqrt( d[0]*d[0]+d[1]*d[1]+d[2]*d[2] );
+}
+
+float_v KFParticleBaseSIMD::GetDistanceFromParticle( const KFParticleBaseSIMD &p ) const
+{ 
+  /** Returns the DCA distance from another particle p.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v dS[2];
+  GetDStoParticleFast( p, dS );   
+  float_v mP[8], mP1[8];
+  TransportFast( dS[0], mP ); 
+  p.TransportFast( dS[1], mP1 ); 
+  float_v dx = mP[0]-mP1[0]; 
+  float_v dy = mP[1]-mP1[1]; 
+  float_v dz = mP[2]-mP1[2]; 
+  return sqrt(dx*dx+dy*dy+dz*dz);  
+}
+
+float_v KFParticleBaseSIMD::GetDeviationFromVertex( const KFParticleBaseSIMD &Vtx ) const
+{
+  /** Returns Chi2 deviation of the current particle from the vertex in the KFParticle format in 3D.
+   ** \param[in] Vtx - the vertex in KFPartcile format
+   **/
+  
+  return GetDeviationFromVertex( Vtx.fP, Vtx.fC );
+}
+
+
+float_v KFParticleBaseSIMD::GetDeviationFromVertex( const float_v v[], const float_v Cv[] ) const
+{
+  /** Returns Chi2 deviation of the current particle from the vertex v with the covariance matrix Cv in 3D.
+   ** \param[in] v[3] - coordinates of the vertex {X, Y, Z}
+   ** \param[in] Cv[6] - covariance matrix of the vertex {Cxx, Cxy, Cyy, Cxz, Czy, Czz}
+   **/
+
+  float_v mP[8];
+  float_v mC[36];
+  float_v dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float_v dS = GetDStoPoint(v, dsdr);
+  float_v dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0.f, 0.f, 0.f};
+  float_v F[36], F1[36];
+  for(int i2=0; i2<36; i2++)
+  {
+    F[i2]  = 0.f;
+    F1[i2] = 0.f;
+  }
+  Transport( dS, dsdr, mP, mC, dsdp, F, F1 );  
+
+  if(Cv)
+  {
+    float_v VFT[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<6; j++)
+      {
+        VFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          VFT[i][j] +=  Cv[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+  
+    float_v FVFT[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        FVFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          FVFT[i][j] += F1[i*6+k] * VFT[k][j];
+        }
+      }
+    mC[0] += FVFT[0][0] + Cv[0];
+    mC[1] += FVFT[1][0] + Cv[1];
+    mC[2] += FVFT[1][1] + Cv[2];
+    mC[3] += FVFT[2][0] + Cv[3];
+    mC[4] += FVFT[2][1] + Cv[4];
+    mC[5] += FVFT[2][2] + Cv[5];
+  }
+  
+  InvertCholetsky3(mC);
+  
+  float_v d[3]={ v[0]-mP[0], v[1]-mP[1], v[2]-mP[2]};
+
+  return ( ( mC[0]*d[0] + mC[1]*d[1] + mC[3]*d[2])*d[0]
+           +(mC[1]*d[0] + mC[2]*d[1] + mC[4]*d[2])*d[1]
+           +(mC[3]*d[0] + mC[4]*d[1] + mC[5]*d[2])*d[2] );
+}
+
+float_v KFParticleBaseSIMD::GetDeviationFromParticle( const KFParticleBaseSIMD &p ) const
+{ 
+  /** Returns Chi2 deviation of the current particle from another particle in 3D.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  float_v F1[36], F2[36], F3[36], F4[36];
+  for(int i1=0; i1<36; i1++)
+  {
+    F1[i1] = 0;
+    F2[i1] = 0;
+    F3[i1] = 0;
+    F4[i1] = 0;
+  }
+  GetDStoParticle( p, ds, dsdr );
+  
+  float_v V0Tmp[36] ;
+  float_v V1Tmp[36] ;
+
+  
+  float_v mP1[8], mC1[36];
+  float_v mP2[8], mC2[36]; 
+  
+    Transport(ds[0], dsdr[0], mP1, mC1, dsdr[1], F1, F2);
+  p.Transport(ds[1], dsdr[3], mP2, mC2, dsdr[2], F4, F3);
+  
+  MultQSQt(F2, p.fC, V0Tmp, 6);
+  MultQSQt(F3,   fC, V1Tmp, 6);
+      
+  for(int iC=0; iC<6; iC++)
+    mC1[iC] += V0Tmp[iC] + mC2[iC] + V1Tmp[iC];
+
+  float_v d[3]={ mP2[0]-mP1[0], mP2[1]-mP1[1], mP2[2]-mP1[2]};
+  
+  return ( ( mC1[0]*d[0] + mC1[1]*d[1] + mC1[3]*d[2])*d[0]
+           +(mC1[1]*d[0] + mC1[2]*d[1] + mC1[4]*d[2])*d[1]
+           +(mC1[3]*d[0] + mC1[4]*d[1] + mC1[5]*d[2])*d[2] );
+}
+
+void KFParticleBaseSIMD::SubtractFromVertex(  KFParticleBaseSIMD &Vtx ) const
+{
+  /** Subtract the current particle from vertex Vtx using the Kalman filter mathematics.
+   ** \param[in] Vtx - vertex from which particle should be subtracted
+   **/
+  
+  float_v m[8];
+  float_v mCm[36];
+  float_v D[3][3];
+  Vtx.GetMeasurement( *this, m, mCm, D );
+  //* 
+            
+  float_v mS[6] = { mCm[0] - Vtx.fC[0] + (D[0][0] + D[0][0]), 
+                  mCm[1] - Vtx.fC[1] + (D[1][0] + D[0][1]), mCm[2] - Vtx.fC[2] + (D[1][1] + D[1][1]), 
+                  mCm[3] - Vtx.fC[3] + (D[2][0] + D[0][2]), mCm[4] - Vtx.fC[4] + (D[1][2] + D[2][1]), mCm[5] - Vtx.fC[5] + (D[2][2] + D[2][2]) };
+  InvertCholetsky3(mS);   
+    
+  //* Residual (measured - estimated)
+    
+  float_v zeta[3] = { m[0]-Vtx.fP[0], m[1]-Vtx.fP[1], m[2]-Vtx.fP[2] };
+        
+  //* mCHt = mCH' - D'
+    
+  float_v mCHt0[3], mCHt1[3], mCHt2[3];
+    
+  mCHt0[0]=Vtx.fC[ 0] ;      mCHt1[0]=Vtx.fC[ 1] ;      mCHt2[0]=Vtx.fC[ 3] ;
+  mCHt0[1]=Vtx.fC[ 1] ;      mCHt1[1]=Vtx.fC[ 2] ;      mCHt2[1]=Vtx.fC[ 4] ;
+  mCHt0[2]=Vtx.fC[ 3] ;      mCHt1[2]=Vtx.fC[ 4] ;      mCHt2[2]=Vtx.fC[ 5] ;
+  
+  //* Kalman gain K = mCH'*S
+    
+  float_v k0[3], k1[3], k2[3];
+    
+  for(Int_t i=0;i<3;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+    
+  //* New estimation of the vertex position r += K*zeta
+    
+  float_v dChi2 = ((mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+              +  (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+              +  (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]);
+
+  for(Int_t i=0;i<3;++i) 
+    Vtx.fP[i] -= k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2];       
+    
+  //* New covariance matrix C -= K*(mCH')'
+    
+  for(Int_t i=0, k=0;i<3;++i){
+    for(Int_t j=0;j<=i;++j,++k) 
+      Vtx.fC[k] += k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j];
+  }
+    
+  //* Calculate Chi^2 
+
+  Vtx.fNDF  -= 2;
+  Vtx.fChi2 -= dChi2;
+}
+
+void KFParticleBaseSIMD::SubtractFromParticle(  KFParticleBaseSIMD &Vtx ) const
+{
+  /** Subtract the current particle from another particle Vtx using the Kalman filter mathematics. 
+   ** The function is depricated and is kept for compatibility reasons. Should be replaced with SubtractDaughter().
+   ** \param[in] Vtx - particle from which the current particle should be subtracted
+   **/
+  
+  float_v m[8];
+  float_v mV[36];
+
+  float_v D[3][3];
+  Vtx.GetMeasurement( *this, m, mV, D );
+
+  float_v mS[6] = { mV[0] - Vtx.fC[0] + (D[0][0] + D[0][0]), 
+                  mV[1] - Vtx.fC[1] + (D[1][0] + D[0][1]), mV[2] - Vtx.fC[2] + (D[1][1] + D[1][1]), 
+                  mV[3] - Vtx.fC[3] + (D[2][0] + D[0][2]), mV[4] - Vtx.fC[4] + (D[1][2] + D[2][1]), mV[5] - Vtx.fC[5] + (D[2][2] + D[2][2]) };
+  InvertCholetsky3(mS);
+
+  //* Residual (measured - estimated)
+
+  float_v zeta[3] = { m[0]-Vtx.fP[0], m[1]-Vtx.fP[1], m[2]-Vtx.fP[2] };    
+
+  //* CHt = CH' - D'
+
+  float_v mCHt0[7], mCHt1[7], mCHt2[7];
+
+  mCHt0[0]=mV[ 0] ;           mCHt1[0]=mV[ 1] ;           mCHt2[0]=mV[ 3] ;
+  mCHt0[1]=mV[ 1] ;           mCHt1[1]=mV[ 2] ;           mCHt2[1]=mV[ 4] ;
+  mCHt0[2]=mV[ 3] ;           mCHt1[2]=mV[ 4] ;           mCHt2[2]=mV[ 5] ;
+  mCHt0[3]=Vtx.fC[ 6]-mV[ 6]; mCHt1[3]=Vtx.fC[ 7]-mV[ 7]; mCHt2[3]=Vtx.fC[ 8]-mV[ 8];
+  mCHt0[4]=Vtx.fC[10]-mV[10]; mCHt1[4]=Vtx.fC[11]-mV[11]; mCHt2[4]=Vtx.fC[12]-mV[12];
+  mCHt0[5]=Vtx.fC[15]-mV[15]; mCHt1[5]=Vtx.fC[16]-mV[16]; mCHt2[5]=Vtx.fC[17]-mV[17];
+  mCHt0[6]=Vtx.fC[21]-mV[21]; mCHt1[6]=Vtx.fC[22]-mV[22]; mCHt2[6]=Vtx.fC[23]-mV[23];
+
+  //* Kalman gain K = mCH'*S
+    
+  float_v k0[7], k1[7], k2[7];
+    
+  for(Int_t i=0;i<7;++i){
+    k0[i] = mCHt0[i]*mS[0] + mCHt1[i]*mS[1] + mCHt2[i]*mS[3];
+    k1[i] = mCHt0[i]*mS[1] + mCHt1[i]*mS[2] + mCHt2[i]*mS[4];
+    k2[i] = mCHt0[i]*mS[3] + mCHt1[i]*mS[4] + mCHt2[i]*mS[5];
+  }
+
+    //* Add the daughter momentum to the particle momentum
+    
+  Vtx.fP[ 3] -= m[ 3];
+  Vtx.fP[ 4] -= m[ 4];
+  Vtx.fP[ 5] -= m[ 5];
+  Vtx.fP[ 6] -= m[ 6];
+  
+  Vtx.fC[ 9] -= mV[ 9];
+  Vtx.fC[13] -= mV[13];
+  Vtx.fC[14] -= mV[14];
+  Vtx.fC[18] -= mV[18];
+  Vtx.fC[19] -= mV[19];
+  Vtx.fC[20] -= mV[20];
+  Vtx.fC[24] -= mV[24];
+  Vtx.fC[25] -= mV[25];
+  Vtx.fC[26] -= mV[26];
+  Vtx.fC[27] -= mV[27];
+
+   //* New estimation of the vertex position r += K*zeta
+    
+  for(Int_t i=0;i<3;++i) 
+    Vtx.fP[i] = m[i] - (k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2]);
+  for(Int_t i=3;i<7;++i) 
+    Vtx.fP[i] = Vtx.fP[i] - (k0[i]*zeta[0] + k1[i]*zeta[1] + k2[i]*zeta[2]);
+
+    //* New covariance matrix C -= K*(mCH')'
+
+  float_v ffC[28] = {-mV[ 0],
+                   -mV[ 1], -mV[ 2],
+                   -mV[ 3], -mV[ 4], -mV[ 5],
+                    mV[ 6],  mV[ 7],  mV[ 8], Vtx.fC[ 9],
+                    mV[10],  mV[11],  mV[12], Vtx.fC[13], Vtx.fC[14],
+                    mV[15],  mV[16],  mV[17], Vtx.fC[18], Vtx.fC[19], Vtx.fC[20],
+                    mV[21],  mV[22],  mV[23], Vtx.fC[24], Vtx.fC[25], Vtx.fC[26], Vtx.fC[27] };
+
+  for(Int_t i=0, k=0;i<7;++i){
+    for(Int_t j=0;j<=i;++j,++k){
+      Vtx.fC[k] = ffC[k] + (k0[i]*mCHt0[j] + k1[i]*mCHt1[j] + k2[i]*mCHt2[j] );
+    }
+  }
+
+    //* Calculate Chi^2 
+  Vtx.fNDF  -= 2;
+  Vtx.fQ    -= GetQ();
+  Vtx.fSFromDecay = 0;    
+  Vtx.fChi2 -= ((mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2])*zeta[0]
+             +  (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2])*zeta[1]
+             +  (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2])*zeta[2]);
+}
+
+void KFParticleBaseSIMD::TransportLine( float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1, float_v* F, float_v* F1 ) const 
+{
+  /** Transports the parameters and their covariance matrix of the current particle assuming the straight line trajectory
+   ** on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/
+  
+  float_v mJ[8][8];
+  for( Int_t i=0; i<8; i++ ) for( Int_t j=0; j<8; j++) mJ[i][j]=0;
+
+  mJ[0][0]=1; mJ[0][1]=0; mJ[0][2]=0; mJ[0][3]=dS;  mJ[0][4]=0;  mJ[0][5]=0;
+  mJ[1][0]=0; mJ[1][1]=1; mJ[1][2]=0; mJ[1][3]=0;     mJ[1][4]=dS;  mJ[1][5]=0;
+  mJ[2][0]=0; mJ[2][1]=0; mJ[2][2]=1; mJ[2][3]=0; mJ[2][4]=0; mJ[2][5]=dS;
+  
+  mJ[3][0]=0; mJ[3][1]=0; mJ[3][2]=0; mJ[3][3]=1;   mJ[3][4]=0;  mJ[3][5]=0;
+  mJ[4][0]=0; mJ[4][1]=0; mJ[4][2]=0; mJ[4][3]=0;     mJ[4][4]=1;   mJ[4][5]=0;
+  mJ[5][0]=0; mJ[5][1]=0; mJ[5][2]=0; mJ[5][3]=0; mJ[5][4]=0; mJ[5][5]=1;
+  mJ[6][6] = mJ[7][7] = 1;
+  
+  float_v px = fP[3], py = fP[4], pz = fP[5];
+  
+  P[0] = fP[0] + dS*fP[3];
+  P[1] = fP[1] + dS*fP[4];
+  P[2] = fP[2] + dS*fP[5];
+  P[3] = fP[3];
+  P[4] = fP[4];
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];
+  
+  float_v mJds[6][6];
+  for( Int_t i=0; i<6; i++ ) for( Int_t j=0; j<6; j++) mJds[i][j]=0;
+  
+  mJds[0][3]= 1; 
+  mJds[1][4]= 1;
+  mJds[2][5]= 1;
+  
+  for(int i1=0; i1<6; i1++)
+    for(int i2=0; i2<6; i2++)
+      mJ[i1][i2] += mJds[i1][3]*px*dsdr[i2] + mJds[i1][4]*py*dsdr[i2] + mJds[i1][5]*pz*dsdr[i2];
+  MultQSQt( mJ[0], fC, C, 8);
+  
+  if(F)
+  {
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+        F[i*6+j] = mJ[i][j];
+
+    for(int i1=0; i1<6; i1++)
+      for(int i2=0; i2<6; i2++)
+        F1[i1*6 + i2] = mJds[i1][3]*px*dsdr1[i2] + mJds[i1][4]*py*dsdr1[i2] + mJds[i1][5]*pz*dsdr1[i2];
+  }
+}
+
+void KFParticleBaseSIMD::TransportLine( float_v dS, float_v P[] ) const 
+{
+  /** Transports the parameters of the current particle assuming the straight line trajectory
+   ** on the length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. The obtained parameters are stored to the array P 
+   ** P can be set to the parameters fP of the current particle. In this
+   ** case the particle parameters will be modified. 
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   **/
+  
+  P[0] = fP[0] + dS*fP[3];
+  P[1] = fP[1] + dS*fP[4];
+  P[2] = fP[2] + dS*fP[5];
+  P[3] = fP[3];
+  P[4] = fP[4];
+  P[5] = fP[5];
+  P[6] = fP[6];
+  P[7] = fP[7];  
+}
+
+void KFParticleBaseSIMD::GetArmenterosPodolanski(KFParticleBaseSIMD& positive, KFParticleBaseSIMD& negative, float_v QtAlfa[2] )
+{
+  /** Calculates parameters for the Armenteros-Podolanski plot for two particles. 
+   ** Example how to use:\n
+   ** KFParticle PosParticle(...) \n
+   ** KFParticle NegParticle(...) \n
+   ** Gamma.ConstructGamma(PosParticle, NegParticle); \n
+   ** float VertexGamma[3] = {Gamma.GetX(), Gamma.GetY(), Gamma.GetZ()}; \n
+   ** PosParticle.TransportToPoint(VertexGamma); \n
+   ** NegParticle.TransportToPoint(VertexGamma); \n
+   ** float armenterosQtAlfa[2] = {0.}; \n
+   ** KFParticle::GetArmenterosPodolanski(PosParticle, NegParticle, armenterosQtAlfa ); \n
+   ** \param[in] positive - first particle, positive or neutral
+   ** \param[in] negative - second particle, negative or neutral
+   ** \param[out] QtAlfa[2] - parameters for the Armenteros-Podolanski plot: QtAlfa[0] = qt - projection of the 
+   ** momenta of the particles on the transverse direction with respect to the total momentum, same for both particles;
+   ** QtAlfa[1] = (Pl+ - Pl-)/(Pl+ + Pl-) - combination of the longitudinal components.
+   **/
+
+  float_v alpha = 0.f, qt = 0.f;
+  float_v spx = positive.GetPx() + negative.GetPx();
+  float_v spy = positive.GetPy() + negative.GetPy();
+  float_v spz = positive.GetPz() + negative.GetPz();
+  float_v sp  = sqrt(spx*spx + spy*spy + spz*spz);
+  float_m mask = float_m(  abs(sp) < float_v(1.e-10f));
+  float_v pn, pp, pln, plp;
+
+  pn = sqrt(negative.GetPx()*negative.GetPx() + negative.GetPy()*negative.GetPy() + negative.GetPz()*negative.GetPz());
+  pp = sqrt(positive.GetPx()*positive.GetPx() + positive.GetPy()*positive.GetPy() + positive.GetPz()*positive.GetPz());
+  pln  = (negative.GetPx()*spx+negative.GetPy()*spy+negative.GetPz()*spz)/sp;
+  plp  = (positive.GetPx()*spx+positive.GetPy()*spy+positive.GetPz()*spz)/sp;
+
+  mask = float_m(mask & float_m(  abs(pn) < float_v(1.E-10f)));
+  float_v ptm  = (1.f-((pln/pn)*(pln/pn)));
+  qt(ptm >= 0.f) =  pn*sqrt(ptm);
+  alpha = (plp-pln)/(plp+pln);
+
+  QtAlfa[0](mask) = qt;
+  QtAlfa[1](mask) = alpha;
+}
+
+void KFParticleBaseSIMD::RotateXY(float_v angle, float_v Vtx[3])
+{
+  /** Rotates the KFParticle object around OZ axis, OZ axis is set by the vertex position.
+   ** \param[in] angle - angle of rotation in XY plane in [rad]
+   ** \param[in] Vtx[3] - position of the vertex in [cm]
+   **/
+
+  // Before rotation the center of the coordinat system should be moved to the vertex position; move back after rotation
+  X() = X() - Vtx[0];
+  Y() = Y() - Vtx[1];
+  Z() = Z() - Vtx[2];
+
+  // Rotate the kf particle
+  float_v s = sin(angle);
+  float_v c = cos(angle);
+  
+  float_v mA[8][ 8];
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<8; j++){
+      mA[i][j] = 0;
+    }
+  }
+  for( int i=0; i<8; i++ ){
+    mA[i][i] = 1;
+  }
+  mA[0][0] =  c;  mA[0][1] = s;
+  mA[1][0] = -s;  mA[1][1] = c;
+  mA[3][3] =  c;  mA[3][4] = s;
+  mA[4][3] = -s;  mA[4][4] = c;
+
+  float_v mAC[8][8];
+  float_v mAp[8];
+
+  for( Int_t i=0; i<8; i++ ){
+    mAp[i] = 0;
+    for( Int_t k=0; k<8; k++){
+      mAp[i]+=mA[i][k] * fP[k];
+    }
+  }
+
+  for( Int_t i=0; i<8; i++){
+    fP[i] = mAp[i];
+  }
+
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<8; j++ ){
+      mAC[i][j] = 0;
+      for( Int_t k=0; k<8; k++ ){
+        mAC[i][j]+= mA[i][k] * GetCovariance(k,j);
+      }
+    }
+  }
+
+  for( Int_t i=0; i<8; i++ ){
+    for( Int_t j=0; j<=i; j++ ){
+      float_v xx = 0.f;
+      for( Int_t k=0; k<8; k++){
+        xx+= mAC[i][k]*mA[j][k];
+      }
+      Covariance(i,j) = xx;
+    }
+  }
+
+  X() = GetX() + Vtx[0];
+  Y() = GetY() + Vtx[1];
+  Z() = GetZ() + Vtx[2];
+}
+
+void KFParticleBaseSIMD::InvertCholetsky3(float_v a[6])
+{
+  /** Inverts symmetric 3x3 matrix a using modified Choletsky decomposition. The result is stored to the same matrix a.
+   ** \param[in,out] a - 3x3 symmetric matrix
+   **/
+
+  float_v d[3], uud, u[3][3];
+  for(int i=0; i<3; i++) 
+  {
+    d[i]=0.f;
+    for(int j=0; j<3; j++) 
+      u[i][j]=0.f;
+  }
+
+  for(int i=0; i<3 ; i++)
+  {
+    uud=0.f;
+    for(int j=0; j<i; j++) 
+      uud += u[j][i]*u[j][i]*d[j];
+    uud = a[i*(i+3)/2] - uud;
+
+    uud(abs(uud)<1.e-8f) = 1.e-8f;
+    d[i] = uud/abs(uud);
+    u[i][i] = sqrt(abs(uud));
+
+    for(int j=i+1; j<3; j++) 
+    {
+      uud = 0.f;
+      for(int k=0; k<i; k++)
+        uud += u[k][i]*u[k][j]*d[k];
+      uud = a[j*(j+1)/2+i] - uud;
+      u[i][j] = d[i]/u[i][i]*uud;
+    }
+  }
+
+  float_v u1[3];
+
+  for(int i=0; i<3; i++)
+  {
+    u1[i] = u[i][i];
+    u[i][i] = 1.f/u[i][i];
+  }
+  for(int i=0; i<2; i++)
+  {
+    u[i][i+1] = - u[i][i+1]*u[i][i]*u[i+1][i+1];
+  }
+  for(int i=0; i<1; i++)
+  {
+    u[i][i+2] = u[i][i+1]*u1[i+1]*u[i+1][i+2]-u[i][i+2]*u[i][i]*u[i+2][i+2];
+  }
+
+  for(int i=0; i<3; i++)
+    a[i+3] = u[i][2]*u[2][2]*d[2];
+  for(int i=0; i<2; i++)
+    a[i+1] = u[i][1]*u[1][1]*d[1] + u[i][2]*u[1][2]*d[2];
+  a[0] = u[0][0]*u[0][0]*d[0] + u[0][1]*u[0][1]*d[1] + u[0][2]*u[0][2]*d[2];
+}
+
+void KFParticleBaseSIMD::MultQSQt( const float_v Q[], const float_v S[], float_v SOut[], const int kN )
+{
+  /** Matrix multiplication SOut = Q*S*Q^T, where Q - square matrix, S - symmetric matrix.
+   ** \param[in] Q - square matrix
+   ** \param[in] S - input symmetric matrix
+   ** \param[out] SOut - output symmetric matrix
+   ** \param[in] kN - dimensionality of the matrices
+   **/
+  
+  float_v* mA = new float_v[kN*kN];
+  
+  for( Int_t i=0, ij=0; i<kN; i++ ){
+    for( Int_t j=0; j<kN; j++, ++ij ){
+      mA[ij] = 0 ;
+      for( Int_t k=0; k<kN; ++k ) mA[ij]+= S[( k<=i ) ? i*(i+1)/2+k :k*(k+1)/2+i] * Q[ j*kN+k];
+    }
+  }
+    
+  for( Int_t i=0; i<kN; i++ ){
+    for( Int_t j=0; j<=i; j++ ){
+      Int_t ij = ( j<=i ) ? i*(i+1)/2+j :j*(j+1)/2+i;
+      SOut[ij] = 0 ;
+      for( Int_t k=0; k<kN; k++ )  SOut[ij] += Q[ i*kN+k ] * mA[ k*kN+j ];
+    }
+  }
+  
+  if(mA) delete[] mA;
+}
+
+
+// 72-charachters line to define the printer border
+//3456789012345678901234567890123456789012345678901234567890123456789012
+
diff --git a/external/KFParticle/KFParticle/KFParticleBaseSIMD.h b/external/KFParticle/KFParticle/KFParticleBaseSIMD.h
new file mode 100644
index 0000000000000000000000000000000000000000..c39dec909fd2ea7eda937cd78b90995506d82118
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleBaseSIMD.h
@@ -0,0 +1,341 @@
+//---------------------------------------------------------------------------------
+// The KFParticleBaseSIMD class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class describes general mathematics which is used by KFParticle class
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+
+#ifndef KFParticleBaseSIMD_H
+#define KFParticleBaseSIMD_H
+
+#ifdef HLTCA_STANDALONE
+#include "RootTypesDef.h"
+#endif
+
+#include <vector>
+#include "KFParticleDef.h"
+
+/** @class KFParticleBaseSIMD
+ ** @brief The base of KFParticleSIMD class.
+ ** @author  M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** Contains the main mathematics of the vectorised KF Particle. Will be merged with the KFParticleSIMD class. 
+ ** The class stores all the data in a format of SIMD vectors, the mathematics is fully vectorised.
+ ** THe mathematics is implemented in single precision.
+ ** The functionality of the vectorised and scalar classes is the same.
+ **/
+
+class KFParticleBaseSIMD {
+  
+ public:
+                  
+  //*
+  //* ABSTRACT METHODS HAVE TO BE DEFINED IN USER CLASS 
+  //* 
+#if  __GNUC__ && ( defined(ENVIRONMENT32) ||  GCC_VERSION < 40300 )
+
+#else
+                                            
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(float_v)); }     ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(float_v)); }   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);} ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                        ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                      ///< delete operator for the SIMD-alligned dynamic memory release
+ 
+#endif 
+                  
+  /** Virtual method to access the magnetic field**/
+  virtual void GetFieldValue(const float_v xyz[], float_v B[]) const = 0;
+  
+  //* Virtual methods needed for particle transportation 
+  //* One can use particular implementations for collider (only Bz component) 
+  //* geometry and for fixed-target (CBM-like) geometry which are provided below 
+  //* in TRANSPORT section
+ 
+  //* Get dS to xyz[] space point 
+
+   /** Virtual method to get extrapolation parameter dS=l/p to . Is defined in KFParticleSIMD.**/
+  virtual float_v GetDStoPoint( const float_v xyz[3], float_v dsdr[6] ) const = 0;
+  
+  float_v GetDStoPointLine( const float_v xyz[3], float_v dsdr[6] ) const;
+  float_v GetDStoPointBz( float_v Bz, const float_v xyz[3], float_v dsdr[6], const float_v* param = 0 ) const;
+  float_v GetDStoPointBy( float_v By, const float_v xyz[3], float_v dsdr[6] ) const;
+  float_v GetDStoPointCBM( const float_v xyz[3], float_v dsdr[6] ) const;
+
+  /** Virtual method to get extrapolation parameter dS=l/p and ds/dr partial derivatives to another particle. Is defined in KFParticleSIMD.**/
+  virtual void GetDStoParticle( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const = 0;
+  /** Virtual method to get extrapolation parameter dS=l/p to another particle. Is defined in KFParticleSIMD.**/
+  virtual void GetDStoParticleFast( const KFParticleBaseSIMD &p, float_v dS[2] ) const = 0;
+  
+  void GetDStoParticleLine( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const ;
+  void GetDStoParticleLine( const KFParticleBaseSIMD &p, float_v dS[2]  ) const ;
+  void GetDStoParticleBz( float_v Bz, const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6], const float_v* param1 =0, const float_v* param2 =0  ) const ;
+  void GetDStoParticleBz( float_v Bz, const KFParticleBaseSIMD &p, float_v dS[2], const float_v* param1 =0, const float_v* param2 =0  ) const ;
+  void GetDStoParticleBy( float_v B, const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const ;
+  void GetDStoParticleBy( float_v B, const KFParticleBaseSIMD &p, float_v dS[2] ) const ;
+  void GetDStoParticleB( float_v B[3], const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const;
+  void GetDStoParticleB( float_v B[3], const KFParticleBaseSIMD &p, float_v dS[2] ) const;
+  void GetDStoParticleCBM( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const ;
+  void GetDStoParticleCBM( const KFParticleBaseSIMD &p, float_v dS[2] ) const ;
+  
+  /** Virtual method to transport a particle parameters and covariance matrix on a certain distance along the trajectory. Is defined in KFParticleSIMD.**/
+  virtual void Transport( float_v dS, const float_v dsdr[6], float_v P[], float_v C[], float_v* dsdr1=0, float_v* F=0, float_v* F1=0 ) const = 0;
+  /** Virtual method to transport a particle parameters on a certain distance along the trajectory. Is defined in KFParticleSIMD.**/
+  virtual void TransportFast( float_v dS, float_v P[] ) const = 0;
+
+
+
+  //*
+  //*  INITIALIZATION
+  //*
+
+  //* Constructor 
+
+  KFParticleBaseSIMD();
+
+  //* Destructor 
+
+  virtual ~KFParticleBaseSIMD() { ; } ///< The default destructor.
+
+  void Initialize( const float_v Param[], const float_v Cov[], int_v Charge, float_v Mass );
+  void Initialize();
+
+  void SetConstructMethod(Int_t m) {fConstructMethod = m;} ///< Defines the construction method for the current particle (see description of fConstructMethod).
+  void SetMassHypo(float_v m) { fMassHypo = m;} ///< Sets the mass hypothesis to the particle, is used when fConstructMethod = 2.
+  const float_v& GetMassHypo() const { return fMassHypo; } ///< Returns the mass hypothesis.
+  const float_v& GetSumDaughterMass() const {return SumDaughterMass;} ///< Returns the sum of masses of the daughters.
+
+  //*
+  //*  ACCESSORS
+  //*
+
+  //* Simple accessors 
+
+  float_v GetX    () const { return fP[0]; } ///< Returns the sum of masses of the daughters
+  float_v GetY    () const { return fP[1]; } ///< Returns the sum of masses of the daughters
+  float_v GetZ    () const { return fP[2]; } ///< Returns the sum of masses of the daughters
+  float_v GetPx   () const { return fP[3]; } ///< Returns the sum of masses of the daughters
+  float_v GetPy   () const { return fP[4]; } ///< Returns the sum of masses of the daughters
+  float_v GetPz   () const { return fP[5]; } ///< Returns the sum of masses of the daughters
+  float_v GetE    () const { return fP[6]; } ///< Returns the sum of masses of the daughters
+  float_v GetS    () const { return fP[7]; } ///< Returns the sum of masses of the daughters
+  int_v   GetQ    () const { return fQ;    } ///< Returns the sum of masses of the daughters
+  float_v GetChi2 () const { return fChi2; } ///< Returns the sum of masses of the daughters
+  int_v GetNDF    () const { return fNDF;  } ///< Returns the sum of masses of the daughters
+
+  const float_v& X    () const { return fP[0]; } ///< Retruns X coordinate of the particle, fP[0].
+  const float_v& Y    () const { return fP[1]; } ///< Retruns Y coordinate of the particle, fP[1].
+  const float_v& Z    () const { return fP[2]; } ///< Retruns Z coordinate of the particle, fP[2].
+  const float_v& Px   () const { return fP[3]; } ///< Retruns X component of the momentum, fP[3].
+  const float_v& Py   () const { return fP[4]; } ///< Retruns Y component of the momentum, fP[4].
+  const float_v& Pz   () const { return fP[5]; } ///< Retruns Z component of the momentum, fP[5].
+  const float_v& E    () const { return fP[6]; } ///< Returns energy of the particle, fP[6].
+  const float_v& S    () const { return fP[7]; } ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  const int_v&   Q    () const { return fQ;    } ///< Returns charge of the particle.
+  const float_v& Chi2 () const { return fChi2; } ///< Returns Chi2 of the fit.
+  const int_v& NDF    () const { return fNDF;  } ///< Returns number of decrease of freedom.
+  
+  float_v GetParameter ( Int_t i )          const { return fP[i];       } ///< Returns P[i] parameter.
+  float_v GetCovariance( Int_t i )          const { return fC[i];       } ///< Returns C[i] element of the covariance matrix in the lower triangular form.
+  float_v GetCovariance( Int_t i, Int_t j ) const { return fC[IJ(i,j)]; } ///< Returns C[i,j] element of the covariance matrix.
+
+  //* Accessors with calculations( &value, &estimated sigma )
+  //* error flag returned (0 means no error during calculations) 
+
+  float_m GetMomentum      ( float_v &p,    float_v &error ) const ;
+  float_m GetPt            ( float_v &pt,   float_v &error ) const ;
+  float_m GetEta           ( float_v &eta,  float_v &error ) const ;
+  float_m GetPhi           ( float_v &phi,  float_v &error ) const ;
+  float_m GetMass          ( float_v &m,    float_v &error ) const ;
+  float_m GetDecayLength   ( float_v &l,    float_v &error ) const ;
+  float_m GetDecayLengthXY ( float_v &l,    float_v &error ) const ;
+  float_m GetLifeTime      ( float_v &ctau, float_v &error ) const ;
+  float_m GetR             ( float_v &r,    float_v &error ) const ;
+
+  //*
+  //*  MODIFIERS
+  //*
+  
+  float_v & X    () { return fP[0]; } ///< Modifier of X coordinate of the particle, fP[0].
+  float_v & Y    () { return fP[1]; } ///< Modifier of Y coordinate of the particle, fP[1].
+  float_v & Z    () { return fP[2]; } ///< Modifier of Z coordinate of the particle, fP[2].
+  float_v & Px   () { return fP[3]; } ///< Modifier of X component of the momentum, fP[3].
+  float_v & Py   () { return fP[4]; } ///< Modifier of Y component of the momentum, fP[4].
+  float_v & Pz   () { return fP[5]; } ///< Modifier of Z component of the momentum, fP[5].
+  float_v & E    () { return fP[6]; } ///< Modifier of energy of the particle, fP[6].
+  float_v & S    () { return fP[7]; } ///< Modifier of dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  int_v   & Q    () { return fQ;    } ///< Modifier of charge of the particle.
+  float_v & Chi2 () { return fChi2; } ///< Modifier of Chi2 of the fit.
+  int_v & NDF    () { return fNDF;  } ///< Modifier of number of decrease of freedom.
+
+  float_v & Parameter ( Int_t i )          { return fP[i];       } ///< Modifier of P[i] parameter.
+  float_v & Covariance( Int_t i )          { return fC[i];       } ///< Modifier of C[i] element of the covariance matrix in the lower triangular form.
+  float_v & Covariance( Int_t i, Int_t j ) { return fC[IJ(i,j)]; } ///< Modifier of C[i,j] element of the covariance matrix.
+
+
+  //* 
+  //* CONSTRUCTION OF THE PARTICLE BY ITS DAUGHTERS AND MOTHER
+  //* USING THE KALMAN FILTER METHOD
+  //*
+
+
+  //* Simple way to add daughter ex. D0+= Pion; 
+
+  void operator +=( const KFParticleBaseSIMD &Daughter );  
+
+  //* Add daughter track to the particle 
+
+  void AddDaughter( const KFParticleBaseSIMD &Daughter );
+  void SubtractDaughter( const KFParticleBaseSIMD &Daughter );
+
+  void AddDaughterWithEnergyFit( const KFParticleBaseSIMD &Daughter );
+  void AddDaughterWithEnergyFitMC( const KFParticleBaseSIMD &Daughter ); 
+  //with mass constrained
+
+  //* Set production vertex 
+
+  void SetProductionVertex( const KFParticleBaseSIMD &Vtx );
+
+  //* Set mass constraint 
+
+  void SetNonlinearMassConstraint( float_v Mass );
+  void SetMassConstraint( float_v Mass, float_v SigmaMass = float_v(0.f) );
+
+  //* Set no decay length for resonances
+
+  void SetNoDecayLength();
+
+
+  //* Everything in one go  
+
+  void Construct( const KFParticleBaseSIMD *vDaughters[], Int_t nDaughters, const KFParticleBaseSIMD *ProdVtx=0,   Float_t Mass=-1 );
+
+
+  //*
+  //*                   TRANSPORT
+  //* 
+  //*  ( main transportation parameter is S = SignedPath/Momentum )
+  //*  ( parameters of decay & production vertices are stored locally )
+  //*
+
+
+  //* Transport the particle to its decay vertex 
+
+  void TransportToDecayVertex();
+
+  //* Transport the particle to its production vertex 
+
+  void TransportToProductionVertex();
+
+  //* Transport the particle on dS parameter (SignedPath/Momentum) 
+
+  void TransportToDS( float_v dS, const float_v* dsdr );
+  void TransportToDSLine( float_v dS, const float_v* dsdr );
+  //* Particular extrapolators one can use 
+  void TransportBz( float_v Bz, float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1=0, float_v* F=0, float_v* F1=0 ) const;
+  void TransportBz( float_v Bz, float_v dS, float_v P[] ) const;
+  void TransportCBM( float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1=0, float_v* F=0, float_v* F1=0 ) const;
+  void TransportCBM( float_v dS, float_v P[] ) const;    
+
+  //* 
+  //* OTHER UTILITIES
+  //*
+
+  //* Calculate distance from another object [cm]
+
+  float_v GetDistanceFromVertex( const float_v vtx[] ) const;
+  float_v GetDistanceFromVertex( const KFParticleBaseSIMD &Vtx ) const;
+  float_v GetDistanceFromParticle( const KFParticleBaseSIMD &p ) const;
+
+  //* Calculate CAMath::Sqrt(Chi2/ndf) deviation from vertex
+  //* v = [xyz], Cv=[Cxx,Cxy,Cyy,Cxz,Cyz,Czz]-covariance matrix
+
+  float_v GetDeviationFromVertex( const float_v v[], 
+                                   const float_v Cv[]=0 ) const;
+  float_v GetDeviationFromVertex( const KFParticleBaseSIMD &Vtx ) const;
+  float_v GetDeviationFromParticle( const KFParticleBaseSIMD &p ) const;  
+
+  //* Subtract the particle from the vertex  
+
+  void SubtractFromVertex( KFParticleBaseSIMD &Vtx ) const;
+  void SubtractFromParticle( KFParticleBaseSIMD &Vtx ) const;
+
+  static void GetArmenterosPodolanski(KFParticleBaseSIMD& positive, KFParticleBaseSIMD& negative, float_v QtAlfa[2] );
+  void RotateXY(float_v angle, float_v Vtx[3]);
+
+  int_v Id() const { return fId; } ///< Returns Id of the particle.
+  int NDaughters() const { return fDaughterIds.size(); } ///< Returns number of daughter particles.
+  std::vector<int_v> & DaughterIds() { return fDaughterIds; } ///< Returns the vector with the indices of daughter particles.
+  int_v GetDaughterId(int iD) const { return fDaughterIds[iD]; } ///< Returns the daughter Id with the index iD.
+  
+  void SetId( int_v id ){ fId = id; } ///< Sets the Id of the particle. After the construction of a particle should be set by user.
+  void SetNDaughters( int n ) { fDaughterIds.reserve(n); } ///< Reserves the size of the vector with daughter Ids to n
+  void AddDaughterId( int_v id ){ fDaughterIds.push_back(id); } ///< Adds index of the daughter particle. 
+  void CleanDaughtersId() { fDaughterIds.clear(); } ///< Cleans the vector with the indices of daughter particles.
+
+  void SetPDG ( int pdg ) { fPDG = pdg; } ///< Sets the PDG hypothesis common for all elements of the SIMD vector.
+  void SetPDG ( int_v& pdg ) { fPDG = pdg; } ///< Sets the PDG hypothesis individual for each entry of the SIMD vector.
+  const int_v& GetPDG () const { return fPDG; } ///< Returns the PDG hypothesis.
+  const int_v& PDG () const { return fPDG; } ///< Returns the PDG hypothesis.
+
+  void GetDistanceToVertexLine( const KFParticleBaseSIMD &Vertex, float_v &l, float_v &dl, float_m *isParticleFromVertex = 0 ) const;
+
+  static void MultQSQt( const float_v Q[], const float_v S[], float_v SOut[], const int kN  );
+
+ protected:
+  /** Converts a pair of indices {i,j} of the covariance matrix to one index corresponding to the triangular form. */
+  static Int_t IJ( Int_t i, Int_t j ){ 
+    return ( j<=i ) ? i*(i+1)/2+j :j*(j+1)/2+i;
+  }
+  /** Return an element of the covariance matrix with {i,j} indices. */
+  float_v & Cij( Int_t i, Int_t j ){ return fC[IJ(i,j)]; }
+
+  void TransportLine( float_v S, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1=0, float_v* F=0, float_v* F1=0 ) const ;
+  void TransportLine( float_v S, float_v P[] ) const ;
+
+  static void InvertCholetsky3(float_v a[6]);
+
+  void GetMeasurement( const KFParticleBaseSIMD& daughter, float_v m[], float_v V[], float_v D[3][3] ) ;
+
+  //* Mass constraint function. is needed for the nonlinear mass constraint and a fit with mass constraint
+  void SetMassConstraint( float_v *mP, float_v *mC, float_v mJ[7][7], float_v mass, float_m mask );
+
+  float_v fP[8];              ///< Particle parameters { X, Y, Z, Px, Py, Pz, E, S[=DecayLength/P]}.
+  float_v fC[36];             ///< Low-triangle covariance matrix of fP.
+  int_v fQ;                   ///< The charge of the particle in the units of the elementary charge.
+  int_v fNDF;                 ///< Number of degrees of freedom.
+  float_v fChi2;              ///< Chi^2.
+  float_v fSFromDecay;        ///< Distance from the decay vertex to the current position.
+  float_v SumDaughterMass;    ///< Sum of the daughter particles masses. Needed to set the constraint on the minimum mass during particle construction.
+  float_v fMassHypo;          ///< The mass hypothesis, used for the constraints during particle construction.
+  int_v fId;                  ///< Id of the particle.
+  Bool_t fAtProductionVertex; ///< Flag shows if particle is at the production point.
+  int_v fPDG;                 ///< The PDG hypothesis assigned to the particle.
+  /** \brief Determines the method for the particle construction. \n
+   ** 0 - Energy considered as an independent veriable, fitted independently from momentum, without any constraints on mass \n
+   ** 2 - Energy considered as an independent variable, fitted independently from momentum, with constraints on mass of daughter particle
+   **/
+  Int_t fConstructMethod;
+  /** \brief A vector with ids of the daughter particles: \n
+   ** 1) if particle is created from a track - the index of the track, in this case the size of the vector is always equal to one; \n
+   ** 2) if particle is constructed from other particles - indices of these particles in the same array.
+   **/
+  std::vector<int_v> fDaughterIds; // id of particles it created from. if size == 1 then this is id of track.
+
+} __attribute__((aligned(sizeof(float_v))));
+
+#endif 
diff --git a/external/KFParticle/KFParticle/KFParticleDatabase.cxx b/external/KFParticle/KFParticle/KFParticleDatabase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e89afd8b6021223bcb563f530493e33f643b3bba
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleDatabase.cxx
@@ -0,0 +1,98 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFParticleDatabase.h"
+
+KFParticleDatabase* KFParticleDatabase::fDatabase = 0;
+
+KFParticleDatabase::KFParticleDatabase():
+  fMassPi0PDG(0.13498),
+#ifdef PANDA_STT
+  fMassPi0PDGSigma(0.009),
+#elif defined ALICE_ITS
+  fMassPi0PDGSigma(0.006),
+#elif defined STAR_HFT
+  fMassPi0PDGSigma(0.006),
+#elif defined CBM
+  fMassPi0PDGSigma(0.006),
+#else 
+  fMassPi0PDGSigma(0.006),
+#endif
+  fMassD0PDG(1.86484),
+#ifdef CBM
+  fMassD0PDGSigma(0.0145),
+#else
+  fMassD0PDGSigma(0.0154),
+#endif
+  fMassDPlusPDG(1.86962),
+#ifdef CBM
+  fMassDPlusPDGSigma(0.0145)
+#else
+  fMassDPlusPDGSigma(0.0115)
+#endif
+{
+  /** The default constructor. Initialises masses and widths of the peaks. 
+   ** Be aware, that widths of the peaks are experiment specific.
+   **/
+  fMass[0] = 0.000510999;
+  fMass[1] = 0.105658;
+  fMass[2] = 0.13957;
+  fMass[3] = 0.493667;
+  fMass[4] = 0.9382723;
+  fMass[5] = 1.876124;
+  fMass[6] = 2.809432;
+  fMass[7] = 2.809413;
+  fMass[8] = 3.728400;
+  fMass[9] = 1.197449;
+  fMass[10] = 1.18937;
+  fMass[11] = 1.32171;
+  fMass[12] = 1.67245;
+  
+  fMassSecPDG[0] = 0.497614; //K0
+  fMassSecPDG[1] = 1.115683; //Lambda
+  fMassSecPDG[2] = 1.32171; //Xi  
+  fMassSecPDG[3] = 0; //gamma
+  fMassSecPDG[4] = 1.67245; //Omega
+  fMassSecPDG[5] = 2.99339; //H3L
+  fMassSecPDG[6] = 3.93070; //He4L
+  fMassSecPDG[7] = 4.86824; //He5L
+  
+#ifdef PANDA_STT
+  fMassSecPDGSigma[0]=12.0e-3; //K0 TODO tune
+  fMassSecPDGSigma[1]=2.7e-3; //Lambda
+  fMassSecPDGSigma[2]=2.8e-3; //Xi TODO tune
+#elif defined ALICE_ITS
+  fMassSecPDGSigma[0]=17.7e-3;
+  fMassSecPDGSigma[1]=5.9e-3;
+  fMassSecPDGSigma[2]=7.3e-3;
+#elif defined STAR_HFT
+  fMassSecPDGSigma[0]=17.7e-3;
+  fMassSecPDGSigma[1]=5.9e-3;
+  fMassSecPDGSigma[2]=7.3e-3;
+#elif defined CBM
+  fMassSecPDGSigma[0]=3.7e-3; //2.2e-3;
+  fMassSecPDGSigma[1]=1.5e-3; //1.2e-3;
+  fMassSecPDGSigma[2]=2.0e-3;  
+#else //STAR
+  fMassSecPDGSigma[0]=4.9e-3;
+  fMassSecPDGSigma[1]=2.1e-3;
+  fMassSecPDGSigma[2]=2.1e-3;
+#endif
+  fMassSecPDGSigma[3]=6.0e-3; //TODO tune //Gamma
+  fMassSecPDGSigma[4]=2.1e-3; //Omega
+  fMassSecPDGSigma[5]=3.0e-3; //H3L
+  fMassSecPDGSigma[6]=3.0e-3; //He4L
+  fMassSecPDGSigma[7]=3.0e-3; //He5L
+  
+  fDatabase = this;
+}
+
+KFParticleDatabase kfPartDatabase; //create instance
diff --git a/external/KFParticle/KFParticle/KFParticleDatabase.h b/external/KFParticle/KFParticle/KFParticleDatabase.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b8523260f2b95cc1194233c1892d5e0e7dca07e
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleDatabase.h
@@ -0,0 +1,176 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#ifndef KFParticleDatabase_H
+#define KFParticleDatabase_H
+
+#include "Vc/Vc"
+
+/** @class KFParticleDatabase
+ ** @brief The class stores information about particle masses and expected width of the peacks.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class contains information required for the reconstruction of decay trees: \n
+ ** - masses of the stable particles; \n
+ ** - masses of the intermediate daughter particles (like Lambda, K0, Xi, D0, etc.);\n
+ ** - expected widths of the peaks.
+ **/
+
+class KFParticleDatabase
+{
+ public:
+  KFParticleDatabase();
+
+  ~KFParticleDatabase() {};
+
+  float GetMass(const int pdg) const
+  {
+    /** Returns scalar float variable with the mass of the stable particle with the given PDG code.
+     ** If the given PDG code is not the list of the current database mass of the pion is returned.
+     ** \param[in] pdg - the input PDG code
+     **/
+    int pdgIndex = 2;
+    switch ( abs(pdg) )
+    {
+      case         11: pdgIndex = 0; break;
+      case         13: pdgIndex = 1; break;
+      case         19: pdgIndex = 1; break;
+      case        211: pdgIndex = 2; break;
+      case        321: pdgIndex = 3; break;
+      case       2212: pdgIndex = 4; break;
+      case 1000010020: pdgIndex = 5; break;
+      case 1000010030: pdgIndex = 6; break;
+      case 1000020030: pdgIndex = 7; break;
+      case 1000020040: pdgIndex = 8; break;
+      case       3112: pdgIndex = 9; break;
+      case       3222: pdgIndex = 10; break;
+      case       3312: pdgIndex = 11; break;
+      case       3334: pdgIndex = 12; break;
+      default:   pdgIndex = 2; break;
+    }
+    
+    return fMass[pdgIndex];
+  }
+
+  Vc::float_v GetMass(const Vc::int_v& pdg) const
+  {
+    /** Returns vector float variable with the mass of the stable particles with the given PDG codes.
+     ** If the given PDG code is not in the list of the current database mass of the pion is returned.
+     ** \param[in] pdg - the input PDG codes of a set of particles in the SIMD-vector format
+     **/
+    Vc::int_v pdgIndex(2);
+    pdgIndex(Vc::abs(pdg) ==         11) = 0;    
+    pdgIndex(Vc::abs(pdg) ==         13) = 1;
+    pdgIndex(Vc::abs(pdg) ==         19) = 1;
+    pdgIndex(Vc::abs(pdg) ==        211) = 2;
+    pdgIndex(Vc::abs(pdg) ==        321) = 3;
+    pdgIndex(Vc::abs(pdg) ==       2212) = 4;
+    pdgIndex(Vc::abs(pdg) == 1000010020) = 5;
+    pdgIndex(Vc::abs(pdg) == 1000010030) = 6;
+    pdgIndex(Vc::abs(pdg) == 1000020030) = 7;
+    pdgIndex(Vc::abs(pdg) == 1000020040) = 8;
+    pdgIndex(Vc::abs(pdg) ==       3112) = 9;
+    pdgIndex(Vc::abs(pdg) ==       3222) = 10;
+    pdgIndex(Vc::abs(pdg) ==       3312) = 11;
+    pdgIndex(Vc::abs(pdg) ==       3334) = 12;
+    Vc::float_v mass(fMass, pdgIndex);
+    return mass;
+  }
+
+  void GetMotherMass(const Vc::int_v& pdg, Vc::float_v& massMotherPDG, Vc::float_v& massMotherPDGSigma) const
+  {
+    /** Returns vector float variable with the mass of the short-lived particles with the given PDG codes
+     ** and the expected widths of the corresponding peaks.
+     ** If the given PDG code is not in the list of the current database mass of K0s is returned.
+     ** \param[in] pdg - the input PDG code
+     ** \param[out] massMotherPDG - the output table mass for the given PDG code
+     ** \param[out] massMotherPDGSigma - expected width of the corresponding peak
+     **/
+    
+    Vc::int_v pdgIndex(0);
+    pdgIndex(pdg ==  310) = 0;    
+    pdgIndex(Vc::abs(pdg) == 3122) = 1;
+    pdgIndex(Vc::abs(pdg) == 3312) = 2;
+    pdgIndex(pdg == 22) = 3;
+    pdgIndex(Vc::abs(pdg) == 3334) = 4;
+    pdgIndex(Vc::abs(pdg) == 3004) = 5;
+    pdgIndex(Vc::abs(pdg) == 3006) = 6;
+    pdgIndex(Vc::abs(pdg) == 3007) = 7;
+        
+    massMotherPDG.gather(fMassSecPDG, pdgIndex);
+    massMotherPDGSigma.gather(fMassSecPDGSigma, pdgIndex);
+  }
+  
+  void GetMotherMass(const int pdg, float& massMotherPDG, float& massMotherPDGSigma) const
+  {
+    /** Returns scalar float variables with the mass of the short-lived particle  with the given PDG code
+     ** and the expected width of the corresponding peak.
+     ** If the given PDG code is not in the list of the current database mass of K0s is returned.
+     ** \param[in] pdg - the input PDG code
+     ** \param[out] massMotherPDG - the output table mass for the given PDG code
+     ** \param[out] massMotherPDGSigma - expected width of the corresponding peak
+     **/
+        
+    int pdgIndex = 2;
+    switch ( abs(pdg) )
+    {
+      case  310: pdgIndex = 0; break;
+      case 3122: pdgIndex = 1; break;
+      case 3312: pdgIndex = 2; break;
+      case   22: pdgIndex = 3; break;
+      case 3334: pdgIndex = 4; break;
+      case 3004: pdgIndex = 5; break;
+      case 3006: pdgIndex = 6; break;
+      case 3007: pdgIndex = 7; break;
+      default:   pdgIndex = 0; break;
+    }
+   
+    massMotherPDG = fMassSecPDG[pdgIndex];
+    massMotherPDGSigma = fMassSecPDGSigma[pdgIndex];
+  }
+  
+  const float& GetPi0Mass() const { return fMassPi0PDG; }                ///< Returns the table PDG pi0 mass.
+  const float& GetPi0MassSigma() const { return fMassPi0PDGSigma; }      ///< Returns expected width of the pi0 peak.
+  const float& GetD0Mass() const { return fMassD0PDG; }                  ///< Returns the table PDG D0 mass.
+  const float& GetD0MassSigma() const { return fMassD0PDGSigma; }        ///< Returns expected width of the D0 peak.
+  const float& GetDPlusMass() const { return fMassDPlusPDG; }            ///< Returns the table PDG D+ mass.
+  const float& GetDPlusMassSigma() const { return fMassDPlusPDGSigma; }  ///< Returns expected width of the D+ peak.
+  
+  static const KFParticleDatabase* Instance() { return fDatabase; }     ///< Returns a pointer to the singleton object.
+
+ private:
+  /** Table PDG masses of particles, which can be registered by the tracking detector directly: \n
+   ** [ 0] - electron; \n [ 1] - muon; \n [ 2] - pion; \n [ 3] - kaon; \n [ 4] - proton; \n [ 5] - deutron; \n [ 6] - triton; \n [ 7] - He3; \n
+   ** [ 8] - He4; \n [ 9] - Sigma-; \n [10] - Sigma+; \n [11] - Xi; \n [12] - Omega. */
+  float fMass[13];
+
+  /** Table PDG masses of short-lived particles, which are used for reconstruction of the decay trees: \n
+   ** [ 0] - K0s; \n [ 1] - Lambda; \n [ 2] - Xi; \n [ 3] - gamma; \n [ 4] - Omega; \n [ 5] - H3Lambda; \n [ 6] - He4Lambda; \n [ 7] - He5Lambda. */
+  float fMassSecPDG[8];
+  /** Expected widths of peaks of short-lived particles, which are used for reconstruction of the decay trees: \n
+   ** [ 0] - K0s; \n [ 1] - Lambda; \n [ 2] - Xi; \n [ 3] - gamma; \n [ 4] - Omega; \n [ 5] - H3Lambda; \n [ 6] - He4Lambda; \n [ 7] - He5Lambda. */
+  float fMassSecPDGSigma[8];
+  
+  float fMassPi0PDG;          ///< Table mass of pi0
+  float fMassPi0PDGSigma;     ///< Expected width of the pi0 peak
+
+  float fMassD0PDG;           ///< Table mass of D0 
+  float fMassD0PDGSigma;      ///< Expected width of the D0 peak
+  float fMassDPlusPDG;        ///< Table mass of D+ 
+  float fMassDPlusPDGSigma;   ///< Expected width of the D+ peak
+  
+  static KFParticleDatabase* fDatabase; ///< A singleton object.
+};
+
+#endif
\ No newline at end of file
diff --git a/external/KFParticle/KFParticle/KFParticleDef.h b/external/KFParticle/KFParticle/KFParticleDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..ced9c0a32270d2435ced3194d427c474af222e3e
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleDef.h
@@ -0,0 +1,145 @@
+//---------------------------------------------------------------------------------
+// The KFParticleBaseSIMD class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class describes general mathematics which is used by KFParticle class
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+
+#ifndef KFParticleDef_H
+#define KFParticleDef_H
+
+#ifdef __ROOT__ //for the STAR experiment
+#define HomogeneousField
+#endif
+
+#ifdef HLTCA_STANDALONE
+#include "RootTypesDef.h"
+#else
+#include "TObject.h"
+#endif
+
+#define NInputSets 8
+
+#include <Vc/Vc>
+#include <Vc/version.h>
+#include <Vc/limits>
+using ::Vc::float_v;
+using ::Vc::double_v;
+using ::Vc::float_v;
+using ::Vc::int_v;
+using ::Vc::uint_v;
+using ::Vc::VectorAlignment;
+using ::Vc::double_m;
+using ::Vc::float_m;
+using ::Vc::int_m;
+using ::Vc::uint_m;
+using ::Vc::atan2;
+using ::Vc::asin;
+using ::Vc::round;
+using ::Vc::isfinite;
+
+#ifdef VC_VERSION_NUMBER
+#if VC_VERSION_NUMBER < VC_VERSION_CHECK(1,0,0)
+template <typename To, typename From> To simd_cast(From &&x) { return static_cast<To>(x); }
+#endif
+#elif defined(Vc_VERSION_NUMBER)
+#if Vc_VERSION_NUMBER < Vc_VERSION_CHECK(1,0,0)
+template <typename To, typename From> To simd_cast(From &&x) { return static_cast<To>(x); }
+#endif
+#endif
+
+const int float_vLen = float_v::Size;
+
+#if defined(HLTCA_STANDALONE)
+typedef unsigned char UChar_t;
+typedef UChar_t Byte_t;
+typedef int Int_t;
+typedef double Double_t;
+#else
+#include "Rtypes.h"
+#endif
+
+#include "KFPSimdAllocator.h"    
+typedef std::vector<float_v, KFPSimdAllocator<float_v> > kfvector_floatv;
+
+typedef std::vector<float, KFPSimdAllocator<float> > kfvector_float;
+typedef std::vector<int, KFPSimdAllocator<int> > kfvector_int;
+typedef std::vector<unsigned int, KFPSimdAllocator<unsigned int> > kfvector_uint;
+
+namespace KFPMath
+{
+  static inline __attribute__((always_inline)) float_v Sin  ( const float_v &phi ) 
+  {
+    const float_v pi(3.1415926535897932f);
+    const float_v nTurnsF = (phi + pi) / (float_v(2.f)*pi);
+    int_v nTurns = simd_cast<int_v>( nTurnsF );
+    nTurns( (nTurns<=int_v(Vc::Zero)) && simd_cast<int_m>(phi<-pi)) -= 1;
+    
+    const float_v& x = phi - simd_cast<float_v>(nTurns)*(float_v(2.f)*pi);
+    
+    const float_v& B = 4.f/pi;
+    const float_v& C = -B/pi;
+
+    float_v y = (B + C * Vc::abs(x)) * x;
+
+    const float_v& P = 0.218f;
+    y = P * (y * Vc::abs(y) - y) + y;
+    
+    return y;    
+  }
+  static inline __attribute__((always_inline)) float_v Cos  ( const float_v &phi )
+  {     
+    return Sin( phi + 1.570796326795f ); //x + pi/2
+  }
+  static inline __attribute__((always_inline)) float_v ATan2( const float_v &y, const float_v &x )
+  { 
+    const float_v pi(3.1415926535897932f);
+    const float_v zero(Vc::Zero);
+
+    const float_m &xZero = (x == zero);
+    const float_m &yZero = (y == zero);
+    const float_m &xNeg  = (x < zero);
+    const float_m &yNeg  = (y < zero);
+
+    const float_v &absX = Vc::abs(x);
+    const float_v &absY = Vc::abs(y);
+
+    float_v a = absY / absX;
+    const float_m &gt_tan_3pi_8 = (a > float_v(2.414213562373095f));
+    const float_m &gt_tan_pi_8  = (a > float_v(0.4142135623730950f)) && (!gt_tan_3pi_8);
+    float_v b(Vc::Zero);
+    b(gt_tan_3pi_8) = pi/2.f;
+    b(gt_tan_pi_8) = pi/4.f;
+    a(gt_tan_3pi_8) =  (-1.f / a);
+    a(gt_tan_pi_8) =  ((absY - absX) / (absY + absX)) ;
+    const float_v &a2 = a * a;
+    b += (((8.05374449538e-2f * a2
+          - 1.38776856032E-1f) * a2
+          + 1.99777106478E-1f) * a2
+          - 3.33329491539E-1f) * a2 * a
+          + a;
+    b(xNeg ^ yNeg) = -b;
+    b(xNeg && !yNeg) = (b+pi);
+    b(xNeg &&  yNeg)  = (b-pi);
+    b(xZero && yZero) = zero;
+    b(xZero &&  yNeg) = (-pi/2.f);
+    return b;
+  }
+  template<typename T> static inline __attribute__((always_inline)) 
+    typename Vc::Vector<T>::Mask Finite(const Vc::Vector<T> &x) { return Vc::isfinite( x ); }
+  template<typename T> static inline __attribute__((always_inline)) T Log ( const T &x ) { return std::log( x ); }
+  template<typename T> static inline __attribute__((always_inline)) T ACos( const T &x ) { return (3.1415926535897f/2.f - asin( x )); }
+}
+
+#endif 
diff --git a/external/KFParticle/KFParticle/KFParticleField.h b/external/KFParticle/KFParticle/KFParticleField.h
new file mode 100644
index 0000000000000000000000000000000000000000..605c63a66373eaa7ee057776e9b53107cf604241
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleField.h
@@ -0,0 +1,190 @@
+//----------------------------------------------------------------------------
+// Class for approximation of the magnetic field for KF Particle
+// .
+// @author  I.Kisel, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFParticleField_h
+#define KFParticleField_h 1
+
+#include <iostream>
+
+/** @class KFParticleFieldValue
+ ** @brief A class to store a vector with the magnetic field values {Bx, By, Bz} at the certain point.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to represent the vector of the magnetic field at the certain position of the track.
+ ** It contains three components of the magnetic field: Bx, By and Bz. It allows to combine the current
+ ** field measurement with another measurement using a weight.
+ **/
+
+class KFParticleFieldValue
+{
+ public:
+  KFParticleFieldValue():x(0.f),y(0.f),z(0.f){};
+      
+  float_v x; ///< Bx component of the magnetic field 
+  float_v y; ///< By component of the magnetic field 
+  float_v z; ///< Bz component of the magnetic field 
+
+  void Combine( KFParticleFieldValue &B, float_v w )
+  {
+    /** Function allows to combine the current magntic field measurement with another measurement
+      ** weighted by "w"
+      ** \param[in] B - another field measurement to be combined with the current value
+      ** \param[in] w - weight of the measurement being added
+      **/
+    x+= w*( B.x - x );
+    y+= w*( B.y - y );
+    z+= w*( B.z - z );
+  }
+
+  /** Operator to print components of the magnetic field in order Bx, By, Bz.
+    ** \param[in] out - output stream where the values will be printed
+    ** \param[in] B - field vecrot to be printed
+    **/
+  friend std::ostream& operator<<(std::ostream& out, KFParticleFieldValue &B){
+    return out << B.x[0] << " | " << B.y[0] << " | " << B.z[0];
+  };
+};
+
+/** @class KFParticleFieldRegion
+ ** @brief A class to store an approximation of the magnetic field along the particle trajectory. Is used for nonhomogeneous field.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to store the approximation of the magnetic field along the particle trajectory.
+ ** Each component Bx, By, Bz is approximated with a parabola function depending on the z coordinate.
+ ** The class is fully vectorised, all parameters are stored in SIMD vectors.
+ ** The class is used in case of the CBM-like nonhomogenious magnetic field.
+ **/
+
+class KFParticleFieldRegion
+{
+ public:
+  KFParticleFieldRegion() {};
+  KFParticleFieldRegion(const float field[10])
+  {
+    /** Sets current vectorised representation of the magnetic field approximation from the scalar input  array.
+     ** \param[in] field[10] - the scalar input array with the magnetic field approximation
+     **/
+    for(int i=0; i<10; i++)
+      fField[i] = field[i];
+  }
+
+  KFParticleFieldValue Get(const float_v z)
+  {
+    /** Returns a magnetic field vector calculated using current parametrisation at the given Z coordinate.
+      ** \param[in] z - value of the Z coordinate, where magnetic field should be calculated.
+      **/ 
+    float_v dz = (z-fField[9]);
+    float_v dz2 = dz*dz;
+    KFParticleFieldValue B;
+    B.x = fField[0] + fField[1]*dz + fField[2]*dz2;
+    B.y = fField[3] + fField[4]*dz + fField[5]*dz2;
+    B.z = fField[6] + fField[7]*dz + fField[8]*dz2;
+    return B;
+  }
+  
+  void Set( const KFParticleFieldValue &B0, const float_v B0z,
+            const KFParticleFieldValue &B1, const float_v B1z,
+            const KFParticleFieldValue &B2, const float_v B2z )
+  {
+    /** Approximates the magnetic field with the parabolas using three points along the particle trajectory.
+     ** \param[in] B0 - magnetic field vector at the first point
+     ** \param[in] B0z - Z position of the first point
+     ** \param[in] B1 - magnetic field vector at the second point
+     ** \param[in] B1z - Z position of the second point
+     ** \param[in] B2 - magnetic field vector at the third point
+     ** \param[in] B2z - Z position of the third point
+     **/
+    fField[9] = B0z;
+    float_v dz1 = B1z-B0z, dz2 = B2z-B0z;
+    float_v det = 1.f/(float_v(dz1*dz2*(dz2-dz1)));
+    float_v w21 = -dz2*det;
+    float_v w22 = dz1*det;
+    float_v w11 = -dz2*w21;
+    float_v w12 = -dz1*w22;
+    
+    float_v dB1 = B1.x - B0.x;
+    float_v dB2 = B2.x - B0.x;
+    fField[0] = B0.x;
+    fField[1] = dB1*w11 + dB2*w12 ;
+    fField[2] = dB1*w21 + dB2*w22 ;
+    
+    dB1 = B1.y - B0.y;
+    dB2 = B2.y - B0.y;
+    fField[3] = B0.y;
+    fField[4] = dB1*w11 + dB2*w12 ;
+    fField[5] = dB1*w21 + dB2*w22  ;
+
+    dB1 = B1.z - B0.z;
+    dB2 = B2.z - B0.z;
+    fField[6] = B0.z;
+    fField[7] = dB1*w11 + dB2*w12 ;
+    fField[8] = dB1*w21 + dB2*w22   ;
+  }
+
+  void Set( const KFParticleFieldValue &B0, const float_v B0z,
+            const KFParticleFieldValue &B1, const float_v B1z )
+  {
+    /** Approximates the magnetic field with the strainght line using two points.
+     ** \param[in] B0 - magnetic field vector at the first point
+     ** \param[in] B0z - Z position of the first point
+     ** \param[in] B1 - magnetic field vector at the second point
+     ** \param[in] B1z - Z position of the second point
+     **/
+    fField[9] = B0z;
+    float_v dzi = 1.f/(float_v( B1z - B0z));
+    fField[0] = B0.x;
+    fField[3] = B0.y;
+    fField[6] = B0.z;
+    fField[1] = ( B1.x - B0.x )*dzi;
+    fField[4] = ( B1.y - B0.y )*dzi;
+    fField[7] = ( B1.z - B0.z )*dzi;
+    fField[2] = fField[5] = fField[8] = 0.f;
+  }
+  
+  void SetOneEntry( const float* field, int iEntry=0 )
+  {
+    /** Sets one element of the SIMD vector with index iEntry.
+     ** \param[in] field - a scalar input array with the approximation of the magnetic field
+     ** \param[in] iEntry - entry number of the current SIMD vectors to be set with the input approximation
+     **/
+    for(int i=0; i<10; i++)
+      fField[i][iEntry] = field[i];
+  }
+  
+  void SetOneEntry( const int i0, const KFParticleFieldRegion &f1, const int i1 )
+  {
+    /** Copies the field approximation from the vector f1 with index i1 to the SIMD vector elemets of the current object with index i0.
+     ** \param[in] i0 - index of the SIMD vector elements of the current field approximation to be set
+     ** \param[in] f1 - input approximation of the magnetic field
+     ** \param[in] i1 - index of the SIMD vector elements of the input approximation to be copied to the current object 
+     **/
+    for(int i=0; i<10; i++)
+      fField[i][i0] = f1.fField[i][i1];
+  }
+    
+  /** The coefficients of the field approximation: \n
+   ** cx0 = fField[0], cx1 = fField[1], cx2 = fField[2] - coefficients of the Bx approximation; \n
+   ** cy0 = fField[3], cy1 = fField[4], cy2 = fField[5] - coefficients of the By approximation; \n
+   ** cz0 = fField[6], cz1 = fField[7], cz2 = fField[8] - coefficients of the Bz approximation; \n
+   ** z0 = fField[9] - reference Z coordinate. \n
+   ** Bx(z) = cx0 + cx1*(z-z0) + cx2*(z-z0)^2 \n
+   ** By(z) = cy0 + cy1*(z-z0) + cy2*(z-z0)^2 \n
+   ** Bz(z) = cz0 + cz1*(z-z0) + cz2*(z-z0)^2
+   **/
+  float_v fField[10]; 
+};
+
+
+#endif
diff --git a/external/KFParticle/KFParticle/KFParticleFinder.cxx b/external/KFParticle/KFParticle/KFParticleFinder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..78bc5048aec1fe16d9ed9e5ef396593cf1f6a9c8
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleFinder.cxx
@@ -0,0 +1,3114 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFParticleFinder.h"
+
+using std::map;
+using std::vector;
+
+#include "KFParticleDatabase.h"
+#include "KFPEmcCluster.h"
+
+KFParticleFinder::KFParticleFinder():
+  fNPV(-1),fNThreads(1),fDistanceCut(1.f),fLCut(-5.f),fCutCharmPt(0.2f),fCutCharmChiPrim(85.f),fCutLVMPt(0.0f),fCutLVMP(0.0f),fCutJPsiPt(1.0f),
+  fD0(0), fD0bar(0), fD04(0), fD04bar(0), fD0KK(0), fD0pipi(0), fDPlus(0), fDMinus(0), 
+  fDPlus3Pi(0), fDMinus3Pi(0), fDsPlusK2Pi(0), fDsMinusK2Pi(0), fLcPlusP2Pi(0), fLcMinusP2Pi(0),
+  fLPi(0), fLPiPIndex(0), fHe3Pi(0), fHe3PiBar(0), fHe4Pi(0), fHe4PiBar(0), 
+  fHe4L(0), fHe5L(0),  fLLn(0), fH5LL(0),
+  fSecCandidates(), fPrimCandidates(), fPrimCandidatesTopo(),fPrimCandidatesTopoMass(),
+  fEmcClusters(0), fMixedEventAnalysis(0), fDecayReconstructionList()
+{
+  /** The default constructor. Initialises all cuts to the default values. **/
+  //Cuts
+  //track + track
+  //chi2_prim         chi2_geo          ldl
+  fCuts2D[0] = 3.f; fCuts2D[1] = 3.f; fCuts2D[2] = 5.f; 
+  //cuts to select primary and secondary particles
+  //mass              chi2_topo          ldl
+#ifdef PANDA_STT
+  fSecCuts[0] = 3.f; fSecCuts[1] = -3.f; fSecCuts[2] = 10.f;
+#else  
+  fSecCuts[0] = 3.f; fSecCuts[1] = 5.f; fSecCuts[2] = 10.f;
+#endif
+  
+#ifdef __ROOT__
+  fCutCharmChiPrim = 8;
+#endif
+  
+  //track + particle
+  //                ldl          chi2_topo                        chi2_geo
+  fCutsTrackV0[0][0] =  5;     fCutsTrackV0[0][1] = 5;        fCutsTrackV0[0][2] = 6;  //Xi, Omega
+  fCutsTrackV0[1][0] =  5;     fCutsTrackV0[1][1] = 5;        fCutsTrackV0[1][2] = 6;  //Charm, H0, Sigma+
+  fCutsTrackV0[2][0] = -100.;  fCutsTrackV0[2][1] = 10000.;   fCutsTrackV0[2][2] = 3;  //resonances
+  
+  //charm
+  //chi2               l/dl                  chi2_topo
+  fCutsCharm[0] = 3.f; fCutsCharm[1] = 10.f;  fCutsCharm[2] = 3.f; //D0 -> pi+ K-
+  
+  //cuts on particles reconstructed from short-lived particles
+  //ldl,                      chi2_topo                 chi2_geo
+  //H0 -> Lambda Lambda, Xi0 -> Lambda pi0
+  fCutsPartPart[0][0] =  10;  fCutsPartPart[0][1] = 3;  fCutsPartPart[0][2] = 3;
+  //Sigma0 -> Lambda Gamma, pi0 -> Gamma Gamma, K* -> K pi0, Sigma*0 -> Lambda pi0, Xi* -> Xi pi0
+  fCutsPartPart[1][0] = -10;  fCutsPartPart[1][1] = 3;  fCutsPartPart[1][2] = 3;  
+}
+
+//________________________________________________________________________________
+void KFParticleFinder::Init(int nPV) 
+{
+  /** Initialises the new event: all vectors with temporary candidates are cleaned, the number of 
+   ** primary vertices is set to "nPV", vectors with primary candidates are resized correspondingly.
+   ** \param[in] nPV - number of primary vertices in the event which will be processed
+   **/
+  
+  fNPV = nPV;
+//   Particles.reserve(vRTracks.size() + nPart);
+
+  fD0.clear();
+  fD0bar.clear();
+  fD04.clear();
+  fD04bar.clear();
+  fD0KK.clear();
+  fD0pipi.clear();
+  fDPlus.clear();
+  fDMinus.clear();
+  fDPlus3Pi.clear();
+  fDMinus3Pi.clear();
+  fDsPlusK2Pi.clear();
+  fDsMinusK2Pi.clear();
+  fLcPlusP2Pi.clear();
+  fLcMinusP2Pi.clear();
+  fLPi.clear();
+  fLPiPIndex.clear();
+  fHe3Pi.clear();
+  fHe3PiBar.clear();
+  fHe4Pi.clear();
+  fHe4PiBar.clear();
+  fHe4L.clear();
+  fHe5L.clear();
+  fLLn.clear();
+  fH5LL.clear();
+  
+  for(int iCandidates=0; iCandidates<fNSecCandidatesSets; iCandidates++)
+    fSecCandidates[iCandidates].clear();
+  
+  for(int iCandidates=0; iCandidates<fNPrimCandidatesSets; iCandidates++)
+  {
+    fPrimCandidates[iCandidates].clear();
+    fPrimCandidates[iCandidates].resize(fNPV);
+  }
+  
+  for(int iCandidates=0; iCandidates<fNPrimCandidatesTopoSets; iCandidates++)
+  {
+    fPrimCandidatesTopo[iCandidates].clear();
+    fPrimCandidatesTopo[iCandidates].resize(fNPV);
+    
+    fPrimCandidatesTopoMass[iCandidates].clear();
+    fPrimCandidatesTopoMass[iCandidates].resize(fNPV);
+  }
+  
+}
+//________________________________________________________________________________
+
+void KFParticleFinder::FindParticles(KFPTrackVector* vRTracks, kfvector_float* ChiToPrimVtx, std::vector<KFParticle>& Particles,
+                                     std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx, int nPV)
+{
+  /** The main interface which runs reconstruction of short-lived particles:\n
+   ** 1) a new event is initialised; \n
+   ** 2) long-lived particles formed from tracks are stored to the output array "Particles"; \n
+   ** 3) 2-daughter channels are reconstructed (KFParticleFinder::Find2DaughterDecay()); \n
+   ** 4) the 2-daughter same-signed background is collected for resonances (KFParticleFinder::ConstructPrimaryBG()); \n
+   ** 5) found primary candidates of \f$K_s^0\f$, \f$\Lambda\f$, \f$\overline{\Lambda}\f$ and \f$\gamma\f$ are transported
+   ** to the point of the closest approach with the corresponding primary vertex (KFParticleFinder::ExtrapolateToPV()); \n
+   ** 6) reconstruction with the missing mass method (KFParticleFinder::NeutralDaughterDecay()); \n
+   ** 7) all other decays are reconstructed one after another. \n
+   ** If analysis is run in the mixed event mode only steps 1) and 2) are performed.
+   ** \param[in] vRTracks - pointer to the array with vectors of tracks:\n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** \param[in] ChiToPrimVtx - arrays with vectors of the \f$\chi^2_{prim}\f$ deviations for track vectors 1) and 2).
+   ** \param[out] Particles - output vector with particles.
+   ** \param[in] PrimVtx - vector with primary vertices.
+   ** \param[in] nPV - number of the input primary vertices.
+   **/
+  
+  Init(nPV);
+  const int nPartPrim = vRTracks[2].NPions() * vRTracks[3].NKaons() + 
+                        vRTracks[3].NPions() * vRTracks[2].NKaons() + 
+                        vRTracks[2].NKaons() * vRTracks[3].NKaons() + 
+                        vRTracks[2].NKaons() * vRTracks[3].NProtons() + 
+                        vRTracks[3].NKaons() * vRTracks[2].NProtons() + 
+                        vRTracks[2].NElectrons() * vRTracks[3].NElectrons() + 
+                        vRTracks[2].NMuons() * vRTracks[3].NMuons();
+
+  const int nPart = vRTracks[0].NPions() * vRTracks[1].NPions() +
+                    vRTracks[0].NPions() * vRTracks[1].NProtons() +
+                    vRTracks[1].NPions() * vRTracks[0].NProtons() + nPartPrim;
+  int nEmcClusters = 0;
+  if(fEmcClusters)
+    nEmcClusters = fEmcClusters->Size();
+  vector<KFParticle> vGammaPrimEmc;
+
+  int nPartEstimation = nPart+vRTracks[0].Size()+vRTracks[1].Size()+vRTracks[2].Size()+vRTracks[3].Size() + nEmcClusters;
+
+  if(nPartEstimation < 100000)
+    Particles.reserve(nPartEstimation);
+  //* Finds particles (K0s and Lambda) from a given set of tracks
+  {
+    KFPTrack kfTrack;
+    for(int iV=0; iV<4; iV++)
+    {
+      for(int iTr=0; iTr < vRTracks[iV].Size(); iTr++)
+      {
+        vRTracks[iV].GetTrack(kfTrack, iTr);
+        int pdg = vRTracks[iV].PDG()[iTr];
+        if( pdg == 19 ) pdg =  13;
+        if( pdg ==-19 ) pdg = -13;
+        KFParticle tmp(kfTrack, pdg);
+        tmp.SetPDG(pdg);
+        tmp.SetId(Particles.size());
+        vRTracks[iV].SetId(Particles.size(),iTr);
+        if(vRTracks[iV+4].Size() > 0)
+          vRTracks[iV+4].SetId(Particles.size(),iTr);
+        tmp.AddDaughterId( kfTrack.Id() );
+#ifdef NonhomogeneousField
+        for(int iF=0; iF<10; iF++)
+          tmp.SetFieldCoeff( vRTracks[iV].FieldCoefficient(iF)[iTr], iF);
+#endif
+        Particles.push_back(tmp);
+      }
+    }
+
+    if(fEmcClusters)
+    {
+      KFParticleSIMD tmpGammaSIMD;
+      KFParticle tmpGamma;
+      
+      for(int iEmc=0; iEmc < fEmcClusters->Size(); iEmc += float_vLen)
+      {
+        const int NClustersVec = (iEmc + float_vLen < fEmcClusters->Size()) ? float_vLen : (fEmcClusters->Size() - iEmc);
+        tmpGammaSIMD.Load(*fEmcClusters, iEmc, PrimVtx[0]);
+        for(int iV=0; iV<NClustersVec; iV++)
+        {
+          tmpGammaSIMD.GetKFParticle(tmpGamma, iV);
+          tmpGamma.SetPDG(22); //gamma pdg
+          tmpGamma.SetId(Particles.size());
+          tmpGamma.CleanDaughtersId();
+          tmpGamma.AddDaughterId(fEmcClusters->Id()[iEmc+iV]);
+          Particles.push_back(tmpGamma);
+          vGammaPrimEmc.push_back(tmpGamma);
+        }
+      }
+    }
+  }
+
+
+
+  Find2DaughterDecay(vRTracks, ChiToPrimVtx,
+                     Particles, PrimVtx, fCuts2D,
+                     fSecCuts, fPrimCandidates, fSecCandidates);
+
+  if(!fMixedEventAnalysis)
+  {
+    //Construct two-particle background from positive primary tracks for subtraction from the resonance spectra
+    ConstructPrimaryBG(vRTracks, Particles, PrimVtx, fCuts2D, fSecCuts, fPrimCandidates, fSecCandidates);
+    
+    for(int iPV=0; iPV<fNPV; iPV++ )
+    {
+      ExtrapolateToPV(fPrimCandidates[0][iPV],PrimVtx[iPV]);
+      ExtrapolateToPV(fPrimCandidates[1][iPV],PrimVtx[iPV]);
+      ExtrapolateToPV(fPrimCandidates[2][iPV],PrimVtx[iPV]);
+      ExtrapolateToPV(fPrimCandidates[3][iPV],PrimVtx[iPV]);
+    }
+    
+    NeutralDaughterDecay(vRTracks, Particles);
+    
+    //Xi- -> Lambda pi-, Omega- -> Lambda K-
+    FindTrackV0Decay(fSecCandidates[1], 3122, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastKaon(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[1]), &fPrimCandidates[5]);
+    //Xi+ -> Lambda pi+, Omega+ -> Lambda K+
+    FindTrackV0Decay(fSecCandidates[2], -3122, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastKaon(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[0]), &fPrimCandidates[6]);
+
+    for(int iPV=0; iPV<fNPV; iPV++ )
+    {
+      ExtrapolateToPV(fPrimCandidates[5][iPV],PrimVtx[iPV]);
+      ExtrapolateToPV(fPrimCandidates[6][iPV],PrimVtx[iPV]);
+      
+      ExtrapolateToPV(fPrimCandidates[7][iPV],PrimVtx[iPV]);
+      ExtrapolateToPV(fPrimCandidates[8][iPV],PrimVtx[iPV]);
+    }
+
+    //K*+ -> K0 pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                      Particles, PrimVtx, iPV, 0);
+    //K*- -> K0 pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                      Particles, PrimVtx, iPV, 0);
+    //Sigma*+ -> Lambda pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[1][iPV], 3122, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                      Particles, PrimVtx, iPV, 0);
+    //Sigma*- -> Lambda pi-, Xi*- -> Lambda K-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[1][iPV], 3122, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastKaon(),
+                      Particles, PrimVtx, iPV, 0);
+    //Sigma*+_bar -> Lambda_bar pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[2][iPV], -3122, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //Sigma*-_bar -> Lambda_bar pi+, Xi*+ -> Lambda_bar + K+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[2][iPV], -3122, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastKaon(),
+                        Particles, PrimVtx, iPV, 0);
+    //Xi*0 -> Xi- pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[5][iPV], 3312, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                        Particles, PrimVtx, iPV, 0, &fPrimCandidates[9]);
+    //Xi*0_bar -> Xi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[6][iPV], -3312, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                        Particles, PrimVtx, iPV, 0, &fPrimCandidates[10]);
+    //Omega*- -> Xi- pi+ K-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[9][iPV], 3324, vRTracks[3], -1, vRTracks[3].FirstKaon(), vRTracks[3].LastKaon(),
+                        Particles, PrimVtx, iPV, 0);
+    //Omega*+ -> Xi+ pi- K+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[10][iPV], -3324, vRTracks[2], 1, vRTracks[2].FirstKaon(), vRTracks[2].LastKaon(),
+                        Particles, PrimVtx, iPV, 0);
+    //Hypernuclei
+    //He4L -> He3 p pi-
+    FindTrackV0Decay(fHe3Pi   , 3004, vRTracks[0],  1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(), Particles, PrimVtx, -1, 0, 0, &fHe4L);
+    //LLn -> H3L pi-
+    FindTrackV0Decay(fHe3Pi   , 3004, vRTracks[1], -1, vRTracks[1].FirstPion(),   vRTracks[1].LastPion(),   Particles, PrimVtx, -1, 0 );
+    //He4L_bar -> He3_bar p- pi+
+    FindTrackV0Decay(fHe3PiBar,-3004, vRTracks[1], -1, vRTracks[1].FirstProton(), vRTracks[1].LastProton(), Particles, PrimVtx, -1, 0);
+    //He5L -> He4 p pi-
+    FindTrackV0Decay(fHe4Pi   , 3005, vRTracks[0],  1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(), Particles, PrimVtx, -1, 0, 0, &fHe5L);
+    //He5L_bar -> He4_bar p- pi+
+    FindTrackV0Decay(fHe4PiBar,-3005, vRTracks[1], -1, vRTracks[1].FirstProton(), vRTracks[1].LastProton(), Particles, PrimVtx, -1, 0);
+    //H4LL -> He4L pi-
+    FindTrackV0Decay(fHe4L    , 3006, vRTracks[1], -1, vRTracks[1].FirstPion(),   vRTracks[1].LastPion(),   Particles, PrimVtx, -1, 0 );
+    //H5LL -> He5L pi-
+    FindTrackV0Decay(fHe5L    , 3007, vRTracks[1], -1, vRTracks[1].FirstPion(),   vRTracks[1].LastPion(),   Particles, PrimVtx, -1, 0 );
+    //H4LL -> H3L p pi-
+    FindTrackV0Decay(fLLn     , 3203, vRTracks[0],  1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(), Particles, PrimVtx, -1, 0 );
+    //He6LL -> He5L p pi-
+    FindTrackV0Decay(fH5LL    , 3010, vRTracks[0],  1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(), Particles, PrimVtx, -1, 0 );
+    // Charm
+    //LambdaC -> pi+ K- p, Ds+ -> pi+ K- K+, D+ -> pi+ K- pi+
+    FindTrackV0Decay(fD0, 421, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastProton(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[0]));
+    //LambdaC_bar -> pi- K+ p-, Ds- -> pi- K+ K-, D- -> pi- K+ pi-
+    FindTrackV0Decay(fD0bar, -421, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastProton(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[1]));    
+    //D0->pi+ K- pi+ pi-
+    FindTrackV0Decay(fDPlus, 411, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastPion(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[1]));
+    //D0_bar->pi- K+ pi- pi+
+    FindTrackV0Decay(fDMinus, -411, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastPion(),
+                    Particles, PrimVtx, -1, &(ChiToPrimVtx[0]));
+    //B+ -> D0_bar pi+, B+ -> D0_bar K+
+    FindTrackV0Decay(fD0bar, -421, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastKaon(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[0]));    
+    //B- -> D0 pi-, B- -> D0 K-
+    FindTrackV0Decay(fD0, 421, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastKaon(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[1]));
+    //B0 -> D- pi+, B0 -> D- K+
+    FindTrackV0Decay(fDMinus, -419, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastKaon(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[0]));    
+    //B0_bar -> D+ pi-, B0_bar -> D+ K-
+    FindTrackV0Decay(fDPlus, 419, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastKaon(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[1]));
+    //D0 -> pi+ K-
+    SelectParticles(Particles,fD0,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D0_bar -> pi+ K-
+    SelectParticles(Particles,fD0bar,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);    
+    //D*+->D0 pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fD0, 421, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //D*- -> D0_bar pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fD0, -421, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //D0 -> pi+ K- pi+ pi-
+    SelectParticles(Particles,fD04,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D0_bar -> pi- K+ pi- pi+
+    SelectParticles(Particles,fD04bar,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D*+->D0 pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fD04, 429, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //D0*- -> D0_bar pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fD04bar, -429, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //D+
+    SelectParticles(Particles,fDPlus,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetDPlusMass(), KFParticleDatabase::Instance()->GetDPlusMassSigma(), fSecCuts[0]);
+    //D-
+    SelectParticles(Particles,fDMinus,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetDPlusMass(), KFParticleDatabase::Instance()->GetDPlusMassSigma(), fSecCuts[0]);
+    //D*0->D+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fDPlus, 411, vRTracks[3], -1, vRTracks[3].FirstPion(), vRTracks[3].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    //D*0_bar->D- pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fDMinus, -411, vRTracks[2], 1, vRTracks[2].FirstPion(), vRTracks[2].LastPion(),
+                        Particles, PrimVtx, iPV, 0);
+    
+    float cutsD0[3] = {fCutsCharm[1], fCutsCharm[2], fCutsCharm[0]};
+//     float cutsD0[3] = {-5, 1e10, 1e10}; 
+    //D0 -> K0 pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fD0pipi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, 425, 0, 1);
+    //D0 -> K0 K+ K-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fD0KK, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, 427, 0, 1);
+    
+    
+    //LambdaC -> p pi+ pi-, Ds+ -> K+ pi+ pi-, D+ -> pi+ pi+ pi-
+    FindTrackV0Decay(fD0pipi, 420, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastProton(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[0]));
+    //LambdaC_bar -> p_bar pi+ pi-, Ds- -> K- pi+ pi-, D- -> pi+ pi- pi-
+    FindTrackV0Decay(fD0pipi, 420, vRTracks[1],-1, vRTracks[1].FirstPion(), vRTracks[1].LastProton(),
+                     Particles, PrimVtx, -1, &(ChiToPrimVtx[1]));
+    
+    //D+ -> K0 pi+ pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDPlus3Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, 200411, 0, 1);
+    //D- -> K0 pi+ pi- pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDMinus3Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, -200411, 0, 1);
+    //Lc+ -> Lambda pi+ pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDPlus3Pi, fPrimCandidates[1][iPV], Particles, PrimVtx, cutsD0, -1, 404122, 0, 1);
+    //Lc- -> Lambda_bar pi+ pi- pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDMinus3Pi, fPrimCandidates[2][iPV], Particles, PrimVtx, cutsD0, -1, -404122, 0, 1);
+    //Xic0 -> Xi- pi+ pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDPlus3Pi, fPrimCandidates[5][iPV], Particles, PrimVtx, cutsD0, -1, 4132, 0, 1);
+    //Xic0_bar -> Xi+ pi+ pi- pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDMinus3Pi, fPrimCandidates[6][iPV], Particles, PrimVtx, cutsD0, -1, -4132, 0, 1);
+    
+    //Ds+ -> K0 K+ pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDsPlusK2Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, 300431, 0, 1);
+    //Ds- -> K0 K- pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fDsMinusK2Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, -300431, 0, 1);
+    
+    //Lc+ -> p K0 pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fLcPlusP2Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, 204122, 0, 1);
+    //Lc- -> p- K0 pi+ pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fLcMinusP2Pi, fPrimCandidates[0][iPV], Particles, PrimVtx, cutsD0, -1, -204122, 0, 1);
+    
+    //D0 -> pi+ pi-
+    SelectParticles(Particles,fD0pipi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D0 -> K+ K-
+    SelectParticles(Particles,fD0KK,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D+ -> pi+ pi+ pi-
+    SelectParticles(Particles,fDPlus3Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetDPlusMass(), KFParticleDatabase::Instance()->GetDPlusMassSigma(), fSecCuts[0]);
+    //D- -> pi+ pi- pi-
+    SelectParticles(Particles,fDMinus3Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetDPlusMass(), KFParticleDatabase::Instance()->GetDPlusMassSigma(), fSecCuts[0]);
+    //Ds+ -> K+ pi+ pi-, 
+    SelectParticles(Particles,fDsPlusK2Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //Ds- -> K- pi+ pi-
+    SelectParticles(Particles,fDsMinusK2Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //LambdaC -> p pi+ pi-
+    SelectParticles(Particles,fLcPlusP2Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //LambdaC_bar -> p_bar pi+ pi-
+    SelectParticles(Particles,fLcMinusP2Pi,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    
+    
+    //D+ -> K0 pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[0],  1, vRTracks[0].FirstPion(), vRTracks[0].LastPion(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[0]) );
+    //D- -> K0 pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastPion(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[1]) );
+    //Ds+ -> K0 K+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[0],  1, vRTracks[0].FirstKaon(), vRTracks[0].LastKaon(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[0]) );
+    //Ds- -> K0 K-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[1], -1, vRTracks[1].FirstKaon(), vRTracks[1].LastKaon(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[1]) );      
+    //Lambdac+ -> Lambda pi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[1][iPV], 3122, vRTracks[0], 1, vRTracks[0].FirstPion(), vRTracks[0].LastPion(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[0]) );
+    //Lambdac_bar- -> Lambda_bar pi-
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[2][iPV], -3122, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastPion(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[1]) );
+    //Lambdac+ -> p K0s
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[0], 1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[0]) );
+    //Lambdac_bar- -> p_bar K0s
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[0][iPV], 310, vRTracks[1], -1, vRTracks[1].FirstProton(), vRTracks[1].LastProton(),
+                       Particles, PrimVtx, -1, &(ChiToPrimVtx[1]) );   
+      
+    //H0 -> Lambda Lambda
+    CombinePartPart(fSecCandidates[1], fSecCandidates[1], Particles, PrimVtx, fCutsPartPart[0], -1, 3000, 1, 1);
+    //H0 -> Lambda p pi-
+    FindTrackV0Decay(fLPi, 3002, vRTracks[0], 1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(),
+                      Particles, PrimVtx, -1);
+    //Sigma0 -> Lambda Gamma
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[3][iPV], fPrimCandidates[1][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 3212);
+    //Sigma0_bar -> Lambda_bar Gamma
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[3][iPV], fPrimCandidates[2][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, -3212);
+    //pi0 -> gamma gamma
+    const float& mPi0 = KFParticleDatabase::Instance()->GetPi0Mass();
+    const float& mPi0Sigma = KFParticleDatabase::Instance()->GetPi0MassSigma();
+    CombinePartPart(fSecCandidates[3], fSecCandidates[3], Particles, PrimVtx, fCutsPartPart[1], -1, 111, 1, 0, &fPrimCandidates[4], &fSecCandidates[4], mPi0, mPi0Sigma);
+    for(int iPV=0; iPV<fNPV; iPV++)
+    {
+      CombinePartPart(fPrimCandidates[3][iPV], fPrimCandidates[3][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 111, 1, 0, &fPrimCandidates[4], &fSecCandidates[4], mPi0, mPi0Sigma);
+      CombinePartPart(fSecCandidates[3],       fPrimCandidates[3][iPV], Particles, PrimVtx, fCutsPartPart[1],  -1, 111, 0, 0, &fPrimCandidates[4], &fSecCandidates[4], mPi0, mPi0Sigma);
+    }
+    for(int iPV=0; iPV<fNPV; iPV++ )
+      ExtrapolateToPV(fPrimCandidates[4][iPV],PrimVtx[iPV]);
+    //eta -> pi0 pi0 pi0
+    //TODO implement this
+    //Sigma+ -> p pi0
+    FindTrackV0Decay(fSecCandidates[4], 111, vRTracks[0],  1, vRTracks[0].FirstProton(), vRTracks[0].LastProton(),
+                      Particles, PrimVtx, -1);
+    //Sigma+_bar -> p- pi0
+    FindTrackV0Decay(fSecCandidates[4], 111, vRTracks[1], -1, vRTracks[1].FirstProton(), vRTracks[1].LastProton(),
+                      Particles, PrimVtx, -1);
+    //Xi0 -> Lambda pi0
+    CombinePartPart(fSecCandidates[4], fSecCandidates[1], Particles, PrimVtx, fCutsPartPart[0], -1, 3322);
+    //Xi0_bar -> Lambda_bar pi0
+    CombinePartPart(fSecCandidates[4], fSecCandidates[2], Particles, PrimVtx, fCutsPartPart[0], -1, -3322);
+    //K*+ -> K+ pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[4][iPV], 111, vRTracks[2],  1, vRTracks[2].FirstKaon(), vRTracks[2].LastKaon(),
+                        Particles, PrimVtx, -1);
+    //K*- -> K- pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      FindTrackV0Decay(fPrimCandidates[4][iPV], 111, vRTracks[3], -1, vRTracks[3].FirstKaon(), vRTracks[3].LastKaon(),
+                        Particles, PrimVtx, -1);
+    //K*0 -> K0 pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[4][iPV], fPrimCandidates[0][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 100313, 0, 1);    
+    //Sigma*0 -> Lambda pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[4][iPV], fPrimCandidates[1][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 3214, 0, 1);       
+    //Sigma*0_bar -> Lambda_bar pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[4][iPV], fPrimCandidates[2][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, -3214, 0, 1);       
+    //Xi*- -> Xi- pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[4][iPV], fPrimCandidates[5][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 3314, 0, 1);   
+    //Xi*+ -> Xi+ pi0
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[4][iPV], fPrimCandidates[6][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, -3314, 0, 1);  
+    //JPsi -> Lambda Lambda_bar
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[1][iPV], fPrimCandidates[2][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 300443, 0, 1);  
+    //JPsi -> Xi- Xi+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[5][iPV], fPrimCandidates[6][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 400443, 0, 1);  
+    //Psi -> Omega- Omega+
+    for(int iPV=0; iPV<fNPV; iPV++)
+      CombinePartPart(fPrimCandidates[7][iPV], fPrimCandidates[8][iPV], Particles, PrimVtx, fCutsPartPart[1], iPV, 500443, 0, 1);  
+    
+    //reconstruct particles with daughters in ElectroMagnetic Calorimeter
+//     if(fEmcClusters)
+//     {
+//       //pi0 -> gamma gamma, EMC
+//       vector< vector<KFParticle> > vPi0PrimEmc(1);
+//       vector<KFParticle> vPi0SecEmc;
+//       vector< vector<KFParticle> > vD0PrimEmc(1);
+//       CombinePartPart(vGammaPrimEmc, vGammaPrimEmc, Particles, PrimVtx, fCutsPartPart[1], 0, 111, 1, 0, &vPi0PrimEmc, &vPi0SecEmc, mPi0, mPi0Sigma);
+//           
+//       //D+ -> K0 pi+
+//       FindTrackV0Decay(fSecCandidates[0],    310, vRTracks[0],  1, vRTracks[0].FirstPion(), vRTracks[0].LastPion(), Particles, PrimVtx, -1/*, &(ChiToPrimVtx[0])*/);
+//       //D0 -> K0 pi+ pi-
+//       FindTrackV0Decay(fK0PiPlus, 100411, vRTracks[1], -1, vRTracks[1].FirstPion(), vRTracks[1].LastPion(), Particles, PrimVtx, -1/*, &(ChiToPrimVtx[0])*/);
+//       //D0 -> K0 pi+ pi- pi0
+//       CombinePartPart(fK0PiPi, vPi0PrimEmc[0], Particles, PrimVtx, fCutsPartPart[1], -1, 428, 0, 0, &vD0PrimEmc, 0, 
+//                       KFParticleDatabase::Instance()->GetD0Mass(), 0.025);
+//       
+//       for(int iPV=0; iPV<1; iPV++ )
+//       {
+//         ExtrapolateToPV(vPi0PrimEmc[iPV],PrimVtx[iPV]);
+//         ExtrapolateToPV(vD0PrimEmc[iPV],PrimVtx[iPV]);
+//       }
+//       //D0* -> D0 pi0
+//       CombinePartPart(vD0PrimEmc[0], vPi0PrimEmc[0], Particles, PrimVtx, fCutsPartPart[1], 0, 10428);
+//     }
+  }
+  else
+  {
+    //D0 -> pi+ K-
+    SelectParticles(Particles,fD0,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+    //D0_bar -> pi+ K-
+    SelectParticles(Particles,fD0bar,PrimVtx,fCutsCharm[2],fCutsCharm[1],
+                    KFParticleDatabase::Instance()->GetD0Mass(), KFParticleDatabase::Instance()->GetD0MassSigma(), fSecCuts[0]);
+  }
+}
+
+void KFParticleFinder::ExtrapolateToPV(vector<KFParticle>& vParticles, KFParticleSIMD& PrimVtx)
+{
+  /** Extrapolates all particles from the input vector to the DCA point with the primary vertex.
+   ** \param[in,out] vParticles - array of particles to be transported.
+   ** \param[in] PrimVtx - the primary vertex, where particles should be transported.
+   **/
+  KFParticle* parts[float_vLen];
+  KFParticle tmpPart[float_vLen];
+  
+  for(int iv=0; iv<float_vLen; iv++)
+    parts[iv] = &tmpPart[iv];
+    
+  for(unsigned int iL=0; iL<vParticles.size(); iL += float_vLen)
+  {
+
+    unsigned int nPart = vParticles.size();
+    unsigned int nEntries = (iL + float_vLen < nPart) ? float_vLen : (nPart - iL);
+
+    
+    for(unsigned int iv=0; iv<nEntries; iv++)
+      tmpPart[iv] = vParticles[iL+iv];
+
+    KFParticleSIMD tmp(parts,nEntries);
+
+    tmp.TransportToPoint(PrimVtx.Parameters());
+
+    for(unsigned int iv=0; iv<nEntries; iv++)
+    {
+      tmp.GetKFParticle(vParticles[iL+iv], iv);
+    }
+  }
+}
+
+inline void KFParticleFinder::ConstructV0(KFPTrackVector* vTracks,
+                                          int iTrTypePos,
+                                          int iTrTypeNeg,
+                                          uint_v& idPosDaughters,
+                                          uint_v& idNegDaughters,
+                                          int_v& daughterPosPDG,
+                                          int_v& daughterNegPDG,
+                                          KFParticleSIMD& mother,
+                                          KFParticle& mother_temp,
+                                          const unsigned short NTracks,
+                                          kfvector_floatv& l,
+                                          kfvector_floatv& dl,
+                                          vector<KFParticle>& Particles,
+                                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                          const float* cuts,
+                                          const int_v& pvIndex,
+                                          const float* secCuts,
+                                          const float_v& massMotherPDG,
+                                          const float_v& massMotherPDGSigma,
+                                          KFParticleSIMD& motherPrimSecCand,
+                                          int& nPrimSecCand,
+                                          vector< vector<KFParticle> >* vMotherPrim,
+                                          vector<KFParticle>* vMotherSec
+                                         )
+{
+  /** Combines two SIMD vectors of particles into 2-daughter candidate.
+   ** \param[in] vRTracks - pointer to the array with vectors of tracks:\n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** \param[in] iTrTypePos - index of the first vector with tracks in the vTracks array.
+   ** \param[in] iTrTypeNeg - index of the second vector with tracks in the vTracks array.
+   ** \param[in] idPosDaughters - indices of particles from the first vector of tracks.
+   ** \param[in] idNegDaughters - indices of particles from the second vector of tracks.
+   ** \param[in] daughterPosPDG - PDG hypothesis of the first SIMD vector of tracks.
+   ** \param[in] daughterNegPDG - PDG hypothesis of the second SIMD vector of tracks.
+   ** \param[out] mother - constructed 2-daughter SIMD-candidate.
+   ** \param[in] mother_temp - temporary object to extract KFParticle from constructed KFParticleSIMD mother. Preallocated for better performance.
+   ** \param[in] NTracks - number of tracks in each SIMD vector.
+   ** \param[in] l - SIMD-vector with extracted distance to the primary vertex. Is preallocated for better performance.
+   ** \param[in] dl - SIMD-vector with extracted error of distance to the primary vertex. Is preallocated for better performance.
+   ** \param[out] Particles - the output array with the reconstructed particle-candidates.
+   ** \param[in] PrimVtx - array with primary vertices.
+   ** \param[in] cuts - set of cuts: \f$\chi^2_{prim}\f$, \f$\chi^2_{geo}\f$, \f$l/\Delta l\f$.
+   ** \param[in] pvIndex - index of the primary vertex for reconstruction of resonances. Tracks should come from the same vertex.
+   ** in case of other particles the value should be "-1".
+   ** \param[in] secCuts - cuts to select primary and secondary candidates from the reconstructed set: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$.
+   ** \param[in] massMotherPDG - PDG table mass for the mother particle, is used for selection of primary and secondary candidates.
+   ** \param[in] massMotherPDGSigma - sigma of the peak width, is used for selection of primary and secondary candidates.
+   ** \param[out] motherPrimSecCand - a SIMD-particle with possible primary and secondary candidates.
+   ** \param[out] nPrimSecCand - number of possible primary and secondary candidates. Can be "0" if no of them are found.
+   ** \param[out] vMotherPrim - array with output primary candidates if any.
+   ** \param[out] vMotherSec - array with output secondary candidates if any.
+   **/
+  float_m isPrimary(simd_cast<float_m>(pvIndex>-1));
+  int_v trackId;
+  KFParticleSIMD posDaughter(vTracks[iTrTypePos],idPosDaughters, daughterPosPDG);
+  trackId.gather( &(vTracks[iTrTypePos].Id()[0]), idPosDaughters );
+  posDaughter.SetId(trackId);
+
+  KFParticleSIMD negDaughter(vTracks[iTrTypeNeg],idNegDaughters, daughterNegPDG);
+  trackId.gather( &(vTracks[iTrTypeNeg].Id()[0]), idNegDaughters );
+  negDaughter.SetId(trackId);   
+#ifdef CBM
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  negDaughter.GetDStoParticle( posDaughter, ds, dsdr );
+  negDaughter.TransportToDS(ds[0], dsdr[0]);
+  posDaughter.TransportToDS(ds[1], dsdr[3]);
+#endif
+  const KFParticleSIMD* vDaughtersPointer[2] = {&negDaughter, &posDaughter};
+  mother.Construct(vDaughtersPointer, 2, 0);
+  
+  float_m saveParticle(simd_cast<float_m>(int_v::IndexesFromZero() < int(NTracks)));
+  float_v chi2Cut = cuts[1];
+  float_v ldlCut  = cuts[2];
+  if( !(simd_cast<float_m>(abs(mother.PDG()) == 421 || abs(mother.PDG()) == 426 || abs(mother.PDG()) == 420)).isEmpty() )
+  {
+    chi2Cut( simd_cast<float_m>(abs(mother.PDG()) == 421 || abs(mother.PDG()) == 426 || abs(mother.PDG()) == 420) ) = fCutsCharm[0];
+    ldlCut( simd_cast<float_m>(abs(mother.PDG()) == 421 || abs(mother.PDG()) == 426 || abs(mother.PDG()) == 420) ) = -1;//fCutsCharm[1];
+  }
+  
+  saveParticle &= (mother.Chi2()/simd_cast<float_v>(mother.NDF()) < chi2Cut );
+  saveParticle &= KFPMath::Finite(mother.GetChi2());
+  saveParticle &= (mother.GetChi2() > 0.0f);
+  saveParticle &= (mother.GetChi2() == mother.GetChi2());
+
+  if( saveParticle.isEmpty() ) return;
+  
+  float_v lMin(1.e8f);
+  float_v ldlMin(1.e8f);
+  float_m isParticleFromVertex(false);
+
+  for(int iP=0; iP<fNPV; iP++)
+  {
+    float_m isParticleFromVertexLocal;
+    mother.GetDistanceToVertexLine(PrimVtx[iP], l[iP], dl[iP], &isParticleFromVertexLocal);
+    isParticleFromVertex |= isParticleFromVertexLocal;
+    float_v ldl = (l[iP]/dl[iP]);
+    lMin( (l[iP] < lMin) && saveParticle) = l[iP];
+    ldlMin( (ldl < ldlMin) && saveParticle) = ldl;
+  }
+
+  saveParticle &= (lMin < 200.f);
+#ifdef NonhomogeneousField  
+  KFParticleSIMD motherTopo;
+    ldlMin = 1.e8f;
+  for(int iP=0; iP<fNPV; iP++)
+  {
+    motherTopo = mother;
+    motherTopo.SetProductionVertex(PrimVtx[iP]);
+    motherTopo.GetDecayLength(l[iP], dl[iP]);
+    float_v ldl = (l[iP]/dl[iP]);
+    ldlMin( (ldl < ldlMin) && saveParticle) = ldl;
+  }
+#endif
+  saveParticle &= ( (float_m(!isPrimary) && ldlMin > ldlCut) || float_m(isPrimary) );
+  
+  saveParticle &= (float_m(!isPrimary) && isParticleFromVertex) || isPrimary;
+  if( saveParticle.isEmpty() ) return;
+  
+  float_m isK0     = saveParticle && simd_cast<float_m>(mother.PDG() == int_v(310));
+  float_m isLambda = saveParticle && simd_cast<float_m>(abs(mother.PDG()) == int_v(3122));
+  float_m isGamma  = saveParticle && simd_cast<float_m>(mother.PDG() == int_v(22));
+  float_m isHyperNuclei = saveParticle && simd_cast<float_m>(abs(mother.PDG()) > 3000 && abs(mother.PDG()) < 3104);
+  
+  saveParticle &= ( ((isK0 || isLambda || isHyperNuclei) && lMin > float_v(fLCut)) || !(isK0 || isLambda || isHyperNuclei) );
+
+  float_m saveMother(false);
+  
+  if( !(isK0.isEmpty()) || !(isLambda.isEmpty()) || !(isGamma.isEmpty()))
+  { 
+    float_v mass, errMass;
+
+    mother.GetMass(mass, errMass);
+    saveMother = saveParticle;
+    saveMother &= (abs(mass - massMotherPDG)/massMotherPDGSigma) < secCuts[0];
+    saveMother &= ((ldlMin > secCuts[2]) && !isGamma) || isGamma;
+    saveMother &= (isK0 || isLambda || isGamma);
+  }
+  
+  for(int iv=0; iv<NTracks; iv++)
+  {
+    if(!saveParticle[iv]) continue;
+  
+    mother.GetKFParticle(mother_temp, iv);
+    int motherId = Particles.size();
+    mother_temp.SetId(Particles.size());
+    if( mother.PDG()[iv] == 421 ) 
+    {
+      fD0.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -421 ) 
+    {
+      fD0bar.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 426 ) 
+    {
+      fD0KK.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 420 ) 
+    {
+      fD0pipi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 3004)
+      fHe3Pi.push_back(mother_temp);
+    if( mother.PDG()[iv] == -3004)
+      fHe3PiBar.push_back(mother_temp);
+    if( mother.PDG()[iv] == 3005)
+      fHe4Pi.push_back(mother_temp);
+    if( mother.PDG()[iv] == -3005)
+      fHe4PiBar.push_back(mother_temp);
+    
+    Particles.push_back(mother_temp);
+    
+    if( mother.PDG()[iv] == 22 && isPrimary[iv] )
+    {
+      float negPt2 = negDaughter.Px()[iv]*negDaughter.Px()[iv] + negDaughter.Py()[iv]*negDaughter.Py()[iv];
+      float posPt2 = posDaughter.Px()[iv]*posDaughter.Px()[iv] + posDaughter.Py()[iv]*posDaughter.Py()[iv];
+
+      if( (negPt2 >fCutLVMPt*fCutLVMPt) && (posPt2 >fCutLVMPt*fCutLVMPt) )
+      {
+        mother_temp.SetPDG(100113);
+        mother_temp.SetId(Particles.size());
+        Particles.push_back(mother_temp);
+        
+        if( (negPt2 >fCutJPsiPt*fCutJPsiPt) && (posPt2 >fCutJPsiPt*fCutJPsiPt) )
+        {
+          mother_temp.SetPDG(443);
+          mother_temp.SetId(Particles.size());
+          Particles.push_back(mother_temp);
+        }
+      }  
+    }
+
+    if( mother.PDG()[iv] == 200113 )
+    {
+      float negPt2 = negDaughter.Px()[iv]*negDaughter.Px()[iv] + negDaughter.Py()[iv]*negDaughter.Py()[iv];
+      float posPt2 = posDaughter.Px()[iv]*posDaughter.Px()[iv] + posDaughter.Py()[iv]*posDaughter.Py()[iv];
+      
+      if( (negPt2 >fCutJPsiPt*fCutJPsiPt) && (posPt2 >fCutJPsiPt*fCutJPsiPt) && (abs(daughterPosPDG[iv]) == 13) && (abs(daughterNegPDG[iv]) == 13))
+      {
+        mother_temp.SetPDG(100443);
+        mother_temp.SetId(Particles.size());
+        Particles.push_back(mother_temp);
+      }  
+    }
+    
+    if(saveMother[iv])
+    {
+      mother.SetId(motherId);
+      motherPrimSecCand.SetOneEntry(nPrimSecCand,mother,iv);
+
+      nPrimSecCand++;
+      if(nPrimSecCand==float_vLen)
+      {
+        SaveV0PrimSecCand(motherPrimSecCand,nPrimSecCand,mother_temp,PrimVtx,secCuts,vMotherPrim,vMotherSec);
+        nPrimSecCand = 0;
+      }
+    }
+  }
+}
+
+inline void KFParticleFinder::SaveV0PrimSecCand(KFParticleSIMD& mother,
+                                                int& NParticles,
+                                                KFParticle& mother_temp,
+                                                std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                                const float* secCuts,
+                                                vector< vector<KFParticle> >* vMotherPrim,
+                                                vector<KFParticle>* vMotherSec)
+{
+  /** The function which decides if primary and secondary candidates found by KFParticleFinder::ConstructV0()
+   ** should be stored and stores them to the provided arrays.
+   ** \param[in] mother - constructed SIMD vector of particle candidates. 
+   ** \param[in] NParticles - number of particles in the SIMD vector.
+   ** \param[in] mother_temp - temporary object to extract KFParticle from constructed KFParticleSIMD mother. Preallocated for better performance.
+   ** \param[in] PrimVtx - array with primary vertices.
+   ** \param[in] secCuts - cuts to select primary and secondary candidates from the reconstructed set: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$.
+   ** \param[out] vMotherPrim - array with output primary candidates if any.
+   ** \param[out] vMotherSec - array with output secondary candidates if any.
+   **/
+  
+  KFParticleSIMD motherTopo;
+  float_v massMotherPDG, massMotherPDGSigma;
+  
+  float_m isSec(false);
+  float_m isPrim(false);
+  vector<int> iPrimVert[float_vLen];
+
+  KFParticleDatabase::Instance()->GetMotherMass(mother.PDG(),massMotherPDG,massMotherPDGSigma);
+  
+  float_m isK0        = simd_cast<float_m>(mother.PDG() == int_v(310));
+  float_m isLambda    = simd_cast<float_m>(abs(mother.PDG()) == int_v(3122));
+  float_m isGamma     = simd_cast<float_m>(mother.PDG() == int_v(22));
+
+  int_v arrayIndex(-1); //for saving primary candidates; 
+
+  arrayIndex(mother.PDG() ==   int_v(310)) = 0;
+  arrayIndex(mother.PDG() ==  int_v(3122)) = 1;
+  arrayIndex(mother.PDG() == int_v(-3122)) = 2;
+  arrayIndex(mother.PDG() ==    int_v(22)) = 3;
+
+  float_m isPrimaryPart(false);
+
+  float_v chi2TopoMin = 1.e4f;
+  
+  for(int iP=0; iP< fNPV; iP++)
+  {
+    motherTopo = mother;
+    motherTopo.SetProductionVertex(PrimVtx[iP]);
+    
+    const float_v& motherTopoChi2Ndf = motherTopo.GetChi2()/simd_cast<float_v>(motherTopo.GetNDF());
+    chi2TopoMin(motherTopoChi2Ndf < chi2TopoMin) = motherTopoChi2Ndf;
+    const float_m isPrimaryPartLocal = ( motherTopoChi2Ndf < secCuts[1] );
+    if(isPrimaryPartLocal.isEmpty()) continue;
+    isPrimaryPart |= isPrimaryPartLocal;
+    for(int iV=0; iV<NParticles; iV++)
+    {
+      if(isPrimaryPartLocal[iV])
+      {
+        motherTopo.GetKFParticle(mother_temp, iV);
+        fPrimCandidatesTopo[arrayIndex[iV]][iP].push_back(mother_temp);
+        iPrimVert[iV].push_back(iP);
+      }
+    }
+    
+    motherTopo.SetNonlinearMassConstraint(massMotherPDG);
+    for(int iV=0; iV<NParticles; iV++)
+    {
+      if(isPrimaryPartLocal[iV])
+      {
+        motherTopo.GetKFParticle(mother_temp, iV);
+        fPrimCandidatesTopoMass[arrayIndex[iV]][iP].push_back(mother_temp);
+      }
+    }
+  }
+  
+  isPrim |= ( ( isPrimaryPart ) && (isK0 || isLambda || isGamma) );
+#ifdef __ROOT__
+  isSec  |= ( (!isPrimaryPart ) && (isK0 || isLambda || isGamma) && (chi2TopoMin < float_v(500.f)) );
+#else
+  isSec  |= ( (!isPrimaryPart ) && (isK0 || isLambda || isGamma) );
+#endif
+  
+  mother.SetNonlinearMassConstraint(massMotherPDG);
+
+  for(int iv=0; iv<NParticles; iv++)
+  { 
+    if(isPrim[iv] || isSec[iv])
+    {  
+      mother.GetKFParticle(mother_temp, iv);
+      
+      if(isPrim[iv] )
+      {
+        for(unsigned int iP = 0; iP<iPrimVert[iv].size(); iP++)
+          vMotherPrim[arrayIndex[iv]][iPrimVert[iv][iP]].push_back(mother_temp);
+      }
+      
+      if(isSec[iv] )
+        vMotherSec[arrayIndex[iv]].push_back(mother_temp);
+    }
+  }
+}
+
+void KFParticleFinder::Find2DaughterDecay(KFPTrackVector* vTracks, kfvector_float* ChiToPrimVtx,
+                                          vector<KFParticle>& Particles,
+                                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                          const float* cuts,
+                                          const float* secCuts,
+                                          vector< vector<KFParticle> >* vMotherPrim,
+                                          vector<KFParticle>* vMotherSec )
+{
+  /** Reconstructs all 2-daughter decays.
+   ** \param[in] vRTracks - pointer to the array with vectors of tracks:\n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** \param[in] ChiToPrimVtx - arrays with vectors of the \f$\chi^2_{prim}\f$ deviations for track vectors 1) and 2).
+   ** \param[out] Particles - output vector with particles.
+   ** \param[in] PrimVtx - vector with primary vertices.
+   ** \param[in] cuts - set of cuts: \f$\chi^2_{prim}\f$, \f$\chi^2_{geo}\f$, \f$l/\Delta l\f$.
+   ** \param[in] secCuts - cuts to select primary and secondary candidates from the reconstructed set: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$.
+   ** \param[out] vMotherPrim - array with output primary candidates.
+   ** \param[out] vMotherSec - array with output secondary candidates.
+   **/
+  KFParticle mother_temp;
+  KFParticleSIMD mother;
+  kfvector_floatv l(fNPV), dl(fNPV);
+
+  KFParticleSIMD daughterNeg, daughterPos;
+    
+  // for secondary V0
+  unsigned int nBufEntry = 0;
+  uint_v idNegDaughters;
+  uint_v idPosDaughters;
+  int_v daughterPosPDG(-1);
+  int_v daughterNegPDG(-1);
+    
+  int_v pvIndexMother(-1);
+  
+  float_v massMotherPDG(Vc::Zero), massMotherPDGSigma(Vc::Zero);
+  int_v V0PDG(Vc::Zero);
+
+  KFParticleSIMD motherPrimSecCand;
+  int nPrimSecCand =0;
+  
+  int trTypeIndexPos[2] = {0,2};
+  int trTypeIndexNeg[2] = {1,3};
+
+  for( int iTrTypeNeg = 0; iTrTypeNeg<2; iTrTypeNeg++)
+  {
+    KFPTrackVector& negTracks = vTracks[ trTypeIndexNeg[iTrTypeNeg] ];
+    
+    for(int iTrTypePos=0; iTrTypePos<2; iTrTypePos++)
+    {
+      KFPTrackVector& posTracks = vTracks[ trTypeIndexPos[iTrTypePos] ];
+      int_v negTracksSize = negTracks.Size();
+      int nPositiveTracks = posTracks.Size();
+      
+      //track categories
+      int nTC = 5;
+      int startTCPos[5] = {0};
+      int endTCPos[5] = {0};
+      int startTCNeg[5] = {0};
+      int endTCNeg[5] = {0};
+      
+      if((iTrTypeNeg == 0) && (iTrTypePos == 0))
+      {
+        // Secondary particles
+        nTC = 5;
+        // e-
+        startTCPos[0] = 0; endTCPos[0] = nPositiveTracks; //posTracks.LastElectron();
+        startTCNeg[0] = 0; endTCNeg[0] = negTracksSize[0];  //negTracks.LastElectron(); 
+        //mu-
+        startTCPos[1] = 0; endTCPos[1] = 0;
+        startTCNeg[1] = 0; endTCNeg[1] = 0; 
+        //pi- + ghosts
+        startTCPos[2] = posTracks.FirstPion(); endTCPos[2] = nPositiveTracks;
+        startTCNeg[2] = negTracks.FirstPion(); endTCNeg[2] = negTracks.LastPion();        
+        //K-
+        startTCPos[3] = posTracks.FirstPion(); endTCPos[3] = posTracks.LastKaon();
+        startTCNeg[3] = negTracks.FirstKaon(); endTCNeg[3] = negTracks.LastKaon();  
+        //p-, d-, t-, he3-, he4-
+        startTCPos[4] = posTracks.FirstPion(); endTCPos[4] = posTracks.LastPion();
+        startTCNeg[4] = negTracks.FirstProton(); endTCNeg[4] = negTracksSize[0];  
+      }
+      
+      if( iTrTypeNeg != iTrTypePos )
+      {
+        //Mixed particles - only gamma -> e+ e-
+        nTC = 1;
+        startTCPos[0] = 0; endTCPos[0] = nPositiveTracks; //posTracks.LastElectron();
+        startTCNeg[0] = 0; endTCNeg[0] = negTracksSize[0];  //negTracks.LastElectron(); 
+      }
+      
+      if((iTrTypeNeg == 1) && (iTrTypePos == 1))
+      {
+        //primary particles
+        nTC = 5;
+        // e-
+        startTCPos[0] = 0; endTCPos[0] = nPositiveTracks; //posTracks.LastElectron();
+        startTCNeg[0] = 0; endTCNeg[0] = negTracksSize[0];  //negTracks.LastElectron(); 
+        //mu-
+        startTCPos[1] = posTracks.FirstMuon(); endTCPos[1] = posTracks.LastMuon();
+        startTCNeg[1] = negTracks.FirstMuon(); endTCNeg[1] = negTracks.LastMuon(); 
+        //pi- + ghosts
+        startTCPos[2] = posTracks.FirstPion(); endTCPos[2] = posTracks.LastProton();
+        startTCNeg[2] = negTracks.FirstPion(); endTCNeg[2] = negTracks.LastPion();        
+        //K-
+        startTCPos[3] = posTracks.FirstPion(); endTCPos[3] = nPositiveTracks;
+        startTCNeg[3] = negTracks.FirstKaon(); endTCNeg[3] = negTracks.LastKaon();  
+        //p-
+        startTCPos[4] = posTracks.FirstPion(); endTCPos[4] = posTracks.LastProton();
+        startTCNeg[4] = negTracks.FirstProton(); endTCNeg[4] = negTracks.LastProton();      
+      }
+      
+      for(int iTC=0; iTC<nTC; iTC++)
+      {
+        for(int iTrN=startTCNeg[iTC]; iTrN < endTCNeg[iTC]; iTrN += float_vLen)
+        {
+          const int NTracksNeg = (iTrN + float_vLen < negTracks.Size()) ? float_vLen : (negTracks.Size() - iTrN);
+
+          int_v negInd = int_v::IndexesFromZero() + int(iTrN);
+
+          int_v negPDG = reinterpret_cast<const int_v&>(negTracks.PDG()[iTrN]);
+          int_v negPVIndex = reinterpret_cast<const int_v&>(negTracks.PVIndex()[iTrN]);
+          int_v negNPixelHits = reinterpret_cast<const int_v&>(negTracks.NPixelHits()[iTrN]);
+          
+          int_v trackPdgNeg = negPDG;
+          int_m activeNeg = (negPDG != -1);
+#ifdef CBM          
+          if( !((negPDG == -1).isEmpty()) )
+          {
+            trackPdgNeg(negPVIndex<0 && (negPDG == -1) ) = -211;
+                
+            activeNeg |= int_m(negPVIndex < 0) && int_m(negPDG == -1) ;
+          }
+#endif    
+          activeNeg &= (int_v::IndexesFromZero() < int(NTracksNeg));
+              
+          daughterNeg.Load(negTracks, iTrN, negPDG);
+                
+          float_v chiPrimNeg(Vc::Zero);
+          float_v chiPrimPos(Vc::Zero);
+          
+          if( (iTrTypeNeg == 0) && (iTrTypePos == 0) )
+            chiPrimNeg = reinterpret_cast<const float_v&>( ChiToPrimVtx[trTypeIndexNeg[iTrTypeNeg]][iTrN]);
+          
+          for(int iTrP=startTCPos[iTC]; iTrP < endTCPos[iTC]; iTrP += float_vLen)
+          {
+            const int NTracks = (iTrP + float_vLen < nPositiveTracks) ? float_vLen : (nPositiveTracks - iTrP);
+
+            const int_v& posPDG = reinterpret_cast<const int_v&>(posTracks.PDG()[iTrP]);
+            const int_v& posPVIndex = reinterpret_cast<const  int_v&>(posTracks.PVIndex()[iTrP]);     
+            const int_v& posNPixelHits = reinterpret_cast<const int_v&>(posTracks.NPixelHits()[iTrP]);
+            const int_m& isPosSecondary = (posPVIndex < 0);
+
+            daughterPos.Load(posTracks, iTrP, posPDG);
+            
+            if( (iTrTypeNeg == 0) && (iTrTypePos == 0) )
+              chiPrimPos = reinterpret_cast<const float_v&>( ChiToPrimVtx[trTypeIndexPos[iTrTypePos]][iTrP]);
+            
+            for(int iRot = 0; iRot<float_vLen; iRot++)
+            {
+//               if(iRot>0)
+              {
+                negPDG = negPDG.rotated(1);
+                negPVIndex = negPVIndex.rotated(1);
+                negNPixelHits = negNPixelHits.rotated(1);
+                negInd = negInd.rotated(1);
+                trackPdgNeg = trackPdgNeg.rotated(1);
+              
+                daughterNeg.Rotate();
+                chiPrimNeg = chiPrimNeg.rotated(1);
+
+                activeNeg = ( (negPDG != -1) || ( (negPVIndex < 0) && (negPDG == -1) ) ) && (negInd < negTracksSize);
+              }
+              const int_m& isSecondary = int_m( negPVIndex < 0 ) && isPosSecondary;
+              const int_m& isPrimary   = int_m( negPVIndex >= 0 ) && (!isPosSecondary);
+            
+              float_m closeDaughters = simd_cast<float_m>(activeNeg && (int_v::IndexesFromZero() < int_v(NTracks)));
+              
+              if(closeDaughters.isEmpty() && (iTC != 0)) continue;
+              
+              
+              int_v trackPdgPos[2];
+              int_m active[2];
+
+              active[0] = (posPDG != -1);
+              active[0] &= ((isPrimary && (posPVIndex == negPVIndex)) || !(isPrimary));
+
+              active[1] = int_m(false);
+              
+              trackPdgPos[0] = posPDG;
+#ifdef CBM
+              int nPDGPos = 2;
+              if( (posPDG == -1).isEmpty() && (posPDG > 1000000000).isEmpty() && (posPDG == 211).isEmpty() )
+              {
+                nPDGPos = 1;
+              }
+              else
+              {
+                trackPdgPos[0](isSecondary && posPDG == -1) = 211;
+                trackPdgPos[1] = 2212;
+                
+                active[0] |= isSecondary && int_m(posPDG == -1);
+                active[1]  = isSecondary && (int_m(posPDG == -1) || (posPDG > 1000000000) || (posPDG == 211));
+              }
+#else
+              int nPDGPos = 1;
+#endif
+              active[0] &= simd_cast<int_m>(closeDaughters);
+              active[1] &= simd_cast<int_m>(closeDaughters);
+              
+              if(iTC==0) 
+              {
+                nPDGPos = 1;
+                active[0] = (negInd < negTracksSize) && (int_v::IndexesFromZero() < int_v(NTracks));
+              }
+
+              for(int iPDGPos=0; iPDGPos<nPDGPos; iPDGPos++)
+              {
+                if(active[iPDGPos].isEmpty()) continue;
+                
+                //detetrmine a pdg code of the mother particle
+                
+                int_v motherPDG(-1);
+                
+                if(!fMixedEventAnalysis)
+                {
+                  if(iTC==0)
+                  {
+                    motherPDG( (abs(trackPdgPos[iPDGPos]) == 11) || int_m(abs(trackPdgNeg) == 11) || isSecondary ) = 22; //gamma -> e+ e-
+                  }
+                  else if(iTC==1)
+                  {
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])== 13 || abs(trackPdgPos[iPDGPos])==19)
+                                           && (int_m(abs(trackPdgNeg) == 13) || int_m(abs(trackPdgNeg) == 19)) ) =   200113; //rho -> mu+ mu-
+                  }
+                  else if(iTC==2)
+                  {
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==        211) && int_m(abs(trackPdgNeg) ==  211) ) =   310; //K0 -> pi+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==       2212) && int_m(abs(trackPdgNeg) ==  211) ) =  3122; //Lambda -> p+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])== 1000010020) && int_m(abs(trackPdgNeg) ==  211) ) =  3003; //LambdaN -> d+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])== 1000010030) && int_m(abs(trackPdgNeg) ==  211) ) =  3103; //LambdaNN -> t+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])== 1000020030) && int_m(abs(trackPdgNeg) ==  211) ) =  3004; //H3Lambda -> He3+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])== 1000020040) && int_m(abs(trackPdgNeg) ==  211) ) =  3005; //H4Lambda -> He4+ pi-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==        321) && int_m(abs(trackPdgNeg) ==  211) ) =  -421; //D0_bar -> pi- K+
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==        321) && int_m(abs(trackPdgNeg) ==  211) ) =   313; //K*0 -> K+ pi-
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==        211) && int_m(abs(trackPdgNeg) ==  211) ) =   113; //rho -> pi+ pi-
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==       2212) && int_m(abs(trackPdgNeg) ==  211) ) =  2114; //Delta0 -> p pi-
+                  }
+                  else if(iTC==3)
+                  {
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) ==  321) ) =   421; //D0 -> pi+ K-
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  321) && int_m(abs(trackPdgNeg) ==  321) ) =   426; //D0 -> K+ K-
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) ==  321) ) =  -313; //K*0_bar -> K- pi+
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])== 2212) && int_m(abs(trackPdgNeg) ==  321) ) =  3124; //Lambda* -> p K-
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==  321) && int_m(abs(trackPdgNeg) ==  321) ) =   333; //phi -> K+ K-
+                  }
+                  else if(iTC==4)
+                  {
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) ==       2212) ) =  -3122; //Lambda_bar -> p- pi+
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) == 1000010020) ) =  -3003; //LambdaN_bar -> d- pi+
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) == 1000010030) ) =  -3103; //LambdaNN_bar -> t- pi+
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) == 1000020030) ) =  -3004; //H3Lambda_bar -> He3- pi+
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) == 1000020040) ) =  -3005; //H4Lambda_bar -> He4- pi+
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==  321) && int_m(abs(trackPdgNeg) ==       2212) ) =  -3124; //Lambda*_bar -> p- K+
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])== 2212) && int_m(abs(trackPdgNeg) ==       2212) ) = 200443; //JPsi -> p- p
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) ==       2212) ) =  -2114; //Delta0_bar -> p- pi+
+                  }
+                }
+                else
+                {
+                  if(iTC==0)
+                    motherPDG(                (abs(trackPdgPos[iPDGPos])==   11) && int_m(abs(trackPdgNeg) ==   11) ) =    22; //gamma -> e+ e-
+                  else if(iTC==1)
+                    motherPDG( isPrimary   && (abs(trackPdgPos[iPDGPos])== 13 || abs(trackPdgPos[iPDGPos])==19)
+                                           && (int_m(abs(trackPdgNeg) == 13) || int_m(abs(trackPdgNeg) == 19)) ) =   200113; //rho -> mu+ mu-
+                  else if(iTC==2)
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==        321) && int_m(abs(trackPdgNeg) ==  211) ) =  -421; //D0_bar -> pi- K+
+                  else if(iTC==3)
+                    motherPDG( isSecondary && (abs(trackPdgPos[iPDGPos])==  211) && int_m(abs(trackPdgNeg) ==  321) ) =   421; //D0 -> pi+ K-
+                }
+                
+                if( (iTrTypeNeg == 0) && (iTrTypePos == 0) )
+                {
+                  float_v chiprimCut = fCuts2D[0];
+                  chiprimCut( simd_cast<float_m>(abs(motherPDG) == 421 || abs(motherPDG) == 426) ) = fCutCharmChiPrim;
+                  active[iPDGPos] &= simd_cast<int_m>(chiPrimNeg > chiprimCut && chiPrimPos > chiprimCut);
+                }
+                
+                active[iPDGPos] &= (motherPDG != -1);
+                if(!(fDecayReconstructionList.empty()))
+                {
+                  for(int iV=0; iV<float_vLen; iV++)
+                  {
+                    if(!(active[iPDGPos][iV])) continue;
+                    if(fDecayReconstructionList.find(motherPDG[iV]) == fDecayReconstructionList.end())
+                      motherPDG[iV] = -1;
+                  }
+                  active[iPDGPos] &= (motherPDG != -1);
+                }
+                if(active[iPDGPos].isEmpty()) continue;
+
+                if(!( (iTrTypePos == 1) && (iTrTypeNeg == 1) ) )
+                {
+                  float_v dS[2];
+                  daughterNeg.GetDStoParticleFast( daughterPos, dS );   
+                  float_v negParameters[8], posParameters[8];
+                  daughterNeg.TransportFast( dS[0], negParameters ); 
+                  daughterPos.TransportFast( dS[1], posParameters ); 
+                  float_v dx = negParameters[0]-posParameters[0]; 
+                  float_v dy = negParameters[1]-posParameters[1]; 
+                  float_v dz = negParameters[2]-posParameters[2];
+                  float_v dr = sqrt(dx*dx+dy*dy+dz*dz);
+
+                  active[iPDGPos] &= simd_cast<int_m>(dr < float_v(fDistanceCut));
+                  if(active[iPDGPos].isEmpty()) continue;
+                  
+                  float_v p1p2 = posParameters[3]*negParameters[3] + posParameters[4]*negParameters[4] + posParameters[5]*negParameters[5];
+                  float_v p12  = posParameters[3]*posParameters[3] + posParameters[4]*posParameters[4] + posParameters[5]*posParameters[5];
+                  float_v p22  = negParameters[3]*negParameters[3] + negParameters[4]*negParameters[4] + negParameters[5]*negParameters[5];
+                  active[iPDGPos] &= simd_cast<int_m>(p1p2 > -p12);
+                  active[iPDGPos] &= simd_cast<int_m>(p1p2 > -p22);
+                }
+                
+                const float_v& ptNeg2 = daughterNeg.Px()*daughterNeg.Px() + daughterNeg.Py()*daughterNeg.Py();
+                const float_v& ptPos2 = daughterPos.Px()*daughterPos.Px() + daughterPos.Py()*daughterPos.Py();
+                if( !((abs(motherPDG) == 421 || abs(motherPDG) == 426).isEmpty()) )
+                {
+                  active[iPDGPos] &= ( (abs(motherPDG) == 421 || abs(motherPDG) == 426) && 
+                                      simd_cast<int_m>(ptNeg2 >= fCutCharmPt*fCutCharmPt) && 
+                                      simd_cast<int_m>(ptPos2 >= fCutCharmPt*fCutCharmPt) &&
+                                      simd_cast<int_m>(chiPrimNeg > fCutCharmChiPrim) && simd_cast<int_m>(chiPrimPos > fCutCharmChiPrim) &&
+                                      int_m(negNPixelHits >= int_v(3)) && int_m(posNPixelHits >= int_v(3)) )
+                                    || (!(abs(motherPDG) == 421 || abs(motherPDG) == 426));
+                }
+                
+                if(active[iPDGPos].isEmpty()) continue;
+
+                for(int iV=0; iV<float_vLen; iV++)
+                {
+                  if(!(active[iPDGPos][iV])) continue;
+                  
+
+                  idPosDaughters[nBufEntry] = iTrP+iV;
+                  idNegDaughters[nBufEntry] = negInd[iV];
+                  
+                  daughterPosPDG[nBufEntry] = trackPdgPos[iPDGPos][iV];
+                  daughterNegPDG[nBufEntry] = trackPdgNeg[iV];
+                  
+                  if(motherPDG[iV] == 22)
+                  {
+                    daughterPosPDG[nBufEntry] = -11;
+                    daughterNegPDG[nBufEntry] =  11;
+                  }
+                  
+                  pvIndexMother[nBufEntry] = isPrimary[iV] ? negPVIndex[iV] : -1;
+                  
+                  if( iTrTypeNeg != iTrTypePos ) pvIndexMother[nBufEntry] = 0;
+                  
+                  V0PDG[nBufEntry] = motherPDG[iV];
+                  
+                  nBufEntry++;
+
+                  if(int(nBufEntry) == float_vLen)
+                  {
+                    KFParticleDatabase::Instance()->GetMotherMass(V0PDG,massMotherPDG,massMotherPDGSigma);
+                    mother.SetPDG( V0PDG );
+                    ConstructV0(vTracks, trTypeIndexPos[iTrTypePos], trTypeIndexNeg[iTrTypeNeg],                
+                                idPosDaughters, idNegDaughters, daughterPosPDG, daughterNegPDG,
+                                mother, mother_temp,
+                                nBufEntry, l, dl, Particles, PrimVtx,
+                                cuts, pvIndexMother, secCuts, massMotherPDG,
+                                massMotherPDGSigma, motherPrimSecCand, nPrimSecCand, vMotherPrim, vMotherSec);
+                    nBufEntry = 0; 
+                  }
+                  
+                  //TODO optimize this part of code for D-mesons
+                  if(motherPDG[iV] == 310 && 
+                     (fDecayReconstructionList.empty() ||
+                      (!(fDecayReconstructionList.empty()) && !(fDecayReconstructionList.find(420) == fDecayReconstructionList.end()) ) ) &&
+                     negNPixelHits[iV] >= 3 && posNPixelHits[iV] >= 3 &&
+                     chiPrimNeg[iV] > fCutCharmChiPrim && chiPrimPos[iV] > fCutCharmChiPrim &&
+                     ptNeg2[iV] >= fCutCharmPt*fCutCharmPt && ptPos2[iV] >= fCutCharmPt*fCutCharmPt )
+                  {
+                    idPosDaughters[nBufEntry] = iTrP+iV;
+                    idNegDaughters[nBufEntry] = negInd[iV];
+                    
+                    daughterPosPDG[nBufEntry] = trackPdgPos[iPDGPos][iV];
+                    daughterNegPDG[nBufEntry] = trackPdgNeg[iV];
+                    
+                    pvIndexMother[nBufEntry] = isPrimary[iV] ? negPVIndex[iV] : -1;
+                    
+                    V0PDG[nBufEntry] = 420;
+                    
+                    nBufEntry++;
+
+                    if(int(nBufEntry) == float_vLen)
+                    {
+                      KFParticleDatabase::Instance()->GetMotherMass(V0PDG,massMotherPDG,massMotherPDGSigma);
+                      mother.SetPDG( V0PDG );
+                      ConstructV0(vTracks, trTypeIndexPos[iTrTypePos], trTypeIndexNeg[iTrTypeNeg],                
+                                  idPosDaughters, idNegDaughters, daughterPosPDG, daughterNegPDG,
+                                  mother, mother_temp,
+                                  nBufEntry, l, dl, Particles, PrimVtx,
+                                  cuts, pvIndexMother, secCuts, massMotherPDG,
+                                  massMotherPDGSigma, motherPrimSecCand, nPrimSecCand, vMotherPrim, vMotherSec);
+                      nBufEntry = 0; 
+                    }
+                  }
+                  
+                }//iV
+              }//iPDGPos
+            }//iRot
+          }//iTrP
+        }//iTrN
+        
+        if( nBufEntry>0 )
+        {
+          for(int iV=nBufEntry; iV<float_vLen; iV++)
+          {
+            idPosDaughters[iV] = idPosDaughters[0];
+            idNegDaughters[iV] = idNegDaughters[0];
+          }
+
+          KFParticleDatabase::Instance()->GetMotherMass(V0PDG,massMotherPDG,massMotherPDGSigma);
+          mother.SetPDG( V0PDG );
+
+          ConstructV0(vTracks, trTypeIndexPos[iTrTypePos], trTypeIndexNeg[iTrTypeNeg],              
+                      idPosDaughters, idNegDaughters, daughterPosPDG, daughterNegPDG,
+                      mother, mother_temp,
+                      nBufEntry, l, dl, Particles, PrimVtx,
+                      cuts, pvIndexMother, secCuts, massMotherPDG,
+                      massMotherPDGSigma, motherPrimSecCand, nPrimSecCand, vMotherPrim, vMotherSec);
+          nBufEntry = 0; 
+        }
+        
+        if(nPrimSecCand>0)
+        {
+          SaveV0PrimSecCand(motherPrimSecCand,nPrimSecCand,mother_temp,PrimVtx,secCuts,vMotherPrim,vMotherSec);
+          nPrimSecCand = 0;
+        }
+      }//iTC
+    }//iTrTypeNeg
+  }//iTrTypePos
+}
+
+void KFParticleFinder::ConstructPrimaryBG(KFPTrackVector* vTracks,
+                                          vector<KFParticle>& Particles,
+                                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                          const float* cuts,
+                                          const float* secCuts,
+                                          vector< vector<KFParticle> >* vMotherPrim,
+                                          vector<KFParticle>* vMotherSec )
+{
+  /** Constructs same-sign background candidates for 2-daughter resonances.
+   ** \param[in] vRTracks - pointer to the array with vectors of tracks:\n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** \param[out] Particles - the output array with the reconstructed particle-candidates.
+   ** \param[in] PrimVtx - vector with primary vertices.
+   ** \param[in] cuts - set of cuts: \f$\chi^2_{prim}\f$, \f$\chi^2_{geo}\f$, \f$l/\Delta l\f$.
+   ** \param[in] secCuts - cuts to select primary and secondary candidates from the reconstructed set: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$.
+   ** \param[out] vMotherPrim - array with output primary candidates. Is provided for consistency with KFParticleFinder::ConstructV0().
+   ** \param[out] vMotherSec - array with output secondary candidates. Is provided for consistency with KFParticleFinder::ConstructV0().
+   **/
+  KFParticle mother_temp;
+  KFParticleSIMD mother;
+  kfvector_floatv l(fNPV), dl(fNPV);
+
+  KFParticleSIMD daughterNeg, daughterPos;
+
+  // for secondary V0
+  unsigned int nBufEntry = 0;
+  float_v dS;
+  uint_v idNegDaughters;
+  uint_v idPosDaughters;
+  int_v daughterPosPDG(-1);
+  int_v daughterNegPDG(-1);
+    
+  int_v pvIndexMother(-1);
+  
+  float_v massMotherPDG(Vc::Zero), massMotherPDGSigma(Vc::Zero);
+  int_v V0PDG(Vc::Zero);
+
+  KFParticleSIMD motherPrimSecCand;
+  int nPrimSecCand =0;
+  
+  for(int iSet=2; iSet<4; iSet++)
+  {
+    int signPDG = 1;
+    if(iSet == 3)
+      signPDG = -1;
+    
+    KFPTrackVector& positivePrimaryTracks = vTracks[iSet];
+    int nPositiveTracks = positivePrimaryTracks.Size();
+
+    for(int iTrN = positivePrimaryTracks.FirstPion(); iTrN < positivePrimaryTracks.LastProton(); iTrN += float_vLen)
+    {
+      int_v negPDG = positivePrimaryTracks.PDG()[iTrN];
+      int_v negPVIndex = positivePrimaryTracks.PVIndex()[iTrN];
+      
+      int_m activeNeg = (negPDG != -1);
+
+      for(int iTrP = iTrN+1; iTrP < positivePrimaryTracks.LastProton(); iTrP += float_vLen)
+      {
+        const int NTracks = (iTrP + float_vLen < nPositiveTracks) ? float_vLen : (nPositiveTracks - iTrP);
+
+        int_v posPDG(0); // = reinterpret_cast<const int_v&>(positivePrimaryTracks.PDG()[iTrP]);
+        int_v posPVIndex(0); // = reinterpret_cast<const  int_v&>(positivePrimaryTracks.PVIndex()[iTrP]);              
+        for(int iV=0; iV<NTracks; iV++)
+        {
+          posPDG[iV] = positivePrimaryTracks.PDG()[iTrP+iV];
+          posPVIndex[iV] = positivePrimaryTracks.PVIndex()[iTrP+iV];
+        }
+
+        int_m active = (activeNeg && (int_v::IndexesFromZero() < int_v(NTracks)));
+        if(active.isEmpty()) continue;
+        
+        active &= (posPDG != int_v(-1));
+        active &= (posPVIndex == negPVIndex);
+        
+        if(active.isEmpty()) continue;
+        
+        //detetrmine a pdg code of the mother particle
+        
+        int_v motherPDG(-1);
+        
+        motherPDG( (abs(posPDG)==  211) && int_m(abs(negPDG) ==  211) ) = signPDG*9001; //pi+pi+
+        motherPDG( (abs(posPDG)==  321) && int_m(abs(negPDG) ==  211) ) = signPDG*9002; //pi+K+
+        motherPDG( (abs(posPDG)==  211) && int_m(abs(negPDG) ==  321) ) = signPDG*9002; //pi+K+
+        motherPDG( (abs(posPDG)==  211) && int_m(abs(negPDG) == 2212) ) = signPDG*2224; //pi+p
+        motherPDG( (abs(posPDG)== 2212) && int_m(abs(negPDG) ==  211) ) = signPDG*2224; //pi+p
+        motherPDG( (abs(posPDG)==  321) && int_m(abs(negPDG) ==  321) ) = signPDG*9003; //K+K+
+        motherPDG( (abs(posPDG)==  321) && int_m(abs(negPDG) == 2212) ) = signPDG*9004; //K+p
+        motherPDG( (abs(posPDG)== 2212) && int_m(abs(negPDG) ==  321) ) = signPDG*9004; //K+p
+        
+        active &= (motherPDG != -1);
+        if(!(fDecayReconstructionList.empty()))
+        {
+          for(int iV=0; iV<float_vLen; iV++)
+          {
+            if(!(active[iV])) continue;
+            if(fDecayReconstructionList.find(motherPDG[iV]) == fDecayReconstructionList.end())
+              motherPDG[iV] = -1;
+          }
+          active &= (motherPDG != -1);
+        }
+        if(active.isEmpty()) continue;
+
+        
+        if(active.isEmpty()) continue;
+
+        for(int iV=0; iV<NTracks; iV++)
+        {
+          if(!(active[iV])) continue;
+          
+          idPosDaughters[nBufEntry] = iTrP+iV;
+          idNegDaughters[nBufEntry] = iTrN;
+          
+          daughterPosPDG[nBufEntry] = posPDG[iV];
+          daughterNegPDG[nBufEntry] = negPDG[iV];
+          
+          pvIndexMother[nBufEntry] = negPVIndex[iV];
+          
+          V0PDG[nBufEntry] = motherPDG[iV];
+          
+          nBufEntry++;
+
+          if(int(nBufEntry) == float_vLen)
+          {
+            KFParticleDatabase::Instance()->GetMotherMass(V0PDG,massMotherPDG,massMotherPDGSigma);
+            mother.SetPDG( V0PDG );
+            ConstructV0(vTracks, iSet, iSet,                
+                        idPosDaughters, idNegDaughters, daughterPosPDG, daughterNegPDG,
+                        mother, mother_temp,
+                        nBufEntry, l, dl, Particles, PrimVtx,
+                        cuts, pvIndexMother, secCuts, massMotherPDG,
+                        massMotherPDGSigma, motherPrimSecCand, nPrimSecCand, vMotherPrim, vMotherSec);
+            nBufEntry = 0; 
+          }
+        }//iV
+      }//iTrP
+          
+      if( nBufEntry>0 )
+      {
+        for(int iV=nBufEntry; iV<float_vLen; iV++)
+        {
+          idPosDaughters[iV] = idPosDaughters[0];
+          idNegDaughters[iV] = idNegDaughters[0];
+        }
+
+        KFParticleDatabase::Instance()->GetMotherMass(V0PDG,massMotherPDG,massMotherPDGSigma);
+        mother.SetPDG( V0PDG );
+
+        ConstructV0(vTracks, iSet, iSet,              
+                    idPosDaughters, idNegDaughters, daughterPosPDG, daughterNegPDG,
+                    mother, mother_temp,
+                    nBufEntry, l, dl, Particles, PrimVtx,
+                    cuts, pvIndexMother, secCuts, massMotherPDG,
+                    massMotherPDGSigma, motherPrimSecCand, nPrimSecCand, vMotherPrim, vMotherSec);
+        nBufEntry = 0; 
+      }
+      
+      if(nPrimSecCand>0)
+      {
+        SaveV0PrimSecCand(motherPrimSecCand,nPrimSecCand,mother_temp,PrimVtx,secCuts,vMotherPrim,vMotherSec);
+        nPrimSecCand = 0;
+      }
+    }
+  }
+}
+
+void KFParticleFinder::ConstructTrackV0Cand(KFPTrackVector& vTracks,
+                                            uint_v& idTracks,
+                                            int_v& trackPDG,
+                                            KFParticle* vV0[],
+                                            KFParticleSIMD& mother,
+                                            std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& motherTopo,
+                                            KFParticle& mother_temp,
+                                            const unsigned short nElements,
+                                            kfvector_floatv& l,
+                                            kfvector_floatv& dl,
+                                            std::vector<KFParticle>& Particles,
+                                            std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                            const float_v* cuts,
+                                            const int_v& pvIndex,
+                                            const float_v& massMotherPDG,
+                                            const float_v& massMotherPDGSigma,
+                                            std::vector< std::vector<KFParticle> >* vMotherPrim,
+                                            std::vector<KFParticle>* vMotherSec)
+{
+  /** Constructs a candidate from a track and already reconstructed particle candidate.
+   ** \param[in] vTracks - vector with tracks.
+   ** \param[in] idTracks - indices of particles from the vector of tracks.
+   ** \param[in] trackPDG - PDG hypothesis of the SIMD vector of tracks.
+   ** \param[in] vV0 - array with already reconstructed particle candidate with the size of SIMD vector.
+   ** \param[out] mother - constructed 2-daughter SIMD-candidate.
+   ** \param[in] motherTopo - preallocated SIMD vector for topological constraint for better performance.
+   ** \param[in] mother_temp - temporary object to extract KFParticle from constructed KFParticleSIMD mother. Preallocated for better performance.
+   ** \param[in] nElements - number of elements in each SIMD vector.
+   ** \param[in] l - SIMD-vector with extracted distance to the primary vertex. Is preallocated for better performance.
+   ** \param[in] dl - SIMD-vector with extracted error of distance to the primary vertex. Is preallocated for better performance.
+   ** \param[out] Particles - the output array with the reconstructed particle-candidates.
+   ** \param[in] PrimVtx - array with primary vertices.
+   ** \param[in] cuts - set of cuts: \f$l/\Delta l\f$, \f$\chi^2_{topo}\f$, \f$\chi^2_{geo}\f$.
+   ** \param[in] pvIndex - index of the primary vertex for reconstruction of resonances. Tracks should come from the same vertex.
+   ** in case of other particles the value should be "-1".
+   ** \param[in] massMotherPDG - PDG table mass for the mother particle, is used for selection of primary and secondary candidates.
+   ** \param[in] massMotherPDGSigma - sigma of the peak width, is used for selection of primary and secondary candidates.
+   ** \param[out] vMotherPrim - array with output primary candidates if any. If pointer is set to NULL - not filled.
+   ** \param[out] vMotherSec - array with output secondary candidates if any. If pointer is set to NULL - not filled.
+   **/
+  
+  float_m isPrimary(simd_cast<float_m>(pvIndex>-1));
+  
+  int_v trackId( &(vTracks.Id()[0]), idTracks );
+  KFParticleSIMD V0(vV0,nElements);
+  KFParticleSIMD track(vTracks, idTracks, trackPDG);
+  track.SetId(trackId);
+    
+  float_m isSameParticle = simd_cast<float_m>((abs(mother.PDG()) ==    int_v(4122)) ||
+                                              (abs(mother.PDG()) ==  int_v(114122)) ||
+                                              (abs(mother.PDG()) ==  int_v(204122)) ||
+                                              (abs(mother.PDG()) ==  int_v(504122)) ||
+                                              (abs(mother.PDG()) ==  int_v(404122)) ||
+                                              (abs(mother.PDG()) ==     int_v(425)) ||
+                                              (abs(mother.PDG()) ==     int_v(427)) ||
+                                              (abs(mother.PDG()) ==  int_v(200411)) ||
+                                              (abs(mother.PDG()) ==  int_v(300411)) ||
+                                              (abs(mother.PDG()) ==  int_v(300431)) ||
+                                              (abs(mother.PDG()) ==  int_v(400431)) ||
+                                              (abs(mother.PDG()) ==     int_v(411)) ||
+                                              (abs(mother.PDG()) ==     int_v(431)) ||
+                                              (abs(mother.PDG()) ==     int_v(429)) ||
+                                              (abs(mother.PDG()) == int_v(1003334)) ||
+                                              (abs(mother.PDG()) ==    int_v(3001)) ||
+                                              (abs(mother.PDG()) ==    int_v(3006)) ||
+                                              (abs(mother.PDG()) ==    int_v(3007)) ||
+                                              (abs(mother.PDG()) ==    int_v(3009)) ||
+                                              (abs(mother.PDG()) ==    int_v(3011)) );
+  if( isSameParticle.isEmpty() )
+  {
+#ifdef CBM
+    float_v ds[2] = {0.f,0.f};
+    float_v dsdr[4][6];
+    track.GetDStoParticle( V0, ds, dsdr );
+    track.TransportToDS(ds[0], dsdr[0]);
+    V0.TransportToDS(ds[1], dsdr[3]);
+#endif
+    const KFParticleSIMD* vDaughtersPointer[2] = {&track, &V0};
+    mother.Construct(vDaughtersPointer, 2, 0);
+  }
+  else
+  {
+    int_v motherPDG = mother.PDG();
+    mother = V0;
+    mother.SetPDG(motherPDG);
+    track.TransportToPoint(V0.Parameters());
+    mother += track;
+  }
+
+  float_m active = simd_cast<float_m>(int_v::IndexesFromZero() < int(nElements));
+  
+  float_m saveParticle(active);
+  saveParticle &= (mother.Chi2()/simd_cast<float_v>(mother.NDF()) < cuts[2] );
+  saveParticle &= KFPMath::Finite(mother.GetChi2());
+  saveParticle &= (mother.GetChi2() > 0.0f);
+  saveParticle &= (mother.GetChi2() == mother.GetChi2());
+
+  if( saveParticle.isEmpty() ) { return; }
+
+  int_m isSameTrack(false);
+  for(unsigned int iD=0; iD<V0.DaughterIds().size(); iD++)
+    isSameTrack |= ( int_v(V0.DaughterIds()[iD]) == int_v(trackId) );
+  
+  saveParticle &= ( !simd_cast<float_m>(isSameTrack));
+  if( saveParticle.isEmpty() ) { return; }        
+      
+  float_v lMin(1.e8f);
+  float_v ldlMin(1.e8f);
+  float_m isParticleFromVertex(false);
+
+  for(int iP=0; iP<fNPV; iP++)
+  {
+    float_m isParticleFromVertexLocal;
+    mother.GetDistanceToVertexLine(PrimVtx[iP], l[iP], dl[iP], &isParticleFromVertexLocal);
+    isParticleFromVertex |= isParticleFromVertexLocal;
+    float_v ldl = (l[iP]/dl[iP]);
+    lMin( (l[iP] < lMin) && active) = l[iP];
+    ldlMin( (ldl < ldlMin) && active) = ldl;
+  }
+  saveParticle &= (lMin < 200.f);
+  saveParticle &= ((float_m(!isPrimary) && isParticleFromVertex) || float_m(isPrimary) );
+  if( saveParticle.isEmpty() ) { return; }
+
+  isSameParticle = isSameParticle || isPrimary;
+  if(!((isSameParticle).isFull()))
+  {
+    float_m isParticleFromVertexLocal;
+    float_v l1, dl1;
+    V0.GetDistanceToVertexLine(mother, l1, dl1, &isParticleFromVertexLocal);
+    
+    saveParticle &= ( isSameParticle || ((!isSameParticle) && isParticleFromVertexLocal));
+    if( saveParticle.isEmpty() ) { return; }
+  }
+
+  saveParticle &= ( (float_m(!isPrimary) && ldlMin > cuts[0]) || float_m(isPrimary) );
+
+  int_m setLCut = abs(mother.PDG()) == 3312 || abs(mother.PDG()) == 3334 || abs(mother.PDG()) == 3001;
+  saveParticle &= ( (simd_cast<float_m>(setLCut) && lMin > float_v(fLCut)) || simd_cast<float_m>(!setLCut) );
+
+  ldlMin = 1.e8f;
+  for(int iP=0; iP<fNPV; iP++)
+  {
+    motherTopo[iP] = mother;
+    motherTopo[iP].SetProductionVertex(PrimVtx[iP]);
+    motherTopo[iP].GetDecayLength(l[iP], dl[iP]);
+    float_v ldl = (l[iP]/dl[iP]);
+    ldlMin( (ldl < ldlMin) && active) = ldl;
+  }
+                       
+  vector<int> iPrimVert[float_vLen];
+  float_m isPrimaryPart(false);
+
+  for(int iP=0; iP<fNPV; iP++)
+  {
+    const float_v& motherTopoChi2Ndf = motherTopo[iP].GetChi2()/simd_cast<float_v>(motherTopo[iP].GetNDF());
+    const float_m isPrimaryPartLocal = ( motherTopoChi2Ndf < cuts[1] );
+    isPrimaryPart |= isPrimaryPartLocal;
+    for(int iV=0; iV<float_vLen; iV++)
+    {
+      if(isPrimaryPartLocal[iV])
+        iPrimVert[iV].push_back(iP);
+    }
+  }
+            
+  for(unsigned int iv=0; iv<nElements; iv++)
+  {
+    if(!saveParticle[iv]) continue; 
+    
+    mother.GetKFParticle(mother_temp, iv);
+    if( mother.PDG()[iv] == 3312 )
+    {
+      fLPi.push_back(mother_temp);
+      fLPiPIndex.push_back( V0.DaughterIds()[1][iv] );
+    }
+    
+//     if(  mother.PDG()[iv] == 100411 )
+//     {
+//       fK0PiPlus.push_back(mother_temp);
+//       fK0PiMinusIndex.push_back( V0.DaughterIds()[0][iv] );
+//       continue;
+//     }
+    
+    //TODO check if needed with current implementation
+    // reset daughter ids for 3- and 4-particle decays
+    if( (abs(mother.PDG()[iv]) == 411)  ||
+        (abs(mother.PDG()[iv]) == 429) ||
+        (abs(mother.PDG()[iv]) == 431)  ||
+        (abs(mother.PDG()[iv]) == 4122) ||
+        (abs(mother.PDG()[iv]) == 114122) ||
+        (abs(mother.PDG()[iv]) == 204122) ||
+        (abs(mother.PDG()[iv]) == 314122) ||
+        (abs(mother.PDG()[iv]) == 404122) ||
+        (abs(mother.PDG()[iv]) == 504122) ||
+        (abs(mother.PDG()[iv]) == 425) ||
+        (abs(mother.PDG()[iv]) == 427) ||
+        (abs(mother.PDG()[iv]) == 200411) ||
+        (abs(mother.PDG()[iv]) == 300411) ||
+        (abs(mother.PDG()[iv]) == 300431) ||
+        (abs(mother.PDG()[iv]) == 400431) ||
+        (abs(mother.PDG()[iv]) == 1003334) ||
+        (abs(mother.PDG()[iv]) == 3001) )
+    {
+      mother_temp.CleanDaughtersId();
+      for(int iD=0; iD < vV0[iv]->NDaughters(); iD++)
+        mother_temp.AddDaughterId( vV0[iv]->DaughterIds()[iD] );
+      mother_temp.AddDaughterId(trackId[iv]);
+    }
+    
+    if( mother.PDG()[iv] == 411 ) 
+    {
+      fDPlus.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -411 ) 
+    {
+      fDMinus.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 300411 ) 
+    {
+      fDPlus3Pi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -300411 ) 
+    {
+      fDMinus3Pi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 400431 ) 
+    {
+      fDsPlusK2Pi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -400431 ) 
+    {
+      fDsMinusK2Pi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == 504122 ) 
+    {
+      fLcPlusP2Pi.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -504122 ) 
+    {
+      fLcMinusP2Pi.push_back(mother_temp);
+      continue;
+    }
+//     if( mother.PDG()[iv] == 427 )
+//     {
+//       fK0PiPi.push_back(mother_temp);
+//       continue;
+//     }
+    
+    if( mother.PDG()[iv] == 429 ) 
+    {
+      fD04.push_back(mother_temp);
+      continue;
+    }
+    if( mother.PDG()[iv] == -429 ) 
+    {
+      fD04bar.push_back(mother_temp);
+      continue;
+    }
+    
+    if( mother.PDG()[iv] == 3203 ) 
+      fLLn.push_back(mother_temp);
+    if( mother.PDG()[iv] == 3010 ) 
+      fH5LL.push_back(mother_temp);
+    
+    mother_temp.SetId(Particles.size());
+
+    if(!(isPrimaryPart[iv]))
+    {
+      if( vMotherSec )
+      {
+        float mass, errMass;
+        mother_temp.GetMass(mass, errMass);
+        if(abs(mother.PDG()[iv]) == 3324)
+        {
+          vMotherSec->push_back(mother_temp);
+        }
+        else
+        {    
+          if( (fabs(mass - massMotherPDG[iv])/massMotherPDGSigma[iv]) <= 3 )
+          {
+            KFParticle mother_sec = mother_temp;
+            mother_sec.SetNonlinearMassConstraint(massMotherPDG[iv]);
+            vMotherSec->push_back(mother_temp);
+          }
+        }
+      }
+      if(!(mother.PDG()[iv] == 3006 || mother.PDG()[iv] == 3007))
+        continue;
+    }
+    
+    //check Ds+ and Lc+ candidates not to be D+
+//     if(abs(mother_temp.GetPDG())==431 || abs(mother_temp.GetPDG())==4122)
+//     {
+//       KFPTrack dPionTrack;
+//       vTracks.GetTrack(dPionTrack, idTracks[iv]);
+//       KFParticle dPion(dPionTrack, 211);
+//       
+//       KFParticle dMeson = *vV0[iv];
+//       dMeson += dPion;
+//       float dMass, dMassError;
+//       dMeson.GetMass(dMass, dMassError);
+//       if(fabs(dMass - KFParticleDatabase::Instance()->GetDPlusMass())/KFParticleDatabase::Instance()->GetDPlusMassSigma() < 3) continue;
+//     }
+    
+    if(abs(mother.GetPDG()[iv]) == 521 || abs(mother.GetPDG()[iv]) == 529 || abs(mother.GetPDG()[iv]) == 511 || abs(mother.GetPDG()[iv]) == 519)
+    {
+      KFParticle daughter_temp = *vV0[iv];
+      float massPDG = KFParticleDatabase::Instance()->GetDPlusMass();
+      float massSigmaPDG = KFParticleDatabase::Instance()->GetDPlusMassSigma();
+      if(abs(mother.GetPDG()[iv]) == 521 || abs(mother.GetPDG()[iv]) == 529)
+      {
+        massPDG = KFParticleDatabase::Instance()->GetD0Mass();
+        massSigmaPDG = KFParticleDatabase::Instance()->GetD0MassSigma();
+      }
+      float mass, dm;
+      daughter_temp.GetMass(mass,dm);
+      if( (fabs(mass - massPDG)/massSigmaPDG) > 3 ) continue;
+      
+//       KFParticleSIMD daughter_tempSIMD(daughter_temp);
+//       daughter_tempSIMD.SetProductionVertex(PrimVtx[0]);
+//       if(daughter_tempSIMD.GetChi2()[0]/daughter_tempSIMD.GetNDF()[0] < 3. ) continue;
+      
+      daughter_temp.SetId(Particles.size());
+      daughter_temp.SetPDG(-1);
+      mother_temp.SetId(Particles.size()+1);
+      mother_temp.CleanDaughtersId();
+      mother_temp.AddDaughterId(Particles.size());
+      mother_temp.AddDaughterId(trackId[iv]);
+      Particles.push_back(daughter_temp);
+    }
+    Particles.push_back(mother_temp);
+
+    if( abs(mother.GetPDG()[iv]) == 3334 ) //Omega-
+    {
+      float mass, errMass;
+      mother_temp.GetMass(mass, errMass);
+      
+      vector< vector<KFParticle> >* motherVector = &fPrimCandidates[7];
+      if( mother.GetPDG()[iv] == 3334 )
+        motherVector = &fPrimCandidates[8];
+        
+      mother_temp.SetNonlinearMassConstraint(massMotherPDG[iv]);
+
+      if( (fabs(mass - massMotherPDG[iv])/massMotherPDGSigma[iv]) <= 3 )
+        for(unsigned int iP=0; iP<iPrimVert[iv].size(); iP++)
+          (*motherVector)[iPrimVert[iv][iP]].push_back(mother_temp);
+    }
+    
+    if(vMotherPrim)
+    {
+      if( !((abs(mother.GetPDG()[iv]) == 3312) || (abs(mother.GetPDG()[iv]) == 3324))) continue;
+      float mass, errMass;
+
+      mother_temp.GetMass(mass, errMass);
+      if(abs(mother.PDG()[iv]) == 3324)
+      {
+        for(unsigned int iP=0; iP<iPrimVert[iv].size(); iP++)
+          (*vMotherPrim)[iPrimVert[iv][iP]].push_back(mother_temp);
+      }
+      else
+      {
+        mother_temp.SetNonlinearMassConstraint(massMotherPDG[iv]);
+
+        if( (fabs(mass - massMotherPDG[iv])/massMotherPDGSigma[iv]) <= 3 )
+          for(unsigned int iP=0; iP<iPrimVert[iv].size(); iP++)
+            (*vMotherPrim)[iPrimVert[iv][iP]].push_back(mother_temp);
+      }
+    }
+  }
+}
+
+void KFParticleFinder::FindTrackV0Decay(vector<KFParticle>& vV0,
+                                        const int V0PDG,
+                                        KFPTrackVector& vTracks,
+                                        const int q,
+                                        const int firstTrack,
+                                        const int lastTrack,
+                                        vector<KFParticle>& Particles,    
+                                        std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                        int v0PVIndex,
+                                        kfvector_float* ChiToPrimVtx,
+                                        vector< vector<KFParticle> >* vMotherPrim,
+                                        vector<KFParticle>* vMotherSec)
+{
+  /** Combines tracks and already reconstructed particle candidate of certain type in the next candidate.
+   ** \param[in] vV0 - the input vector with already reconstructed particle candidate.
+   ** \param[in] V0PDG - PDG code of the provided particle candidates.
+   ** \param[in] vTracks - vector with input tracks.
+   ** \param[in] q - charge of the provided tracks.
+   ** \param[in] firstTrack - index of the first track to be used.
+   ** \param[in] lastTrack - index of the last track to be used.
+   ** \param[out] Particles - the output array with the reconstructed particle-candidates.
+   ** \param[in] PrimVtx - array with primary vertices.
+   ** \param[in] v0PVIndex - index of the corresponding primary vertex if the tracks are primary. If not "-1" should be set.
+   ** \param[in] ChiToPrimVtx - vector with the \f$\chi^2_{prim}\f$ deviations for provided tracks. If tracks are primary NULL pointer is provided.
+   ** \param[out] vMotherPrim - array with output primary candidates.
+   ** \param[out] vMotherSec - array with output secondary candidates.
+   **/
+  
+  if( (vV0.size() < 1) || ((lastTrack-firstTrack) < 1) ) return;
+  KFParticle mother_temp;
+
+  KFParticle* v0Pointer[float_v::Size];
+
+  KFParticleSIMD mother, track;
+  std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> > motherTopo(fNPV);
+
+  kfvector_floatv l(fNPV), dl(fNPV);
+
+  float_v cuts[3];
+
+  // for secondary V0
+  unsigned int nBufEntry = 0;
+  float_v dS;
+  uint_v idTrack;
+  int_v trackPDGMother(-1);
+    
+  int_v pvIndexMother(-1);
+  
+  float_v massMotherPDG(Vc::Zero), massMotherPDGSigma(Vc::Zero);
+  int_v motherParticlePDG(Vc::Zero);
+//   Particles.reserve(Particles.size() + vV0.size());
+
+  bool isCharm = ((abs(V0PDG) == 421) || (abs(V0PDG) == 411) || (abs(V0PDG) == 429) || (abs(V0PDG) == 420) || (abs(V0PDG) == 419)) && (v0PVIndex<0);
+
+  for(unsigned int iV0=0; iV0 < vV0.size(); iV0++)
+  {    
+    int iNegDaughter = vV0[iV0].DaughterIds()[0];
+    int iPosDaughter = vV0[iV0].DaughterIds()[1];
+    
+    for(int iTr=firstTrack; iTr < lastTrack; iTr += float_vLen)
+    {
+      const int NTracks = (iTr + float_vLen < lastTrack) ? float_vLen : (lastTrack - iTr);
+
+      const int_v& trackPDG = reinterpret_cast<const int_v&>(vTracks.PDG()[iTr]);
+      const int_v& trackPVIndex = reinterpret_cast<const  int_v&>(vTracks.PVIndex()[iTr]);
+      
+      const int_m& isTrackSecondary = (trackPVIndex < 0);
+      const int_m& isSecondary = int_m( v0PVIndex < 0 ) && isTrackSecondary;
+      const int_m& isPrimary   = int_m( v0PVIndex >= 0 ) && (!isTrackSecondary);
+      const int_m& isSamePV = (isPrimary && (v0PVIndex == trackPVIndex)) || !(isPrimary);
+
+      float_m closeDaughters = simd_cast<float_m>(isSamePV) && simd_cast<float_m>(int_v::IndexesFromZero() < int(NTracks));
+
+//       if(v0PVIndex < 0)
+//       {
+//         KFParticleSIMD v0(vV0[iV0]);
+//         track.Load(vTracks, iTr, trackPDG);
+     
+//         float_v dsV0, dsTrack;
+//         float_v dsdrV0[6] = {0.f,0.f,0.f,0.f,0.f,0.f}; 
+//         float_v dsdrTrack[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+//         float_v par1[8], cov1[36], par2[8], cov2[36];
+//         v0.GetDStoParticle(track, dsV0, dsTrack);
+//         v0.Transport(dsV0, dsdrV0, par1, cov1);
+//         track.Transport(dsTrack, dsdrTrack, par2, cov2);
+//   
+//         const float_v& dx = par1[0] - par2[0];
+//         const float_v& dy = par1[1] - par2[1];
+//         const float_v& dz = par1[2] - par2[2];
+//         const float_v& r2 = dx*dx + dy*dy + dz*dz;
+//         
+//         const float_v vtx[3] = {(par1[0] + par2[0])/2.f,
+//                                 (par1[1] + par2[1])/2.f,
+//                                 (par1[2] + par2[2])/2.f, };
+// 
+//         v0.CorrectErrorsOnS(par1, vtx, cov1);
+//         track.CorrectErrorsOnS(par2, vtx, cov2);
+//         
+//         const float_v cov[6] = {cov1[0]+cov2[0],
+//                                 cov1[1]+cov2[1],
+//                                 cov1[2]+cov2[2],
+//                                 cov1[3]+cov2[3],
+//                                 cov1[4]+cov2[4],
+//                                 cov1[5]+cov2[5] };
+//         const float_v& err2 = cov[0]*dx*dx + cov[2]*dy*dy + cov[5]*dz*dz + 2.f*( cov[1]*dx*dy + cov[3]*dx*dz + cov[4]*dy*dz );
+//                 
+//         closeDaughters &= ( (r2 < float_v(1.f)) && (r2*r2/err2) < float_v(3.f) && isSecondary);
+//         closeDaughters &= v0.GetDeviationFromParticle(track) < float_v(10.f);
+//       }
+      
+      if(v0PVIndex < 0)
+      {
+        KFParticleSIMD v0(vV0[iV0]);
+        track.Load(vTracks, iTr, trackPDG);
+        closeDaughters &= v0.GetDistanceFromParticle(track) < float_v(fDistanceCut);
+        if(closeDaughters.isEmpty()) continue;
+      }
+      
+      int_v trackPdgPos[2];
+      int_m active[2];
+
+      int nPDGPos = 2;
+      
+      active[0] = simd_cast<int_m>(closeDaughters);
+      active[1] = (trackPDG == -1) && isSecondary && simd_cast<int_m>(closeDaughters);
+      
+      trackPdgPos[0] = trackPDG;
+      
+      if( (trackPDG == -1).isEmpty() || (abs(V0PDG) ==  421) || (abs(V0PDG) ==  411) )
+      {
+        nPDGPos = 1;
+      }
+      else
+      {
+        trackPdgPos[0](trackPDG == -1) = q*211;
+        nPDGPos = 1;//TODO
+        trackPdgPos[1](isSecondary) = q*321;
+      }
+
+      for(int iPDGPos=0; iPDGPos<nPDGPos; iPDGPos++)
+      {
+        
+        if(active[iPDGPos].isEmpty()) continue;
+        
+        //detetrmine a pdg code of the mother particle
+        
+        int_v motherPDG(-1);
+        
+        if( V0PDG == 3122 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) =  3312;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  304122;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  321) ) =  3334;
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] ==  211) ) =  3224; 
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  3114;
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] == -321) ) =   1003314; 
+        }
+        else if( V0PDG == -3122 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) = -3312;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -304122;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  321) ) = -3334;
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  -3224; 
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] ==   211) ) =  -3114;
+          motherPDG( isPrimary   && int_m(trackPdgPos[iPDGPos] ==  321) ) =  -1003314; 
+        }
+        else if( V0PDG == 310)
+        {
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  323; 
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  -323; 
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==   211) ) =  100411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  -211) ) = -100411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==   321) ) =  100431;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  -321) ) = -100431;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  2212) ) =  104122;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -2212) ) = -104122;
+        }
+        else if( V0PDG == 3312 )
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  3324; 
+        else if( V0PDG == -3312)
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] == -211) ) = -3324; 
+        else if( V0PDG == 3324 )
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] == -321) ) =  1003334; 
+        else if( V0PDG == -3324 )
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  321) ) = -1003334;         
+        else if(V0PDG ==  421)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  321) ) =  431;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 2212) ) =  4122;
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isDMeson = isSecondary && int_m(trackPdgPos[iPDGPos] ==  211);
+          active[iPDGPos] &= (!(isDMeson)) || (isDMeson && ( id > iPosDaughter) );
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) =  -521;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -321) ) =  -529;          
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==   211) ) =   10411; 
+        }
+        else if(V0PDG == -421)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -321) ) = -431;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==-2212) ) = -4122;
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isDMeson = isSecondary && int_m(trackPdgPos[iPDGPos] == -211);
+          active[iPDGPos] &= (!(isDMeson)) || (isDMeson && ( id > iNegDaughter) );
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) = 521;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  321) ) = 529;
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  -10411; 
+        }
+        else if(V0PDG == 420 && q>0)
+        {
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  211) ) =  300411;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  321) ) =  400431;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) == 2212) ) =  504122;
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isDMeson = isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  211);
+          active[iPDGPos] &= (!(isDMeson)) || (isDMeson && ( id > iPosDaughter) );
+        }
+        else if(V0PDG == 420 && q<0)
+        {
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  211) ) =  -300411;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  321) ) =  -400431;
+          motherPDG( isSecondary && int_m(abs(trackPdgPos[iPDGPos]) == 2212) ) =  -504122;
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isDMeson = isSecondary && int_m(abs(trackPdgPos[iPDGPos]) ==  211);
+          active[iPDGPos] &= (!(isDMeson)) || (isDMeson && ( id > iNegDaughter) );
+        }
+        else if(V0PDG == 411)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = 429;
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  -211) ) =   10421; 
+        }
+        else if(V0PDG == -411)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) = -429;
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==   211) ) =  -10421; 
+        }
+        else if(V0PDG == 419)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -511;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -321) ) = -519;
+        }
+        else if(V0PDG == -419)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 211) ) =  511;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 321) ) =  519;
+        }
+        else if(V0PDG == 429)      
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==   211) ) =   20411; 
+        else if(V0PDG == -429)
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  -20411; 
+        else if( V0PDG == 3002 )
+        {
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isSameProton = (id == fLPiPIndex[iV0]);
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 2212) && (!isSameProton)) =  3001; 
+        }
+        else if( V0PDG == 100411 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) =  425;           
+        }
+        else if( V0PDG == 100431 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -321) ) =  427;
+        }
+        else if( V0PDG == 425)
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  200411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -200411;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  321) ) =  300431;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -321) ) = -300431;
+        }
+        else if( V0PDG == 111 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 2212) ) =  3222; 
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -2212) ) =  -3222; 
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] == 321) ) =  100323; 
+          motherPDG( isPrimary && int_m(trackPdgPos[iPDGPos] == -321) ) =  -100323; 
+        }
+        else if( V0PDG == 3004 )
+        {
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  2212) ) =  3006;
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  -211) ) =  3203; 
+        }
+        else if( V0PDG == -3004 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -2212) ) = -3006; 
+        else if( V0PDG == 3005 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  2212) ) =  3007; 
+        else if( V0PDG == -3005 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -2212) ) = -3007;
+        else if( V0PDG == 3006 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = 3008; 
+        else if( V0PDG == 3007 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = 3010; 
+        else if( V0PDG == 3203 )
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 2212) ) = 3009;
+        else if( V0PDG == 3010 )
+        {
+          const int_v& id = reinterpret_cast<const int_v&>(vTracks.Id()[iTr]);
+          int_m isSameProton = (id == Particles[vV0[iV0].DaughterIds()[1]].DaughterIds()[2]);
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == 2212) && (!isSameProton)) = 3011;
+        }
+        else if(V0PDG ==  304122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  314122;
+        else if(V0PDG == -304122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -314122;          
+        else if(V0PDG ==  314122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) =  404122;
+        else if(V0PDG == -314122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) = -404122;
+        else if(V0PDG ==  104122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) =  114122;
+        else if(V0PDG == -104122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) = -114122;
+        else if(V0PDG ==  114122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] == -211) ) =  204122;
+        else if(V0PDG == -114122)
+          motherPDG( isSecondary && int_m(trackPdgPos[iPDGPos] ==  211) ) = -204122;
+        
+        active[iPDGPos] &= (motherPDG != -1);
+        if(!(fDecayReconstructionList.empty()))
+        {
+          for(int iV=0; iV<float_vLen; iV++)
+          {
+            if(!(active[iPDGPos][iV])) continue;
+            if(fDecayReconstructionList.find(motherPDG[iV]) == fDecayReconstructionList.end())
+              motherPDG[iV] = -1;
+          }
+          active[iPDGPos] &= (motherPDG != -1);
+        }
+        if(ChiToPrimVtx)
+          active[iPDGPos] &= ( !( (abs(motherPDG) == 3334 || abs(motherPDG) == 3312 ) ) ||
+                             ( (abs(motherPDG) == 3334 || abs(motherPDG) == 3312 ) && simd_cast<int_m>(reinterpret_cast<const float_v&>((*ChiToPrimVtx)[iTr]) > float_v(fCuts2D[0])) ) );
+        
+        if(active[iPDGPos].isEmpty()) continue;
+        
+        if(isCharm)
+        {
+          track.Load(vTracks, iTr, trackPDG);
+          const float_v& trackPt = track.Px()*track.Px() + track.Py()*track.Py();
+          const int_v& nPixelHits = reinterpret_cast<const int_v&>(vTracks.NPixelHits()[iTr]);
+          
+          active[iPDGPos] &= simd_cast<int_m>(trackPt >= fCutCharmPt*fCutCharmPt) && simd_cast<int_m>(reinterpret_cast<const float_v&>((*ChiToPrimVtx)[iTr]) > fCutCharmChiPrim ) && int_m(nPixelHits >= int_v(3));
+        }
+        {
+          int_m isCharmParticle = (abs(motherPDG) == 104122) ||
+                                  (abs(motherPDG) == 204122) ||
+                                  (abs(motherPDG) == 304122) ||
+                                  (abs(motherPDG) == 404122) ||
+                                  (abs(motherPDG) ==    425) ||
+                                  (abs(motherPDG) ==    426) ||
+                                  (abs(motherPDG) ==    427) ||
+                                  (abs(motherPDG) == 100411) ||
+                                  (abs(motherPDG) == 200411) ||
+                                  (abs(motherPDG) == 100431) ||
+                                  (abs(motherPDG) == 300431) ;
+                 
+          if(!(isCharmParticle.isEmpty()))
+          {
+            track.Load(vTracks, iTr, trackPDG);
+            const float_v& trackPt = track.Px()*track.Px() + track.Py()*track.Py();
+            const int_v& nPixelHits = reinterpret_cast<const int_v&>(vTracks.NPixelHits()[iTr]);
+            
+            active[iPDGPos] &= ( (simd_cast<int_m>(trackPt >= fCutCharmPt*fCutCharmPt) && simd_cast<int_m>(reinterpret_cast<const float_v&>((*ChiToPrimVtx)[iTr]) > fCutCharmChiPrim ) && (nPixelHits >= int_v(3)) ) && isCharmParticle ) || (!isCharmParticle);
+          }
+        }
+        
+        for(int iV=0; iV<NTracks; iV++)
+        {
+          if(!(active[iPDGPos][iV])) continue;
+          
+
+          idTrack[nBufEntry] = iTr+iV;
+          v0Pointer[nBufEntry] = &vV0[iV0];
+          
+          trackPDGMother[nBufEntry] = trackPdgPos[iPDGPos][iV];
+          
+          pvIndexMother[nBufEntry] = v0PVIndex;
+          
+          float massMother, massMotherSigma;
+          KFParticleDatabase::Instance()->GetMotherMass(motherPDG[iV],massMother,massMotherSigma);
+
+          massMotherPDG[nBufEntry] = massMother;
+          massMotherPDGSigma[nBufEntry] = massMotherSigma;
+          motherParticlePDG[nBufEntry] = motherPDG[iV];
+                    
+          int motherType = 0;
+
+          switch (abs(motherPDG[iV]))
+          {
+            case   3312: motherType = 0; break; //Xi
+            case   3334: motherType = 0; break; //Omega
+            case   4122: motherType = 1; break; //LambdaC
+            case 104122: motherType = 1; break; //LambdaC
+            case 304122: motherType = 1; break; //LambdaC
+            case 504122: motherType = 1; break; //LambdaC
+            case    425: motherType = 1; break; //D0
+            case    426: motherType = 1; break; //D0
+            case    427: motherType = 1; break; //D0
+            case 100411: motherType = 1; break; //D+
+            case 300411: motherType = 1; break; //D+
+            case 100431: motherType = 1; break; //Ds+
+            case 400431: motherType = 1; break; //Ds+
+            case    431: motherType = 1; break; //Ds+-
+            case    411: motherType = 1; break; //D+-
+            case    428: motherType = 1; break; //D0
+            case    429: motherType = 1; break; //D0
+            case    521: motherType = 1; break; //B+
+            case    529: motherType = 1; break; //B+
+            case    511: motherType = 1; break; //B0
+            case    519: motherType = 1; break; //B0
+            case   3001: motherType = 1; break; //H0
+            case   3222: motherType = 1; break; //Sigma+
+            case   3006: motherType = 1; break; //He4L
+            case   3007: motherType = 1; break; //He5L
+            case   3008: motherType = 1; break; //H4LL
+            case   3009: motherType = 1; break; //H4LL
+            case   3011: motherType = 1; break; //He6LL
+            default:   motherType = 2; break; //resonances
+          }
+          for(int iCut=0; iCut<3; iCut++)
+            cuts[iCut][nBufEntry] = fCutsTrackV0[motherType][iCut];
+
+          nBufEntry++;
+
+          if(int(nBufEntry) == float_vLen)
+          {
+            mother.SetPDG( motherParticlePDG );
+            ConstructTrackV0Cand(vTracks,   
+                                 idTrack, trackPDGMother, v0Pointer,
+                                 mother, motherTopo, mother_temp,
+                                 nBufEntry, l, dl, Particles, PrimVtx,
+                                 cuts, pvIndexMother, massMotherPDG,
+                                 massMotherPDGSigma, vMotherPrim, vMotherSec);
+            nBufEntry = 0; 
+          }
+        }//iV
+      }//iPDGPos
+    }//iTr
+  }
+
+  if(nBufEntry > 0)
+  {
+    for(int iV=nBufEntry; iV<float_vLen; iV++)
+      idTrack[iV] = idTrack[0];
+    
+    mother.SetPDG( motherParticlePDG );
+    ConstructTrackV0Cand(vTracks,  
+                          idTrack, trackPDGMother, v0Pointer,
+                          mother, motherTopo, mother_temp,
+                          nBufEntry, l, dl, Particles, PrimVtx,
+                          cuts, pvIndexMother, massMotherPDG,
+                          massMotherPDGSigma, vMotherPrim, vMotherSec);
+    nBufEntry = 0; 
+  }
+}
+
+void KFParticleFinder::SelectParticles(vector<KFParticle>& Particles,
+                                       vector<KFParticle>& vCandidates,
+                                       std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                       const float& cutChi2Topo,
+                                       const float& cutLdL,
+                                       const float& mass,
+                                       const float& massErr,
+                                       const float& massCut)
+{
+  /** Selects particles from a set of candidates "vCandidates" according to the provided cuts
+   ** on \f$\chi^2_{topo}\f$ and \f$l/\Delta l\f$
+   ** and stores them to the output array "Particles". Also, "vCandidates" is cleaned, only
+   ** selected particles with additional cut on \f$\sigma_{M}\f$ are left there.
+   ** \param[out] Particles - output vector with particles.
+   ** \param[in,out] vCandidates - vector with the input candidates.
+   ** \param[in] PrimVtx - vector with primary vertices.
+   ** \param[in] cutChi2Topo - \f$\chi^2_{topo}\f$ cut.
+   ** \param[in] cutLdL - \f$l/\Delta l\f$ cut.
+   ** \param[in] mass - table mass for the given PDG hypothesis.
+   ** \param[in] massErr - sigma of the peak width for the given PDG hypothesis.
+   ** \param[in] massCut - \f$\sigma_{M}\f$ cut.
+   **/
+  KFParticle* cand[float_vLen];
+  int nCand = vCandidates.size();
+  
+  vector<KFParticle> newCandidates;
+  kfvector_floatv l(fNPV), dl(fNPV);
+
+  for(int iC=0; iC < nCand; iC += float_vLen)
+  {
+    int nEntries = (iC + float_vLen < nCand) ? float_vLen : (nCand - iC);
+
+    for(int iv=0; iv<nEntries; iv++)
+      cand[iv] = &vCandidates[iC+iv];
+
+    KFParticleSIMD mother(cand,nEntries);
+    
+    float_m saveParticle(simd_cast<float_m>(int_v::IndexesFromZero() < int(nEntries)));
+
+    float_v lMin(1.e8f);
+    float_v ldlMin(1.e8f);
+    float_m isParticleFromVertex(false);
+
+    for(int iP=0; iP<fNPV; iP++)
+    {
+      float_m isParticleFromVertexLocal;
+      mother.GetDistanceToVertexLine(PrimVtx[iP], l[iP], dl[iP], &isParticleFromVertexLocal);
+      isParticleFromVertex |= isParticleFromVertexLocal;
+      float_v ldl = (l[iP]/dl[iP]);
+      lMin( (l[iP] < lMin) && saveParticle) = l[iP];
+      ldlMin( (ldl < ldlMin) && saveParticle) = ldl;
+    }
+    saveParticle &= ldlMin > cutLdL;
+    saveParticle &= (lMin < 200.f);
+    saveParticle &= isParticleFromVertex;
+    if( saveParticle.isEmpty() ) continue;
+
+    KFParticleSIMD* candTopo = new KFParticleSIMD[fNPV];
+
+    for(int iP=0; iP<fNPV; iP++)
+    {
+      candTopo[iP] = mother;
+      candTopo[iP].SetProductionVertex(PrimVtx[iP]);
+    }
+    
+    for(int iv=0; iv<nEntries; iv++)
+    {
+      if(!saveParticle[iv]) continue;
+      
+      bool isPrimary = 0;
+      for(int iP=0; iP<fNPV; iP++)
+      {
+        if( !(KFPMath::Finite(candTopo[iP].GetChi2())[iv]) ) continue;
+        if(!(candTopo[iP].GetChi2()[iv] > 0.0f)) continue;
+        if(!(candTopo[iP].GetChi2()[iv]==candTopo[iP].GetChi2()[iv])) continue;
+      
+        if(float(candTopo[iP].GetChi2()[iv])/float(candTopo[iP].GetNDF()[iv]) <= cutChi2Topo )
+          isPrimary = 1;
+      }
+      if(!isPrimary)
+        continue;
+
+      vCandidates[iC+iv].SetId(Particles.size());
+      Particles.push_back(vCandidates[iC+iv]);
+      
+      float m, dm;
+      vCandidates[iC+iv].GetMass(m,dm);
+      if( (fabs(m - mass)/massErr) > massCut ) continue;
+
+      vCandidates[iC+iv].SetNonlinearMassConstraint(mass);
+      newCandidates.push_back(vCandidates[iC+iv]);
+    }
+    if(candTopo) delete [] candTopo;
+  }
+  
+  vCandidates = newCandidates;
+}
+
+void KFParticleFinder::CombinePartPart(vector<KFParticle>& particles1,
+                                       vector<KFParticle>& particles2,
+                                       vector<KFParticle>& Particles,
+                                       std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                                       const float* cuts,
+                                       int iPV,
+                                       const int MotherPDG,
+                                       bool isSameInputPart,
+                                       bool saveOnlyPrimary,
+                                       vector< vector<KFParticle> >* vMotherPrim,
+                                       vector<KFParticle>* vMotherSec,
+                                       float massMotherPDG,
+                                       float massMotherPDGSigma)
+{
+  /** Combines two already constructed candidates into a new particle.
+   ** \param[in] particles1 - vector with the first set of particles.
+   ** \param[in] particles2 - vector with the second set of particles.
+   ** \param[out] Particles - output vector with particles.
+   ** \param[in] PrimVtx - vector with primary vertices.
+   ** \param[in] cuts - set of cuts: \f$l/\Delta l\f$, \f$\chi^2_{topo}\f$, \f$\chi^2_{geo}\f$.
+   ** \param[in] iPV - index of the primary vertex for reconstruction of resonances. Tracks should come from the same vertex.
+   ** \param[in] MotherPDG - PDG hypothesis of the constructed mother particles.
+   ** \param[in] isSameInputPart - shows if vectors of input particles are the same to avoid double reconstruction of the same candidate.
+   ** \param[in] saveOnlyPrimary - defines if only primary particles should be searched and \f$\chi^2_{topo}\f$ should be applied.
+   ** \param[out] vMotherPrim - array with output primary candidates if any. If pointer is set to NULL - not filled.
+   ** \param[out] vMotherSec - array with output secondary candidates if any. If pointer is set to NULL - not filled.
+   ** \param[in] massMotherPDG - PDG table mass for the mother particle, is used for selection of primary and secondary candidates.
+   ** \param[in] massMotherPDGSigma - sigma of the peak width, is used for selection of primary and secondary candidates.
+   **/
+  if( (particles1.size() ==  0) || (particles2.size() ==  0) ) return;  
+  if(!(fDecayReconstructionList.empty()) && (fDecayReconstructionList.find(MotherPDG) == fDecayReconstructionList.end())) return;
+
+  KFParticle mother_temp;
+  KFParticleSIMD mother;
+  KFParticleSIMD *motherTopo = new KFParticleSIMD[fNPV];
+  mother.SetPDG( MotherPDG );
+
+  kfvector_floatv l(fNPV), dl(fNPV);
+
+  KFParticle* tmpPart2[float_vLen];
+  int nPart2 = particles2.size();
+
+  bool isPrimary = (iPV >= 0);
+  bool isCharm = (MotherPDG == 425) ||
+                 (MotherPDG == 427) || 
+                 (abs(MotherPDG) == 200411) ||
+                 (abs(MotherPDG) == 404122) ||
+                 (abs(MotherPDG) ==   4132) ||
+                 (abs(MotherPDG) == 300431) ||
+                 (abs(MotherPDG) == 204122);
+  
+  for(unsigned int iP1=0; iP1 < particles1.size(); iP1++)
+  {
+    KFParticleSIMD vDaughters[2] = {KFParticleSIMD(particles1[iP1]), KFParticleSIMD()};
+
+    unsigned int startIndex=0;
+    if(isSameInputPart) startIndex=iP1+1;
+    for(int iP2=startIndex; iP2 < nPart2; iP2 += float_vLen)
+    {
+      int nElements = (iP2 + float_vLen < nPart2) ? float_vLen : (nPart2 - iP2);
+      float_m active(simd_cast<float_m>(int_v::IndexesFromZero() < int(nElements)));
+
+      for(int iv=0; iv<nElements; iv++)
+        tmpPart2[iv] = &particles2[iP2+iv];
+
+      vDaughters[1] = KFParticleSIMD(tmpPart2,nElements);
+
+//       if( reconstructPi0 )
+//       {
+//         int indexOffset = fEmcClusters->Id()[0];
+//         uint_v gammaIndex1( (unsigned int)0);
+//         uint_v gammaIndex2( (unsigned int)0);
+//         for(int iv=0; iv<nElements; iv++)
+//         {
+//           gammaIndex1[iv] = Particles[ particles2[iP2+iv].DaughterIds()[0] ].DaughterIds()[0] - indexOffset;
+//           gammaIndex2[iv] = Particles[ particles2[iP2+iv].DaughterIds()[1] ].DaughterIds()[0] - indexOffset;
+//         }
+//         
+//         KFParticleSIMD gamma1(*fEmcClusters, gammaIndex1, vDaughters[0]);
+//         KFParticleSIMD gamma2(*fEmcClusters, gammaIndex2, vDaughters[0]);
+//         const KFParticleSIMD* pi0Daughters[2] = {&gamma1, &gamma2};
+//         
+//         int_v gammaId = vDaughters[1].Id();
+//         vDaughters[1].SetVtxGuess(vDaughters[0].X(), vDaughters[0].Y(), vDaughters[0].Z());
+//         vDaughters[1].Construct(pi0Daughters, 2);
+//         vDaughters[1].SetId(gammaId);
+//         
+//         float_v mass, dm;
+//         vDaughters[1].GetMass(mass,dm);
+//         const float& mPi0 = KFParticleDatabase::Instance()->GetPi0Mass();
+//         const float& mPi0Sigma = KFParticleDatabase::Instance()->GetPi0MassSigma();
+//         active &= (abs(mass - mPi0)/mPi0Sigma) < 3.f;
+//         vDaughters[1].SetNonlinearMassConstraint(mPi0);
+//         if(active.isEmpty()) continue;
+//       }
+      
+      if(isCharm)
+      {
+        mother  = vDaughters[0];
+        mother += vDaughters[1];
+        mother.SetPDG( MotherPDG );
+      }
+      else
+      {
+        const KFParticleSIMD* vDaughtersPointer[2] = {&vDaughters[0], &vDaughters[1]};
+        mother.Construct(vDaughtersPointer, 2, 0);
+      }
+  
+      float_m saveParticle(active);
+      saveParticle &= (mother.Chi2()/simd_cast<float_v>(mother.NDF()) < cuts[2] );
+      saveParticle &= KFPMath::Finite(mother.GetChi2());
+      saveParticle &= (mother.GetChi2() >= 0.0f);
+      saveParticle &= (mother.GetChi2() == mother.GetChi2());
+      
+      if( saveParticle.isEmpty() ) { continue; }
+
+      int_m isSameTrack(false);
+      for(unsigned int iD=0; iD<vDaughters[0].DaughterIds().size(); iD++)
+        for(unsigned int iD1=0; iD1<vDaughters[1].DaughterIds().size(); iD1++)
+          isSameTrack |= ( int_v(vDaughters[0].DaughterIds()[iD]) == int_v(vDaughters[1].DaughterIds()[iD1]) );
+      saveParticle &= ( !simd_cast<float_m>(isSameTrack));
+      if( saveParticle.isEmpty() ) { continue; }        
+      
+      float_v lMin(1.e8f);
+      float_v ldlMin(1.e8f);
+      float_m isParticleFromVertex(false);
+
+      for(int iP=0; iP<fNPV; iP++)
+      {
+        if( (iPV > -1) && (iP !=iPV) ) continue;
+        float_m isParticleFromVertexLocal;
+        mother.GetDistanceToVertexLine(PrimVtx[iP], l[iP], dl[iP], &isParticleFromVertexLocal);
+        isParticleFromVertex |= isParticleFromVertexLocal;
+        float_v ldl = (l[iP]/dl[iP]);
+        lMin( (l[iP] < lMin) && active) = l[iP];
+        ldlMin( (ldl < ldlMin) && active) = ldl;
+      }
+      saveParticle &= ( (float_m(!isPrimary) && ldlMin > cuts[0]) || float_m(isPrimary) );
+      saveParticle &= (lMin < 200.f);
+    
+      int_m setLCut = abs(mother.PDG()) == 3000;
+      saveParticle &= ( (simd_cast<float_m>(setLCut) && lMin > float_v(fLCut)) || simd_cast<float_m>(!setLCut) );
+
+//         if(isPrimary && (float(ldlMin > 3) )) continue;
+      saveParticle &= ((float_m(!isPrimary) && isParticleFromVertex) || float_m(isPrimary) );
+      if( saveParticle.isEmpty() ) { continue; }
+
+      float_m isSameParticle(isPrimary || isCharm);
+      if(!((isSameParticle).isFull()))
+      {
+        float_m isParticleFromVertexLocal;
+        float_v l1, dl1;
+        vDaughters[0].GetDistanceToVertexLine(mother, l1, dl1, &isParticleFromVertexLocal);
+        
+        saveParticle &= ( isSameParticle || ((!isSameParticle) && isParticleFromVertexLocal));
+        if( saveParticle.isEmpty() ) { continue; }
+      }
+  
+      for(int iP=0; iP<fNPV; iP++)
+      {
+        if( (iPV > -1) && (iP !=iPV) ) continue;
+        motherTopo[iP] = mother;
+        motherTopo[iP].SetProductionVertex(PrimVtx[iP]);
+      }
+  
+      vector<int> iPrimVert[float_vLen];
+      float_m isPrimaryPart(false);
+
+      for(int iP=0; iP<fNPV; iP++)
+      {
+        if( (iPV > -1) && (iP !=iPV) ) continue;
+        const float_v& motherTopoChi2Ndf = motherTopo[iP].GetChi2()/simd_cast<float_v>(motherTopo[iP].GetNDF());
+        const float_m isPrimaryPartLocal = ( motherTopoChi2Ndf < float_v(cuts[1]) );
+        isPrimaryPart |= isPrimaryPartLocal;
+        for(int iV=0; iV<float_vLen; iV++)
+        {
+          if(isPrimaryPartLocal[iV])
+            iPrimVert[iV].push_back(iP);
+        }
+      }
+      
+      for(int iv=0; iv<nElements; iv++)
+      {
+        if(!saveParticle[iv]) continue; 
+        
+        mother.GetKFParticle(mother_temp, iv);
+
+        // reset daughter ids for 3- and 4-particle decays
+        if( (abs(mother.PDG()[iv]) == 428))
+        {
+          mother_temp.CleanDaughtersId();
+          for(int iD=0; iD < particles1[iP1].NDaughters(); iD++)
+            mother_temp.AddDaughterId( particles1[iP1].DaughterIds()[iD] );
+          mother_temp.AddDaughterId(tmpPart2[iv]->Id());
+        }
+        
+        if(saveOnlyPrimary)
+        {
+          if(isPrimaryPart[iv])
+          {
+            mother_temp.SetId(Particles.size());
+            Particles.push_back(mother_temp);
+          }
+        }
+        else
+        {
+          mother_temp.SetId(Particles.size());
+          Particles.push_back(mother_temp);
+        }
+        
+        if(vMotherPrim || vMotherSec)
+        {
+          float mass, errMass;
+          mother_temp.GetMass(mass, errMass);
+          if( (fabs(mass - massMotherPDG)/massMotherPDGSigma) > 3.f ) continue;
+          mother_temp.SetNonlinearMassConstraint(massMotherPDG);
+          
+          if(MotherPDG == 428)
+          {
+            mother_temp.CleanDaughtersId();
+            for(int iD=0; iD < tmpPart2[iv]->NDaughters(); iD++)
+              mother_temp.AddDaughterId( tmpPart2[iv]->DaughterIds()[iD] );
+            for(int iD=0; iD < particles1[iP1].NDaughters(); iD++)
+              mother_temp.AddDaughterId( particles1[iP1].DaughterIds()[iD] );            
+          }
+          
+          if(vMotherSec && (!(isPrimaryPart[iv])) )
+            vMotherSec->push_back(mother_temp);
+          if(vMotherPrim)
+            for(unsigned int iP=0; iP<iPrimVert[iv].size(); iP++)
+              (*vMotherPrim)[iPrimVert[iv][iP]].push_back(mother_temp);
+        }
+      }
+    }
+  }
+  
+  if(motherTopo) delete [] motherTopo;
+}
+
+
+void KFParticleFinder::NeutralDaughterDecay(KFPTrackVector* vTracks,
+                                            vector<KFParticle>& Particles)
+{
+  /** Reconstructs particles by the missing mass method.
+   ** \param[in] vRTracks - pointer to the array with vectors of tracks:\n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** \param[out] Particles - the output array with the reconstructed particle-candidates.
+   **/
+  KFParticle mother_temp;
+  KFParticleSIMD ChargedDaughter, MotherTrack;
+
+  uint_v idMotherTrack;
+  uint_v idChargedDaughter;
+  int_v ChargedDaughterPDG(-1);
+    
+  int_v pvIndexMother(-1); 
+  
+  int outNeutralDaughterPDG[4][5]; //[iTC][iHypothesis]
+  int outMotherPDG[4][5];
+  
+  int trTypeIndexMother[2] = {6,7};
+  int trTypeIndexDaughter[2] = {0,1};
+
+  for( int iTrTypeDaughter = 0; iTrTypeDaughter<2; iTrTypeDaughter++)
+  {
+    KFPTrackVector& DaughterTracks = vTracks[ trTypeIndexDaughter[iTrTypeDaughter] ];
+    KFPTrackVector& MotherTracks = vTracks[ trTypeIndexMother[iTrTypeDaughter] ];
+
+    int_v DaughterTracksSize = DaughterTracks.Size();
+    int MotherTracksSize = MotherTracks.Size();
+
+    //track categories
+    int nTC = 4;
+    int startTCMother[4] = {0,0,0,0};
+    int endTCMother[4] = {0,0,0,0};
+    int startTCDaughter[4] = {0,0,0,0};
+    int endTCDaughter[4] = {0,0,0,0};
+
+    nTC = 4;
+    vector<int> nMotherHypothesis(nTC,0);
+    vector< vector<int> > motherPDGHypothesis(nTC);
+    vector< vector<float> > neutralDaughterMassHypothesis(nTC);
+
+
+    //mu+, mu-
+    startTCMother[0] = 0; endTCMother[0] = MotherTracksSize;
+    startTCDaughter[0] = DaughterTracks.FirstMuon(); endTCDaughter[0] = DaughterTracks.LastMuon(); 
+
+    nMotherHypothesis[0] = 2;
+
+
+    motherPDGHypothesis[0].push_back(211);
+    motherPDGHypothesis[0].push_back(321);
+
+    neutralDaughterMassHypothesis[0].push_back(0.);
+    neutralDaughterMassHypothesis[0].push_back(0.);
+
+    outNeutralDaughterPDG[0][0]=-7000014;
+    outNeutralDaughterPDG[0][1]=-8000014;
+
+    outMotherPDG[0][0]=-7000211;
+    outMotherPDG[0][1]=-7000321;
+
+    //Pi+, Pi-
+    startTCMother[1] = 0; endTCMother[1] = MotherTracksSize;
+    startTCDaughter[1] = DaughterTracks.FirstPion(); endTCDaughter[1] = DaughterTracks.LastPion();
+
+    nMotherHypothesis[1] = 5;
+
+    motherPDGHypothesis[1].push_back(3112);
+    motherPDGHypothesis[1].push_back(3222);
+    motherPDGHypothesis[1].push_back(3312);
+    motherPDGHypothesis[1].push_back(3334);
+    motherPDGHypothesis[1].push_back(321);
+    
+    neutralDaughterMassHypothesis[1].push_back(0.939565);
+    neutralDaughterMassHypothesis[1].push_back(0.939565);
+    neutralDaughterMassHypothesis[1].push_back(1.115683);
+    neutralDaughterMassHypothesis[1].push_back(1.31486);
+    neutralDaughterMassHypothesis[1].push_back(0.1349766);
+    
+    outNeutralDaughterPDG[1][0]= 7002112;
+    outNeutralDaughterPDG[1][1]=-8002112;
+    outNeutralDaughterPDG[1][2]= 7003122;
+    outNeutralDaughterPDG[1][3]= 7003322;
+    outNeutralDaughterPDG[1][4]=-9000111;
+    
+    outMotherPDG[1][0]= 7003112;
+    outMotherPDG[1][1]=-7003222;
+    outMotherPDG[1][2]= 7003312;
+    outMotherPDG[1][3]= 7003334;
+    outMotherPDG[1][4]=-9000321;
+    
+    //K+, K-
+    startTCMother[2] = 0; endTCMother[2] = MotherTracksSize;
+    startTCDaughter[2] = DaughterTracks.FirstKaon(); endTCDaughter[2] = DaughterTracks.LastKaon();
+
+    nMotherHypothesis[2] = 1;
+    
+    motherPDGHypothesis[2].push_back(3334);
+    
+    neutralDaughterMassHypothesis[2].push_back(1.115683);
+    
+    outNeutralDaughterPDG[2][0]= 8003122;
+    
+    outMotherPDG[2][0]= 8003334;
+
+    //p+, p-
+    startTCMother[3] = 0; endTCMother[3] = MotherTracksSize;
+    startTCDaughter[3] = DaughterTracks.FirstProton(); endTCDaughter[3] = DaughterTracks.LastProton(); 
+
+    nMotherHypothesis[3] = 1;
+    
+    motherPDGHypothesis[3].push_back(3222);
+    
+    neutralDaughterMassHypothesis[3].push_back(0.1349766);
+    
+    outNeutralDaughterPDG[3][0]=-8000111;
+    
+    outMotherPDG[3][0]=-8003222;
+    
+    
+
+    for(int iTC=0; iTC<nTC; iTC++)
+    {
+      for(unsigned short iTrD=startTCDaughter[iTC]; iTrD < endTCDaughter[iTC]; iTrD += float_vLen)
+      {
+        const unsigned short NTracksDaughter = (iTrD + float_vLen < DaughterTracks.Size()) ? float_vLen : (DaughterTracks.Size() - iTrD);
+
+        int_v DaughterInd = int_v::IndexesFromZero() + int(iTrD);
+
+        int_v DaughterPDG = reinterpret_cast<const int_v&>(DaughterTracks.PDG()[iTrD]);
+        int_v DaughterPVIndex = reinterpret_cast<const int_v&>(DaughterTracks.PVIndex()[iTrD]);
+        int_v daughterId = reinterpret_cast<const int_v&>(DaughterTracks.Id()[iTrD]);
+        
+        int_v trackPdgDaughter = DaughterPDG;
+        int_m activeDaughter = (DaughterPDG != -1);
+        
+        if( !((DaughterPDG == -1).isEmpty()) )
+        {
+          trackPdgDaughter(DaughterPVIndex<0 && (DaughterPDG == -1) ) = 211;
+              
+//             activeDaughter |= int_m(DaughterPVIndex < 0) && int_m(DaughterPDG == -1) ;
+        }
+        
+        activeDaughter = (int_v::IndexesFromZero() < int(NTracksDaughter));
+            
+        ChargedDaughter.Load(DaughterTracks, iTrD, DaughterPDG);
+        ChargedDaughter.SetId(daughterId);
+
+        for(unsigned short iTrM=startTCMother[iTC]; iTrM < endTCMother[iTC]; iTrM += float_vLen)
+        {
+          const unsigned short NTracks = (iTrM + float_vLen < MotherTracksSize) ? float_vLen : (MotherTracksSize - iTrM);
+
+          //const int_v& MotherPDG = reinterpret_cast<const int_v&>(MotherTracks.PDG()[iTrM]);
+          //const int_v& MotherPVIndex = reinterpret_cast<const  int_v&>(MotherTracks.PVIndex()[iTrM]);              
+          const int_v& motherTrackId = reinterpret_cast<const  int_v&>(MotherTracks.Id()[iTrM]);
+          
+          for(int iRot = 0; iRot<float_vLen; iRot++)
+          {
+            if(iRot>0)
+            {
+              DaughterPDG = DaughterPDG.rotated(1);
+              DaughterPVIndex = DaughterPVIndex.rotated(1);
+              DaughterInd = DaughterInd.rotated(1);
+              trackPdgDaughter = trackPdgDaughter.rotated(1);
+            
+              ChargedDaughter.Rotate();
+
+              activeDaughter = /*( (DaughterPDG != -1) || ( (DaughterPVIndex < 0) && (DaughterPDG == -1) ) ) &&*/ (DaughterInd < DaughterTracksSize);
+            }
+            
+            int_v trackPdgMother;
+
+            if(iTC==0)
+              activeDaughter &= abs(DaughterPDG)==13;
+            if(iTC==1)
+              activeDaughter &= abs(DaughterPDG)==211;
+            if(iTC==2)
+              activeDaughter &= abs(DaughterPDG)==321;
+            if(iTC==3)
+              activeDaughter &= abs(DaughterPDG)==2212;
+            if (activeDaughter.isEmpty()) continue;
+            
+            
+            for(int iHypothesis=0; iHypothesis<nMotherHypothesis[iTC]; iHypothesis++)
+            {
+              int motherKFPDG = outMotherPDG[iTC][iHypothesis];
+              if(iTrTypeDaughter==0) motherKFPDG = -outMotherPDG[iTC][iHypothesis];
+              if(!(fDecayReconstructionList.empty()) && (fDecayReconstructionList.find(motherKFPDG) == fDecayReconstructionList.end())) continue;
+              
+              int_m active = activeDaughter && (int_v::IndexesFromZero() < int(NTracks));
+              
+              MotherTrack.Load(MotherTracks, iTrM, motherPDGHypothesis[iTC][iHypothesis]);
+              
+              float_v zMother = MotherTrack.Z();
+              float_v zCD = ChargedDaughter.Z();
+              
+              //daughter particle should start after the last hit of a mother track
+              active &= simd_cast<int_m>(zCD >= (zMother - float_v(0.5f)));
+              if( active.isEmpty() ) continue;
+              
+              KFParticleSIMD neutralDaughter = MotherTrack;
+              //energy of the mother particle should be greater then of the daughter particle
+              active &= simd_cast<int_m>(neutralDaughter.E() > ChargedDaughter.E());
+              if( active.isEmpty() ) continue;
+              
+              neutralDaughter.AddDaughterId(motherTrackId);
+              neutralDaughter.NDF() = -1;
+              neutralDaughter.Chi2() = 0.f;
+              neutralDaughter.SubtractDaughter(ChargedDaughter);
+              
+              //decay point shoud be between mother and daughter tracks
+              active &= simd_cast<int_m>(neutralDaughter.Z() >= zMother - float_v(10.0f));
+              active &= simd_cast<int_m>(neutralDaughter.Z() <= zCD + float_v(10.0f));
+              //set cut on chi2 of the fit of the neutral daughter
+              active &= simd_cast<int_m>(neutralDaughter.NDF() >= int_v(Vc::Zero));
+              active &= simd_cast<int_m>(neutralDaughter.Chi2()/simd_cast<float_v>(neutralDaughter.NDF()) <= fCuts2D[1]);
+              //fit should converge
+              active &= simd_cast<int_m>(neutralDaughter.Chi2() >= float_v(Vc::Zero));
+              active &= simd_cast<int_m>(neutralDaughter.Chi2() == neutralDaughter.Chi2());
+              if( active.isEmpty() ) continue;
+              
+              //kill particle-candidates produced by clones
+              active &= simd_cast<int_m>( neutralDaughter.GetRapidity()<6.f && neutralDaughter.GetRapidity()>0.f);
+              if ((iTC==1 && iHypothesis<4) || iTC==2)
+                active &= simd_cast<int_m>( !( (neutralDaughter.GetPt())<0.5f && neutralDaughter.GetRapidity()<0.5f ) );
+              if (iTC==3)
+                active &= simd_cast<int_m>( !( (neutralDaughter.GetPt())<0.2f && neutralDaughter.GetRapidity()<1.f ) );
+              if( active.isEmpty() ) continue;
+              
+              KFParticleSIMD neutralDaughterUnconstr = neutralDaughter;
+              neutralDaughter.SetNonlinearMassConstraint(neutralDaughterMassHypothesis[iTC][iHypothesis]);
+              
+              const KFParticleSIMD* daughters[2] = {&neutralDaughter, &ChargedDaughter};
+              KFParticleSIMD mother;
+              mother.Construct(daughters, 2);
+              
+              //decay point shoud be between mother and daughter tracks
+              active &= simd_cast<int_m>(mother.Z() >= zMother);
+              active &= simd_cast<int_m>(mother.Z() <= zCD);
+              //set cut on chi2 of the fit of the mother particle
+              active &= simd_cast<int_m>(mother.NDF() >= int_v(Vc::Zero));
+              active &= simd_cast<int_m>(mother.Chi2()/simd_cast<float_v>(mother.NDF()) <= fCuts2D[1]);
+              //fit should converge
+              active &= simd_cast<int_m>(mother.Chi2() >= float_v(Vc::Zero));
+              active &= simd_cast<int_m>(mother.Chi2() == mother.Chi2());
+              if( active.isEmpty() ) continue;
+
+              for(int iV=0; iV<NTracks; iV++)
+              {
+                if(!active[iV]) continue;
+                
+                neutralDaughterUnconstr.GetKFParticle(mother_temp, iV);
+                int neutralId = Particles.size();
+                mother_temp.SetId(neutralId);
+                if (iTrTypeDaughter==0)
+                  mother_temp.SetPDG(-outNeutralDaughterPDG[iTC][iHypothesis]);
+                else
+                  mother_temp.SetPDG(outNeutralDaughterPDG[iTC][iHypothesis]);
+                Particles.push_back(mother_temp);
+
+                mother.GetKFParticle(mother_temp, iV);
+                mother_temp.SetId(Particles.size());
+                mother_temp.CleanDaughtersId();
+                mother_temp.AddDaughterId(ChargedDaughter.Id()[iV]);
+                mother_temp.AddDaughterId(neutralId);
+                
+                if (iTrTypeDaughter==0)  
+                  mother_temp.SetPDG(-outMotherPDG[iTC][iHypothesis]);
+                else
+                  mother_temp.SetPDG(outMotherPDG[iTC][iHypothesis]);
+                Particles.push_back(mother_temp);
+              }
+            }
+          }//iRot
+        }//iTrM
+      }//iTrD
+    }//iTC
+  }//iTrTypeDaughter
+}
+
+void KFParticleFinder::AddCandidate(const KFParticle& candidate, int iPV)
+{
+  /** Adds an externally found particle to either set of secondary or primary candidates:\n
+   ** 1) if iPV is negative the candidate is stored to KFParticleFinder::fSecCandidates;\n
+   ** 2) if iPV is not negative and smaller then the set number of primary vertices and
+   ** NDF=2 the candidate is stored to KFParticleFinder::fPrimCandidates;\n
+   ** 3) if iPV is not negative and smaller then the set number of primary vertices and
+   ** NDF=3 the candidate is stored to KFParticleFinder::fPrimCandidatesTopo;\n
+   ** 4) if iPV is not negative and smaller then the set number of primary vertices and
+   ** NDF=4 the candidate is stored to KFParticleFinder::fPrimCandidatesTopoMass.\n
+   ** Only those particles will be stored which have accepted PDG. Please check the documentation
+   ** of the corresponding vectors for the list of particles.
+   ** \param[in] candidate - candidate to be added
+   ** \param[in] iPV - index of the associated PV
+   **/
+
+  //0 Ks, 1 Lambda,2 LambdaBar, 3 gamma, 4 pi0, 5 Xi, 6 XiBar, 7 Omega, 8 OmegaBar, 9 XiStar
+  int iSet = -1;
+  if(candidate.GetPDG() ==   310) iSet = 0;
+  if(candidate.GetPDG() ==  3122) iSet = 1;
+  if(candidate.GetPDG() == -3122) iSet = 2;
+  if(candidate.GetPDG() ==    22) iSet = 3;
+  if(candidate.GetPDG() ==   111) iSet = 4;
+  if(candidate.GetPDG() ==  3312) iSet = 5;
+  if(candidate.GetPDG() == -3312) iSet = 6;
+  if(candidate.GetPDG() ==  3334) iSet = 7;
+  if(candidate.GetPDG() == -3334) iSet = 8;
+  
+  if(iSet > -1)
+  {
+    if(iPV >= 0 && iPV<fNPV)
+    {
+      if(candidate.NDF() == 2)
+        fPrimCandidates[iSet][iPV].push_back(candidate);
+      if(candidate.NDF() == 3)
+        fPrimCandidatesTopo[iSet][iPV].push_back(candidate);
+      if(candidate.NDF() == 4)
+        fPrimCandidatesTopoMass[iSet][iPV].push_back(candidate);
+    }
+    else if(iPV < 0)
+    {
+      fSecCandidates[iSet].push_back(candidate);
+    }
+  }
+}
+
+void KFParticleFinder::SetNPV(int nPV)
+{
+  /** Sets the number of primary vertices to "nPV", resizes all vectors
+   ** with primary candidates correspondingly.
+   ** \param[in] nPV - number of the primary vertices in the event to be set.
+   **/
+  
+  fNPV = nPV;
+  
+  for(int iCandidates=0; iCandidates<fNPrimCandidatesSets; iCandidates++)
+  {
+    fPrimCandidates[iCandidates].clear();
+    fPrimCandidates[iCandidates].resize(fNPV);
+  }
+  
+  for(int iCandidates=0; iCandidates<fNPrimCandidatesTopoSets; iCandidates++)
+  {
+    fPrimCandidatesTopo[iCandidates].clear();
+    fPrimCandidatesTopo[iCandidates].resize(fNPV);
+    
+    fPrimCandidatesTopoMass[iCandidates].clear();
+    fPrimCandidatesTopoMass[iCandidates].resize(fNPV);
+  }
+}
diff --git a/external/KFParticle/KFParticle/KFParticleFinder.h b/external/KFParticle/KFParticle/KFParticleFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e914489ffdb3dd2b06867da75c82a712a140aa0
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleFinder.h
@@ -0,0 +1,460 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#ifndef KFParticleFinder_h
+#define KFParticleFinder_h
+
+#include "KFParticle.h"
+#include "KFParticleSIMD.h"
+#include "KFPTrackVector.h"
+
+#include <vector>
+#include <map>
+
+class KFPEmcCluster;
+
+/** @class KFParticleFinder
+ ** @brief Class for reconstruction short-lived particles.
+ ** @author  I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class reconstructs short-lived particles by combining long-lived
+ ** and already reconstructed short-lived particles. As an input it requires 
+ ** tracks and primary vertices. All short-lived particles are stored to one
+ ** array. The default values of cuts are initialised in the constructor.
+ **/
+
+class KFParticleFinder
+{
+ public:
+
+  KFParticleFinder();
+  ~KFParticleFinder() {};
+  
+  void Init(int nPV);
+  void SetNThreads(short int n) { fNThreads = n;} ///< Sets the number of threads to by run in parallel. Currently not used.
+
+  void FindParticles(KFPTrackVector* vRTracks, kfvector_float* ChiToPrimVtx,
+                     std::vector<KFParticle>& Particles, std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx, int nPV);
+
+  void ExtrapolateToPV(std::vector<KFParticle>& vParticles, KFParticleSIMD& PrimVtx);
+     
+  inline void ConstructV0(KFPTrackVector* vTracks,
+                    int iTrTypePos,
+                    int iTrTypeNeg,
+                    uint_v& idPosDaughters,
+                    uint_v& idNegDaughters,
+                    int_v& daughterPosPDG,
+                    int_v& daughterNegPDG,
+                    KFParticleSIMD& mother,
+                    KFParticle& mother_temp,
+                    const unsigned short NTracks,
+                    kfvector_floatv& l,
+                    kfvector_floatv& dl,
+                    std::vector<KFParticle>& Particles,
+                    std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                    const float* cuts,
+                    const int_v& pvIndex,
+                    const float* secCuts,
+                    const float_v& massMotherPDG,
+                    const float_v& massMotherPDGSigma,
+                    KFParticleSIMD& motherPrimSecCand,
+                    int& nPrimSecCand,
+                    std::vector< std::vector<KFParticle> >* vMotherPrim = 0,
+                    std::vector<KFParticle>* vMotherSec = 0
+                  ) __attribute__((always_inline));
+  
+  void SaveV0PrimSecCand(KFParticleSIMD& mother,
+                          int& NParticles,
+                          KFParticle& mother_temp,
+                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                          const float* secCuts,
+                          std::vector< std::vector<KFParticle> >* vMotherPrim,
+                          std::vector<KFParticle>* vMotherSec);
+  
+  void ConstructTrackV0Cand(KFPTrackVector& vTracks,
+                              uint_v& idTracks,
+                              int_v& trackPDG,
+                              KFParticle* vV0[],
+                              KFParticleSIMD& mother,
+                              std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& motherTopo,
+                              KFParticle& mother_temp,
+                              const unsigned short nElements,
+                              kfvector_floatv& l,
+                              kfvector_floatv& dl,
+                              std::vector<KFParticle>& Particles,
+                              std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                              const float_v* cuts,
+                              const int_v& pvIndex,
+                              const float_v& massMotherPDG,
+                              const float_v& massMotherPDGSigma,
+                              std::vector< std::vector<KFParticle> >* vMotherPrim,
+                              std::vector<KFParticle>* vMotherSec);
+
+  void Find2DaughterDecay(KFPTrackVector* vTracks, kfvector_float* ChiToPrimVtx,
+                          std::vector<KFParticle>& Particles,
+                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                          const float* cuts,
+                          const float* secCuts,
+                          std::vector< std::vector<KFParticle> >* vMotherPrim,
+                          std::vector<KFParticle>* vMotherSec );
+  
+  void ConstructPrimaryBG(KFPTrackVector* vTracks,
+                          std::vector<KFParticle>& Particles,
+                          std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                          const float* cuts,
+                          const float* secCuts,
+                          std::vector< std::vector<KFParticle> >* vMotherPrim,
+                          std::vector<KFParticle>* vMotherSec );
+  
+  void NeutralDaughterDecay(KFPTrackVector* vTracks, std::vector<KFParticle>& Particles);
+
+  void FindTrackV0Decay(std::vector<KFParticle>& vV0,
+                        const int V0PDG,
+                        KFPTrackVector& vTracks,
+                        const int q,
+                        const int firstTrack,
+                        const int lastTrack,
+                        std::vector<KFParticle>& Particles,    
+                        std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                        int v0PVIndex = -1,
+                        kfvector_float* ChiToPrimVtx = 0,
+                        std::vector< std::vector<KFParticle> >* vMotherPrim = 0,
+                        std::vector<KFParticle>* vMotherSec = 0);
+
+  void SelectParticles(std::vector<KFParticle>& Particles,
+                       std::vector<KFParticle>& vCandidates,
+                       std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                       const float& cutChi2Topo,
+                       const float& cutLdL,
+                       const float& mass,
+                       const float& massErr,
+                       const float& massCut);
+  
+  void CombinePartPart(std::vector<KFParticle>& particles1,
+                       std::vector<KFParticle>& particles2,
+                       std::vector<KFParticle>& Particles,
+                       std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> >& PrimVtx,
+                       const float* cuts,
+                       int iPV,
+                       const int MotherPDG,
+                       bool isSameInputPart = 0,
+                       bool saveOnlyPrimary = 1,
+                       std::vector< std::vector<KFParticle> >* vMotherPrim = 0,
+                       std::vector<KFParticle>* vMotherSec = 0,
+                       float massMotherPDG = 0.f,
+                       float massMotherPDGSigma = 0.f);
+
+  //Set Emc clusters containing gammas
+  void SetEmcClusters(KFPEmcCluster* clusters) { fEmcClusters = clusters; } ///< Set a pointer to the gamma-clusters from the electromagnetic calorimeter.
+  
+  // Mixed Event Analysis
+  void SetMixedEventAnalysis() { fMixedEventAnalysis = 1; } ///< Switch KFParticleFinder to the mixed event mode.
+  
+  //Get secondary particles with the mass constraint
+  /** Returns number of sets of vectors with secondary candidates for different decays. */
+  static int GetNSecondarySets()  { return fNSecCandidatesSets; }
+  /** Returns a pointer to array with sets of vectors with secondary candidates for different decays. */
+  const std::vector<KFParticle>* GetSecondaryCandidates() const { return fSecCandidates;    }
+  /** Returns a constant reference to the vector with secondary candidates for \f$K_s^0\rightarrow\pi^+\pi^-\f$. **/
+  const std::vector<KFParticle>& GetSecondaryK0()         const { return fSecCandidates[0]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Lambda\rightarrow p\pi^-\f$. **/
+  const std::vector<KFParticle>& GetSecondaryLambda()     const { return fSecCandidates[1]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Lambda}\rightarrow \overline{p}\pi^+\f$. **/
+  const std::vector<KFParticle>& GetSecondaryAntiLambda() const { return fSecCandidates[2]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\gamma\rightarrow e^+e^-\f$ conversion. **/
+  const std::vector<KFParticle>& GetSecondaryGamma()      const { return fSecCandidates[3]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\pi^0\rightarrow \gamma\gamma\f$. **/
+  const std::vector<KFParticle>& GetSecondaryPi0()        const { return fSecCandidates[4]; }
+  
+  //Get primary particles with the mass constraint
+  /** Returns number of sets of vectors with primary candidates for different decays. */
+  static int GetNPrimarySets() { return fNPrimCandidatesTopoSets; }
+  /** Returns a pointer to array with sets of vectors with primary candidates for different decays. */
+  const std::vector< std::vector<KFParticle> >* GetPrimaryCandidates() const { return fPrimCandidates;    }
+  /** Returns a constant reference to the vector with primary candidates for \f$K_s^0\rightarrow\pi^+\pi^-\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryK0()         const { return fPrimCandidates[0]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\Lambda\rightarrow p\pi^-\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryLambda()     const { return fPrimCandidates[1]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\overline{\Lambda}\rightarrow \overline{p}\pi^+\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryAntiLambda() const { return fPrimCandidates[2]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\gamma\rightarrow e^+e^-\f$ conversion. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryGamma()      const { return fPrimCandidates[3]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\pi^0\rightarrow \gamma\gamma\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryPi0()        const { return fPrimCandidates[4]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Xi^-\rightarrow \Lambda\pi^-\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryXi()         const { return fPrimCandidates[5]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Xi}^-\rightarrow \overline{\Lambda}\pi^+\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryAntiXi()     const { return fPrimCandidates[6]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Omega^-\rightarrow \Lambda K^-\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryOmega()      const { return fPrimCandidates[7]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Omega}^-\rightarrow \overline{\Lambda} K^+\f$. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryAntiOmega()  const { return fPrimCandidates[8]; }
+  
+  //Get primary particles with the topologigal constraint
+  /** Returns a pointer to array with sets of vectors with primary candidates for different decays with topological constraint set on. */
+  const std::vector< std::vector<KFParticle> >* GetPrimaryTopoCandidates() const { return fPrimCandidatesTopo;    }
+  /** Returns a constant reference to the vector with primary candidates for \f$K_s^0\rightarrow\pi^+\pi^-\f$ 
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoK0()         const { return fPrimCandidatesTopo[0]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\Lambda\rightarrow p\pi^-\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoLambda()     const { return fPrimCandidatesTopo[1]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\overline{\Lambda}\rightarrow \overline{p}\pi^+\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoAntiLambda() const { return fPrimCandidatesTopo[2]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\gamma\rightarrow e^+e^-\f$ conversion
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoGamma()      const { return fPrimCandidatesTopo[3]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\pi^0\rightarrow \gamma\gamma\f$
+   **  with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoPi0()        const { return fPrimCandidatesTopo[4]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Xi^-\rightarrow \Lambda\pi^-\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoXi()         const { return fPrimCandidatesTopo[5]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Xi}^-\rightarrow \overline{\Lambda}\pi^+\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoAntiXi()     const { return fPrimCandidatesTopo[6]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Omega^-\rightarrow \Lambda K^-\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoOmega()      const { return fPrimCandidatesTopo[7]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Omega}^-\rightarrow \overline{\Lambda} K^+\f$
+   ** with topological constraint set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoAntiOmega()  const { return fPrimCandidatesTopo[8]; }
+
+  //Get primary particles with the topologigal and mass constraint
+  /** Returns a pointer to array with sets of vectors with primary candidates for different decays with topological and mass constraints set on. */
+  const std::vector< std::vector<KFParticle> >* GetPrimaryTopoMassCandidates() const { return fPrimCandidatesTopoMass;    }
+  /** Returns a constant reference to the vector with primary candidates for \f$K_s^0\rightarrow\pi^+\pi^-\f$ 
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassK0()         const { return fPrimCandidatesTopoMass[0]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\Lambda\rightarrow p\pi^-\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassLambda()     const { return fPrimCandidatesTopoMass[1]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\overline{\Lambda}\rightarrow \overline{p}\pi^+\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassAntiLambda() const { return fPrimCandidatesTopoMass[2]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\gamma\rightarrow e^+e^-\f$ conversion
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassGamma()      const { return fPrimCandidatesTopoMass[3]; }
+  /** Returns a constant reference to the vector with primary candidates for \f$\pi^0\rightarrow \gamma\gamma\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassPi0()        const { return fPrimCandidatesTopoMass[4]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Xi^-\rightarrow \Lambda\pi^-\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassXi()         const { return fPrimCandidatesTopoMass[5]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Xi}^-\rightarrow \overline{\Lambda}\pi^+\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassAntiXi()     const { return fPrimCandidatesTopoMass[6]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\Omega^-\rightarrow \Lambda K^-\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassOmega()      const { return fPrimCandidatesTopoMass[7]; }
+  /** Returns a constant reference to the vector with secondary candidates for \f$\overline{\Omega}^-\rightarrow \overline{\Lambda} K^+\f$
+   ** with topological and mass constraints set on. **/
+  const std::vector< std::vector<KFParticle> >& GetPrimaryTopoMassAntiOmega()  const { return fPrimCandidatesTopoMass[8]; }
+  
+  void AddCandidate(const KFParticle& candidate, int iPV = -1);
+  void SetNPV(int nPV);
+  
+  //Functionality to change cuts, all cuts have default values set in the constructor
+  void SetMaxDistanceBetweenParticlesCut(float cut) { fDistanceCut = cut; } ///< Sets cut on the distance between secondary tracks at the DCA point.
+  void SetLCut(float cut) { fLCut = cut; } ///< Sets cut on the distance to the primary vertex from the decay vertex.
+  
+  void SetChiPrimaryCut2D(float cut) { fCuts2D[0] = cut; } ///< Sets cut on \f$\chi^2_{prim}\f$ of each track for 2-daughter decays.
+  void SetChi2Cut2D(float cut)       { fCuts2D[1] = cut; } ///< Sets cut on \f$\chi^2_{geo}\f$ for 2-daughter decays.
+  void SetLdLCut2D(float cut)        { fCuts2D[2] = cut; } ///< Sets cut on \f$l/\Delta l\f$ for 2-daughter decays.
+  
+  /** \brief Sets cuts on selection of secondary and primary candidates: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$. */
+  void SetSecondaryCuts(const float sigmaMass = 3.f, const float chi2Topo = 5.f, const float ldl = 10.f) {
+    fSecCuts[0] = sigmaMass;
+    fSecCuts[1] = chi2Topo;
+    fSecCuts[2] = ldl;
+  }
+  
+  void SetLdLCutXiOmega(float cut)      { fCutsTrackV0[0][0] = cut; } ///< Sets \f$l/\Delta l\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+  void SetChi2TopoCutXiOmega(float cut) { fCutsTrackV0[0][1] = cut; } ///< Sets \f$\chi^2_{topo}\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+  void SetChi2CutXiOmega(float cut)     { fCutsTrackV0[0][2] = cut; } ///< Sets \f$\chi^2_{geo}\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+
+  void SetChi2TopoCutResonances(float cut) { fCutsTrackV0[2][1] = cut; } ///< Sets \f$\chi^2_{topo}\f$ cut for resonances.
+  void SetChi2CutResonances(float cut)     { fCutsTrackV0[2][2] = cut; } ///< Sets \f$\chi^2_{geo}\f$ cut for resonances.
+
+  void SetPtCutLMVM(float cut) { fCutLVMPt = cut; }  ///< Sets the cut on transverse momentum of each daughter track of low mass vector mesons.
+  void SetPCutLMVM(float cut)  { fCutLVMP = cut; }   ///< Sets the cut on momentum of each daughter track of low mass vector mesons in dimuon channel.
+  void SetPtCutJPsi(float cut) { fCutJPsiPt = cut; } ///< Sets the cut on transverse momentum of each daughter track of \f$J/\psi\f$.
+  
+  void SetPtCutCharm(float cut)         { fCutCharmPt = cut; } ///< Sets the cut on transverse momentum of each daughter track of open charm particles.
+  void SetChiPrimaryCutCharm(float cut) { fCutCharmChiPrim = cut; } ///< Sets cut on \f$\chi^2_{prim}\f$ of each track for open charm particles.
+  void SetLdLCutCharmManybodyDecays(float cut)      { fCutsTrackV0[1][0] = cut; } ///< Sets \f$l/\Delta l\f$ cut for open charm with >=3 daughters.
+  void SetChi2TopoCutCharmManybodyDecays(float cut) { fCutsTrackV0[1][1] = cut; } ///< Sets \f$\chi^2_{topo}\f$ cut for open charm with >=3 daughters.
+  void SetChi2CutCharmManybodyDecays(float cut)     { fCutsTrackV0[1][2] = cut; } ///< Sets \f$\chi^2_{geo}\f$ cut for open charm with >=3 daughters.
+
+  void SetLdLCutCharm2D(float cut)      { fCutsCharm[1] = cut; } ///< Sets \f$l/\Delta l\f$ cut for open charm with 2 daughters.
+  void SetChi2TopoCutCharm2D(float cut) { fCutsCharm[2] = cut; } ///< Sets \f$\chi^2_{topo}\f$ cut for open charm with 2 daughters.
+  void SetChi2CutCharm2D(float cut)     { fCutsCharm[0] = cut; } ///< Sets \f$\chi^2_{geo}\f$ cut for open charm with 2 daughters.
+  
+  void CopyCuts(const KFParticleFinder* finder)
+  {
+    /** Copies all cuts from the external KFParticleFinder "finder" to the current object.
+     ** \param[in] finder - constant pointer to the external KFParticleFinder object
+     **/
+    fDistanceCut = finder->fDistanceCut;
+    fLCut = finder->fLCut;
+    for(int iCut=0; iCut<3; iCut++)
+      fCuts2D[iCut] = finder->fCuts2D[iCut];
+    for(int iCut=0; iCut<3; iCut++)
+      fSecCuts[iCut] = finder->fSecCuts[iCut];
+    for(int iCut=0; iCut<3; iCut++)
+      for(int jCut=0; jCut<3; jCut++)
+        fCutsTrackV0[iCut][jCut] = finder->fCutsTrackV0[iCut][jCut];
+    for(int iCut=0; iCut<2; iCut++)
+      for(int jCut=0; jCut<3; jCut++)
+        fCutsPartPart[iCut][jCut] = finder->fCutsPartPart[iCut][jCut];
+    fCutCharmPt = finder->fCutCharmPt;
+    fCutCharmChiPrim = finder->fCutCharmChiPrim;
+    for(int iCut=0; iCut<3; iCut++)
+      fCutsCharm[iCut] = finder->fCutsCharm[iCut];  
+    fCutLVMPt = finder->fCutLVMPt;
+    fCutLVMP = finder->fCutLVMP;
+    fCutJPsiPt = finder->fCutJPsiPt;
+  }
+  
+  //Functionality to check the cuts
+  const float GetMaxDistanceBetweenParticlesCut() const { return fDistanceCut; } ///< Returns cut on the distance between secondary tracks at the DCA point.
+  const float GetLCut() const { return fLCut; } ///< Returns cut on the distance to the primary vertex from the decay vertex.
+  
+  const float GetChiPrimaryCut2D() const { return fCuts2D[0]; } ///< Returns cut on \f$\chi^2_{prim}\f$ of each track for 2-daughter decays.
+  const float GetChi2Cut2D()       const { return fCuts2D[1]; } ///< Returns cut on \f$\chi^2_{geo}\f$ for 2-daughter decays.
+  const float GetLdLCut2D()        const { return fCuts2D[2]; } ///< Returns cut on \f$l/\Delta l\f$ for 2-daughter decays.
+  
+  const float GetSecondarySigmaMassCut() const { return fSecCuts[0]; } ///< Returns \f$\sigma_{M}\f$ cut for selection of primary and secondary candidates.
+  const float GetSecondaryChi2TopoCut()  const { return fSecCuts[1]; } ///< Returns \f$\chi^2_{topo}\f$ cut for selection of primary and secondary candidates.
+  const float GetSecondaryLdLCut()       const { return fSecCuts[2]; } ///< Returns \f$l/\Delta l\f$ cut for selection of primary and secondary candidates.
+  
+  const float GetLdLCutXiOmega()      const { return fCutsTrackV0[0][0]; } ///< Returns \f$l/\Delta l\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+  const float GetChi2TopoCutXiOmega() const { return fCutsTrackV0[0][1]; } ///< Returns \f$\chi^2_{topo}\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+  const float GetChi2CutXiOmega()     const { return fCutsTrackV0[0][2]; } ///< Returns \f$\chi^2_{geo}\f$ cut for \f$\Xi\f$ and \f$\Omega\f$.
+
+  const float GetChi2TopoCutResonances() const { return fCutsTrackV0[2][1]; } ///< Returns \f$\chi^2_{topo}\f$ cut for resonances.
+  const float GetChi2CutResonances()     const { return fCutsTrackV0[2][2]; } ///< Returns \f$\chi^2_{geo}\f$ cut for resonances.
+
+  const float GetPtCutLMVM() const { return fCutLVMPt; }  ///< Returns cut on transverse momentum of each daughter track of low mass vector mesons.
+  const float GetPCutLMVM()  const { return fCutLVMP; }   ///< Returns cut on momentum of each daughter track of low mass vector mesons in dimuon channel.
+  const float GetPtCutJPsi() const { return fCutJPsiPt; } ///< Returns cut on transverse momentum of each daughter track of \f$J/\psi\f$.
+  
+  const float GetPtCutCharm()         const { return fCutCharmPt; } ///< Returns the cut on transverse momentum of each daughter track of open charm particles.
+  const float GetChiPrimaryCutCharm() const { return fCutCharmChiPrim; } ///< Returns cut on \f$\chi^2_{prim}\f$ of each track for open charm particles.
+  const float GetLdLCutCharmManybodyDecays()      const { return fCutsTrackV0[1][0]; } ///< Returns \f$l/\Delta l\f$ cut for open charm with >=3 daughters.
+  const float GetChi2TopoCutCharmManybodyDecays() const { return fCutsTrackV0[1][1]; } ///< Returns \f$\chi^2_{topo}\f$ cut for open charm with >=3 daughters.
+  const float GetChi2CutCharmManybodyDecays()     const { return fCutsTrackV0[1][2]; } ///< Returns \f$\chi^2_{geo}\f$ cut for open charm with >=3 daughters.
+
+  const float GetLdLCutCharm2D()      const { return fCutsCharm[1]; } ///< Returns \f$l/\Delta l\f$ cut for open charm with 2 daughters.
+  const float GetChi2TopoCutCharm2D() const { return fCutsCharm[2]; } ///< Returns \f$\chi^2_{topo}\f$ cut for open charm with 2 daughters.
+  const float GetChi2CutCharm2D()     const { return fCutsCharm[0]; } ///< Returns \f$\chi^2_{geo}\f$ cut for open charm with 2 daughters.
+  
+  /** Add decay to the reconstruction list. If at least one is added - only those channels are considered which are in the list. Otherwise 
+   ** all decays are reconstructed.
+   ** \param[in] pdg - PDG code of the decay which should be reconstructed
+   **/
+  void AddDecayToReconstructionList(int pdg) { fDecayReconstructionList[pdg] = true; }
+  const std::map<int,bool> GetReconstructionList() const { return fDecayReconstructionList; } ///< Returns list of decays to be reconstructed.
+  void SetReconstructionList(const std::map<int,bool>& decays) { fDecayReconstructionList = decays; } ///< Set enitre reconstruction list
+
+ private:
+
+  short int fNPV; ///< Number of primary vertex candidates in the event.
+  short int fNThreads; ///< Number of threads to be run in parallel. Currently is not used. 
+  
+  float fDistanceCut; ///< Cut on the distance between secondary tracks at the DCA point, is soft and used to speed up the algorithm only.
+  float fLCut; ///< Cut on the distance to the primary vertex from the decay vertex. Is applied to \f$K^0_s\f$, \f$\Lambda\f$, \f$\Xi\f$, \f$\Omega\f$, hypernuclei and dibaryons.
+
+  float fCuts2D[3]; ///< Cuts on 2-daughter decays: \f$\chi^2_{prim}\f$, \f$\chi^2_{geo}\f$, \f$l/\Delta l\f$
+  float fSecCuts[3]; ///< Cuts to select secondary and primary particle candidates: \f$\sigma_{M}\f$, \f$\chi^2_{topo}\f$, \f$l/\Delta l\f$
+  /** \brief Cuts on the combination of track and short-lived particle candidate: \f$l/\Delta l\f$, \f$\chi^2_{topo}\f$, \f$\chi^2_{geo}\f$.
+   ** Three sets of cuts are defined: 1) for \f$\Xi\f$ and \f$\Omega\f$, 2) for hypernuclei and open charm, 3) for resonances. **/
+  float fCutsTrackV0[3][3]; 
+  /** \brief Cuts on the combination of two short-lived particle candidates: \f$l/\Delta l\f$, \f$\chi^2_{topo}\f$, \f$\chi^2_{geo}\f$. 
+   ** Two sets are defined: 1) for particles that fly away from the primary vertex and 2) for resonances. **/
+  float fCutsPartPart[2][3];
+  
+  //cuts on open charm particles with 2 daughters
+  float fCutCharmPt; ///< Cut on transverse momentum of the track for open charm reconstruction.
+  float fCutCharmChiPrim; ///< Cut on the \f$\chi^2_{prim}\f$ deviation of the track from the primary vertex for open charm reconstruction.
+  float fCutsCharm[3]; ///< Cuts on reconstructed 2-daughter charm candidates: \f$\chi^2_{geo}\f$, \f$l/\Delta l\f$, \f$\chi^2_{topo}\f$.
+  
+  //cuts on LVM
+  float fCutLVMPt; ///< Cut on transverse momentum of daughter tracks for low mass vector mesons.
+  float fCutLVMP;  ///< Cut on momentum of low mass vector mesons in dimuon channel.
+  
+  //cuts on J/Psi
+  float fCutJPsiPt; ///< Cut on transverse momentum of daughter tracks for \f$J/\psi\f$.
+  
+  //vectors with temporary particles for charm reconstruction
+  std::vector<KFParticle> fD0;         ///<Vector with temporary D0->K-pi+ candidates.
+  std::vector<KFParticle> fD0bar;      ///<Vector with temporary D0_bar->K+pi- candidates.
+  std::vector<KFParticle> fD04;        ///<Vector with temporary D0->K-pi+pi+pi- candidates.
+  std::vector<KFParticle> fD04bar;     ///<Vector with temporary D0_bar->K+pi+pi-pi- candidates.
+  std::vector<KFParticle> fD0KK;       ///<Vector with temporary D0->K+K- candidates.
+  std::vector<KFParticle> fD0pipi;     ///<Vector with temporary D0->pi+pi- candidates.
+  std::vector<KFParticle> fDPlus;      ///<Vector with temporary D+->K-pi+pi+ candidates.
+  std::vector<KFParticle> fDMinus;     ///<Vector with temporary D-->K+pi-pi- candidates.
+  std::vector<KFParticle> fDPlus3Pi;   ///<Vector with temporary D+->pi+pi+pi- candidates.
+  std::vector<KFParticle> fDMinus3Pi;  ///<Vector with temporary D-->pi+pi-pi- candidates.
+  std::vector<KFParticle> fDsPlusK2Pi; ///<Vector with temporary Ds+->K+pi+pi- candidates.
+  std::vector<KFParticle> fDsMinusK2Pi;///<Vector with temporary Ds-->K-pi+pi- candidates.
+  std::vector<KFParticle> fLcPlusP2Pi; ///<Vector with temporary Lambda_c->p pi+pi- candidates.
+  std::vector<KFParticle> fLcMinusP2Pi;///<Vector with temporary Lambda_c_bar->p-pi+pi- candidates.
+  
+  //vectors with temporary particles for H0
+  std::vector<KFParticle> fLPi;      ///< Temporary Lambda pi+ combinations
+  std::vector<int> fLPiPIndex;       ///< Index of the proton in Labmda for Lambda pi+ combinations
+  std::vector<KFParticle> fHe3Pi;    ///< Temporary He3+ pi- combinations
+  std::vector<KFParticle> fHe3PiBar; ///< Temporary He3- pi+ combinations
+  std::vector<KFParticle> fHe4Pi;    ///< Temporary He4+ pi- combinations
+  std::vector<KFParticle> fHe4PiBar; ///< Temporary He4- pi+ combinations
+  std::vector<KFParticle> fHe4L;     ///< Vector with temporary He4_Lambda->He3 p pi- candidates
+  std::vector<KFParticle> fHe5L;     ///< Vector with temporary He4_Lambda->He4 p pi- candidates
+  std::vector<KFParticle> fLLn;      ///< Vector with temporary H3_Lambda pi- candidates
+  std::vector<KFParticle> fH5LL;     ///< Vector with temporary H5_LL->He5_Lambda pi- candidates
+  
+  //vectors of candidates with the mass constraint
+  static const int fNSecCandidatesSets = 5; ///< Number of sets of secondary particle candidates.
+  /** \brief Array of vectors with secondary candidates: 0) \f$K_s^0\f$, 1) \f$\Lambda\f$, 2) \f$\overline{\Lambda}\f$, 3) \f$\gamma\f$, 4) \f$\pi^0\f$. */
+  std::vector<KFParticle> fSecCandidates[fNSecCandidatesSets];
+  static const int fNPrimCandidatesSets = 11; ///< Number of sets of primary particle candidates.
+  /** \brief Array of vectors with primary candidates for each primary vertex: 
+   ** 0) \f$K_s^0\f$, 1) \f$\Lambda\f$, 2) \f$\overline{\Lambda}\f$, 3) \f$\gamma\f$, 4) \f$\pi^0\f$, 
+   ** 5) \f$\Xi^-\f$, 6) \f$\overline{\Xi}^+\f$, 7) \f$\Omega^-\f$, 8) \f$\overline{\Omega}^+\f$, 9) \f$\Xi^{0*}\f$, 10) \f$\overline{\Xi}^{0*}\f$. */
+  std::vector< std::vector<KFParticle> > fPrimCandidates[fNPrimCandidatesSets]; //
+  static const int fNPrimCandidatesTopoSets = 9; ///< Number of sets of primary particle candidates with topological constraint.
+  /** \brief Array of vectors with primary candidates for each primary vertex with a topological constraint set:
+   ** 0) \f$K_s^0\f$, 1) \f$\Lambda\f$, 2) \f$\overline{\Lambda}\f$, 3) \f$\gamma\f$, 4) \f$\pi^0\f$, 
+   ** 5) \f$\Xi^-\f$, 6) \f$\overline{\Xi}^+\f$, 7) \f$\Omega^-\f$, 8) \f$\overline{\Omega}^+\f$. */
+  std::vector< std::vector<KFParticle> > fPrimCandidatesTopo[fNPrimCandidatesTopoSets];
+  /** \brief Array of vectors with primary candidates for each primary vertex with a topological and mass constraints set:
+   ** 0) \f$K_s^0\f$, 1) \f$\Lambda\f$, 2) \f$\overline{\Lambda}\f$, 3) \f$\gamma\f$, 4) \f$\pi^0\f$, 
+   ** 5) \f$\Xi^-\f$, 6) \f$\overline{\Xi}^+\f$, 7) \f$\Omega^-\f$, 8) \f$\overline{\Omega}^+\f$. */
+  std::vector< std::vector<KFParticle> > fPrimCandidatesTopoMass[fNPrimCandidatesTopoSets];
+  
+  KFPEmcCluster* fEmcClusters; ///< Pointer to the input gamma-clusters from the electromagnetic calorimeter.
+
+  bool fMixedEventAnalysis; ///< Flag defines if the mixed event analysis is run. In mixed event mode limited number of decays is reconstructed.
+  
+  /** \brief Map defines if the reconstruction of the decay with a certain PDG hypothesis should be run. If the map is empty - all decays are reconstructed. If at least one decay is added - only those decays will be reconstructed which are specified in the list. **/
+  std::map<int,bool> fDecayReconstructionList;
+  
+  KFParticleFinder(const KFParticleFinder&); ///< Copying is disabled for this class.
+  KFParticleFinder& operator=(const KFParticleFinder&); ///< Copying is disabled for this class.
+};
+
+#endif /* !KFParticleFinder_h */
+
diff --git a/external/KFParticle/KFParticle/KFParticlePVReconstructor.cxx b/external/KFParticle/KFParticle/KFParticlePVReconstructor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a2e7a93afd2069a8dc623fc8d4f0846018c9eac5
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticlePVReconstructor.cxx
@@ -0,0 +1,359 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFParticlePVReconstructor.h"
+#include "KFPTrackVector.h"
+#include "KFParticle.h"
+
+using std::vector;
+
+void KFParticlePVReconstructor::Init(KFPTrackVector *tracks, int nParticles)
+{
+  /** The function initialises an input for the search of primary vertices:\n
+   ** 1) it receives as an input an array with tracks;\n
+   ** 2) tracks are converted to KFParticle objects assuming pion mass;\n
+   ** 3) the position of the primary vertex is estimated with simplified
+   ** Kalman filter equations using all tracks; \n
+   ** 4) tracks are checked to deviate from the obtained estimation within
+   ** KFParticlePVReconstructor::fChi2CutPreparation; \n
+   ** 5) from the selected tracks a more precise estimation is obtained
+   ** using KFVertex::ConstructPrimaryVertex() with soft cut 
+   ** KFParticlePVReconstructor::fChi2CutPreparation; \n
+   ** 6) input particles are transported to the DCA point with the obtained
+   ** estimation;\n
+   ** 7) the weight for each particle is calculated according to its errors,
+   ** if errors are not defined after extrapolation or if particle 10 cm
+   ** away from the {0,0,0} point the weight of -100 is assigned.
+   ** \param[in] tracks - a pointer to the KFPTrackVector with input tracks
+   ** \param[in] nParticles - number of the input tracks
+   **/
+  
+  fNParticles = nParticles;
+  fParticles.resize(fNParticles);
+  fWeight.resize(fNParticles);
+  
+  float C[3] = {0,0,0};
+  int nC[3] = {0,0,0};
+  
+  KFPTrack track;
+  for ( int iTr = 0; iTr < fNParticles; iTr++ ) {
+    tracks->GetTrack(track,iTr);
+    fParticles[iTr] = KFParticle( track, 211 );
+    fParticles[iTr].AddDaughterId(track.Id());
+    float zeroPoint[3]{0,0,0};
+    fParticles[iTr].TransportToPoint(zeroPoint);
+    
+    for(int iC=0; iC<3; iC++)
+    {
+      if(!(fParticles[0].Covariance(iC,iC)==fParticles[0].Covariance(iC,iC))) continue; 
+      if(fParticles[0].Covariance(iC,iC) < 10.f && fParticles[0].Covariance(iC,iC) > 0.f )
+      {
+        C[iC] += fParticles[0].Covariance(iC,iC);
+        nC[iC]++;
+      }
+    }
+  }
+  
+  fPrimVertices.clear();
+  fClusters.clear();
+  
+  float pvEstimation[3] = {0.};
+  float pvEstimationTr[3] = {0.};
+
+  float parTmp[8] = {0.};
+  float covTmp[36] = {0.};
+  
+  for(int iC=0; iC<3; iC++)
+  {
+    if(nC[iC] >0)
+      C[iC] /= nC[iC];
+    else
+      C[iC] = 1.e-2;
+  }
+  
+  for(int iIter=0; iIter<3; iIter++)
+  {
+    C[0]*=100.f; C[1]*=100.f; C[2]*=100.f;
+    for ( int iTr = 0; iTr < fNParticles; iTr++ ) {
+      float ds = 0.f;
+      float dsdr[6] = {0.f};
+      if(iIter>0)
+        ds = fParticles[iTr].GetDStoPoint(pvEstimationTr, dsdr);
+      fParticles[iTr].Transport( ds, dsdr, parTmp, covTmp);
+
+      float r2 = parTmp[0]*parTmp[0] + parTmp[1]*parTmp[1];
+      if(!(r2==r2)) continue;
+      if(r2 > 25 ) continue;  
+      
+      const float V[3] = {covTmp[0], covTmp[2], covTmp[5]}; 
+      
+      for(int iComp=0; iComp<3; iComp++)
+      {
+        float K = C[iComp]/(C[iComp]+V[iComp]);
+        if (fabs(V[iComp]) < 1.e-8) continue;
+        if(C[iComp] > 16*V[iComp])
+          K = 1.f - V[iComp]/C[iComp];
+        const float dzeta = parTmp[iComp]-pvEstimation[iComp];
+        if(K!=K) continue;
+        if(K<0. || K>0.999) continue;
+        pvEstimation[iComp] += K*dzeta;
+        C[iComp] -= K*C[iComp];
+      }
+    }
+    pvEstimationTr[0] = pvEstimation[0];
+    pvEstimationTr[1] = pvEstimation[1];
+    pvEstimationTr[2] = pvEstimation[2];
+  }
+
+  for(int iP=0; iP<fNParticles; iP++)
+  {
+    fParticles[iP].TransportToPoint(pvEstimation);
+
+    fWeight[iP] = fParticles[iP].CovarianceMatrix()[0]
+      + fParticles[iP].CovarianceMatrix()[2] + fParticles[iP].CovarianceMatrix()[5];
+    
+    if(fWeight[iP] > 0.f)
+      fWeight[iP] = 1.f/sqrt(fWeight[iP]);
+    else
+      fWeight[iP] = -100;
+    
+    if( (fParticles[iP].X()*fParticles[iP].X() + fParticles[iP].Y()*fParticles[iP].Y()) > 100.f ) fWeight[iP] = -100.f;
+  }
+} // void KFParticlePVReconstructor::Init
+
+void KFParticlePVReconstructor::FindPrimaryClusters( int cutNDF )
+{
+  /** The functions searches for a set of clusters of particles - candidates for the primary
+   ** vertex:\n
+   ** 1) input particles are assumed to be transported to the beam line or target position;\n
+   ** 2) at first, the best particle with the highest weight is selected;\n
+   ** 3) then a cluster is formed around this particle;\n
+   ** 4) if a beam line is set it is used for the reconstruction as an additional track,
+   ** but will not be added to the resulting cluster of daughter particles;\n
+   ** 5) the primary vertex candidate is fitted with KFVertex::ConstructPrimaryVertex()
+   ** using KFParticlePVReconstructor::fChi2Cut;\n
+   ** 6) cluster is cleaned from particles deviating more then the fChi2Cut from the fitted
+   ** candidate;\n
+   ** 7) the cluster and the vertex candidate are stored if they satisfy the provided cutNDF;\n
+   ** 8) the procedure is repeated until not used tracks with well-defined weight are left.
+   ** 
+   ** \param[in] cutNDF - cut on the number of degrees of freedom (effectively - number of
+   ** particles used for the reconstruction), if resulting NDF is smaller then this cut - 
+   ** the PV-candidate is rejected
+   **/
+
+  if( IsBeamLine() )
+    cutNDF += 2;
+  
+  vector<unsigned short int> notUsedTracks(fNParticles);
+  vector<unsigned short int> *notUsedTracksPtr = &notUsedTracks;
+  int nNotUsedTracks = fNParticles;
+
+  vector<unsigned short int> notUsedTracksNew(fNParticles);
+  vector<unsigned short int> *notUsedTracksNewPtr = &notUsedTracksNew;
+  int nNotUsedTracksNew = 0;
+
+  for(int iTr=0; iTr<fNParticles; iTr++)
+    (*notUsedTracksPtr)[iTr] = iTr;
+    
+  while(nNotUsedTracks>0)
+  {
+    short int bestTrack = 0;
+    float bestWeight = -1.f;
+
+    for(unsigned short int iTr = 0; iTr < nNotUsedTracks; iTr++)
+    {
+      unsigned short int &curTrack = (*notUsedTracksPtr)[iTr];
+      
+      if (fWeight[curTrack] > bestWeight)
+      {
+        bestWeight = fWeight[curTrack];
+        bestTrack = curTrack;
+      }
+    }
+
+    if(bestWeight < 0.f) break;
+    
+    KFParticleCluster cluster;
+    cluster.fTracks.reserve(nNotUsedTracks);
+
+    const float *rBest = fParticles[bestTrack].Parameters();
+    const float *covBest = fParticles[bestTrack].CovarianceMatrix();
+
+    float rVertex[3] = {0.f};
+    float covVertex[6] = {0.f};
+    float weightVertex = 0.f;
+
+    for(unsigned short int iTr = 0; iTr < nNotUsedTracks; iTr++)
+    {
+      unsigned short int &curTrack = (*notUsedTracksPtr)[iTr];
+      float chi2deviation = fParticles[curTrack].GetDeviationFromVertex(rBest, covBest);
+      if( ( chi2deviation < fChi2CutPreparation && chi2deviation >= 0 && fWeight[curTrack] > -1.f) || curTrack == bestTrack)
+      {
+        for(int iP=0; iP<3; iP++)
+          rVertex[iP] += fWeight[curTrack] * fParticles[curTrack].Parameters()[iP];
+        
+        float weight2 = fWeight[curTrack] * fWeight[curTrack];
+        for(int iC=0; iC<6; iC++)
+          covVertex[iC] += weight2 *fParticles[curTrack].CovarianceMatrix()[iC];
+
+        weightVertex += fWeight[curTrack];
+        cluster.fTracks.push_back(curTrack);
+      }
+      else
+      {
+        (*notUsedTracksNewPtr)[nNotUsedTracksNew] = curTrack;
+        nNotUsedTracksNew++;
+      }
+    }
+    
+    vector<unsigned short int> *notUsedTracksPtrSave = notUsedTracksPtr;
+    notUsedTracksPtr = notUsedTracksNewPtr;
+    notUsedTracksNewPtr = notUsedTracksPtrSave;
+    
+    nNotUsedTracks = nNotUsedTracksNew;
+    nNotUsedTracksNew = 0;
+
+    if(cluster.fTracks.size() < 2) continue;
+    if((cluster.fTracks.size() < 3) && (fNParticles>3)) continue;
+
+    for(int iP=0; iP<3; iP++)
+      cluster.fP[iP] = rVertex[iP]/weightVertex;
+
+    for(int iC=0; iC<6; iC++)
+      cluster.fC[iC] = covVertex[iC]/(weightVertex*weightVertex);
+
+
+    int nPrimCand = cluster.fTracks.size(); // 1 is reserved for a beam line
+    int nTracks = cluster.fTracks.size();
+    
+    const KFParticle **pParticles = new const KFParticle*[nPrimCand+1]; // tmp array
+
+    for ( int iP = 0; iP < nPrimCand; iP++ )
+      pParticles[iP] = &fParticles[ cluster.fTracks[iP] ];
+
+    if( IsBeamLine() )
+    {
+      pParticles[nPrimCand] = &fBeamLine;
+      nPrimCand++;
+    }
+      
+      
+      // find prim vertex
+    KFVertex primVtx;
+
+    if(fNParticles>1)
+    {
+      // construct PV candidate from a cluster
+      bool *vFlags = new bool[nPrimCand];  // flags returned by the vertex finder
+      for(int iFl=0; iFl<nPrimCand; iFl++)
+        vFlags[iFl] = true;
+//       primVtx.SetVtxGuess(cluster.fP[0], cluster.fP[1], cluster.fP[2]);
+      primVtx.SetConstructMethod(0);
+      primVtx.ConstructPrimaryVertex( pParticles, nPrimCand, vFlags, fChi2Cut );
+
+      // clean cluster
+      vector<int> clearClusterInd;
+      clearClusterInd.reserve(cluster.fTracks.size());
+      for ( int iP = 0; iP < nTracks; iP++ ){
+        if(cluster.fTracks[iP] == bestTrack) {
+          clearClusterInd.push_back(cluster.fTracks[iP]);
+          continue;
+        }
+        if(vFlags[iP])
+          clearClusterInd.push_back(cluster.fTracks[iP]);
+        else
+        {
+          (*notUsedTracksPtr)[nNotUsedTracks] = cluster.fTracks[iP];
+          nNotUsedTracks++;
+        }
+      }
+      
+      for(unsigned short int iTr = 0; iTr < nNotUsedTracks; iTr++)
+      {
+        unsigned short int &curTrack = (*notUsedTracksPtr)[iTr];
+        if( fParticles[curTrack].GetDeviationFromVertex(primVtx)<fChi2Cut )
+        {
+          primVtx += fParticles[curTrack];
+          clearClusterInd.push_back(curTrack);
+        }
+        else
+        {
+          (*notUsedTracksNewPtr)[nNotUsedTracksNew] = curTrack;
+          nNotUsedTracksNew++;
+        }
+      }      
+      cluster.fTracks = clearClusterInd;
+
+      notUsedTracksPtrSave = notUsedTracksPtr;
+      notUsedTracksPtr = notUsedTracksNewPtr;
+      notUsedTracksNewPtr = notUsedTracksPtrSave;
+    
+      nNotUsedTracks = nNotUsedTracksNew;
+      nNotUsedTracksNew = 0;
+    
+      // save PV
+#ifdef CBM
+      if( primVtx.GetNDF() >= cutNDF && ((cluster.fTracks.size()>0.1f*fNParticles && fNParticles > 30) || fNParticles<=30 ) ) //at least 2 particles
+#else
+      if( primVtx.GetNDF() >= cutNDF)
+#endif
+      {
+        fPrimVertices.push_back(primVtx);
+        fClusters.push_back(cluster);
+      }
+      
+      if(vFlags) delete [] vFlags;
+    }
+    if(pParticles) delete [] pParticles;
+  }
+}
+
+void KFParticlePVReconstructor::ReconstructPrimVertex()
+{
+  /** Reconstructs primary vertices and corresponding clusters of tracks.
+   ** For this it calls KFParticlePVReconstructor::FindPrimaryClusters(),
+   ** if no vertex is found empty primary vertex is used.
+   **/
+  
+  FindPrimaryClusters();
+
+  if ( fPrimVertices.size() == 0 )
+  {
+    float X=0,Y=0,Z=0;
+
+    KFPVertex primVtx_tmp;
+    primVtx_tmp.SetXYZ(X, Y, Z);
+    primVtx_tmp.SetCovarianceMatrix( 0, 0, 0, 0, 0, 0 );
+    primVtx_tmp.SetNContributors(0);
+    primVtx_tmp.SetChi2(-100);
+
+    fPrimVertices.push_back(primVtx_tmp);
+    
+    KFParticleCluster cluster;
+    fClusters.push_back(cluster);
+  }
+}
+
+void KFParticlePVReconstructor::AddPV(const KFVertex &pv, const vector<int> &tracks)
+{ 
+  fPrimVertices.push_back(pv);
+  KFParticleCluster cluster;
+  cluster.fTracks = tracks;
+  fClusters.push_back(cluster);
+}
+
+void KFParticlePVReconstructor::AddPV(const KFVertex &pv)
+{
+  fPrimVertices.push_back(pv);
+  KFParticleCluster cluster;
+  fClusters.push_back(cluster);
+}
diff --git a/external/KFParticle/KFParticle/KFParticlePVReconstructor.h b/external/KFParticle/KFParticle/KFParticlePVReconstructor.h
new file mode 100644
index 0000000000000000000000000000000000000000..c59ace9680c859d79e13f7b76749bd6a33b1fd19
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticlePVReconstructor.h
@@ -0,0 +1,107 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#ifndef KFParticlePVReconstructor_H
+#define KFParticlePVReconstructor_H
+
+#include "KFVertex.h"
+#include "assert.h"
+
+#include <vector>
+
+class KFParticle;
+class KFPTrackVector;
+
+/** @class KFParticlePVReconstructor
+ ** @brief Class for reconstruction of primary vertices.
+ ** @author  I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is based on KFVertex. For reconstruction of primary vertices
+ ** the Kalman filter mathematics is used. Allows reconstruction of multiple
+ ** primary vertices.
+ **/
+
+class KFParticlePVReconstructor{
+ public:
+  KFParticlePVReconstructor():fParticles(0), fNParticles(0), fWeight(0.f), fBeamLine(), fIsBeamLine(0), fClusters(0), fPrimVertices(0), fChi2CutPreparation(100), fChi2Cut(16) {};
+  ~KFParticlePVReconstructor(){};
+  
+  void Init(KFPTrackVector *tracks, int nParticles);
+  
+  void ReconstructPrimVertex();
+
+  int NPrimaryVertices() const { return fPrimVertices.size(); } ///< Returns number of the found candidates for the primary vertex.
+  KFParticle &GetPrimVertex(int iPV=0)   { return fPrimVertices[iPV]; } ///< Returns primary vertex candidate in KFParticle with index "iPV".
+  KFVertex   &GetPrimKFVertex(int iPV=0)   { return fPrimVertices[iPV]; } ///< Returns primary vertex candidate in KFVertex with index "iPV".
+  std::vector<int>& GetPVTrackIndexArray(int iPV=0) { return fClusters[iPV].fTracks; } ///< Returns vector with track indices from a cluster with index "iPV".
+  KFParticle &GetParticle(int i){ assert( i < fNParticles ); return fParticles[i]; } ///< Returns input particle with index "i".
+  
+  void SetBeamLine(KFParticle& p) { fBeamLine = p; fIsBeamLine = 1; } ///< Sets the beam line position and direction, sets corresponding flag to "true".
+  bool IsBeamLine() const { return fIsBeamLine; } ///< Check if the beam line is set.
+  
+  /** Adds externally found primary vertex to the list together with the cluster of
+   ** tracks from this vertex.
+   ** \param[in] pv - external primary vertex
+   ** \param[in] tracks - vector with indices of tracks associated with the provided primary vertex.
+   **/
+  void AddPV(const KFVertex &pv, const std::vector<int> &tracks);
+  /** Adds externally found primary vertex to the list.
+   ** \param[in] pv - external primary vertex
+   **/
+  void AddPV(const KFVertex &pv);
+  void CleanPV() { fClusters.clear(); fPrimVertices.clear(); } ///< Clean vectors with primary vertex candidates and corresponding clusters.
+
+  /** \brief Sets cut fChi2Cut on chi2-deviation of primary tracks from the vertex candidate to "chi2"
+   ** and a soft preparation cut fChi2CutPreparation to "10*chi2". */
+  void SetChi2PrimaryCut(float chi2) { fChi2Cut = chi2; fChi2CutPreparation = chi2*5; }
+  
+ private:
+  KFParticlePVReconstructor &operator=(KFParticlePVReconstructor &); ///< Is not defined. Deny copying of the objects of this class.
+  KFParticlePVReconstructor(KFParticlePVReconstructor &); ///< Is not defined. Deny copying of the objects of this class.
+
+  void FindPrimaryClusters( int cutNDF = 1);
+
+  std::vector<KFParticle> fParticles; ///< Array of the input particles constructed from tracks.
+  int fNParticles;                    ///< Number of the input particles.
+
+  std::vector<float> fWeight; ///< Vector with weights of each track, the weight is defined in KFParticlePVReconstructor::Init().
+  
+  KFParticle fBeamLine; ///< Position and direction of the beam line.
+  bool fIsBeamLine;     ///< Flag showing if the beam line is set.
+  
+  /** @class KFParticleCluster
+   ** @brief A helper structure for reconstruction of a primary vertex.
+   ** @author  I.Kisel, M.Zyzak
+   ** @date 05.02.2019
+   ** @version 1.0
+   ** Contains a list of track and initial approximation for the vertex position,
+   ** which are then provided to KFVertex object for fit.
+   **/
+  struct KFParticleCluster {
+    KFParticleCluster():fTracks(0) {};
+    std::vector<int> fTracks; ///< List of tracks in a cluster.
+    float fP[3]; ///< Estimation of the vertex position based on the current cluster: {X, Y, Z}.
+    float fC[6]; ///< Estimated errors of the position approximation.
+  };
+
+  std::vector< KFParticleCluster > fClusters; ///< Vector with clusters to be used for fit of a primary vertex.
+  std::vector<KFVertex> fPrimVertices;  ///< Vector with reconstructed candidates for a primary vertex.
+  
+  float fChi2CutPreparation; ///< A soft cut on the chi2-deviation which is used to form a cluster.
+  float fChi2Cut;            ///< Cut on the chi2-deviation of the tracks to the primary vertex \see KFVertex::ConstructPrimaryVertex(), where it is used.
+}; // class KFParticlePVReconstructor
+
+
+#endif // KFParticlePVReconstructor_H
+  
diff --git a/external/KFParticle/KFParticle/KFParticleSIMD.cxx b/external/KFParticle/KFParticle/KFParticleSIMD.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..994fdffe68cef0c69367aadefc22424f286ad51a
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleSIMD.cxx
@@ -0,0 +1,1036 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+
+#include "KFParticleSIMD.h"
+#include "KFParticle.h"
+#include "KFParticleDatabase.h"
+
+#ifdef HomogeneousField
+float_v KFParticleSIMD::fgBz = -5.f;  //* Bz compoment of the magnetic field
+#endif
+
+KFParticleSIMD::KFParticleSIMD( const KFParticleSIMD &d1, const KFParticleSIMD &d2 ): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructs a particle from two input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   **/
+    
+  KFParticleSIMD mother;
+  mother+= d1;
+  mother+= d2;
+  *this = mother;
+}
+
+void KFParticleSIMD::Create( const float_v Param[], const float_v Cov[], int_v Charge, float_v mass /*Int_t PID*/ )
+{
+  /** Constructor from a "cartesian" track, mass hypothesis should be provided
+   **
+   ** \param[in] Param[6] = { X, Y, Z, Px, Py, Pz } - position and momentum
+   ** \param[in] Cov[21]  - lower-triangular part of the covariance matrix:@n
+   ** \verbatim
+             (  0  .  .  .  .  . )
+             (  1  2  .  .  .  . )
+   Cov[21] = (  3  4  5  .  .  . )
+             (  6  7  8  9  .  . )
+             ( 10 11 12 13 14  . )
+             ( 15 16 17 18 19 20 )
+   \endverbatim
+   ** \param[in] Charge - charge of the particle in elementary charge units
+   ** \param[in] mass - the mass hypothesis
+   **/
+  
+  float_v C[21];
+  for( int i=0; i<21; i++ ) C[i] = Cov[i];
+  
+  KFParticleBaseSIMD::Initialize( Param, C, Charge, mass );
+}
+
+KFParticleSIMD::KFParticleSIMD( const KFPTrack *track, Int_t PID ): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of the particle from an array of tracks.
+   ** \param[in] track - pointer to the array of n=float_vLen tracks
+   ** \param[in] PID - the PID hypothesis common for all elements of the SIMD vector
+   **/
+  
+  Double_t r[3];
+  Double_t C[21];
+
+  for(Int_t iPart = 0; iPart<float_vLen; iPart++)
+  {
+    track[iPart].XvYvZv(r);
+    for(Int_t i=0; i<3; i++)
+      fP[i][iPart] = r[i];
+    track[iPart].PxPyPz(r);
+    for(Int_t i=0; i<3; i++)
+      fP[i+3][iPart] = r[i];
+    fQ[iPart] = track[iPart].Charge();
+    track[iPart].GetCovarianceXYZPxPyPz( C );
+    for(Int_t i=0; i<21; i++)
+      fC[i][iPart] = C[i];
+  }
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(PID);
+  Create(fP,fC,fQ,mass);
+
+  for(Int_t iPart = 0; iPart<float_vLen; iPart++)
+  {
+    fChi2[iPart] = track[iPart].GetChi2();
+    fNDF[iPart] = track[iPart].GetNDF();
+  }
+}
+
+KFParticleSIMD::KFParticleSIMD(KFPTrack &Track, const Int_t *pdg): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of the particle from a single track. The same track is put to each element of the SIMD vector.
+   ** \param[in] Track - track in the KFPTrack format
+   ** \param[in] PID - the PID hypothesis common for all elements of the SIMD vector
+   **/
+  
+  Double_t r[3];
+  Double_t C[21];
+
+  Track.XvYvZv(r);
+  for(Int_t i=0; i<3; i++)
+    fP[i] = r[i];
+  Track.PxPyPz(r);
+  for(Int_t i=0; i<3; i++)
+    fP[i+3] = r[i];
+  fQ = Track.Charge();
+  Track.GetCovarianceXYZPxPyPz( C );
+  for(Int_t i=0; i<21; i++)
+    fC[i] = C[i];
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(*pdg);
+  Create(fP,fC,fQ,mass);
+
+  fChi2 = Track.GetChi2();
+  fNDF = Track.GetNDF();
+}
+
+KFParticleSIMD::KFParticleSIMD(KFPTrackVector &track, int n, const Int_t *pdg): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of the particle from a single track with index "n" stored in the KFPTrackVector format. 
+   ** The same track is put to each element of the SIMD vector.
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] n - index of the track to be used
+   ** \param[in] pdg - pointer to the pdg hypothesis
+   **/
+  
+  for(int i=0; i<6; i++)
+    fP[i] = track.Parameter(i)[n];
+  for(int i=0; i<21; i++)
+    fC[i] = track.Covariance(i)[n];
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    fField.fField[i] = track.FieldCoefficient(i)[n];
+#endif
+  fQ = track.Q()[n];
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(*pdg);
+  Create(fP,fC,fQ,mass);
+}
+
+  
+KFParticleSIMD::KFParticleSIMD(KFPTrack* Track[], int NTracks, const Int_t *pdg): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of the particle from an array tracks.
+   ** \param[in] Track - an array of pointers to tracks in the KFPTrack format
+   ** \param[in] NTracks - number of tracks in the arry
+   ** \param[in] pdg - pointer to the pdg hypothesis common for all elements of the SIMD vector
+   **/
+  Create(Track, NTracks, pdg);
+}
+
+void KFParticleSIMD::Create(KFPTrack* Track[], int NTracks, const Int_t *pdg)
+{
+  /** Create a particle from from an array tracks.
+   ** \param[in] Track - an array of pointers to tracks in the KFPTrack format
+   ** \param[in] NTracks - number of tracks in the arry
+   ** \param[in] pdg - pointer to the pdg hypothesis common for all elements of the SIMD vector
+   **/
+  
+  Double_t r[3];
+  Double_t C[21];
+
+  for(Int_t iPart = 0; iPart<float_vLen; iPart++)
+  {
+    Int_t iEntry = (iPart < NTracks) ? iPart : 0; 
+    Track[iEntry]->XvYvZv(r);
+    for(Int_t i=0; i<3; i++)
+      fP[i][iEntry] = r[i];
+    Track[iEntry]->PxPyPz(r);
+    for(Int_t i=0; i<3; i++)
+      fP[i+3][iEntry] = r[i];
+    fQ[iEntry] = Track[iEntry]->Charge();
+    Track[iEntry]->GetCovarianceXYZPxPyPz( C );
+    for(Int_t i=0; i<21; i++)
+      fC[i][iEntry] = C[i];
+  }
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(*pdg);
+  Create(fP,fC,fQ,mass);
+
+  for(Int_t iPart = 0; iPart<float_vLen; iPart++)
+  {
+    Int_t iEntry = (iPart < NTracks) ? iPart : 0; 
+    fChi2[iEntry] = Track[iEntry]->GetChi2();
+    fNDF[iEntry] = Track[iEntry]->GetNDF();
+  }
+}
+
+KFParticleSIMD::KFParticleSIMD(KFPTrackVector &track, uint_v& index, const int_v& pdg): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of the particle from a set of tracks with random indices "index" stored in the KFPTrackVector format.
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] index - indices of the tracks to be converted to the KFParticleSIMD object
+   ** \param[in] pdg - a SIMD vector with an individual pdg hypothesis for each element
+   **/
+  
+  Create(track, index, pdg);
+}
+
+void KFParticleSIMD::Create(KFPTrackVector &track, uint_v& index, const int_v& pdg)
+{
+  /** Create a particle from a set of tracks with indices "index" stored in the KFPTrackVector format.
+   ** The function should be used in case if indices are random. If they are aligned please use function Load()
+   ** that will benefit of the aligned memory reading and result in a faster code.
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] index - indices of the tracks to be converted to the KFParticleSIMD object
+   ** \param[in] pdg - a SIMD vector with an individual pdg hypothesis for each element
+   **/
+  
+  for(int i=0; i<6; i++)
+    fP[i].gather(&(track.Parameter(i)[0]), index);
+  for(int i=0; i<21; i++)
+    fC[i].gather(&(track.Covariance(i)[0]), index);
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    fField.fField[i].gather(&(track.FieldCoefficient(i)[0]), index);
+#endif
+  
+  //   fPDG.gather(&(track.PDG()[0]), index);
+  fQ.gather(&(track.Q()[0]), index);
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(pdg);
+  Create(fP,fC,fQ,mass);
+}
+
+void KFParticleSIMD::Load(KFPTrackVector &track, int index, const int_v& pdg)
+{
+  /** Create a particle from a set of consequetive tracks stored in the KFPTrackVector format
+   ** starting from the index "index".
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] index - index of the first track
+   ** \param[in] pdg - a SIMD vector with an individual pdg hypothesis for each element
+   **/
+  
+  for(int i=0; i<6; i++)
+    fP[i] = reinterpret_cast<const float_v&>(track.Parameter(i)[index]);
+  for(int i=0; i<21; i++)
+    fC[i] = reinterpret_cast<const float_v&>(track.Covariance(i)[index]);
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    fField.fField[i] = reinterpret_cast<const float_v&>(track.FieldCoefficient(i)[index]);
+#endif
+  
+  //   fPDG.gather(&(track.PDG()[0]), index);
+  fQ = reinterpret_cast<const int_v&>(track.Q()[index]);
+
+  float_v mass = KFParticleDatabase::Instance()->GetMass(pdg);
+  Create(fP,fC,fQ,mass);
+}
+
+void KFParticleSIMD::Rotate()
+{
+  /** Rotates the entries of each SIMD vector of the data members. */
+  
+  for(int i=0; i<7; i++)
+    fP[i] = fP[i].rotated(1);
+  for(int i=0; i<27; i++)
+    fC[i] = fC[i].rotated(1);
+#ifdef NonhomogeneousField
+  for(int i=0; i<10; i++)
+    fField.fField[i] = fField.fField[i].rotated(1);
+#endif
+  fQ = fQ.rotated(1);
+  fId = fId.rotated(1);
+}
+
+KFParticleSIMD::KFParticleSIMD(KFPEmcCluster &track, uint_v& index, const KFParticleSIMD& vertexGuess): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructor of gamma particles from a set of clusters of the electromagnetic calorimeter (EMC) 
+   ** with random indices "index". The vertex hypothesis should be provided for the estimation of the momentum.
+   ** \param[in] track - an array of EMC clusters
+   ** \param[in] index - indices of the clusters to be converted to the KFParticleSIMD object
+   ** \param[in] vertexGuess - vertex guess for estimation of the momentum of created gamma particles
+   **/
+  
+  Create(track, index, vertexGuess);
+}
+
+void KFParticleSIMD::Create(KFPEmcCluster &track, uint_v& index, const KFParticleSIMD& vertexGuess)
+{
+  /** Creates gamma particles from a set of clusters of the electromagnetic calorimeter (EMC) 
+   ** with random indices "index". The vertex hypothesis should be provided for the estimation of the momentum.
+   ** \param[in] track - an array of EMC clusters
+   ** \param[in] index - indices of the clusters to be converted to the KFParticleSIMD object
+   ** \param[in] vertexGuess - vertex guess for estimation of the momentum of created gamma particles
+   **/
+  
+  for(int i=0; i<3; i++)
+    fP[i].gather(&(track.Parameter(i)[0]), index);
+  fP[6].gather(&(track.Parameter(3)[0]), index);
+  
+  const float_v& dx = fP[0] - vertexGuess.fP[0];
+  const float_v& dy = fP[1] - vertexGuess.fP[1];
+  const float_v& dz = fP[2] - vertexGuess.fP[2];
+  const float_v& dl2 = dx*dx + dy*dy + dz*dz;
+  const float_v& dl = sqrt(dl2);
+
+  fP[0] = vertexGuess.fP[0];
+  fP[1] = vertexGuess.fP[1];
+  fP[2] = vertexGuess.fP[2];
+  
+  fP[3] = dx/dl * fP[6];
+  fP[4] = dy/dl * fP[6];
+  fP[5] = dz/dl * fP[6];
+  
+  float_v V[10];
+  for(int i=0; i<10; i++)
+    V[i].gather(&(track.Covariance(i)[0]), index);
+  
+  float_v J[7][4];
+  for(int i=0; i<7; i++)
+    for(int j=0; j<4; j++)
+      J[i][j] = 0.f;
+  J[0][0] = 1.f; J[1][1] = 1.f; J[2][2] = 1.f; J[6][3] = 1.f;
+  J[3][0] = fP[6]/dl * (1.f - dx*dx/dl2); J[3][1] = -dx*dy*fP[6]/(dl*dl2); J[3][2] = -dx*dz*fP[6]/(dl*dl2); J[3][3] = dx/dl;
+  J[4][0] = -dx*dy*fP[6]/(dl*dl2); J[4][1] = fP[6]/dl * (1.f - dy*dy/dl2); J[4][2] = -dy*dz*fP[6]/(dl*dl2); J[4][3] = dy/dl;
+  J[5][0] = -dx*dz*fP[6]/(dl*dl2); J[5][1] = -dy*dz*fP[6]/(dl*dl2); J[5][2] = fP[6]/dl * (1.f - dz*dz/dl2); J[5][3] = dz/dl;
+  
+  float_v VJT[4][7]; // V*J^T
+  for(Int_t i=0; i<4; i++)
+  {
+    for(Int_t j=0; j<7; j++)
+    {
+      VJT[i][j] = 0.f;
+      for(Int_t k=0; k<4; k++)
+        VJT[i][j] += V[IJ(i,k)]*J[j][k];
+    }
+  }
+  //Calculate the covariance matrix of the particle fC
+  for( Int_t i=0; i<36; i++ ) fC[i] = 0.f;
+  
+  for(Int_t i=0; i<7; ++i)
+    for(Int_t j=0; j<=i; ++j)
+      for(Int_t l=0; l<4; l++)
+        fC[IJ(i,j)]+= J[i][l]*VJT[l][j];
+  fC[35] = 1.f;
+  
+  fQ = int_v(Vc::Zero);
+  fNDF = 0;
+  fChi2 = 0;
+  
+  SumDaughterMass = float_v(Vc::Zero);
+  fMassHypo = float_v(Vc::Zero);
+}
+
+KFParticleSIMD::KFParticleSIMD(KFPEmcCluster &track, int index, const KFParticleSIMD& vertexGuess): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructr gamma particles from a set of consequetive clusters of the electromagnetic calorimeter (EMC) 
+   ** starting from the index "index". The vertex hypothesis should be provided for the estimation of the momentum.
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] index - index of the first EMC cluster
+   ** \param[in] vertexGuess - vertex guess for estimation of the momentum of created gamma particles
+   **/
+  
+  Load(track, index, vertexGuess);
+}
+
+void KFParticleSIMD::Load(KFPEmcCluster &track, int index, const KFParticleSIMD& vertexGuess)
+{
+  /** Create gamma particles from a set of consequetive clusters of the electromagnetic calorimeter (EMC) 
+   ** starting from the index "index". The vertex hypothesis should be provided for the estimation of the momentum.
+   ** \param[in] track - an array with tracks in the KFPTrackVector format
+   ** \param[in] index - index of the first EMC cluster
+   ** \param[in] vertexGuess - vertex guess for estimation of the momentum of created gamma particles
+   **/
+  
+  for(int i=0; i<3; i++)
+    fP[i] = reinterpret_cast<const float_v&>(track.Parameter(i)[index]);
+  fP[6] = reinterpret_cast<const float_v&>(track.Parameter(3)[index]);
+  const float_v& dx = fP[0] - vertexGuess.fP[0];
+  const float_v& dy = fP[1] - vertexGuess.fP[1];
+  const float_v& dz = fP[2] - vertexGuess.fP[2];
+  const float_v& dl2 = dx*dx + dy*dy + dz*dz;
+  const float_v& dl = sqrt(dl2);
+
+  fP[0] = vertexGuess.fP[0];
+  fP[1] = vertexGuess.fP[1];
+  fP[2] = vertexGuess.fP[2];
+  
+  fP[3] = dx/dl * fP[6];
+  fP[4] = dy/dl * fP[6];
+  fP[5] = dz/dl * fP[6];
+  
+  float_v V[10];
+  for(int i=0; i<10; i++)
+    V[i] = reinterpret_cast<const float_v&>(track.Covariance(i)[index]);
+  
+  float_v J[7][4];
+  for(int i=0; i<7; i++)
+    for(int j=0; j<4; j++)
+      J[i][j] = 0.f;
+  J[0][0] = 1.f; J[1][1] = 1.f; J[2][2] = 1.f; J[6][3] = 1.f;
+  J[3][0] = fP[6]/dl * (1.f - dx*dx/dl2); J[3][1] = -dx*dy*fP[6]/(dl*dl2); J[3][2] = -dx*dz*fP[6]/(dl*dl2); J[3][3] = dx/dl;
+  J[4][0] = -dx*dy*fP[6]/(dl*dl2); J[4][1] = fP[6]/dl * (1.f - dy*dy/dl2); J[4][2] = -dy*dz*fP[6]/(dl*dl2); J[4][3] = dy/dl;
+  J[5][0] = -dx*dz*fP[6]/(dl*dl2); J[5][1] = -dy*dz*fP[6]/(dl*dl2); J[5][2] = fP[6]/dl * (1.f - dz*dz/dl2); J[5][3] = dz/dl;
+  
+  float_v VJT[4][7]; // V*J^T
+  for(Int_t i=0; i<4; i++)
+  {
+    for(Int_t j=0; j<7; j++)
+    {
+      VJT[i][j] = 0.f;
+      for(Int_t k=0; k<4; k++)
+        VJT[i][j] += V[IJ(i,k)]*J[j][k];
+    }
+  }
+  //Calculate the covariance matrix of the particle fC
+  for( Int_t i=0; i<36; i++ ) fC[i] = 0.f;
+  
+  for(Int_t i=0; i<7; ++i)
+    for(Int_t j=0; j<=i; ++j)
+      for(Int_t l=0; l<4; l++)
+        fC[IJ(i,j)]+= J[i][l]*VJT[l][j];
+  fC[35] = 1.f;
+  
+  fQ = int_v(Vc::Zero);
+  fNDF = 0;
+  fChi2 = 0;
+  
+  SumDaughterMass = float_v(Vc::Zero);
+  fMassHypo = float_v(Vc::Zero);
+}
+
+KFParticleSIMD::KFParticleSIMD( const KFPVertex &vertex ): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Copies a vertex in KFPVertex into each element of the vectorised KFParticle
+   ** \param[in] vertex - vertex to b converted
+   **/
+  
+  Double_t r[3];
+  Double_t C[21];
+
+  vertex.GetXYZ( r );
+  for(Int_t i=0; i<3; i++)
+    fP[i] = r[i];
+  vertex.GetCovarianceMatrix( C );
+  for(Int_t i=0; i<21; i++)
+    fC[i] = C[i];
+  fChi2 = vertex.GetChi2();
+  fNDF = 2*vertex.GetNContributors() - 3;
+  fQ = int_v(Vc::Zero);
+  fAtProductionVertex = 0;
+  fSFromDecay = 0;
+}
+
+void KFParticleSIMD::SetOneEntry(int iEntry, KFParticleSIMD& part, int iEntryPart)
+{
+  /** Copies one element of the KFParticleSIMD to one element of another KFParticleSIMD.
+   ** \param[in] iEntry - index of the element of the current track, where the data will be copied
+   ** \param[in] part - particle, element of which should be copied to the current particle
+   ** \param[in] iEntryPart - index of the element of particle part, which should be copied to the current particle
+   **/
+  
+  for( int i = 0; i < 7; ++i )
+    fP[i][iEntry] = part.Parameters()[i][iEntryPart];
+  for( int i = 0; i < 36; ++i )
+    fC[i][iEntry] = part.CovarianceMatrix()[i][iEntryPart];
+  
+  fQ[iEntry] = part.Q()[iEntryPart];
+  fNDF[iEntry] = part.NDF()[iEntryPart];
+  fChi2[iEntry] = part.Chi2()[iEntryPart];
+  
+//   fSFromDecay[iEntry] = part.fSFromDecay[iEntryPart];
+//   SumDaughterMass[iEntry] = part.SumDaughterMass[iEntryPart];
+//   fMassHypo[iEntry] = part.fMassHypo[iEntryPart];
+
+  fId[iEntry] = part.Id()[iEntryPart];
+
+  fPDG[iEntry] = part.GetPDG()[iEntryPart];
+  
+  if(iEntry==0)
+    fDaughterIds.resize( part.NDaughters(), int_v(-1) );
+  
+  for(int iD=0; iD<part.NDaughters(); iD++)
+    fDaughterIds[iD][iEntry] = part.fDaughterIds[iD][iEntryPart];
+
+#ifdef NonhomogeneousField
+  fField.SetOneEntry( iEntry, part.fField, iEntryPart ); //CHECKME
+#endif
+}
+
+KFParticleSIMD::KFParticleSIMD(KFParticle* parts[], const int nPart): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructs a vectoriesd particle from an array of scalar KFParticle objects.
+   ** \param[in] parts - array of scalar KFParticle objects
+   ** \param[in] nPart - number of particles in the array
+   **/
+  
+  { // check
+    bool ok = 1;
+
+    const int nD = (parts[0])->NDaughters();
+    for ( int ie = 1; ie < nPart; ie++ ) {
+      const KFParticle &part = *(parts[ie]);
+      ok &= part.NDaughters() == nD;
+    }
+    if (!ok) {
+      std::cout << " void CbmKFParticle_simd::Create(CbmKFParticle *parts[], int N) " << std::endl;
+      exit(1);
+    }
+  }
+  fDaughterIds.resize( (parts[0])->NDaughters(), int_v(-1) );
+
+  for ( int iPart = 0; iPart < float_vLen; iPart++ ) {
+    Int_t iEntry = (iPart < nPart) ? iPart : 0; 
+    KFParticle &part = *(parts[iEntry]);
+
+    fId[iEntry] = part.Id();
+    for(int iD=0; iD<part.NDaughters(); iD++)
+      fDaughterIds[iD][iEntry] = part.DaughterIds()[iD];
+
+    fPDG[iEntry] = part.GetPDG();
+    
+    for( int i = 0; i < 8; ++i )
+      fP[i][iEntry] = part.Parameters()[i];
+    for( int i = 0; i < 36; ++i )
+      fC[i][iEntry] = part.CovarianceMatrix()[i];
+
+    fNDF[iEntry] = part.GetNDF();
+    fChi2[iEntry] = part.GetChi2();
+    fQ[iEntry] = part.GetQ();
+    fAtProductionVertex = part.GetAtProductionVertex(); // CHECKME
+#ifdef NonhomogeneousField
+    fField.SetOneEntry( part.GetFieldCoeff(), iEntry);
+#endif
+  }
+}
+
+KFParticleSIMD::KFParticleSIMD( KFParticle &part): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+, fField()
+#endif
+{
+  /** Constructs a vectoriesd particle from a single scalar KFParticle object. The same particle is copied to each element.
+   ** \param[in] part - a scalar particle which should be copied to the current vectorised particle
+   **/
+  
+ fId = part.Id();
+ fNDF = part.GetNDF();
+ fChi2 = part.GetChi2();
+ fQ = part.GetQ();
+ fPDG = part.GetPDG();
+ fAtProductionVertex = part.GetAtProductionVertex();
+
+  SetNDaughters(part.NDaughters());
+  for( int i = 0; i < part.NDaughters(); ++i ) {
+    fDaughterIds.push_back( part.DaughterIds()[i] );
+  }
+  
+  for( int i = 0; i < 8; ++i )
+    fP[i] = part.Parameters()[i];
+  for( int i = 0; i < 36; ++i )
+    fC[i] = part.CovarianceMatrix()[i];
+
+#ifdef NonhomogeneousField
+  fField = KFParticleFieldRegion(part.GetFieldCoeff());
+#endif
+}
+
+float_m KFParticleSIMD::GetDistanceFromVertexXY( const float_v vtx[], const float_v Cv[], float_v &val, float_v &err ) const
+{
+  /** Calculates the DCA distance from a vertex together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   **
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[in] Cv[3] - lower-triangular part of the covariance matrix of the vertex
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+  
+  float_v mP[8];
+  float_v mC[36];
+  
+  float_v dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float_v dS = GetDStoPoint(vtx, dsdr);
+  Transport( dS, dsdr, mP, mC );  
+
+  float_v dx = mP[0] - vtx[0];
+  float_v dy = mP[1] - vtx[1];
+  float_v px = mP[3];
+  float_v py = mP[4];
+  float_v pt = sqrt(px*px + py*py);
+  float_v ex(Vc::Zero), ey(Vc::Zero);
+  float_m mask = ( pt < float_v(1.e-4) );
+
+  pt(mask) = float_v(1.f);
+  ex(!mask) = (px/pt);
+  ey(!mask) = (py/pt);
+  val(mask) = float_v(1.e4);
+  val(!mask)= dy*ex - dx*ey;
+
+  float_v h0 = -ey;
+  float_v h1 = ex;
+  float_v h3 = (dy*ey + dx*ex)*ey/pt;
+  float_v h4 = -(dy*ey + dx*ex)*ex/pt;
+  
+  err = 
+    h0*(h0*GetCovariance(0,0) + h1*GetCovariance(0,1) + h3*GetCovariance(0,3) + h4*GetCovariance(0,4) ) +
+    h1*(h0*GetCovariance(1,0) + h1*GetCovariance(1,1) + h3*GetCovariance(1,3) + h4*GetCovariance(1,4) ) +
+    h3*(h0*GetCovariance(3,0) + h1*GetCovariance(3,1) + h3*GetCovariance(3,3) + h4*GetCovariance(3,4) ) +
+    h4*(h0*GetCovariance(4,0) + h1*GetCovariance(4,1) + h3*GetCovariance(4,3) + h4*GetCovariance(4,4) );
+
+  if( Cv ){
+    err+= h0*(h0*Cv[0] + h1*Cv[1] ) + h1*(h0*Cv[1] + h1*Cv[2] ); 
+  }
+
+  err = sqrt(abs(err));
+
+  return mask;
+}
+
+float_m KFParticleSIMD::GetDistanceFromVertexXY( const float_v vtx[], float_v &val, float_v &err ) const
+{
+  /** Calculates the DCA distance from a vertex together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle only
+   **/
+  return GetDistanceFromVertexXY( vtx, 0, val, err );
+}
+
+
+float_m KFParticleSIMD::GetDistanceFromVertexXY( const KFParticleSIMD &Vtx, float_v &val, float_v &err ) const 
+{
+  /** Calculates the DCA distance from a vertex in the KFParticle format together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+  
+  return GetDistanceFromVertexXY( Vtx.fP, Vtx.fC, val, err );
+}
+
+#ifdef HomogeneousField
+float_m KFParticleSIMD::GetDistanceFromVertexXY( const KFPVertex &Vtx, float_v &val, float_v &err ) const 
+{
+  /** Calculates the DCA distance from a vertex in the KFPVertex format together with the error in the XY plane.
+   ** Returns "true" if calculation is failed, "false" if both value and the error are well defined.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   ** \param[out] val - the distance in the XY plane to the vertex
+   ** \param[out] err - the error of the calculated distance, takes into account errors of the particle and vertex
+   **/
+  
+  return GetDistanceFromVertexXY( KFParticleSIMD(Vtx), val, err );
+}
+#endif
+
+float_v KFParticleSIMD::GetDistanceFromVertexXY( const float_v vtx[] ) const
+{
+  /** Returns the DCA distance from a vertex in the XY plane.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   **/
+
+  float_v val, err;
+  GetDistanceFromVertexXY( vtx, 0, val, err );
+  return val;
+}
+
+float_v KFParticleSIMD::GetDistanceFromVertexXY( const KFParticleSIMD &Vtx ) const 
+{
+  /** Returns the DCA distance from a vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+  
+  return GetDistanceFromVertexXY( Vtx.fP );
+}
+
+#ifdef HomogeneousField
+float_v KFParticleSIMD::GetDistanceFromVertexXY( const KFPVertex &Vtx ) const 
+{
+  /** Returns the DCA distance from a vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   **/
+  
+  return GetDistanceFromVertexXY( KFParticleSIMD(Vtx).fP );
+}
+#endif
+
+float_v KFParticleSIMD::GetDistanceFromParticleXY( const KFParticleSIMD &p ) const 
+{
+  /** Returns the DCA distance between the current and the second particles in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v dS[2];
+  float_v dsdr[4][6];
+  GetDStoParticle( p, dS, dsdr );   
+  float_v mP[8], mC[36], mP1[8], mC1[36];
+  Transport( dS[0], dsdr[0], mP, mC ); 
+  p.Transport( dS[1], dsdr[3], mP1, mC1 ); 
+  float_v dx = mP[0]-mP1[0]; 
+  float_v dy = mP[1]-mP1[1]; 
+  return sqrt(dx*dx+dy*dy);
+}
+
+float_v KFParticleSIMD::GetDeviationFromParticleXY( const KFParticleSIMD &p ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from other particle in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  float_v F1[36], F2[36], F3[36], F4[36];
+  for(int i1=0; i1<36; i1++)
+  {
+    F1[i1] = 0;
+    F2[i1] = 0;
+    F3[i1] = 0;
+    F4[i1] = 0;
+  }
+  GetDStoParticle( p, ds, dsdr );
+  
+  float_v V0Tmp[36] ;
+  float_v V1Tmp[36] ;
+
+  
+  float_v mP1[8], mC1[36];
+  float_v mP2[8], mC2[36]; 
+  
+    Transport(ds[0], dsdr[0], mP1, mC1, dsdr[1], F1, F2);
+  p.Transport(ds[1], dsdr[3], mP2, mC2, dsdr[2], F4, F3);
+  
+  MultQSQt(F2, p.fC, V0Tmp, 6);
+  MultQSQt(F3,   fC, V1Tmp, 6);
+      
+  for(int iC=0; iC<3; iC++)
+    mC1[iC] += V0Tmp[iC] + mC2[iC] + V1Tmp[iC];
+
+  float_v d[3]={ mP2[0]-mP1[0], mP2[1]-mP1[1], mP2[2]-mP1[2]};
+  
+  return ( ( mC1[0]*d[0] + mC1[1]*d[1])*d[0]
+           +(mC1[1]*d[0] + mC1[2]*d[1])*d[1] );
+}
+
+
+float_v KFParticleSIMD::GetDeviationFromVertexXY( const float_v vtx[], const float_v Cv[] ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the XY plane.
+   ** \param[in] vtx[2] - { X, Y } coordinates of the vertex
+   ** \param[in] Cv[3] - lower-triangular part of the covariance matrix of the vertex
+   **/
+  
+  float_v mP[8];
+  float_v mC[36];
+  float_v dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float_v dS = GetDStoPoint(vtx, dsdr);
+  float_v dsdp[6] = {-dsdr[0], -dsdr[1], -dsdr[2], 0.f, 0.f, 0.f};
+  float_v F[36], F1[36];
+  for(int i2=0; i2<36; i2++)
+  {
+    F[i2]  = 0.f;
+    F1[i2] = 0.f;
+  }
+  Transport( dS, dsdr, mP, mC, dsdp, F, F1 );  
+
+  if(Cv)
+  {
+    float_v VFT[3][6];
+    for(int i=0; i<3; i++)
+      for(int j=0; j<6; j++)
+      {
+        VFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          VFT[i][j] +=  Cv[IJ(i,k)] * F1[j*6+k];
+        }
+      }
+  
+    float_v FVFT[6][6];
+    for(int i=0; i<6; i++)
+      for(int j=0; j<6; j++)
+      {
+        FVFT[i][j] = 0;
+        for(int k=0; k<3; k++)
+        {
+          FVFT[i][j] += F1[i*6+k] * VFT[k][j];
+        }
+      }
+    mC[0] += FVFT[0][0] + Cv[0];
+    mC[1] += FVFT[1][0] + Cv[1];
+    mC[2] += FVFT[1][1] + Cv[2];
+    mC[3] += FVFT[2][0] + Cv[3];
+    mC[4] += FVFT[2][1] + Cv[4];
+    mC[5] += FVFT[2][2] + Cv[5];
+  }
+  
+  InvertCholetsky3(mC);
+  
+  float_v d[3]={ vtx[0]-mP[0], vtx[1]-mP[1], vtx[2]-mP[2]};
+
+  return ( ( mC[0]*d[0] + mC[1]*d[1] )*d[0]
+           +(mC[1]*d[0] + mC[2]*d[1] )*d[1] );
+}
+
+
+float_v KFParticleSIMD::GetDeviationFromVertexXY( const KFParticleSIMD &Vtx ) const  
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the KFParticle format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFParticle format
+   **/
+  
+  return GetDeviationFromVertexXY( Vtx.fP, Vtx.fC );
+}
+
+#ifdef HomogeneousField
+float_v KFParticleSIMD::GetDeviationFromVertexXY( const KFPVertex &Vtx ) const 
+{
+  /** Returns sqrt(Chi2/ndf) deviation from the vertex in the KFPVertex format in the XY plane.
+   ** \param[in] Vtx - the vertex in the KFPVertex format
+   **/
+  
+  KFParticleSIMD v(Vtx);
+  return GetDeviationFromVertexXY( v.fP, v.fC );
+}
+#endif
+
+float_v KFParticleSIMD::GetAngle  ( const KFParticleSIMD &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in 3D.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  GetDStoParticle( p, ds, dsdr );   
+  float_v mP[8], mC[36], mP1[8], mC1[36];
+  Transport( ds[0], dsdr[0], mP, mC ); 
+  p.Transport( ds[1], dsdr[3], mP1, mC1 ); 
+  float_v n = sqrt( mP[3]*mP[3] + mP[4]*mP[4] + mP[5]*mP[5] );
+  float_v n1= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4] + mP1[5]*mP1[5] );
+  n*=n1;
+  float_v a(Vc::Zero);
+  float_m mask = (n>(1.e-8f));
+  a(mask) = ( mP[3]*mP1[3] + mP[4]*mP1[4] + mP[5]*mP1[5] )/n;
+  mask = ( abs(a) < float_v(1.f));
+  float_m aPos = (a>=float_v(Vc::Zero));
+  a(mask) = KFPMath::ACos(a);
+  a((!mask) && aPos) = float_v(Vc::Zero);
+  a((!mask) && (!aPos)) = 3.1415926535f;
+  return a;
+}
+
+float_v KFParticleSIMD::GetAngleXY( const KFParticleSIMD &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in the XY plane.
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  GetDStoParticle( p, ds, dsdr );   
+  float_v mP[8], mC[36], mP1[8], mC1[36];
+  Transport( ds[0], dsdr[0], mP, mC ); 
+  p.Transport( ds[1], dsdr[3], mP1, mC1 ); 
+  float_v n = sqrt( mP[3]*mP[3] + mP[4]*mP[4] );
+  float_v n1= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4] );
+  n*=n1;
+  float_v a(Vc::Zero);
+  float_m mask = (n>(1.e-8f));
+  a = ( mP[3]*mP1[3] + mP[4]*mP1[4] )/n;
+  a(!mask) = 0.f;
+  mask = ( abs(a) < float_v(1.f));
+  float_m aPos = (a>=float_v(Vc::Zero));
+  a(mask) = KFPMath::ACos(a);
+  a((!mask) && aPos) = float_v(Vc::Zero);
+  a((!mask) && (!aPos)) = 3.1415926535f;
+  return a;
+}
+
+float_v KFParticleSIMD::GetAngleRZ( const KFParticleSIMD &p ) const 
+{
+  /** Returns the opening angle between the current and the second particle in the RZ plane, R = sqrt(X*X+Y*Y).
+   ** \param[in] p - the second particle
+   **/
+  
+  float_v ds[2] = {0.f,0.f};
+  float_v dsdr[4][6];
+  GetDStoParticle( p, ds, dsdr );   
+  float_v mP[8], mC[36], mP1[8], mC1[36];
+  Transport( ds[0], dsdr[0], mP, mC ); 
+  p.Transport( ds[1], dsdr[3], mP1, mC1 );  
+  float_v nr = sqrt( mP[3]*mP[3] + mP[4]*mP[4] );
+  float_v n1r= sqrt( mP1[3]*mP1[3] + mP1[4]*mP1[4]  );
+  float_v n = sqrt( nr*nr + mP[5]*mP[5] );
+  float_v n1= sqrt( n1r*n1r + mP1[5]*mP1[5] );
+  n*=n1;
+  float_v a(Vc::Zero);
+  float_m mask = (n>(1.e-8f));
+  a(mask) = ( nr*n1r +mP[5]*mP1[5])/n;
+  mask = ( abs(a) < float_v(Vc::Zero));
+  float_m aPos = (a>=float_v(Vc::Zero));
+  a(mask) = KFPMath::ACos(a);
+  a((!mask) && aPos) = float_v(Vc::Zero);
+  a((!mask) && (!aPos)) = 3.1415926535f;
+  return a;
+}
+
+float_v KFParticleSIMD::GetPseudoProperDecayTime( const KFParticleSIMD &pV, const float_v& mass, float_v* timeErr2 ) const
+{ 
+  /** Returns the Pseudo Proper Time of the decay = (r*pt) / |pt| * M/|pt|
+   **
+   ** \param[in] pV - the creation point of the particle
+   ** \param[in] mass - the mass of the particle
+   ** \param[out] timeErr2 - error of the returned value, if null pointer is provided - is not calculated
+   **/
+  
+  const float_v ipt2 = 1/( Px()*Px() + Py()*Py() );
+  const float_v mipt2 = mass*ipt2;
+  const float_v dx = X() - pV.X();
+  const float_v dy = Y() - pV.Y();
+
+  if ( timeErr2 ) {
+      // -- calculate error = sigma(f(r)) = f'Cf'
+      // r = {x,y,px,py,x_pV,y_pV}
+      // df/dr = { px*m/pt^2,
+      //     py*m/pt^2,
+      //    ( x - x_pV )*m*(1/pt^2 - 2(px/pt^2)^2),
+      //    ( y - y_pV )*m*(1/pt^2 - 2(py/pt^2)^2),
+      //     -px*m/pt^2,
+      //     -py*m/pt^2 }
+    const float_v f0 = Px()*mipt2;
+    const float_v f1 = Py()*mipt2;
+    const float_v mipt2derivative = mipt2*(1-2*Px()*Px()*ipt2);
+    const float_v f2 = dx*mipt2derivative;
+    const float_v f3 = -dy*mipt2derivative;
+    const float_v f4 = -f0;
+    const float_v f5 = -f1;
+
+    const float_v& mC00 =    GetCovariance(0,0);
+    const float_v& mC10 =    GetCovariance(0,1);
+    const float_v& mC11 =    GetCovariance(1,1);
+    const float_v& mC20 =    GetCovariance(3,0);
+    const float_v& mC21 =    GetCovariance(3,1);
+    const float_v& mC22 =    GetCovariance(3,3);
+    const float_v& mC30 =    GetCovariance(4,0);
+    const float_v& mC31 =    GetCovariance(4,1);
+    const float_v& mC32 =    GetCovariance(4,3);
+    const float_v& mC33 =    GetCovariance(4,4);
+    const float_v& mC44 = pV.GetCovariance(0,0);
+    const float_v& mC54 = pV.GetCovariance(1,0);
+    const float_v& mC55 = pV.GetCovariance(1,1);
+
+    *timeErr2 =
+      f5*mC55*f5 +
+      f5*mC54*f4 +
+      f4*mC44*f4 +
+      f3*mC33*f3 +
+      f3*mC32*f2 +
+      f3*mC31*f1 +
+      f3*mC30*f0 +
+      f2*mC22*f2 +
+      f2*mC21*f1 +
+      f2*mC20*f0 +
+      f1*mC11*f1 +
+      f1*mC10*f0 +
+      f0*mC00*f0;
+  }
+  return ( dx*Px() + dy*Py() )*mipt2;
+}
+
+void KFParticleSIMD::GetKFParticle(KFParticle &Part, int iPart)
+{
+  /** Copies an entry "iPart" of the current vectorised particle to the scalar KFParticle object.
+   ** \param[out] Part - an output scalar particle, where element "iPart" will be copied
+   ** \param[in] iPart - index of the element to be copied to the scalar particle
+   **/
+  
+  Part.SetId(static_cast<int>(Id()[iPart]));
+
+  Part.CleanDaughtersId();
+  for( unsigned int i = 0; i < DaughterIds().size(); i++ )
+    Part.AddDaughterId(static_cast<int>(DaughterIds()[i][iPart]));
+
+  Part.SetPDG( static_cast<int>(GetPDG()[iPart]) );
+
+  for(int iP=0; iP<8; iP++)
+    Part.Parameters()[iP] = Parameters()[iP][iPart];
+  for(int iC=0; iC<36; iC++)
+    Part.CovarianceMatrix()[iC] = CovarianceMatrix()[iC][iPart];
+
+  Part.NDF() = static_cast<int>(GetNDF()[iPart]);
+  Part.Chi2() = GetChi2()[iPart];
+  Part.Q()    = GetQ()[iPart];
+  Part.SetAtProductionVertex(fAtProductionVertex);
+#ifdef NonhomogeneousField
+  for(int iF=0; iF<10; iF++)
+    Part.SetFieldCoeff(fField.fField[iF][iPart], iF);
+#endif
+}
+
+void KFParticleSIMD::GetKFParticle(KFParticle* Part, int nPart)
+{
+  /** Copies "nPart" elements of the current vectorised particle to the array of scalar KFParticle objects.
+   ** \param[out] Part - an output array of scalar particles
+   ** \param[in] nPart - number of elements to be copied to the array of scalar objects
+   **/
+  
+  for(int i=0; i<nPart; i++)
+    GetKFParticle(Part[i],i);
+}
diff --git a/external/KFParticle/KFParticle/KFParticleSIMD.h b/external/KFParticle/KFParticle/KFParticleSIMD.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0db5a0e5a3207a73750028b7842a7a75001238e
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleSIMD.h
@@ -0,0 +1,1101 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+//#define NonhomogeneousField
+// #define HomogeneousField
+
+#ifndef KFPARTICLESIMD_H
+#define KFPARTICLESIMD_H
+
+#include "KFParticleBaseSIMD.h"
+
+#include "KFPTrack.h"
+#include "KFPTrackVector.h"
+#include "KFPEmcCluster.h"
+#include "KFPVertex.h"
+
+#ifdef NonhomogeneousField
+#include "KFParticleField.h"
+#endif
+
+class KFParticle;
+
+/** @class KFParticleSIMD
+ ** @brief The main vectorised class of KF Particle pacakge, describes particle objects.
+ ** @author  M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** Vectorised version of the KF Particle class, describes particle objects.
+ ** The particle is described with the state vector { X, Y, Z, Px, Py, Pz, E }
+ ** and the corresponding covariance matrix.
+ ** It contains functionality to create particle-object from track, to construct 
+ ** short-lived particles from other tracks or particles. The mathematics is 
+ ** based on the Kalman filter method. It also allows to subtract particles from 
+ ** the already constructed object,
+ ** to transport partices, get parameters together with their erros, get distance 
+ ** to other particles and vertices, get deviations from them in terms of errors, etc.
+ **/
+
+class KFParticleSIMD :public KFParticleBaseSIMD
+{
+  
+ public:
+
+  void *operator new(size_t size) { return _mm_malloc(size, sizeof(float_v)); }     ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size) { return _mm_malloc(size, sizeof(float_v)); }   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new(size_t size, void *ptr) { return ::operator new(size, ptr);}   ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void *operator new[](size_t size, void *ptr) { return ::operator new(size, ptr);} ///< new operator for allocation of the SIMD-alligned dynamic memory allocation
+  void operator delete(void *ptr, size_t) { _mm_free(ptr); }                        ///< delete operator for the SIMD-alligned dynamic memory release
+  void operator delete[](void *ptr, size_t) { _mm_free(ptr); }                      ///< delete operator for the SIMD-alligned dynamic memory release
+  //*
+  //*  INITIALIZATION
+  //*
+
+  //* Set magnetic field for all particles
+#ifdef HomogeneousField
+  static void SetField( float_v Bz ); ///< Set Bz field.
+#endif
+#ifdef NonhomogeneousField
+  void SetField(const KFParticleFieldRegion &field)
+  {
+    /** Set the field approximation along the particle trajectory
+     ** \param[in] field - approximation of each component of the magnetic field with the parabola alnog the particle trajectory
+     **/
+    fField = field;
+  }
+#endif
+  //* Constructor (empty)
+
+  KFParticleSIMD():KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+  , fField() 
+#endif
+  { ; }
+
+  //* Destructor (empty)
+
+  ~KFParticleSIMD(){ ; }
+
+  //* Construction of mother particle by its 2-3-4 daughters
+
+  KFParticleSIMD( const KFParticleSIMD &d1, const KFParticleSIMD &d2 );
+  KFParticleSIMD( const KFParticleSIMD &d1, const KFParticleSIMD &d2,  const KFParticleSIMD &d3 );
+  KFParticleSIMD( const KFParticleSIMD &d1, const KFParticleSIMD &d2, const KFParticleSIMD &d3, const KFParticleSIMD &d4 );
+
+ //* Initialisation from "cartesian" coordinates ( X Y Z Px Py Pz )
+ //* Parameters, covariance matrix, charge and PID hypothesis should be provided 
+
+  void Create( const float_v Param[], const float_v Cov[], int_v Charge, float_v mass /*Int_t PID*/ );
+
+  void SetOneEntry(int iEntry, KFParticleSIMD& part, int iEntryPart);
+
+  KFParticleSIMD( const KFPTrack *track, Int_t PID );
+  KFParticleSIMD( KFPTrack* Track[], int NTracks, const Int_t *pdg=0 );
+  KFParticleSIMD( KFPTrackVector &track, uint_v& index, const int_v& pdg );
+
+  void Create(KFPTrack* Track[], int NTracks, const Int_t *pdg=0);
+  void Create(KFPTrackVector &track, uint_v& index, const int_v& pdg);
+  void Load(KFPTrackVector &track, int index, const int_v& pdg);
+  void Rotate();
+
+  KFParticleSIMD(KFPTrack &Track, const Int_t *pdg=0);
+  KFParticleSIMD(KFPTrackVector &track, int n, const Int_t *pdg=0);
+
+  KFParticleSIMD( KFPEmcCluster &track, uint_v& index, const KFParticleSIMD& vertexGuess );
+  KFParticleSIMD( KFPEmcCluster &track, int index, const KFParticleSIMD& vertexGuess );
+  void Create( KFPEmcCluster &track, uint_v& index, const KFParticleSIMD& vertexGuess );
+  void Load( KFPEmcCluster &track, int index, const KFParticleSIMD& vertexGuess );
+
+    
+  //* Initialisation from VVertex 
+
+  KFParticleSIMD( const KFPVertex &vertex );
+  KFParticleSIMD( KFParticle* part[], const int nPart = 0 );
+  KFParticleSIMD( KFParticle &part );
+
+  //*
+  //*  ACCESSORS
+  //*
+
+  //* Simple accessors 
+
+  float_v GetX    () const ; ///< Retruns X coordinate of the particle, fP[0].
+  float_v GetY    () const ; ///< Retruns Y coordinate of the particle, fP[1].
+  float_v GetZ    () const ; ///< Retruns Z coordinate of the particle, fP[2].
+  float_v GetPx   () const ; ///< Retruns X component of the momentum, fP[3].
+  float_v GetPy   () const ; ///< Retruns Y component of the momentum, fP[4].
+  float_v GetPz   () const ; ///< Retruns Z component of the momentum, fP[5].
+  float_v GetE    () const ; ///< Returns energy of the particle, fP[6].
+  float_v GetS    () const ; ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  int_v   GetQ    () const ; ///< Returns charge of the particle.
+  float_v GetChi2 () const ; ///< Returns Chi2 of the fit.
+  int_v   GetNDF  () const ; ///< Returns number of decrease of freedom.
+
+  Bool_t GetAtProductionVertex() const { return fAtProductionVertex; }  ///< Returns a flag which shows if the particle is located at the production point
+
+  const float_v& X    () const { return fP[0]; } ///< Retruns X coordinate of the particle, fP[0].
+  const float_v& Y    () const { return fP[1]; } ///< Retruns Y coordinate of the particle, fP[1].
+  const float_v& Z    () const { return fP[2]; } ///< Retruns Z coordinate of the particle, fP[2].
+  const float_v& Px   () const { return fP[3]; } ///< Retruns X component of the momentum, fP[3].
+  const float_v& Py   () const { return fP[4]; } ///< Retruns Y component of the momentum, fP[4].
+  const float_v& Pz   () const { return fP[5]; } ///< Retruns Z component of the momentum, fP[5].
+  const float_v& E    () const { return fP[6]; } ///< Returns energy of the particle, fP[6].
+  const float_v& S    () const { return fP[7]; } ///< Returns dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  const int_v  & Q    () const { return fQ;    } ///< Returns charge of the particle.
+  const float_v& Chi2 () const { return fChi2; } ///< Returns Chi2 of the fit.
+  const int_v& NDF  () const { return fNDF;  }   ///< Returns number of decrease of freedom.
+  
+  float_v GetParameter ( int i ) const ;        ///< Returns P[i] parameter.
+  float_v GetCovariance( int i ) const ;        ///< Returns C[i] element of the covariance matrix in the lower triangular form.
+  float_v GetCovariance( int i, int j ) const ; ///< Returns C[i,j] element of the covariance matrix.
+
+  //* Accessors with calculations, value returned w/o error flag
+  
+  float_v GetP             () const; ///< Returns momentum
+  float_v GetPt            () const; ///< Returns transverse momentum
+  float_v GetEta           () const; ///< Returns pseudorapidity
+  float_v GetPhi           () const; ///< Returns the azimuthal angle phi 
+  float_v GetMomentum      () const; ///< Returns momentum
+  float_v GetMass          () const; ///< Returns mass
+  float_v GetDecayLength   () const; ///< Returns decay length
+  float_v GetDecayLengthXY () const; ///< Returns decay length in XY
+  float_v GetLifeTime      () const; ///< Returns life time ctau [cm]
+  float_v GetR             () const; ///< Returns distance to the origin of the coordinate system {0,0,0}
+  float_v GetRapidity() const { return float_v(0.5f)*log((fP[6] + fP[5])/(fP[6] - fP[5])); }  ///< Returns rapidity of the particle
+  
+  //* Accessors to estimated errors
+
+  float_v GetErrX             () const ; ///< Returns the error of X of current position 
+  float_v GetErrY             () const ; ///< Returns the error of Y of current position
+  float_v GetErrZ             () const ; ///< Returns the error of Z of current position
+  float_v GetErrPx            () const ; ///< Returns the error of X-compoment of the particle momentum
+  float_v GetErrPy            () const ; ///< Returns the error of Y-compoment of the particle momentum
+  float_v GetErrPz            () const ; ///< Returns the error of Z-compoment of the particle momentum
+  float_v GetErrE             () const ; ///< Returns the error of energy
+  float_v GetErrS             () const ; ///< Returns the error of decay length / momentum
+  float_v GetErrP             () const ; ///< Returns the error of momentum
+  float_v GetErrPt            () const ; ///< Returns the error of transverse momentum
+  float_v GetErrEta           () const ; ///< Returns the error of pseudorapidity
+  float_v GetErrPhi           () const ; ///< Returns the error of the azimuthal angle phi 
+  float_v GetErrMomentum      () const ; ///< Returns the error of momentum
+  float_v GetErrMass          () const ; ///< Returns the error of mass
+  float_v GetErrDecayLength   () const ; ///< Returns the error of decay length
+  float_v GetErrDecayLengthXY () const ; ///< Returns the error of decay length in XY
+  float_v GetErrLifeTime      () const ; ///< Returns the error of life time
+  float_v GetErrR             () const ; ///< Returns the error of distance to the origin of the coordinate system {0,0,0}
+
+  //* Accessors with calculations( &value, &estimated sigma )
+  //* error flag returned (0 means no error during calculations) 
+
+  float_m GetP           ( float_v &P, float_v &SigmaP ) const ;   //* momentum
+  float_m GetPt          ( float_v &Pt, float_v &SigmaPt ) const ; //* transverse momentum
+  float_m GetEta         ( float_v &Eta, float_v &SigmaEta ) const ; //* pseudorapidity
+  float_m GetPhi         ( float_v &Phi, float_v &SigmaPhi ) const ; //* phi
+  float_m GetMomentum    ( float_v &P, float_v &SigmaP ) const ;   //* momentum
+  float_m GetMass        ( float_v &M, float_v &SigmaM ) const ;   //* mass
+  float_m GetDecayLength ( float_v &L, float_v &SigmaL ) const ;   //* decay length
+  float_m GetDecayLengthXY ( float_v &L, float_v &SigmaL ) const ;   //* decay length in XY
+  float_m GetLifeTime    ( float_v &T, float_v &SigmaT ) const ;   //* life time
+  float_m GetR           ( float_v &R, float_v &SigmaR ) const ; //* R
+
+
+  //*
+  //*  MODIFIERS
+  //*
+  
+  float_v & X    () ; ///< Modifier of X coordinate of the particle, fP[0].
+  float_v & Y    () ; ///< Modifier of Y coordinate of the particle, fP[1].
+  float_v & Z    () ; ///< Modifier of Z coordinate of the particle, fP[2].
+  float_v & Px   () ; ///< Modifier of X component of the momentum, fP[3].
+  float_v & Py   () ; ///< Modifier of Y component of the momentum, fP[4].
+  float_v & Pz   () ; ///< Modifier of Z component of the momentum, fP[5].
+  float_v & E    () ; ///< Modifier of energy of the particle, fP[6].
+  float_v & S    () ; ///< Modifier of dS=l/p, l - decay length, fP[7], defined if production vertex is set.
+  int_v   & Q    () ; ///< Modifier of charge of the particle.
+  float_v & Chi2 () ; ///< Modifier of Chi2 of the fit.
+  int_v & NDF  () ;   ///< Modifier of number of decrease of freedom.
+
+  float_v & Parameter ( int i ) ;         ///< Modifier of P[i] parameter.
+  float_v & Covariance( int i ) ;         ///< Modifier of C[i] element of the covariance matrix in the lower triangular form.
+  float_v & Covariance( int i, int j ) ;  ///< Modifier of C[i,j] element of the covariance matrix.
+  float_v * Parameters () ;               ///< Returns pointer to the parameters fP
+  float_v * CovarianceMatrix() ;          ///< Returns pointer to the covariance matrix fC
+
+  void GetKFParticle( KFParticle &Part, int iPart = 0);
+  void GetKFParticle( KFParticle *Part, int nPart = 0);
+
+  //* 
+  //* CONSTRUCTION OF THE PARTICLE BY ITS DAUGHTERS AND MOTHER
+  //* USING THE KALMAN FILTER METHOD
+  //*
+
+
+  //* Add daughter to the particle 
+
+  void AddDaughter( const KFParticleSIMD &Daughter );
+
+  //* Add daughter via += operator: ex.{ D0; D0+=Pion; D0+= Kaon; }
+
+  void operator +=( const KFParticleSIMD &Daughter );  
+
+  //* Everything in one go  
+
+  void Construct( const KFParticleSIMD *vDaughters[], int nDaughters, 
+                  const KFParticleSIMD *ProdVtx=0,   Float_t Mass=-1 );
+
+  //*
+  //*                   TRANSPORT
+  //* 
+  //*  ( main transportation parameter is S = SignedPath/Momentum )
+  //*  ( parameters of decay & production vertices are stored locally )
+  //*
+
+  //* Transport the particle close to xyz[] point 
+
+  void TransportToPoint( const float_v xyz[] );
+
+  //* Transport the particle close to VVertex  
+#ifdef HomogeneousField
+  void TransportToVertex( const KFPVertex &v );
+#endif
+  //* Transport the particle close to another particle p 
+
+  void TransportToParticle( const KFParticleSIMD &p );
+
+  //* Get dS to a certain space point 
+
+  float_v GetDStoPoint( const float_v xyz[3], float_v dsdr[6] ) const ;
+  
+  //* Get dS to other particle p (dSp for particle p also returned) 
+
+  void GetDStoParticle( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] ) const ;
+  void GetDStoParticleFast( const KFParticleBaseSIMD &p, float_v dS[2] ) const ;
+  //* 
+  //* OTHER UTILITIES
+  //*
+ 
+  //* Calculate distance from another object [cm] in XY-plane
+
+  float_m GetDistanceFromVertexXY( const float_v vtx[], float_v &val, float_v &err ) const ;
+  float_m GetDistanceFromVertexXY( const float_v vtx[], const float_v Cv[], float_v &val, float_v &err ) const ;
+  float_m GetDistanceFromVertexXY( const KFParticleSIMD &Vtx, float_v &val, float_v &err ) const ;
+#ifdef HomogeneousField
+  float_m GetDistanceFromVertexXY( const KFPVertex &Vtx, float_v &val, float_v &err ) const ;
+#endif
+
+  float_v GetDistanceFromVertexXY( const float_v vtx[] ) const ;
+  float_v GetDistanceFromVertexXY( const KFParticleSIMD &Vtx ) const ;
+#ifdef HomogeneousField
+  float_v GetDistanceFromVertexXY( const KFPVertex &Vtx ) const ;
+#endif
+  float_v GetDistanceFromParticleXY( const KFParticleSIMD &p ) const ;
+
+  //* Calculate sqrt(Chi2/ndf) deviation from another object in XY plane
+  //* ( v = [xyz]-vertex, Cv=[Cxx,Cxy,Cyy,Cxz,Cyz,Czz]-covariance matrix )
+
+  float_v GetDeviationFromVertexXY( const float_v v[], const float_v Cv[]=0 ) const ;
+  float_v GetDeviationFromVertexXY( const KFParticleSIMD &Vtx ) const ;
+#ifdef HomogeneousField
+  float_v GetDeviationFromVertexXY( const KFPVertex &Vtx ) const ;
+#endif
+  float_v GetDeviationFromParticleXY( const KFParticleSIMD &p ) const ;
+
+  //* Calculate opennig angle between two particles
+
+  float_v GetAngle  ( const KFParticleSIMD &p ) const ;
+  float_v GetAngleXY( const KFParticleSIMD &p ) const ;
+  float_v GetAngleRZ( const KFParticleSIMD &p ) const ;
+
+    // * Pseudo Proper Time of decay = (r*pt) / |pt| * M/|pt|
+    // @primVertex - primary vertex
+    // @mass - mass of the mother particle (in the case of "Hb -> JPsi" it would be JPsi mass)
+    // @*timeErr2 - squared error of the decay time. If timeErr2 = 0 it isn't calculated
+  float_v GetPseudoProperDecayTime( const KFParticleSIMD &primVertex, const float_v& mass, float_v* timeErr2 = 0 ) const;
+
+  void GetFieldValue( const float_v xyz[], float_v B[] ) const ;
+  
+  void Transport( float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1=0, float_v* F=0, float_v* F1=0  ) const ;
+  void TransportFast( float_v dS, float_v P[] ) const ;
+  
+ protected: 
+  
+  //*
+  //*  INTERNAL STUFF
+  //* 
+
+  //* Method to access ALICE field 
+#ifdef HomogeneousField
+  static float_v GetFieldAlice();
+#endif
+  //* Other methods required by the abstract KFParticleBaseSIMD class 
+  
+ private:
+#ifdef HomogeneousField
+  static float_v fgBz;  ///< Bz compoment of the magnetic field (is defined in case of #ifdef HomogeneousField)
+#endif
+#ifdef NonhomogeneousField
+  /** \brief Approximation of the magnetic field along the track trajectory.
+   ** Each component (Bx, By, Bz) is approximated with the parabola depending on Z coordinate. Is defined in case of #ifdef NonhomogeneousField.
+   **/
+  KFParticleFieldRegion fField;
+#endif
+};
+
+
+
+//---------------------------------------------------------------------
+//
+//     Inline implementation of the KFParticleSIMD methods
+//
+//---------------------------------------------------------------------
+
+#ifdef HomogeneousField
+inline void KFParticleSIMD::SetField( float_v Bz )
+{ 
+  /** Sets the constant homogemeous one-component magnetic field Bz (is defined in case of #ifdef HomogeneousField).
+   ** \param[in] Bz - Z-component of the magnetic field
+   **/
+  fgBz = Bz;
+}
+#endif
+
+inline KFParticleSIMD::KFParticleSIMD( const KFParticleSIMD &d1, 
+                                       const KFParticleSIMD &d2, 
+                                       const KFParticleSIMD &d3 ): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+                                       , fField()
+#endif
+{
+  /** Constructs a particle from three input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   ** \param[in] d3 - the third daughter particle
+   **/
+    
+  KFParticleSIMD mother;
+  mother+= d1;
+  mother+= d2;
+  mother+= d3;
+  *this = mother;
+}
+
+inline KFParticleSIMD::KFParticleSIMD( const KFParticleSIMD &d1, 
+                               const KFParticleSIMD &d2, 
+                               const KFParticleSIMD &d3, 
+                               const KFParticleSIMD &d4 ): KFParticleBaseSIMD()
+#ifdef NonhomogeneousField
+                                                          , fField()
+#endif
+{
+  /** Constructs a particle from four input daughter particles
+   ** \param[in] d1 - the first daughter particle
+   ** \param[in] d2 - the second daughter particle
+   ** \param[in] d3 - the third daughter particle
+   ** \param[in] d4 - the fourth daughter particle
+   **/
+  
+  KFParticleSIMD mother;
+  mother+= d1;
+  mother+= d2;
+  mother+= d3;
+  mother+= d4;
+  *this = mother;
+}
+
+inline float_v KFParticleSIMD::GetX    () const 
+{ 
+  return KFParticleBaseSIMD::GetX();    
+}
+
+inline float_v KFParticleSIMD::GetY    () const 
+{ 
+  return KFParticleBaseSIMD::GetY();    
+}
+
+inline float_v KFParticleSIMD::GetZ    () const 
+{ 
+  return KFParticleBaseSIMD::GetZ();    
+}
+
+inline float_v KFParticleSIMD::GetPx   () const 
+{ 
+  return KFParticleBaseSIMD::GetPx();   
+}
+
+inline float_v KFParticleSIMD::GetPy   () const 
+{ 
+  return KFParticleBaseSIMD::GetPy();   
+}
+
+inline float_v KFParticleSIMD::GetPz   () const 
+{ 
+  return KFParticleBaseSIMD::GetPz();   
+}
+
+inline float_v KFParticleSIMD::GetE    () const 
+{ 
+  return KFParticleBaseSIMD::GetE();    
+}
+
+inline float_v KFParticleSIMD::GetS    () const 
+{ 
+  return KFParticleBaseSIMD::GetS();    
+}
+
+inline int_v    KFParticleSIMD::GetQ    () const 
+{ 
+  return KFParticleBaseSIMD::GetQ();    
+}
+
+inline float_v KFParticleSIMD::GetChi2 () const 
+{ 
+  return KFParticleBaseSIMD::GetChi2(); 
+}
+
+inline int_v    KFParticleSIMD::GetNDF  () const 
+{ 
+  return KFParticleBaseSIMD::GetNDF();  
+}
+
+inline float_v KFParticleSIMD::GetParameter ( int i ) const 
+{ 
+  return KFParticleBaseSIMD::GetParameter(i);  
+}
+
+inline float_v KFParticleSIMD::GetCovariance( int i ) const 
+{ 
+  return KFParticleBaseSIMD::GetCovariance(i); 
+}
+
+inline float_v KFParticleSIMD::GetCovariance( int i, int j ) const 
+{ 
+  return KFParticleBaseSIMD::GetCovariance(i,j);
+}
+
+
+inline float_v KFParticleSIMD::GetP    () const
+{
+  float_v par, err;
+  KFParticleBaseSIMD::GetMomentum( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetPt   () const
+{
+  float_v par, err;
+  KFParticleBaseSIMD::GetPt( par, err ) ;
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetEta   () const
+{
+  float_v par, err;
+  KFParticleBaseSIMD::GetEta( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetPhi   () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetPhi( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetMomentum    () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetMomentum( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetMass        () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetMass( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetDecayLength () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetDecayLength( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetDecayLengthXY () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetDecayLengthXY( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetLifeTime    () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetLifeTime( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetR   () const
+{
+  float_v par, err;
+  KFParticleSIMD::GetR( par, err );
+  return par;
+}
+
+inline float_v KFParticleSIMD::GetErrX           () const 
+{
+  return sqrt(abs( GetCovariance(0,0) ));
+}
+
+inline float_v KFParticleSIMD::GetErrY           () const 
+{
+  return sqrt(abs( GetCovariance(1,1) ));
+}
+
+inline float_v KFParticleSIMD::GetErrZ           () const 
+{
+  return sqrt(abs( GetCovariance(2,2) ));
+}
+
+inline float_v KFParticleSIMD::GetErrPx          () const 
+{
+  return sqrt(abs( GetCovariance(3,3) ));
+}
+
+inline float_v KFParticleSIMD::GetErrPy          () const 
+{
+  return sqrt(abs( GetCovariance(4,4) ));
+}
+
+inline float_v KFParticleSIMD::GetErrPz          () const 
+{
+  return sqrt(abs( GetCovariance(5,5) ));
+}
+
+inline float_v KFParticleSIMD::GetErrE           () const 
+{
+  return sqrt(abs( GetCovariance(6,6) ));
+}
+
+inline float_v KFParticleSIMD::GetErrS           () const 
+{
+  return sqrt(abs( GetCovariance(7,7) ));
+}
+
+inline float_v KFParticleSIMD::GetErrP    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetMomentum( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrPt    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetPt( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrEta    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetEta( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrPhi    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetPhi( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrMomentum    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetMomentum( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrMass        () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetMass( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrDecayLength () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetDecayLength( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrDecayLengthXY () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetDecayLengthXY( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrLifeTime    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetLifeTime( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+inline float_v KFParticleSIMD::GetErrR    () const
+{
+  float_v par, err;
+  float_m mask = KFParticleSIMD::GetR( par, err );
+  float_v ret(1.e10f);
+  ret(!mask) = err;
+  return ret;
+}
+
+
+inline float_m KFParticleSIMD::GetP( float_v &P, float_v &SigmaP ) const 
+{
+  /** Calculates particle momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] P - momentum of the particle
+   ** \param[out] SigmaP - its error
+   **/
+  return KFParticleBaseSIMD::GetMomentum( P, SigmaP );
+}
+
+inline float_m KFParticleSIMD::GetPt( float_v &Pt, float_v &SigmaPt ) const 
+{
+  /** Calculates particle transverse  momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Pt - transverse momentum of the particle
+   ** \param[out] SigmaPt - its error
+   **/
+  return KFParticleBaseSIMD::GetPt( Pt, SigmaPt );
+}
+
+inline float_m KFParticleSIMD::GetEta( float_v &Eta, float_v &SigmaEta ) const 
+{
+  /** Calculates particle pseudorapidity and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Eta - pseudorapidity of the particle
+   ** \param[out] SigmaEta - its error
+   **/
+  return KFParticleBaseSIMD::GetEta( Eta, SigmaEta );
+}
+
+inline float_m KFParticleSIMD::GetPhi( float_v &Phi, float_v &SigmaPhi ) const 
+{
+  /** Calculates particle polar angle at the current point and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] Phi - polar angle of the particle
+   ** \param[out] SigmaPhi - its error
+   **/
+  return KFParticleBaseSIMD::GetPhi( Phi, SigmaPhi );
+}
+
+inline float_m KFParticleSIMD::GetMomentum( float_v &P, float_v &SigmaP ) const 
+{
+  /** Calculates particle momentum and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] P - momentum of the particle
+   ** \param[out] SigmaP - its error
+   **/
+  return KFParticleBaseSIMD::GetMomentum( P, SigmaP );
+}
+
+inline float_m KFParticleSIMD::GetMass( float_v &M, float_v &SigmaM ) const 
+{
+  /** Calculates the mass of the particle and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] M - mass of the particle
+   ** \param[out] SigmaM - its error
+   **/
+  return KFParticleBaseSIMD::GetMass( M, SigmaM );
+}
+
+inline float_m KFParticleSIMD::GetDecayLength( float_v &L, float_v &SigmaL ) const 
+{
+  /** Calculates the decay length of the particle in the laboratory system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] L - the decay length
+   ** \param[out] SigmaL - its error
+   **/
+  return KFParticleBaseSIMD::GetDecayLength( L, SigmaL );
+}
+
+inline float_m KFParticleSIMD::GetDecayLengthXY( float_v &L, float_v &SigmaL ) const 
+{
+  /** Calculates the projection in the XY plane of the decay length of the particle in the laboratory 
+   ** system and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] L - the decay length
+   ** \param[out] SigmaL - its error
+   **/
+  return KFParticleBaseSIMD::GetDecayLengthXY( L, SigmaL );
+}
+
+inline float_m KFParticleSIMD::GetLifeTime( float_v &T, float_v &SigmaT ) const 
+{
+  /** Calculates the lifetime times speed of life (ctau) [cm] of the particle in the  
+   ** center of mass frame and its error. If they are well defined returns 0, otherwise 1.
+   ** The production point should be set before calling this function.
+   ** \param[out] T - lifetime of the particle [cm]
+   ** \param[out] SigmaT - its error
+   **/
+  return KFParticleBaseSIMD::GetLifeTime( T, SigmaT );
+}
+
+inline float_m KFParticleSIMD::GetR( float_v &R, float_v &SigmaR ) const 
+{
+  /** Calculates the distance to the point {0,0,0} and its error. If they are well defined returns 0, otherwise 1.
+   ** \param[out] R - polar angle of the particle
+   ** \param[out] SigmaR - its error
+   **/
+  return KFParticleBaseSIMD::GetR( R, SigmaR );
+}
+
+inline float_v & KFParticleSIMD::X() 
+{ 
+  return KFParticleBaseSIMD::X();    
+}
+
+inline float_v & KFParticleSIMD::Y()
+{ 
+  return KFParticleBaseSIMD::Y();    
+}
+
+inline float_v & KFParticleSIMD::Z() 
+{ 
+  return KFParticleBaseSIMD::Z();    
+}
+
+inline float_v & KFParticleSIMD::Px() 
+{ 
+  return KFParticleBaseSIMD::Px();   
+}
+
+inline float_v & KFParticleSIMD::Py() 
+{ 
+  return KFParticleBaseSIMD::Py();   
+}
+
+inline float_v & KFParticleSIMD::Pz() 
+{ 
+  return KFParticleBaseSIMD::Pz();   
+}
+
+inline float_v & KFParticleSIMD::E() 
+{ 
+  return KFParticleBaseSIMD::E();    
+}
+
+inline float_v & KFParticleSIMD::S() 
+{ 
+  return KFParticleBaseSIMD::S();    
+}
+
+inline int_v    & KFParticleSIMD::Q() 
+{ 
+  return KFParticleBaseSIMD::Q();    
+}
+
+inline float_v & KFParticleSIMD::Chi2() 
+{ 
+  return KFParticleBaseSIMD::Chi2(); 
+}
+
+inline int_v    & KFParticleSIMD::NDF() 
+{ 
+  return KFParticleBaseSIMD::NDF();  
+}
+
+inline float_v & KFParticleSIMD::Parameter ( int i )        
+{ 
+  return KFParticleBaseSIMD::Parameter(i);
+}
+
+inline float_v & KFParticleSIMD::Covariance( int i )        
+{ 
+  return KFParticleBaseSIMD::Covariance(i);
+}
+
+inline float_v & KFParticleSIMD::Covariance( int i, int j ) 
+{ 
+  return KFParticleBaseSIMD::Covariance(i,j); 
+}
+
+inline float_v * KFParticleSIMD::Parameters ()
+{
+  return fP;
+}
+
+inline float_v * KFParticleSIMD::CovarianceMatrix()
+{
+  return fC;
+}
+
+
+inline void KFParticleSIMD::operator +=( const KFParticleSIMD &Daughter )
+{
+  /** Operator to add daughter to the current particle. Calls AddDaughter() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+#ifdef NonhomogeneousField
+  fField = Daughter.fField;
+#endif
+  KFParticleBaseSIMD::operator +=( Daughter );
+}
+  
+
+inline void KFParticleSIMD::AddDaughter( const KFParticleSIMD &Daughter )
+{
+  /** Adds daughter to the current particle. Depending on the selected construction method uses: \n
+   ** 1) Either simplifyed fast mathematics which consideres momentum and energy as
+   ** independent variables and thus ignores constraint on the fixed mass (fConstructMethod = 0).
+   ** In this case the mass of the daughter particle can be corrupted when the constructed vertex
+   ** is added as the measurement and the mass of the output short-lived particle can become 
+   ** unphysical - smaller then the threshold. Implemented in the 
+   ** AddDaughterWithEnergyFit() function \n
+   ** 2) Or slower but correct mathematics which requires that the masses of daughter particles 
+   ** stays fixed in the construction process (fConstructMethod = 2). Implemented in the
+   ** AddDaughterWithEnergyFitMC() function.
+   ** \param[in] Daughter - the daughter particle
+   **/
+#ifdef NonhomogeneousField
+  fField = Daughter.fField;
+#endif
+  KFParticleBaseSIMD::AddDaughter( Daughter );
+}
+
+inline void KFParticleSIMD::Construct( const KFParticleSIMD *vDaughters[], int nDaughters, 
+                                       const KFParticleSIMD *ProdVtx,   Float_t Mass )
+{
+  /** Constructs a short-lived particle from a set of daughter particles:\n
+   ** 1) all parameters of the "this" objects are initialised;\n
+   ** 2) daughters are added one after another;\n
+   ** 3) if Parent pointer is not null, the production vertex is set to it;\n
+   ** 4) if Mass hypothesis >=0 the mass constraint is set.
+   ** \param[in] vDaughters - array of daughter particles
+   ** \param[in] nDaughters - number of daughter particles in the input array
+   ** \param[in] Parent - optional parrent particle
+   ** \param[in] Mass - optional mass hypothesis
+   **/  
+#ifdef NonhomogeneousField
+  fField = vDaughters[0]->fField;
+#endif
+  KFParticleBaseSIMD::Construct( ( const KFParticleBaseSIMD**)vDaughters, nDaughters, 
+                                 ( const KFParticleBaseSIMD*)ProdVtx, Mass );
+}
+
+inline void KFParticleSIMD::TransportToPoint( const float_v xyz[] )
+{
+  /** Transports particle to the distance of closest approach to the point xyz.
+   ** \param[in] xyz[3] - point, where particle should be transported
+   **/
+  
+  float_v dsdr[6] = {0.f,0.f,0.f,0.f,0.f,0.f};
+  const float_v dS = GetDStoPoint(xyz, dsdr);
+  TransportToDS( dS, dsdr );
+}
+#ifdef HomogeneousField
+inline void KFParticleSIMD::TransportToVertex( const KFPVertex &v )
+{
+  /** Transports particle to the distance of closest approach to the vertex v.
+   ** \param[in] v - vertex, where particle should be transported
+   **/
+  TransportToPoint( KFParticleSIMD(v).fP );
+}
+#endif
+inline void KFParticleSIMD::TransportToParticle( const KFParticleSIMD &p )
+{ 
+  /** Transports particle to the distance of closest approach to the particle p.
+   ** \param[in] p - particle, to which the current particle should be transported.
+   **/
+  float_v dsdr[4][6];
+  float_v dS[2];
+  GetDStoParticle( p, dS, dsdr );
+  TransportToDS( dS[0], dsdr[0] );
+}
+
+inline float_v KFParticleSIMD::GetDStoPoint( const float_v xyz[3], float_v dsdr[6] ) const 
+{
+  /** Returns dS = l/p parameter, where \n
+   ** 1) l - signed distance to the DCA point with the input xyz point;\n
+   ** 2) p - momentum of the particle; \n
+   ** Also calculates partial derivatives dsdr of the parameter dS over the state vector of the current particle.
+   ** If "HomogeneousField" is defined KFParticleBaseSIMD::GetDStoPointBz() is called,
+   ** if "NonhomogeneousField" is defined - KFParticleBaseSIMD::GetDStoPointCBM()
+   ** \param[in] xyz[3] - point, to which particle should be transported
+   ** \param[out] dsdr[6] = ds/dr partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[in] param - optional parameter, is used in case if the parameters of the particle are rotated
+   ** to other coordinate system (see GetDStoPointBy() function), otherwise fP are used
+   **/
+#ifdef HomogeneousField
+  return KFParticleBaseSIMD::GetDStoPointBz( GetFieldAlice(), xyz, dsdr );
+#endif
+#ifdef NonhomogeneousField
+  return KFParticleBaseSIMD::GetDStoPointCBM( xyz, dsdr );
+#endif
+  return 0.;
+}
+
+
+#ifdef HomogeneousField
+inline float_v KFParticleSIMD::GetFieldAlice()
+{ 
+  /** Returns value of the constant homogemeous one-component magnetic field Bz, (is defined in case of #ifdef HomogeneousField). */
+  return fgBz; 
+}
+#endif
+
+#ifdef HomogeneousField
+inline void KFParticleSIMD::GetFieldValue( const float_v * /*xyz*/, float_v B[] ) const 
+{  
+  /** Calculates the Bx, By, Bz components at the point xyz using approximation of the
+   ** magnetic field along the particle trajectory.
+   ** \param[in] xyz[3] - X, Y, Z coordiantes of the point where the magnetic field should be calculated
+   ** \param[out] B[3] - value of X, Y, Z components of the calculated magnetic field at the given point
+   **/  
+  B[0] = B[1] = 0;
+  B[2] = GetFieldAlice();
+}
+#endif
+
+#ifdef NonhomogeneousField
+inline void KFParticleSIMD::GetFieldValue( const float_v xyz[], float_v B[] ) const 
+{
+  /** Calculates the Bx, By, Bz components at the point xyz using approximation of the
+   ** magnetic field along the particle trajectory.
+   ** \param[in] xyz[3] - X, Y, Z coordiantes of the point where the magnetic field should be calculated
+   ** \param[out] B[3] - value of X, Y, Z components of the calculated magnetic field at the given point
+   **/
+  KFParticleFieldValue mB = const_cast<KFParticleFieldRegion&>(fField).Get(xyz[2]);
+  B[0] = mB.x;
+  B[1] = mB.y;
+  B[2] = mB.z;
+}
+#endif
+
+inline void KFParticleSIMD::GetDStoParticle( const KFParticleBaseSIMD &p, float_v dS[2], float_v dsdr[4][6] )const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particleСЋ \n
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** Also calculates partial derivatives dsdr of the parameters dS[0] and dS[1] over the state vectors of the particles:\n
+   ** 1) dsdr[0][6] = d(dS[0])/d(param1);\n
+   ** 2) dsdr[1][6] = d(dS[0])/d(param2);\n
+   ** 3) dsdr[2][6] = d(dS[1])/d(param1);\n
+   ** 4) dsdr[3][6] = d(dS[1])/d(param2);\n
+   ** where param1 are parameters of the current particle fP and
+   ** param2 are parameters of the second particle p.fP. If "HomogeneousField" is defined KFParticleBaseSIMD::GetDStoParticleBz() is called,
+   ** if "NonhomogeneousField" is defined - KFParticleBaseSIMD::GetDStoParticleCBM()
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   ** \param[out] dsdr[4][6] - partial derivatives of the parameters dS[0] and dS[1] over the state vectors of the both particles
+   **/
+#ifdef HomogeneousField
+  KFParticleBaseSIMD::GetDStoParticleBz( GetFieldAlice(), p, dS, dsdr ) ;
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBaseSIMD::GetDStoParticleCBM( p, dS, dsdr ) ;
+#endif
+}
+
+inline void KFParticleSIMD::GetDStoParticleFast( const KFParticleBaseSIMD &p, float_v dS[2] )const
+{
+  /** Calculates dS = l/p parameters for two particles, where \n
+   ** 1) l - signed distance to the DCA point with the other particle;\n
+   ** 2) p - momentum of the particleСЋ \n
+   ** dS[0] is the transport parameter for the current particle, dS[1] - for the particle "p".
+   ** If "HomogeneousField" is defined KFParticleBaseSIMD::GetDStoParticleBz() is called,
+   ** if "NonhomogeneousField" is defined - KFParticleBaseSIMD::GetDStoParticleCBM()
+   ** \param[in] p - second particle
+   ** \param[out] dS[2] - transport parameters dS for the current particle (dS[0]) and the second particle "p" (dS[1])
+   **/
+#ifdef HomogeneousField
+  KFParticleBaseSIMD::GetDStoParticleBz( GetFieldAlice(), p, dS ) ;
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBaseSIMD::GetDStoParticleCBM( p, dS ) ;
+#endif
+}
+
+inline void KFParticleSIMD::Transport( float_v dS, const float_v* dsdr, float_v P[], float_v C[], float_v* dsdr1, float_v* F, float_v* F1 ) const 
+{
+  /** Transports the parameters and their covariance matrix of the current particle
+   ** on a length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. If "HomogeneousField" is defined KFParticleBaseSIMD::TransportBz()
+   ** is called, if "NonhomogeneousField" - KFParticleBaseSIMD::TransportCBM().
+   ** The obtained parameters and covariance matrix are stored to the arrays P and 
+   ** C respectively. P and C can be set to the parameters fP and covariance matrix fC of the current particle. In this
+   ** case the particle parameters will be modified. Dependence of the transport parameter dS on the state vector of the
+   ** current particle is taken into account in the covariance matrix using partial derivatives dsdr = d(dS)/d(fP). If
+   ** a pointer to F is initialised the transport jacobian F = d(fP new)/d(fP old) is stored.
+   ** Since dS can depend on the state vector r1 of other particle or vertex, the corelation matrix 
+   ** F1 = d(fP new)/d(r1) can be optionally calculated if a pointer F1 is provided.
+   *  Parameters F and F1 should be either both initialised or both set to null pointer.
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[in] dsdr[6] = ds/dr - partial derivatives of the parameter dS over the state vector of the current particle
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   ** \param[out] C[36] - array, where transported covariance matrix (8x8) should be stored in the lower triangular form 
+   ** \param[in] dsdr1[6] = ds/dr - partial derivatives of the parameter dS over the state vector of another particle 
+   ** or vertex
+   ** \param[out] F[36] - optional parameter, transport jacobian, 6x6 matrix F = d(fP new)/d(fP old)
+   ** \param[out] F1[36] - optional parameter, corelation 6x6 matrix betweeen the current particle and particle or vertex
+   ** with the state vector r1, to which the current particle is being transported, F1 = d(fP new)/d(r1)
+   **/ 
+#ifdef HomogeneousField
+  KFParticleBaseSIMD::TransportBz( GetFieldAlice(), dS, dsdr, P, C, dsdr1, F, F1 );
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBaseSIMD::TransportCBM( dS, dsdr, P, C, dsdr1, F, F1 );
+#endif
+}
+
+inline void KFParticleSIMD::TransportFast( float_v dS, float_v P[] ) const 
+{
+  /** Transports the parametersof the current particle
+   ** on a length defined by the transport parameter dS = l/p, where l is the signed distance and p is 
+   ** the momentum of the current particle. If "HomogeneousField" is defined KFParticleBaseSIMD::TransportBz()
+   ** is called, if "NonhomogeneousField" - KFParticleBaseSIMD::TransportCBM().
+   ** The obtained parameters are stored to the array P.
+   ** P can be set to the parameters fP of the current particle. In this
+   ** case the particle parameters will be modified. 
+   ** \param[in] dS - transport parameter which defines the distance to which particle should be transported
+   ** \param[out] P[8] - array, where transported parameters should be stored
+   **/ 
+#ifdef HomogeneousField
+  KFParticleBaseSIMD::TransportBz( GetFieldAlice(), dS, P );
+#endif
+#ifdef NonhomogeneousField
+  KFParticleBaseSIMD::TransportCBM( dS, P );
+#endif
+}
+
+#endif 
diff --git a/external/KFParticle/KFParticle/KFParticleTopoReconstructor.cxx b/external/KFParticle/KFParticle/KFParticleTopoReconstructor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0132badc59874d9f2fda0851ce9085b214d56447
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleTopoReconstructor.cxx
@@ -0,0 +1,1186 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#include "KFParticleTopoReconstructor.h"
+
+#ifdef KFPWITHTRACKER
+#include "AliHLTTPCCAGBTracker.h"
+#endif
+
+#include "KFParticleSIMD.h"
+#include "KFParticleDatabase.h"
+
+#include <fstream>
+#include <iostream>
+#include "string"
+using std::string;
+using std::ofstream;
+using std::vector;
+
+#include "KFPInputData.h"
+
+KFParticleTopoReconstructor::~KFParticleTopoReconstructor()
+{
+  /** The default destructor. Deallocates memory for all pointers if objects exist. **/
+  if (fKFParticlePVReconstructor) delete fKFParticlePVReconstructor;
+  if (fKFParticleFinder) delete fKFParticleFinder;
+  if(fTracks) delete [] fTracks;
+}
+
+#ifdef HomogeneousField
+void KFParticleTopoReconstructor::SetField(double b)
+{
+  /** Sets constant homogeneous one component magnetic field Bz to "b". */
+  KFParticle::SetField(b);
+  KFParticleSIMD::SetField(float(b));
+}
+#endif
+
+#ifdef KFPWITHTRACKER
+void KFParticleTopoReconstructor::Init(AliHLTTPCCAGBTracker* tracker, vector<int>* pdg)
+{
+  if(!fTracks) 
+    fTracks = new KFPTrackVector[NInputSets];
+
+  fTracks[0].Resize(0);
+  fTracks[1].Resize(0);
+  fTracks[2].Resize(0);
+  fTracks[3].Resize(0);
+  fTracks[4].Resize(0);
+  fTracks[5].Resize(0);
+  fTracks[6].Resize(0);
+  fTracks[7].Resize(0);
+  
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+
+  KFParticle::SetField( tracker->Slice(0).Param().Bz() );
+  KFParticleSIMD::SetField( tracker->Slice(0).Param().Bz() );
+
+    // create and fill array of tracks to init KFParticleTopoReconstructor
+  const int nTracks = tracker->NTracks();
+  fTracks[1].Resize( int(nTracks/float_vLen+1)*float_vLen );
+  fTracks[5].Resize( int(nTracks/float_vLen+1)*float_vLen );
+  fParticles.clear();
+  int iOTr = 0; // index in out array
+  
+  float_v alpha(Vc::Zero);
+  int nElements=0;
+  
+  for ( int iTr = 0; iTr < nTracks; iTr++ ) {
+      // get track params in local CS
+    
+    bool ok = true;
+    const int q = -(tracker->Tracks()[ iTr ].InnerParam().QPt()>=0 ? 1 : -1);
+    
+    for(int iParamSet=0; iParamSet<2; iParamSet++)
+    {
+      AliHLTTPCCATrackParam trParam;
+      int arrayIndex = -1;
+      if(iParamSet==0)
+      {
+        arrayIndex = 1;
+        trParam = tracker->Tracks()[ iTr ].InnerParam();
+      }
+      if(iParamSet==1)
+      {
+        arrayIndex = 5;
+        trParam = tracker->Tracks()[ iTr ].OuterParam();
+      }
+          
+      const float x0 = 0;
+      trParam.TransportToXWithMaterial( x0, tracker->Slice(0).Param().cBz( ) );
+
+        // -- convert parameters
+      fTracks[arrayIndex].SetParameter(trParam.X(), 0, iOTr); // X
+      fTracks[arrayIndex].SetParameter(trParam.Y(), 1, iOTr); // Y
+      fTracks[arrayIndex].SetParameter(trParam.Z(), 2, iOTr); // Z
+
+      const float pt = CAMath::Abs( 1.f / trParam.QPt() );
+//       const int q = -(trParam.QPt()>=0 ? 1 : -1);
+  //    if ( pt < 1 ) continue; // dbg
+      ok = ok && !( trParam.NDF() < 10+5); //if ( trParam.NDF() < 10+5 ) continue; // at least 15 hits in track
+      ok = ok && !( trParam.Chi2() > 10*trParam.NDF() ); //if ( trParam.Chi2() > 10*trParam.NDF() ) continue; // dbg
+  //    if ( iOTr >= 4 ) continue; // dbg
+      
+      const float cosL = trParam.DzDs();
+      fTracks[arrayIndex].SetParameter(pt * trParam.GetCosPhi(), 3, iOTr); // Px
+      fTracks[arrayIndex].SetParameter(pt * trParam.SinPhi()   , 4, iOTr); // Py
+      fTracks[arrayIndex].SetParameter(pt * cosL               , 5, iOTr); // Pz
+      
+        // -- convert cov matrix
+        // get jacobian
+      float J[6][6];
+      for (int i = 0; i < 6; i++)
+        for (int j = 0; j < 6; j++)
+          J[i][j] = 0;
+      J[0][0] = 1; // x -> x
+      J[1][1] = 1; // y -> y
+      J[2][2] = 1; // z -> z
+      J[3][3] = -pt * trParam.SinPhi() / trParam.GetCosPhi();
+      J[3][5] = -q * pt * pt * trParam.GetCosPhi(); // q/pt -> px
+      J[4][3] = pt; // sinPhi -> py
+      J[4][5] = -q* pt * pt * trParam.SinPhi(); // q/pt -> py
+      J[5][4] = pt; // dz/ds -> pz
+      J[5][5] = -q* pt * pt * cosL; // q/pt -> pz
+
+      float CovIn[6][6]; // triangular -> symmetric matrix
+      {
+        CovIn[0][0] = .001f*.001f; // dx. From nowhere. TODO
+        for (int i = 1; i < 6; i++) {
+          CovIn[i][0] = 0;
+          CovIn[0][i] = 0;
+        }
+        int k = 0;
+        for (int i = 1; i < 6; i++) {
+          for (int j = 1; j <= i; j++, k++) {
+            CovIn[i][j] = trParam.Cov()[k];
+            CovIn[j][i] = trParam.Cov()[k];
+          }
+        }
+      }
+      
+      float CovInJ[6][6];      // CovInJ = CovIn * J^t
+      for (int i = 0; i < 6; i++)
+        for (int j = 0; j < 6; j++) {
+          CovInJ[i][j] = 0;
+          for (int k = 0; k < 6; k++) {
+            CovInJ[i][j] += CovIn[i][k] * J[j][k];
+          }
+        }
+      
+      float CovOut[6][6];      // CovOut = J * CovInJ
+      for (int i = 0; i < 6; i++)
+        for (int j = 0; j < 6; j++) {
+          CovOut[i][j] = 0;
+          for (int k = 0; k < 6; k++) {
+            CovOut[i][j] += J[i][k] * CovInJ[k][j];
+          }
+        }
+
+      float KFPCov[21]; // symmetric matrix -> triangular
+      {
+        int k = 0;
+        for (int i = 0; i < 6; i++) {
+          for (int j = 0; j <= i; j++, k++) {
+            KFPCov[k] = CovOut[i][j];
+            ASSERT( !CAMath::Finite(CovOut[i][j]) ||  CovOut[i][j] == 0 || fabs( 1. - CovOut[j][i]/CovOut[i][j] ) <= 0.05,
+              "CovOut[" << i << "][" << j << "] == CovOut[" << j << "][" << i << "] : " << CovOut[i][j] << " == " << CovOut[j][i]);
+          }
+        }
+      }
+      
+      if(iParamSet == 0)
+      {   // check cov matrix
+        int k = 0;
+        for (int i = 0; i < 6; i++) {
+          for (int j = 0; j <= i; j++, k++) {
+            ok &= CAMath::Finite( KFPCov[k] );
+          }
+          ok &= ( KFPCov[k-1] > 0 );
+        }
+      }
+      
+      if(ok)
+      {
+        int trackPDG = -1;  
+        if(pdg)
+          trackPDG = (*pdg)[iTr];
+      
+        for(int iC=0; iC<21; iC++)
+          fTracks[arrayIndex].SetCovariance( KFPCov[iC], iC, iOTr);
+        fTracks[arrayIndex].SetId(iTr, iOTr);
+        fTracks[arrayIndex].SetPDG(trackPDG, iOTr);
+        fTracks[arrayIndex].SetQ(q, iOTr);
+        fTracks[arrayIndex].SetPVIndex(-1, iOTr);
+      }
+    }
+    if (!ok) continue;
+    
+    iOTr++;
+    
+    // convert into Global CS. Can't be done erlier because in tracker X hasn't correspondent covMatrix elements.
+    alpha[nElements] = tracker->Tracks()[ iTr ].Alpha();
+    nElements++;
+    if(nElements == float_vLen)
+    {
+      fTracks[1].RotateXY( alpha, iOTr-nElements);
+      fTracks[5].RotateXY( alpha, iOTr-nElements);
+      nElements=0;
+    }
+  }
+  if(nElements>0)
+  {
+    fTracks[1].RotateXY( alpha, iOTr-nElements);
+    fTracks[5].RotateXY( alpha, iOTr-nElements);
+  }
+    
+  fTracks[0].Resize(iOTr);
+  fTracks[0].Set(fTracks[1],iOTr,0);
+
+  fTracks[4].Resize(iOTr);
+  fTracks[4].Set(fTracks[5],iOTr,0);
+  
+  fKFParticlePVReconstructor->Init( &fTracks[0], iOTr );
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[0] = timer.RealTime();
+#endif // USE_TIMERS
+} // void KFParticleTopoReconstructor::Init(AliHLTTPCCAGBTracker* tracker)
+#endif
+
+void KFParticleTopoReconstructor::Init(vector<KFParticle> &particles, vector<int>* pdg, vector<int>* nPixelHits)
+{
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+  
+  if(!fTracks) 
+    fTracks = new KFPTrackVector[NInputSets];
+  
+  fParticles.clear();
+  fPV.clear(); 
+
+  int nTracks = particles.size();
+  fTracks[0].Resize(nTracks);
+  fTracks[1].Resize(0);
+  fTracks[2].Resize(0);
+  fTracks[3].Resize(0);
+  fTracks[4].Resize(0);
+  fTracks[5].Resize(0);
+  fTracks[6].Resize(0);
+  fTracks[7].Resize(0);
+  
+  for(int iTr=0; iTr<nTracks; iTr++)
+  {  
+    int trackPDG = -1;
+    if(pdg)
+      trackPDG = (*pdg)[iTr];
+    
+    int npixelhits = 0;
+    if(nPixelHits)
+      npixelhits = nPixelHits->at(iTr);
+    
+    for(int iP=0; iP<6; iP++)
+      fTracks[0].SetParameter(particles[iTr].Parameters()[iP], iP, iTr);
+    for(int iC=0; iC<21; iC++)
+      fTracks[0].SetCovariance(particles[iTr].CovarianceMatrix()[iC], iC, iTr);
+//     fTracks[0].SetId(iTr, iTr);
+    fTracks[0].SetId(particles[iTr].Id(), iTr);
+    fTracks[0].SetPDG(trackPDG, iTr);
+    fTracks[0].SetQ(particles[iTr].Q(), iTr);
+    fTracks[0].SetPVIndex(-1, iTr);
+    fTracks[0].SetNPixelHits(npixelhits,iTr);
+  }
+
+  fKFParticlePVReconstructor->Init( &fTracks[0], nTracks );
+  
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[0] = timer.RealTime();
+#endif // USE_TIMERS
+}
+
+void KFParticleTopoReconstructor::Init(KFPTrackVector &tracks, KFPTrackVector &tracksAtLastPoint)
+{
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+  
+  if(!fTracks) 
+    fTracks = new KFPTrackVector[NInputSets];
+  
+  fParticles.clear();
+  fPV.clear(); 
+  
+  int nTracks = tracks.Size();
+  fTracks[0].Resize(nTracks);
+  fTracks[0].Set(tracks, nTracks, 0);
+  fTracks[1].Resize(0);
+  fTracks[2].Resize(0);
+  fTracks[3].Resize(0);
+  fTracks[4].Resize(tracksAtLastPoint.Size());
+  fTracks[4].Set(tracksAtLastPoint, tracksAtLastPoint.Size(), 0);
+  fTracks[5].Resize(0);
+  fTracks[6].Resize(0);
+  fTracks[7].Resize(0);
+  fKFParticlePVReconstructor->Init( &fTracks[0], nTracks );
+  
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[0] = timer.RealTime();
+#endif // USE_TIMERS
+}
+
+void KFParticleTopoReconstructor::Init(const KFPTrackVector *particles, const vector<KFParticle>& pv)
+{ 
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+  fParticles.clear();
+  fPV.clear(); 
+
+  fTracks = const_cast< KFPTrackVector* >(particles);
+  fChiToPrimVtx[0].resize(fTracks[0].Size());
+  fChiToPrimVtx[1].resize(fTracks[1].Size());
+  fPV.resize(pv.size());
+
+  for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+    fPV[iPV] = KFParticleSIMD(const_cast<KFParticle&>(pv[iPV]));
+
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[0] = timer.RealTime();
+#endif // USE_TIMERS
+}
+
+void KFParticleTopoReconstructor::ReconstructPrimVertex(bool isHeavySystem)
+{
+  /** Runs reconstruction of primary vertices. If "isHeavySystem" is defined - only the
+   ** best vertex with the maximum number of tracks-contributors is stored.
+   **/
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+  fKFParticlePVReconstructor->ReconstructPrimVertex();
+  
+  fPV.clear(); 
+
+  int nPrimVtx = NPrimaryVertices();
+  int nPV = 0;
+  if(isHeavySystem)
+  {
+    if(NPrimaryVertices() > 1)
+    {
+      unsigned int nMax = GetPVTrackIndexArray(0).size();
+      for(int i=1; i<NPrimaryVertices(); i++)
+        if(GetPVTrackIndexArray(i).size() > nMax)
+        {
+          nMax = GetPVTrackIndexArray(i).size();
+          nPV = i;
+        }
+    }
+  
+    nPrimVtx = 1;
+    fPV.resize(nPrimVtx);
+    fPV[0] = GetPrimVertex(nPV);
+  }
+  else
+  {
+    fPV.resize(nPrimVtx);
+    for(int iPV=0; iPV<nPrimVtx; iPV++)
+      fPV[iPV] = GetPrimVertex(iPV);
+  }
+  
+  for(int iPV=0; iPV<NPrimaryVertices(); iPV++)
+  {
+    int pvI = iPV;
+
+    if( isHeavySystem )
+    {
+      if(iPV != nPV) continue;
+      pvI = 0; //save only one PV
+    }
+
+    vector<int>& tracks = GetPVTrackIndexArray(iPV);
+    for(unsigned int iTr=0; iTr<tracks.size(); iTr++)
+      fTracks[0].SetPVIndex(pvI, tracks[iTr]);
+  }
+  
+  if(isHeavySystem)
+  {
+    vector<int> pvTracks = fKFParticlePVReconstructor->GetPVTrackIndexArray(nPV);
+    KFVertex pv = fKFParticlePVReconstructor->GetPrimKFVertex(nPV);
+    fKFParticlePVReconstructor->CleanPV();
+    fKFParticlePVReconstructor->AddPV(pv, pvTracks);
+  }
+  
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[1] = timer.RealTime();
+#endif // USE_TIMERS
+} // void KFParticleTopoReconstructor::ReconstructPrimVertex
+
+void KFParticleTopoReconstructor::SortTracks()
+{
+  /** Sorts input tracks according to they charge, relation to the primary 
+   ** vertex candidates, PDG hypothesis. The tracks after sorting are divided 
+   ** into several groups: \n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position. \n
+   ** In each group they are sorted according to PDG: electrons, muons, pions, 
+   ** tracks without PID, kaons, protons, deuterons, tritons, He3, He4.
+   **/
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+  
+  int offset[2] = {0, 4};
+  int nSets = 2;
+  
+  if(fTracks[4].Size() == 0)
+    nSets = 1;
+  
+  for(int iSet=nSets-1; iSet>=0; iSet--)
+  {
+    int Size = fTracks[0].Size();
+    
+    vector<KFPTrackIndex> sortedTracks(Size);
+    kfvector_uint trackIndex[4];
+    for(int iTV=0; iTV<4; iTV++)
+      trackIndex[iTV].resize(Size);
+    int nTracks[4] = {0,0,0,0};
+    
+    for(int iTr=0; iTr<Size; iTr++)
+    {
+      sortedTracks[iTr].fIndex = iTr;
+      sortedTracks[iTr].fPdg = fTracks[0].PDG()[iTr];
+    }
+    
+    std::sort(sortedTracks.begin(), sortedTracks.end(), KFPTrackIndex::Compare);
+    
+    for(int iTr=0; iTr<Size; iTr++)
+    {
+      int iTrSorted = sortedTracks[iTr].fIndex;
+      
+      //int q = fTracks[offset[iSet]].Q()[iTrSorted];
+      int q = fTracks[0].Q()[iTrSorted]; //take the charge at the first point to avoid ambiguities in array size
+      if(fTracks[0].PVIndex()[iTrSorted] < 0) //secondary track
+      {
+
+        if(q<0) //secondary negative track
+        {
+          trackIndex[1][nTracks[1]] = iTrSorted;
+          nTracks[1]++;
+        }
+        else //secondary positive track
+        {
+          trackIndex[0][nTracks[0]] = iTrSorted;
+          nTracks[0]++;
+        }
+      }
+      else //primary track
+      {
+        if(q<0) //primary negative track
+        {
+          trackIndex[3][nTracks[3]] = iTrSorted;
+          nTracks[3]++;
+        }
+        else //primary positive track
+        {
+          trackIndex[2][nTracks[2]] = iTrSorted;
+          nTracks[2]++;
+        }
+      }
+    }
+    
+    for(int iTV=1; iTV<4; iTV++)  
+      fTracks[iTV+offset[iSet]].SetTracks(fTracks[offset[iSet]], trackIndex[iTV], nTracks[iTV]);
+      
+    KFPTrackVector positive;
+    positive.SetTracks(fTracks[offset[iSet]], trackIndex[0], nTracks[0]);
+    fTracks[offset[iSet]].Resize(nTracks[0]);
+    fTracks[offset[iSet]].Set(positive,nTracks[0],0);
+      
+    for(int iTV=0; iTV<4; iTV++)
+      fTracks[iTV+offset[iSet]].RecalculateLastIndex();
+    
+    //correct index of tracks in primary clusters with respect to the sorted array 
+    if(iSet == 0)
+    {
+      vector<int> newIndex(Size);
+      int iCurrentTrack=0;
+      for(int iTC=0; iTC<4; iTC++)
+      {
+        for(int iTrackIndex=0; iTrackIndex<fTracks[iTC].Size(); iTrackIndex++)
+        {
+          newIndex[trackIndex[iTC][iTrackIndex]] = iCurrentTrack;
+          iCurrentTrack++;
+        }
+      }
+      
+      for(int iPV=0; iPV<NPrimaryVertices(); iPV++)
+        for(unsigned int iTrack=0; iTrack<GetPVTrackIndexArray(iPV).size(); iTrack++)
+          fKFParticlePVReconstructor->GetPVTrackIndexArray(iPV)[iTrack] = newIndex[GetPVTrackIndexArray(iPV)[iTrack]];
+    }
+  }
+  
+  fChiToPrimVtx[0].resize(fTracks[0].Size(), -1);
+  fChiToPrimVtx[1].resize(fTracks[1].Size(), -1);
+  
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[2] = timer.RealTime();
+#endif // USE_TIMERS
+}
+
+void KFParticleTopoReconstructor::TransportPVTracksToPrimVertex()
+{
+  /** Tracks which are considered as primary, i.e. were used in fit of candidates
+   ** for the primary vertex, are transported to the DCA point to the corresponding
+   ** primary vertex.
+   **/
+  float_v point[3];
+  KFParticleSIMD tmpPart;
+  
+  for(int iTV=2; iTV<4; iTV++)
+  {
+    unsigned int NTr = fTracks[iTV].Size(); 
+    for(unsigned int iTr=0; iTr < NTr; iTr += float_vLen) 
+    { 
+      const int_v& pdg = reinterpret_cast<const int_v&>(fTracks[iTV].PDG()[iTr]);
+      const int_v& pvIndex = reinterpret_cast<const int_v&>(fTracks[iTV].PVIndex()[iTr]);
+      
+      tmpPart.Load(fTracks[iTV], iTr, pdg);
+      
+      for(unsigned int iV=0; iV < (unsigned int)float_vLen; iV++)
+      {
+        if(iV+iTr >= NTr) continue;
+        
+        int iPV = pvIndex[iV];
+        point[0][iV] = fPV[iPV].X()[0];
+        point[1][iV] = fPV[iPV].Y()[0];
+        point[2][iV] = fPV[iPV].Z()[0];     
+      }
+      
+      tmpPart.TransportToPoint(point);
+      
+      for(int iP=0; iP<6; iP++)
+        fTracks[iTV].SetParameter( tmpPart.GetParameter(iP), iP, iTr );
+      for(int iC=0; iC<21; iC++)
+        fTracks[iTV].SetCovariance( tmpPart.GetCovariance(iC), iC, iTr ); 
+    }
+  }
+}
+
+void KFParticleTopoReconstructor::GetChiToPrimVertex(KFParticleSIMD* pv, const int nPV)
+{ 
+  /** Calculates the chi2-deviation from the primary vertex. If several primary vertices
+   ** are found the minimum value is stored.
+   ** \param[in] pv - pointer to the array with primary vertices
+   ** \param[in] nPV - number of the primary vertices in the array
+   **/
+  KFParticleSIMD tmpPart;
+  
+  for(int iTV=0; iTV<2; iTV++)
+  {
+    unsigned int NTr = fTracks[iTV].Size();
+    for(unsigned int iTr=0; iTr < NTr; iTr += float_vLen) 
+    { 
+      uint_v trackIndex = iTr + uint_v::IndexesFromZero();
+      const int_v& pdg = reinterpret_cast<const int_v&>(fTracks[iTV].PDG()[iTr]);
+      tmpPart.Create(fTracks[iTV],trackIndex, pdg);
+      
+      float_v& chi2 = reinterpret_cast<float_v&>(fChiToPrimVtx[iTV][iTr]);
+      chi2(simd_cast<float_m>(trackIndex<NTr)) = 10000.f;
+
+      for(int iPV=0; iPV<nPV; iPV++)
+      {
+        const float_v point[3] = {pv[iPV].X(), pv[iPV].Y(), pv[iPV].Z()};
+        tmpPart.TransportToPoint(point);
+        const float_v& chiVec = tmpPart.GetDeviationFromVertex(pv[iPV]);
+        chi2( (chi2>chiVec) && simd_cast<float_m>(trackIndex<NTr) ) = chiVec;
+      }
+    } 
+  }
+}
+
+/** @class ParticleInfo
+ ** @brief Helper structure to clean particle spectra by competition of PDG hypothesis.
+ ** @author  I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The structure contains index of the particle and difference in sigmas between the mass of
+ ** the particle candidate and the table mass of the corresponding PDG hypothesis. Is used to
+ ** sort the array with particle candidates according to the smallest difference. Then only
+ ** the best candidate is stored.
+ **/
+struct ParticleInfo
+{
+  ParticleInfo():fParticleIndex(-1),fMassDistance(1.e9f) {};
+  /** \brief Constructor with all parameters initialised by user. */
+  ParticleInfo(int index, float massDistance):fParticleIndex(index),fMassDistance(massDistance) {};
+  
+  /** \brief Sorting function, returns true if the mass difference of "a" is smaller then of "b". The array is sorted according to the smallest difference.*/
+  static bool compare(const ParticleInfo& a, const ParticleInfo& b) { return (a.fMassDistance < b.fMassDistance); }
+  
+  int   fParticleIndex; ///< Index in the array of the particle candidates.
+  float fMassDistance;  ///< difference between the mass of the candidate and the table mass normalised to the width of the peak.
+};
+
+bool UseParticleInCompetition(int PDG)
+{
+  /** Defines if a particle with a given PDG code should be used in the
+   ** competition between reconstructed particle candidates.
+   **/
+  bool use = (PDG == 310) ||         //K0
+             (PDG == 22) ||          //gamma
+             (PDG == 111) ||         //pi0
+             (abs(PDG) == 3122) ||   //Lambda
+             (abs(PDG) == 3312) ||   //Xi
+             (abs(PDG) == 3334) ||   //Omega
+             (abs(PDG) == 3003) ||   //LambdaN
+             (abs(PDG) == 3103) ||   //LambdaNN
+             (abs(PDG) == 3004) ||   //H3L
+             (abs(PDG) == 3005) ||   //H4L
+             (abs(PDG) == 3006) ||   //He4L
+             (abs(PDG) == 3007) ||   //He5L
+             (abs(PDG) == 3203) ||   //LLn
+             (abs(PDG) == 3008) ||   //H4LL
+             (abs(PDG) == 3009) ||   //H4LL
+             (abs(PDG) == 3010) ||   //H5LL
+             (abs(PDG) == 3011);     //He6LL
+  return use;
+}
+
+void KFParticleTopoReconstructor::SelectParticleCandidates()
+{
+  /** Cleans reconstructed short-lived particles: \n
+   ** 1) primary K0, Lambda, anti-Lambda, gamma, hypernuclei are selected; \n
+   ** 2) competition between candidates defined by the 
+   ** KFParticleTopoReconstructor::UseParticleInCompetition is run; \n
+   ** 3) dielectron spectrum is cleaned from gamma-electrons; \n
+   ** 4) in the dielectron spectrum for low mass vector mesons only those
+   ** candidates are left, which have both daughters identified as electrons.
+   **/
+  
+  std::vector<ParticleInfo> particleInfo;
+  std::vector<bool> isUsed(fParticles.size());
+  std::vector<bool> deleteCandidate(fParticles.size());
+  std::vector<int>  bestMother(fParticles.size());
+  
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    isUsed[iParticle] = false;
+    deleteCandidate[iParticle] = false; 
+    bestMother[iParticle] = -1;
+  }
+
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    if(!UseParticleInCompetition(fParticles[iParticle].GetPDG())) continue;
+    
+    bool isSecondary = 1;
+    for(int iPV=0; iPV<NPrimaryVertices(); iPV++)
+    {
+      KFParticle tmp = fParticles[iParticle];
+      tmp.SetProductionVertex(GetPrimVertex(iPV));
+      if(tmp.Chi2()/tmp.NDF()<5)
+        isSecondary=0;
+    }
+    if(isSecondary)
+      deleteCandidate[iParticle] = true;
+  }
+
+//   for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+//   {
+//     if(abs(fParticles[iParticle].GetPDG()) == 431 || abs(fParticles[iParticle].GetPDG()) == 4122)
+//     {
+//       vector<int> daughterIds(fParticles[iParticle].NDaughters());
+//       for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+//         daughterIds[iDaughter] = fParticles[fParticles[iParticle].DaughterIds()[iDaughter]].DaughterIds()[0];
+//       std::sort(daughterIds.begin(), daughterIds.end());
+//       
+//       for(unsigned int jParticle=0; jParticle<fParticles.size(); jParticle++)
+//       {
+//         if(abs(fParticles[jParticle].GetPDG()) == 411)
+//         {
+//           vector<int> daughterIdsDPlus(fParticles[jParticle].NDaughters());
+//           for(int iDaughter=0; iDaughter<fParticles[jParticle].NDaughters(); iDaughter++)
+//             daughterIdsDPlus[iDaughter] = fParticles[fParticles[jParticle].DaughterIds()[iDaughter]].DaughterIds()[0];
+//           std::sort(daughterIdsDPlus.begin(), daughterIdsDPlus.end());
+//           
+//           if(daughterIdsDPlus.size() != daughterIds.size()) continue;
+//           
+//           bool isSameParticle=1;
+//           for(unsigned int iDaughter=0; iDaughter<daughterIds.size(); iDaughter++)
+//             isSameParticle &= daughterIds[iDaughter] == daughterIdsDPlus[iDaughter];
+//           if(!isSameParticle) continue; 
+//       
+//           float mass, massSigma;
+//           fParticles[jParticle].GetMass(mass, massSigma);
+//           
+//           if(fabs(mass - KFParticleDatabase::Instance()->GetDPlusMass()) < 3*KFParticleDatabase::Instance()->GetDPlusMassSigma())
+//           {
+//             deleteCandidate[iParticle] = true;
+//             break;
+//           }
+//         }
+//       }
+//     }
+//   }
+  
+
+  //clean K0 and Lambda
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    if(deleteCandidate[iParticle]) continue;
+    if(!UseParticleInCompetition(fParticles[iParticle].GetPDG())) continue;
+    
+    float mass, massSigma;
+    fParticles[iParticle].GetMass(mass, massSigma);
+    
+    float massPDG, massPDGSigma;
+    KFParticleDatabase::Instance()->GetMotherMass(fParticles[iParticle].GetPDG(), massPDG, massPDGSigma);
+    
+    float dm1 = fabs(mass - massPDG)/massPDGSigma;
+//     if(dm1 > 3.f)  continue;
+      
+    for(unsigned int jParticle=iParticle+1; jParticle<fParticles.size(); jParticle++)
+    {
+      if(deleteCandidate[jParticle]) continue;
+      if(!UseParticleInCompetition(fParticles[jParticle].GetPDG())) continue;
+      
+      fParticles[jParticle].GetMass(mass, massSigma);
+      KFParticleDatabase::Instance()->GetMotherMass(fParticles[jParticle].GetPDG(), massPDG, massPDGSigma);
+      
+      float dm2 = fabs(mass - massPDG)/massPDGSigma;
+//       if(dm2 > 3.f)  continue;
+      
+      if(! (fParticles[iParticle].DaughterIds()[0] == fParticles[jParticle].DaughterIds()[0] &&
+            fParticles[iParticle].DaughterIds()[1] == fParticles[jParticle].DaughterIds()[1]) ) continue;
+      
+      if(dm1 < 3.f || dm2 < 3.f)
+      {
+//         if(dm1 < 3.f && dm2<3.f)
+//         {
+//           KFParticle part1 = fParticles[iParticle];
+//           KFParticle part2 = fParticles[jParticle];
+//           
+//           if(fParticles[iParticle].GetPDG() == 310)
+//           {
+//             deleteCandidate[iParticle] = true;
+//             break;
+//           }
+//           else
+//           {
+//             deleteCandidate[jParticle] = true;
+//           }
+//         }
+          
+        if(dm1 < dm2)
+        {
+          deleteCandidate[jParticle] = true;
+          bestMother[fParticles[iParticle].DaughterIds()[0]] = iParticle;
+          bestMother[fParticles[iParticle].DaughterIds()[1]] = iParticle;
+        }
+        else
+        {
+          deleteCandidate[iParticle] = true;
+          bestMother[fParticles[iParticle].DaughterIds()[0]] = jParticle;
+          bestMother[fParticles[iParticle].DaughterIds()[1]] = jParticle;
+          break;
+        }
+      }
+    }
+  }
+  
+//   for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+//   {
+//     if(!(abs(fParticles[iParticle].GetPDG()) == 22)) continue;
+//     
+//     bool bothDaughtersElectrons = 1;
+//     for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+//     {
+//       const int daughterIndex = fParticles[iParticle].DaughterIds()[iDaughter];
+//       bothDaughtersElectrons &= abs(fParticles[daughterIndex].GetPDG()) == 11;
+//     }
+//     if(!bothDaughtersElectrons)
+//     {
+//       deleteCandidate[iParticle] = true;
+//       continue;
+//     }
+//   }
+  //clean dielectron spectrum
+  //at first - both electrons are identified
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    if(deleteCandidate[iParticle]) continue;
+    if(!(abs(fParticles[iParticle].GetPDG()) == 22)) continue;
+    
+//     bool bothDaughtersElectrons = 1;
+//     for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+//     {
+//       const int daughterIndex = fParticles[iParticle].DaughterIds()[iDaughter];
+//       bothDaughtersElectrons &= abs(fParticles[daughterIndex].GetPDG()) == 11;
+//     }
+//     if(!bothDaughtersElectrons) continue;
+    
+    float mass, massSigma;
+    fParticles[iParticle].GetMass(mass, massSigma);  
+    float massPDG, massPDGSigma;
+    KFParticleDatabase::Instance()->GetMotherMass(fParticles[iParticle].GetPDG(), massPDG, massPDGSigma);
+    float dm = fabs(mass - massPDG)/massPDGSigma;
+    
+    if(dm < 3.f)
+      particleInfo.push_back(ParticleInfo(iParticle, dm));
+  }
+
+  std::sort(particleInfo.begin(), particleInfo.end(), ParticleInfo::compare);
+  
+  for(unsigned int iPI=0; iPI<particleInfo.size(); iPI++)
+  {
+    const int index = particleInfo[iPI].fParticleIndex;
+    if(deleteCandidate[index]) continue;
+    
+    bool isStore = true;
+    for(int iDaughter=0; iDaughter<fParticles[index].NDaughters(); iDaughter++)
+      isStore &= !(isUsed[ fParticles[index].DaughterIds()[iDaughter] ]);
+    
+    if(isStore)
+    {
+      for(int iDaughter=0; iDaughter<fParticles[index].NDaughters(); iDaughter++)
+        isUsed[ fParticles[index].DaughterIds()[iDaughter] ] = true;
+    }
+    else
+      deleteCandidate[index] = true;
+  }
+  
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    if(deleteCandidate[iParticle]) continue;
+    if(!(abs(fParticles[iParticle].GetPDG()) == 22)) continue;
+    
+    bool bothDaughtersElectrons = 1;
+    for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+    {
+      const int daughterIndex = fParticles[iParticle].DaughterIds()[iDaughter];
+      bothDaughtersElectrons &= abs(fParticles[daughterIndex].GetPDG()) == 11;
+    }
+    
+    float mass, massSigma;
+    fParticles[iParticle].GetMass(mass, massSigma);  
+    float massPDG, massPDGSigma;
+    KFParticleDatabase::Instance()->GetMotherMass(fParticles[iParticle].GetPDG(), massPDG, massPDGSigma);
+    float dm = fabs(mass - massPDG)/massPDGSigma;
+    
+//     if( (bothDaughtersElectrons && dm > 3.f) || !bothDaughtersElectrons)
+    if( dm > 3.f )
+    {
+      bool isStore = true;
+      for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+        isStore &= !(isUsed[ fParticles[iParticle].DaughterIds()[iDaughter] ]);
+      if(!isStore)
+      {
+        deleteCandidate[iParticle] = true;
+      }
+    }
+  }
+  
+  // clean LMVM spectrum
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+  {
+    if(!(abs(fParticles[iParticle].GetPDG()) == 100113 || abs(fParticles[iParticle].GetPDG()) == 443)) continue;
+    
+    bool bothDaughtersElectrons = 1;
+    for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+    {
+      const int daughterIndex = fParticles[iParticle].DaughterIds()[iDaughter];
+      bothDaughtersElectrons &= abs(fParticles[daughterIndex].GetPDG()) == 11;
+    }
+    if(!bothDaughtersElectrons)
+    {
+      deleteCandidate[iParticle] = true;
+      continue;
+    }
+    
+    bool isStore = true;
+    for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+      isStore &= !(isUsed[ fParticles[iParticle].DaughterIds()[iDaughter] ]);
+    if(!isStore)
+    {
+      deleteCandidate[iParticle] = true;
+    }
+  }
+//   for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+//   {
+//     if(deleteCandidate[iParticle]) continue;
+//     if(abs(fParticles[iParticle].GetPDG()) == 310 || abs(fParticles[iParticle].GetPDG()) == 3122)
+//     {
+// //       float mass, massSigma;
+// //       fParticles[iParticle].GetMass(mass, massSigma);
+// //       
+//       float massPDG, massPDGSigma;
+//       KFParticleDatabase::Instance()->GetMotherMass(fParticles[iParticle].GetPDG(), massPDG, massPDGSigma);
+// //       
+// //       float dm = fabs(mass - massPDG)/massPDGSigma;
+//       
+//       KFParticle tmp = fParticles[iParticle];
+// //       tmp.SetNonlinearMassConstraint(massPDG);
+//       
+//       particleInfo.push_back(ParticleInfo(iParticle, tmp.Chi2()));
+//     }
+//   }
+//   
+//   std::sort(particleInfo.begin(), particleInfo.end(), ParticleInfo::compare);
+//   
+//   for(unsigned int iPI=0; iPI<particleInfo.size(); iPI++)
+//   {
+//     const int index = particleInfo[iPI].fParticleIndex;
+//     if(deleteCandidate[index]) continue;
+//     
+//     bool isStore = true;
+//     for(int iDaughter=0; iDaughter<fParticles[index].NDaughters(); iDaughter++)
+//       isStore &= !(isUsed[ fParticles[index].DaughterIds()[iDaughter] ]);
+//     
+//     if(isStore)
+//     {
+//       for(int iDaughter=0; iDaughter<fParticles[index].NDaughters(); iDaughter++)
+//         isUsed[ fParticles[index].DaughterIds()[iDaughter] ] = true;
+//     }
+//     else
+//       deleteCandidate[index] = true;
+//   }
+  
+  for(int iParticle=0; iParticle<int(fParticles.size()); iParticle++)
+  {
+    if(deleteCandidate[iParticle]) continue;
+    
+    for(int iDaughter=0; iDaughter<fParticles[iParticle].NDaughters(); iDaughter++)
+      if(bestMother[fParticles[iParticle].DaughterIds()[iDaughter]] != iParticle && bestMother[fParticles[iParticle].DaughterIds()[iDaughter]] > -1)
+      {
+        deleteCandidate[iParticle] = true;
+        break;
+      }
+  }
+
+  for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+    if(deleteCandidate[iParticle])
+      fParticles[iParticle].SetPDG(-1);
+}
+
+bool KFParticleTopoReconstructor::ParticleHasRepeatingDaughters(const KFParticle& particle)
+{
+  /** Checks if the provided particle candidate has two or more daughter tracks 
+   ** with the same index including tracks from the daughter particles in the decay
+   ** chains. Such candidates should be rejected.
+   **/
+  if(particle.NDaughters() < 2) return 0;
+  
+  vector<int> daughters;
+  GetListOfDaughterTracks(particle, daughters);
+  std::sort(daughters.begin(), daughters.end());
+  bool sameDaughter=0;
+  for(unsigned int iDaughter=1; iDaughter<daughters.size(); iDaughter++)
+  {
+    if(daughters[iDaughter] == daughters[iDaughter-1])
+    {
+      sameDaughter = 1;
+      break;
+    }
+  }
+  return sameDaughter;
+}
+
+void KFParticleTopoReconstructor::GetListOfDaughterTracks(const KFParticle& particle, vector<int>& daughters)
+{
+  /** Returns the list of indices of all tracks used for construction of the given particle
+   ** including tracks from the short-lived daughter particles in the decay chain.
+   ** \param[in] particle - the particle to be processed
+   ** \param[out] daughters - a vector with indices of all daughter tracks
+   **/
+  if(particle.NDaughters() == 1)
+    daughters.push_back( particle.DaughterIds()[0] );
+  else
+    for(int iDaughter=0; iDaughter<particle.NDaughters(); iDaughter++)
+      GetListOfDaughterTracks( fParticles[ particle.DaughterIds()[iDaughter] ], daughters);
+}
+
+void KFParticleTopoReconstructor::ReconstructParticles()
+{
+  /** Runs reconstruction of the short-lived particles by KFParticleFinder.
+   ** At first, primary tracks are transported to the DCA point with the
+   ** corresponding primary vertices for better precision,
+   ** chi2-deviation of the secondary tracks to the primary vertex is 
+   ** calculated, and than KFParticleFinder is run. Optionally cleanup of
+   ** the output array of particle candidates can be run.
+   **/
+#ifdef USE_TIMERS
+  timer.Start();
+#endif // USE_TIMERS
+
+  fParticles.clear();
+
+  if(fPV.size() < 1) return;
+
+  TransportPVTracksToPrimVertex();
+  //calculate chi to primary vertex, chi = sqrt(dr C-1 dr)
+  GetChiToPrimVertex(&(fPV[0]), fPV.size());
+
+  fKFParticleFinder->FindParticles(fTracks, fChiToPrimVtx, fParticles, fPV, fPV.size());
+// #pragma omp critical 
+//   std::cout << "NPart " << fParticles.size() << " " << fTracks[0].Size() << " "<< fTracks[1].Size() << " " << fTracks[2].Size() << " " << fTracks[3].Size()<< std::endl;
+    
+//   for(unsigned int iParticle=0; iParticle<fParticles.size(); iParticle++)
+//     if(ParticleHasRepeatingDaughters(fParticles[iParticle]))
+//       fParticles[iParticle].SetPDG(-1);
+//     
+//   SelectParticleCandidates();
+      
+#ifdef USE_TIMERS
+  timer.Stop();
+  fStatTime[3] = timer.RealTime();
+#endif // USE_TIMERS
+} // void KFParticleTopoReconstructor::ReconstructPrimVertex
+
+#ifdef WITHSCIF
+void KFParticleTopoReconstructor::SendDataToXeonPhi( int iHLT, scif_epd_t& endpoint, void* buffer, off_t& offsetServer, off_t& offsetSender, float Bz)
+{
+  //pack the input data
+  int* data = reinterpret_cast<int*>(buffer);
+  int dataSize = NInputSets + 1 + 1; //sizes of the track vectors and pv vector, and field
+  for(int iSet=0; iSet<NInputSets; iSet++)
+    dataSize += fTracks[iSet].DataSize();
+  dataSize += fPV.size() * 9;
+      
+  for(int iSet=0; iSet<NInputSets; iSet++)
+    data[iSet] = fTracks[iSet].Size();
+  data[NInputSets] = fPV.size();
+  
+  float& field = reinterpret_cast<float&>(data[NInputSets+1]);
+  field = Bz;
+  
+  int offset = NInputSets+2;
+      
+  for(int iSet=0; iSet<NInputSets; iSet++)
+    fTracks[iSet].SetDataToVector(data, offset);
+  
+  for(int iP=0; iP<3; iP++)
+  {
+    for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+    {
+      float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+      tmpFloat = fPV[iPV].Parameter(iP)[0];
+    }
+    offset += fPV.size();
+  }
+  
+  for(int iC=0; iC<6; iC++)
+  {
+    for(unsigned int iPV=0; iPV<fPV.size(); iPV++)
+    {
+      float& tmpFloat = reinterpret_cast<float&>(data[offset + iPV]);
+      tmpFloat = fPV[iPV].Covariance(iC)[0];
+    }
+    offset += fPV.size();
+  }
+  
+  //send the input data to Xeon Phi
+  int msgSize = sizeof(int) * dataSize;//1000 * sizeof(int);
+  
+  const uint16_t portSenderId = 2000 + iHLT;
+
+  int controlSignal = portSenderId;
+  scif_send(endpoint, &msgSize, sizeof(int), SCIF_SEND_BLOCK);
+  scif_recv(endpoint, &controlSignal, sizeof(controlSignal), 1);
+  if(controlSignal != portSenderId) { std::cout << controlSignal << " " << portSenderId << std::endl; return; }
+  
+  int ret = scif_writeto(endpoint, offsetServer, msgSize, offsetSender, 0);
+  if ( ret == -1 ) std::cout << "Fail sending array to the server. Error: " << errno << std::endl;
+      
+  scif_send(endpoint, &controlSignal, sizeof(int), SCIF_SEND_BLOCK); // synchronization
+}
+#endif
+
+void KFParticleTopoReconstructor::SaveInputParticles(const string prefix, bool onlySecondary)
+{
+  /** Stores input tracks to the output file. If the "onlySecondary" flag is set,
+   ** only secondary particles are stored. As an input function takes the full path
+   ** to the folder, where output files should be stored. For each event a corresponding
+   ** file will be created in the provided folder. The name of the file is 
+   ** "event#_KFPTracks.data", where "#" is the number of the event.
+   ** \param[in] prefix - path to the output folder
+   ** \param[in] onlySecondary - flag shows if only secondary tracks should be stored
+   **/ 
+  static int nEvents = 0;
+  string outFileName = "/event";
+  char Result[16]; // string which will contain the number
+  sprintf ( Result, "%d", nEvents ); 
+  outFileName += string(Result);
+  outFileName += "_KFPTracks.data";
+
+  ofstream out((prefix+outFileName).data());
+  
+  //save tracks. tracks are already propagated to the beam
+  
+  int nSets = NInputSets;
+  if(onlySecondary)
+    nSets = 2;
+    
+  float B[3] = {0.f}, r[3] = {0.f};
+  KFParticle kfpTmp;
+  kfpTmp.GetFieldValue(r, B);
+  out << B[2] << std::endl;
+  out << nSets << std::endl;
+  for(int iSet=0; iSet<nSets; iSet++)
+  {
+    out << fTracks[iSet].Size() << std::endl;
+    for(int iP=0; iP<6; iP++)
+    {
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+        out << fTracks[iSet].Parameter(iP)[iTr]<< " ";
+      out << std::endl;
+    }
+
+    for(int iC=0; iC<21; iC++)
+    {
+      for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+        out << fTracks[iSet].Covariance(iC)[iTr]<< " ";
+      out << std::endl;
+    }
+
+    for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      out <<  fTracks[iSet].Id()[iTr] << " ";
+    out << std::endl;
+    
+    for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      out <<  fTracks[iSet].PDG()[iTr] << " ";
+    out << std::endl;
+
+    for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      out <<  fTracks[iSet].Q()[iTr] << " ";
+    out << std::endl;
+    
+    for(int iTr=0; iTr<fTracks[iSet].Size(); iTr++)
+      out <<  fTracks[iSet].PVIndex()[iTr] << " ";
+    out << std::endl;
+    
+    out << fTracks[iSet].LastElectron() << " "
+        << fTracks[iSet].LastMuon() << " "
+        << fTracks[iSet].LastPion() << " "
+        << fTracks[iSet].LastKaon() << " "
+        << fTracks[iSet].LastProton() << std::endl;
+  }
+
+  //Save PVs
+  out << fPV.size() << std::endl;
+  for(unsigned int iPV=0; iPV < fPV.size(); iPV++)
+  {
+    out << fPV[iPV].X()[0] << " " << fPV[iPV].Y()[0] << " " << fPV[iPV].Z()[0] << " " << std::endl;
+  
+    for(int iC=0; iC<6; iC++)
+      out << fPV[iPV].GetCovariance(iC)[0] << " ";
+    out << std::endl;
+  }
+  out.close();
+  
+  nEvents++;
+}
+
diff --git a/external/KFParticle/KFParticle/KFParticleTopoReconstructor.h b/external/KFParticle/KFParticle/KFParticleTopoReconstructor.h
new file mode 100644
index 0000000000000000000000000000000000000000..81df1eca06e4cb111778d6d8addbc262b9263e70
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFParticleTopoReconstructor.h
@@ -0,0 +1,276 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFParticleTopoReconstructor_H
+#define KFParticleTopoReconstructor_H
+
+#include "KFParticlePVReconstructor.h"
+#include "KFParticleFinder.h"
+
+#include <vector>
+#include <string>
+
+#include "KFPTrackVector.h"
+#include "KFParticleSIMD.h"
+
+#ifdef USE_TIMERS
+#ifndef HLTCA_STANDALONE
+#include "TStopwatch.h"
+typedef TStopwatch Stopwatch;
+#else
+#include "Stopwatch.h"
+#endif
+#endif
+
+#ifdef KFPWITHTRACKER
+class AliHLTTPCCAGBTracker;
+#endif
+
+#ifdef WITHSCIF
+#include <scif.h>
+#endif
+
+/** @class KFParticleTopoReconstructor
+ ** @brief Class for reconstruction of the full event topology including primary vertices and short-lived particles.
+ ** @author  I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class receives as an input tracks from the track finder (both at first and last hit positions)
+ ** with the PDG hypothesis, reconstructs primary vertex candidates, divides tracks into secondary and 
+ ** primary, each of these groups are subdivided into positive and negative tracks, then they are
+ ** sorted according to the PDG hypothesis, short-lived particles are constructed, optionally competition
+ ** between different particle hypothesis is run for the constructed candidates.
+ **/
+
+class KFParticleTopoReconstructor{
+ public:
+  KFParticleTopoReconstructor():fKFParticlePVReconstructor(0),fKFParticleFinder(0),fTracks(0), fParticles(0), fPV(0), fNThreads(1)
+#ifdef USE_TIMERS
+  ,fTime(0.),timer()
+#endif
+  {
+    /** The default constructor. Allocates memory for all pointers. **/
+#ifdef USE_TIMERS
+    for ( int i = 0; i < fNTimers; i++ ) fStatTime[i] = 0;
+#endif
+    fKFParticlePVReconstructor = new KFParticlePVReconstructor;
+    
+    fKFParticleFinder = new KFParticleFinder;
+    fKFParticleFinder->SetNThreads(fNThreads);
+  }
+  ~KFParticleTopoReconstructor();
+
+#ifdef KFPWITHTRACKER
+  /** Copies tracks from the standalone CA track finder to the vector KFParticleTopoReconstructor::fTracks
+   ** assuming a given pdg hypothesis for each track. Tracks are rotated to the global coordinate system 
+   ** and checked to have finite parameters. The KFParticleTopoReconstructor::fKFParticlePVReconstructor
+   ** is initialised with the copied tracks.
+   ** \param[in] tracker - the standalone CA track finder
+   ** \param[in] pdg - pointer to the vector with PDG hypothesis for each track, if pointer is not provided
+   ** "-1" is set as the pdg hypothesis for all tracks
+   **/
+  void Init(AliHLTTPCCAGBTracker* tracker, std::vector<int>* pdg=0); // init array of particles
+#endif
+  /** Copies provided particles to the vector KFParticleTopoReconstructor::fTracks
+   ** assuming a given PDG hypothesis for each particle. If pointer to pdg-vector is not provided
+   ** "-1" PDG is assigned to each input particle. If pointer to number of precise measurements
+   ** is provided then this field of KFPTrackVector is also initialised. 
+   ** Only tracks at the first hit position are initialised by this method.
+   ** The KFParticleTopoReconstructor::fKFParticlePVReconstructor is initialised with the copied tracks.
+   ** \param[in] particles - vector with input particles (tracks)
+   ** \param[in] pdg - pointer to the vector with PDG hypothesis for each track, if pointer is not provided
+   ** "-1" is set as the pdg hypothesis for all tracks
+   ** \param[in] nPixelHits - pointer to the vector with number of precise measurement in each track
+   **/  
+  void Init(std::vector<KFParticle> &particles, std::vector<int>* pdg=0, std::vector<int>* nPixelHits=0);
+  /** Initialises the pointer KFParticleTopoReconstructor::fTracks with the external pointer "particles".
+   ** Primary vertices are assumed to be found and are also provided externally. Only reconstruction
+   ** of short-lived particles should be run if this initialisation method is used.
+   ** After reconstruction of short-lived particles the KFParticleTopoReconstructor::DeInit() method
+   ** should be called, otherwise an external memory will be released that can lead to the memory
+   ** corruption and segmentation fault.
+   ** \param[in] particles - pointer to the external vectors with input tracks
+   ** \param[in] pv - vector with externally reconstructed primary vertex candidates
+   **/
+  void Init(const KFPTrackVector *particles, const std::vector<KFParticle>& pv);
+  /** Initialises tracks at the first and last hit positions. 
+   ** The KFParticleTopoReconstructor::fKFParticlePVReconstructor is initialised with the copied 
+   ** tracks at the first hit position.
+   ** \param[in] tracks - vector with the tracks at the first hit position
+   ** \param[in] tracksAtLastPoint - vector with the tracks at the last hit position
+   **/
+  void Init(KFPTrackVector &tracks, KFPTrackVector &tracksAtLastPoint);
+
+  /** \brief Sets input clusters of the electromagnetic calorimeter to KFParticleFinder. */
+  void SetEmcClusters(KFPEmcCluster* clusters) { fKFParticleFinder->SetEmcClusters(clusters); }
+  void SetMixedEventAnalysis() { fKFParticleFinder->SetMixedEventAnalysis(); } ///< KFParticleFinder is forced to be run in the mixed event analysis mode.
+  
+  void DeInit() { fTracks = NULL; } ///< Sets a pointer to the input tracks KFParticleTopoReconstructor::fTracks to NULL.
+  /** \brief Cleans all candidates for primary vertices and short-lived particles. */
+  void Clear() { fParticles.clear(); fPV.clear(); fKFParticlePVReconstructor->CleanPV(); }
+  
+  void ReconstructPrimVertex(bool isHeavySystem = 1); // find primary vertex
+  void SortTracks(); //sort tracks according to the pdg hypothesis and pv index
+  void ReconstructParticles(); //find short-lived particles 
+  void SelectParticleCandidates(); //clean particle candidates: track can belong to only one particle
+#ifdef WITHSCIF
+  void SendDataToXeonPhi( int iHLT, scif_epd_t& endpoint, void* buffer, off_t& offsetServer, off_t& offsetSender, float Bz);
+#endif
+  int NPrimaryVertices() const { return fKFParticlePVReconstructor->NPrimaryVertices(); } ///< Returns number of the found primary vertex candidates.
+  KFParticle &GetPrimVertex(int iPV=0) const { return fKFParticlePVReconstructor->GetPrimVertex(iPV); } ///< Return primary vertex candidate with index "iPV".
+  KFVertex &GetPrimKFVertex(int iPV=0) const { return fKFParticlePVReconstructor->GetPrimKFVertex(iPV); } ///< Return primary vertex candidate with index "iPV".
+  /** Returns vector with track indices from a cluster with index "iPV".  */
+  std::vector<int>& GetPVTrackIndexArray(int iPV=0) const { return fKFParticlePVReconstructor->GetPVTrackIndexArray(iPV); }
+  
+  std::vector<KFParticle> const &GetParticles() const { return fParticles; } ///< Returns constant reference to the vector with short-lived particle candidates.
+  /** \brief Logically kills the candidate for short-lived particle with index "iParticle" by setting its PDG hypothesis to "-1". */
+  void RemoveParticle(const int iParticle) { if(iParticle>=0 && iParticle<int(fParticles.size())) fParticles[iParticle].SetPDG(-1); } 
+  const KFPTrackVector* GetTracks() const { return fTracks; } ///< Returns a pointer to the arrays with tracks KFParticleTopoReconstructor::fTracks.
+  const kfvector_float* GetChiPrim() const { return fChiToPrimVtx; } ///<Returns a pointer to the arrays with chi2-deviations KFParticleTopoReconstructor::fChiToPrimVtx.
+  
+  KFParticleFinder* GetKFParticleFinder() { return fKFParticleFinder; } ///< Returns a pointer to the KFParticleFinder object.
+  const KFParticleFinder* GetKFParticleFinder() const { return fKFParticleFinder; } ///< Returns a constant pointer to the KFParticleFinder object.
+  
+  void CleanPV() {
+    /** Cleans vectors with primary vertex candidates and corresponding clusters by calling KFParticlePVReconstructor::CleanPV(). */
+    fKFParticlePVReconstructor->CleanPV();
+  }
+  void AddPV(const KFVertex &pv, const std::vector<int> &tracks) { 
+    /** Adds externally found primary vertex to the list together with the cluster of
+     ** tracks from this vertex.
+     ** \param[in] pv - external primary vertex
+     ** \param[in] tracks - vector with indices of tracks associated with the provided primary vertex.
+     **/
+    fKFParticlePVReconstructor->AddPV(pv,tracks);
+    KFParticle pvPart=pv;
+    fPV.push_back(pvPart);
+    fKFParticleFinder->SetNPV(fPV.size());
+  }
+  void AddPV(const KFVertex &pv) { 
+   /** Adds externally found primary vertex to the list.
+    ** \param[in] pv - external primary vertex
+    **/
+    fKFParticlePVReconstructor->AddPV(pv);
+    KFParticle pvPart=pv;
+    fPV.push_back(pvPart);
+    fKFParticleFinder->SetNPV(fPV.size());
+  }
+  void FillPVIndices()
+  {
+    /** Assigns index of the corresponding primary vertex to each input track
+     ** according to the clusters reconstructed by KFParticlePVReconstructor. */
+    if(fTracks)
+      for(int iPV=0; iPV<NPrimaryVertices(); iPV++)
+        for(unsigned int iPVTrack=0; iPVTrack<GetPVTrackIndexArray(iPV).size(); iPVTrack++)
+          fTracks[0].SetPVIndex(iPV,GetPVTrackIndexArray(iPV)[iPVTrack]);
+  }
+  /** \brief Adds an external particle candidate to the vector. */
+  void AddParticle(const KFParticle& particle) { fParticles.push_back(particle); }
+  /** \brief Adds an external particle candidate to the vector with primary or secondary candidates of KFParticleFinde. */
+  void AddCandidate(const KFParticle& candidate, int iPV = -1) { fKFParticleFinder->AddCandidate(candidate, iPV); }
+
+  void SetBeamLine(KFParticle& p) { fKFParticlePVReconstructor->SetBeamLine(p); } ///< Sets the beam line for precise reconstruction of the primary vertex.
+#ifdef HomogeneousField
+  void SetField(double b);
+#endif
+  
+  //speed measurements
+#ifdef USE_TIMERS
+  void SetTime(double d) { fTime = d; } ///< Sets the total execution time.
+  double Time() const { return fTime; } ///< Returns the total execution time.
+  /** Returns the time of the part of the topology reconstruction according to the index "iTimer":\n
+   ** 0) initialisation, \n
+   ** 1) reconstruction of primary vertices, \n
+   ** 2) sorting of input particles, \n
+   ** 3) reconstruction of short-lived particles.
+   **/
+  double StatTime( int iTimer ) const { return fStatTime[iTimer]; } 
+  int NTimers() const { return fNTimers; } ///< returns number of the timers to measure performance of different parts of the procedure.
+#endif
+
+  void SaveInputParticles(const std::string prefix = "KFPData", bool onlySecondary = 0);
+  void SetNThreads(short int n) { fNThreads=n; } ///< Sets the number of threads to be run in KFParticleFinder. Currently is not used.
+  
+  void SetChi2PrimaryCut(float chi) {
+    /** Sets the same chi-primary cut to the primary vertex finder and KF Particle Finder. */
+    fKFParticlePVReconstructor->SetChi2PrimaryCut(chi); 
+    fKFParticleFinder->SetChiPrimaryCut2D(chi);
+  }
+  
+  void GetListOfDaughterTracks(const KFParticle& particle, std::vector<int>& daughters);
+  bool ParticleHasRepeatingDaughters(const KFParticle& particle);
+
+  const KFParticleTopoReconstructor &operator=(const KFParticleTopoReconstructor& a)
+  {
+    /** Copy operator. All pointers are set to zero, other members are copied. Returns the current object after copying is finished. **/
+    fKFParticlePVReconstructor = 0;
+    fKFParticleFinder = 0;
+    fTracks = 0;
+    
+    fNThreads = a.fNThreads;
+    
+    return *this;
+  }
+  
+  /** \brief A copy constructor. All pointers are set to zero, other members are copied. **/
+  KFParticleTopoReconstructor(const KFParticleTopoReconstructor& a):fKFParticlePVReconstructor(0),fKFParticleFinder(0),fTracks(0), fParticles(), fPV(), fNThreads(a.fNThreads)
+#ifdef USE_TIMERS
+  ,fTime(0.),timer()
+#endif
+  {
+  }
+  
+  /** Copy cuts from KF Particle Finder of another topology reconstructor object topo. */
+  void CopyCuts(const KFParticleTopoReconstructor* topo) { fKFParticleFinder->CopyCuts(topo->fKFParticleFinder); }
+ private:
+
+  void GetChiToPrimVertex(KFParticleSIMD* pv, const int nPV);
+  void TransportPVTracksToPrimVertex();
+  
+  KFParticlePVReconstructor* fKFParticlePVReconstructor; ///< Pointer to the KFParticlePVReconstructor. Allocated in the constructor.
+  KFParticleFinder* fKFParticleFinder; ///< Pointer to the KFParticleFinder object. Allocated in the constructor.
+  /** Pointer to the array with the input tracks. Memory is allocated by the Init() functions.
+   ** For reconstruction of primary vertex candidates unsorted tracks are used. For reconstruction of short-lived particles
+   ** Tracks should be sorted by the KFParticleTopoReconstructor::SortTracks() function. The tracks after sorting are divided 
+   ** into several groups: \n
+   ** 0) secondary positive at the first hit position; \n
+   ** 1) secondary negative at the first hit position; \n
+   ** 2) primary positive at the first hit position; \n
+   ** 3) primary negative at the first hit position; \n
+   ** 4) secondary positive at the last hit position; \n
+   ** 5) secondary negative at the last hit position; \n
+   ** 6) primary positive at the last hit position; \n
+   ** 7) primary negative at the last hit position.
+   **/
+  KFPTrackVector *fTracks; 
+  kfvector_float fChiToPrimVtx[2]; ///< Chi2-deviation of the secondary tracks.
+  std::vector<KFParticle> fParticles; ///< Vector of the reconstructed candidates of short-lived particles.
+  std::vector<KFParticleSIMD, KFPSimdAllocator<KFParticleSIMD> > fPV; ///< Vector of the reconstructed primary vertices.
+    
+  short int fNThreads; ///< Number of threads to be run in KFParticleFinder. Currently is not used.
+  
+  //speed measurements
+#ifdef USE_TIMERS
+  double fTime; ///< Total run time.
+  static const int fNTimers = 4; ///< Number of timers to measure different part of the code.
+  /** \brief Execution time of different parts of the code: initialisation, reconstruction of primary vertices, 
+   ** sorting of input particles, reconstruction of short-lived particles. */ 
+  double fStatTime[fNTimers];
+  Stopwatch timer; ///< Timer.
+#endif // USE_TIMERS
+
+}__attribute__((aligned(sizeof(float_v)))); // class KFParticleTopoReconstructor
+
+
+  
+#endif // KFParticleTopoReconstructor_H
+  
diff --git a/external/KFParticle/KFParticle/KFVertex.cxx b/external/KFParticle/KFParticle/KFVertex.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..40630d225a53dacbd9baeedb8a799aa63e8fd492
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFVertex.cxx
@@ -0,0 +1,139 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  S.Gorbunov, I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#include "KFVertex.h"
+
+#ifndef KFParticleStandalone
+ClassImp(KFVertex);
+#endif
+
+KFVertex::KFVertex( const KFPVertex &vertex ): fIsConstrained(0)
+{
+  /** Constructor from KFPVertex. **/
+
+  vertex.GetXYZ( fP );
+  vertex.GetCovarianceMatrix( fC );  
+  fChi2 = vertex.GetChi2();  
+  fNDF = 2*vertex.GetNContributors() - 3;
+  fQ = 0;
+  fAtProductionVertex = 0;
+  fSFromDecay = 0;
+}
+
+void KFVertex::SetBeamConstraint( float x, float y, float z, 
+                                  float errX, float errY, float errZ )
+{
+  /** Sets a soft beam constraint on the vertex position.
+   ** \param[in] x, y, z - coordinates of the constraint
+   ** \param[in] errX, errY, errZ - corresponding errors
+   **/
+  fP[0] = x;
+  fP[1] = y;
+  fP[2] = z;
+  fC[0] = errX*errX;
+  fC[1] = 0;
+  fC[2] = errY*errY;
+  fC[3] = 0;
+  fC[4] = 0;
+  fC[5] = errZ*errZ;
+  fIsConstrained = 1;
+}
+
+void KFVertex::SetBeamConstraintOff()
+{
+  /** Switches off the constraint. Should be called before KFVertex::ConstructPrimaryVertex() **/
+  fIsConstrained = 0;
+}
+
+void KFVertex::ConstructPrimaryVertex( const KFParticle *vDaughters[], 
+                                       int nDaughters, Bool_t vtxFlag[],
+                                       float ChiCut  )
+{
+  /** Reconstructs the primary vertex from a set of particles. Reconstruction is 
+   ** parformed in three steps:\n
+   ** 1) vertex seed is constructed from all particles; \n
+   ** 2) if particle deviates more then on the "ChiCut" it is rejected; \n
+   ** 3) the final vertex is constructed from the set of remaining particles.\n
+   ** Rejected particles are marked with "false" in the output array of flags.
+   ** \param[in] vDaughters - input array of pointers to the particles
+   ** \param[in] nDaughters - number of particles in the input array
+   ** \param[out] vtxFlag - array of flags showing if particle was used in the 
+   ** vertex fit, if yes - set to "true"
+   ** \param[in] ChiCut - cut on the chi2-deviation of the particle from the created
+   ** seed, by default the cut is set to 3.5
+   **/
+
+  if( nDaughters<2 ) return;
+  float constrP[3]={fP[0], fP[1], fP[2]};
+  float constrC[6]={fC[0], fC[1], fC[2], fC[3], fC[4], fC[5]};
+
+  Construct( vDaughters, nDaughters, 0, -1 );
+
+//   SetVtxGuess( fVtxGuess[0], fVtxGuess[1], fVtxGuess[2] );
+
+  for( int i=0; i<nDaughters; i++ ) vtxFlag[i] = 1;
+
+  Int_t nRest = nDaughters;
+//   while( nRest>2 )
+//   {    
+//     float worstChi = 0.;
+//     Int_t worstDaughter = 0;
+//     for( Int_t it=0; it<nDaughters; it++ ){
+//       if( !vtxFlag[it] ) continue;        
+//       const KFParticle &p = *(vDaughters[it]);
+//       //KFVertex tmp = *this - p;
+//       //float chi = p.GetDeviationFromVertex( tmp );      
+//       float chi = p.GetDeviationFromVertex( *this );      
+//       if( worstChi < chi ){
+//         worstChi = chi;
+//         worstDaughter = it;
+//       }
+//     }
+//     if( worstChi < ChiCut ) break;
+//       std::cout <<"worst 1 " <<  worstDaughter << " " << worstChi << std::endl;
+//     vtxFlag[worstDaughter] = 0;    
+//     //*this -= *(vDaughters[worstDaughter]);
+//     nRest--;
+//   } 
+
+  for( Int_t it=0; it<nDaughters; it++ ){
+    const KFParticle &p = *(vDaughters[it]);
+    float chi = p.GetDeviationFromVertex( *this );      
+    if( chi >= ChiCut ){
+      vtxFlag[it] = 0;    
+      nRest--;
+    }
+  }
+
+  if( nRest>=2 ) {// final refit     
+//     SetVtxGuess( fP[0], fP[1], fP[2] );
+    if( fIsConstrained ){
+      fP[0] = constrP[0];
+      fP[1] = constrP[1];
+      fP[2] = constrP[2];
+      for( int i=0; i<6; i++ ) fC[i] = constrC[i];
+    }
+    int nDaughtersNew=0;
+    const KFParticle **vDaughtersNew=new const KFParticle *[nDaughters];
+    for( int i=0; i<nDaughters; i++ ){
+      if( vtxFlag[i] )  vDaughtersNew[nDaughtersNew++] = vDaughters[i];
+    }
+    Construct( vDaughtersNew, nDaughtersNew, 0, -1 );
+    if (vDaughtersNew) delete[] vDaughtersNew;
+  }
+
+  if( nRest<=2 && GetChi2() > ChiCut*ChiCut*GetNDF() ) {
+    for( int i=0; i<nDaughters; i++ ) vtxFlag[i] = 0;
+    fNDF = -3;
+    fChi2 = 0;
+  }
+}
diff --git a/external/KFParticle/KFParticle/KFVertex.h b/external/KFParticle/KFParticle/KFVertex.h
new file mode 100644
index 0000000000000000000000000000000000000000..f12330835c315cc1ddceb9e6a32979cf6db5f8fe
--- /dev/null
+++ b/external/KFParticle/KFParticle/KFVertex.h
@@ -0,0 +1,88 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  S.Gorbunov, I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#ifndef KFVERTEX_H
+#define KFVERTEX_H
+
+#include "KFParticle.h"
+#include "KFPVertex.h"
+
+/** @class KFVertex
+ ** @brief Mathematics for reconstruction of primary vertices based on KFParticle.
+ ** @author  S.Gorbunov, I.Kisel, M.Zyzak
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is inherited from KFParticle, adds functionality for reconstruction of
+ ** primary vertices.
+ **/
+
+class KFVertex : public KFParticle
+{
+ public:
+
+  KFVertex():KFParticle(),fIsConstrained(0){ } 
+  KFVertex( const KFParticle &particle ): KFParticle(particle), fIsConstrained(0) {} ///< Vertex is constructed from the current position of a given particle.
+  KFVertex( const KFPVertex &vertex );
+  ~KFVertex(){}
+
+  Int_t GetNContributors() const { return fIsConstrained ?fNDF/2:(fNDF+3)/2; } ///< Returns number of particles used for construction of the vertex.
+
+
+  void operator +=( const KFParticle &Daughter );  ///< Adds particle to a vertex.
+  KFVertex operator -( const KFParticle &Daughter ) const; ///< Subtracts particle from a vertex, returns temporary object. Initial vertex stays untouched.
+  void operator -=( const KFParticle &Daughter );  ///< Subtracts particle from a current vertex.
+
+  void SetBeamConstraint( float X, float Y, float Z, 
+                          float ErrX, float ErrY, float ErrZ );
+  void SetBeamConstraintOff();
+
+  void ConstructPrimaryVertex( const KFParticle *vDaughters[], int nDaughters,
+                               Bool_t vtxFlag[], float ChiCut=3.5  );
+
+ protected:
+
+  Bool_t fIsConstrained; ///< Flag showing if the the beam constraint is set
+  
+#ifndef KFParticleStandalone
+  ClassDef( KFVertex, 2 )
+#endif
+};
+
+
+//---------------------------------------------------------------------
+//
+//     Inline implementation of the KFVertex methods
+//
+//---------------------------------------------------------------------
+
+
+inline void KFVertex::operator+=( const KFParticle &Daughter )
+{
+  KFParticle::operator+=( Daughter );
+}
+  
+
+inline void KFVertex::operator-=( const KFParticle &Daughter )
+{
+  Daughter.SubtractFromVertex( *this );
+}
+  
+inline KFVertex KFVertex::operator-( const KFParticle &Daughter ) const 
+{
+  KFVertex tmp = *this;
+  Daughter.SubtractFromVertex( tmp );
+  return tmp;
+}
+
+
+#endif 
diff --git a/external/KFParticle/KFParticleLinkDef.h b/external/KFParticle/KFParticleLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..9591913ae1c185abea19a05e1447093dc766e711
--- /dev/null
+++ b/external/KFParticle/KFParticleLinkDef.h
@@ -0,0 +1,24 @@
+#if defined(__CINT__) || defined(__CLING__)
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+//KFParticle
+#pragma link C++ class  KFParticleBase+;
+#pragma link C++ class  KFParticle+;
+#pragma link C++ class  KFVertex+;
+#pragma link C++ class  KFPTrack+;
+
+//KFParticlePerformance
+#pragma link C++ class  KFMCParticle+;
+#pragma link C++ class  KFPartEfficiencies+;
+
+//#pragma link C++ class  KFParticleTest+;
+
+#endif
+
+
+
+
+
diff --git a/external/KFParticle/KFParticlePerformance/KFMCCounter.h b/external/KFParticle/KFParticlePerformance/KFMCCounter.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c8f1ce30fb01dbefd6ef5d5b0219cd19f4ba878
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCCounter.h
@@ -0,0 +1,119 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFMCCounter_H
+#define KFMCCounter_H
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+/** @class KFMCCounter
+ ** @brief A helper structure to store information on the number of reconstructed and Monte Carlo particles for efficiency calculation.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to calculate reconstruction efficiency and ratios of a given set of particles.
+ **/
+
+template <typename T>
+struct KFMCCounter
+{
+  int NCounters; ///< Number of counters in the current object.
+  
+  std::vector<T> counters; ///< Counters of different set of particles.
+
+  KFMCCounter():NCounters(0),counters(0) { }
+  KFMCCounter(int nCounters):NCounters(nCounters), counters(nCounters,T(0)) { } ///< Constructs the object with the set of counters "nCounters".
+
+  void AddCounter(){ NCounters++; counters.push_back(T(0)); } ///< Adds a counter to the existing list.
+  void AddCounters(int nCounters){ NCounters += nCounters; counters.resize( NCounters, T(0)); } ///< Adds several counters to the existing list.
+  
+  /** Operator adds all counters from object "a" to the current object. Returns the current object. */
+  KFMCCounter& operator+=(KFMCCounter& a){
+    if (NCounters != a.NCounters){
+      std::cout << " KFMCCounter: Error. Addition of counters of different sizes: " << NCounters << " " << a.NCounters << std::endl;
+    }
+    else{
+      for (int iC = 0; iC < NCounters; iC++){
+        counters[iC] += a.counters[iC];
+      }
+    }
+    return *this;
+  };
+  /** Operator adds all counters from object "a" to the current object, result is stored to the temporary object. Returns the temporary object. */
+  KFMCCounter operator+(KFMCCounter& a){
+    KFMCCounter res = *this;
+    res += a;
+    return res;
+  };
+  /** Operator divides all counters from the current object to the counters from object "a", result is stored to the temporary object. Returns the temporary object. */
+  template <typename T2>
+  KFMCCounter<double> operator/(KFMCCounter<T2>& a){
+    KFMCCounter<double> b(NCounters);
+    if (NCounters != a.NCounters){
+      std::cout << " KFMCCounter: Error. Addition of counters of different sizes: " << NCounters << " " << a.NCounters << std::endl;
+    }
+    else{
+      for (int iC = 0; iC < NCounters; iC++){
+        b.counters[iC] = Div(counters[iC],a.counters[iC]);
+      }
+    }
+    return b;
+  }
+  /** Operator divides all counters from the current object to the value "a", result is stored to the temporary object. Returns the temporary object. */
+  template <typename T2>
+  KFMCCounter<T2> operator/(double a){
+    KFMCCounter<T2> b(NCounters);
+    for (int iC = 0; iC < NCounters; iC++){
+      b.counters[iC] = (T2)Div(counters[iC],a);
+    }
+    return b;
+  }
+  /** Operator to write the object "a" to the file "strm".*/
+  friend std::fstream & operator<<(std::fstream &strm, const KFMCCounter<T> &a ){
+    strm << a.NCounters << " " << a.counters.size() << " ";
+    for(unsigned int iV=0; iV<a.counters.size(); iV++)
+      strm << a.counters[iV] << " ";
+    strm << std::endl;
+    return strm;
+  }
+  /** Operator to write the object "a" to the stream "strm".*/
+  friend std::ostream & operator<<(std::ostream &strm, const KFMCCounter<T> &a ){
+    strm << a.NCounters << " " << a.counters.size() << " ";
+    for(unsigned int iV=0; iV<a.counters.size(); iV++)
+      strm << a.counters[iV] << " ";
+    strm << std::endl;
+    return strm;
+  }
+  /** Operator to read the object "a" from the file "strm".*/
+  friend std::fstream & operator>>(std::fstream &strm, KFMCCounter<T> &a ){
+    int tmp;
+    strm >> tmp;
+    a.NCounters = tmp;
+    strm >> tmp;
+    a.counters.resize(tmp,T(0));
+    for(int iV=0; iV<tmp; iV++)
+    {
+      T tmp1;
+      strm >> tmp1;
+      a.counters[iV] = tmp1;
+    }
+    return strm;
+  }
+
+  private:
+    /** Divides value "a" on value "b" if b is not zero, otherwise returns "-1". */
+    double Div(double a, double b){return (b > 0) ? a/b : -1.;}
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFMCParticle.cxx b/external/KFParticle/KFParticlePerformance/KFMCParticle.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f0c55526f6573b8d2173f5b2072358e5f16e6710
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCParticle.cxx
@@ -0,0 +1,36 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFMCParticle.h"
+
+#ifndef KFParticleStandalone
+ClassImp(KFMCParticle)
+#endif
+
+KFMCParticle::KFMCParticle() :fDaughterIds(), fMCTrackID(-1), fMotherId(-1), fPDG(0), fInitialParticleId(-1)
+{
+  for(int i=0; i<3; i++)
+  {
+    fIsReconstructable[i] = 0;
+    fIsV0[i] = 0;
+  }
+  fIsReconstructable[3] = 0;
+  fIsReconstructable[4] = 0;
+}
+
+KFMCParticle::~KFMCParticle()
+{
+}
+
+void KFMCParticle::AddDaughter( int i )
+{
+  fDaughterIds.push_back(i);
+}
diff --git a/external/KFParticle/KFParticlePerformance/KFMCParticle.h b/external/KFParticle/KFParticlePerformance/KFMCParticle.h
new file mode 100644
index 0000000000000000000000000000000000000000..a870deb997e78f63e1ad347f1909c893403704d2
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCParticle.h
@@ -0,0 +1,102 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef _KFMCParticle_h_
+#define _KFMCParticle_h_
+
+#include <vector>
+
+#ifdef HLTCA_STANDALONE
+#include "RootTypesDef.h"
+#else
+#include "TObject.h"
+#endif
+
+/** @class KFMCParticle
+ ** @brief A class to store relations between mother and daughter Monte Carlo simulated particles.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to calculate reconstruction efficiency of all Monte Carlo particles. It is
+ ** simplifies the procedure for short-lived particles. Contains a vector with unique Ids of all
+ ** MC daughters, a unique Id of the corresponding MC track, a unique Id of the MC mother particle,
+ ** the PDG code of the MC particle, flags showing if particle can be reconstructed according
+ ** to several different definitions, flags showing if particle creates a secondary vertex with
+ ** two or more daughters, an index of the initial particle Id in case of the K->mu+nu and pi-> mu+nu
+ ** decays, since GEANT engines do not store neutrinos. 
+ **/
+
+class KFMCParticle :public TObject
+{
+ public:
+  KFMCParticle();
+  ~KFMCParticle();
+
+  void AddDaughter( int i ); ///< Adds an Id of the new particle to the list with Ids of daughter particles.
+  int  NDaughters() const { return fDaughterIds.size(); } ///< Returns number of daughter particles.
+  const std::vector<int>&  GetDaughterIds() const { return fDaughterIds; } ///< Returns a reference to the vector with Id of daughter particle KFMCParticle::fDaughterIds.
+  void CleanDaughters() { fDaughterIds.resize(0); } ///< Remove Ids of all daughter particles from the current object.
+
+  void SetPDG(int pdg) {fPDG = pdg;} ///< Set the PDG code of the current particle KFMCParticle::fPDG.
+  void SetMCTrackID(int id) {fMCTrackID = id;} ///< Sets the Id of the corresponding Monte Carlo track KFMCParticle::fMCTrackID.
+  void SetMotherId(int id) {fMotherId = id;} ///< Sets the Id of the mother particle or primary vertex KFMCParticle::fMotherId.
+  
+  int  GetMCTrackID()      const {return fMCTrackID;} ///< Returns Id of the corresponding MC track KFMCParticle::fMCTrackID.
+  int  GetMotherId()       const {return fMotherId;}  ///< Returns Id of the mother particle or primary vertex KFMCParticle::fMotherId.
+  int  GetPDG()            const {return fPDG;}       ///< Returns PDG code of the current particle KFMCParticle::fPDG.
+  
+  bool IsReconstructable(int i) const {return fIsReconstructable[i];} ///< Returns a flag showing if particle can be reconstructed with KFMCParticle::fIsReconstructable index "i".
+  void SetAsReconstructable(int i) { fIsReconstructable[i] = 1;} ///< Defines the particle as those which should be reconstructed for the efficiency set "i".
+    
+  bool IsReconstructableV0(int i) const {return fIsV0[i];} ///< Returns a flag showing if particle is a reconstructable V0.
+  void SetAsReconstructableV0(int i) { fIsV0[i] = 1;}      ///< Defines the particle as V0 which should be reconstructed for the efficiency set "i".
+  
+  void SetInitialParticleId(int i) {fInitialParticleId = i;} ///< Sets Id of the Monte Carlo particle, from which the current particle was copied.
+  int InitialParticleId() const {return fInitialParticleId;} ///< Returns the Id of the Monte Carlo particle, from which the current particle was copied.
+ private: //data
+  std::vector<int> fDaughterIds; ///< A vector with Ids of the daughter Monte Carlo particles.
+  int fMCTrackID; ///< A unique Id of the corresponding Monte Carlo track.
+  int fMotherId;  ///< A unique Id of the mother particle. If the current particle is primary the Id of the primary vertex with a negative sigh is stored.
+  int fPDG;       ///< A PDG code of the current particle.
+  
+  /** Flags for calculation of the efficiency, define the denominator in each set of efficiency. 
+   ** Flags 0-2 are used for particles reconstructed by the conventional method, 3 and 4 are used
+   ** for particles found by the missing mass method: \n
+   ** [0] - true for all particles, is used for calculation of the efficiency in 4pi;\n
+   ** [1] - true if the particle is long-lived and can be reconstructed in the detector or
+   ** if the particle is short-lived and all its daughter particles can be reconstructed; detector-dependent;\n
+   ** [2] - true if the particle is long-lived and is reconstructed in the detector or
+   ** if the particle is short-lived and all its daughter particles are reconstructed, 
+   ** is used in calculation of efficiency of the KF Particle Finder method;\n
+   ** [3] - true if the particle is long-lived and is reconstructed in the detector or
+   ** if the particle is short-lived, can be reconstructed by the missing mass method
+   ** and all its daughter particles are reconstructed; \n
+   ** [4] - true for all particles, which can be found by the missing mass method,
+   ** is used for calculation of the efficiency in 4pi.
+   **/
+  bool fIsReconstructable[5];
+  /** Flags to calculate efficiency of short-lived particles producing a secondary vertex with 
+   ** two or more daughters; similar to KFMCParticle::fIsReconstructable[0-2].
+   **/
+  bool fIsV0[3]; 
+
+  /** For calculation of missing mass method efficiency a copy of the mother particle
+   ** is created. fInitialParticleId is an Id of the initial mother particle.
+   **/
+  int fInitialParticleId;
+#ifndef KFParticleStandalone
+  ClassDef( KFMCParticle, 1 )
+#endif
+};
+
+#endif
+
diff --git a/external/KFParticle/KFParticlePerformance/KFMCTrack.h b/external/KFParticle/KFParticlePerformance/KFMCTrack.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7d4fe87f4553ad4ed6e6baaab05e92957939d82
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCTrack.h
@@ -0,0 +1,82 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFMCTRACK_H
+#define KFMCTRACK_H
+
+#include <cmath>
+
+/** @class KFMCTrack
+ ** @brief A class for storage of the Monte Carlo simulated track in the cartesian parametrisation.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** A track is described with the parameters { X, Y, Z, Px, Py, Pz, q/P }. Parameters are stored at
+ ** the origin position. Class also contains Id of the mother track, PDG code for the current track,
+ ** number of Monte Carlo points produced by the simulation engine at the detector stations,
+ ** number of Monte Carlo points produced at the precise detectors (like MVD in CBM, HFT in STAR, 
+ ** ITS in ALICE, etc.). It also has a flag showing if track was found by the reconstruction procedure
+ ** for efficiency calculation, and a flag showing if track was out of acceptance.
+ **/
+
+class KFMCTrack
+{
+ public:
+  KFMCTrack():fMotherId(-1),fPDG(0),fNMCPoints(0), fNMCPixelPoints(0), fIsReconstructed(0),fIsOutOfDetector(0) {};
+
+  int   MotherId()        const { return fMotherId; } ///< Returns a uniqueue Id of the mother track or primary vertex KFMCTrack::fMotherId.
+  int   PDG()             const { return fPDG;}       ///< Returns PDG code of the track KFMCTrack::fPDG.
+  float Par( int i )      const { return fPar[i]; }   ///< Returns value of the parameter KFMCTrack::fPar with index "i".
+  float X()               const { return fPar[0]; }   ///< Returns X coordinate of the track at the origin position.
+  float Y()               const { return fPar[1]; }   ///< Returns Y coordinate of the track at the origin position.
+  float Z()               const { return fPar[2]; }   ///< Returns Y coordinate of the track at the origin position.
+  float L()               const { return sqrt(X()*X() + Y()*Y() + Z()*Z()); } ///< Returns distance from the origin of the track to a point {0,0,0}.
+  float Px()              const { return fPar[3]; }   ///< Returns Px momentum component of the track at the origin position.
+  float Py()              const { return fPar[4]; }   ///< Returns Py momentum component of the track at the origin position.
+  float Pz()              const { return fPar[5]; }   ///< Returns Pz momentum component of the track at the origin position.
+  float P()               const { return sqrt(fPar[3]*fPar[3] + fPar[4]*fPar[4] + fPar[5]*fPar[5]); } ///< Returns momentum of the track.
+  float Pt()              const { return sqrt(fPar[3]*fPar[3] + fPar[4]*fPar[4]); } ///< Returns transverse momentum of the track.
+  const float *Par()      const { return fPar; }             ///< Returns a pointer to the array with track parameters KFMCTrack::fPar.
+  int   NMCPoints()       const { return fNMCPoints; }       ///< Returns number of MC points KFMCTrack::fNMCPoints.
+  int   NMCPixelPoints()  const { return fNMCPixelPoints; }  ///< Returns number of MC points at the precise detectors KFMCTrack::fNMCPixelPoints.
+  bool  IsReconstructed() const { return fIsReconstructed; } ///< Returns a flag showing if track was found by the reconstruction procedure.
+  bool  IsOutOfDetector() const { return fIsOutOfDetector; } ///< Returns a flag showing if track was out of acceptance.
+  
+  void SetPar( int i, float v )  { fPar[i] = v; }          ///< Sets a value "v" to the parameter with index "i".
+  void SetX( float v )           { fPar[0] = v; }          ///< Sets X coordinate at the origin position of the track.
+  void SetY( float v )           { fPar[1] = v; }          ///< Sets Y coordinate at the origin position of the track.
+  void SetZ( float v )           { fPar[2] = v; }          ///< Sets Z coordinate at the origin position of the track.
+  void SetPx( float v )          { fPar[3] = v; }          ///< Sets Px momentum component at the origin position of the track.
+  void SetPy( float v )          { fPar[4] = v; }          ///< Sets Py momentum component at the origin position of the track.
+  void SetPz( float v )          { fPar[5] = v; }          ///< Sets Pz momentum component at the origin position of the track.
+  void SetQP( float v )          { fPar[6] = v; }          ///< Sets q/P at the origin position of the track.
+  void SetMotherId( int v )      { fMotherId = v; }        ///< Sets a unique id of the mother track if track is secondary or primary vertex with a negative sign if it is primary.
+  void SetPDG( int v )           { fPDG = v; }             ///< Sets PDG code of the current track.
+  void SetNMCPoints( int v )     { fNMCPoints = v; }       ///< Sets number of MC points produced at the detector planes.
+  void SetNMCPixelPoints( int v ){ fNMCPixelPoints = v; }  ///< Sets number of the MC points produced at the precise detectors.
+  void SetReconstructed()        { fIsReconstructed = 1; } ///< Defines the track as reconstructed.
+  void SetNotReconstructed()     { fIsReconstructed = 0; } ///< Defines the track as not reconstructed.
+  void SetOutOfDetector()        { fIsOutOfDetector = 1; } ///< Defines the track out of acceptance.
+  
+ protected:
+
+  int   fMotherId;       ///< Index of the mother track in tracks array. If track is produced at the primary vertex (PV) negative value with the PV Id is assigned.
+  int   fPDG;            ///< The PDG code of the current Monte Carlo track.
+  float fPar[7];         ///< Parameters of the track: { X, Y, Z, Px, Py, Pz, q/P }, where "q" is its charge.
+  int   fNMCPoints;      ///< Total number of Monte Carlo points produced by the simulation engine at the detector stations.
+  int   fNMCPixelPoints; ///< Number of Monte Carlo points produced at the precise detectors (like MVD in CBM, HFT in STAR, ITS in ALICE, etc.).
+  
+  bool fIsReconstructed; ///< A flag showing if track was found by the reconstruction procedure. Is required for correct efficiency calculation.
+  bool fIsOutOfDetector; ///< A flag showing if track was out of acceptance. Is required for correct calculation of the acceptance.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFMCVertex.cxx b/external/KFParticle/KFParticlePerformance/KFMCVertex.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..eab2f904b1309c45f703e6ea89c7680dfc41198a
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCVertex.cxx
@@ -0,0 +1,38 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFMCVertex.h"
+
+KFMCVertex::KFMCVertex():fDaughterTracks(0),fIsReconstructable(0),fIsMCReconstructable(0),fIsReconstructed(0),fNReconstructedDaughters(0),fIsTriggerPV(0)
+{
+  for( int i = 0; i < 3; i++) fPar[i] = 0;
+}
+
+std::ostream& operator<<(std::ostream& out, const KFMCVertex &a)
+{
+  /** Operator to print coordinates of the MC vertex "a".
+   ** \param[in] out - stream, where coordinates will be printed
+   ** \param[in] a - vertex to be printed
+   **/
+  for (int i = 0; i < 3; i++) out << a.fPar[i] << std::endl;
+  return out;
+}
+
+std::istream& operator>>(std::istream& in, KFMCVertex &a)
+{
+  /** Operator to read coordinates of the vertex from the input stream. 
+   ** \param[in] in - input stream
+   ** \param[in] a - vertex, where the coordinates will be read in
+   **/
+  for (int i = 0; i < 3; i++) in >> a.fPar[i];
+  return in;
+}
+
diff --git a/external/KFParticle/KFParticlePerformance/KFMCVertex.h b/external/KFParticle/KFParticlePerformance/KFMCVertex.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff1ec2d68933ee9c64ccf4a080200943ce4b1c53
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFMCVertex.h
@@ -0,0 +1,95 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFMCVERTEX_H
+#define KFMCVERTEX_H
+
+#include <iostream>
+#include <vector>
+
+/** @class KFMCVertex
+ ** @brief A class to store information about simulated Monte Carlo primary vertices.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class contains coordinates of the vertex, indices of the Monte Carlo tracks produced
+ ** at this vertex, classification flags, number of the reconstructed Monte Carlo tracks.
+ **/
+
+class KFMCVertex
+{
+ public:
+  KFMCVertex();
+
+  float Par( int i )  const { return fPar[i]; } ///< Returns parameter with index "i" from KFMCVertex::fPar
+
+  float X()           const { return fPar[0]; } ///< Returns X coordinate of the vertex.
+  float Y()           const { return fPar[1]; } ///< Returns Y coordinate of the vertex.
+  float Z()           const { return fPar[2]; } ///< Returns Z coordinate of the vertex.
+  
+  const float* GetPar()      const { return fPar; } ///< Returns pointer to the parameters of the vertex KFMCVertex::fPar
+  
+  void SetPar( int i, float v )   { fPar[i] = v; } ///< Sets a value "v" to parameter "i".
+  
+  void SetX( float v )            { fPar[0] = v; } ///< Sets value "v" to the X coordinate.
+  void SetY( float v )            { fPar[1] = v; } ///< Sets value "v" to the Y coordinate.
+  void SetZ( float v )            { fPar[2] = v; } ///< Sets value "v" to the Z coordinate.
+
+  int NDaughterTracks() const { return fDaughterTracks.size(); } ///< Returns number of Monte Carlo tracks produced at the current vertex.
+  int NReconstructedDaughterTracks() const { return fNReconstructedDaughters; } ///< Returns number of reconstructed tracks from this vertex.
+  void AddDaughterTrack( int iTr ) { fDaughterTracks.push_back(iTr); } ///< Adds unique id of the Monte Carlo track produced at the current vertex.
+  int DaughterTrack( int iTr ) const 
+  { 
+    /** Returns unique id of the Monte Carlo track from this vertex with index "iTr".
+     ** \param[in] iTr - index of the track.
+     **/
+    if(iTr >= NDaughterTracks())
+    {
+      std::cout << "ERROR!!!! MC PV contains only " << NDaughterTracks() << " tracks" << std::endl; 
+      return -1;
+    }
+    return fDaughterTracks[iTr];
+  }
+
+  bool IsMCReconstructable() const { return fIsMCReconstructable; } ///< Returns flag showing if the vertex can be found (definition is based on the MC tracks)
+  bool IsReconstructable() const { return fIsReconstructable; }     ///< Returns flag showing if the vertex can be found (definition is based on the reconstructed tracks)
+  bool IsReconstructed()  const { return fIsReconstructed;   }      ///< Returns flag showing if the vertex was reconstructed
+  
+  void SetReconstructable() { fIsReconstructable = 1; }        ///< Defines the current vertex as such that can be reconstructed (based on the reconstructed tracks)
+  void SetUnReconstructable() { fIsReconstructable = 0; }      ///< Defines the current vertex as such that can not be reconstructed (based on the reconstructed tracks)     
+  
+  void SetMCReconstructable() { fIsMCReconstructable = 1; }    ///< Defines the current vertex as such that can be reconstructed (based on the MC tracks)
+  void SetMCUnReconstructable() { fIsMCReconstructable = 0; }  ///< Defines the current vertex as such that can not be reconstructed (based on the MC tracks)
+  
+  void SetReconstructed() { fIsReconstructed = 1; }   ///< Defines the current vertex as such that was reconstructed
+  void SetUnReconstructed() { fIsReconstructed = 0; } ///< Defines the current vertex as such that was not reconstructed
+
+  void SetNReconstructedDaughters(int n) { fNReconstructedDaughters = n; } ///< Defines number of the reconstructed tracks produced at the current vertex.
+  
+  bool IsTriggerPV() const { return fIsTriggerPV; } ///< Returns flag showing if the vertex is considerred as tigger.
+  void SetTriggerPV() { fIsTriggerPV = 1; }         ///< Defines the current vertex as the trigger primary vertex.
+  
+  friend std::ostream& operator<<(std::ostream& out, const KFMCVertex &a);
+  friend std::istream& operator>>(std::istream& in, KFMCVertex &a);
+
+ protected:
+
+  float fPar[3];                    ///< Cartesian coordinates of the vertex: { X, Y, Z }.
+  std::vector<int> fDaughterTracks; ///< Vector with unique ids of the Monte Carlo tracks produced at this vertex.
+  bool fIsReconstructable;          ///< Flag showing if the vertex considered as reconstructable based on the reconstructed tracks.
+  bool fIsMCReconstructable;        ///< Flag showing if the vertex considered as reconstructable based on the Monte Carlo tracks.
+  bool fIsReconstructed;            ///< Flag showing if vertex was reconstructed.
+  int fNReconstructedDaughters;     ///< Number of found tracks, produced at the current vertex.
+  bool fIsTriggerPV;                ///< Flag showing if the vertex was a trigger primary vertex.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram.h b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd82adbe554e1ed25d1593cf3b02c58c20435537
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram.h
@@ -0,0 +1,164 @@
+//----------------------------------------------------------------------------
+// Structures to collect histograms online
+// .
+// @author  M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+
+#ifndef KFPHISTOGRAM
+#define KFPHISTOGRAM
+
+#include "KFPHistogramSet.h"
+#include "KFPartEfficiencies.h"
+#include "KFParticleTopoReconstructor.h"
+#include <map>
+#include <iostream>
+#include <fstream>
+
+/** @class KFPHistogram
+ ** @brief A common object containing histograms for all particle species.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to collect histograms in the environment,
+ ** where ROOT is not available, for example at Intel Xeon Phi cards.
+ ** Contains a set of histograms for each decay reconstructed by the
+ ** KF Particle Finder package, allocates the memory for all histograms:
+ ** This allows faster allocation, faster transfer of the memory,
+ ** easier access from the Intel Xeon Phi, better performance.
+ **/
+
+class KFPHistogram
+{  
+ public:
+  KFPHistogram(): fPdgToIndex(), fOutFileName("KFPHistograms.txt"), fMemory(0)
+  {
+    KFPartEfficiencies partEff;
+    fPdgToIndex = partEff.GetPdgToIndexMap();
+    
+    int dataSize = 0;
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    {
+      fKFPHistogramSet[iParticle] = KFPHistogramSet(iParticle);
+      dataSize += fKFPHistogramSet[iParticle].DataSize();
+    }
+    
+    fMemory = new int[dataSize];
+    std::memset(fMemory, 0, dataSize);
+    
+    int* pointer = fMemory;
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    {
+      fKFPHistogramSet[iParticle].SetHistogramMemory(pointer);
+      pointer += fKFPHistogramSet[iParticle].DataSize();
+    }
+  } ///< Default Constructor. Creates histograms, allocates memory for them.
+  ~KFPHistogram() { if(fMemory) delete [] fMemory; }
+  
+  void SetOutFileName(std::string name) { fOutFileName = name; } ///< Set the name of the output file.
+  
+  inline void Fill(const KFParticle& particle)
+  {
+    std::map<int, int>::iterator it;
+    it=fPdgToIndex.find(particle.GetPDG());
+    if(it != fPdgToIndex.end())
+      fKFPHistogramSet[it->second].Fill(particle);
+  } ///< Fills histograms using parameters of the given particle.
+  
+  inline void Fill(const KFParticleTopoReconstructor& topoReconstructor)
+  {
+    for(unsigned int iParticle=0; iParticle<topoReconstructor.GetParticles().size(); iParticle++)
+      Fill(topoReconstructor.GetParticles()[iParticle]);
+  } ///< Fills histograms for each particle reconstructed by the KFParticleFinder object from the given KFParticleTopoReconstructor.
+    
+  KFPHistogramSet GetHistogramSet(int iSet)   const { return fKFPHistogramSet[iSet]; } ///< Returns set of histograms for the decay with index iSet.
+  /** \brief Returns "iHistogram" histogram from the set of histograms for the decay with index "iSet". */
+  KFPHistogram1D  GetHistogram(int iSet, int iHistogram) const { return fKFPHistogramSet[iSet].GetHistogram1D(iHistogram); }
+  
+  friend std::fstream & operator<<(std::fstream &strm, KFPHistogram &histograms)
+  {
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++ )
+    {
+      strm << iParticle << std::endl;
+      const int& nHistograms = histograms.fKFPHistogramSet[iParticle].GetNHisto1D();
+      for(int iHistogram = 0; iHistogram<nHistograms; iHistogram++)
+      {
+        const KFPHistogram1D& histogram = histograms.fKFPHistogramSet[iParticle].GetHistogram1D(iHistogram);
+        strm << histogram.Name() << " " << histogram.MinBin() << " " << histogram.MaxBin() << " " << histogram.NBins() << std::endl;
+        for(int iBin=0; iBin<histogram.NBins()+2; iBin++)
+          strm << histogram.GetHistogram()[iBin] << " ";
+        strm << std::endl;
+      }
+    }
+
+    return strm;
+  } ///< Stores all histograms to the output file.
+  
+  void Save() 
+  {
+    std::fstream file(fOutFileName.data(),std::fstream::out);
+    file << (*this);
+    file.close();
+  } ///< Stores all histograms to the file with the name defined in KFPHistogram::fOutFileName.
+  
+  bool FillFromFile( std::string prefix )
+  {
+    std::fstream ifile(prefix.data(),std::fstream::in);
+    if ( !ifile.is_open() ) return 0;
+
+    int iSet = 0;
+    
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++ )
+    {
+      ifile >> iSet;
+      const int& nHistograms = fKFPHistogramSet[iParticle].GetNHisto1D();
+      for(int iHistogram = 0; iHistogram<nHistograms; iHistogram++)
+      {
+        std::string name;
+        float minBin = 0.f, maxBin = 0.f;
+        int nBins = 0;
+        ifile >> name >> minBin >> maxBin >> nBins;
+        if(nBins  != fKFPHistogramSet[iParticle].GetHistogram1D(iHistogram).NBins()  || 
+           minBin != fKFPHistogramSet[iParticle].GetHistogram1D(iHistogram).MinBin() || 
+           maxBin != fKFPHistogramSet[iParticle].GetHistogram1D(iHistogram).MaxBin() ) 
+        {
+          std::cout << "Fatal error: size of the histograms is not in an agreement with the current version." << std::endl;
+          exit(1);
+        }
+        
+        int binContent = 0;
+        for(int iBin=0; iBin<nBins+2; iBin++)
+        {
+          ifile >> binContent;
+          fKFPHistogramSet[iParticle].SetHisto1DBinContent(iHistogram, iBin, binContent);
+        }
+      }
+    }
+    
+    ifile.close();
+    return 1;
+  } ///< Reads object from the file with the name defined by "prefix".
+  
+  inline void operator += ( const KFPHistogram &h )
+  {
+    for(int i=0; i<KFPartEfficiencies::nParticles; i++)
+      fKFPHistogramSet[i] += h.fKFPHistogramSet[i];
+  }///< Adds all histograms from object "h" to the current object.
+  
+ private:
+  std::map<int, int> fPdgToIndex; ///< A map between PDG code and index of the decay in the KF Particle Finder scheme. A copy of an object from KFPartEfficiencies.
+  std::string fOutFileName; ///< The name of the output file, where histograms will be stored.
+  KFPHistogramSet fKFPHistogramSet[KFPartEfficiencies::nParticles]; ///< A set of histograms for all decays reconstructed by KF Particle Finder.
+  int* fMemory; ///< A pointer to the memory for all histograms.
+  
+  KFPHistogram(const KFPHistogram&); ///< Does not allow copying of the objects of this class.
+  KFPHistogram& operator=(const KFPHistogram&); ///< Does not allow copying of the objects of this class.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram1D.h b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram1D.h
new file mode 100644
index 0000000000000000000000000000000000000000..dba6e858727264eb12a01b295ed67f1303a683c6
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogram1D.h
@@ -0,0 +1,109 @@
+//----------------------------------------------------------------------------
+// Structures to collect histograms online
+// .
+// @author  M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPHISTOGRAM1D
+#define KFPHISTOGRAM1D
+
+#include <vector>
+#include <string>
+#include <cmath>
+#include <iostream>
+#include <cstdlib>
+
+/** @class KFPHistogram1D
+ ** @brief One-dimensional histogram.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used to collect one-dimensional histograms in the environment,
+ ** where ROOT is not available, for example at Intel Xeon Phi cards.
+ ** It contains the histogram itself, number of bins, its name,
+ ** minimum and maximum value of the axis. The histogram memory is allocated externally
+ ** (by KFPHistogram) for better performance.
+ **/
+
+class KFPHistogram1D
+{
+ public:
+   
+  KFPHistogram1D(): fHistogram(0), fSize(0), fName(""), fMinBin(0), fMaxBin(0) {}
+  KFPHistogram1D(std::string name, int nBins, float minX, float maxX):
+    fHistogram(0), fSize(nBins+2), fName(name), fMinBin(minX), fMaxBin(maxX) {} ///< Constructor with user-defined parameters.
+  ~KFPHistogram1D() {}
+  
+  int* GetHistogram() const { return fHistogram; } ///< Returns a pointer to the histogram data.
+  std::string Name()  const { return fName; }      ///< Returns name of the histogram.
+  float MinBin()      const { return fMinBin; }    ///< returns minimum of the X axis.
+  float MaxBin()      const { return fMaxBin; }    ///< Returns maximum of the X axis.
+  int   NBins()       const { return (fSize-2); }  ///< Returns number of bins.
+  int   DataSize()    const { return fSize; }      ///< Returns number of bins plus underflow and overflow bins.
+  int   Size()        const { return fSize; }      ///< Returns number of bins plus underflow and overflow bins.
+  
+  inline void SetBinContent(int iBin, int value) { fHistogram[iBin] = value; } ///< Sets the value of the bin "iBin".
+  inline void SetHistogramMemory(int* pointer)   { fHistogram = pointer; }     ///< Sets the pointer to the memory with the histogram.
+  
+  /** Adds "value" to the histogram: calculates the corresponding bin and adds one there. */
+  void Fill(float value)
+  {
+    int iBin = floor(float(value - fMinBin)/float(fMaxBin - fMinBin) * float(fSize-2)) + 1;
+    
+    if(iBin > fSize-1)
+      iBin = fSize-1;
+    if(iBin < 1)
+      iBin = 0;
+    
+    if( !(iBin==iBin) || !(std::isfinite(iBin)) ) iBin = 0;
+    
+    fHistogram[iBin]++;    
+  }
+  
+  /** Adds histogram "h" to the current histogram bin-by-bin. */
+  inline void operator += ( const KFPHistogram1D &h )
+  {
+    if( fSize != h.fSize )
+    {
+      std::cout << "Size of 1D histogram " << fName << " is incorrect. Stop the program." << std::endl;
+    }
+    else
+    {
+      for(int i=0; i<fSize; i++)
+        fHistogram[i] += h.fHistogram[i];
+    }
+  }
+  
+  /** The copy-constructor. Memory for the fHistogram is not allocated, only the pointer is copied.*/
+  KFPHistogram1D(const KFPHistogram1D& h): fHistogram(h.fHistogram), fSize(h.fSize), fName(h.fName), fMinBin(h.fMinBin), fMaxBin(h.fMaxBin)
+  {
+  }
+  
+  /** Copies object "h" to the current object. Memory for the fHistogram is not allocated, only the pointer is copied. Returns the current object.  */
+  const KFPHistogram1D& operator=(const KFPHistogram1D& h)
+  {
+    fHistogram = h.fHistogram;
+    fSize = h.fSize;
+    fName = h.fName;
+    fMinBin = h.fMinBin;
+    fMaxBin = h.fMaxBin;
+    
+    return *this;
+  }
+  
+ private:
+  int* fHistogram;   ///< Pointer to the array with the values of the histogram.
+  int fSize;         ///< Number of bins +2, additional two bins are reserved for the underflow and overflow.
+  
+  std::string fName; ///< Name of the histogram.
+  float fMinBin;     ///< Minimum value at the X axis.
+  float fMaxBin;     ///< Maximum value at the X axis.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.cxx b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2ec0aed5311f70a688931ef15d8586637c1acb57
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.cxx
@@ -0,0 +1,168 @@
+//----------------------------------------------------------------------------
+// Structures to collect histograms online
+// .
+// @author  M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPHistogramSet.h"
+#include "KFPartEfficiencies.h"
+
+KFPHistogramSet::KFPHistogramSet(int iPart)
+{
+  /** Creates a set of histograms for the given particle specie. 
+   ** \param[in] iPart - number of the particle specie in the KF Particle Finder scheme
+   ** \see KFPartEfficiencies for the definition of "iPart". 
+   **/
+  KFPartEfficiencies fParteff;
+  std::string parName[NHisto1D] = {"M","p","p_{t}","y","DecayL","c#tau","chi2ndf","prob","#theta","phi","X","Y","Z","R", "L", "l/dl","Multiplicity"};
+#ifdef CBM
+  int nBins[NHisto1D] = {1000, // M
+                          100, // p
+                          100, // pt
+                          100, // y
+                          100, // DecayL
+                          100, // ctau
+                          100, // chi2/ndf
+                          100, // prob
+                          100, // theta
+                          100, // phi
+                          200, // X
+                          200, // Y
+                          360, // Z
+                          200, // R
+                          200, // L
+                          200, // L/dL
+                        fParteff.partMaxMult[iPart]+1};
+  float xMin[NHisto1D] = { fParteff.partMHistoMin[iPart], // M
+                            0.f, // p
+                            0.f, // pt
+                            0.f, // y
+                            -5.f, // DecayL
+                            0.f, // ctau
+                            0.f, // chi2/ndf
+                            0.f, // prob
+                            -2.f, // theta
+                            -2.f, // phi
+                          -50.f, // X
+                          -50.f, // Y
+                          -10.f, // Z
+                            0.f, // R
+                            0.f, // L
+                            -1.f, // L/dL
+                            -0.5f };
+  float xMax[NHisto1D] = { fParteff.partMHistoMax[iPart], // M
+                            10.f, // p
+                              3.f, // pt
+                              6.f, // y
+                            55.f, // DecayL
+                            30.f, // ctau
+                            20.f, // chi2/ndf
+                              1.f, // prob
+                              2.f, // theta
+                              2.f, // phi
+                            50.f, // X
+                            50.f, // Y
+                            80.f, // Z
+                            50.f, // R
+                            100.f, // L
+                            35.f, // L/dL
+                          float(fParteff.partMaxMult[iPart])+0.5f};
+#else
+  int nBins[NHisto1D] = {1000, // M
+                          100, // p
+                          100, // pt
+                          100, // y
+                          100, // DecayL
+                          100, // ctau
+                          100, // chi2/ndf
+                          100, // prob
+                          100, // theta
+                          100, // phi
+                          100, // X
+                        1000, // Y
+                        1000, // Z
+                        1000, // R
+                        1000, // L
+                        1000, // L/dL
+                        fParteff.partMaxMult[iPart]+1};
+  float xMin[NHisto1D] = { fParteff.partMHistoMin[iPart], // M
+                            0.f, // p
+                            0.f, // pt
+                            -6.f, // y
+                            -5.f, // DecayL
+                            0.f, // ctau
+                            0.f, // chi2/ndf
+                            0.f, // prob
+                            -2.f, // theta
+                            -2.f, // phi
+                          -200.f, // X
+                          -200.f, // Y
+                          -200.f, // Z
+                            0.f, // R
+                            0.f, // L
+                            -1.f, // L/dL
+                            -0.5f };
+  float xMax[NHisto1D] = { fParteff.partMHistoMax[iPart], // M
+                            10.f, // p
+                              3.f, // pt
+                              6.f, // y
+                            55.f, // DecayL
+                            30.f, // ctau
+                            20.f, // chi2/ndf
+                              1.f, // prob
+                              2.f, // theta
+                              2.f, // phi
+                            200.f, // X
+                            200.f, // Y
+                            200.f, // Z
+                            200.f, // R
+                            400.f, // L
+                            35.f, // L/dL
+                          float(fParteff.partMaxMult[iPart])+0.5f};
+#endif
+  for(int iHisto=0; iHisto<NHisto1D; iHisto++)
+    fKFPHistogram1D[iHisto] = KFPHistogram1D(parName[iHisto], nBins[iHisto], xMin[iHisto], xMax[iHisto]);
+}
+
+void KFPHistogramSet::SetHistogramMemory(int* pointer)
+{
+  /** Sets a pointer to the memory allocated externally for the current set of histograms.
+   ** \param[in] pointer - pointer to the memory
+   **/
+  for(int i=0; i<NHisto1D; i++)
+  {
+    fKFPHistogram1D[i].SetHistogramMemory(pointer);
+    pointer += fKFPHistogram1D[i].DataSize();
+  }
+}
+
+void KFPHistogramSet::Fill(const KFParticle& particle)
+{
+  /** Fill all possible histograms using parameters of the provided KFParticle object.
+   ** \param[in] particle - KFParticle object
+   **/  
+  float mass = 0, p=0, pt=0, err = 0;
+  particle.GetMass(mass, err);
+  particle.GetMomentum(p, err);
+  particle.GetPt(pt, err);
+  float rapidity = particle.GetRapidity();
+  float chi2ndf  = particle.GetChi2()/float(particle.GetNDF());
+  float r        = sqrt(particle.X()*particle.X() + particle.Y()*particle.Y());
+  float l        = sqrt(particle.X()*particle.X() + particle.Y()*particle.Y() + particle.Z()*particle.Z());
+  
+  fKFPHistogram1D[0].Fill(mass);
+  fKFPHistogram1D[1].Fill(p);
+  fKFPHistogram1D[2].Fill(pt);
+  fKFPHistogram1D[3].Fill(rapidity);
+  fKFPHistogram1D[6].Fill(chi2ndf);
+  fKFPHistogram1D[10].Fill(particle.X());
+  fKFPHistogram1D[11].Fill(particle.Y());
+  fKFPHistogram1D[12].Fill(particle.Z());
+  fKFPHistogram1D[13].Fill(r);
+  fKFPHistogram1D[14].Fill(l);
+}
diff --git a/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.h b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.h
new file mode 100644
index 0000000000000000000000000000000000000000..032c22125a71cf39d74597bc7547cd13eeb1fba5
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPHistogram/KFPHistogramSet.h
@@ -0,0 +1,68 @@
+//----------------------------------------------------------------------------
+// Structures to collect histograms online
+// .
+// @author  M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPHISTOGRAMSET
+#define KFPHISTOGRAMSET
+
+#include "KFPHistogram1D.h"
+#include "KFParticle.h"
+
+/** @class KFPHistogramSet
+ ** @brief A set of histograms collected at the external devise.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class defines a set of histograms to be collect in the environment,
+ ** where ROOT is not available, for example at Intel Xeon Phi cards.
+ ** It contains a set of one-dimensional histograms.
+ ** Also,Calculates the needed amount of memory to be allocated
+ **/
+
+class KFPHistogramSet
+{
+ public:
+  KFPHistogramSet(int iPart=0);
+  ~KFPHistogramSet() {}
+  
+  void Fill(const KFParticle& particle);
+  
+  inline int GetNHisto1D() const { return NHisto1D; } ///< Returns a number of one dimensional histograms in the set.
+  inline int DataSize() const 
+  {
+    int dataSize = 0;
+    for(int i=0; i<NHisto1D; i++)
+      dataSize += fKFPHistogram1D[i].DataSize();
+    return dataSize;
+  } ///< Returns the size of the memory in blocks of integer (or 4 bytes, or 32 bits) to be allocated for the histogram set. \see KFPHistogram, where memory is allocated.
+  KFPHistogram1D GetHistogram1D(int iHistogram) const { return fKFPHistogram1D[iHistogram]; } ///< Returns one dimensional histogram with index "iHistogram".
+  
+  /**Sets bin content of the histogram "iHisto" to a given value.
+   ** \param[in] iHisto - index of the histogram in the set
+   ** \param[in] iBin - number of the bin
+   ** \param[in] value - value to be set
+   **/
+  inline void SetHisto1DBinContent(int iHisto, int iBin, int value)   { fKFPHistogram1D[iHisto].SetBinContent(iBin,value); }
+  
+  inline void operator += ( const KFPHistogramSet &h )
+  {
+    for(int i=0; i<NHisto1D; i++)
+      fKFPHistogram1D[i] += h.fKFPHistogram1D[i];
+  } ///< Adds all histograms bin-by-bin from the histogram set "h" to the current set.
+  
+  void SetHistogramMemory(int* pointer);
+  
+ private:
+  static const int NHisto1D = 17; ///< Number of histogram per each particle specie.
+  KFPHistogram1D fKFPHistogram1D[NHisto1D]; ///< A set of the one dimensional histograms.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPVEfficiencies.h b/external/KFParticle/KFParticlePerformance/KFPVEfficiencies.h
new file mode 100644
index 0000000000000000000000000000000000000000..5efb4ada1109a516c65fbd5c8fa22f6391bd83be
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPVEfficiencies.h
@@ -0,0 +1,220 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPVEfficiencies_H
+#define KFPVEfficiencies_H
+
+#ifndef HLTCA_STANDALONE
+#include "TNamed.h"
+#endif
+
+#include <map>
+#include <iomanip>
+#include "KFMCCounter.h"
+
+/** @class KFPVEfficiencies
+ ** @brief Class to calculate efficiency of KF Particle Finder.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class calculates reconstruction efficiency of the primary vertices.\n
+ ** Definitions:\n
+ ** background - physics background, when daughter particle come from the secondary vertex;\n
+ ** ghost - combinatorial background, tracks do not form a real vertex;\n
+ ** clone - a vertex is reconstructed several times, for example, half of tracks form one group and
+ ** another half form second group.
+ **/
+
+class KFPVEfficiencies: public TNamed
+{
+ public:
+
+  KFPVEfficiencies():
+    names(),
+    indices(),
+    ratio_reco(),
+    mc(),
+    reco(),
+    ratio_ghost(),
+    ratio_bg(),
+    ratio_clone(),
+    ghost(),
+    bg(),
+    clone()
+  {
+    AddCounter(Form("%s","PV"), Form("%-*s",12,"PV"));
+    AddCounter(Form("%s","PVtrigger"), Form("%-*s",12,"PV trigger"));
+    AddCounter(Form("%s","PVpileup"), Form("%-*s",12,"PV pileup "));
+  }
+
+  virtual ~KFPVEfficiencies(){};
+
+  virtual void AddCounter(TString shortname, TString name)
+  {
+    /** Adds a counter with the name defined by "name" to all counter
+     ** objects. For easiness of operation with counters, a shortname is assigned
+     ** to each of them and the corresponding entry in the map indices is done.
+     ** \param[in] shortname - a short name of the counter for fast and easy access to its index
+     ** \param[in] name - name of the counter which is added to each counter object.
+     **/
+    indices[shortname] = names.size();
+    names.push_back(name);
+
+    ratio_reco.AddCounter();
+    mc.AddCounter();
+    reco.AddCounter();
+
+    ratio_ghost.AddCounter();
+    ratio_bg.AddCounter();
+    ratio_clone.AddCounter();
+    ghost.AddCounter();
+    bg.AddCounter();
+    clone.AddCounter();
+  };
+
+  /** \brief Operator to add efficiency table from object "a" to the current object. Returns the current object after addition. */
+  KFPVEfficiencies& operator+=(KFPVEfficiencies& a){
+    mc += a.mc; reco += a.reco;
+    ghost += a.ghost; bg += a.bg; clone += a.clone;
+    return *this;
+  };
+  
+  /** \brief Function to calculate efficiency after all counters are set. If the counters are modified the function should be called again. */
+  void CalcEff(){
+    ratio_reco = reco/mc;
+
+    KFMCCounter<int> allReco = reco + ghost + bg;
+    ratio_ghost = ghost/allReco;
+    ratio_bg  = bg/allReco;
+    ratio_clone  = clone/allReco;
+  };
+  
+
+  void Inc(bool isReco, int nClones, TString name)
+  {
+    /** Increases counters by one, if the corresponding boolean variable is "true".
+     ** MC counter is increased in any case.
+     ** \param[in] isReco - "true" if vertex is reconstructed
+     ** \param[in] nClones - number of double reconstructed vertices for the given MC vertex,
+     ** will be added to the "clone" counters
+     ** \param[in] name  - "shortname" of the set of counters, which should be increased
+     **/
+    const int index = indices[name];
+    
+    mc.counters[index]++;
+    if (isReco) reco.counters[index]++;
+    if(nClones > 0)
+      clone.counters[index] += nClones;
+  };
+
+  void IncReco(bool isGhost, bool isBg, TString name)
+  {
+    /** Increases counters by one, if the corresponding boolean variable is "true".
+     ** \param[in] isGhost - "true" if ghost is added
+     ** \param[in] isBg - "true" if physics background is added
+     ** \param[in] name  - "shortname" of the set of counters, which should be increased
+     **/
+    const int index = indices[name];
+
+    if (isGhost) ghost.counters[index]++;
+    if (isBg)    bg.counters[index]++;
+  };
+
+  /** \brief Prints the efficiency table on the screen. */
+  void PrintEff(){
+    std::ios_base::fmtflags original_flags = std::cout.flags();
+    std::cout.setf(std::ios::fixed);
+    std::cout.setf(std::ios::showpoint);
+    std::cout.precision(3);
+    std::cout << "              : "
+         << "   Eff "
+         <<" / "<< " Ghost "
+         <<" / "<< "BackGr "
+         <<" / "<< "Clone  "
+         <<" / "<< "N Ghost"
+         <<" / "<< "N BackGr"
+         <<" / "<< "N Reco "
+         <<" / "<< "N Clone "
+         <<" | "<< "  N MC "  << std::endl;
+    
+    int NCounters = mc.NCounters;
+    for (int iC = 0; iC < NCounters; iC++){
+        std::cout << names[iC]
+             << "  : " << std::setw(6) << ratio_reco.counters[iC]              
+             << "  / " << std::setw(6) << ratio_ghost.counters[iC]  // particles w\o MCParticle
+             << "  / " << std::setw(6) << ratio_bg.counters[iC]     // particles with incorrect MCParticle
+             << "  / " << std::setw(6) << ratio_clone.counters[iC]     // particles with incorrect MCParticle
+             << "  / " << std::setw(6) << ghost.counters[iC]
+             << "  / " << std::setw(7) << bg.counters[iC]
+             << "  / " << std::setw(6) << reco.counters[iC]
+             << "  / " << std::setw(7) << clone.counters[iC]
+             << "  | " << std::setw(6) << mc.counters[iC]  << std::endl;
+    }
+    std::cout.flags(original_flags); 
+  };
+  
+  /** \brief Operator to write efficiencies to file. */
+  friend std::fstream & operator<<(std::fstream &strm, KFPVEfficiencies &a) {
+
+    strm << a.ratio_reco;
+    strm << a.mc;
+    strm << a.reco;
+    strm << a.ratio_ghost;
+    strm << a.ratio_bg;
+    strm << a.ratio_clone;
+    strm << a.ghost;
+    strm << a.bg;
+    strm << a.clone;
+
+    return strm;
+  }
+  /** \brief Operator to read efficiencies from file. */
+  friend std::fstream & operator>>(std::fstream &strm, KFPVEfficiencies &a){
+
+    strm >> a.ratio_reco;
+    strm >> a.mc;
+    strm >> a.reco;
+    strm >> a.ratio_ghost;
+    strm >> a.ratio_bg;
+    strm >> a.ratio_clone;
+    strm >> a.ghost;
+    strm >> a.bg;
+    strm >> a.clone;
+
+    return strm;
+  }
+  /** \brief Adds efficiency from the file with the name defined by "fileName" to the current objects. */
+  void AddFromFile(TString fileName)
+  {
+    std::fstream file(fileName.Data(),std::fstream::in);
+    file >> *this;
+  }
+
+ private:
+  std::vector<TString> names;      ///< Names of the counters. The same for all counters objects.
+  std::map<TString, int> indices;  ///< Map between the counter index and its short name.
+
+  KFMCCounter<double> ratio_reco;  ///< Efficiency.
+
+  KFMCCounter<int> mc;             ///< Counters of the Monte Carlo vertices.
+  KFMCCounter<int> reco;           ///< Counters of the reconstructed vertices.
+
+  KFMCCounter<double> ratio_ghost; ///< Ratio of the ghost candidates to the total number of candidates.
+  KFMCCounter<double> ratio_bg;    ///< Ratio of the physics background candidates to the total number of candidates.
+  KFMCCounter<double> ratio_clone; ///< Ratio of double reconstructed vertices to the total number of signal candidates.
+
+  KFMCCounter<int> ghost;          ///< Counters of the ghost candidates.
+  KFMCCounter<int> bg;             ///< Counters of the physics background candidates.
+  KFMCCounter<int> clone;          ///< Counters of the double reconstructed vertices.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.cxx b/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4b86a8f6d2a72e04275a4dc8b37e695830298128
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.cxx
@@ -0,0 +1,16 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#include "KFPartEfficiencies.h"
+
+#ifndef KFParticleStandalone
+ClassImp(KFPartEfficiencies)
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.h b/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.h
new file mode 100644
index 0000000000000000000000000000000000000000..0cae660c3a79be623abc1279345a843dc2d571a1
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPartEfficiencies.h
@@ -0,0 +1,1327 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPartEfficiencies_H
+#define KFPartEfficiencies_H
+
+#include <map>
+#include <iomanip>
+#include "KFMCCounter.h"
+
+#ifdef HLTCA_STANDALONE
+#include "RootTypesDef.h"
+#else
+#include "TObject.h"
+#endif
+
+/** @class KFEfficiencyParticleInfo
+ ** @brief A helper class to define parameters of the decay list in KFPartEfficiencies.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **/
+
+class KFEfficiencyParticleInfo
+{
+ public:
+  KFEfficiencyParticleInfo():fName("null"),fTitle("null"),fPDG(0),fHistoMin(0.f),fHistoMax(0.f),fMass(0.f),fLifeTime(0.f),fCharge(0), fMassSigma(0.001) {};
+  /** \brief Constructor with all parameters set in. There is no other way to define the parameters other then use this constructor.*/
+  KFEfficiencyParticleInfo(std::string name, std::string title, int pdg, float histoMin, float histoMax, float mass, float lifeTime, int charge, float massSigma ):
+    fName(name), fTitle(title), fPDG(pdg), fHistoMin(histoMin), fHistoMax(histoMax), fMass(mass), fLifeTime(lifeTime), fCharge(charge), fMassSigma(massSigma) {};
+  ~KFEfficiencyParticleInfo() {};
+  
+  //accessors
+  std::string Name()      const { return fName; }      ///< Returns name of the decay in the file with histograms.
+  std::string Title()     const { return fTitle; }     ///< Returns name of the decay in the output table with efficiency.
+  int         PDG()       const { return fPDG; }       ///< Returns the assigned PDG code.
+  float       HistoMin()  const { return fHistoMin; }  ///< Returns lower boundary in the mass histogram for the current decay.
+  float       HistoMax()  const { return fHistoMax; }  ///< Returns upper boundary in the mass histogram for the current decay.
+  float       Mass()      const { return fMass; }      ///< Returns table mass of the particle.
+  float       LifeTime()  const { return fLifeTime; }  ///< Returns lifetime of the particle.
+  int         Charge()    const { return fCharge; }    ///< Returns charge of the particle in units of the elementary charge.
+  float       MassSigma() const { return fMassSigma; } ///< Returns expected width of the mass peak, used in the side bands method.
+  
+ private:
+  std::string fName;  ///< Name of the decay in the file with histograms.
+  std::string fTitle; ///< Name of the decay in the output table with efficiency.
+  int fPDG;           ///< PDG code assigned to the current decay in the scheme of KF Particle Finder.
+  float fHistoMin;    ///< Lower boundary in the mass histogram for the current decay.
+  float fHistoMax;    ///< Upper boundary in the mass histogram for the current decay.
+  float fMass;        ///< Table mass of the particle.
+  float fLifeTime;    ///< Lifetime of the particle in seconds.
+  int fCharge;        ///< Charge in units of the elementary charge.
+  float fMassSigma;   ///< Expected width of the decay, determines peak sigma for the side bands method.
+};
+
+/** @class KFPartEfficiencies
+ ** @brief Class to calculate efficiency of KF Particle Finder.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class has two main purposes:\n
+ ** 1) Defines the list of decays to be analysed: a unique code of the decay, its mass, lifetime,
+ ** a list of daughter particles, etc. See KFPartEfficiencies::KFPartEfficiencies() for more details.\n
+ ** 2) It calculates reconstruction efficiency of the decays from the KF Particle Finder scheme.\n
+ ** Definitions:\n
+ ** background - physics background, when daughter particle come from the real particle, but the pdg
+ ** hypothesis is incorrect, for example, Lambda->p pi will create a physics background for
+ ** K0s if the proton is misidentified;\n
+ ** ghost - combinatorial background, tracks do not form a real vertex;\n
+ ** clone - a particle is reconstructed several times, for example, particle track is split into 
+ ** to parts due to the multiple scattering.
+ **/
+
+class KFPartEfficiencies :public TObject
+{
+ public:
+
+  /** \brief The default constructor. Defines the list of decays to be analysed and their properties. Please, see the code for indexing scheme. */
+  KFPartEfficiencies():
+    partDaughterPdg(0),
+    names(),
+    indices(),
+    fPdgToIndex(),
+    ratio_reco1(),
+    ratio_reco2(),
+    ratio_reco3(),
+    mc1(),
+    mc2(),
+    mc3(),
+    reco(),
+    ratio_ghost(),
+    ratio_bg(),
+    ratio_clone(),
+    ghost(),
+    bg(),
+    clone()
+  {                                    
+    KFEfficiencyParticleInfo particleInfo[nParticles] = 
+    {
+      //                       name                title               PDG code   min   max    mass       lifetime    Q
+#ifdef CBM
+      KFEfficiencyParticleInfo("Ks",               "KShort        ",        310, 0.3f, 1.3f, 0.497614   , 8.954e-11,  0, 0.0045), //0
+#else
+      KFEfficiencyParticleInfo("Ks",               "KShort        ",        310, 0.3f, 1.3f, 0.497614   , 8.954e-11,  0, 0.0057), //0
+#endif
+      KFEfficiencyParticleInfo("Lambda",           "Lambda        ",       3122, 1.0f, 2.0f, 1.115683   , 2.632e-10,  0, 0.0020), //1
+      KFEfficiencyParticleInfo("Lambdab",          "Lambda b      ",      -3122, 1.0f, 2.0f, 1.115683   , 2.632e-10,  0, 0.0020), //2
+      KFEfficiencyParticleInfo("Xi-",              "Xi-           ",       3312, 1.0f, 3.0f, 1.32171    , 1.639e-10, -1, 0.0022), //3
+      KFEfficiencyParticleInfo("Xi+",              "Xi+           ",      -3312, 1.0f, 3.0f, 1.32171    , 1.639e-10,  1, 0.0022), //4
+      KFEfficiencyParticleInfo("Xi0",              "Xi0           ",       3322, 1.0f, 3.0f, 1.31486    , 2.9e-10,    0, 0.0030), //5
+      KFEfficiencyParticleInfo("Xi0b",             "Xi0 b         ",      -3322, 1.0f, 3.0f, 1.31486    , 2.9e-10,    0, 0.0030), //6
+      KFEfficiencyParticleInfo("Omega-",           "Omega-        ",       3334, 1.0f, 3.0f, 1.67245    , 0.821e-10, -1, 0.0022), //7
+      KFEfficiencyParticleInfo("Omega+",           "Omega+        ",      -3334, 1.0f, 3.0f, 1.67245    , 0.821e-10,  1, 0.0022), //8
+      KFEfficiencyParticleInfo("Sigma^0",          "Sigma0        ",       3212, 1.0f, 3.0f, 1.192642   , 7.4e-20,    0, 0.0030), //9
+      KFEfficiencyParticleInfo("Sigma^0b",         "Sigma0 b      ",      -3212, 1.0f, 3.0f, 1.192642   , 7.4e-20,    0, 0.0030), //10
+      KFEfficiencyParticleInfo("Sigma^+",          "Sigma+        ",       3222, 1.0f, 3.0f, 1.18937    , 0.8018e-10, 1, 0.0030), //11
+      KFEfficiencyParticleInfo("Sigma^-b",         "Sigma- b      ",      -3222, 1.0f, 3.0f, 1.18937    , 0.8018e-10,-1, 0.0030), //12
+      KFEfficiencyParticleInfo("K*0",              "K*0           ",        313, 0.6f, 2.6f, 0.8958     , 1.38e-23,   0, 0.0300), //13
+      KFEfficiencyParticleInfo("K*0b",             "K*0 b         ",       -313, 0.6f, 2.6f, 0.8958     , 1.38e-23,   0, 0.0300), //14
+      KFEfficiencyParticleInfo("K*+",              "K*+           ",        323, 0.6f, 2.6f, 0.89166    , 1.30e-23,   1, 0.0300), //15
+      KFEfficiencyParticleInfo("K*-",              "K*-           ",       -323, 0.6f, 2.6f, 0.89166    , 1.30e-23,  -1, 0.0300), //16
+      KFEfficiencyParticleInfo("K*0_K0,pi0",       "K*0_K0pi0     ",     100313, 0.6f, 2.6f, 0.8958     , 1.38e-23,   0, 0.0030), //17
+      KFEfficiencyParticleInfo("K*+_K+,pi0",       "K*+_K+pi0     ",     100323, 0.6f, 2.6f, 0.89166    , 1.30e-23,   1, 0.0030), //18
+      KFEfficiencyParticleInfo("K*-_K-,pi0",       "K*-_K-pi0     ",    -100323, 0.6f, 2.6f, 0.89166    , 1.30e-23,  -1, 0.0030), //19
+      KFEfficiencyParticleInfo("Sigma*+",          "Sigma*+       ",       3224, 1.0f, 3.0f, 1.3828     , 1.83e-23,   1, 0.0100), //20
+      KFEfficiencyParticleInfo("Sigma*-",          "Sigma*-       ",       3114, 1.0f, 3.0f, 1.3872     , 1.67e-23,  -1, 0.0100), //21
+      KFEfficiencyParticleInfo("Sigma*+b",         "Sigma*+ b     ",      -3114, 1.0f, 3.0f, 1.3828     , 1.83e-23,  -1, 0.0100), //22
+      KFEfficiencyParticleInfo("Sigma*-b",         "Sigma*- b     ",      -3224, 1.0f, 3.0f, 1.3872     , 1.67e-23,   1, 0.0100), //23
+      KFEfficiencyParticleInfo("Sigma*0",          "Sigma*0       ",       3214, 1.0f, 3.0f, 1.3837     , 1.83e-23,   0, 0.0030), //24
+      KFEfficiencyParticleInfo("Sigma*0b",         "Sigma*0 b     ",      -3214, 1.0f, 3.0f, 1.3837     , 1.83e-23,   0, 0.0030), //25
+      KFEfficiencyParticleInfo("Lambda*",          "Lambda*       ",       3124, 1.4f, 3.4f, 1.5195     , 4.22e-23,   0, 0.0100), //26
+      KFEfficiencyParticleInfo("Lambda*b",         "Lambda* b     ",      -3124, 1.4f, 3.4f, 1.5195     , 4.22e-23,   0, 0.0100), //27
+      KFEfficiencyParticleInfo("Xi*0",             "Xi*0          ",       3324, 1.4f, 3.4f, 1.53180    , 7.23e-23,   0, 0.0100), //28
+      KFEfficiencyParticleInfo("Xi*0b",            "Xi*0 b        ",      -3324, 1.4f, 3.4f, 1.53180    , 7.23e-23,   0, 0.0100), //29
+      KFEfficiencyParticleInfo("Xi*-_LK",          "Xi*-_lk       ",    1003314, 1.4f, 3.4f, 1.823      , 2.74e-23,  -1, 0.0030), //30
+      KFEfficiencyParticleInfo("Xi*+_LK",          "Xi*+_lk       ",   -1003314, 1.4f, 3.4f, 1.823      , 2.74e-23,   1, 0.0030), //31
+      KFEfficiencyParticleInfo("Xi*-_xi-,pi0",     "Xi*-_XiPi     ",       3314, 1.4f, 3.4f, 1.535      , 6.65e-23,  -1, 0.0030), //32
+      KFEfficiencyParticleInfo("Xi*+_xi+,pi0",     "Xi*+_XiPi     ",      -3314, 1.4f, 3.4f, 1.535      , 6.65e-23,   1, 0.0030), //33
+      KFEfficiencyParticleInfo("Omega*-",          "Omega*-       ",    1003334, 1.8f, 3.8f, 2.252      , 1.2e-23,   -1, 0.0030), //34
+      KFEfficiencyParticleInfo("Omega*+",          "Omega*+       ",   -1003334, 1.8f, 3.8f, 2.252      , 1.2e-23,    1, 0.0030), //35
+      KFEfficiencyParticleInfo("H0_LL",            "H0_LL         ",       3000, 1.5f, 3.5f, 2.21       , 1.32e-10,   0, 0.0030), //36
+      KFEfficiencyParticleInfo("phi_KK",           "phi_KK        ",        333, 0.8f, 2.8f, 1.019455   , 1.55e-22,   0, 0.0030), //37
+      KFEfficiencyParticleInfo("rho_pipi",         "rho_pipi      ",        113, 0.0f, 2.0f, 0.77526    , 4.45e-24,   0, 0.0030), //38
+      KFEfficiencyParticleInfo("rho_ee",           "rho_ee        ",     100113, 0.0f, 2.0f, 0.77526    , 4.45e-24,   0, 0.0030), //39
+      KFEfficiencyParticleInfo("rho_mm",           "rho_mm        ",     200113, 0.0f, 2.0f, 0.77526    , 4.45e-24,   0, 0.0030), //40
+      KFEfficiencyParticleInfo("gamma",            "gamma         ",         22, 0.0f, 3.0f, 0.         , 1.e20,      0, 0.0030), //41
+      KFEfficiencyParticleInfo("pi0",              "pi0           ",        111, 0.0f, 3.0f, 0.1349766  , 8.52e-17,   0, 0.0030), //42
+      KFEfficiencyParticleInfo("eta",              "eta           ",        221, 0.0f, 3.0f, 0.547862   , 5.0e-19,    0, 0.0030), //43
+//Delta and N resonances
+      KFEfficiencyParticleInfo("Delta0",           "Delta0        ",       2114, 1.0f, 3.0f, 1.232      , 5.63e-24,   0, 0.0030), //44
+      KFEfficiencyParticleInfo("Delta0 b",         "Delta0 b      ",      -2114, 1.0f, 3.0f, 1.232      , 5.63e-24,   0, 0.0030), //45
+      KFEfficiencyParticleInfo("Delta++",          "Delta++       ",       2224, 1.0f, 3.0f, 1.232      , 5.63e-24,   2, 0.0030), //46
+      KFEfficiencyParticleInfo("Delta-- b",        "Delta-- b     ",      -2224, 1.0f, 3.0f, 1.232      , 5.63e-24,  -2, 0.0030), //47
+//charmonium
+      KFEfficiencyParticleInfo("JPsi_ee",          "JPsi_ee       ",        443, 1.0f, 4.0f, 3.096916   , 7.1e-21,    0, 0.0030), //48
+      KFEfficiencyParticleInfo("JPsi_mumu",        "JPsi_mm       ",     100443, 1.0f, 4.0f, 3.096916   , 7.1e-21,    0, 0.0030), //49
+      KFEfficiencyParticleInfo("JPsi_pp",          "JPsi_pp       ",     200443, 1.0f, 4.0f, 3.096916   , 7.1e-21,    0, 0.0030), //50
+      KFEfficiencyParticleInfo("JPsi_LL",          "JPsi_LL       ",     300443, 2.0f, 5.0f, 3.096916   , 7.1e-21,    0, 0.0030), //51
+      KFEfficiencyParticleInfo("JPsi_XiXi",        "JPsi_XiXi     ",     400443, 2.0f, 5.0f, 3.096916   , 7.1e-21,    0, 0.0030), //52
+      KFEfficiencyParticleInfo("Psi_OO",           "Psi_OO        ",     500443, 3.0f, 6.0f, 3.686109   , 2.1e-22,    0, 0.0030), //53
+//open charm
+      KFEfficiencyParticleInfo("D0",               "D0            ",        421, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0154), //54
+      KFEfficiencyParticleInfo("D0b",              "D0b           ",       -421, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0154), //55
+      KFEfficiencyParticleInfo("D0_4",             "D0_4          ",        429, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0100), //56
+      KFEfficiencyParticleInfo("D0b_4",            "D0b_4         ",       -429, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0100), //57
+      KFEfficiencyParticleInfo("D0_pipi",          "D0_pipi       ",        420, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0154), //58
+      KFEfficiencyParticleInfo("D0_2pi2pi",        "D0_2pi2pi     ",        470, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0154), //59
+      KFEfficiencyParticleInfo("D0_K0pipi",        "D0_K0pipi     ",        425, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0150), //60
+      KFEfficiencyParticleInfo("D0_KK",            "D0_KK         ",        426, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0130), //61
+      KFEfficiencyParticleInfo("D0_KKK0",          "D0_KKK0       ",        427, 0.6f, 3.6f, 1.86486    , 4.1e-13,    0, 0.0154), //62
+      KFEfficiencyParticleInfo("D0_pi0",           "D0_#pi0       ",        428, 1.0f, 3.0f, 1.86486    , 4.1e-13,    0, 0.0030), //63
+      KFEfficiencyParticleInfo("D+",               "D+            ",        411, 1.0f, 3.0f, 1.86962    , 1.04e-13,   1, 0.0114), //64
+      KFEfficiencyParticleInfo("D-",               "D-            ",       -411, 1.0f, 3.0f, 1.86962    , 1.04e-13,  -1, 0.0114), //65
+      KFEfficiencyParticleInfo("D+_K0pi+",         "D+_K0pi+      ",     100411, 0.6f, 4.6f, 1.86962    , 1.04e-13,   1, 0.0030), //66
+      KFEfficiencyParticleInfo("D-_K0pi-",         "D-_K0pi-      ",    -100411, 0.6f, 4.6f, 1.86962    , 1.04e-13,  -1, 0.0030), //67
+      KFEfficiencyParticleInfo("D+_K03pi",         "D+_K03pi      ",     200411, 0.6f, 4.6f, 1.86962    , 1.04e-13,   1, 0.0030), //68
+      KFEfficiencyParticleInfo("D-_K03pi",         "D-_K03pi      ",    -200411, 0.6f, 4.6f, 1.86962    , 1.04e-13,  -1, 0.0030), //69
+      KFEfficiencyParticleInfo("D+_3pi",           "D+_3pi        ",     300411, 0.6f, 4.6f, 1.86962    , 1.04e-13,   1, 0.0030), //70
+      KFEfficiencyParticleInfo("D-_3pi",           "D-_3pi        ",    -300411, 0.6f, 4.6f, 1.86962    , 1.04e-13,  -1, 0.0030), //71
+      KFEfficiencyParticleInfo("Ds+",              "Ds+           ",        431, 1.0f, 3.0f, 1.96850    , 5.0e-13,    1, 0.0110), //72
+      KFEfficiencyParticleInfo("Ds-",              "Ds-           ",       -431, 1.0f, 3.0f, 1.96850    , 5.0e-13,   -1, 0.0110), //73
+      KFEfficiencyParticleInfo("Ds+_K0K+",         "Ds+_K0K+      ",     100431, 1.0f, 3.0f, 1.96850    , 5.0e-13,    1, 0.0030), //74
+      KFEfficiencyParticleInfo("Ds-_K0K-",         "Ds-_K0K-      ",    -100431, 1.0f, 3.0f, 1.96850    , 5.0e-13,   -1, 0.0030), //75
+      KFEfficiencyParticleInfo("Ds+_K0K0pi+",      "Ds+_K0K0pi+   ",     200431, 1.0f, 3.0f, 1.96850    , 5.0e-13,    1, 0.0030), //76
+      KFEfficiencyParticleInfo("Ds-_K0K0pi-",      "Ds-_K0K0pi-   ",    -200431, 1.0f, 3.0f, 1.96850    , 5.0e-13,   -1, 0.0030), //77
+      KFEfficiencyParticleInfo("Ds+_K0K+pipi",     "Ds+_K0K+pipi  ",     300431, 1.0f, 3.0f, 1.96850    , 5.0e-13,    1, 0.0030), //78
+      KFEfficiencyParticleInfo("Ds-_K0K-pipi",     "Ds-_K0K-pipi  ",    -300431, 1.0f, 3.0f, 1.96850    , 5.0e-13,   -1, 0.0030), //79
+      KFEfficiencyParticleInfo("Ds+_K+pipi",       "Ds+_K+pipi    ",     400431, 1.0f, 3.0f, 1.96850    , 5.0e-13,    1, 0.0030), //80
+      KFEfficiencyParticleInfo("Ds-_K-pipi",       "Ds-_K-pipi    ",    -400431, 1.0f, 3.0f, 1.96850    , 5.0e-13,   -1, 0.0030), //81
+      KFEfficiencyParticleInfo("Lc",               "Lambdac       ",       4122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0110), //82
+      KFEfficiencyParticleInfo("Lcb",              "Lambdac b     ",      -4122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0110), //83
+      KFEfficiencyParticleInfo("Lc_{pK0}",         "Lc   {pK0}    ",     104122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0030), //84
+      KFEfficiencyParticleInfo("Lcb_{pK0}",        "Lc b {pK0}    ",    -104122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0030), //85
+      KFEfficiencyParticleInfo("Lc_{pK02pi}",      "Lc   {pK02pi} ",     204122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0030), //86
+      KFEfficiencyParticleInfo("Lcb_{pK02pi}",     "Lc b {pK02pi} ",    -204122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0030), //87
+      KFEfficiencyParticleInfo("Lc_{Lpi}",         "Lc   {Lpi}    ",     304122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0030), //88
+      KFEfficiencyParticleInfo("Lcb_{Lpi}",        "Lc b {Lpi}    ",    -304122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0030), //89
+      KFEfficiencyParticleInfo("Lc_{L3pi}",        "Lc   {L3pi}   ",     404122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0030), //90
+      KFEfficiencyParticleInfo("Lcb_{L3pi}",       "Lc b {L3pi}   ",    -404122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0030), //91
+      KFEfficiencyParticleInfo("Lc_{p2pi}",        "Lc   {p2pi}   ",     504122, 1.8f, 3.8f, 2.28646    , 2.0e-13,    1, 0.0030), //92
+      KFEfficiencyParticleInfo("Lcb_{p2pi}",       "Lc b {p2pi}   ",    -504122, 1.8f, 3.8f, 2.28646    , 2.0e-13,   -1, 0.0030), //93  
+      KFEfficiencyParticleInfo("Xic0",             "Xic0          ",       4132, 2.1f, 4.1f, 2.47087    , 1.0e-13,    0, 0.0030), //94
+      KFEfficiencyParticleInfo("Xic0b",            "Xic0b         ",      -4132, 2.1f, 4.1f, 2.47087    , 1.0e-13,    0, 0.0030), //95  
+      KFEfficiencyParticleInfo("D*0",              "D*0           ",      10421, 1.8f, 3.8f, 2.00699    , 3.0e-22,    0, 0.0030), //96
+      KFEfficiencyParticleInfo("D*0b",             "D*0 b         ",     -10421, 1.8f, 3.8f, 2.00699    , 3.0e-22,    0, 0.0030), //97
+      KFEfficiencyParticleInfo("D*+",              "D*+           ",      10411, 1.8f, 3.8f, 2.01029    , 6.86e-21,   1, 0.0030), //98
+      KFEfficiencyParticleInfo("D*-",              "D*-           ",     -10411, 1.8f, 3.8f, 2.01029    , 6.86e-21,  -1, 0.0030), //99
+      KFEfficiencyParticleInfo("D*+_4",            "D*+_4         ",      20411, 1.8f, 3.8f, 2.01029    , 6.86e-21,   1, 0.0030), //100
+      KFEfficiencyParticleInfo("D*-_4",            "D*-_4         ",     -20411, 1.8f, 3.8f, 2.01029    , 6.86e-21,  -1, 0.0030), //101
+      KFEfficiencyParticleInfo("D0*_pi0",          "D0*_#pi0      ",      10428, 1.8f, 3.8f, 2.00699    , 6.86e-21,   0, 0.0030), //102
+//B mesons
+      KFEfficiencyParticleInfo("B_Jpsi_ee",        "B_Jpsi_ee     ",        500, 1.0f, 4.0f, 3.096916   , 7.1e-21,    0, 0.0030), //103
+      KFEfficiencyParticleInfo("B_Jpsi_mm",        "B_Jpsi_mm     ",        501, 1.0f, 4.0f, 3.096916   , 7.1e-21,    0, 0.0030), //104
+      KFEfficiencyParticleInfo("B+_D0bPi+",        "B+ {D0bPi+}   ",        521, 3.0f, 7.0f, 5.27931    , 1.638e-12,  0, 0.0030), //105
+      KFEfficiencyParticleInfo("B-_D0Pi-",         "B- {D0Pi-}    ",       -521, 3.0f, 7.0f, 5.27931    , 1.638e-12,  0, 0.0030), //106
+      KFEfficiencyParticleInfo("B+_D0bK+",         "B+ {D0bK+}    ",        529, 3.0f, 7.0f, 5.27931    , 1.638e-12,  0, 0.0030), //107
+      KFEfficiencyParticleInfo("B-_D0K-",          "B- {D0K+}     ",       -529, 3.0f, 7.0f, 5.27931    , 1.638e-12,  0, 0.0030), //108
+      KFEfficiencyParticleInfo("B0_D-Pi+",         "B0 {D-Pi+}    ",        511, 3.0f, 7.0f, 5.27962    , 1.520e-12,  0, 0.0030), //109
+      KFEfficiencyParticleInfo("B0b_D+Pi-",        "B0b {D+Pi-}   ",       -511, 3.0f, 7.0f, 5.27962    , 1.520e-12,  0, 0.0030), //110
+      KFEfficiencyParticleInfo("B0_D-K+",          "B0 {D-K+}     ",        519, 3.0f, 7.0f, 5.27962    , 1.520e-12,  0, 0.0030), //111
+      KFEfficiencyParticleInfo("B0b_D+K-",         "B0b {D+K-}    ",       -519, 3.0f, 7.0f, 5.27962    , 1.520e-12,  0, 0.0030), //112
+      KFEfficiencyParticleInfo("H0_{Lppi}",        "H0            ",       3001, 2.0f, 4.0f, 2.21       , 1.32e-10,   0, 0.0030), //113
+//hypernuclei
+      KFEfficiencyParticleInfo("LambdaN",          "LambdaN       ",       3003, 1.0f, 3.0f, 2.05395    , 1.00e-10,   0, 0.0030), //114
+      KFEfficiencyParticleInfo("LambdaNb",         "LambdaN b     ",      -3003, 1.0f, 3.0f, 2.05395    , 1.00e-10,   0, 0.0030), //115
+      KFEfficiencyParticleInfo("LambdaNN",         "LambdaNN      ",       3103, 2.0f, 4.0f, 2.99352    , 1.00e-10,   0, 0.0030), //116
+      KFEfficiencyParticleInfo("LambdaNNb",        "LambdaNN b    ",      -3103, 2.0f, 4.0f, 2.99352    , 1.00e-10,   0, 0.0030), //117
+      KFEfficiencyParticleInfo("H3L",              "H3L           ",       3004, 2.0f, 4.0f, 2.99339    , 1.85e-10,   1, 0.0030), //118
+      KFEfficiencyParticleInfo("H3Lb",             "H3L b         ",      -3004, 2.0f, 4.0f, 2.99339    , 1.85e-10,  -1, 0.0030), //119
+      KFEfficiencyParticleInfo("H4L",              "H4L           ",       3005, 3.0f, 5.0f, 3.92975    , 1.80e-10,   1, 0.0030), //120
+      KFEfficiencyParticleInfo("H4Lb",             "H4L b         ",      -3005, 3.0f, 5.0f, 3.92975    , 1.80e-10,  -1, 0.0030), //121
+      KFEfficiencyParticleInfo("He4L",             "He4L          ",       3006, 3.0f, 5.0f, 3.93070    , 1.50e-10,   2, 0.0030), //122
+      KFEfficiencyParticleInfo("He4Lb",            "He4L b        ",      -3006, 3.0f, 5.0f, 3.93070    , 1.50e-10,  -2, 0.0030), //123
+      KFEfficiencyParticleInfo("He5L",             "He5L          ",       3007, 4.0f, 6.0f, 4.86824    , 1.40e-10,   2, 0.0030), //124
+      KFEfficiencyParticleInfo("He5Lb",            "He5L b        ",      -3007, 4.0f, 6.0f, 4.86824    , 1.40e-10,  -2, 0.0030), //125
+      KFEfficiencyParticleInfo("LLn",              "LLn           ",       3203, 3.0f, 5.0f, 3.16964    , 1.00e-10,   0, 0.0030), //126
+      KFEfficiencyParticleInfo("H4LL_{He4Lpi-}",   "H4LL_{He4Lpi-}",       3008, 3.0f, 5.0f, 4.10791    ,  1.0e-10,   1, 0.0030), //127
+      KFEfficiencyParticleInfo("H4LL_{H3Lppi-}",   "H4LL_{H3Lppi-}",       3009, 3.0f, 5.0f, 4.10791    ,  1.0e-10,   1, 0.0030), //128
+      KFEfficiencyParticleInfo("H5LL_{He5Lpi-}",   "H5LL_{He5Lpi-}",       3010, 4.0f, 6.0f, 5.04748    ,  1.0e-10,   1, 0.0030), //129
+      KFEfficiencyParticleInfo("He6LL",            "He6LL         ",       3011, 5.0f, 7.0f, 5.98575    ,  1.0e-10,   2, 0.0030), //130
+//missing mass method      
+      KFEfficiencyParticleInfo("pi-_{mu,nu}",      "pi-_{mnu}     ",   -7000211,-1.0f, 1.0f, 0.139570   , 2.6e-8,    -1, 0.0030), //131
+      KFEfficiencyParticleInfo("nu_{pi-}",         "nu_{mupi-} b  ",   -7000014,-1.0f, 1.0f, 0.         , 1.0e20,     0, 0.0030), //132
+      KFEfficiencyParticleInfo("pi+_{mu,nu}",      "pi+_{mnu}     ",    7000211,-1.0f, 1.0f, 0.139570   , 2.6e-8,     1, 0.0030), //133
+      KFEfficiencyParticleInfo("nu_{pi+}",         "nu_{mupi+}    ",    7000014,-1.0f, 1.0f, 0.         , 1.0e20,     0, 0.0030), //134
+      KFEfficiencyParticleInfo("K-_{mu,nu}",       "K-_{mnu}      ",   -7000321,-1.0f, 1.0f, 0.493677   , 1.238e-8,  -1, 0.0030), //135
+      KFEfficiencyParticleInfo("nu_{K-}",          "nu_{K-} b     ",   -8000014,-1.0f, 1.0f, 0.         , 1.0e20,     0, 0.0030), //136
+      KFEfficiencyParticleInfo("K+_{mu,nu}",       "K+_{mnu}      ",    7000321,-1.0f, 1.0f, 0.493677   , 1.238e-8,   1, 0.0030), //137
+      KFEfficiencyParticleInfo("nu_{K+}",          "nu_{K+}       ",    8000014,-1.0f, 1.0f, 0.         , 1.0e20,     0, 0.0030), //138
+      KFEfficiencyParticleInfo("Sigma-_{pi-,n}",   "Sigma-_{pi-n} ",    7003112, 0.0f, 3.0f, 1.192642   , 1.479e-10, -1, 0.0100), //139
+      KFEfficiencyParticleInfo("n_{Sigma-}",       "n_{Sigma-}    ",    7002112, 0.0f, 1.5f, 0.9395654  , 880,        0, 0.0030), //140
+      KFEfficiencyParticleInfo("Sigma+_{pi+n}b",   "Sigma+{pi+n} b",   -7003112, 0.0f, 3.0f, 1.192642   , 1.479e-10, -1, 0.0030), //141
+      KFEfficiencyParticleInfo("n_{Sigma+} b",     "n_{Sigma+b} b ",   -7002112, 0.0f, 1.5f, 0.9395654  , 880,        0, 0.0030), //142
+      KFEfficiencyParticleInfo("Sigma-_{pi-n}b",   "Sigma+{pi-n} b",   -7003222, 0.0f, 3.0f, 1.18937    , 0.8018e-10, 1, 0.0030), //143
+      KFEfficiencyParticleInfo("n_{Sigma-} b",     "n_{Sigma-_b} b",   -8002112, 0.0f, 1.5f, 0.9395654  , 0.93956541, 0, 0.0030), //144
+      KFEfficiencyParticleInfo("Sigma+_{pi+n}",    "Sigma+_{pi+n} ",    7003222, 0.0f, 3.0f, 1.18937    , 0.8018e-10, 1, 0.0100), //145
+      KFEfficiencyParticleInfo("n_{Sigma+}",       "n_{Sigma+}    ",    8002112, 0.0f, 1.5f, 0.9395654  , 880,        0, 0.0030), //146
+      KFEfficiencyParticleInfo("Xi-_{pi-L}",       "Xi-_{pi-L}    ",    7003312, 0.0f, 3.0f, 1.32171    , 1.639e-10, -1, 0.0030), //147
+      KFEfficiencyParticleInfo("Lambda_{Xi-}",     "Lambda_{Xi-}  ",    7003122, 0.0f, 2.0f, 1.115683   , 2.632e-10,  0, 0.0030), //148
+      KFEfficiencyParticleInfo("Xi+_{pi+L_b}",     "Xi+_{pi+L_b}  ",   -7003312, 0.0f, 3.0f, 1.32171    , 1.639e-10,  1, 0.0030), //149
+      KFEfficiencyParticleInfo("Lambda_{Xi+} b",   "Lambda_{Xi+} b",   -7003122, 0.0f, 2.0f, 1.115683   , 2.632e-10,  0, 0.0030), //150
+      KFEfficiencyParticleInfo("Omega-_{Xi-pi0}",  "Omega-{pi-Xi0}",    7003334, 0.0f, 3.0f, 1.67245    , 0.821e-10, -1, 0.0030), //151
+      KFEfficiencyParticleInfo("Xi0_{Omega-}",     "Xi0_{Omega-}  ",    7003322, 0.0f, 3.0f, 1.31486    , 2.9e-10,    0, 0.0030), //152
+      KFEfficiencyParticleInfo("Omega+_{Xi+pi0}",  "Omega+_{Xipi0}",   -7003334, 0.0f, 3.0f, 1.67245    , 0.821e-10,  1, 0.0030), //153
+      KFEfficiencyParticleInfo("Xi0_{Omega+} b",   "Xi0_{Omega+} b",   -7003322, 0.0f, 3.0f, 1.31486    , 2.9e-10,    0, 0.0030), //154
+      KFEfficiencyParticleInfo("K-_{pi-pi0}",      "K-_{pi-pi0}   ",   -9000321, 0.0f, 3.0f, 0.493677   , 1.24e-8,   -1, 0.0030), //155
+      KFEfficiencyParticleInfo("pi0_{K-}",         "pi0_{K-}      ",   -9000111, 0.0f, 3.0f, 0.1349766  , 8.52e-17,   0, 0.0030), //156
+      KFEfficiencyParticleInfo("K+_{pi+pi0}",      "K+_{pi+pi0}   ",    9000321, 0.0f, 3.0f, 0.493677   , 1.24e-8,    1, 0.0030), //157
+      KFEfficiencyParticleInfo("pi0_{K+}",         "pi0_{K+}      ",    9000111, 0.0f, 3.0f, 0.1349766  , 8.52e-17,   0, 0.0030), //158
+      KFEfficiencyParticleInfo("Omega-{K-L}",      "Omega-_{K-L}  ",    8003334, 0.0f, 3.0f, 1.67245    , 0.821e-10, -1, 0.0030), //159
+      KFEfficiencyParticleInfo("Lambda_{Omega-}",  "Lambda_{O-}   ",    8003122, 0.0f, 3.0f, 1.115683   , 2.632e-10,  0, 0.0030), //160
+      KFEfficiencyParticleInfo("Omega+_{K+L_b}",   "Omega+_{K+Lb} ",   -8003334, 0.0f, 3.0f, 1.67245    , 0.821e-10,  1, 0.0030), //161
+      KFEfficiencyParticleInfo("Lamda_{Omega+} b", "Lambda_{O+} b ",   -8003122, 0.0f, 3.0f, 1.115683   , 2.632e-10,  0, 0.0030), //162
+      KFEfficiencyParticleInfo("Sigma-{p_b pi0} b","Sigma-{ppi0} b",   -8003222, 0.0f, 3.0f, 1.18937    , 0.8018e-10, 1, 0.0030), //163
+      KFEfficiencyParticleInfo("pi0_{Sigma-b}",    "pi0_{Sigma-_b}",   -8000111, 0.0f, 3.0f, 0.1349766  , 8.52e-17,   0, 0.0030), //164
+      KFEfficiencyParticleInfo("Sigma+_{p pi0}",   "Sigma+_{ppi0} ",    8003222, 0.0f, 3.0f, 1.18937    , 0.8018e-10, 1, 0.0250), //165
+      KFEfficiencyParticleInfo("pi0_{Sigma+}",     "pi0_{Sigma+}  ",    8000111, 0.0f, 3.0f, 0.1349766  , 8.52e-17,   0, 0.0030), //166
+//tracks
+      KFEfficiencyParticleInfo("e-",               "e-            ",         11, 0.0f,0.01f, 5.485799e-4, 1.0e20,    -1, 0.0030), //167
+      KFEfficiencyParticleInfo("e+",               "e+            ",        -11, 0.0f,0.01f, 5.485799e-4, 1.0e20,     1, 0.0030), //168
+      KFEfficiencyParticleInfo("mu-",              "mu-           ",         13, 0.0f, 1.0f, 0.105658   , 2.2e-6,    -1, 0.0030), //169
+      KFEfficiencyParticleInfo("mu+",              "mu+           ",        -13, 0.0f, 1.0f, 0.105658   , 2.2e-6,     1, 0.0030), //170
+      KFEfficiencyParticleInfo("pi+",              "pi+           ",        211, 0.0f, 1.0f, 0.139570   , 2.6e-8,     1, 0.0030), //171
+      KFEfficiencyParticleInfo("pi-",              "pi-           ",       -211, 0.0f, 1.0f, 0.139570   , 2.6e-8,    -1, 0.0030), //172
+      KFEfficiencyParticleInfo("K+",               "K+            ",        321, 0.0f, 1.0f, 0.493677   , 1.238e-8,   1, 0.0030), //173
+      KFEfficiencyParticleInfo("K-",               "K-            ",       -321, 0.0f, 1.0f, 0.493677   , 1.238e-8,  -1, 0.0030), //174
+      KFEfficiencyParticleInfo("p+",               "p+            ",       2212, 0.0f, 1.5f, 0.938272   , 1.0e20,     1, 0.0030), //175
+      KFEfficiencyParticleInfo("p-",               "p-            ",      -2212, 0.0f, 1.5f, 0.938272   , 1.0e20,    -1, 0.0030), //176
+      KFEfficiencyParticleInfo("d+",               "d+            ", 1000010020, 0.0f, 2.5f, 1.876124   , 1.0e20,     1, 0.0030), //177
+      KFEfficiencyParticleInfo("d-",               "d-            ",-1000010020, 0.0f, 2.5f, 1.876124   , 1.0e20,    -1, 0.0030), //178
+      KFEfficiencyParticleInfo("t+",               "t+            ", 1000010030, 0.0f, 3.5f, 2.809432   , 1.0e20,     1, 0.0030), //179
+      KFEfficiencyParticleInfo("t-",               "t-            ",-1000010030, 0.0f, 3.5f, 2.809432   , 1.0e20,    -1, 0.0030), //180
+      KFEfficiencyParticleInfo("He3+",             "He3+          ", 1000020030, 0.0f, 3.5f, 2.809413   , 1.0e20,     2, 0.0030), //181
+      KFEfficiencyParticleInfo("He3-",             "He3-          ",-1000020030, 0.0f, 3.5f, 2.809413   , 1.0e20,    -2, 0.0030), //182
+      KFEfficiencyParticleInfo("He4+",             "He4+          ", 1000020040, 0.0f, 4.5f, 3.728400   , 1.0e20,     2, 0.0030), //183
+      KFEfficiencyParticleInfo("He4-",             "He4-          ",-1000020040, 0.0f, 4.5f, 3.728400   , 1.0e20,    -2, 0.0030), //184
+//background for subtraction
+      KFEfficiencyParticleInfo("pi+pi+",           "pi+pi+        ",       9001, 0.0f, 2.0f, 0          , 1.0e20,     0, 0.0030), //185
+      KFEfficiencyParticleInfo("pi+K+",            "pi+K+         ",       9002, 0.6f, 5.6f, 0          , 1.0e20,     0, 0.0030), //186
+      KFEfficiencyParticleInfo("K+K+",             "K+K+          ",       9003, 0.8f, 3.8f, 0          , 1.0e20,     0, 0.0030), //187
+      KFEfficiencyParticleInfo("K+p+",             "K+p+          ",       9004, 1.4f, 5.4f, 0          , 1.0e20,     0, 0.0030), //188
+      KFEfficiencyParticleInfo("pi-pi-",           "pi-pi-        ",      -9001, 0.0f, 2.0f, 0          , 1.0e20,     0, 0.0030), //189
+      KFEfficiencyParticleInfo("pi-K-",            "pi-K-         ",      -9002, 0.6f, 5.6f, 0          , 1.0e20,     0, 0.0030), //190
+      KFEfficiencyParticleInfo("K-K-",             "K-K-          ",      -9003, 0.8f, 3.8f, 0          , 1.0e20,     0, 0.0030), //191
+      KFEfficiencyParticleInfo("K-p-",             "K-p-          ",      -9004, 1.4f, 5.4f, 0          , 1.0e20,     0, 0.0030), //192
+//V0
+      KFEfficiencyParticleInfo("V0",               "V0            ",  123456789, 0.3f, 1.3f, 0          , 0,          0, 0.0030)  //193
+    };
+                                        
+    int mPartMaxMult[nParticles];
+    for(int i=0; i<nParticles; i++)
+      mPartMaxMult[i] = 20;
+    mPartMaxMult[fFirstStableParticleIndex + 4] = 500;
+    mPartMaxMult[fFirstStableParticleIndex + 5] = 500;
+    mPartMaxMult[fFirstStableParticleIndex + 6] = 50;
+    mPartMaxMult[fFirstStableParticleIndex + 7] = 50;
+    mPartMaxMult[fFirstStableParticleIndex + 8] = 500;
+                                    
+    //set decay mode
+    partDaughterPdg.resize(nParticles);
+
+    int curPart = 0;
+    
+    partDaughterPdg[curPart].push_back(  211); //K0s -> pi+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Lambda -> p pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-2212); //Lambda_bar -> p- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Xi- -> Lambda pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Xi+ -> Lambda_bar pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Xi0 -> Lambda Pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Xi0_bar -> Lambda_bar Pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Omega- -> Lambda K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Omega+ -> Lambda_bar K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   22); //Sigma0 -> Lambda Gamma
+    partDaughterPdg[curPart].push_back( 3122);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   22); //Sigma0_bar -> Lambda_bar Gamma
+    partDaughterPdg[curPart].push_back(-3122);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  111); //Sigma+ -> p Pi0
+    partDaughterPdg[curPart].push_back( 2212);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  111); //Sigma+_bar -> p- Pi0
+    partDaughterPdg[curPart].push_back(-2212);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //K*0 -> K+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -321); //K*0_bar -> K- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //K*+ -> K0s pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //K*- -> K0s pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //K*0 -> K0 pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  111); //K*+ -> K+ pi0
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  111); //K*- -> K- pi0
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Sigma+ -> Lambda pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Sigma- -> Lambda pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Sigma+_bar -> Lambda_bar pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Sigma-_bar -> Lambda_bar pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Sigma*0 -> Lambda pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Sigma*0_bar -> Lambda_bar pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Lambda* -> p K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-2212); //Lambda*_bar -> p- K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3312); //Xi*0 -> Xi- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3312); //Xi*0_bar -> Xi+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Xi*- -> Lambda K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3122); //Xi*+ -> Lambda_bar K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3312); //Xi*- -> Xi- pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3312); //Xi*+ -> Xi+ pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3312); //Omega*- -> Xi- pi+ K-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3312); //Omega*- -> Xi+ pi- K+
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //H-dibar -> Lambda Lambda
+    partDaughterPdg[curPart].push_back( 3122);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //phi -> K+ K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  211); //rho, omega, phi -> pi+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   11); //rho, omega, phi -> e+ e-
+    partDaughterPdg[curPart].push_back(  -11);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   13); //rho, omega, phi -> mu+ mu-
+    partDaughterPdg[curPart].push_back(  -13);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   11); //gamma -> e+ e-
+    partDaughterPdg[curPart].push_back(  -11);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   22); //pi0 -> gamma gamma
+    partDaughterPdg[curPart].push_back(   22);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  111); //eta -> pi0 pi0
+    partDaughterPdg[curPart].push_back(  111);
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Delta0 -> p pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-2212); //Delta0_bar -> p- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 2212); //Delta++ -> p pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-2212); //Delta--_bar -> p- pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   11); //JPsi -> e+ e-
+    partDaughterPdg[curPart].push_back(  -11);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   13); //JPsi -> mu+ mu-
+    partDaughterPdg[curPart].push_back(  -13);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(   2212); //JPsi -> p p-
+    partDaughterPdg[curPart].push_back(  -2212);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(   3122); //JPsi -> Lambda Lambda_bar
+    partDaughterPdg[curPart].push_back(  -3122);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(   3312); //JPsi -> Xi- Xi+
+    partDaughterPdg[curPart].push_back(  -3312);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(   3334); //Psi -> Omega- Omega+
+    partDaughterPdg[curPart].push_back(  -3334);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  211); //D0 -> pi+ K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -211); //D0_bar -> K+ pi-
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  211); //D0 -> pi+ pi+ pi- K-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -211); //D0_bar -> pi- pi- pi+ K+
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  211); //D0 -> pi+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  211); //D0 -> 2pi+ 2pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D0_bar -> K0 pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //D0_bar -> K+ K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  321); //D0_bar -> K+ K- K0
+    partDaughterPdg[curPart].push_back( -321);
+    partDaughterPdg[curPart].push_back(  310);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D0_bar -> K0 pi+ pi- pi0
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -321); //D+ -> K- pi+ pi+
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //D- -> K+ pi- pi-
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D+ -> K0 pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D- -> K0 pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D+ -> K0 pi+ pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //D- -> K0 pi+ pi- pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  211); //D+ -> pi+ pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  211); //D- -> pi+ pi- pi-
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -321); //Ds+ -> K- K+ pi+
+    partDaughterPdg[curPart].push_back(  321);
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //Ds- -> K+ K- pi-
+    partDaughterPdg[curPart].push_back( -321);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //Ds+ -> K0 K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //Ds- -> K0 K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //Ds+ -> K0 K0 pi+
+    partDaughterPdg[curPart].push_back(  310);
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  310); //Ds- -> K0 K0 pi-
+    partDaughterPdg[curPart].push_back(  310);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  310); //Ds+ -> K0 K+ pi+ pi-
+    partDaughterPdg[curPart].push_back(  321);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  310); //Ds- -> K0 K- pi+ pi-
+    partDaughterPdg[curPart].push_back( -321);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  321); //Ds+ -> K+ pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( -321); //Ds- -> K- pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    
+    partDaughterPdg[curPart].push_back(  211); //Lambdac -> pi+ K- p
+    partDaughterPdg[curPart].push_back( -321);
+    partDaughterPdg[curPart].push_back( 2212);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -211); //Lambdac_bar -> pi- K+ p-
+    partDaughterPdg[curPart].push_back(  321);
+    partDaughterPdg[curPart].push_back(-2212);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Lambdac -> p K0s
+    partDaughterPdg[curPart].push_back(  310);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-2212); //Lambdac_bar -> p_bar K0s
+    partDaughterPdg[curPart].push_back(  310);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Lambdac -> p K0s pi+ pi-
+    partDaughterPdg[curPart].push_back(  310);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-2212); //Lambdac_bar -> p_bar K0s pi+ pi-
+    partDaughterPdg[curPart].push_back(  310);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Lambdac -> Lambda pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-3122); //Lambdac_bar -> Lambda_bar pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3122); //Lambdac -> Lambda 2pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-3122); //Lambdac_bar -> Lambda_bar 2pi- pi+
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;  
+    
+    partDaughterPdg[curPart].push_back( 3312); //Xic0 -> Xi- 2pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(-3312); //Xic0_bar -> Xi+ 2pi- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 2212); //Lambdac -> p pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-2212); //Lambdac_bar -> p_bar pi+ pi-
+    partDaughterPdg[curPart].push_back(  211);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    
+    partDaughterPdg[curPart].push_back(  411); //D*0 -> D+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -411); //D*0_bar -> D- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  421); //D*+ -> D0 pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -421); //D*- -> D0_bar pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  429); //D*+ -> D04 pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -429); //D*- -> D04_bar pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(  428); //D*0 -> D04 pi0
+    partDaughterPdg[curPart].push_back(  111);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   11); //B -> e+ e-
+    partDaughterPdg[curPart].push_back(  -11);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(   13); //B -> mu+ mu-
+    partDaughterPdg[curPart].push_back(  -13);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -421); //B+ -> D0_bar pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  421); //B- -> D0 pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -421); //B+ -> D0_bar K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  421); //B- -> D0 K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( -411); //B0 -> D- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  411); //B0_bar -> D+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( -411); //B0 -> D0_bar K+
+    partDaughterPdg[curPart].push_back(  321);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(  411); //B0_bar -> D0 K-
+    partDaughterPdg[curPart].push_back( -321);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 3122); //H0-> Lambda pi- p
+    partDaughterPdg[curPart].push_back( -211);
+    partDaughterPdg[curPart].push_back( 2212);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 1000010020); //LambdaN -> d+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000010020); //LambdaN_bar-> d- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 1000010030); //LambdaNN -> t+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000010030); //LambdaNN_bar -> t- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 1000020030); //H3Lambda -> He3+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000020030); //H3Lambda_bar -> He3- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 1000020040); //H4Lambda -> He4+ pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000020040); //H4Lambda_bar -> He4- pi+
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 1000020030); //He4Lambda -> He3+ p+ pi-
+    partDaughterPdg[curPart].push_back( 2212);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000020030); //He4Lambda_bar -> He3- p- pi+
+    partDaughterPdg[curPart].push_back(-2212);
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 1000020040); //He5Lambda -> He4+ p+ pi-
+    partDaughterPdg[curPart].push_back( 2212);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back(-1000020040); //He5Lambda_bar -> He4- p- pi+
+    partDaughterPdg[curPart].push_back(-2212);
+    partDaughterPdg[curPart].push_back(  211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3004); //LLn -> H3Lambda pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3006); //H4LL -> He4Lambda pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 3004); //H4LL -> H3Lambda p pi-
+    partDaughterPdg[curPart].push_back( 2212);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+
+    partDaughterPdg[curPart].push_back( 3007); //H5LL -> He5Lambda pi-
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back( 3007); //He6LL -> He5Lambda p pi-
+    partDaughterPdg[curPart].push_back( 2212);
+    partDaughterPdg[curPart].push_back( -211);
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      13); // pi- -> mu- + nu_mu_bar
+    partDaughterPdg[curPart].push_back(-7000014); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(    -211); // nu_mu_bar <- pi- - mu-
+    partDaughterPdg[curPart].push_back(      13); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -13); // pi+ -> mu+ + nu_mu
+    partDaughterPdg[curPart].push_back( 7000014); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(    211); // nu_mu <- pi+ - mu+
+    partDaughterPdg[curPart].push_back(    -13); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      13); // K- -> mu- + nu_mu_bar
+    partDaughterPdg[curPart].push_back(-8000014); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(    -321); // nu_mu_bar <- K- - mu-
+    partDaughterPdg[curPart].push_back(      13); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -13); // K+ -> mu+ + nu_mu
+    partDaughterPdg[curPart].push_back( 8000014); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     321); // nu_mu <- K+ - mu+
+    partDaughterPdg[curPart].push_back(     -13); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -211); // Sigma- -> pi- + n
+    partDaughterPdg[curPart].push_back(  7002112); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     3112); // n <- Sigma- - pi-
+    partDaughterPdg[curPart].push_back(     -211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       211); // Sigma-b -> pi+ + nb
+    partDaughterPdg[curPart].push_back(  -7002112); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -3112); // nb <- Sigma-b - pi+
+    partDaughterPdg[curPart].push_back(       211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -211); // Sigma+b -> pi- + nb
+    partDaughterPdg[curPart].push_back(  -8002112); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(    -3222); // nb <- Sigma+b - pi-
+    partDaughterPdg[curPart].push_back(     -211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       211); // Sigma+ -> pi+ + n
+    partDaughterPdg[curPart].push_back(   8002112); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      3222); // n <- Sigma+ - pi+
+    partDaughterPdg[curPart].push_back(       211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -211); // Xi- -> pi- + lam
+    partDaughterPdg[curPart].push_back(   7003122); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      3312); // lam <- Xi- - pi-
+    partDaughterPdg[curPart].push_back(      -211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       211); // Xi-b -> pi+ + lam_b
+    partDaughterPdg[curPart].push_back(  -7003122); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -3312); // lam_b <- Xi-b - pi+
+    partDaughterPdg[curPart].push_back(       211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -211); // Om- -> pi- + Xi0
+    partDaughterPdg[curPart].push_back(   7003322); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      3334); // Xi0 <- Om- - pi-
+    partDaughterPdg[curPart].push_back(      -211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       211); // Om-b -> pi+ + Xi0_b
+    partDaughterPdg[curPart].push_back(  -7003322); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -3334); // Xi0_b <- Om-b - pi+
+    partDaughterPdg[curPart].push_back(       211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -211); // K- -> pi- + Pi0_b
+    partDaughterPdg[curPart].push_back(  -9000111); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -321); // Pi0_b <- K- - pi-
+    partDaughterPdg[curPart].push_back(      -211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       211); // K+ -> pi+ + Pi0
+    partDaughterPdg[curPart].push_back(   9000111); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       321); // Pi0 <- K+ - pi+
+    partDaughterPdg[curPart].push_back(       211); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      -321); // Om- -> K- + Lam
+    partDaughterPdg[curPart].push_back(   8003122); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      3334); // Lam <- Om- - K-
+    partDaughterPdg[curPart].push_back(      -321); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(       321); // Om+ -> K+ + Lam_b
+    partDaughterPdg[curPart].push_back(  -8003122); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -3334); // Lam_b <- Om+ - K+
+    partDaughterPdg[curPart].push_back(       321); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -2212); // Si+b -> p_b + Pi0
+    partDaughterPdg[curPart].push_back(  -8000111); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(     -3222); // Pi0 <- Si+b - p_b
+    partDaughterPdg[curPart].push_back(     -2212); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      2212); // Si+ -> p + Pi0
+    partDaughterPdg[curPart].push_back(   8000111); //
+    curPart++;
+    
+    partDaughterPdg[curPart].push_back(      3222); // Pi0 <- Si+ - p
+    partDaughterPdg[curPart].push_back(      2212); //
+    curPart++;
+    
+    for(int iP=0; iP<nParticles; iP++)
+    {
+      partPDG[iP] = particleInfo[iP].PDG();
+      partName[iP] = particleInfo[iP].Name();
+      partTitle[iP] = particleInfo[iP].Title();
+      partMHistoMin[iP] = particleInfo[iP].HistoMin();
+      partMHistoMax[iP] = particleInfo[iP].HistoMax();
+      partMaxMult[iP] = mPartMaxMult[iP];
+      partMass[iP] = particleInfo[iP].Mass();
+      partLifeTime[iP] = particleInfo[iP].LifeTime();
+      partCharge[iP] = particleInfo[iP].Charge();
+      partMassSigma[iP] = particleInfo[iP].MassSigma();
+    }
+
+    for(int iP=0; iP<nParticles; iP++)
+    {
+      AddCounter(partName[iP],           partTitle[iP] + "     ");
+      AddCounter(partName[iP] + "_prim", partTitle[iP] + " Prim");
+      AddCounter(partName[iP] + "_sec",  partTitle[iP] + " Sec ");
+    }
+
+    for(int iP=0; iP<nParticles; iP++)
+      fPdgToIndex[particleInfo[iP].PDG()] = iP;
+  }
+
+  virtual ~KFPartEfficiencies(){};
+
+  /** \brief Returns index of the decay with a given PDG code in the scheme of the KF Particle Finder. If it is not present there - returns "-1". */
+  int GetParticleIndex(int pdg)
+  {
+    std::map<int, int>::iterator it;
+    it=fPdgToIndex.find(pdg);
+    if(it != fPdgToIndex.end()) return it->second;
+    else return -1;
+  }
+
+  /** \brief Returns the map between PDG codes and index of the decay in the scheme of the KF Particle Finder. */
+  std::map<int,int> GetPdgToIndexMap() const { return fPdgToIndex; } 
+  
+  virtual void AddCounter(std::string shortname, std::string name)
+  {
+    /** Adds a counter with the name defined by "name" to all counter
+     ** objects. For easiness of operation with counters, a shortname is assigned
+     ** to each of them and the corresponding entry in the map indices is done.
+     ** \param[in] shortname - a short name of the counter for fast and easy access to its index
+     ** \param[in] name - name of the counter which is added to each counter object.
+     **/
+    indices[shortname] = names.size();
+    names.push_back(name);
+
+    ratio_reco1.AddCounter();
+    ratio_reco2.AddCounter();
+    ratio_reco3.AddCounter();
+
+    mc1.AddCounter();
+    mc2.AddCounter();
+    mc3.AddCounter();
+    
+    reco.AddCounter();
+
+    ratio_ghost.AddCounter();
+    ratio_bg.AddCounter();
+    ratio_clone.AddCounter();
+    ghost.AddCounter();
+    bg.AddCounter();
+    clone.AddCounter();
+  };
+
+  /** \brief Operator to add efficiency table from object "a" to the current object. Returns the current object after addition. */
+  KFPartEfficiencies& operator+=(KFPartEfficiencies& a){
+    mc1 += a.mc1; mc2 += a.mc2; mc3 += a.mc3; reco += a.reco;
+    ghost += a.ghost; bg += a.bg; clone += a.clone;
+    return *this;
+  };
+  
+  /** \brief Function to calculate efficiency after all counters are set. If the counters are modified the function should be called again. */
+  void CalcEff(){
+    ratio_reco1 = reco/mc1;
+    ratio_reco2 = reco/mc2;
+    ratio_reco3 = reco/mc3;
+
+    KFMCCounter<int> allReco = reco + ghost + bg;
+    ratio_ghost = ghost/allReco;
+    ratio_bg  = bg/allReco;
+    ratio_clone  = clone/allReco;
+  };
+  
+  void Inc(bool isReco, int nClones, bool isMC1, bool isMC2, bool isMC3, std::string name)
+  {
+    /** Increases counters by one, if the corresponding boolean variable is "true".
+     ** \param[in] isReco - "true" if particle is reconstructed
+     ** \param[in] nClones - number of double reconstructed particles for the given MC particle,
+     ** will be added to the "clone" counters
+     ** \param[in] isMC1 - "true" if particle is reconstructable in 4pi, mc1 is increased
+     ** \param[in] isMC2 - "true" if all daughters are reconstructable, mc2 is increased
+     ** \param[in] isMC3 - "true" if all daughters are reconstructed, mc3 is increased
+     ** \param[in] name  - "shortname" of the set of counters, which should be increased
+     **/
+    const int index = indices[name];
+    
+    if(isMC1) mc1.counters[index]++;
+    if(isMC2) mc2.counters[index]++;
+    if(isMC3) mc3.counters[index]++;
+    
+    if(isReco) reco.counters[index]++;
+    if(nClones > 0)
+      clone.counters[index] += nClones;
+  };
+
+  void IncReco(bool isGhost, bool isBg, std::string name)
+  {
+    /** Increases counters by one, if the corresponding boolean variable is "true".
+     ** \param[in] isGhost - "true" if ghost is added
+     ** \param[in] isBg - "true" if physics background is added
+     ** \param[in] name  - "shortname" of the set of counters, which should be increased
+     **/
+    const int index = indices[name];
+
+    if (isGhost) ghost.     counters[index]++;
+    if (isBg)    bg.counters[index]++;
+  };
+
+  /** \brief Prints the efficiency table on the screen. */
+  void PrintEff(){
+    std::ios_base::fmtflags original_flags = std::cout.flags();
+    std::cout.setf(std::ios::fixed);
+    std::cout.setf(std::ios::showpoint);
+    std::cout.precision(3);
+    std::cout << "Particle             : "
+         <<        "   Eff 4pi "
+         <<" / "<< " Eff accept"
+         <<" / "<< "  Eff KFPF "
+         <<" / "<< "     Ghost "
+         <<" / "<< "    BackGr "
+         <<" / "<< "   N Ghost "
+         <<" / "<< "  N BackGr "
+         <<" / "<< "    N Reco "
+         <<" / "<< "   N Clone "
+         <<" | "<< "  N MC 4pi " 
+         <<" | "<< "N MC accept" 
+         <<" | "<< " N MC KFPF "  << std::endl;
+    
+    int NCounters = mc1.NCounters;
+    for (int iC = 0; iC < NCounters; iC++){
+        std::cout << names[iC]
+             << "  : " << std::setw(10) << ratio_reco1.counters[iC]    
+             << "  / " << std::setw(10) << ratio_reco2.counters[iC]
+             << "  / " << std::setw(10) << ratio_reco3.counters[iC]
+             << "  / " << std::setw(10) << ratio_ghost.counters[iC]  // particles w\o MCParticle
+             << "  / " << std::setw(10) << ratio_bg.counters[iC]     // particles with incorrect MCParticle
+             << "  / " << std::setw(10) << ghost.counters[iC]
+             << "  / " << std::setw(10) << bg.counters[iC]
+             << "  / " << std::setw(10) << reco.counters[iC]
+             << "  / " << std::setw(10) << clone.counters[iC]
+             << "  | " << std::setw(10) << mc1.counters[iC] 
+             << "  | " << std::setw(10) << mc2.counters[iC]
+             << "  | " << std::setw(10) << mc3.counters[iC]  << std::endl;
+    }
+    std::cout.flags(original_flags); 
+  };
+  
+  float GetTotal4piEfficiency(int iDecay) { return ratio_reco1.counters[3*iDecay]; }  ///< Returns efficiency in 4pi for decay "iDecay".
+  float GetTotalKFPEfficiency(int iDecay) { return ratio_reco3.counters[3*iDecay]; }  ///< Returns efficiency of KF Particle Finder method (cuts) for decay "iDecay".
+  float GetPrimary4piEfficiency(int iDecay) { return ratio_reco1.counters[3*iDecay+1]; } ///< Returns efficiency in 4pi for decay "iDecay" for primary particles.
+  float GetPrimaryKFPEfficiency(int iDecay) { return ratio_reco3.counters[3*iDecay+1]; } ///< Returns efficiency of KF Particle Finder method (cuts) for decay "iDecay" for primary particles.
+  float GetSecondary4piEfficiency(int iDecay) { return ratio_reco1.counters[3*iDecay+2]; } ///< Returns efficiency in 4pi for decay "iDecay" for secondary particles.
+  float GetSecondaryKFPEfficiency(int iDecay) { return ratio_reco3.counters[3*iDecay+2]; } ///< Returns efficiency of KF Particle Finder method (cuts) for decay "iDecay" for secondary particles.
+  
+  /** \brief Operator to write efficiencies to file. */
+  friend std::fstream & operator<<(std::fstream &strm, KFPartEfficiencies &a) 
+  {
+    strm << a.ratio_reco1;
+    strm << a.ratio_reco2;
+    strm << a.ratio_reco3;
+    strm << a.mc1;
+    strm << a.mc2;
+    strm << a.mc3;
+    strm << a.reco;
+    strm << a.ratio_ghost;
+    strm << a.ratio_bg;
+    strm << a.ratio_clone;
+    strm << a.ghost;
+    strm << a.bg;
+    strm << a.clone;
+
+    return strm;
+  }
+  /** \brief Operator to read efficiencies from file. */
+  friend std::fstream & operator>>(std::fstream &strm, KFPartEfficiencies &a)
+  {
+    strm >> a.ratio_reco1;
+    strm >> a.ratio_reco2;
+    strm >> a.ratio_reco3;
+    strm >> a.mc1;
+    strm >> a.mc2;
+    strm >> a.mc3;
+    strm >> a.reco;
+    strm >> a.ratio_ghost;
+    strm >> a.ratio_bg;
+    strm >> a.ratio_clone;
+    strm >> a.ghost;
+    strm >> a.bg;
+    strm >> a.clone;
+
+    return strm;
+  }
+  /** \brief Adds efficiency from the file with the name defined by "fileName" to the current objects. */
+  void AddFromFile(std::string fileName)
+  {
+    std::fstream file(fileName.data(),std::fstream::in);
+    file >> *this;
+  }
+  
+  int GetNDaughters(int iParticle) const { return partDaughterPdg[iParticle].size(); } ///< Returns number of daughter particles for the decay with index "iParticle".
+  /** \brief Returns the PDG code of the daughter "iDaughter" from the decay with index "iParticle". */
+  int GetDaughterPDG(int iParticle, int iDaughter) const { return partDaughterPdg[iParticle][iDaughter]; }
+  
+  float GetMass(int iParticle) const { return partMass[iParticle]; } ///< Returns the table mass of the decay with index "iParticle".
+  float GetMassSigma(int iParticle) const { return partMassSigma[iParticle]; } ///< Returns expected width of the mass peak of the decay with index "iParticle".
+  
+  static const int nParticles = 194;                     ///< Number of particles.
+  static const int fFirstHypernucleusIndex = 114;        ///< Index of the first hypernuclei in the list.
+  static const int fLastHypernucleusIndex = 130;         ///< Index of the last hypernuclei in the list.
+  static const int fFirstMissingMassParticleIndex = 131; ///< Index of the first decay reconstructed by the missing mass method.
+  static const int fLastMissingMassParticleIndex = 166;  ///< Index of the last decay reconstructed by the missing mass method.
+  static const int fFirstStableParticleIndex = 167;      ///< Index of the first stable particle in the list.
+  static const int fLastStableParticleIndex = 184;       ///< Index of the last stable particle in the list.
+  
+  int partPDG[nParticles];                        ///< Array of PDG codes assigned to the decays.
+  std::string partName[nParticles];               ///< Array of names of the decay in the file with histograms.
+  std::string partTitle[nParticles];              ///< Array of names of the decay in the output table with efficiency.
+  std::vector<std::vector<int> > partDaughterPdg; ///< Array with vectors of daughter particles for each decay.
+  float partMHistoMin[nParticles];                ///< Array with lower boundary in the mass histograms for each decay.
+  float partMHistoMax[nParticles];                ///< Array with upper boundary in the mass histograms for each decay.
+  int partMaxMult[nParticles];                    ///< Array with upper boundary in the multiplicity histograms of each decay.
+  float partMass[nParticles];                     ///< Array with table masses of each decay.
+  float partLifeTime[nParticles];                 ///< Array with lifetimes in seconds of each decay.
+  int partCharge[nParticles];                     ///< Array with charge of each particle specie in units of the elementary charge.
+  float partMassSigma[nParticles];                ///< Array with expected width of mass peaks used for the side band method.
+
+  
+ private:
+  std::vector<std::string> names;     ///< Names of the counters. The same for all counters objects.
+  std::map<std::string, int> indices; ///< Map between the counter index and its short name.
+
+  std::map<int, int> fPdgToIndex;     ///< The map between PDG code assigned to the decay and index in the decay list.
+
+  KFMCCounter<double> ratio_reco1;    ///< Efficiency in 4 pi for all decays.
+  KFMCCounter<double> ratio_reco2;    ///< Efficiency normalised on the particles with all daughters reconstructable for all decays.
+  KFMCCounter<double> ratio_reco3;    ///< Efficiency normalised on the particles with all daughters reconstructed for all decays.
+
+  KFMCCounter<int> mc1;               ///< Counters of the Monte Carlo particles of all species.
+  KFMCCounter<int> mc2;               ///< Counters of the Monte Carlo particles with all daughters reconstructable for all species.
+  KFMCCounter<int> mc3;               ///< Counters of the Monte Carlo particles with all daughters found for all species.
+
+  KFMCCounter<int> reco;              ///< Counters of the reconstructed particles for all species.
+
+  KFMCCounter<double> ratio_ghost;    ///< Ratio of the ghost candidates to the total number of candidates for all species.
+  KFMCCounter<double> ratio_bg;       ///< Ratio of the physics background candidates to the total number of candidates for all species.
+  KFMCCounter<double> ratio_clone;    ///< Ratio of double reconstructed particles to the total number of signal candidates for all species.
+
+  KFMCCounter<int> ghost;             ///< Counters of the ghost candidates for all species.
+  KFMCCounter<int> bg;                ///< Counters of the physics background candidates for all species.
+  KFMCCounter<int> clone;             ///< Counters of the double reconstructed particles for all species.
+  
+#ifndef KFParticleStandalone
+  ClassDef( KFPartEfficiencies, 1 )
+#endif
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFPartMatch.h b/external/KFParticle/KFParticlePerformance/KFPartMatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c1c8e8ee6e04cc2d1b89a6d0f39954151bbc95f
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFPartMatch.h
@@ -0,0 +1,48 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifndef KFPartMatch_H
+#define KFPartMatch_H
+
+#include <vector>
+
+
+/** @class KFPartMatch
+ ** @brief A structure to store matching information between simulated Monte Carlo and reconstructed particles.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class is used in both directions: to store links from Monte Carlo to reconstructed particles and vise versa.
+ ** It contains two kind of links: 1) PDG hypothesis of the reconstructed and Monte Carlo particles should be the same;
+ ** 2) PDG code differs. 
+ **/
+
+struct KFPartMatch // used for Reco to MC match as well as for MC to Reco
+{
+  KFPartMatch():ids(),idsMI() {}
+  
+  bool IsMatched() const { return ids.size() != 0 || idsMI.size() != 0; } ///< Returns true if at least one link exists independently of the PDG hypothesis.
+  bool IsMatchedWithPdg() const { return ids.size() != 0; }               ///< Returns true is at least one link with the correct PDG exists.
+  int  GetBestMatch() const { 
+    if      (ids.size()   != 0) return ids[0];
+    else if (idsMI.size() != 0) return idsMI[0];
+    else return -1;
+  } ///< Returns first link with correct PDG if exists, otherwise first link with incorrect PDG. If no link exists returns "-1".
+  int  GetBestMatchWithPdg() const { 
+    if      (ids.size()   != 0) return ids[0];
+    else return -1;
+  } ///< Returns first link with correct PDG if exists, otherwise returns "-1".
+  std::vector<int> ids;   ///< Vector of links, PDG hypothesis of the reconstructed particle is required to be the same as the PDG code of the Monte Carlo particle.
+  std::vector<int> idsMI; ///< Vector of links, PDG hypothesis of the reconstructed particle differs from the Monte Carlo particle.
+};
+
+#endif
diff --git a/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.cxx b/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e3ca1e24fcace602a24ab9f4e8b7e1cfb64c11d5
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.cxx
@@ -0,0 +1,1072 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifdef DO_TPCCATRACKER_EFF_PERFORMANCE
+
+#include "KFParticlePerformanceBase.h"
+
+#include "TDirectory.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TH3.h"
+#include "TProfile.h"
+#include "TProfile2D.h"
+
+
+KFParticlePerformanceBase::KFParticlePerformanceBase():
+  fParteff(), fPVeff(), fPVeffMCReconstructable(), outfileName(), histodir(0), fNEvents(0), fStoreMCHistograms(1), 
+  fStorePrimSecHistograms(1), fStoreZRHistograms(1),fHistoDir(0)
+{
+  /** The default constructor. Initialises all pointers to nullptr.  **/
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+  {
+    for(int iFitQA=0; iFitQA<nFitQA; iFitQA++)
+    {
+      hFitDaughtersQA         [iParticle][iFitQA] = nullptr;
+      hFitQA                  [iParticle][iFitQA] = nullptr;
+      hFitQANoConstraint      [iParticle][iFitQA] = nullptr;
+      hFitQAMassConstraint    [iParticle][iFitQA] = nullptr;
+      hFitQATopoConstraint    [iParticle][iFitQA] = nullptr;
+      hFitQATopoMassConstraint[iParticle][iFitQA] = nullptr;
+    }
+  }
+
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    for(int iQA=0; iQA<nDSToParticleQA; iQA++)
+      hDSToParticleQA[iParticle][iQA] = nullptr;
+  
+  for(int iParameterSet=0; iParameterSet<nParametersSet; iParameterSet++)
+  {
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    {
+      for(int iHisto=0; iHisto<nHistoPartParam; iHisto++)
+      {
+        hPartParam               [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamPrimary        [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamPrimaryMass    [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamPrimaryTopo    [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamPrimaryTopoMass[iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamSecondary      [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParamSecondaryMass  [iParameterSet][iParticle][iHisto] = nullptr;
+      }
+    }
+  }
+
+  for(int iParameterSet=0; iParameterSet<nParametersSet; iParameterSet++)
+  {
+    for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    {
+      for(int iHisto=0; iHisto<nHistoPartParam2D; iHisto++)
+      {
+        hPartParam2D               [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DPrimary        [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DPrimaryMass    [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DPrimaryTopo    [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DPrimaryTopoMass[iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DSecondary      [iParameterSet][iParticle][iHisto] = nullptr;
+        hPartParam2DSecondaryMass  [iParameterSet][iParticle][iHisto] = nullptr;
+      }
+    }
+  }
+
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    for(int iHisto=0; iHisto<nHistoPartParam3D; iHisto++)
+      hPartParam3D[0][iParticle][iHisto] = nullptr;
+
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    for(int iEffSet=0; iEffSet<3; iEffSet++)
+      for(int iEff=0; iEff<nPartEfficiency; iEff++)
+        hPartEfficiency[iParticle][iEffSet][iEff] = nullptr;
+        
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+    for(int iEffSet=0; iEffSet<3; iEffSet++)
+      for(int iEff=0; iEff<nPartEfficiency2D; iEff++)
+        hPartEfficiency2D[iParticle][iEffSet][iEff] = nullptr;
+  
+  for(int iEffSet=0; iEffSet<2; iEffSet++)
+    for(int iHistoPV=0; iHistoPV<nHistosPV; iHistoPV++)
+      hPVFitQa[iEffSet][iHistoPV] = nullptr;
+
+  for(int iEffSet1=0; iEffSet1<2; iEffSet1++)
+    for(int iEffSet2=0; iEffSet2<2; iEffSet2++)
+      for(int iHistoPV=0; iHistoPV<nHistosPV-1; iHistoPV++)
+        hPVFitQa2D[iEffSet1][iEffSet2][iHistoPV] = nullptr;
+
+  for(int iParam=0; iParam<nHistosPVParam; iParam++)
+  {
+    hPVParam      [iParam] = nullptr;
+    hPVParamGhost [iParam] = nullptr;
+    hPVParamSignal[iParam] = nullptr;
+    hPVParamPileup[iParam] = nullptr;
+    hPVParamBG    [iParam] = nullptr;
+  }
+  
+  for(int iParam=0; iParam<nHistosPVParam2D; iParam++)
+    hPVParam2D[iParam] = nullptr;
+  
+  for(int iFitQA=0; iFitQA<nFitPVTracksQA; iFitQA++)
+    hFitPVTracksQA[iFitQA] = nullptr;
+  
+  for(int iTP=0; iTP<nHistosTP; iTP++)
+    hTrackParameters[iTP] = nullptr;
+
+  for(int iEffSet=0; iEffSet<4; iEffSet++)
+    for(int iEff=0; iEff<nPVefficiency; iEff++)
+      hPVefficiency[iEffSet][iEff] = nullptr;
+}
+
+void KFParticlePerformanceBase::CreateHistos(std::string histoDir, TDirectory* outFile, std::map<int,bool> decays)
+{
+  /** Creates all histograms. If "outFile" is provided - creates a new ROOT directory and stores all 
+   ** histograms there. Otherwise histograms are stored in TDirectory::CurrentDirectory().
+   ** \param[in] histoDir - name of the ROOT directory with histograms
+   ** \param[in] outFile - pointer to the external ROOT directory or file, where histograms should be stored
+   ** \param[in] decays - a list of decays, for which histograms are created, if empty - histograms are
+   ** created for all decay channels from the KF Particle Finder reconstruction scheme
+   **/
+  TDirectory *curdir = gDirectory;
+  if (outFile) {
+    outFile->cd();
+    fHistoDir = outFile;
+    if (histoDir != "") {
+      fHistoDir = outFile->mkdir( TString(histoDir) );
+      fHistoDir->cd();
+    }
+  } else {
+    fHistoDir = TDirectory::CurrentDirectory();
+  }
+  {
+    gDirectory->mkdir("KFParticlesFinder");
+    gDirectory->cd("KFParticlesFinder");
+    histodir = gDirectory;
+    gDirectory->mkdir("Particles");
+    gDirectory->cd("Particles");
+    for(int iPart=0; iPart<fParteff.nParticles; ++iPart)
+    {
+      if(!(decays.empty()) && (iPart < fParteff.fFirstStableParticleIndex || iPart > fParteff.fLastStableParticleIndex))
+        if(decays.find(fParteff.partPDG[iPart]) == decays.end()) continue;
+        
+      gDirectory->mkdir(fParteff.partName[iPart].data());
+      gDirectory->cd(fParteff.partName[iPart].data());
+      {
+        if(fStoreMCHistograms)
+        {
+          TString res = "res";
+          TString pull = "pull";
+
+          gDirectory->mkdir("DaughtersQA");
+          gDirectory->cd("DaughtersQA");
+          {
+            TString parName[nFitQA/2] = {"X","Y","Z","Px","Py","Pz","E","M"};
+            int nBins = 100;
+            float xMax[nFitQA/2] = {0.15,0.15,0.03,0.01,0.01,0.06,0.06,0.01};
+  //             float xMax[nFitQA/2] = {2.,2.,5.,0.3,0.3,0.3,0.03,0.03};
+
+            for( int iH=0; iH<nFitQA/2; iH++ ){
+              hFitDaughtersQA[iPart][iH]   = new TH1F((res+parName[iH]).Data(),
+                                                      (GetDirectoryPath()+res+parName[iH]).Data(), 
+                                                      nBins, -xMax[iH],xMax[iH]);
+              hFitDaughtersQA[iPart][iH+8] = new TH1F((pull+parName[iH]).Data(),
+                                                      (GetDirectoryPath()+pull+parName[iH]).Data(), 
+                                                      nBins, -6,6);
+            }
+          }
+          gDirectory->cd(".."); //particle directory
+
+          gDirectory->mkdir("DSToParticleQA");
+          gDirectory->cd("DSToParticleQA");
+          {
+            TString parName[3] = {"X","Y","Z"};
+            int nBins = 100;
+            float xMax[3] = {0.5, 0.5, 2.};
+
+            for( int iH=0; iH<3; iH++ ){
+              hDSToParticleQA[iPart][iH]   = new TH1F((res+parName[iH]).Data(),
+                                                      (GetDirectoryPath()+res+parName[iH]).Data(), 
+                                                      nBins, -xMax[iH],xMax[iH]);
+              hDSToParticleQA[iPart][iH+3] = new TH1F((pull+parName[iH]).Data(),
+                                                      (GetDirectoryPath()+pull+parName[iH]).Data(), 
+                                                      nBins, -6,6);
+            }
+            
+            hDSToParticleQA[iPart][6] = new TH1F("r", (GetDirectoryPath()+TString("r")).Data(), 1000, 0.0, 20.0);
+          }
+          gDirectory->cd(".."); //particle directory
+          
+          CreateFitHistograms(hFitQA[iPart], iPart);
+          CreateEfficiencyHistograms(hPartEfficiency[iPart],hPartEfficiency2D[iPart]);
+        }
+        gDirectory->mkdir("Parameters");
+        gDirectory->cd("Parameters");
+        {
+          const bool drawZR = IsCollectZRHistogram(iPart);
+          CreateParameterHistograms(hPartParam[0], hPartParam2D[0], hPartParam3D[0], iPart, drawZR);
+
+          if(IsCollect3DHistogram(iPart))
+          {
+            gDirectory->mkdir("SignalReco");
+            gDirectory->cd("SignalReco");
+            {
+              CreateParameterHistograms(hPartParam[4], hPartParam2D[4], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // Parameters
+            gDirectory->mkdir("BGReco");
+            gDirectory->cd("BGReco");
+            {
+              CreateParameterHistograms(hPartParam[5], hPartParam2D[5], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // Parameters
+          }
+          
+          if(fStoreMCHistograms)
+          {
+            gDirectory->mkdir("Signal");
+            gDirectory->cd("Signal");
+            {
+              CreateParameterHistograms(hPartParam[1], hPartParam2D[1], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // particle directory / Parameters
+            gDirectory->mkdir("Background");
+            gDirectory->cd("Background");
+            {
+              CreateParameterHistograms(hPartParam[2], hPartParam2D[2], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // particle directory
+            gDirectory->mkdir("Ghost");
+            gDirectory->cd("Ghost");
+            {
+              CreateParameterHistograms(hPartParam[3], hPartParam2D[3], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // Parameters
+            gDirectory->mkdir("MCSignal");
+            gDirectory->cd("MCSignal");
+            {
+              CreateParameterHistograms(hPartParam[6], hPartParam2D[6], 0, iPart, drawZR);
+            }
+            gDirectory->cd(".."); // Parameters
+            
+            
+            bool plotPrimaryHistograms = abs(fParteff.partPDG[iPart]) == 310 ||
+                                         abs(fParteff.partPDG[iPart]) == 3122 ||
+                                         abs(fParteff.partPDG[iPart]) == 22 ||
+                                         abs(fParteff.partPDG[iPart]) == 111 ||
+                                         abs(fParteff.partPDG[iPart]) == 3312 ||
+                                         abs(fParteff.partPDG[iPart]) == 3334;  
+                                          
+            bool plotSecondaryHistograms = abs(fParteff.partPDG[iPart]) == 310 ||
+                                           abs(fParteff.partPDG[iPart]) == 3122 ||
+                                           abs(fParteff.partPDG[iPart]) == 22 ||
+                                           abs(fParteff.partPDG[iPart]) == 111;
+                                            
+            if(fStorePrimSecHistograms && plotPrimaryHistograms)
+            {
+              gDirectory->mkdir("Primary");
+              gDirectory->cd("Primary");
+              {
+                CreateParameterSubfolder("NoConstraint (1C-Fit)", hPartParamPrimary, hPartParam2DPrimary, hFitQANoConstraint, iPart, true);
+                CreateParameterSubfolder("MassConstraint (2C-Fit)", hPartParamPrimaryMass, hPartParam2DPrimaryMass, hFitQAMassConstraint, iPart, true);
+                CreateParameterSubfolder("PVConstraint (3C-Fit)", hPartParamPrimaryTopo, hPartParam2DPrimaryTopo, hFitQATopoConstraint, iPart, true);
+                CreateParameterSubfolder("PVMassConstraint (4C-Fit)", hPartParamPrimaryTopoMass, hPartParam2DPrimaryTopoMass, hFitQATopoMassConstraint, iPart, true);
+              }
+              gDirectory->cd(".."); // particle directory / Parameters
+            }
+            
+            if(fStorePrimSecHistograms && plotSecondaryHistograms)
+            {
+              gDirectory->mkdir("Secondary");
+              gDirectory->cd("Secondary");
+              {
+                CreateParameterSubfolder("NoConstraint (1C-Fit)", hPartParamSecondary, hPartParam2DSecondary, 0, iPart, true);
+                CreateParameterSubfolder("MassConstraint (2C-Fit)", hPartParamSecondaryMass, hPartParam2DSecondaryMass, 0, iPart, true);
+              }
+              gDirectory->cd(".."); // particle directory / Parameters
+            }
+          }
+        }
+        gDirectory->cd(".."); //particle directory
+      }
+      gDirectory->cd(".."); //Particles
+    }
+    gDirectory->cd(".."); //main
+    gDirectory->mkdir("PrimaryVertexQA");
+    gDirectory->cd("PrimaryVertexQA");
+    {
+      struct {
+        TString name;
+        TString title;
+        Int_t n;
+        Double_t l,r;
+      } Table[nHistosPV]=
+      {
+        {"PVResX",  "x_{rec}-x_{mc}, cm", 100, -0.1f, 0.1f},
+        {"PVResY",  "y_{rec}-y_{mc}, cm", 100, -0.1f, 0.1f},
+        {"PVResZ",  "z_{rec}-z_{mc}, cm", 100, -1.f, 1.f},
+        {"PVPullX", "Pull X",             100, -6.f, 6.f},
+        {"PVPullY", "Pull Y",             100, -6.f, 6.f},
+        {"PVPullZ", "Pull Z",             100, -6.f, 6.f},
+        {"Lost",    "Lost tracks",        102, -0.01f, 1.01f}        
+      };
+      
+      TString parName[nHistosPVParam] = {"x","y","z","r","Ntracks","Chi2","NDF","Chi2NDF","prob", "PVpurity", 
+                                         "ghostTr", "triggerTr", "pileupTr", "bgTr", "dzSamePV"};
+      TString parAxisName[nHistosPVParam] = {"x [cm]","y [cm]","z [cm]","r [cm]","N tracks","Chi2","NDF","Chi2NDF","prob","purity",
+                                             "ghost tracks [%]", "trigger tracks [%]", "pileup tracks [%]", "bg tracks [%]", "dz [cm]"};
+      int nBins[nHistosPVParam] = {1000,1000,1000,1000,1001,10000,1001,10000,100,102,102,102,102,102,1000};
+      float xMin[nHistosPVParam] = {-1., -1., -10.,  0,   -0.5,    0.,   -0.5,    0., 0., -0.01, -0.01, -0.01, -0.01, -0.01, 0.};
+      float xMax[nHistosPVParam] = { 1.,  1.,  10., 10, 1000.5, 1000., 1000.5, 1000., 1.,  1.01,  1.01,  1.01,  1.01,  1.01, 100.};
+      
+      TString parName2D[nHistosPVParam2D] = {"xy"};
+      TString parXAxisName2D[nHistosPVParam2D] = {"x [cm]"};
+      TString parYAxisName2D[nHistosPVParam2D] = {"y [cm]"};
+      int nBinsX2D[nHistosPVParam2D] = {1000};
+      float xMin2D[nHistosPVParam2D] = {-1.};
+      float xMax2D[nHistosPVParam2D] = { 1.};
+      int nBinsY2D[nHistosPVParam2D] = {1000};
+      float yMin2D[nHistosPVParam2D] = {-1.};
+      float yMax2D[nHistosPVParam2D] = { 1.};
+      
+      for(int iH=0; iH<nHistosPVParam; iH++)
+      {
+        hPVParam[iH]       = new TH1F(parName[iH].Data(),(GetDirectoryPath()+parName[iH]).Data(),
+                                        nBins[iH],xMin[iH],xMax[iH]);
+        hPVParam[iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+      }
+
+      for(int iH=0; iH<nHistosPVParam2D; iH++)
+      {
+        hPVParam2D[iH]       = new TH2F(parName2D[iH].Data(),(GetDirectoryPath()+parName2D[iH]).Data(),
+                                        nBinsX2D[iH],xMin2D[iH],xMax2D[iH],
+                                        nBinsY2D[iH],yMin2D[iH],yMax2D[iH]);
+        hPVParam2D[iH]->GetXaxis()->SetTitle(parXAxisName2D[iH].Data());
+        hPVParam2D[iH]->GetYaxis()->SetTitle(parYAxisName2D[iH].Data());
+        hPVParam2D[iH]->GetYaxis()->SetTitleOffset(1.0);
+      }
+      
+      gDirectory->mkdir("Efficiency");
+      gDirectory->cd("Efficiency");
+      {
+        TString effName[nPVefficiency] = {"effVsNMCPVTracks","effVsNMCPV","effVsNMCTracks","effVsNPVTracks","effVsNPV","effVsNTracks"};
+        int nBinsEff[nPVefficiency]  = { 100 , 100 ,  100 ,  100 , 100 , 1000 };
+        float xMinEff[nPVefficiency] = {   0.,   0.,    0.,    0.,   0.,    0.};
+        float xMaxEff[nPVefficiency] = { 100., 100., 1000.,  100., 100., 1000.};
+
+        gDirectory->mkdir("Signal");
+        gDirectory->cd("Signal");
+        {
+          for( int iH=0; iH<nPVefficiency; iH++ ){
+            hPVefficiency[0][iH]   = new TProfile( effName[iH].Data(), (GetDirectoryPath()+effName[iH]).Data(), nBinsEff[iH], xMinEff[iH], xMaxEff[iH]);
+          }
+        }
+        gDirectory->cd(".."); //L1
+
+        gDirectory->mkdir("Pileup");
+        gDirectory->cd("Pileup");
+        {
+          for( int iH=0; iH<nPVefficiency; iH++ ){
+            hPVefficiency[1][iH]   = new TProfile( effName[iH].Data(), (GetDirectoryPath()+effName[iH].Data()), nBinsEff[iH], xMinEff[iH], xMaxEff[iH]);
+          }
+        }
+        gDirectory->cd(".."); //L1
+        
+        gDirectory->mkdir("Signal_MCReconstructable");
+        gDirectory->cd("Signal_MCReconstructable");
+        {
+          for( int iH=0; iH<nPVefficiency; iH++ ){
+            hPVefficiency[2][iH]   = new TProfile( effName[iH].Data(), (GetDirectoryPath()+effName[iH].Data()), nBinsEff[iH], xMinEff[iH], xMaxEff[iH]);
+          }
+        }
+        gDirectory->cd(".."); //L1
+        
+        gDirectory->mkdir("Pileup_MCReconstructable");
+        gDirectory->cd("Pileup_MCReconstructable");
+        {
+          for( int iH=0; iH<nPVefficiency; iH++ ){
+            hPVefficiency[3][iH]   = new TProfile( effName[iH].Data(), (GetDirectoryPath()+effName[iH].Data()), nBinsEff[iH], xMinEff[iH], xMaxEff[iH]);
+          }
+        }
+        gDirectory->cd(".."); //L1
+      }      
+      gDirectory->cd(".."); //L1
+      
+      gDirectory->mkdir("PVTracksQA");
+      gDirectory->cd("PVTracksQA");
+      {
+        TString resTrPV = "resTrPV";
+        TString pullTrPV = "pullTrPV";
+        TString parNameTrPV[nFitPVTracksQA/2] = {"X","Y","Z","Px","Py","Pz"};
+        int nBinsTrPV = 100;
+        float xMaxTrPV[nFitPVTracksQA/2] = {0.5,0.5,0.5,0.05,0.05,0.05};
+
+        for( int iH=0; iH<nFitPVTracksQA/2; iH++ ){
+          hFitPVTracksQA[iH]   = new TH1F((resTrPV+parNameTrPV[iH]).Data(),
+                                                  (GetDirectoryPath()+resTrPV+parNameTrPV[iH]).Data(), 
+                                                  nBinsTrPV, -xMaxTrPV[iH],xMaxTrPV[iH]);
+          hFitPVTracksQA[iH+nFitPVTracksQA/2] = new TH1F((pullTrPV+parNameTrPV[iH]).Data(),
+                                                  (GetDirectoryPath()+pullTrPV+parNameTrPV[iH]).Data(), 
+                                                  nBinsTrPV, -6,6);
+        }
+      }      
+      gDirectory->cd(".."); //L1
+      
+      gDirectory->mkdir("Signal");
+      gDirectory->cd("Signal");
+      {
+        gDirectory->mkdir("FitQA");
+        gDirectory->cd("FitQA");
+        {
+          gDirectory->mkdir("FitQAvcNMCPVTracks");
+          gDirectory->cd("FitQAvcNMCPVTracks");
+          {
+            for(int iHPV=0; iHPV<nHistosPV-1; ++iHPV){
+              hPVFitQa2D[0][0][iHPV] = new TH2F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                                500, 0., 5000.,
+                                                Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+            }
+          }
+          gDirectory->cd(".."); //FitQA
+
+          gDirectory->mkdir("FitQAvcNPVTracks");
+          gDirectory->cd("FitQAvcNPVTracks");
+          {
+            for(int iHPV=0; iHPV<nHistosPV-1; ++iHPV){
+              hPVFitQa2D[0][1][iHPV] = new TH2F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                                500, 0., 5000.,
+                                                Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+            }
+          }
+          gDirectory->cd(".."); //FitQA
+          
+          for(int iHPV=0; iHPV<nHistosPV; ++iHPV){
+            hPVFitQa[0][iHPV] = new TH1F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                         Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+          }
+        }
+        gDirectory->cd(".."); //Signal
+
+        for(int iH=0; iH<nHistosPVParam; iH++)
+        {
+          hPVParamSignal[iH] = new TH1F((parName[iH]).Data(),(GetDirectoryPath()+parName[iH]).Data(),
+                                        nBins[iH],xMin[iH],xMax[iH]);
+          hPVParamSignal[iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+        }
+      }      
+      gDirectory->cd(".."); //L1
+
+      gDirectory->mkdir("Pileup");
+      gDirectory->cd("Pileup");
+      {
+        gDirectory->mkdir("FitQA");
+        gDirectory->cd("FitQA");
+        {
+          gDirectory->mkdir("FitQAvcNMCPVTracks");
+          gDirectory->cd("FitQAvcNMCPVTracks");
+          {
+            for(int iHPV=0; iHPV<nHistosPV-1; ++iHPV){
+              hPVFitQa2D[1][0][iHPV] = new TH2F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                                500, 0., 5000.,
+                                                Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+            }
+          }
+          gDirectory->cd(".."); //FitQA
+
+          gDirectory->mkdir("FitQAvcNPVTracks");
+          gDirectory->cd("FitQAvcNPVTracks");
+          {
+            for(int iHPV=0; iHPV<nHistosPV-1; ++iHPV){
+              hPVFitQa2D[1][1][iHPV] = new TH2F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                                500, 0., 5000.,
+                                                Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+            }
+          }
+          gDirectory->cd(".."); //FitQA
+          
+          for(int iHPV=0; iHPV<nHistosPV; ++iHPV){
+            hPVFitQa[1][iHPV] = new TH1F(Table[iHPV].name.Data(),(GetDirectoryPath()+Table[iHPV].title).Data(),
+                                         Table[iHPV].n, Table[iHPV].l, Table[iHPV].r);
+          }
+        }
+        gDirectory->cd(".."); //Signal
+        
+        for(int iH=0; iH<nHistosPVParam; iH++)
+        {
+          hPVParamPileup[iH] = new TH1F((parName[iH]).Data(),(GetDirectoryPath()+parName[iH]).Data(),
+                                        nBins[iH],xMin[iH],xMax[iH]);
+          hPVParamPileup[iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+        }
+      }      
+      gDirectory->cd(".."); //L1
+      
+      gDirectory->mkdir("Background");
+      gDirectory->cd("Background");
+      {
+        for(int iH=0; iH<nHistosPVParam; iH++)
+        {
+          hPVParamBG[iH] = new TH1F((parName[iH]).Data(),(GetDirectoryPath()+parName[iH]).Data(),
+                                        nBins[iH],xMin[iH],xMax[iH]);
+          hPVParamBG[iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+        }
+      }      
+      gDirectory->cd(".."); //L1
+      
+      gDirectory->mkdir("Ghost");
+      gDirectory->cd("Ghost");
+      {
+        for(int iH=0; iH<nHistosPVParam; iH++)
+        {
+          hPVParamGhost[iH] = new TH1F((parName[iH]).Data(),(GetDirectoryPath()+parName[iH]).Data(),
+                                        nBins[iH],xMin[iH],xMax[iH]);
+          hPVParamGhost[iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+        }
+      }
+      gDirectory->cd(".."); //L1
+    }
+    gDirectory->cd(".."); //L1
+    gDirectory->mkdir("TrackParameters");
+    gDirectory->cd("TrackParameters");
+    {
+      TString chi2Name = "Chi2Prim";
+      for(int iPart=0; iPart < KFPartEfficiencies::nParticles; iPart++)
+      {
+        TString chi2NamePart = "Chi2Prim";
+        chi2NamePart += "_";
+        chi2NamePart += fParteff.partName[iPart].data();
+        hTrackParameters[iPart] = new TH1F(chi2NamePart.Data(), (GetDirectoryPath()+chi2NamePart).Data(), 1000, 0, 100);
+
+      }
+      hTrackParameters[KFPartEfficiencies::nParticles  ] = new TH1F("Chi2Prim_total", (GetDirectoryPath()+TString("Chi2Prim_total")), 1000, 0, 100);
+      hTrackParameters[KFPartEfficiencies::nParticles+1] = new TH1F("Chi2Prim_prim", (GetDirectoryPath()+TString("Chi2Prim_prim")), 1000, 0, 100);
+      hTrackParameters[KFPartEfficiencies::nParticles+2] = new TH1F("Chi2Prim_sec", (GetDirectoryPath()+TString("Chi2Prim_sec")), 1000, 0, 100);
+      hTrackParameters[KFPartEfficiencies::nParticles+3] = new TH1F("Chi2Prim_ghost", (GetDirectoryPath()+TString("Chi2Prim_ghost")), 1000, 0, 100);
+      
+      hTrackParameters[KFPartEfficiencies::nParticles+4] = new TH1F("ProbPrim_total", (GetDirectoryPath()+TString("ProbPrim_total")), 10000, 0, 1);
+      hTrackParameters[KFPartEfficiencies::nParticles+5] = new TH1F("ProbPrim_prim", (GetDirectoryPath()+TString("ProbPrim_prim")), 10000, 0, 1);
+      hTrackParameters[KFPartEfficiencies::nParticles+6] = new TH1F("ProbPrim_sec", (GetDirectoryPath()+TString("ProbPrim_sec")), 10000, 0, 1);
+      hTrackParameters[KFPartEfficiencies::nParticles+7] = new TH1F("ProbPrim_ghost", (GetDirectoryPath()+TString("ProbPrim_ghost")), 10000, 0, 1);
+    }
+    gDirectory->cd(".."); //particle directory
+    curdir->cd();    
+  }
+}
+
+void KFParticlePerformanceBase::CreateFitHistograms(TH1F* histo[nFitQA], int iPart)
+{
+  /** Creates 1D histograms with fit QA for decay with "iPart" number.
+   ** \param[in,out] histo - array with pointers, for which the memory is allocated
+   ** \param[in] iPart - number of the decay in the KF Particle Finder reconstruction scheme
+   **/
+  TString res = "res";
+  TString pull = "pull";
+  
+  TString AxisNameResidual[nFitQA/2];
+  TString AxisNamePull[nFitQA/2];
+
+  AxisNameResidual[0] = "Residual (x^{reco} - x^{mc}) [cm]";
+  AxisNameResidual[1] = "Residual (y^{reco} - y^{mc}) [cm]";
+  AxisNameResidual[2] = "Residual (z^{reco} - z^{mc}) [cm]";
+  AxisNameResidual[3] = "Residual (P_{x}^{reco} - P_{x}^{mc}) [GeV/c]";
+  AxisNameResidual[4] = "Residual (P_{y}^{reco} - P_{y}^{mc}) [GeV/c]";
+  AxisNameResidual[5] = "Residual (P_{z}^{reco} - P_{z}^{mc}) [GeV/c]";
+  AxisNameResidual[6] = "Residual (E^{reco} - E^{mc}) [GeV/c^{2}]";
+  AxisNameResidual[7] = "Residual (M^{reco} - M^{mc}) [GeV/c^{2}]"; 
+
+  AxisNamePull[0] = "Pull x";
+  AxisNamePull[1] = "Pull y";
+  AxisNamePull[2] = "Pull z";
+  AxisNamePull[3] = "Pull P_{x}";
+  AxisNamePull[4] = "Pull P_{y}";
+  AxisNamePull[5] = "Pull P_{z}";
+  AxisNamePull[6] = "Pull E";
+  AxisNamePull[7] = "Pull M";
+  
+  gDirectory->mkdir("FitQA");
+  gDirectory->cd("FitQA");
+  {
+    TString parName[nFitQA/2] = {"X","Y","Z","Px","Py","Pz","E","M"};
+    int nBins = 50;
+    float xMax[nFitQA/2] = {0.15,0.15,1.2,0.02,0.02,0.15,0.15,0.006};
+    float mult[nFitQA/2]={1.f,1.f,1.f,1.f,1.f,1.f,1.f,1.f};
+    if(iPart>63 && iPart<75)
+      for(int iMult=3; iMult<nFitQA/2; iMult++)
+        mult[iMult] = 3;
+    if(iPart>45 && iPart<64)
+    {
+#ifdef CBM
+      for(int iMult=0; iMult<3; iMult++)
+        mult[iMult] = 0.03;
+      for(int iMult=3; iMult<nFitQA/2; iMult++)
+        mult[iMult] = 3;
+#else
+      mult[2] = 0.1;
+      for(int iMult=3; iMult<nFitQA/2; iMult++)
+        mult[iMult] = 10;
+      mult[5] = 2;
+      mult[6] = 2;
+#endif
+    }
+    if(iPart==44 || iPart==45)
+    {
+      mult[0] = 0.25;
+      mult[1] = 0.5;
+      mult[2] = 0.15;
+      for(int iMult=3; iMult<nFitQA/2; iMult++)
+        mult[iMult] = 4;
+    }
+    
+    for( int iH=0; iH<nFitQA/2; iH++ )
+    {
+      histo[iH]   = new TH1F((res+parName[iH]).Data(),
+                             (GetDirectoryPath()+res+parName[iH]).Data(), 
+                             nBins, -mult[iH]*xMax[iH],mult[iH]*xMax[iH]);
+      histo[iH]->GetXaxis()->SetTitle(AxisNameResidual[iH].Data());
+      histo[iH+8] = new TH1F((pull+parName[iH]).Data(),
+                             (GetDirectoryPath()+pull+parName[iH]).Data(), 
+                             nBins, -6,6);
+      histo[iH+8]->GetXaxis()->SetTitle(AxisNamePull[iH+8].Data());
+    }
+  }
+  gDirectory->cd("..");
+}
+
+void KFParticlePerformanceBase::CreateEfficiencyHistograms(TProfile* histo[3][nPartEfficiency], TProfile2D* histo2[3][nPartEfficiency2D])
+{
+  /** Creates efficiency plots in the current ROOT folder.
+   ** \param[in,out] histo - 1D efficiency plots
+   ** \param[in,out] histo2 - 2D efficiency plots
+   **/
+  gDirectory->mkdir("Efficiency");
+  gDirectory->cd("Efficiency");
+  {//vs p, pt, y, z, c*tau, decay length, l, r
+    TString partNameEff[nPartEfficiency] = {"EffVsP","EffVsPt","EffVsY","EffVsZ","EffVsCT","EffVsDL","EffVsL","EffVsR","EffVsMt" };
+    TString partAxisNameEff[nPartEfficiency] = {"p [GeV/c]","p_{t} [GeV/c]",
+                                                "y", "z [cm]", "Life time c#tau [cm]", "Decay length [cm]", 
+                                                "L [cm]", "Rxy [cm]", "m_{t} [GeV/c^{2}]"};
+#ifdef CBM
+    int nBinsEff[nPartEfficiency]  = { 100 , 100 , 100 ,  360 ,  100 ,  100 , 200 , 200 , 100 };
+    float xMinEff[nPartEfficiency] = {   0.,   0.,  0.,  -10.,    0.,    0.,    0.,    0. , 0.};
+    float xMaxEff[nPartEfficiency] = {  20.,  5.,   6.,   80.,  100.,  100.,  100.,  50. , 4.};
+#else
+    int nBinsEff[nPartEfficiency]  = { 100 , 100 ,  30  ,   100 ,  100 ,  100 ,  100 ,  100 , 100  };
+    float xMinEff[nPartEfficiency] = {   0.,   0.,  -1.5,   -10.,    0.,    0.,    0.,    0.,   0. };
+    float xMaxEff[nPartEfficiency] = {  10.,  10.,   1.5,    10.,   30.,    5.,    1.,    1.,  10. };
+#endif
+    TString effTypeName[3] = {"All particles",
+                              "Reconstructable daughters",
+                              "Reconstructed daughters"};
+    
+    for(int iEff=0; iEff<3; iEff++)
+    {
+      gDirectory->mkdir(effTypeName[iEff].Data());
+      gDirectory->cd(effTypeName[iEff].Data());
+      {
+        for(int iH=0; iH<nPartEfficiency; iH++)
+        {
+          histo[iEff][iH] = new TProfile( partNameEff[iH].Data(), (GetDirectoryPath()+partAxisNameEff[iH]).Data(), nBinsEff[iH], xMinEff[iH], xMaxEff[iH]);
+          histo[iEff][iH]->GetYaxis()->SetTitle("Efficiency");                  
+          histo[iEff][iH]->GetYaxis()->SetTitleOffset(1.0);  
+          histo[iEff][iH]->GetXaxis()->SetTitle(partAxisNameEff[iH].Data());
+        }
+        
+        histo2[iEff][0] = new TProfile2D( "EffVsPtVsY", (GetDirectoryPath()+partAxisNameEff[2]+partAxisNameEff[1]).Data(), 
+                                          nBinsEff[2], xMinEff[2], xMaxEff[2], nBinsEff[1], xMinEff[1], xMaxEff[1]);
+        histo2[iEff][0]->GetZaxis()->SetTitle("Efficiency");
+        histo2[iEff][0]->GetXaxis()->SetTitle(partAxisNameEff[2].Data());
+        histo2[iEff][0]->GetYaxis()->SetTitle(partAxisNameEff[1].Data());
+        histo2[iEff][0]->GetYaxis()->SetTitleOffset(1.0);
+        
+        histo2[iEff][1] = new TProfile2D( "EffVsMtVsY", (GetDirectoryPath()+partAxisNameEff[2]+partAxisNameEff[8]).Data(), 
+                                          nBinsEff[2], xMinEff[2], xMaxEff[2], nBinsEff[8], xMinEff[8], xMaxEff[8]);
+        histo2[iEff][1]->GetZaxis()->SetTitle("Efficiency");
+        histo2[iEff][1]->GetXaxis()->SetTitle(partAxisNameEff[2].Data());
+        histo2[iEff][1]->GetYaxis()->SetTitle(partAxisNameEff[8].Data());
+        histo2[iEff][1]->GetYaxis()->SetTitleOffset(1.0);
+      }
+      gDirectory->cd("..");// particle directory / Efficiency
+    }
+  }
+  gDirectory->cd("..");// particle directory 
+}
+
+void KFParticlePerformanceBase::CreateParameterHistograms(TH1F* histoParameters[KFPartEfficiencies::nParticles][nHistoPartParam],
+                                                          TH2F *histoParameters2D[KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                                                          TH3F *histoParameters3D[KFPartEfficiencies::nParticles][nHistoPartParam3D],
+                                                          int iPart, bool drawZR)
+{
+  /** Creates histograms with parameter distributions for decay with "iPart" number.
+   ** \param[in,out] histoParameters - 1D histograms
+   ** \param[in,out] histoParameters2D - 2D histograms
+   ** \param[in,out] histoParameters3D - 3D histograms
+   ** \param[in] iPart - number of the decay in the KF Particle Finder reconstruction scheme
+   ** \param[in] drawZR - flag showing if Z-R histogram should be created
+   **/
+  TString parName[nHistoPartParam] = {"M","p","p_{t}","y","DecayL","c#tau","chi2ndf","prob","#theta","phi","X","Y","Z","R", "L", "l/dl","m_{t}","Multiplicity"};
+  TString parTitle[nHistoPartParam];
+  TString parName2D[nHistoPartParam2D] = {"y-p_{t}", "Z-R", "Armenteros", "y-m_{t}"};
+  TString parTitle2D[nHistoPartParam2D];
+  TString parName3D[nHistoPartParam3D] = {"y-p_{t}-M", "y-m_{t}-M", "centrality-pt-M", "centrality-y-M", "centrality-mt-M", "ct-pt-M"};
+  TString parTitle3D[nHistoPartParam3D];
+  for(int iParam=0; iParam<nHistoPartParam; iParam++)
+  {
+    TString path = GetDirectoryPath();
+    parTitle[iParam] = path + parName[iParam];
+    if(iParam<nHistoPartParam2D)
+      parTitle2D[iParam] = path + parName2D[iParam];
+    if(iParam<nHistoPartParam3D)
+      parTitle3D[iParam] = path + parName3D[iParam];
+  }
+  
+  TString parAxisName[nHistoPartParam] = {"m [GeV/c^{2}]","p [GeV/c]","p_{t} [GeV/c]",
+                                          "y","Decay length [cm]","Life time c#tau [cm]",
+                                          "chi2/ndf","prob","#theta [rad]",
+                                          "phi [rad]","x [cm]","y [cm]","z [cm]","Rxy [cm]", "L [cm]", "L/dL","m_{t} [GeV/c^{2}]","Multiplicity"};
+#ifdef CBM
+  int nBins[nHistoPartParam] =  {1000, // M
+                                  100, // p
+                                  100, // pt
+                                   40, // y
+                                   60, // DecayL
+                                   60, // ctau
+                                  100, // chi2/ndf
+                                  100, // prob
+                                  100, // theta
+                                  100, // phi
+                                  200, // X
+                                  200, // Y
+                                  360, // Z
+                                   60, // R
+                                  140, // L
+                                  200, // L/dL
+                                  100, // Mt
+                                  fParteff.partMaxMult[iPart]+1};
+  float xMin[nHistoPartParam] = { fParteff.partMHistoMin[iPart], // M
+                                  0.f, // p
+                                  0.f, // pt
+                                  0.f, // y
+                                -10.f, // DecayL
+                                -10.f, // ctau
+                                  0.f, // chi2/ndf
+                                  0.f, // prob
+                                 -2.f, // theta
+                                 -2.f, // phi
+                                -50.f, // X
+                                -50.f, // Y
+                                -10.f, // Z
+                                  0.f, // R
+                                  0.f, // L
+                                 -1.f, // L/dL
+                                  0.f, // Mt
+                                 -0.5f };
+  float xMax[nHistoPartParam] = { fParteff.partMHistoMax[iPart], // M
+                                  20.f, // p
+                                   5.f, // pt
+                                   4.f, // y
+                                  50.f, // DecayL
+                                  50.f, // ctau
+                                  20.f, // chi2/ndf
+                                   1.f, // prob
+                                   2.f, // theta
+                                   2.f, // phi
+                                  50.f, // X
+                                  50.f, // Y
+                                  80.f, // Z
+                                  30.f, // R
+                                  70.f, // L
+                                  35.f, // L/dL
+                                  4.f, // Mt
+                                  float(fParteff.partMaxMult[iPart])+0.5f};
+#else
+  int nBins[nHistoPartParam] = {1000, // M
+                                 100, // p
+                                 100, // pt
+                                  30, // y
+                                  60, // DecayL
+                                  60, // ctau
+                                 100, // chi2/ndf
+                                 100, // prob
+                                 100, // theta
+                                 100, // phi
+                                 100, // X
+                                 100, // Y
+                                 100, // Z
+                                 100, // R
+                                 100, // L
+                                1000, // L/dL
+                                 100, // Mt
+                                 fParteff.partMaxMult[iPart]+1};
+  float xMin[nHistoPartParam] = { fParteff.partMHistoMin[iPart], // M
+                                  0.f, // p
+                                  0.f, // pt
+                                -1.5f, // y
+                                -10.f, // DecayL
+                                -10.f, // ctau
+                                  0.f, // chi2/ndf
+                                  0.f, // prob
+                                  0.f, // theta
+                             -3.1416f, // phi
+                                -10.f, // X
+                                -10.f, // Y
+                                -30.f, // Z
+                                  0.f, // R
+                                  0.f, // L
+                                 -1.f, // L/dL
+                                  0.f, // Mt
+                                 -0.5f };
+  float xMax[nHistoPartParam] = { fParteff.partMHistoMax[iPart], // M
+                                  10.f, // p
+                                  10.f, // pt
+                                  1.5f, // y
+                                  50.f, // DecayL
+                                  50.f, // ctau
+                                  20.f, // chi2/ndf
+                                   1.f, // prob
+                               3.1416f, // theta
+                               3.1416f, // phi
+                                  10.f, // X
+                                  10.f, // Y
+                                  30.f, // Z
+                                  50.f, // R
+                                  50.f, // L
+                                  35.f, // L/dL
+                                  10.f, // Mt
+                                  float(fParteff.partMaxMult[iPart])+0.5f};
+  if(iPart < 9)
+  {
+    xMin[10] =-50; xMin[11] =-50; xMin[12] =-100;
+    xMax[10] = 50; xMax[11] = 50; xMax[12] = 100; xMax[13] = 50; xMax[14] = 50; 
+  }
+#endif
+  for(int iH=0; iH<nHistoPartParam; iH++)
+  {
+    histoParameters[iPart][iH] = new TH1F(parName[iH].Data(),parTitle[iH].Data(),
+                                          nBins[iH],xMin[iH],xMax[iH]);
+    histoParameters[iPart][iH]->GetXaxis()->SetTitle(parAxisName[iH].Data());
+  }
+
+  histoParameters2D[iPart][0] = new TH2F(parName2D[0].Data(),parTitle2D[0].Data(),
+                                    nBins[3],xMin[3],xMax[3],
+                                    nBins[2],xMin[2],xMax[2]);
+  histoParameters2D[iPart][0]->GetXaxis()->SetTitle("y");
+  histoParameters2D[iPart][0]->GetYaxis()->SetTitle("p_{t} [GeV/c]");
+  histoParameters2D[iPart][0]->GetYaxis()->SetTitleOffset(1.0);
+
+  if(drawZR)
+  {
+    histoParameters2D[iPart][1] = new TH2F(parName2D[1].Data(),parTitle2D[1].Data(),
+                                      nBins[12],xMin[12],xMax[12],
+                                      nBins[13],xMin[13],xMax[13]);
+    histoParameters2D[iPart][1]->GetXaxis()->SetTitle("Z [cm]");
+    histoParameters2D[iPart][1]->GetYaxis()->SetTitle("R [cm]");
+    histoParameters2D[iPart][1]->GetYaxis()->SetTitleOffset(1.0);
+  }
+  else
+    histoParameters2D[iPart][1] = NULL;
+  
+  //create armenteros plot
+  if(IsCollectArmenteros(iPart))
+  {
+    histoParameters2D[iPart][2] = new TH2F(parName2D[2].Data(),parTitle2D[2].Data(),
+                                           50, -1.f, 1.f,
+                                          150,  0.f, 1.f);
+    histoParameters2D[iPart][2]->GetXaxis()->SetTitle("#alpha (p_{L}^{+}-p_{L}^{-})/(p_{L}^{+}+p_{L}^{-})");
+    histoParameters2D[iPart][2]->GetYaxis()->SetTitle("q_{t} [GeV/c]");
+    histoParameters2D[iPart][2]->GetYaxis()->SetTitleOffset(1.0);
+  }
+  else
+    histoParameters2D[iPart][2] = NULL;
+  //create y-mt plot
+  histoParameters2D[iPart][3] = new TH2F(parName2D[3].Data(),parTitle2D[3].Data(),
+                                         nBins[3],xMin[3], xMax[3],     //y
+                                         nBins[16],xMin[16],xMax[16]); //Mt
+  histoParameters2D[iPart][3]->GetXaxis()->SetTitle("y");
+  histoParameters2D[iPart][3]->GetYaxis()->SetTitle("m_{t} [GeV/c]");
+  histoParameters2D[iPart][3]->GetYaxis()->SetTitleOffset(1.0);
+  
+  
+  if( histoParameters3D && IsCollect3DHistogram(iPart) )
+  {
+    histoParameters3D[iPart][0] = new TH3F(parName3D[0].Data(),parTitle3D[0].Data(),
+                                      nBins[3],xMin[3],xMax[3],
+                                      nBins[2],xMin[2],xMax[2],
+                                      nBins[0],xMin[0],xMax[0]);
+    histoParameters3D[iPart][0]->GetXaxis()->SetTitle("y");
+    histoParameters3D[iPart][0]->GetYaxis()->SetTitle("p_{t} [GeV/c]");
+    histoParameters3D[iPart][0]->GetYaxis()->SetTitleOffset(1.0);
+    histoParameters3D[iPart][0]->GetZaxis()->SetTitle("M");
+    
+    histoParameters3D[iPart][1] = new TH3F(parName3D[1].Data(),parTitle3D[1].Data(),
+                                           nBins[3],xMin[3],xMax[3],
+                                           nBins[16],xMin[16],xMax[16],
+                                           nBins[0],xMin[0],xMax[0]);
+    histoParameters3D[iPart][1]->GetXaxis()->SetTitle("y");
+    histoParameters3D[iPart][1]->GetYaxis()->SetTitle("m_{t} [GeV/c]");
+    histoParameters3D[iPart][1]->GetYaxis()->SetTitleOffset(1.0);
+    histoParameters3D[iPart][1]->GetZaxis()->SetTitle("M");
+    
+    int centralityHisto[3] = {2,3,16};
+    for(int iCH = 0; iCH<3; iCH++)
+    {
+      histoParameters3D[iPart][2+iCH] = new TH3F(parName3D[2+iCH].Data(),parTitle3D[2+iCH].Data(),
+                                                 10,0.,10.,
+                                                 nBins[centralityHisto[iCH]],xMin[centralityHisto[iCH]],xMax[centralityHisto[iCH]],
+                                                 nBins[0],xMin[0],xMax[0]);
+      histoParameters3D[iPart][2+iCH]->GetXaxis()->SetTitle("centrality bin");
+      histoParameters3D[iPart][2+iCH]->GetYaxis()->SetTitle(parAxisName[centralityHisto[iCH]]);
+      histoParameters3D[iPart][2+iCH]->GetYaxis()->SetTitleOffset(1.0);
+      histoParameters3D[iPart][2+iCH]->GetZaxis()->SetTitle("M");
+    }
+    
+    histoParameters3D[iPart][5] = new TH3F(parName3D[5].Data(),parTitle3D[5].Data(),
+                                           nBins[5],xMin[5],xMax[5],
+                                           nBins[2],xMin[2],xMax[2],
+                                           nBins[0],xMin[0],xMax[0]);
+    histoParameters3D[iPart][5]->GetXaxis()->SetTitle("c#tau [cm]");
+    histoParameters3D[iPart][5]->GetYaxis()->SetTitle("p_{t} [GeV/c]");
+    histoParameters3D[iPart][5]->GetYaxis()->SetTitleOffset(1.0);
+    histoParameters3D[iPart][5]->GetZaxis()->SetTitle("M");
+  }
+  else if(histoParameters3D)
+  {
+    histoParameters3D[iPart][0] = NULL;
+    histoParameters3D[iPart][1] = NULL;
+    for(int iCH = 0; iCH<3; iCH++)
+      histoParameters3D[iPart][2+iCH] = NULL;
+    histoParameters3D[iPart][5] = NULL;
+  }
+}
+
+bool KFParticlePerformanceBase::IsCollectZRHistogram(int iParticle) const
+{
+  /** Checks if Z-R histogram for decay "iParticle" should be created. */
+  return (abs(fParteff.partPDG[iParticle]) == 310 ||
+          abs(fParteff.partPDG[iParticle]) == 3122 ||
+          abs(fParteff.partPDG[iParticle]) == 3312 ||
+          abs(fParteff.partPDG[iParticle]) == 3334 ||
+          abs(fParteff.partPDG[iParticle]) == 22) && fStoreMCHistograms && fStoreZRHistograms;
+}
+
+bool KFParticlePerformanceBase::IsCollect3DHistogram(int iParticle) const
+{
+  /** Checks if 3D histograms for decay "iParticle" should be created. */
+  return abs(fParteff.partPDG[iParticle]) == 310 ||
+         abs(fParteff.partPDG[iParticle]) == 3122 ||
+         abs(fParteff.partPDG[iParticle]) == 3312 ||
+         abs(fParteff.partPDG[iParticle]) == 3334 ||
+         abs(fParteff.partPDG[iParticle]) == 3003 ||
+         abs(fParteff.partPDG[iParticle]) == 3103 ||
+         abs(fParteff.partPDG[iParticle]) == 3004 ||
+         abs(fParteff.partPDG[iParticle]) == 3005 ||
+#ifdef CBM
+         abs(fParteff.partPDG[iParticle]) == 7003112 ||
+         abs(fParteff.partPDG[iParticle]) == 7003222 ||
+         abs(fParteff.partPDG[iParticle]) == 7003312 ||
+         abs(fParteff.partPDG[iParticle]) == 8003222 ||
+         abs(fParteff.partPDG[iParticle]) == 9000321;
+#else
+         abs(fParteff.partPDG[iParticle]) == 421 ||
+         abs(fParteff.partPDG[iParticle]) == 429 ||
+         abs(fParteff.partPDG[iParticle]) == 426 ||
+         abs(fParteff.partPDG[iParticle]) == 411 ||
+         abs(fParteff.partPDG[iParticle]) == 431 ||
+         abs(fParteff.partPDG[iParticle]) == 4122 ||
+         abs(fParteff.partPDG[iParticle]) == 521 ||
+         abs(fParteff.partPDG[iParticle]) == 511;
+#endif
+}
+
+bool KFParticlePerformanceBase::IsCollectArmenteros(int iParticle) const
+{
+  /** Checks if Armenteros-Podoliansky plot for decay "iParticle" should be created. */
+  return abs(fParteff.partPDG[iParticle]) == 310 ||
+         abs(fParteff.partPDG[iParticle]) == 3122 ||
+         abs(fParteff.partPDG[iParticle]) == 3312 ||
+         abs(fParteff.partPDG[iParticle]) == 3334 ||
+         abs(fParteff.partPDG[iParticle]) == 22 ||
+         abs(fParteff.partPDG[iParticle]) == 111 ||
+         abs(fParteff.partPDG[iParticle]) == 3003 ||
+         abs(fParteff.partPDG[iParticle]) == 3103 ||
+         abs(fParteff.partPDG[iParticle]) == 3004 ||
+         abs(fParteff.partPDG[iParticle]) == 3005 ||
+         abs(fParteff.partPDG[iParticle]) == 3203 ||
+         abs(fParteff.partPDG[iParticle]) == 3008 ||
+         abs(fParteff.partPDG[iParticle]) == 3000 ||
+         abs(fParteff.partPDG[iParticle]) == 333 ||
+#ifdef CBM
+         abs(fParteff.partPDG[iParticle]) == 7003112 ||
+         abs(fParteff.partPDG[iParticle]) == 7003222 ||
+         abs(fParteff.partPDG[iParticle]) == 7003312 ||
+         abs(fParteff.partPDG[iParticle]) == 8003222 ||
+         abs(fParteff.partPDG[iParticle]) == 9000321;
+#else
+         abs(fParteff.partPDG[iParticle]) == 421 ||
+         abs(fParteff.partPDG[iParticle]) == 420 ||
+         abs(fParteff.partPDG[iParticle]) == 426 ||
+         abs(fParteff.partPDG[iParticle]) == 521 ||
+         abs(fParteff.partPDG[iParticle]) == 511;        
+#endif
+}
+
+void KFParticlePerformanceBase::CreateParameterSubfolder(TString folderName, 
+                                                         TH1F* histoParameters[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam],
+                                                         TH2F* histoParameters2D[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                                                         TH1F* histoFit[KFPartEfficiencies::nParticles][nFitQA], int iPart, bool withWrongPVHypothesis)
+{
+  /** Creates all subfolders in the current ROOT directory for the current decay channel. */
+  gDirectory->mkdir(folderName.Data());
+  gDirectory->cd(folderName.Data());
+  {
+    gDirectory->mkdir("Signal");
+    gDirectory->cd("Signal");
+    {
+      CreateParameterHistograms(histoParameters[1], histoParameters2D[1], 0, iPart);
+    }
+    gDirectory->cd("..");
+    if(withWrongPVHypothesis)
+    {
+      gDirectory->mkdir("WrongPVHypothesis");
+      gDirectory->cd("WrongPVHypothesis");
+      {
+        CreateParameterHistograms(histoParameters[4], histoParameters2D[4], 0, iPart);
+      }
+      gDirectory->cd("..");
+    }
+    gDirectory->mkdir("Background");
+    gDirectory->cd("Background");
+    {
+      CreateParameterHistograms(histoParameters[2], histoParameters2D[2], 0, iPart);
+    }
+    gDirectory->cd("..");
+    gDirectory->mkdir("Ghost");
+    gDirectory->cd("Ghost");
+    {
+      CreateParameterHistograms(histoParameters[3], histoParameters2D[3], 0, iPart);
+    }
+    gDirectory->cd("..");
+    
+    CreateParameterHistograms(histoParameters[0], histoParameters2D[0], 0, iPart);
+    if(histoFit!=0)
+      CreateFitHistograms(histoFit[iPart], iPart);
+  }
+  gDirectory->cd("..");
+}
+
+TString KFParticlePerformanceBase::GetDirectoryPath()
+{
+  /** Returns the path to the current folder. It is used as an addition to the histogram name. */
+  TString path = gDirectory->GetPath();
+  int fileNamePosition = path.Index("Finder/");
+  path.Remove(0, fileNamePosition+7);
+  path.ReplaceAll("Particles/", "");
+  path.ReplaceAll("/Parameters", "");
+  path+=" ";
+  return path;
+}
+
+#endif //DO_TPCCATRACKER_EFF_PERFORMANCE
+
diff --git a/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.h b/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..47fe48dc4e5b2b5f1d65521aadafef6887537a03
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFParticlePerformanceBase.h
@@ -0,0 +1,195 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifdef DO_TPCCATRACKER_EFF_PERFORMANCE
+
+#ifndef KFParticlePERFORMANCEBASE_H
+#define KFParticlePERFORMANCEBASE_H
+
+#ifdef KFPWITHTRACKER
+#include "AliHLTTPCCounters.h"
+
+#include "AliHLTTPCPerformanceBase.h"
+
+#include "AliHLTTPCCADef.h"
+#include "AliHLTArray.h"
+#include "AliHLTTPCCAMCTrack.h"
+#include "AliHLTTPCCAMCPoint.h"
+#endif
+
+#include "KFPartEfficiencies.h"
+#include "KFPVEfficiencies.h"
+
+#include <map>
+#include <string>
+
+class TDirectory;
+class TH1F;
+class TH2F;
+class TH3F;
+
+class KFParticle;
+class TProfile;
+class TProfile2D;
+
+/** @class KFParticlePerformanceBase
+ ** @brief The base class for KFTopoPerformance.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class contains a set of histograms, allocates memory for them, sets names and axis names.
+ ** For each particle from the KF Particle Reconstruction scheme histograms with parameter distribution,
+ ** efficiencies, fit QA, fit QA of daughters, histograms for the side bands method and histograms for
+ ** multi-differential extraction of spectra are collected. Also, a set of histograms for quality of
+ ** the reconstructed parameters of primary vertices is created: distribution of parameters; fit QA;
+ ** fit QA of primary tracks; contamination of ghost, secondary (background) tracks and tracks from
+ ** another primary vertex; efficiency.
+ **/
+
+class KFParticlePerformanceBase
+#ifdef KFPWITHTRACKER
+: public AliHLTTPCPerformanceBase
+#endif
+{
+ public:
+
+  KFParticlePerformanceBase();
+  virtual ~KFParticlePerformanceBase(){};
+    
+    /// Histograms
+  virtual void CreateHistos(std::string histoDir = "", TDirectory* outFile = 0, std::map<int,bool> decays = std::map<int,bool>());
+  TDirectory* GetHistosDirectory() { return fHistoDir; } ///< Returns pointer to the ROOT directory with created histograms.
+
+  /** Switch off collection of histograms requiring Monte Carlo information. Not to allocate memory should be called 
+   ** before KFParticlePerformanceBase::CreateHistos(). **/
+  void DoNotStoreMCHistograms()      { fStoreMCHistograms = 0; } 
+  /** Switch off collection of histograms for primary and secondary candidates. Not to allocate memory should be called 
+   ** before KFParticlePerformanceBase::CreateHistos(). **/
+  void DoNotStorePrimSecHistograms() { fStorePrimSecHistograms = 0; }
+  /** Switch off collection of Z-R histograms. Not to allocate memory should be called 
+   ** before KFParticlePerformanceBase::CreateHistos(). **/
+  void DoNotStoreZRHistograms()      { fStoreZRHistograms = 0; }
+  
+  /** Returns residual histogram with "iParameter" parameter for decay with "iDecay" number. */
+  const TH1F* GetDecayResidual(const int iDecay, const int iParameter) const { return hFitQA[iDecay][iParameter];          }
+  /** Returns pull histogram with "iParameter" parameter for decay with "iDecay" number. */
+  const TH1F* GetDecayPull(const int iDecay, const int iParameter)     const { return hFitQA[iDecay][iParameter+nFitQA/2]; }
+  
+// efficiencies
+  KFPartEfficiencies fParteff; ///< Object with reconstruction efficiency of short-lived particles.
+  KFPVEfficiencies fPVeff; ///< Object with reconstruction efficiency of primary vertices defined by the reconstructed tracks.
+  KFPVEfficiencies fPVeffMCReconstructable; ///< Object with reconstruction efficiency of primary vertices defined by the Monte Carlo tracks.
+    
+ protected:
+  TString outfileName; ///< Name of the output file, where histograms will be stored.
+  TDirectory* histodir; ///< Pointer to the ROOT directory, where histograms are created.
+
+  int fNEvents; ///< Number of processed events.
+  bool fStoreMCHistograms; ///< Flag showing if histograms requiring Monte Carlo information should be created and collected. "True" by default.
+  bool fStorePrimSecHistograms; ///< Flag showing if histograms for primary and secondary candidates should be created and collected. "True" by default.
+  bool fStoreZRHistograms; ///< Flag showing if Z-R histograms should be created and collected. "True" by default.
+
+//histos
+  static const int nFitQA = 16; ///< Number of fit QA histograms: residuals and pulls in X, Y, Z, Px, Py, Pz, E, M.
+  TH1F *hFitDaughtersQA[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of daughter particles at production point.
+  TH1F *hFitQA[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of the reconstructed particle: X, Y, Z at decay point, P, E, M - at production point
+  TH1F *hFitQANoConstraint[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of the particle with no constraints set.
+  TH1F *hFitQAMassConstraint[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of the particle with the mass constraint. 
+  TH1F *hFitQATopoConstraint[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of the particle with the production point constraint.
+  TH1F *hFitQATopoMassConstraint[KFPartEfficiencies::nParticles][nFitQA]; ///< Residuals and pulls of the particle with the mass and production point constraints.
+
+  static const int nDSToParticleQA = 7; ///< Number of histograms to evaluate GetDStoParticle function: residuals and pulls in X, Y, Z; distance between DCA points.
+  TH1F *hDSToParticleQA[KFPartEfficiencies::nParticles][nDSToParticleQA]; ///< Histograms to evaluate KFParticleSIMD::GetDStoParticle() function
+  
+  /** \brief Number of histograms with parameter distributions: mass, p, pt, rapidity, decay length, c*tau, 
+   ** chi/ndf, prob, theta, phi, X, Y, Z, R, L, L/dL, Mt, multiplicity. **/
+  static const int nHistoPartParam = 18;
+  /** Number of sets of histograms with parameter distributions: 0 - all candidates, 1 - reconstructed signal, 2 - physics background from other decays, 3 - combinatorial
+   ** background (ghost), 4 - reconstructed signal for side bands method, 5- reconstructed background for side bands method, 6 - MC signal. **/
+  static const int nParametersSet = 7;
+  TH1F *hPartParam[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of all candidates.
+  TH1F *hPartParamPrimary[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of primary candidates.
+  TH1F *hPartParamPrimaryMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of primary candidates with mass constraint.
+  TH1F *hPartParamPrimaryTopo[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of primary candidates with vertex constraint.
+  TH1F *hPartParamPrimaryTopoMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of primary candidates with mass and vertex constraint.
+  TH1F *hPartParamSecondary[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of secondary candidates.
+  TH1F *hPartParamSecondaryMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam]; ///< Parameters of secondary candidates with mass constraint.
+
+  static const int nHistoPartParam2D = 4; ///< Number of 2D histograms: 0 - y-pt, 1 - z-r, 2 - armenteros, 3- y-mt.
+  TH2F *hPartParam2D[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D histograms for all candidates.
+  TH2F *hPartParam2DPrimary[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D for primary candidates.
+  TH2F *hPartParam2DPrimaryMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D for primary candidates with mass constraint.
+  TH2F *hPartParam2DPrimaryTopo[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D for primary candidates with vertex constraint.
+  TH2F *hPartParam2DPrimaryTopoMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D with mass and vertex constraints.
+  TH2F *hPartParam2DSecondary[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D for secondary candidates.
+  TH2F *hPartParam2DSecondaryMass[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D]; ///< 2D for secondary candidates with mass constraint.
+
+  static const int nHistoPartParam3D = 6; ///< Number of 3D histograms: y-pt-M, y-mt-M, b-pt-M, b-y-M, b-mt-M, ct-pt-M
+  TH3F *hPartParam3D[1][KFPartEfficiencies::nParticles][nHistoPartParam3D]; ///< 3D histograms.
+
+  static const int nPartEfficiency = 9; ///< Number of efficiency plots for each decay: vs p, pt, y, z, c*tau, decay length, l, r, Mt.
+  TProfile* hPartEfficiency[KFPartEfficiencies::nParticles][3][nPartEfficiency]; ///< Efficiency plots.
+  static const int nPartEfficiency2D = 2;  ///< Number of 2D efficiency plots for each decay: y-pt, y-mt.
+  TProfile2D* hPartEfficiency2D[KFPartEfficiencies::nParticles][3][nPartEfficiency2D]; ///< 2D efficiency plots.
+  
+  static const int nHistosPV = 7; ///< Number of QA histograms for primary vertices: residuals, pulls, number of lost tracks.
+  TH1F *hPVFitQa[2][nHistosPV]; ///< Fit QA of primary vertices, 1D histograms.
+  TH2F *hPVFitQa2D[2][2][nHistosPV-1]; ///< Fit QA of primary vertices, 2D histograms.
+
+  /** Number of histograms with parameter distributions: x, y, z, r, Ntracks, Chi2, NDF, Chi2/NDF, prob, purity, part of ghost tracks, 
+   ** part of tracks from the current vertex, number of tracks from merged vertices, number of background tracks from decays, distance in Z between clones. **/
+  static const int nHistosPVParam = 15; ///< 
+  TH1F *hPVParam[nHistosPVParam]; ///< Histograms for all vertex candidates.
+  TH1F *hPVParamGhost[nHistosPVParam]; ///< Histograms for ghost (combinatorial background) vertex candidates.
+  TH1F *hPVParamSignal[nHistosPVParam]; ///< Histograms for signal vertex candidates.
+  TH1F *hPVParamPileup[nHistosPVParam]; ///< Histograms for pileup vertex candidates.
+  TH1F *hPVParamBG[nHistosPVParam]; ///< Histograms for physics background (decays, secondary vertices) vertex candidates.
+  static const int nHistosPVParam2D = 1; ///< Number of 2D histograms for primary vertex.
+  TH2F *hPVParam2D[nHistosPVParam2D]; ///< x-y histogram. 
+  
+  static const int nFitPVTracksQA = 12; ///< Number of fit QA histograms for primary tracks: residuals and pulls in X, Y, Z, Px, Py, Pz.
+  TH1F *hFitPVTracksQA[nFitPVTracksQA]; ///< Residuals and pulls of primary tracks at the primary vertex position.
+  
+  static const int nHistosTP = KFPartEfficiencies::nParticles + 8; ///< Number of histograms with chi2 primary distributions for daughter tracks.
+  /** Histograms with chi2 primary distributions for daughter tracks of each decays plus 4 distributions of chi2 and 4 prob for primary, secondary,
+   ** ghost and all particles. **/
+  TH1F *hTrackParameters[nHistosTP]; 
+  
+  static const int nPVefficiency = 6; ///< Number of Efficiency plots for primary vertices for each category.
+  TProfile* hPVefficiency[4][nPVefficiency]; ///< Efficiency plots for primary vertices.
+  
+  TDirectory *fHistoDir; ///< ROOT directory with histograms.
+
+  bool IsCollectZRHistogram(int iParticle) const;
+  bool IsCollect3DHistogram(int iParticle) const;
+  bool IsCollectArmenteros(int iParticle) const;
+  
+ private:
+  const KFParticlePerformanceBase& operator = (const KFParticlePerformanceBase&); ///< Copying of objects of this class is forbidden.
+  KFParticlePerformanceBase(const KFParticlePerformanceBase&); ///< Copying of objects of this class is forbidden.
+  
+  void CreateFitHistograms(TH1F* histo[nFitQA], int iPart);
+  void CreateEfficiencyHistograms(TProfile* histo[3][nPartEfficiency], TProfile2D* histo2[3][nPartEfficiency2D]);
+  void CreateParameterHistograms(TH1F* histoParameters[KFPartEfficiencies::nParticles][nHistoPartParam],
+                                 TH2F *histoParameters2D[KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                                 TH3F *histoParameters3D[KFPartEfficiencies::nParticles][nHistoPartParam3D],
+                                 int iPart, bool drawZR = 0);
+  void CreateParameterSubfolder(TString folderName, 
+                                TH1F* histoParameters[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam],
+                                TH2F* histoParameters2D[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                                TH1F* histoFit[KFPartEfficiencies::nParticles][nFitQA], int iPart, bool withWrongPVHypothesis = 0);
+  
+  TString GetDirectoryPath();
+};
+
+#endif
+#endif //DO_TPCCATRACKER_EFF_PERFORMANCE
diff --git a/external/KFParticle/KFParticlePerformance/KFTopoPerformance.cxx b/external/KFParticle/KFParticlePerformance/KFTopoPerformance.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..21d387949c86d8d8d897137f57af4815496e84bd
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFTopoPerformance.cxx
@@ -0,0 +1,2179 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifdef DO_TPCCATRACKER_EFF_PERFORMANCE
+
+#include "KFTopoPerformance.h"
+
+#ifdef KFPWITHTRACKER
+#ifdef MAIN_DRAW
+#include "AliHLTTPCCADisplay.h"
+#endif //DRAW
+#include "AliHLTTPCCATracker.h"
+#include "AliHLTTPCCAPerformance.h"
+#endif
+
+#include "KFParticleTopoReconstructor.h"
+#include "KFParticleSIMD.h"
+#include "KFPHistogram/KFPHistogram.h"
+#include "TParticlePDG.h"
+#include "TDatabasePDG.h"
+
+#include "TMath.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TH3.h"
+#include "TProfile.h"
+#include "TProfile2D.h"
+
+#include <map>
+#include <algorithm>
+using std::sort;
+using std::vector;
+
+KFTopoPerformance::KFTopoPerformance():KFParticlePerformanceBase(),fTopoReconstructor(0),fPrimVertices(0), fMCTrackToMCPVMatch(0), 
+  fPVPurity(0), fNCorrectPVTracks(0), fTrackMatch(0), vMCTracks(0), vMCParticles(0), fNeutralIndex(0), MCtoRParticleId(0), RtoMCParticleId(0), 
+  MCtoRPVId(0), RtoMCPVId(0), fPrintEffFrequency(1), fCentralityBin(-1), fCentralityWeight(0.f)
+{
+}
+
+KFTopoPerformance::~KFTopoPerformance()
+{
+}
+
+#ifdef KFPWITHTRACKER
+void KFTopoPerformance::SetNewEvent(
+                            const AliHLTTPCCAGBTracker * const tracker,
+                            AliHLTResizableArray<AliHLTTPCCAHitLabel> *hitLabels,
+                            AliHLTResizableArray<AliHLTTPCCAMCTrack> *mcTracks,
+                            AliHLTResizableArray<AliHLTTPCCALocalMCPoint> *localMCPoints)
+{  
+  vMCTracks.resize(mcTracks->Size());
+  for(int iTr=0; iTr<vMCTracks.size(); iTr++)
+  {
+    for(int iP=0; iP<3; iP++)
+      vMCTracks[iTr].SetPar(iP, (*mcTracks)[iTr].Par(iP));
+    for(int iP=3; iP<6; iP++)
+      vMCTracks[iTr].SetPar(iP, (*mcTracks)[iTr].Par(iP) * (*mcTracks)[iTr].P());
+    vMCTracks[iTr].SetPar(6, (*mcTracks)[iTr].Par(6));
+    
+    vMCTracks[iTr].SetPDG( (*mcTracks)[iTr].PDG() );
+    vMCTracks[iTr].SetMotherId( (*mcTracks)[iTr].MotherId() );
+    vMCTracks[iTr].SetNMCPoints( (*mcTracks)[iTr].NMCPoints() );
+  } 
+} // void KFTopoPerformance::SetNewEvent
+#endif
+
+void KFTopoPerformance::SetTopoReconstructor( const KFParticleTopoReconstructor * const TopoReconstructor)
+{  
+  /** Sets a pointer to the external KFParticleTopoReconstructor object. */
+  fTopoReconstructor = TopoReconstructor;
+} // void KFTopoPerformance::SetTopoReconstructor
+
+void KFTopoPerformance::CheckMCTracks()
+{
+  /** Cleans Monte Carlo information on primary vertices, and refill it with the current event. */
+  fMCTrackToMCPVMatch.clear();
+  fPrimVertices.clear();
+
+    // find prim vertex
+  if (vMCTracks.size() <= 0) return;
+  
+  fMCTrackToMCPVMatch.resize(vMCTracks.size(),-1);
+  
+  vector<int> pvIndex;
+  for(unsigned int iTr=0; iTr<vMCTracks.size(); iTr++)
+  {
+    KFMCTrack &mctr = vMCTracks[iTr];
+    int motherID = mctr.MotherId();
+    if(motherID <0 )
+    {
+      bool newPV = 1;
+      for(unsigned int iPV=0; iPV<pvIndex.size(); iPV++)
+      {
+        if(motherID == pvIndex[iPV])
+        {
+          fPrimVertices[iPV].AddDaughterTrack(iTr);
+          fMCTrackToMCPVMatch[iTr] = iPV;
+          newPV = 0;
+        }
+      }
+      if(newPV)
+      {
+        KFMCVertex primVertex;
+        primVertex.SetX( mctr.X() );
+        primVertex.SetY( mctr.Y() );
+        primVertex.SetZ( mctr.Z() );
+        primVertex.AddDaughterTrack(iTr);
+        if(motherID == -1)
+          primVertex.SetTriggerPV();
+        fPrimVertices.push_back(primVertex);
+        fMCTrackToMCPVMatch[iTr] = pvIndex.size();
+        pvIndex.push_back(motherID);
+      }
+    }
+  }
+} // void KFTopoPerformance::CheckMCTracks()
+
+void KFTopoPerformance::GetMCParticles()
+{
+  /** Fills information on relations between Monte Carlo particles. */
+
+  vMCParticles.clear();
+  vMCParticles.reserve(vMCTracks.size());
+  // all MC tracks are copied into KF MC Particles
+  for(unsigned int iMC=0; iMC < vMCTracks.size(); iMC++)
+  {
+    KFMCTrack &mtra = vMCTracks[iMC];
+    KFMCParticle part;
+    part.SetMCTrackID( iMC );
+    part.SetMotherId ( mtra.MotherId() );
+    part.SetPDG      ( mtra.PDG() );
+    vMCParticles.push_back( part );
+  }
+  // find relations between mother and daughter MC particles
+  const int nMCParticles = vMCParticles.size();
+  for (int iP = 0; iP < nMCParticles; iP++ ) {
+    KFMCParticle &part = vMCParticles[iP];
+    int motherId = part.GetMotherId();
+    if(motherId < 0) continue;
+    if(motherId >= nMCParticles)
+    {
+      std::cout << "ERROR!!!!!  KF Particle Performance: MC track mother Id is out of range." << std::endl;
+      exit(1);
+    }
+    KFMCParticle &motherPart = vMCParticles[motherId];
+    motherPart.AddDaughter(iP);
+  }
+  
+  fNeutralIndex.clear();
+  fNeutralIndex.resize(nMCParticles, -1);
+  
+  for(unsigned int iMC=0; iMC < vMCParticles.size(); iMC++)
+  {
+    KFMCParticle &part = vMCParticles[iMC];
+    part.SetMCTrackID( iMC );
+  }
+  
+  const int NmmPDG = 7;
+  vector<int> mmMotherPDG(NmmPDG); //PDG for particles found by the missing mass method
+  vector<int> mmChargedDaughterPDG(NmmPDG);
+  vector<int> mmNeutralDaughterPDG(NmmPDG);
+  vector<int> newMotherPDG(NmmPDG);
+  vector<int> newNeutralPDG(NmmPDG);
+  
+  mmMotherPDG[ 0] = 3112; mmChargedDaughterPDG[ 0] =  211; mmNeutralDaughterPDG[ 0] = 2112;
+  mmMotherPDG[ 1] = 3222; mmChargedDaughterPDG[ 1] =  211; mmNeutralDaughterPDG[ 1] = 2112;
+  mmMotherPDG[ 2] = 3312; mmChargedDaughterPDG[ 2] =  211; mmNeutralDaughterPDG[ 2] = 3122;
+  mmMotherPDG[ 3] = 3334; mmChargedDaughterPDG[ 3] =  211; mmNeutralDaughterPDG[ 3] = 3322;
+  mmMotherPDG[ 4] =  321; mmChargedDaughterPDG[ 4] =  211; mmNeutralDaughterPDG[ 4] =  111;
+  mmMotherPDG[ 5] = 3334; mmChargedDaughterPDG[ 5] =  321; mmNeutralDaughterPDG[ 5] = 3122;
+  mmMotherPDG[ 6] = 3222; mmChargedDaughterPDG[ 6] = 2212; mmNeutralDaughterPDG[ 6] =  111;
+  
+  newMotherPDG[ 0] = 7003112; newNeutralPDG[ 0] = 7002112;
+  newMotherPDG[ 1] = 7003222; newNeutralPDG[ 1] = 8002112;
+  newMotherPDG[ 2] = 7003312; newNeutralPDG[ 2] = 7003122;
+  newMotherPDG[ 3] = 7003334; newNeutralPDG[ 3] = 7003322;
+  newMotherPDG[ 4] = 9000321; newNeutralPDG[ 4] = 9000111;
+  newMotherPDG[ 5] = 8003334; newNeutralPDG[ 5] = 8003122;
+  newMotherPDG[ 6] = 8003222; newNeutralPDG[ 6] = 8000111;
+    
+  //add neutrinos, if they are not saved
+  for(int iMC=0; iMC<nMCParticles; iMC++)
+  {
+    if( abs(vMCParticles[iMC].GetPDG()) == 211 || abs(vMCParticles[iMC].GetPDG()) == 321 )
+    {
+      int muonIndex = -1;
+      for(int iD=0; iD<vMCParticles[iMC].NDaughters(); iD++)
+        if( abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iD]].GetPDG()) == 13 )
+          muonIndex = vMCParticles[iMC].GetDaughterIds()[iD];
+
+      if(muonIndex > -1)
+      {
+        int newPDG = 0;
+        if(vMCParticles[iMC].GetPDG() >0)
+          newPDG = vMCParticles[iMC].GetPDG() + 7000000;
+        else
+          newPDG = vMCParticles[iMC].GetPDG() - 7000000;
+        KFMCParticle motherPart = vMCParticles[iMC];
+        KFMCTrack motherTrack = vMCTracks[motherPart.GetMCTrackID()];
+        motherTrack.SetPDG(newPDG);
+        motherTrack.SetNotReconstructed();
+        int newMotherIndex = vMCTracks.size();
+        motherPart.SetPDG(newPDG);
+        motherPart.SetMCTrackID(newMotherIndex);
+
+        const KFMCParticle& daughterPart = vMCParticles[muonIndex];
+        const KFMCTrack& daughterTrack = vMCTracks[daughterPart.GetMCTrackID()];
+
+        int neutrinoPDG = 7000014;
+        if(vMCParticles[iMC].GetPDG() == -211) neutrinoPDG = -7000014;
+        if(vMCParticles[iMC].GetPDG() ==  321) neutrinoPDG =  8000014;
+        if(vMCParticles[iMC].GetPDG() == -321) neutrinoPDG = -8000014;
+
+        int neutrinoIndex = vMCTracks.size()+1;
+        vMCParticles[iMC].AddDaughter(neutrinoIndex);
+        
+        fNeutralIndex[iMC] = neutrinoIndex;
+
+        KFMCParticle neutrinoPart;
+        KFMCTrack neutrinoTrack;
+        neutrinoTrack.SetX(daughterTrack.X());
+        neutrinoTrack.SetY(daughterTrack.Y());
+        neutrinoTrack.SetZ(daughterTrack.Z());
+        neutrinoTrack.SetPx(motherTrack.Px() - daughterTrack.Px());
+        neutrinoTrack.SetPy(motherTrack.Py() - daughterTrack.Py());
+        neutrinoTrack.SetPz(motherTrack.Pz() - daughterTrack.Pz());
+        neutrinoTrack.SetQP(0);
+        neutrinoTrack.SetMotherId(newMotherIndex);
+        neutrinoTrack.SetPDG(neutrinoPDG);
+
+        motherPart.CleanDaughters();
+        motherPart.AddDaughter(muonIndex);
+        motherPart.AddDaughter(neutrinoIndex);
+        motherPart.SetInitialParticleId(iMC);
+        vMCTracks.push_back(motherTrack);
+        vMCParticles.push_back(motherPart);
+        fNeutralIndex.push_back(-1);
+        
+        neutrinoPart.SetMCTrackID(neutrinoIndex);
+        neutrinoPart.SetMotherId(newMotherIndex);
+        neutrinoPart.SetPDG(neutrinoPDG);
+        neutrinoPart.AddDaughter(iMC);
+        neutrinoPart.AddDaughter(muonIndex);
+        vMCTracks.push_back(neutrinoTrack);
+        vMCParticles.push_back(neutrinoPart);
+        fNeutralIndex.push_back(-1);
+        
+        vMCParticles[iMC].SetAsReconstructable(4);
+        vMCParticles[muonIndex].SetAsReconstructable(4);
+      }
+    }
+    // add sigmas, omegas, xis ...
+    if( vMCParticles[iMC].NDaughters() >= 2 && 
+        (abs(vMCParticles[iMC].GetPDG()) == 3112 || 
+         abs(vMCParticles[iMC].GetPDG()) == 3222 || 
+         abs(vMCParticles[iMC].GetPDG()) == 3312 || 
+         abs(vMCParticles[iMC].GetPDG()) == 3334 || 
+         abs(vMCParticles[iMC].GetPDG()) ==  321) )
+    {
+      int neutralDaughterId = -1, chargedDaughterId = -1;
+
+      int newPDG = 0;
+      int neutralPDG = 0;
+
+      for(int iPDG=0; iPDG<NmmPDG; iPDG++)
+      {
+        if(abs(vMCParticles[iMC].GetPDG()) == mmMotherPDG[iPDG])
+        {
+          bool isDaughter[2] = {0,0};
+
+          vector<float> xDaughter;
+          vector<float> yDaughter;
+          vector<float> zDaughter;
+          vector< vector<int> > nDaughtersAtPoint;
+          
+          for(int iMCDaughter=0; iMCDaughter<vMCParticles[iMC].NDaughters(); iMCDaughter++)
+          {
+            bool isNewDecayPoint = 1;
+            
+            for(unsigned int iPoint=0; iPoint<xDaughter.size(); iPoint++)
+            {
+              float dx = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].X() - xDaughter[iPoint]);
+              float dy = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Y() - yDaughter[iPoint]);
+              float dz = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Z() - zDaughter[iPoint]);
+              
+              bool isSamePoint = (dx < 1.e-5 && dy < 1.e-5 && dz < 1.e-5);
+              if(isSamePoint)
+                nDaughtersAtPoint[iPoint].push_back(iMCDaughter);
+              
+              isNewDecayPoint &= !isSamePoint;
+            }
+            
+            if(isNewDecayPoint)
+            {
+              xDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].X());
+              yDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Y());
+              zDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Z());
+              vector<int> newPointIndex;
+              newPointIndex.push_back(iMCDaughter);
+              nDaughtersAtPoint.push_back(newPointIndex);
+            }
+          }
+          
+          for(unsigned int iPoint = 0; iPoint<nDaughtersAtPoint.size(); iPoint++)
+          {
+            if(nDaughtersAtPoint[iPoint].size() == 2)
+            {
+              for(unsigned int iDaughter=0; iDaughter<nDaughtersAtPoint[iPoint].size(); iDaughter++)
+              {
+                int iMCDaughter = nDaughtersAtPoint[iPoint][iDaughter];
+                if(abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].GetPDG()) == mmChargedDaughterPDG[iPDG])
+                {
+                  isDaughter[0] = 1;
+                  chargedDaughterId = vMCParticles[iMC].GetDaughterIds()[iMCDaughter];
+                }
+                if(abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].GetPDG()) == mmNeutralDaughterPDG[iPDG])
+                {
+                  isDaughter[1] = 1;
+                  neutralDaughterId = vMCParticles[iMC].GetDaughterIds()[iMCDaughter];
+                }
+              }
+              
+              if(isDaughter[0] && isDaughter[1])
+              {
+                int signPDG = vMCParticles[iMC].GetPDG()/abs(vMCParticles[iMC].GetPDG());
+                newPDG     = signPDG * newMotherPDG[iPDG];
+                neutralPDG = signPDG * newNeutralPDG[iPDG];
+              }
+            }
+          }
+        }
+      }
+
+      if(newPDG != 0)
+      {
+        KFMCParticle motherPart = vMCParticles[iMC];
+        KFMCTrack motherTrack = vMCTracks[motherPart.GetMCTrackID()];
+        motherTrack.SetPDG(newPDG);
+        motherTrack.SetNotReconstructed();
+        int newMotherIndex = vMCTracks.size();
+        motherPart.SetPDG(newPDG);
+        motherPart.SetMCTrackID(newMotherIndex);
+
+        int neutrinoIndex = vMCTracks.size()+1;
+        fNeutralIndex[iMC] = neutrinoIndex;
+        
+        KFMCTrack neutralTrack = vMCTracks[neutralDaughterId];
+        neutralTrack.SetMotherId(newMotherIndex);
+        neutralTrack.SetPDG(neutralPDG);
+
+        motherPart.CleanDaughters();
+        motherPart.AddDaughter(chargedDaughterId);
+        motherPart.AddDaughter(neutrinoIndex);
+        motherPart.SetInitialParticleId(iMC);
+        vMCTracks.push_back(motherTrack);
+        vMCParticles.push_back(motherPart);
+        fNeutralIndex.push_back(-1);
+        
+        KFMCParticle neutralPart;
+        neutralPart.SetMCTrackID(neutrinoIndex);
+        neutralPart.SetMotherId(newMotherIndex);
+        neutralPart.SetPDG(neutralPDG);
+        neutralPart.AddDaughter(iMC);
+        neutralPart.AddDaughter(chargedDaughterId);
+        vMCTracks.push_back(neutralTrack);
+        vMCParticles.push_back(neutralPart);
+        fNeutralIndex.push_back(-1);
+        
+        vMCParticles[iMC].SetAsReconstructable(4);
+        vMCParticles[chargedDaughterId].SetAsReconstructable(4);
+      }
+    }
+  }
+  
+  //clean Lambda c daughters
+  for(unsigned int iMC=0; iMC < vMCParticles.size(); iMC++)
+  {
+    KFMCParticle &part = vMCParticles[iMC];
+
+//     if(abs(part.GetPDG()) == 4122)
+    {
+      //add daughters into one pool
+      vector<int> newDaughters;
+      for(unsigned int iD=0; iD<part.GetDaughterIds().size(); iD++)
+      {
+        KFMCParticle &d = vMCParticles[part.GetDaughterIds()[iD]];
+        if( abs(d.GetPDG())==3224 || 
+            abs(d.GetPDG())==3114 || 
+            abs(d.GetPDG())==113  ||
+            abs(d.GetPDG())==313  ||
+            abs(d.GetPDG())==323  ||
+            abs(d.GetPDG())==2224 ||
+            abs(d.GetPDG())==2214 ||
+            abs(d.GetPDG())==2114 ||
+            abs(d.GetPDG())==1114
+          )
+        {
+          for(unsigned int iDaughter=0; iDaughter<d.GetDaughterIds().size(); iDaughter++)
+          {
+            newDaughters.push_back(d.GetDaughterIds()[iDaughter]);
+            vMCParticles[d.GetDaughterIds()[iDaughter]].SetMotherId(iMC);
+          }
+        }
+        else
+//         if(d.GetDaughterIds().size() == 0 || abs(d.GetPDG())==310 || abs(d.GetPDG())==3122)
+          newDaughters.push_back(part.GetDaughterIds()[iD]);
+      }
+      part.CleanDaughters();
+      for(unsigned int iDaughter=0; iDaughter<newDaughters.size(); iDaughter++)
+        part.AddDaughter(newDaughters[iDaughter]);
+      
+      //change PDG to separate channels
+      int indexPDG = fParteff.GetParticleIndex(part.GetPDG());
+      for(int iPDG=indexPDG; iPDG<indexPDG+10; iPDG++)
+      {
+        const int nDaughters = part.GetDaughterIds().size();
+        
+        if(int(fParteff.partDaughterPdg[iPDG].size()) != nDaughters)
+          continue;
+        
+        vector<bool> isDaughterFound(nDaughters);
+        vector<bool> isDaughterUsed(nDaughters);
+        for(int iDMC=0; iDMC<nDaughters; iDMC++)
+        {
+          isDaughterFound[iDMC] = 0;
+          isDaughterUsed[iDMC] = 0;
+        }
+        
+        bool isCorrectPDG = 1;
+        for(int iDMC=0; iDMC<nDaughters; iDMC++)
+          for(int iD=0; iD<nDaughters; iD++)
+          {
+            if(isDaughterUsed[iD]) continue;
+            if(vMCParticles[part.GetDaughterIds()[iD]].GetPDG() == fParteff.partDaughterPdg[iPDG][iDMC]) 
+            {
+              isDaughterUsed[iD] = 1;
+              isDaughterFound[iDMC] = 1;
+              break;
+            }
+          }
+
+        for(int iDMC=0; iDMC<nDaughters; iDMC++)
+          isCorrectPDG &= isDaughterFound[iDMC];
+        
+        if(isCorrectPDG)
+        {
+          part.SetPDG(fParteff.partPDG[iPDG]);
+          break;
+        }
+      }
+    }
+  }
+}
+
+void KFTopoPerformance::FindReconstructableMCParticles()
+{
+  /** Check each Monte Carlo particle if it can be reconstructed. */
+  const unsigned int nMCParticles = vMCParticles.size();
+
+  for ( unsigned int iP = 0; iP < nMCParticles; iP++ ) {
+    KFMCParticle &part = vMCParticles[iP];
+    CheckMCParticleIsReconstructable(part);
+  }
+}
+
+void KFTopoPerformance::CheckMCParticleIsReconstructable(KFMCParticle &part)
+{
+  /** Checks if the given Monte Carlo particle can be reconstructed. */
+  if ( part.IsReconstructable(0) ) return;
+  if ( vMCTracks[part.GetMCTrackID()].IsOutOfDetector() ) return;
+  
+  if( abs(part.GetPDG()) ==        211 ||
+      abs(part.GetPDG()) ==       2212 ||
+      abs(part.GetPDG()) ==        321 ||
+      abs(part.GetPDG()) ==         13 ||
+      abs(part.GetPDG()) ==       3112 ||
+      abs(part.GetPDG()) ==       3222 ||
+      abs(part.GetPDG()) ==       3312 ||
+      abs(part.GetPDG()) ==       3334 )
+  {
+    int iMCTrack = part.GetMCTrackID();
+    KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+
+    // reconstructable in 4pi is defined in GetMCParticles, when decay is found
+    if(mcTrack.IsReconstructed())
+      part.SetAsReconstructable(3);
+  }
+    // tracks
+  if ( abs(part.GetPDG()) ==        211 ||
+       abs(part.GetPDG()) ==       2212 ||
+       abs(part.GetPDG()) ==        321 ||
+       abs(part.GetPDG()) ==         11 ||
+       abs(part.GetPDG()) ==         13 ||
+       abs(part.GetPDG()) == 1000010020 ||
+       abs(part.GetPDG()) == 1000010030 ||
+       abs(part.GetPDG()) == 1000020030 ||
+       abs(part.GetPDG()) == 1000020040 ||
+       ( (part.GetPDG() == 22) && (vMCTracks[part.GetMCTrackID()].IsReconstructed()) ) )
+  {
+    int iMCTrack = part.GetMCTrackID();
+    KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+
+    part.SetAsReconstructable(0);
+
+    if(mcTrack.NMCPoints() >= 15)
+      part.SetAsReconstructable(1);   
+//     if(mc.IsReconstructable())
+//       part.SetAsReconstructable2();
+
+    if(mcTrack.IsReconstructed())
+      part.SetAsReconstructable(2);
+  }
+    //  mother particles
+  else
+  {
+    //Check if the particle is V0
+    
+    if(part.NDaughters() >= 2)
+    {
+      bool isPositiveDaughter[5] = {0,0,0,0,0};
+      bool isNegativeDaughter[5] = {0,0,0,0,0};
+      
+      int nRecoDaughters[5] = {0,0,0,0,0};
+      
+      for(int iD=0; iD < part.NDaughters(); iD++)
+      {
+        KFMCParticle &daughter = vMCParticles[part.GetDaughterIds()[iD]];
+        CheckMCParticleIsReconstructable(daughter);
+        
+        TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(daughter.GetPDG());
+        Double_t charge = (particlePDG) ? particlePDG->Charge()/3 : 0;
+        
+        for(int iEff=0; iEff<5; iEff++)
+        {
+          if(charge > 0)
+            isPositiveDaughter[iEff] |= daughter.IsReconstructable(iEff);
+          else
+            isNegativeDaughter[iEff] |= daughter.IsReconstructable(iEff);
+          
+          if(daughter.IsReconstructable(iEff))
+            nRecoDaughters[iEff]++;
+        }
+      }
+      
+//       for(int iEff=0; iEff<3; iEff++)
+//         if(isPositiveDaughter[iEff] && isNegativeDaughter[iEff])
+//           part.SetAsReconstructableV0(iEff);
+      for(int iEff=0; iEff<3; iEff++)
+        if(nRecoDaughters[iEff] > 1)
+          part.SetAsReconstructableV0(iEff);
+    }
+    
+    for(int iPart=0; iPart<fParteff.nParticles; iPart++)
+    {
+      if(part.GetPDG() == fParteff.partPDG[iPart])
+      {
+        const unsigned int nDaughters = fParteff.partDaughterPdg[iPart].size();
+        if( part.GetDaughterIds().size() != nDaughters ) return;
+        vector<int> pdg(nDaughters);
+
+        for(unsigned int iD=0; iD<nDaughters; iD++)
+          pdg[iD] = vMCParticles[part.GetDaughterIds()[iD]].GetPDG();
+
+        vector<bool> isDaughterFound(nDaughters);
+        for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
+          isDaughterFound[iDMC] = 0;
+
+        bool isReco = 1;
+        for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
+          for(unsigned int iD=0; iD<nDaughters; iD++)
+            if(pdg[iD] == fParteff.partDaughterPdg[iPart][iDMC]) isDaughterFound[iDMC] = 1;
+
+        for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
+          isReco = isReco && isDaughterFound[iDMC];
+
+        if(!isReco) return;
+      }
+    }
+
+    const vector<int>& dIds = part.GetDaughterIds();
+    const unsigned int nD = dIds.size();
+    if(nD == 0) return; //TODO optimize for all species
+    
+    bool reco1 = 1;
+    bool reco2 = 1;
+    bool reco3 = 1;
+    bool reco4 = 1;
+    bool reco5 = 1;
+      
+    for ( unsigned int iD = 0; iD < nD && (reco1 || reco2 || reco3 || reco4 || reco5); iD++ ) {
+      KFMCParticle &dp = vMCParticles[dIds[iD]];
+      CheckMCParticleIsReconstructable(dp);
+      reco1 &= dp.IsReconstructable(0);
+      reco2 &= dp.IsReconstructable(1);
+      reco3 &= dp.IsReconstructable(2);
+      reco4 &= dp.IsReconstructable(3);
+      reco5 &= dp.IsReconstructable(4);
+    }
+    
+    if (reco1) part.SetAsReconstructable(0);
+    if (reco2) part.SetAsReconstructable(1);
+    if (reco3) part.SetAsReconstructable(2);
+    int iParticle = fParteff.GetParticleIndex(part.GetPDG());
+    if (reco4 && iParticle>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
+                 iParticle<=KFPartEfficiencies::fLastMissingMassParticleIndex ) part.SetAsReconstructable(3);
+    if (reco5 && iParticle>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
+                 iParticle<=KFPartEfficiencies::fLastMissingMassParticleIndex ) part.SetAsReconstructable(4);
+  }
+}
+
+
+void KFTopoPerformance::FindReconstructableMCVertices()
+{
+  /** Checks which Monte Carlo primary vertices can be reconstructed. */
+  const unsigned int nMCVertices = fPrimVertices.size();
+
+  for ( unsigned int iV = 0; iV < nMCVertices; iV++ ) {
+    KFMCVertex &vert = fPrimVertices[iV];
+        
+    int nReconstructableDaughters = 0;
+    int nMCReconstructableDaughters = 0;
+
+    for(int iP=0; iP<vert.NDaughterTracks(); iP++)
+    {
+      int idDaughter = vert.DaughterTrack(iP);
+      KFMCParticle &part = vMCParticles[idDaughter];
+      
+      if(part.IsReconstructable(2)) nReconstructableDaughters++;
+      if(part.IsReconstructable(1)) nMCReconstructableDaughters++;
+    }
+    
+    if(nReconstructableDaughters >= 2) vert.SetReconstructable();
+    else vert.SetUnReconstructable();
+    
+    if(nMCReconstructableDaughters >= 2) vert.SetMCReconstructable();
+    else vert.SetMCUnReconstructable();
+  }
+}
+
+void KFTopoPerformance::MatchParticles()
+{
+  /** Matches Monte Carlo and reconstructed particles. */
+  MCtoRParticleId.clear();
+  RtoMCParticleId.clear();
+  MCtoRParticleId.resize(vMCParticles.size());
+  RtoMCParticleId.resize(fTopoReconstructor->GetParticles().size() );
+
+  // match tracks ( particles which are direct copies of tracks )
+  for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) 
+  {
+    const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
+
+    if (rPart.NDaughters() != 1) continue;
+
+    const int rTrackId = rPart.DaughterIds()[0];
+    const int mcTrackId = fTrackMatch[rTrackId];
+
+    if(mcTrackId < 0) continue;
+
+    KFMCParticle &mPart = vMCParticles[mcTrackId];
+    if( mPart.GetPDG() == rPart.GetPDG() ) 
+    {
+      MCtoRParticleId[mcTrackId].ids.push_back(iRP);
+      RtoMCParticleId[iRP].ids.push_back(mcTrackId);
+    }
+    else {
+      MCtoRParticleId[mcTrackId].idsMI.push_back(iRP);
+      RtoMCParticleId[iRP].idsMI.push_back(mcTrackId);
+    }
+  }
+
+  // match created mother particles
+  for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) {
+    const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
+    const unsigned int NRDaughters = rPart.NDaughters();
+    
+    if (NRDaughters < 2) continue;
+
+    bool isMissingMass = ((abs(rPart.GetPDG()) == 7000211)||(abs(rPart.GetPDG()) == 7000321)||(abs(rPart.GetPDG()) == 7003112) || (abs(rPart.GetPDG()) == 7003222)|| (abs(rPart.GetPDG()) == 7003312)|| (abs(rPart.GetPDG()) == 7003334)|| (abs(rPart.GetPDG()) == 9000321)|| (abs(rPart.GetPDG()) == 8003334)||(abs(rPart.GetPDG()) == 8003222));
+    
+    //missing mass method
+    if ( (abs(rPart.GetPDG()) == 7000014 ) || (abs(rPart.GetPDG()) == 8000014 ) || (abs(rPart.GetPDG()) == 7002112 ) ||
+         (abs(rPart.GetPDG()) == 8002112 ) || (abs(rPart.GetPDG()) == 7003122 ) || (abs(rPart.GetPDG()) == 7003322 ) ||
+         (abs(rPart.GetPDG()) == 9000111 ) || (abs(rPart.GetPDG()) == 8003122 ) || (abs(rPart.GetPDG()) == 8000111 ) )
+    {
+      //During the reconstruction 1st daughter - mother particle, 2nd daughter - charged daughter
+
+      int mcNeutralDaughterId = -1;
+      const int recoMotherId = rPart.DaughterIds()[0];
+      if ( !RtoMCParticleId[recoMotherId].IsMatched() ) continue;
+
+      const int mcMotherId = RtoMCParticleId[recoMotherId].GetBestMatch();
+      
+      const int recoChargedDaughterId = rPart.DaughterIds()[1];
+      if ( !RtoMCParticleId[recoChargedDaughterId].IsMatched() ) continue;
+
+      const int mcChargedDaughterId = RtoMCParticleId[recoChargedDaughterId].GetBestMatch();
+      const KFMCParticle& chargedDaughter = vMCParticles[mcChargedDaughterId];
+
+      if(chargedDaughter.GetMotherId() != mcMotherId) continue;
+      const KFMCParticle& mother = vMCParticles[mcMotherId];
+
+      if(fNeutralIndex[mcMotherId] > -1)
+        mcNeutralDaughterId = fNeutralIndex[mcMotherId];
+
+      if(mcNeutralDaughterId > -1)
+      {
+        KFMCParticle &neutralDaughter = vMCParticles[mcNeutralDaughterId];
+        
+        int iParticle = fParteff.GetParticleIndex(rPart.GetPDG());
+        
+        bool allCorrectDaughters = mother.GetPDG()          == fParteff.partDaughterPdg[iParticle][0] &&
+                                   chargedDaughter.GetPDG() == fParteff.partDaughterPdg[iParticle][1];
+
+        if( neutralDaughter.GetPDG()     == rPart.GetPDG()     &&
+            neutralDaughter.NDaughters() == rPart.NDaughters() &&
+            allCorrectDaughters) {
+          MCtoRParticleId[mcNeutralDaughterId].ids.push_back(iRP);
+          RtoMCParticleId[iRP].ids.push_back(mcNeutralDaughterId);
+        }
+        else {
+          MCtoRParticleId[mcNeutralDaughterId].idsMI.push_back(iRP);
+          RtoMCParticleId[iRP].idsMI.push_back(mcNeutralDaughterId);
+        }
+      }
+    }
+    
+    
+    
+    //normal decays
+    else
+    {
+      unsigned int iD = 0;
+      vector<int> mcDaughterIds;
+      int mmId = -2; // MC id for rPart
+      {
+        const int rdId = rPart.DaughterIds()[iD];
+        if ( !RtoMCParticleId[rdId].IsMatched() ) continue;
+        const int mdId = RtoMCParticleId[rdId].GetBestMatch();
+        mcDaughterIds.push_back(mdId);
+        mmId = vMCParticles[mdId].GetMotherId();
+      }
+      
+      iD++;
+      for ( ; iD < NRDaughters; iD++ ) {
+        const int rdId = rPart.DaughterIds()[iD];
+        if ( !RtoMCParticleId[rdId].IsMatched() ) break;
+        const int mdId = RtoMCParticleId[rdId].GetBestMatch();
+        mcDaughterIds.push_back(mdId);
+
+        if(isMissingMass)
+        {
+          const KFMCParticle &neutralDaughter = vMCParticles[mdId];
+          if(mmId != vMCParticles[neutralDaughter.GetMotherId()].InitialParticleId()) break;
+          mmId = neutralDaughter.GetMotherId();
+        }
+        
+        if( !(isMissingMass) && (vMCParticles[mdId].GetMotherId() != mmId) ) break;
+      }
+      
+      int nClones = 0;
+      sort(mcDaughterIds.begin(), mcDaughterIds.end());
+      for(unsigned int ie=1; ie<mcDaughterIds.size(); ie++)
+      {
+        if(mcDaughterIds[ie] == mcDaughterIds[ie-1])
+          nClones++;
+      }
+
+      if(nClones > 0) continue;
+      
+      if ( iD == NRDaughters && mmId > -1 ) { // match is found and it is not primary vertex
+        KFMCParticle &mmPart = vMCParticles[mmId];
+        
+        if( mmPart.GetPDG()     == rPart.GetPDG()     &&
+            mmPart.NDaughters() == rPart.NDaughters() ) {
+          MCtoRParticleId[mmId].ids.push_back(iRP);
+          RtoMCParticleId[iRP].ids.push_back(mmId);        
+        }
+        else {
+          MCtoRParticleId[mmId].idsMI.push_back(iRP);
+          RtoMCParticleId[iRP].idsMI.push_back(mmId);
+        }
+      }
+    }
+  }
+}
+
+void KFTopoPerformance::MatchPV()
+{
+  /** Matches Monte Carlo and reconstructed primary vertices. */
+  MCtoRPVId.clear();
+  RtoMCPVId.clear();
+  MCtoRPVId.resize(fPrimVertices.size());
+  RtoMCPVId.resize(fTopoReconstructor->NPrimaryVertices() );
+
+  fPVPurity.clear();
+  fPVPurity.resize(fTopoReconstructor->NPrimaryVertices(), 0.);
+  fNCorrectPVTracks.clear();
+  fNCorrectPVTracks.resize(fTopoReconstructor->NPrimaryVertices(), 0);
+
+  for(int iE = 0; iE<4; iE++)
+  {
+    fPVTracksRate[iE].clear();
+    fPVTracksRate[iE].resize(fTopoReconstructor->NPrimaryVertices(),0);
+  }
+  
+  for( unsigned int iMCPV=0; iMCPV<fPrimVertices.size(); iMCPV++)
+  {
+    KFMCVertex &mcPV = fPrimVertices[iMCPV];
+    int nReconstructedDaughters = 0;
+    for(int iD=0; iD<mcPV.NDaughterTracks(); iD++)
+      if(MCtoRParticleId[ mcPV.DaughterTrack(iD) ].IsMatched())
+        nReconstructedDaughters++;
+    
+    mcPV.SetNReconstructedDaughters(nReconstructedDaughters);
+  }
+
+  for( int iPV = 0; iPV < fTopoReconstructor->NPrimaryVertices(); iPV++ ) {
+
+    vector<int> &tracks = fTopoReconstructor->GetPVTrackIndexArray(iPV);
+    
+    int nPVTracks = tracks.size()>0 ? tracks.size() : -1;//tracks.size();
+    
+    vector<short int> nTracksFromMCPV(fPrimVertices.size() + vMCParticles.size(), 0);
+    vector< vector<int> > mcIDs(fPrimVertices.size() + vMCParticles.size());
+
+    int nGhostTracks = 0;
+    int nTriggerTracks = 0;
+    int nPileupTracks = 0;
+    int nBGTracks = 0;
+        
+    for(int iRP=0; iRP < nPVTracks; iRP++)
+    {
+      const int rTrackId = tracks[iRP];
+      if ( !RtoMCParticleId[rTrackId].IsMatched() )
+      {
+        nGhostTracks++;
+        continue;
+      }
+            
+      int iMCPart = RtoMCParticleId[rTrackId].GetBestMatch();
+      KFMCParticle &mcPart = vMCParticles[iMCPart];
+      int iMCTrack = mcPart.GetMCTrackID();
+      KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+      
+      int motherId = mcTrack.MotherId();
+
+      if(motherId < 0) //real PV
+      {
+        if(motherId == -1)
+          nTriggerTracks++;
+        if(motherId < -1)
+          nPileupTracks++;
+        
+        int iMCPV = fMCTrackToMCPVMatch[iMCTrack];
+        if(iMCPV < 0)
+        {
+          std::cout << "Error!!!  iMCPV < 0" << std::endl;
+          continue;
+        }
+      
+        nTracksFromMCPV[iMCPV]++;
+        mcIDs[iMCPV].push_back(iMCTrack);
+      }
+      else // pchysics background
+      {        
+        if(motherId >-1)
+        {
+          nBGTracks++;
+
+          int iMCPV = motherId + fPrimVertices.size();
+      
+          nTracksFromMCPV[iMCPV]++;
+          mcIDs[iMCPV].push_back(iMCTrack);
+        }
+      }
+    }
+    
+
+
+    for(unsigned int iMCPV=0; iMCPV<nTracksFromMCPV.size(); iMCPV++)
+    {
+      int nClones = 0;
+      sort(mcIDs[iMCPV].begin(), mcIDs[iMCPV].end());
+      for(unsigned int ie=1; ie<mcIDs[iMCPV].size(); ie++)
+      {
+        if(mcIDs[iMCPV][ie] == mcIDs[iMCPV][ie-1])
+          nClones++;
+      }
+      nTracksFromMCPV[iMCPV] = nTracksFromMCPV[iMCPV] - nClones;
+      nPVTracks -= nClones;
+    }
+
+    // calculate rate of each type of tracks in reconstructed PV
+    fPVTracksRate[0][iPV] = double(nGhostTracks)/double(nPVTracks);
+    fPVTracksRate[1][iPV] = double(nTriggerTracks)/double(nPVTracks);
+    fPVTracksRate[2][iPV] = double(nPileupTracks)/double(nPVTracks);
+    fPVTracksRate[3][iPV] = double(nBGTracks)/double(nPVTracks);
+
+    int iBestMCPV=-1;
+    int nTracksBestMCPV = 1;
+    for(unsigned int iMCPV=0; iMCPV<nTracksFromMCPV.size(); iMCPV++ )
+    {
+      if(nTracksFromMCPV[iMCPV] > nTracksBestMCPV )
+      {
+        nTracksBestMCPV = nTracksFromMCPV[iMCPV];
+        iBestMCPV = iMCPV;
+      }
+    }
+
+    if( (iBestMCPV > -1) && (iBestMCPV<int(fPrimVertices.size())) )
+    {
+      fNCorrectPVTracks[iPV] = nTracksFromMCPV[iBestMCPV];
+    }
+    else
+      fNCorrectPVTracks[iPV] = 0;
+    
+    double purity = double(nTracksBestMCPV)/double(nPVTracks);
+
+    fPVPurity[iPV] = purity;
+//     if(purity < 0.7) continue;
+
+    if(iBestMCPV < 0) continue;
+    
+    if(iBestMCPV < int(fPrimVertices.size()))
+    {
+      fPrimVertices[iBestMCPV].SetReconstructed();
+    
+      MCtoRPVId[iBestMCPV].ids.push_back(iPV);
+      RtoMCPVId[iPV].ids.push_back(iBestMCPV);
+    }
+    else
+    {
+      RtoMCPVId[iPV].idsMI.push_back(iBestMCPV);
+    }
+  }
+}
+
+void KFTopoPerformance::MatchTracks()
+{
+  /** Runs reading of Monte Carlo particles and vertices, their matching, calculation of efficiency. */
+#ifdef KFPWITHTRACKER
+  for(int iTr=0; iTr<vMCTracks.size(); iTr++)
+  {
+    if( (AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetMCData())[iTr].IsReconstructed() )
+      vMCTracks[iTr].SetReconstructed();
+  } 
+  fTrackMatch.resize(AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetRecoData().size());
+  for(int iTr=0; iTr<fTrackMatch.size(); iTr++)
+  {
+    const AliHLTTPCCAPerformanceRecoTrackData& matchInfo = (AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetRecoData())[iTr];
+    if( matchInfo.IsGhost(PParameters::MinTrackPurity) || matchInfo.GetMCTrackId()<0  )
+      fTrackMatch[iTr] = -1;
+    else
+      fTrackMatch[iTr] = matchInfo.GetMCTrackId();
+  }
+#endif
+
+  GetMCParticles();
+  FindReconstructableMCParticles();
+  MatchParticles();
+  CalculateEfficiency();
+  
+  FindReconstructableMCVertices();
+  MatchPV();
+  CalculatePVEfficiency();
+} // void KFTopoPerformance::MatchTracks()
+
+void KFTopoPerformance::CalculateEfficiency()
+{
+  /** Calculates reconstruction efficiency of short-lived particles. */
+  KFPartEfficiencies partEff; // efficiencies for current event
+
+  const int NRP = fTopoReconstructor->GetParticles().size();
+  for ( int iP = 0; iP < NRP; ++iP ) {
+//    const CbmKFParticle &part = fPF->GetParticles()[iP];
+    const KFParticle &part = fTopoReconstructor->GetParticles()[iP];
+    const int pdg = part.GetPDG();
+
+    const bool isBG = RtoMCParticleId[iP].idsMI.size() != 0;
+    const bool isGhost = !RtoMCParticleId[iP].IsMatched();
+
+    for(int iPart=0; iPart<fParteff.nParticles; iPart++)
+      if ( pdg == fParteff.partPDG[iPart] )
+        partEff.IncReco(isGhost, isBG, fParteff.partName[iPart].data());
+    
+    // Calculate the gost level for V0
+    if(abs(pdg) == 310  /*||
+       CAMath::Abs(pdg) == 3122 ||
+       CAMath::Abs(pdg) == 421  ||
+       CAMath::Abs(pdg) == 22 */)
+    {
+      partEff.IncReco(isGhost, 0, fParteff.partName[fParteff.nParticles - 1].data());
+    }
+  }
+
+  const int NMP = vMCParticles.size();
+  for ( int iP = 0; iP < NMP; ++iP ) {
+    const KFMCParticle &part = vMCParticles[iP];
+    const int pdg = part.GetPDG();
+    const int mId = part.GetMotherId();
+    
+    vector<bool> isReco;
+    vector<int> nClones;
+
+    vector<int> iParticle;
+    iParticle.push_back(fParteff.GetParticleIndex(pdg));
+    vector< vector<bool> > isReconstructable;
+    vector<bool> isRecPart;
+
+    const std::map<int,bool>& decays = fTopoReconstructor->GetKFParticleFinder()->GetReconstructionList();
+    if(!(decays.empty()) && (iParticle[0] < fParteff.fFirstStableParticleIndex || iParticle[0] > fParteff.fLastStableParticleIndex))
+      if(decays.find(pdg) == decays.end()) continue;
+        
+    if( fParteff.GetParticleIndex(pdg)>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
+        fParteff.GetParticleIndex(pdg)<=KFPartEfficiencies::fLastMissingMassParticleIndex )
+    {
+      isRecPart.push_back(part.IsReconstructable(4));
+      isRecPart.push_back(part.IsReconstructable(1));
+      isRecPart.push_back(part.IsReconstructable(3));
+    }
+    else
+      for(int iEff = 0; iEff < 3; iEff++)
+        isRecPart.push_back(part.IsReconstructable(iEff));
+    
+    isReconstructable.push_back(isRecPart);
+    isReco.push_back( MCtoRParticleId[iP].ids.size() != 0 );
+    nClones.push_back( MCtoRParticleId[iP].ids.size() - 1 );
+    
+    if(decays.empty() && (part.IsReconstructableV0(0) || part.IsReconstructableV0(1) || part.IsReconstructableV0(2)) )
+    {
+      iParticle.push_back(fParteff.nParticles - 1);
+      vector<bool> isRecV0;
+      for(int iEff = 0; iEff < 3; iEff++)
+        isRecV0.push_back(part.IsReconstructableV0(iEff));
+      isReconstructable.push_back(isRecV0);
+      isReco.push_back( (MCtoRParticleId[iP].ids.size() != 0) || (MCtoRParticleId[iP].idsMI.size() != 0) );
+      
+      int nClonesV0 = MCtoRParticleId[iP].ids.size() + MCtoRParticleId[iP].idsMI.size() - 1;
+      nClones.push_back( nClonesV0 );
+    }
+
+    {
+      for(unsigned int iPType=0; iPType<iParticle.size(); iPType++)
+      {
+        int iPart = iParticle[iPType];
+        if(iPart<0) continue;
+          
+        partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], fParteff.partName[iPart].data());
+        if ( mId == -1 )
+          partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], (fParteff.partName[iPart]+"_prim").data());
+        else
+          partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], (fParteff.partName[iPart]+"_sec").data());
+        
+        for(int iEff=0; iEff<3; iEff++)
+        {
+          if(!isReconstructable[iPType][iEff]) continue;
+          
+          int iMCTrack = part.GetMCTrackID();
+          KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+          
+          Double_t massMC = fParteff.partMass[iPart];
+          Double_t E = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
+          Double_t Y = 0.5*log((E + mcTrack.Pz())/(E - mcTrack.Pz()));
+          Double_t Z = mcTrack.Z();
+          Double_t R = -1, L=-1;
+          Double_t Mt_mc = sqrt(mcTrack.Pt()*mcTrack.Pt()+massMC*massMC)-massMC;
+          Double_t cT = -1.e10;
+          Double_t decayLength = -1.e10;
+          
+          if(part.NDaughters() > 0)
+          {
+            int mcDaughterId = part.GetDaughterIds()[0];
+            KFMCTrack &mcDaughter = vMCTracks[mcDaughterId];
+            R = sqrt(mcDaughter.X()*mcDaughter.X() + mcDaughter.Y()*mcDaughter.Y());
+            L = sqrt(mcDaughter.X()*mcDaughter.X() + mcDaughter.Y()*mcDaughter.Y());
+            Z = mcDaughter.Z();
+            
+            if(mcTrack.MotherId() < 0)
+            {
+              KFParticle motherKFParticle;
+              float decayPoint[3] = { mcDaughter.X(), mcDaughter.Y(), mcDaughter.Z() };
+              for(int iP=0; iP<6; iP++)
+                motherKFParticle.Parameter(iP) = mcTrack.Par()[iP];
+              
+              float dsdr[6];
+              double s = motherKFParticle.GetDStoPoint(decayPoint, dsdr);
+              int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
+              Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
+              
+              cT = s*massMC;
+              decayLength = s*mcTrack.P();
+            }
+          }
+
+          if(fStoreMCHistograms)
+          {
+            hPartEfficiency[iPart][iEff][0]->Fill( mcTrack.P(), isReco[iPType] );
+            hPartEfficiency[iPart][iEff][1]->Fill( mcTrack.Pt(), isReco[iPType] );
+            hPartEfficiency[iPart][iEff][2]->Fill( Y, isReco[iPType] );
+            hPartEfficiency[iPart][iEff][3]->Fill( Z, isReco[iPType] );
+            if(cT > -1.e10)          hPartEfficiency[iPart][iEff][4]->Fill( cT, isReco[iPType] );
+            if(decayLength > -1.e10) hPartEfficiency[iPart][iEff][5]->Fill( decayLength, isReco[iPType] );
+            hPartEfficiency[iPart][iEff][3]->Fill( Z, isReco[iPType] );
+            hPartEfficiency[iPart][iEff][6]->Fill( L, isReco[iPType] );
+            hPartEfficiency[iPart][iEff][7]->Fill( R, isReco[iPType] );
+            hPartEfficiency[iPart][iEff][8]->Fill( Mt_mc, isReco[iPType] );
+            
+            hPartEfficiency2D[iPart][iEff][0]->Fill( Y, mcTrack.Pt(), isReco[iPType] );
+            hPartEfficiency2D[iPart][iEff][1]->Fill( Y, Mt_mc, isReco[iPType] );
+          }
+        }
+      }
+    }
+  }
+
+  fNEvents++;
+
+  fParteff += partEff;
+
+  partEff.CalcEff();
+  fParteff.CalcEff();
+
+  if(fNEvents%fPrintEffFrequency == 0)
+  {
+    std::cout << " ---- KF Particle finder --- " << std::endl;
+    std::cout << "ACCUMULATED STAT    : " << fNEvents << " EVENTS "               << std::endl << std::endl;
+    fParteff.PrintEff();
+    std::cout<<std::endl;
+  }
+}
+
+void KFTopoPerformance::CalculatePVEfficiency()
+{
+  /** Calculates reconstruction efficiency of primary vertices. */
+  KFPVEfficiencies pvEff; // efficiencies for current event
+  KFPVEfficiencies pvEffMCReconstructable;
+  int nTracks = 0;
+  //calculate N reco tracks
+  for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) {
+//    CbmKFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
+    const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
+
+    if (rPart.NDaughters() != 1) continue;
+    
+    nTracks++;
+  }
+    
+  const int NRecoPV = fTopoReconstructor->NPrimaryVertices();
+  for ( int iP = 0; iP < NRecoPV; ++iP ) {
+      
+    const bool isBG = RtoMCPVId[iP].idsMI.size() != 0;
+    const bool isGhost = !RtoMCPVId[iP].IsMatched();
+
+    pvEff.IncReco(isGhost, isBG, "PV");
+    pvEffMCReconstructable.IncReco(isGhost, isBG, "PV");
+  }
+
+  const int NMCPV = fPrimVertices.size();
+  for ( int iV = 0; iV < NMCPV; ++iV ) {
+    const KFMCVertex &pvMC = fPrimVertices[iV];
+    if ( pvMC.IsReconstructable() ) 
+    {
+      const bool isReco = pvMC.IsReconstructed();
+      const int nClones = MCtoRPVId[iV].ids.size() - 1;
+
+        
+      pvEff.Inc(isReco, nClones, "PV");
+      if ( pvMC.IsTriggerPV() )
+      {
+        pvEff.Inc(isReco, nClones, "PVtrigger");
+        hPVefficiency[0][0]->Fill( pvMC.NDaughterTracks(), isReco );
+        hPVefficiency[0][1]->Fill( NMCPV, isReco );
+        hPVefficiency[0][2]->Fill( vMCTracks.size(), isReco );
+        hPVefficiency[0][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
+        hPVefficiency[0][4]->Fill( NRecoPV, isReco );
+        hPVefficiency[0][5]->Fill( nTracks, isReco );
+      }
+      else
+      {
+        pvEff.Inc(isReco, nClones, "PVpileup");
+        hPVefficiency[1][0]->Fill( pvMC.NDaughterTracks(), isReco );
+        hPVefficiency[1][1]->Fill( NMCPV, isReco );
+        hPVefficiency[1][2]->Fill( vMCTracks.size(), isReco );
+        hPVefficiency[1][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
+        hPVefficiency[1][4]->Fill( NRecoPV, isReco );
+        hPVefficiency[1][5]->Fill( nTracks, isReco );
+      }
+    }
+    if ( pvMC.IsMCReconstructable() ) 
+    {
+      const bool isReco = pvMC.IsReconstructed();
+      const int nClones = MCtoRPVId[iV].ids.size() - 1;
+
+        
+      pvEffMCReconstructable.Inc(isReco, nClones, "PV");
+      if ( pvMC.IsTriggerPV() )
+      {
+        pvEffMCReconstructable.Inc(isReco, nClones, "PVtrigger");
+        hPVefficiency[2][0]->Fill( pvMC.NDaughterTracks(), isReco );
+        hPVefficiency[2][1]->Fill( NMCPV, isReco );
+        hPVefficiency[2][2]->Fill( vMCTracks.size(), isReco );
+        hPVefficiency[2][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
+        hPVefficiency[2][4]->Fill( NRecoPV, isReco );
+        hPVefficiency[2][5]->Fill( nTracks, isReco );
+      }
+      else
+      {
+        pvEffMCReconstructable.Inc(isReco, nClones, "PVpileup");
+        hPVefficiency[3][0]->Fill( pvMC.NDaughterTracks(), isReco );
+        hPVefficiency[3][1]->Fill( NMCPV, isReco );
+        hPVefficiency[3][2]->Fill( vMCTracks.size(), isReco );
+        hPVefficiency[3][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
+        hPVefficiency[3][4]->Fill( NRecoPV, isReco );
+        hPVefficiency[3][5]->Fill( nTracks, isReco );
+      }
+    }
+  }
+
+  fPVeff += pvEff;
+  
+  pvEff.CalcEff();
+  fPVeff.CalcEff();
+  
+  fPVeffMCReconstructable += pvEffMCReconstructable;
+  pvEffMCReconstructable.CalcEff();
+  fPVeffMCReconstructable.CalcEff();
+
+  if(fNEvents%fPrintEffFrequency == 0)
+  {
+    std::cout << " ---- KF PV finder --- " << std::endl;
+    std::cout << "ACCUMULATED STAT    : " << fNEvents << " EVENTS "               << std::endl << std::endl;
+    std::cout << "PV with at least 2 reconstructed tracks is reconstructable:" << std::endl;
+    fPVeff.PrintEff();
+    std::cout << std::endl;
+    std::cout << "PV with at least 2 MC tracks with 15 MC points is reconstructable:" << std::endl;
+    fPVeffMCReconstructable.PrintEff();
+
+    std::cout<<std::endl;
+  }
+}
+
+void KFTopoPerformance::FillParticleParameters(KFParticle& TempPart,
+                                               int iParticle,
+                                               int iP,
+                                               int iPV,
+                                               TH1F* histoParameters[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam],
+                                               TH2F* histoParameters2D[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                                               TH3F* histoParameters3D[1][KFPartEfficiencies::nParticles][nHistoPartParam3D],
+                                               TH1F* histoFit[KFPartEfficiencies::nParticles][nFitQA],
+                                               TH1F* histoFitDaughtersQA[KFPartEfficiencies::nParticles][nFitQA],
+                                               TH1F* histoDSToParticleQA[KFPartEfficiencies::nParticles][nDSToParticleQA],
+                                               vector<int>* multiplicities)
+{
+  /** Fills provided histograms with the parameters of the given particle. */
+  
+  const std::map<int,bool>& decays = fTopoReconstructor->GetKFParticleFinder()->GetReconstructionList();
+  if(!(decays.empty()) && (iParticle < fParteff.fFirstStableParticleIndex || iParticle > fParteff.fLastStableParticleIndex))
+    if(decays.find(TempPart.GetPDG()) == decays.end()) return;
+    
+  float M, M_t, ErrM;
+  float dL, ErrdL; // decay length
+  float cT, ErrcT; // c*tau
+  float P, ErrP;
+  float Pt;
+  float Rapidity;
+  float Theta;
+  float Phi;
+  float X,Y,Z,R;
+  float QtAlpha[2];
+    
+  TempPart.GetMass(M,ErrM);
+  TempPart.GetMomentum(P,ErrP);
+  Pt = TempPart.GetPt();
+  Rapidity = TempPart.GetRapidity();
+  
+  KFParticle TempPartTopo = TempPart;
+  TempPartTopo.SetProductionVertex(fTopoReconstructor->GetPrimVertex(0));
+  TempPartTopo.GetDecayLength(dL,ErrdL);
+  TempPartTopo.GetLifeTime(cT,ErrcT);
+  
+  float chi2 = TempPart.GetChi2();
+  Int_t ndf = TempPart.GetNDF();
+  float prob = TMath::Prob(chi2, ndf);//(TDHelper<float>::Chi2IProbability( ndf, chi2 ));
+  Theta = TempPart.GetTheta();
+  Phi = TempPart.GetPhi();
+  X = TempPart.GetX();
+  Y = TempPart.GetY();
+  Z = TempPart.GetZ();
+#ifdef CBM
+  if(Z>=1. && iParticle>=54 && iParticle<=64) return;
+#endif
+  R = sqrt(X*X+Y*Y);
+  M_t = sqrt(Pt*Pt+fParteff.GetMass(iParticle)*fParteff.GetMass(iParticle))-fParteff.GetMass(iParticle);
+  
+  KFParticleSIMD tempSIMDPart(TempPart);
+  float_v l,dl;
+  KFParticleSIMD pv(fTopoReconstructor->GetPrimVertex(iPV));
+  tempSIMDPart.GetDistanceToVertexLine(pv, l, dl);
+#ifdef __ROOT__
+  if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==   4122 ||
+                                    abs( TempPart.GetPDG() ) == 104122 ||
+                                    abs( TempPart.GetPDG() ) == 204122 ||
+                                    abs( TempPart.GetPDG() ) == 304122 ||
+                                    abs( TempPart.GetPDG() ) == 404122 || 
+                                    abs( TempPart.GetPDG() ) == 504122 )  ) return;
+  if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) == 421 ||
+                                    abs( TempPart.GetPDG() ) == 420 ||
+                                    abs( TempPart.GetPDG() ) == 425 ||
+                                    abs( TempPart.GetPDG() ) == 426 ||
+                                    abs( TempPart.GetPDG() ) == 427 ||
+                                    abs( TempPart.GetPDG() ) == 429)  ) return;
+  if( (l[0] > 0.4f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==    411 ||
+                                    abs( TempPart.GetPDG() ) == 100411 ||
+                                    abs( TempPart.GetPDG() ) == 200411 ||
+                                    abs( TempPart.GetPDG() ) == 300411)  ) return;
+  if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==    431 ||
+                                    abs( TempPart.GetPDG() ) == 100431 ||
+                                    abs( TempPart.GetPDG() ) == 200431 ||
+                                    abs( TempPart.GetPDG() ) == 300431 ||
+                                    abs( TempPart.GetPDG() ) == 400431)  ) return;
+  
+//   if(Pt < 2. && (abs( TempPart.GetPDG() ) ==    443 ||
+//                  abs( TempPart.GetPDG() ) == 100443 ||
+//                  abs( TempPart.GetPDG() ) == 200443 ||
+//                  abs( TempPart.GetPDG() ) == 300443 ||
+//                  abs( TempPart.GetPDG() ) == 400443 ||
+//                  abs( TempPart.GetPDG() ) == 500443) ) return;
+  
+  if(Pt < 0.5f && (abs( TempPart.GetPDG() ) == 3000 ||
+                   abs( TempPart.GetPDG() ) == 3001) ) return;
+#endif
+  float parameters[17] = {M, P, Pt, Rapidity, dL, cT, chi2/ndf, prob, Theta, Phi, X, Y, Z, R, l[0], l[0]/dl[0], M_t };
+
+  //for all particle-candidates
+  for(int iParam=0; iParam<17; iParam++)
+    histoParameters[0][iParticle][iParam]->Fill(parameters[iParam]);
+
+  if(multiplicities)
+    multiplicities[0][iParticle]++;
+
+  histoParameters2D[0][iParticle][0]->Fill(Rapidity,Pt,1);
+  histoParameters2D[0][iParticle][3]->Fill(Rapidity,M_t,1);
+  
+  const bool drawZR = IsCollectZRHistogram(iParticle);
+  if(histoParameters2D[0][iParticle][1] && drawZR)
+  {
+    histoParameters2D[0][iParticle][1]->Fill(Z,R,1);
+  }
+
+  if(TempPart.NDaughters() == 2 && IsCollectArmenteros(iParticle))
+  {
+    int index1 = TempPart.DaughterIds()[0];
+    int index2 = TempPart.DaughterIds()[1];
+    if(index1 >= int(fTopoReconstructor->GetParticles().size()) || 
+        index2 >= int(fTopoReconstructor->GetParticles().size()) || 
+        index1 < 0 || index2 < 0 ) 
+      return;
+      
+    KFParticle posDaughter, negDaughter;
+    if(int(fTopoReconstructor->GetParticles()[index1].Q()) > 0)
+    {
+      posDaughter = fTopoReconstructor->GetParticles()[index1];
+      negDaughter = fTopoReconstructor->GetParticles()[index2];
+    }
+    else
+    {
+      negDaughter = fTopoReconstructor->GetParticles()[index1];
+      posDaughter = fTopoReconstructor->GetParticles()[index2];
+    }
+    float vertex[3] = {TempPart.GetX(), TempPart.GetY(), TempPart.GetZ()};
+    posDaughter.TransportToPoint(vertex);
+    negDaughter.TransportToPoint(vertex);
+    KFParticle::GetArmenterosPodolanski(posDaughter, negDaughter, QtAlpha );
+    
+    histoParameters2D[0][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
+  }
+    
+  //Fill 3D histograms for multi differential analysis
+  if( histoParameters3D && IsCollect3DHistogram(iParticle))
+  {
+    histoParameters3D[0][iParticle][0]->Fill(Rapidity,Pt,M,1);
+    histoParameters3D[0][iParticle][1]->Fill(Rapidity,M_t,M,1);
+    if(fCentralityBin>=0)
+    {
+      histoParameters3D[0][iParticle][2]->Fill(fCentralityBin, Pt, M, fCentralityWeight);
+      histoParameters3D[0][iParticle][3]->Fill(fCentralityBin, Rapidity, M, fCentralityWeight);
+      histoParameters3D[0][iParticle][4]->Fill(fCentralityBin, M_t, M, fCentralityWeight);
+    }
+    histoParameters3D[0][iParticle][5]->Fill(cT, Pt, M, 1);
+  }
+  
+  //Fill histograms for the side bands analysis
+  if(histoDSToParticleQA && IsCollect3DHistogram(iParticle))
+  {
+    if(fabs(fParteff.GetMass(iParticle)-M) < 3.f*fParteff.GetMassSigma(iParticle))//SignalReco
+    {
+      for(int iParam=0; iParam<17; iParam++)
+        histoParameters[4][iParticle][iParam]->Fill(parameters[iParam]);
+      
+      if(multiplicities)
+        multiplicities[4][iParticle]++;
+
+      histoParameters2D[4][iParticle][0]->Fill(Rapidity,Pt,1);
+      histoParameters2D[4][iParticle][3]->Fill(Rapidity,M_t,1);
+      
+      if(drawZR)
+      {
+        if(histoParameters2D[4][iParticle][1])
+          histoParameters2D[4][iParticle][1]->Fill(Z,R,1);
+        if(histoParameters2D[4][iParticle][2])
+          histoParameters2D[4][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
+      }
+    }
+    
+    if( fabs(fParteff.GetMass(iParticle)-M) > 3.f*fParteff.GetMassSigma(iParticle) &&
+        fabs(fParteff.GetMass(iParticle)-M) <= 6.f*fParteff.GetMassSigma(iParticle) )//BGReco
+    {
+      for(int iParam=0; iParam<17; iParam++)
+        histoParameters[5][iParticle][iParam]->Fill(parameters[iParam]);
+      
+      if(multiplicities)
+        multiplicities[5][iParticle]++;
+
+      histoParameters2D[5][iParticle][0]->Fill(Rapidity,Pt,1);
+      histoParameters2D[5][iParticle][3]->Fill(Rapidity,M_t,1);
+      
+      if(drawZR)
+      {
+        if(histoParameters2D[5][iParticle][1])
+          histoParameters2D[5][iParticle][1]->Fill(Z,R,1);
+        if(histoParameters2D[5][iParticle][2])
+          histoParameters2D[5][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
+      }
+    }
+  }
+  
+  if(!fStoreMCHistograms) return;
+
+  int iSet = 1;
+  if(!RtoMCParticleId[iP].IsMatchedWithPdg()) //background
+  {
+    if(!RtoMCParticleId[iP].IsMatched()) iSet = 3; // for ghost particles - combinatorial background
+    else iSet = 2; // for physical background
+  }
+  
+  //Check if PV association is correct
+  if(!histoDSToParticleQA && iSet == 1)
+  { 
+    int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
+    KFMCParticle &mcPart = vMCParticles[iMCPart];
+    int iMCTrack = mcPart.GetMCTrackID();
+    KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+    int motherId = mcTrack.MotherId();
+    bool isSecondaryParticle = motherId >= 0;
+    
+    if(iPV >=0)
+    {
+      if(isSecondaryParticle)
+        iSet = 4;
+      else 
+      {
+        int iMCPV = -1;
+        if(RtoMCPVId[iPV].IsMatchedWithPdg())
+          iMCPV = RtoMCPVId[iPV].GetBestMatch();
+        
+        int iMCPVFromParticle = fMCTrackToMCPVMatch[iMCTrack];
+        if(iMCPV != iMCPVFromParticle)
+          iSet = 4;
+      }
+    }
+    else
+    {
+      if(!isSecondaryParticle)
+        iSet = 4;
+    }
+  }
+  
+  //for signal particles
+  for(int iParam=0; iParam<17; iParam++)
+    histoParameters[iSet][iParticle][iParam]->Fill(parameters[iParam]);
+    
+  if(multiplicities)
+    multiplicities[iSet][iParticle]++;
+  
+  histoParameters2D[iSet][iParticle][0]->Fill(Rapidity,Pt,1);
+  if(drawZR)
+  {
+    if(histoParameters2D[iSet][iParticle][1])
+      histoParameters2D[iSet][iParticle][1]->Fill(Z,R,1);
+    if(histoParameters2D[iSet][iParticle][2])
+      histoParameters2D[iSet][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
+  }
+  histoParameters2D[iSet][iParticle][3]->Fill(Rapidity,M_t,1);
+  
+  if(iSet != 1) return;
+  
+  int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
+  KFMCParticle &mcPart = vMCParticles[iMCPart];
+  // Fit quality of the mother particle
+  if(histoFit)
+  {
+    int iMCTrack = mcPart.GetMCTrackID();
+    KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+    int mcDaughterId = -1;
+    if(iParticle >= fParteff.fFirstStableParticleIndex && iParticle <= fParteff.fLastStableParticleIndex)
+      mcDaughterId = iMCTrack;
+    else if(mcTrack.PDG() == 22 && TempPart.NDaughters() == 1)
+      mcDaughterId = iMCTrack;
+    else if(iParticle >= fParteff.fFirstMissingMassParticleIndex && iParticle <= fParteff.fLastMissingMassParticleIndex)
+      mcDaughterId = mcPart.GetDaughterIds()[1]; //the charged daughter
+    else
+      mcDaughterId = mcPart.GetDaughterIds()[0];
+    
+    KFMCTrack &mcDaughter = vMCTracks[mcDaughterId];
+    
+    float mcX =  mcTrack.X();
+    float mcY =  mcTrack.Y();
+    float mcZ =  mcTrack.Z();
+    if(histoDSToParticleQA || hPartParamPrimary == histoParameters)
+    {
+      mcX =  mcDaughter.X();
+      mcY =  mcDaughter.Y();
+      mcZ =  mcDaughter.Z();
+    }
+    const float mcPx = mcTrack.Par(3);
+    const float mcPy = mcTrack.Par(4);
+    const float mcPz = mcTrack.Par(5);
+
+    float decayVtx[3] = { mcTrack.X(), mcTrack.Y(), mcTrack.Z() };
+    float recParam[8] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+    float errParam[8] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+    for(int iPar=0; iPar<3; iPar++)
+    {
+      recParam[iPar] = TempPart.GetParameter(iPar);
+      Double_t error = TempPart.GetCovariance(iPar,iPar);
+      if(error < 0.) { error = 1.e20;}
+      errParam[iPar] = TMath::Sqrt(error);
+    }
+    TempPart.TransportToPoint(decayVtx);
+    for(int iPar=3; iPar<7; iPar++)
+    {
+      recParam[iPar] = TempPart.GetParameter(iPar);
+      Double_t error = TempPart.GetCovariance(iPar,iPar);
+      if(error < 0.) { error = 1.e20;}
+      errParam[iPar] = TMath::Sqrt(error);
+    }
+
+    int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
+    Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
+    
+    Double_t Emc = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
+    Double_t res[8] = {0}, 
+              pull[8] = {0}, 
+              mcParam[8] = { mcX, mcY, mcZ,
+                            mcPx, mcPy, mcPz, Emc, massMC };
+    for(int iPar=0; iPar < 7; iPar++ )
+    {
+      res[iPar]  = recParam[iPar] - mcParam[iPar];
+      if(fabs(errParam[iPar]) > 1.e-20) pull[iPar] = res[iPar]/errParam[iPar];
+    }
+
+    res[7] = M - mcParam[7];
+    if(fabs(ErrM) > 1.e-20) pull[7] = res[7]/ErrM;
+
+    for(int iPar=0; iPar < 8; iPar++ )
+    {
+      histoFit[iParticle][iPar]->Fill(res[iPar]);
+      histoFit[iParticle][iPar+8]->Fill(pull[iPar]);
+    }
+  }
+  // Fit quality of daughters
+  int daughterIndex[2] = {-1, -1};
+  
+  if(histoFitDaughtersQA)
+  {
+    for(int iD=0; iD<mcPart.NDaughters(); ++iD)
+    {
+      int mcDaughterId = mcPart.GetDaughterIds()[iD];
+  //      if(!MCtoRParticleId[mcDaughterId].IsMatchedWithPdg()) continue;
+      if(!MCtoRParticleId[mcDaughterId].IsMatched()) continue;
+      KFMCTrack &mcTrack = vMCTracks[mcDaughterId];
+  //      int recDaughterId = MCtoRParticleId[mcDaughterId].GetBestMatchWithPdg();
+      int recDaughterId = MCtoRParticleId[mcDaughterId].GetBestMatch();
+      KFParticle Daughter = fTopoReconstructor->GetParticles()[recDaughterId];
+      Daughter.GetMass(M,ErrM);
+
+      const float mcX =  mcTrack.X();
+      const float mcY =  mcTrack.Y();
+      const float mcZ =  mcTrack.Z();
+      const float mcPx = mcTrack.Px();
+      const float mcPy = mcTrack.Py();
+      const float mcPz = mcTrack.Pz();
+
+      float_v decayVtx[3] = {mcX, mcY, mcZ};
+
+      KFParticleSIMD DaughterSIMD(Daughter);
+      DaughterSIMD.TransportToPoint(decayVtx);
+      
+      int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
+      Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
+      Double_t Emc = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
+      
+      Double_t res[8] = {0}, 
+                pull[8] = {0}, 
+                mcParam[8] = { mcX, mcY, mcZ,
+                              mcPx, mcPy, mcPz, Emc, massMC };
+      for(int iPar=0; iPar < 7; iPar++ )
+      {
+        Double_t error = DaughterSIMD.GetCovariance(iPar,iPar)[0];
+        if(error < 0.) { error = 1.e20;}
+        error = TMath::Sqrt(error);
+        Double_t recoPar = DaughterSIMD.GetParameter(iPar)[0];
+        res[iPar]  = recoPar - mcParam[iPar];
+        if(fabs(error) > 1.e-20) pull[iPar] = res[iPar]/error;
+      }
+      res[7] = M - mcParam[7];
+      if(fabs(ErrM) > 1.e-20) pull[7] = res[7]/ErrM;
+
+      for(int iPar=0; iPar < 8; iPar++ )
+      {
+        histoFitDaughtersQA[iParticle][iPar]->Fill(res[iPar]);
+        histoFitDaughtersQA[iParticle][iPar+8]->Fill(pull[iPar]);
+      }
+      
+      //fill Histos for GetDStoParticle
+      if(iD == 0)
+        daughterIndex[0] = recDaughterId;
+      if(iD == 1 && daughterIndex[0] > -1 && histoDSToParticleQA)
+      {
+        daughterIndex[1] = recDaughterId;
+        KFParticle d1 = fTopoReconstructor->GetParticles()[daughterIndex[0]];
+        KFParticle d2 = fTopoReconstructor->GetParticles()[daughterIndex[1]];
+        
+        KFParticleSIMD daughters[2] = {d2, d1};
+        
+        float_v dS[2] = {0.f, 0.f};
+        float_v dsdr[4][6];
+        for(int i1=0; i1<4; i1++)
+          for(int i2=0; i2<6; i2++)
+            dsdr[i1][i2] = 0.f;
+          
+        daughters[0].GetDStoParticle(daughters[1], dS, dsdr);
+        float_v pD[2][8], cD[2][36], corrPD[2][36], corrCD[2][36];
+        
+        for(int iDR=0; iDR<2; iDR++)
+        {
+          for(int iPD = 0; iPD<8; iPD++)
+          {
+            pD[iDR][iPD] = 0;
+            corrPD[iDR][iPD] = 0;
+          }
+          for(int iCD=0; iCD<36; iCD++)
+          {
+            cD[iDR][iCD] = 0;
+            corrCD[iDR][iCD] = 0;
+          }
+        }
+        
+        float_v F[4][36];
+        {
+          for(int i1=0; i1<4; i1++)
+            for(int i2=0; i2<36; i2++)
+                F[i1][i2] = 0;
+        }
+        daughters[0].Transport(dS[0], dsdr[0], pD[0], cD[0], dsdr[1], F[0], F[1]);
+        daughters[1].Transport(dS[1], dsdr[3], pD[1], cD[1], dsdr[2], F[3], F[2]);
+        
+        daughters[0].MultQSQt( F[1], daughters[1].CovarianceMatrix(), corrCD[0], 6);
+        daughters[0].MultQSQt( F[2], daughters[0].CovarianceMatrix(), corrCD[1], 6);
+        for(int iDR=0; iDR<2; iDR++)
+          for(int iC=0; iC<6; iC++)
+            cD[iDR][iC] += corrCD[iDR][iC];
+
+        for(int iDR=0; iDR<2; iDR++)
+        {
+          cD[iDR][1] = cD[iDR][2];
+          cD[iDR][2] = cD[iDR][5];
+          for(int iPar=0; iPar<3; iPar++)
+          {
+            res[iPar] = pD[iDR][iPar][0] - decayVtx[iPar][0];
+            
+            Double_t error = cD[iDR][iPar][0];
+            if(error < 0.) { error = 1.e20;}
+            error = sqrt(error);
+            
+            pull[iPar] = res[iPar] / error;
+            
+            histoDSToParticleQA[iParticle][iPar]->Fill(res[iPar]);
+            histoDSToParticleQA[iParticle][iPar+3]->Fill(pull[iPar]);
+          }
+        }
+        
+        Double_t dXds = pD[0][0][0] - pD[1][0][0];
+        Double_t dYds = pD[0][1][0] - pD[1][1][0];
+        Double_t dZds = pD[0][2][0] - pD[1][2][0];
+        
+        Double_t dRds = sqrt(dXds*dXds + dYds*dYds + dZds*dZds);
+        histoDSToParticleQA[iParticle][6]->Fill(dRds);
+      }
+    }
+  }
+}
+
+void KFTopoPerformance::FillHistos()
+{
+  /** Fills histograms with parameter  distributions and fit quality for all particle and primary vertex candidates. */
+  vector<int> multiplicities[6];
+  for(int iV=0; iV<6; iV++)
+    multiplicities[iV].resize(KFPartEfficiencies::nParticles, 0);
+  
+  //fill histograms for found short-lived particles
+  for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
+  {
+    int iParticle = fParteff.GetParticleIndex(fTopoReconstructor->GetParticles()[iP].GetPDG());
+    if(iParticle < 0) continue;
+    KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
+    
+    FillParticleParameters(TempPart,iParticle, iP, 0, hPartParam, hPartParam2D, hPartParam3D,
+                           hFitQA, hFitDaughtersQA, hDSToParticleQA, multiplicities);
+  }
+  
+  if(fStoreMCHistograms)
+  {
+    for(int iSet=0; iSet<KFParticleFinder::GetNSecondarySets(); iSet++)
+    {
+      const std::vector<KFParticle>& SecondaryCandidates = fTopoReconstructor->GetKFParticleFinder()->GetSecondaryCandidates()[iSet];
+      for(unsigned int iP=0; iP<SecondaryCandidates.size(); iP++)
+      {
+        KFParticle TempPart = SecondaryCandidates[iP];
+        int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
+        if(iParticle < 0) continue;
+        
+        const int id = TempPart.Id();
+        FillParticleParameters(TempPart, iParticle, id, 0, hPartParamSecondaryMass, hPartParam2DSecondaryMass, 0);
+        
+        TempPart = fTopoReconstructor->GetParticles()[id];
+        FillParticleParameters(TempPart, iParticle, id, 0, hPartParamSecondary, hPartParam2DSecondary, 0);
+      }
+    }
+    
+    for(int iSet=0; iSet<KFParticleFinder::GetNPrimarySets(); iSet++)
+    {
+      for(int iPV=0; iPV<fTopoReconstructor->NPrimaryVertices(); iPV++)
+      {
+        const std::vector<KFParticle>& PrimaryCandidates = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryCandidates()[iSet][iPV];
+        for(unsigned int iP=0; iP<PrimaryCandidates.size(); iP++)
+        {
+          KFParticle TempPart =  PrimaryCandidates[iP];
+          int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
+          if(iParticle < 0) continue;
+          
+          const int id = TempPart.Id();
+          FillParticleParameters(TempPart,iParticle, id, iPV, hPartParamPrimaryMass, hPartParam2DPrimaryMass, 0, hFitQAMassConstraint);
+          
+          TempPart = fTopoReconstructor->GetParticles()[id];
+          FillParticleParameters(TempPart,iParticle, id, iPV, hPartParamPrimary, hPartParam2DPrimary, 0, hFitQANoConstraint);
+        }
+        
+        const std::vector<KFParticle>& PrimaryCandidatesTopo = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryTopoCandidates()[iSet][iPV];
+        for(unsigned int iP=0; iP<PrimaryCandidatesTopo.size(); iP++)
+        {
+          KFParticle TempPart =  PrimaryCandidatesTopo[iP];
+          int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
+          if(iParticle < 0) continue;
+          
+          FillParticleParameters(TempPart,iParticle, TempPart.Id(), iPV, hPartParamPrimaryTopo, hPartParam2DPrimaryTopo, 0, hFitQATopoConstraint);
+        }
+        
+        const std::vector<KFParticle>& PrimaryCandidatesTopoMass = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryTopoMassCandidates()[iSet][iPV];
+        for(unsigned int iP=0; iP<PrimaryCandidatesTopoMass.size(); iP++)
+        {
+          KFParticle TempPart =  PrimaryCandidatesTopoMass[iP];
+          int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
+          if(iParticle < 0) continue;
+          
+          FillParticleParameters(TempPart,iParticle, TempPart.Id(), iPV, hPartParamPrimaryTopoMass, hPartParam2DPrimaryTopoMass, 0, hFitQATopoMassConstraint);
+        }
+      }
+    }
+  }
+  //fill histograms with ChiPrim for every particle
+  for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
+  {
+    KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
+    KFParticle vtx = fTopoReconstructor->GetPrimVertex(0);
+    
+    if(RtoMCParticleId[iP].IsMatched())
+    {
+      int iMCPV = vMCParticles[RtoMCParticleId[iP].GetBestMatch()].GetMotherId();
+      if(iMCPV<0.)
+      {
+        iMCPV = -iMCPV - 1;
+        if(MCtoRPVId[iMCPV].IsMatched())
+        { 
+          vtx = fTopoReconstructor->GetPrimVertex(MCtoRPVId[iMCPV].GetBestMatch());
+        }  
+      }
+    }
+//     else
+//       KFParticle & vtx = fTopoReconstructor->GetPrimVertex(0);
+    
+    
+    float chi2 = TempPart.GetDeviationFromVertex(vtx);
+    int ndf = 2;
+    
+    hTrackParameters[KFPartEfficiencies::nParticles]->Fill(chi2);
+    hTrackParameters[KFPartEfficiencies::nParticles+4]->Fill(TMath::Prob(chi2, ndf));
+    
+    if(!RtoMCParticleId[iP].IsMatched()) 
+    {
+      hTrackParameters[KFPartEfficiencies::nParticles+3]->Fill(chi2);
+      hTrackParameters[KFPartEfficiencies::nParticles+7]->Fill(TMath::Prob(chi2, ndf));
+      continue;
+    }
+    
+    int iMCPart = RtoMCParticleId[iP].GetBestMatch();
+    KFMCParticle &mcPart = vMCParticles[iMCPart];
+    if(mcPart.GetMotherId() < 0)
+    {
+      hTrackParameters[KFPartEfficiencies::nParticles+1]->Fill(chi2 );
+      hTrackParameters[KFPartEfficiencies::nParticles+5]->Fill(TMath::Prob(chi2, ndf));
+    }
+    else
+    {
+      hTrackParameters[KFPartEfficiencies::nParticles+2]->Fill(chi2 );
+      hTrackParameters[KFPartEfficiencies::nParticles+6]->Fill(TMath::Prob(chi2, ndf));
+    }    
+    int iParticle = fParteff.GetParticleIndex(fTopoReconstructor->GetParticles()[iP].GetPDG());
+    if(iParticle > -1 && iParticle<KFPartEfficiencies::nParticles)
+      hTrackParameters[iParticle]->Fill(chi2 );
+    
+  }
+  
+  
+  //fill histograms of the primary vertex quality
+  for(int iPV = 0; iPV<fTopoReconstructor->NPrimaryVertices(); iPV++)
+  {
+    KFParticle & vtx = fTopoReconstructor->GetPrimVertex(iPV);
+    vector<int> &tracks = fTopoReconstructor->GetPVTrackIndexArray(iPV);
+
+    Double_t probPV = TMath::Prob(vtx.Chi2(), vtx.NDF());//(TDHelper<float>::Chi2IProbability( ndf, chi2 ));
+    vector<Double_t> dzPV;
+    if(RtoMCPVId[iPV].IsMatched())
+    {
+      int iCurrMCPV = RtoMCPVId[iPV].GetBestMatch();
+      for(int iPV2 = iPV+1; iPV2 < fTopoReconstructor->NPrimaryVertices(); iPV2++)
+      {
+        if(!RtoMCPVId[iPV2].IsMatched()) continue;
+        int iCurrMCPV2 = RtoMCPVId[iPV2].GetBestMatch();
+        if(iCurrMCPV != iCurrMCPV2) continue;
+        KFParticle & vtx2 = fTopoReconstructor->GetPrimVertex(iPV2);
+        
+        dzPV.push_back(fabs(vtx.Z() - vtx2.Z())); 
+      }
+    }
+    
+    hPVParam[ 0]->Fill(vtx.X());
+    hPVParam[ 1]->Fill(vtx.Y());
+    hPVParam[ 2]->Fill(vtx.Z());
+    hPVParam[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
+    hPVParam[ 4]->Fill(tracks.size());    
+    hPVParam[ 5]->Fill(vtx.Chi2());
+    hPVParam[ 6]->Fill(vtx.NDF());
+    hPVParam[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
+    hPVParam[ 8]->Fill(probPV);
+    hPVParam[ 9]->Fill(fPVPurity[iPV]);
+    hPVParam[10]->Fill(fPVTracksRate[0][iPV]);
+    hPVParam[11]->Fill(fPVTracksRate[1][iPV]);
+    hPVParam[12]->Fill(fPVTracksRate[2][iPV]);
+    hPVParam[13]->Fill(fPVTracksRate[3][iPV]);
+    for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
+      hPVParam[14]->Fill(dzPV[iZ]);
+
+    hPVParam2D[0]->Fill(vtx.X(),vtx.Y());
+
+    
+    if(!RtoMCPVId[iPV].IsMatchedWithPdg())
+    {
+      if(!RtoMCPVId[iPV].IsMatched())
+      {
+        hPVParamGhost[ 0]->Fill(vtx.X());
+        hPVParamGhost[ 1]->Fill(vtx.Y());
+        hPVParamGhost[ 2]->Fill(vtx.Z());
+        hPVParamGhost[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
+        hPVParamGhost[ 4]->Fill(tracks.size());    
+        hPVParamGhost[ 5]->Fill(vtx.Chi2());
+        hPVParamGhost[ 6]->Fill(vtx.NDF());
+        hPVParamGhost[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
+        hPVParamGhost[ 8]->Fill(probPV);
+        hPVParamGhost[ 9]->Fill(fPVPurity[iPV]);
+        hPVParamGhost[10]->Fill(fPVTracksRate[0][iPV]);
+        hPVParamGhost[11]->Fill(fPVTracksRate[1][iPV]);
+        hPVParamGhost[12]->Fill(fPVTracksRate[2][iPV]);
+        hPVParamGhost[13]->Fill(fPVTracksRate[3][iPV]);
+        for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
+          hPVParamGhost[14]->Fill(dzPV[iZ]);
+      }
+      else
+      {
+        hPVParamBG[ 0]->Fill(vtx.X());
+        hPVParamBG[ 1]->Fill(vtx.Y());
+        hPVParamBG[ 2]->Fill(vtx.Z());
+        hPVParamBG[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
+        hPVParamBG[ 4]->Fill(tracks.size());    
+        hPVParamBG[ 5]->Fill(vtx.Chi2());
+        hPVParamBG[ 6]->Fill(vtx.NDF());
+        hPVParamBG[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
+        hPVParamBG[ 8]->Fill(probPV);
+        hPVParamBG[ 9]->Fill(fPVPurity[iPV]);
+        hPVParamBG[10]->Fill(fPVTracksRate[0][iPV]);
+        hPVParamBG[11]->Fill(fPVTracksRate[1][iPV]);
+        hPVParamBG[12]->Fill(fPVTracksRate[2][iPV]);
+        hPVParamBG[13]->Fill(fPVTracksRate[3][iPV]);
+        for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
+          hPVParamBG[14]->Fill(dzPV[iZ]);
+      }
+      continue;
+    }
+    
+    int iMCPV = RtoMCPVId[iPV].GetBestMatch();
+    KFMCVertex &mcPV = fPrimVertices[iMCPV]; // primary vertex positions (currently only one vertex is implemented)
+    
+    int iPVType = 0;
+    if(mcPV.IsTriggerPV())
+    {
+      hPVParamSignal[ 0]->Fill(vtx.X());
+      hPVParamSignal[ 1]->Fill(vtx.Y());
+      hPVParamSignal[ 2]->Fill(vtx.Z());
+      hPVParamSignal[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
+      hPVParamSignal[ 4]->Fill(tracks.size());    
+      hPVParamSignal[ 5]->Fill(vtx.Chi2());
+      hPVParamSignal[ 6]->Fill(vtx.NDF());
+      hPVParamSignal[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
+      hPVParamSignal[ 8]->Fill(probPV);
+      hPVParamSignal[ 9]->Fill(fPVPurity[iPV]);
+      hPVParamSignal[10]->Fill(fPVTracksRate[0][iPV]);
+      hPVParamSignal[11]->Fill(fPVTracksRate[1][iPV]);
+      hPVParamSignal[12]->Fill(fPVTracksRate[2][iPV]);
+      hPVParamSignal[13]->Fill(fPVTracksRate[3][iPV]);
+      for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
+        hPVParamSignal[14]->Fill(dzPV[iZ]);
+    }
+    else
+    {
+      hPVParamPileup[ 0]->Fill(vtx.X());
+      hPVParamPileup[ 1]->Fill(vtx.Y());
+      hPVParamPileup[ 2]->Fill(vtx.Z());
+      hPVParamPileup[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
+      hPVParamPileup[ 4]->Fill(tracks.size());    
+      hPVParamPileup[ 5]->Fill(vtx.Chi2());
+      hPVParamPileup[ 6]->Fill(vtx.NDF());
+      hPVParamPileup[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
+      hPVParamPileup[ 8]->Fill(probPV);
+      hPVParamPileup[ 9]->Fill(fPVPurity[iPV]);
+      hPVParamPileup[10]->Fill(fPVTracksRate[0][iPV]);
+      hPVParamPileup[11]->Fill(fPVTracksRate[1][iPV]);
+      hPVParamPileup[12]->Fill(fPVTracksRate[2][iPV]);
+      hPVParamPileup[13]->Fill(fPVTracksRate[3][iPV]);
+      for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
+        hPVParamPileup[14]->Fill(dzPV[iZ]);
+      iPVType = 1;
+    }
+    //Find MC parameters of the primary vertex 
+    float mcPVx[3]={mcPV.X(), mcPV.Y(), mcPV.Z()};
+
+    float errPV[3] = {vtx.CovarianceMatrix()[0], vtx.CovarianceMatrix()[2], vtx.CovarianceMatrix()[5]};
+    for(int iErr=0; iErr<3; iErr++)
+      if(fabs(errPV[iErr]) < 1.e-8f) errPV[iErr] = 1.e8;
+        
+    float dRPVr[3] = {vtx.X()-mcPVx[0],
+                      vtx.Y()-mcPVx[1],
+                      vtx.Z()-mcPVx[2]};
+    float dRPVp[3] = {static_cast<float>(dRPVr[0]/sqrt(errPV[0])),
+                      static_cast<float>(dRPVr[1]/sqrt(errPV[1])),
+                      static_cast<float>(dRPVr[2]/sqrt(errPV[2]))};
+
+    for(unsigned int iHPV=0; iHPV<3; ++iHPV)
+      hPVFitQa[iPVType][iHPV]->Fill(dRPVr[iHPV]);
+    for(unsigned int iHPV=3; iHPV<6; ++iHPV)
+      hPVFitQa[iPVType][iHPV]->Fill(dRPVp[iHPV-3]);
+    
+    for(unsigned int iHPV=0; iHPV<3; ++iHPV)
+      hPVFitQa2D[iPVType][1][iHPV]->Fill(fNCorrectPVTracks[iPV],dRPVr[iHPV]);
+    for(unsigned int iHPV=3; iHPV<6; ++iHPV)
+      hPVFitQa2D[iPVType][1][iHPV]->Fill(fNCorrectPVTracks[iPV],dRPVp[iHPV-3]);
+
+    for(unsigned int iHPV=0; iHPV<3; ++iHPV)
+      hPVFitQa2D[iPVType][0][iHPV]->Fill(mcPV.NReconstructedDaughterTracks(),dRPVr[iHPV]);
+    for(unsigned int iHPV=3; iHPV<6; ++iHPV)
+      hPVFitQa2D[iPVType][0][iHPV]->Fill(mcPV.NReconstructedDaughterTracks(),dRPVp[iHPV-3]);
+    
+    hPVFitQa[iPVType][6]->Fill( double(mcPV.NReconstructedDaughterTracks() - fNCorrectPVTracks[iPV])/double(mcPV.NReconstructedDaughterTracks()) );
+  }
+  
+  //fill histograms with quality of input tracks from PV
+  for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
+  {
+    KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
+    int nDaughters = TempPart.NDaughters();
+    if(nDaughters > 1) continue; //use only tracks, not short lived particles
+    
+    if(!RtoMCParticleId[iP].IsMatchedWithPdg())  continue; //ghost
+    
+    int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
+    KFMCParticle &mcPart = vMCParticles[iMCPart];
+
+    int iMCTrack = mcPart.GetMCTrackID();
+    KFMCTrack &mcTrack = vMCTracks[iMCTrack];
+    
+    if( mcTrack.MotherId() > -1 ) continue; // select only PV tracks
+    
+    const float mcX =  mcTrack.X();
+    const float mcY =  mcTrack.Y();
+    const float mcZ =  mcTrack.Z();
+    const float mcPx = mcTrack.Px();
+    const float mcPy = mcTrack.Py();
+    const float mcPz = mcTrack.Pz();
+
+    float decayVtx[3] = {mcX, mcY, mcZ};
+    TempPart.TransportToPoint(decayVtx);
+
+
+    Double_t res[6] = {0}, 
+             pull[6] = {0}, 
+             mcParam[6] = { mcX, mcY, mcZ,
+                            mcPx, mcPy, mcPz };
+    for(int iPar=0; iPar < 6; iPar++ )
+    {
+      Double_t error = TempPart.GetCovariance(iPar,iPar);
+      if(error < 0.) { error = 1.e20;}
+      error = TMath::Sqrt(error);
+      res[iPar]  = TempPart.GetParameter(iPar) - mcParam[iPar];
+      if(fabs(error) > 1.e-20) pull[iPar] = res[iPar]/error;
+      
+      hFitPVTracksQA[iPar]->Fill(res[iPar]);
+      hFitPVTracksQA[iPar+6]->Fill(pull[iPar]);
+    }
+  }
+  
+  if(fStoreMCHistograms)
+  {
+    for(int iV=0; iV<6; iV++)
+      for(int iP=0; iP < KFPartEfficiencies::nParticles; iP++)
+        if(hPartParam[iV][iP][17])
+          hPartParam[iV][iP][17]->Fill(multiplicities[iV][iP]);
+    FillMCHistos();
+  }
+  else
+    for(int iP=0; iP < KFPartEfficiencies::nParticles; iP++)
+      if(hPartParam[0][iP][17])
+        hPartParam[0][iP][17]->Fill(multiplicities[0][iP]);  
+} // void KFTopoPerformance::FillHistos()
+
+void KFTopoPerformance::FillMCHistos()
+{
+  /** Fills histograms of Monte Carlo particles. */
+  for(unsigned int iMCTrack=0; iMCTrack<vMCTracks.size(); iMCTrack++)
+  {
+    int iPDG = fParteff.GetParticleIndex(vMCTracks[iMCTrack].PDG());
+    if(iPDG < 0) continue;
+    
+    if(vMCTracks[iMCTrack].MotherId()>=0) continue;
+    KFMCParticle &part = vMCParticles[iMCTrack];
+       
+    float M = fParteff.partMass[iPDG];
+    float P = vMCTracks[iMCTrack].P();
+    float Pt = vMCTracks[iMCTrack].Pt();
+    float E = sqrt(M*M+P*P);
+    float Rapidity = 0.5*log((E+vMCTracks[iMCTrack].Pz())/(E-vMCTracks[iMCTrack].Pz()));
+    float M_t = sqrt(Pt*Pt+M*M)-M;
+    
+    float X;
+    float Y;
+    float Z;
+    float R;
+    
+    if (part.NDaughters()>0)
+    {
+      X = vMCTracks[part.GetDaughterIds()[0]].X();
+      Y = vMCTracks[part.GetDaughterIds()[0]].Y();
+      Z = vMCTracks[part.GetDaughterIds()[0]].Z();
+    }
+    else
+    {
+      X = vMCTracks[iMCTrack].X();
+      Y = vMCTracks[iMCTrack].Y();
+      Z = vMCTracks[iMCTrack].Z();
+    }
+    R = sqrt(X*X+Y*Y);
+    
+    
+    float parameters[17] = {M, P, Pt, Rapidity, 0, 0, 0, 0, 0, 0, X, Y, Z, R, 0, 0, M_t};
+    //for all particle-candidates
+    for(int iParam=0; iParam<17; iParam++)
+      if(hPartParam[6][iPDG][iParam]) hPartParam[6][iPDG][iParam]->Fill(parameters[iParam]);
+
+    if(hPartParam2D[6][iPDG][0]) hPartParam2D[6][iPDG][0]->Fill(Rapidity,Pt,1);
+    if(hPartParam2D[6][iPDG][3]) hPartParam2D[6][iPDG][3]->Fill(Rapidity,M_t,1);
+    
+    if(IsCollectZRHistogram(iPDG))
+      if(hPartParam2D[6][iPDG][1]) hPartParam2D[6][iPDG][1]->Fill(Z,R,1);
+    
+    if( part.IsReconstructable(2) && IsCollectArmenteros(iPDG))
+    {
+      int index1 = part.GetDaughterIds()[0];
+      int index2 = part.GetDaughterIds()[1];
+      KFMCTrack positive, negative;
+      if(vMCTracks[index1].Par(6) > 0)
+      {
+        positive = vMCTracks[index1];
+        negative = vMCTracks[index2];
+      }
+      else
+      {
+        negative = vMCTracks[index1];
+        positive = vMCTracks[index2];
+      }
+
+      float alpha = 0., qt = 0.;
+      float spx = positive.Px() + negative.Px();
+      float spy = positive.Py() + negative.Py();
+      float spz = positive.Pz() + negative.Pz();
+      float sp  = sqrt(spx*spx + spy*spy + spz*spz);
+      float pn, pln, plp;
+      pn = sqrt(negative.Px()*negative.Px() + negative.Py()*negative.Py() + negative.Pz()*negative.Pz());
+      pln  = (negative.Px()*spx+negative.Py()*spy+negative.Pz()*spz)/sp;
+      plp  = (positive.Px()*spx+positive.Py()*spy+positive.Pz()*spz)/sp;
+      float ptm  = (1.-((pln/pn)*(pln/pn)));
+      qt= (ptm>=0.)?  pn*sqrt(ptm) :0;
+      alpha = (plp-pln)/(plp+pln);
+      
+      if(hPartParam2D[6][iPDG][2]) hPartParam2D[6][iPDG][2]->Fill(alpha,qt,1);
+    }  
+  }
+}
+
+void KFTopoPerformance::AddV0Histos()
+{
+  /** Copies histograms of K0s candidates to V0 folder. */
+  int iV0 = fParteff.nParticles - 1;
+  int iK0 = fParteff.GetParticleIndex(310);
+  
+  for(int iH=0; iH<nFitQA; iH++)
+  {
+    hFitDaughtersQA[iV0][iH]->Add(hFitDaughtersQA[iK0][iH]);
+    hFitQA[iV0][iH]->Add(hFitQA[iK0][iH]);
+  }
+
+  for(int iV=0; iV<4; iV++)
+    for(int iH=0; iH<nHistoPartParam; iH++)
+      hPartParam[iV][iV0][iH]->Add(hPartParam[iV][iK0][iH]);
+}
+
+void KFTopoPerformance::FillHistos(const KFPHistogram* histograms)
+{
+  /** Fill histograms with the histograms from the provided KFPHistogram object. */
+  for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
+  {
+    const int& nHistograms = histograms->GetHistogramSet(0).GetNHisto1D();
+    for(int iHistogram=0; iHistogram<nHistograms; iHistogram++)
+    {
+      const KFPHistogram1D& histogram = histograms->GetHistogram(iParticle,iHistogram);
+      for(int iBin=0; iBin<histogram.Size(); iBin++)
+        hPartParam[0][iParticle][iHistogram]->SetBinContent( iBin, histogram.GetHistogram()[iBin] );
+    }
+  }
+}
+
+#endif //DO_TPCCATRACKER_EFF_PERFORMANCE
diff --git a/external/KFParticle/KFParticlePerformance/KFTopoPerformance.h b/external/KFParticle/KFParticlePerformance/KFTopoPerformance.h
new file mode 100644
index 0000000000000000000000000000000000000000..e86346ce9f9ca4202b6fee22ebe38f7890ccbc32
--- /dev/null
+++ b/external/KFParticle/KFParticlePerformance/KFTopoPerformance.h
@@ -0,0 +1,159 @@
+//----------------------------------------------------------------------------
+// Implementation of the KFParticle class
+// .
+// @author  I.Kisel, I.Kulakov, M.Zyzak
+// @version 1.0
+// @since   20.08.13
+// 
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//____________________________________________________________________________
+
+#ifdef DO_TPCCATRACKER_EFF_PERFORMANCE
+
+#ifndef KFTOPOPERFORMANCE_H
+#define KFTOPOPERFORMANCE_H
+
+
+#include "KFParticlePerformanceBase.h"
+
+#include "KFMCVertex.h"
+#include "KFMCTrack.h"
+#include <cstdio>
+#include <map>
+
+#include "KFPartMatch.h"
+#include "KFMCParticle.h"
+
+class AliHLTTPCCAGBTracker;
+
+class KFParticleTopoReconstructor;
+class KFPHistogram;
+
+/** @class KFTopoPerformance
+ ** @brief The class to collect histograms.
+ ** @author  M.Zyzak, I.Kisel
+ ** @date 05.02.2019
+ ** @version 1.0
+ **
+ ** The class collects a set of histograms.
+ ** For each particle from the KF Particle Reconstruction scheme histograms with parameter distribution,
+ ** efficiencies, fit QA, fit QA of daughters, histograms for the side bands method and histograms for
+ ** multi-differential extraction of spectra are collected. Also, a set of histograms for quality of
+ ** the reconstructed parameters of primary vertices is created: distribution of parameters; fit QA;
+ ** fit QA of primary tracks; contamination of ghost, secondary (background) tracks and tracks from
+ ** another primary vertex; efficiency.
+ **/
+
+class KFTopoPerformance: public KFParticlePerformanceBase
+{
+ public:
+  
+  KFTopoPerformance();
+  virtual ~KFTopoPerformance();
+#ifdef KFPWITHTRACKER
+  virtual void SetNewEvent(
+    const AliHLTTPCCAGBTracker * const Tracker,
+    AliHLTResizableArray<AliHLTTPCCAHitLabel> *hitLabels,
+    AliHLTResizableArray<AliHLTTPCCAMCTrack> *mcTracks,
+    AliHLTResizableArray<AliHLTTPCCALocalMCPoint> *localMCPoints);
+#endif  
+  void SetTopoReconstructor( const KFParticleTopoReconstructor * const TopoReconstructor );
+  const KFParticleTopoReconstructor * GetTopoReconstructor() const { return fTopoReconstructor; } ///< Returns pointer to the KFParticleTopoReconstructor object.
+    
+    // Check if MC track is reconstructable. Calculate set of MC track. Etc.
+  virtual void CheckMCTracks(); // fill mcData.
+    // Find reco-MCTracks correspondence
+  virtual void MatchTracks();   // fill recoData.
+    // Calculate efficiencies
+  
+  /// Histograms
+  void FillHistos();
+  void FillHistos(const KFPHistogram* histograms);
+  void FillMCHistos();
+
+  void AddV0Histos();
+  
+  void SetTrackMatch(const std::vector<int>& trackMatch) { fTrackMatch = trackMatch;} ///< Fill matching between Monte Carlo and reconstructed tracks.
+  void SetMCTracks(const std::vector<KFMCTrack>& mcTracks) { vMCTracks = mcTracks; } ///< Fill Monte Carlo tracks.
+  
+  const KFPartEfficiencies GetEfficiency() const { return fParteff; } ///< Returns KFPartEfficiencies object with calculated efficiency.
+  void SetPrintEffFrequency(int n) { fPrintEffFrequency = n;} ///< Sets frequency in events for efficiency table to be printed on the screen.
+
+  const std::vector<KFMCVertex> GetPrimVertices() { return fPrimVertices; } ///< Returns Monte Carlo primary vertices in the current event.
+  const std::vector<KFMCParticle>& MCParticles() { return vMCParticles; } ///< Returns Monte Carlo particles in the current event.
+  const std::vector<KFPartMatch>& ParticlesMatch() { return RtoMCParticleId; } ///< Returns matching between reconstructed and Monte Carlo particles.
+  const std::vector<KFPartMatch>& GetMCtoRPVId() { return MCtoRPVId; } ///< Returns matching between Monte Carlo and reconstructed primary vertices.
+  const std::vector<KFPartMatch>& GetRtoMCPVId() { return RtoMCPVId; } ///< Returns matching between reconstructed and Monte Carlo primary vertices.
+  const KFMCTrack& GetMCTrack(const int iRecoTrack)
+  { 
+    /** Returns Monte Carlo track matched with the reconstructed track with index "iRecoTrack". */
+    int iMCTrack = 0;
+    if(RtoMCParticleId[iRecoTrack].IsMatched())
+      iMCTrack = RtoMCParticleId[iRecoTrack].GetBestMatch();
+    return vMCTracks[iMCTrack]; 
+  }
+  
+  void SetCentralityBin(const int iBin) { fCentralityBin = iBin; } ///< Sets centrality bin of the current event.
+  void SetCentralityWeight(const float weight) { fCentralityWeight = weight; } ///< Sets weight of the centrality bin of the current event.
+  
+ private:
+
+  const KFTopoPerformance& operator = (const KFTopoPerformance&); ///< Copying of objects of this class is forbidden.
+  KFTopoPerformance(const KFTopoPerformance&); ///< Copying of objects of this class is forbidden.
+   
+  void GetMCParticles();
+  void MatchParticles();
+  void MatchPV();
+  void CalculateEfficiency();
+  void CalculatePVEfficiency();
+  void FindReconstructableMCParticles();
+  void CheckMCParticleIsReconstructable(KFMCParticle &part);
+  void FindReconstructableMCVertices();
+  void FillParticleParameters(KFParticle& TempPart,
+                              int iParticle,
+                              int iP,
+                              int iPV,
+                              TH1F* histoParameters[4][KFPartEfficiencies::nParticles][nHistoPartParam],
+                              TH2F* histoParameters2D[4][KFPartEfficiencies::nParticles][nHistoPartParam2D],
+                              TH3F* histoParameters3D[1][KFPartEfficiencies::nParticles][nHistoPartParam3D],
+                              TH1F* histoFit[KFPartEfficiencies::nParticles][nFitQA] = 0,
+                              TH1F* histoFitDaughtersQA[KFPartEfficiencies::nParticles][nFitQA] = 0,
+                              TH1F* histoDSToParticleQA[KFPartEfficiencies::nParticles][nDSToParticleQA] = 0,
+                              std::vector<int>* multiplicities = 0);
+  
+  const KFParticleTopoReconstructor *fTopoReconstructor; ///< Pointer to the KFParticleTopoReconstructor object with particles and vertices to be analysed.
+
+  std::vector<KFMCVertex> fPrimVertices; ///< Monte Carlo primary vertices.
+  std::vector<int> fMCTrackToMCPVMatch; ///< Matching of Monte Carlo tracks and corresponding primary vertex 
+  std::vector<double> fPVPurity; ///< Purity of the primary vertices.
+  std::vector<double> fPVTracksRate[4]; ///< Ratio in the primary vertices of: 0 - ghost tracks, 1 - from trigger PV, 2 - from pileup, 3 - from physics background.
+  std::vector<int> fNCorrectPVTracks; ///< Number of correctly attached tracks in the corresponding reconstructed primary vertex.
+
+  std::vector<int> fTrackMatch; ///< Matching between reconstructed tracks and 
+  std::vector<KFMCTrack> vMCTracks;  ///< Monte Carlo tracks (parameters of the particle trajectories at the production point).
+  std::vector<KFMCParticle> vMCParticles;  ///< Monte Carlo particles.
+  std::vector<int> fNeutralIndex; ///< Index of the created neutral daughters for missing mass method in vMCTracks for the Monte Carlo track with given index.
+  
+  /** Matching between Monte Carlo and reconstructed particles. MCtoRParticleId[i] provides index of the reconstructed particle in the 
+   ** fTopoReconstructor->GetParticles() array for the Monte Carlo particle (or track) with index "i". **/
+  std::vector<KFPartMatch> MCtoRParticleId;
+  /** Matching between reconstructed and Monte Carlo particles. RtoMCParticleId[i] provides index of the Monte Carlo particle in the 
+   ** vMCTracks and vMCParticles arrays for the reconstructed particle with index "i" from fTopoReconstructor->GetParticles(). **/
+  std::vector<KFPartMatch> RtoMCParticleId;
+
+  /** Matching between Monte Carlo and reconstructed primary vertices. MCtoRPVId[i] provides index of the reconstructed vertex in the 
+   ** fTopoReconstructor->GetPrimVertex() array for the Monte Carlo vertex with index "i". **/
+  std::vector<KFPartMatch> MCtoRPVId;
+  /** Matching between reconstructed and Monte Carlo primary vertices. RtoMCPVId[i] provides index of the Monte Carlo vertex in the 
+   ** fPrimVertices array for the reconstructed vertex with index "i" from fTopoReconstructor->GetPrimVertex(). **/
+  std::vector<KFPartMatch> RtoMCPVId;
+  
+  int fPrintEffFrequency; ///< Frequency in events with which efficiency table is printed on the screen. 
+  
+  int fCentralityBin; ///< Centrality bin for the current event. 
+  float fCentralityWeight; ///< Centrality weight for the current event.
+};
+
+#endif
+#endif //DO_TPCCATRACKER_EFF_PERFORMANCE
diff --git a/field/CMakeLists.txt b/field/CMakeLists.txt
index 2dbd15ccfcfac07249660da43696c3ae67f0069e..6f3244cfb5d1b7543d4aabc195a9a343c99dcde1 100644
--- a/field/CMakeLists.txt
+++ b/field/CMakeLists.txt
@@ -31,9 +31,24 @@ SpdMultiField.cxx
 SpdFieldCreator.cxx 
 SpdFieldMap.cxx
 SpdFieldMapData.cxx
+SpdAxialFieldMap.cxx
+SpdAxialFieldMapData.cxx
 SpdFieldContFact.cxx
 )
 
+set(HEADERS
+SpdAxialFieldMapData.h
+SpdAxialFieldMap.h
+SpdConstField.h
+SpdFieldContFact.h
+SpdFieldCreator.h
+SpdField.h
+SpdFieldMapData.h
+SpdFieldMap.h
+SpdMultiField.h
+SpdRadialField.h
+)
+
 set(LINKDEF FieldLinkDef.h)
 Set(LIBRARY_NAME SpdField)
 Set(DEPENDENCIES Base SpdData SpdCommon)
diff --git a/field/FieldLinkDef.h b/field/FieldLinkDef.h
index 1ce2c16945a0912feb6e201623e9f25f525a5457..0ac76d5a1ac785c3231aaeaad5c3a9f8f281f54f 100644
--- a/field/FieldLinkDef.h
+++ b/field/FieldLinkDef.h
@@ -12,6 +12,8 @@
 #pragma link C++ class SpdMultiField+;
 #pragma link C++ class SpdFieldMap+;
 #pragma link C++ class SpdFieldMapData+;
+#pragma link C++ class SpdAxialFieldMap+;
+#pragma link C++ class SpdAxialFieldMapData+;
 
 #pragma link C++ class SpdFieldCreator+;
 #pragma link C++ class SpdFieldContFact+;
diff --git a/field/SpdAxialFieldMap.cxx b/field/SpdAxialFieldMap.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ce6fe873c1e6111a5fd2900dbd858a46dde03787
--- /dev/null
+++ b/field/SpdAxialFieldMap.cxx
@@ -0,0 +1,507 @@
+//_____________________________________________________________________________
+//
+// SpdAxialFieldMap
+//_____________________________________________________________________________
+
+#include "SpdAxialFieldMap.h"
+#include "SpdFieldPar.h"
+#include <TSystem.h>
+#include <TMath.h>
+
+#include <iostream>
+#include <iomanip>
+
+using std::cout;
+using std::endl;
+
+using TMath::Abs;
+
+#define RTOLERANCE 1.e-12
+
+ClassImp(SpdAxialFieldMap)
+
+//_____________________________________________________________________________
+SpdAxialFieldMap::SpdAxialFieldMap():
+SpdField("SpdAxialFieldMap"),SpdAxialFieldMapData("SpdAxialFieldMapData"),
+fApproxMethod(0)
+{
+    fType = 3;
+    SetTitle("Map");
+    SetNFieldParameters(2);
+}
+
+//_____________________________________________________________________________
+SpdAxialFieldMap::SpdAxialFieldMap(const Char_t* name, const Char_t* type):
+SpdField(name),SpdAxialFieldMapData(name,type),
+fApproxMethod(0)
+{
+    fType = 3;
+    SetTitle("AxialMap");
+    SetNFieldParameters(2);
+}
+
+//_____________________________________________________________________________
+SpdAxialFieldMap::SpdAxialFieldMap(SpdFieldPar* fieldPar, const Char_t* name):
+SpdField(name),SpdAxialFieldMapData(name),
+fApproxMethod(0) 
+{
+   fType = 3;
+   SetTitle("AxialMap");
+   
+   if (!fieldPar) {
+       cout << "-E- <SpdField::SpdAxialFieldMap> Empty parameter container " << endl;
+       SetNFieldParameters(2);
+       return;
+   }
+ 
+   GetFieldParameters(fieldPar);
+   GetRegionParameters(fieldPar); 
+
+   InitData(fFileName);
+   
+   if (Abs(fParams[0]-1.) > 1e-9 || 
+       Abs(fParams[1]-1.) > 1e-9) 
+   {
+      SpdAxialFieldMapData::MultiplyField(fParams[0],fParams[1]);
+   }
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::Clear()
+{
+   SpdAxialFieldMapData::Clear();
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::InitData(TString fileName, TString path)
+{
+   TString pathToData;
+   Bool_t found = false;
+   
+   while (true) 
+   {
+      // if absolute path to magnetic field map
+      if (path.BeginsWith("/") ) {
+         if (!gSystem->AccessPathName(path.Data())) { 
+             pathToData = path;
+             found = true; 
+             cout << "-I- <SpdAxialFieldMap::InitData> Path to the field map: " << pathToData << endl;
+             break; 
+         }
+      }
+      
+      // if MAGFPATH (path to magnetic field map) is set
+      path = getenv("MAGFPATH");
+      path.ReplaceAll("//","/");
+      if (!path.IsNull() ) {
+          if (!gSystem->AccessPathName(path.Data())) { 
+              pathToData = path;
+              found = true; 
+              cout << "-I- <SpdAxialFieldMap::InitData> Path to the field map ($MAGFPATH): " << pathToData << endl;
+              break; 
+          }
+      }
+      
+      // if file was not found look it in the standard path
+      path = TString(getenv("VMCWORKDIR"));
+      path.ReplaceAll("//","/");
+      if (!path.IsNull() ) {
+          (path.EndsWith("/")) ? path += "input/" : path += "/input/";
+          if (!gSystem->AccessPathName(path.Data())) { 
+              pathToData = path;
+              cout << "-I- <SpdAxialFieldMap::InitData> Path to the field map ($VMCWORKDIR/input): " << pathToData << endl;
+              found = true; 
+              break; 
+          }
+      }
+      
+      break;
+   }
+   
+   if (!found) cout << "-I- <SpdAxialFieldMap::InitData> Search for the field map in a current directory: " << endl;
+   
+   return SpdAxialFieldMapData::InitData(fileName,pathToData);
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::InitData() // protected
+{
+   cout <<"-I- <SpdAxialFieldMap::InitData> " << endl;
+ 
+   fRmin = GetRmin();
+   fZmin = SpdAxialFieldMapData::GetZmin();
+    
+   fRstep = GetRstep();
+   fZstep = GetZstep();
+   
+   fRevCellSize = fRstep*fZstep;
+   fRevCellSize = 1./fRevCellSize; 
+   
+   fFr = fBr->GetArray();
+   fFz = fBz->GetArray();
+   
+   fInitLevel = 2;
+   
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::MultiplyField(Double_t v)
+{
+    MultiplyField(v,v);
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::MultiplyField(Double_t vr, Double_t vz)
+{
+   fParams[0] *= vr;
+   fParams[1] *= vz;
+   
+   SpdAxialFieldMapData::MultiplyField(vr,vz);
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::IsInsideRegion(Double_t x, Double_t y, Double_t z) 
+{
+   z = Abs(z); 
+   if (!IsInsideMapRegion(x,y,z)) return kFALSE;
+   if (!fFieldRegion) return kTRUE;
+   return (fSwitchFieldRegion) ? fFieldRegion->IsInside(x,y,z) : kFALSE; 
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::IsInsideRegion(Double_t r, Double_t z)
+{
+   z = Abs(z);  
+   if (!IsInsideMapRegion(r,z)) return kFALSE;
+   if (!fFieldRegion) return kTRUE;
+   return (fSwitchFieldRegion) ? fFieldRegion->IsInside(r,z) : kFALSE; 
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::ResetParameters()
+{
+   SpdField::ResetParameters();
+    
+   fParams[0] = 1.;
+   fParams[1] = 1.;
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::SetNFieldParameters(Int_t n)
+{
+   SpdField::SetNFieldParameters(2);
+   
+   fParams[0] = 1.;
+   fParams[1] = 1.;
+}
+
+//_____________________________________________________________________________
+void SpdAxialFieldMap::SetApproxMethod(Int_t method)
+{ 
+   if (method < 0 || method > 2) {
+       cout << "<SpdAxialFieldMap::SetApproxMethod> "
+            << " Unknown method approximation type: " << method 
+            << ", set default (0) " << endl;
+       fApproxMethod = 0;       
+   }
+   
+   fApproxMethod = method;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::GetBx(Double_t& f, Double_t x, Double_t y, Double_t z)
+{
+   Int_t sgn = (z < 0) ? -1 : 1;
+   z = Abs(z);  
+   
+   if (!IsInsideRegion(x,y,z)) return kFALSE;
+      
+   Double_t v = TMath::Sqrt(x*x+y*y);
+   
+   FindCell(v,z);
+   
+   if (v < RTOLERANCE) { // very close to z-axis  FIXME
+       // x = 0, y = 0 => phi = pi, cos(phi) = -1 
+       // (see ROOT TVector2 phi angle definition)
+       //v = -1.; 
+       f = 0;
+       return kTRUE;
+   }
+   else {
+       if (Abs(x) > v*1.e-12) v = x/v;   // cos(phi)
+       else { // cos(phi) < 1e-12 => Bx = 0
+           f = 0; 
+           return kTRUE;
+       }
+   }
+   
+   switch (fApproxMethod) 
+   {
+      case 0 : { f = sgn*v*Approx_0(fFr); return kTRUE; }
+      case 1 : { f = sgn*v*Approx_1(fFr); return kTRUE; }
+      case 2 : { f = sgn*v*Approx_2(fFr); return kTRUE; }  
+   
+      default : return kFALSE;
+   } 
+   
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::GetBy(Double_t& f, Double_t x, Double_t y, Double_t z)
+{
+   Int_t sgn = (z < 0) ? -1 : 1;
+   z = Abs(z);
+   
+   if (!IsInsideRegion(x,y,z)) return kFALSE;
+   
+   Double_t v = TMath::Sqrt(x*x+y*y);
+   
+   FindCell(v,z);
+   
+   if (v < RTOLERANCE) { // very close to z-axis  FIXME
+       // x = 0, y = 0 => phi = pi, sin(phi) = 0 => By = 0  
+       // (see ROOT TVector2 phi angle definition)
+       f = 0; 
+       return kTRUE;
+   }
+   else {
+       if (Abs(y) > v*1.e-12) v = y/v;   // sin(phi)
+       else { // sin(phi) < 1e-12 => By = 0
+           f = 0; 
+           return kTRUE;
+       }
+   }
+     
+   switch (fApproxMethod) 
+   {
+      case 0 : { f = sgn*v*Approx_0(fFr); return kTRUE; }
+      case 1 : { f = sgn*v*Approx_1(fFr); return kTRUE; }
+      case 2 : { f = sgn*v*Approx_2(fFr); return kTRUE; }  
+   
+      default : return kFALSE;
+   } 
+    
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::GetBz(Double_t& f, Double_t x, Double_t y, Double_t z)
+{
+   z = Abs(z);
+    
+   if (!IsInsideRegion(x,y,z)) return kFALSE;
+   
+   Double_t v = TMath::Sqrt(x*x+y*y);
+   
+   FindCell(v,z);
+   
+   switch (fApproxMethod) 
+   {
+      case 0 : { f = Approx_0(fFz); return kTRUE; }
+      case 1 : { f = Approx_1(fFz); return kTRUE; }
+      case 2 : { f = Approx_2(fFz); return kTRUE; }  
+   
+      default : return kFALSE;
+   }
+   
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::GetField(const Double_t point[3], Double_t* bField)
+{
+   Double_t z = point[2]; 
+   Int_t sgn = (z < 0) ? -1 : 1; 
+   z = Abs(z);
+   
+   if (!IsInsideRegion(point[0],point[1],z)) return kFALSE;
+   
+   Double_t v = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
+   
+   FindCell(v,z);
+   
+   Double_t cosp(0), sinp(0);// cos(phi), sin(phi)
+   
+   if (v < RTOLERANCE) {
+       // phi = pi, cos(phi) = -1, sin(phi) = 0 
+       // (see ROOT TVector2 phi angle definition for x = y = 0)
+       //cosp = -1;
+       //sinp =  0.; 
+       switch (fApproxMethod) 
+       {
+          case 0 : bField[2] = Approx_0(fFz);
+          case 1 : bField[2] = Approx_1(fFz);
+          case 2 : bField[2] = Approx_2(fFz);
+       }
+       
+       bField[0] = 0;
+       bField[1] = 0;
+       
+       return kTRUE;
+   }
+   else {
+       if (Abs(point[0]) > v*1.e-12) cosp = sgn*point[0]/v;  
+       if (Abs(point[1]) > v*1.e-12) sinp = sgn*point[1]/v; 
+   }
+   
+   switch (fApproxMethod) 
+   {
+      case 0 : {
+                 v = Approx_0(fFr);
+                 
+                 bField[0] = cosp*v; 
+                 bField[1] = sinp*v; 
+                 bField[2] = Approx_0(fFz);
+                 
+                 //cout << " Point: " <<  point[0]  << " " <<  point[1]  << " " << point[2]  << endl;
+                 //cout << " Field: " <<  bField[0] << " " <<  bField[1] << " " << bField[2] << endl;
+                 
+                 return kTRUE;
+               }
+      case 1 : { 
+                 v = Approx_1(fFr);
+                 
+                 bField[0] = cosp*v; 
+                 bField[1] = sinp*v; 
+                 bField[2] = Approx_1(fFz);                 
+   
+                 //cout << " Point: " <<  point[0]  << " " <<  point[1]  << " " << point[2]  << endl;
+                 //cout << " Field: " <<  bField[0] << " " <<  bField[1] << " " << bField[2] << endl;                
+                
+                 return kTRUE;
+               }
+      case 2 : { 
+                 v = Approx_2(fFr);
+                 
+                 bField[0] = cosp*v; 
+                 bField[1] = sinp*v; 
+                 bField[2] = Approx_2(fFz);         
+                 
+                 //cout << " Point: " <<  point[0]  << " " <<  point[1]  << " " << point[2]  << endl;
+                 //cout << " Field: " <<  bField[0] << " " <<  bField[1] << " " << bField[2] << endl;
+                 
+                 return kTRUE;
+               }
+      default : return kFALSE;
+   }
+  
+   return kFALSE;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::GetParameters(SpdFieldPar* pars) // protected
+{ 
+   pars->GetParameter(Add_Name("filename"),fFileName);
+   if (fFileName == "unknown") fFileName = "";
+   
+   pars->GetParameter(Add_Name("approx.type"),fApproxMethod); 
+   
+   return kTRUE; 
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMap::PutParameters(SpdFieldPar* pars) // protected
+{ 
+   if (fFileName.IsWhitespace()) pars->SetParameter(Add_Name("filename"),"unknown");
+   else pars->SetParameter(Add_Name("filename"),fFileName);
+   
+   pars->SetParameter(Add_Name("approx.type"),fApproxMethod);  
+   
+   return kTRUE; 
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________ 
+void SpdAxialFieldMap::PrintFieldParameters() const
+{
+   cout << "<SpdAxialFieldMap::PrintFieldParameters>" << endl;
+   
+   cout << "Init level:           " << fInitLevel << endl;
+   cout << "Approximation method: " << fApproxMethod << endl;
+   
+   cout << endl;
+   
+   printf(" M(Br) = %12.6e\n",fParams[0]);
+   printf(" M(Bz) = %12.6e\n",fParams[1]);
+  
+   cout << endl;
+   
+   SpdAxialFieldMapData::PrintData();
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________ 
+void SpdAxialFieldMap::FindCell(const Double_t& r, const Double_t& z) 
+{
+    static Int_t iz, ir;
+   
+    iz = Int_t((z - fZmin)/fZstep);
+    ir = Int_t((r - fRmin)/fRstep);
+    
+    fI_00 = ir*fNz + iz;  // (z0,r0)
+    fI_10 = fI_00 + 1;    // (z1,r0)
+    fI_01 = fI_00 + fNz;  // (z0,r1)
+    fI_11 = fI_01 + 1;    // (z1,r1)
+
+    fDz1 = z - fZstep * iz - fZmin; // dz1 = z-z1
+    fDr1 = r - fRstep * ir - fRmin; // dr1 = r-r1
+   
+    fDz2 = fZstep - fDz1;  // dz2 = z2-z  
+    fDr2 = fRstep - fDr1;  // dr2 = r2-r
+}
+
+//_____________________________________________________________________________ 
+Double_t SpdAxialFieldMap::Approx_0(const Double_t* V) const
+{
+    static Double_t value = 0;
+
+    value  = fDz1 * (fDr2 * V[fI_10] + fDr1 * V[fI_11])   // F(10) * dz1*dr2 + F(11) * dz1*dr1
+           + fDz2 * (fDr2 * V[fI_00] + fDr1 * V[fI_01]);  // F(00) * dz2*dr2 + F(01) * dz2*dr1
+
+//     cout << "[z0,r0] F(00): " << fI_00 << " " << V[fI_00] << endl;
+//     cout << "[z1,r0] F(10): " << fI_10 << " " << V[fI_10] << endl;
+//     cout << "[z0,r1] F(01): " << fI_01 << " " << V[fI_01] << endl;
+//     cout << "[z1,r1] F(11): " << fI_11 << " " << V[fI_11] << endl;
+//     
+//     cout << "value: " << fRevCellSize * value  << ";   Dz1, Dr1 = " << fDz1 << ", " << fDr1 << "\n\n";
+     
+    return fRevCellSize * value;
+}
+
+//_____________________________________________________________________________ 
+Double_t SpdAxialFieldMap::Approx_1(const Double_t* V) const
+{
+   if (fDr1 < 0.5*fRstep) 
+       return (fDz1 < 0.5*fZstep) ? V[fI_00] : V[fI_10]; 
+   else 
+       return (fDz1 < 0.5*fZstep) ? V[fI_01] : V[fI_11];
+}
+
+//_____________________________________________________________________________ 
+Double_t SpdAxialFieldMap::Approx_2(const Double_t* V) const
+{
+   static Double_t value = 0.;
+   
+   value = V[fI_00] + V[fI_10] + V[fI_01] + V[fI_11];  
+    
+   return 0.25 * value;
+}
+
+
+
diff --git a/field/SpdAxialFieldMap.h b/field/SpdAxialFieldMap.h
new file mode 100644
index 0000000000000000000000000000000000000000..f84d128a313351a5cf7dae4c976e51d2ff0fc936
--- /dev/null
+++ b/field/SpdAxialFieldMap.h
@@ -0,0 +1,123 @@
+// $Id$
+// Author: artur   2020/07/04
+
+#ifndef __SPDAXIALFIELDMAP_H__
+#define __SPDAXIALFIELDMAP_H__
+
+#include "SpdField.h"
+#include "SpdAxialFieldMapData.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdAxialFieldMap                                                           //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdFieldPar;
+
+class SpdAxialFieldMap : public SpdField, public SpdAxialFieldMapData {
+  
+public:
+  
+    SpdAxialFieldMap();
+    SpdAxialFieldMap(const Char_t* name, const Char_t* type = "");
+    SpdAxialFieldMap(SpdFieldPar* fieldPar, const Char_t* name = "SpdAxialFieldMap");
+    
+    virtual ~SpdAxialFieldMap() {}
+    
+    virtual void Clear();
+    virtual void ResetParameters();
+    
+    virtual Bool_t InitData(TString fileName, TString path = "");
+    
+    virtual void Init() {};
+    
+    /* ----- transform field data ----- */
+   
+    virtual void MultiplyField(Double_t v);
+    virtual void MultiplyField(Double_t vr, Double_t vz);
+    
+    virtual void RotateField(Double_t /*angle*/, Double_t /*theta*/, Double_t /*phi*/) {}
+       
+    /* ----- setters ----- */
+  
+    virtual void SetNFieldParameters(Int_t n /*number of parameters*/);
+    
+    void SetApproxMethod(Int_t method);
+    
+    /* ----- getters ----- */
+    
+    virtual Bool_t IsInsideRegion(Double_t x, Double_t y, Double_t z);
+    virtual Bool_t IsInsideRegion(Double_t r, Double_t z);
+    
+    inline  Int_t  GetApproxMethod() { return fApproxMethod; }
+    
+    virtual Bool_t GetField(const Double_t point[3], Double_t* bField); 
+    
+    virtual Bool_t GetBx(Double_t& f, Double_t x, Double_t y, Double_t z);
+    virtual Bool_t GetBy(Double_t& f, Double_t x, Double_t y, Double_t z);
+    virtual Bool_t GetBz(Double_t& f, Double_t x, Double_t y, Double_t z);
+    
+    inline Double_t  GetRStep() const { return fRstep; }
+    inline Double_t  GetZStep() const { return fZstep; }
+    
+    virtual Double_t GetZmin()  const { return -SpdAxialFieldMapData::GetZmax(); }
+    virtual Double_t GetZmax()  const { return  SpdAxialFieldMapData::GetZmax(); }
+    
+    virtual Int_t    GetNz()    const { return 2*fNz-1; }
+    
+    inline Double_t  GetXstep() const { return fRstep; }
+    inline Double_t  GetYstep() const { return fRstep; }
+    inline Int_t     GetNx()    const { return 2*fNr-1; }
+    inline Int_t     GetNy()    const { return 2*fNr-1; }
+    inline Double_t  GetXmin()  const { return -GetRmax(); }
+    inline Double_t  GetYmin()  const { return -GetRmax(); }
+    inline Double_t  GetXmax()  const { return  GetRmax(); }
+    inline Double_t  GetYmax()  const { return  GetRmax(); }
+    
+    /* ------ print ------ */
+    
+    virtual void PrintFieldParameters() const;
+    
+protected:
+  
+    virtual Bool_t GetParameters(SpdFieldPar* pars);
+    virtual Bool_t PutParameters(SpdFieldPar* pars);
+    
+    virtual Bool_t InitData();
+    
+    virtual void   FindCell(const Double_t& r, const Double_t& z); 
+    
+    /* approximation methods */
+    
+    virtual Double_t Approx_0(const Double_t* array) const;
+    virtual Double_t Approx_1(const Double_t* array) const;
+    virtual Double_t Approx_2(const Double_t* array) const;
+    
+    Int_t   fApproxMethod;
+    
+    /* const memebers (DATA MAP) */
+    
+    Double_t fRmin;
+    Double_t fZmin;
+    
+    Double_t fRstep;
+    Double_t fZstep;
+    
+    Double_t fRevCellSize;
+    
+    const Double_t* fFr;
+    const Double_t* fFz;
+    
+    /* auxiliary memebers */
+    
+    Double_t fDz1, fDr1, fDz2, fDr2;
+    Int_t    fI_00, fI_10, fI_01, fI_11;
+           
+    ClassDef(SpdAxialFieldMap,1) 
+
+}; 
+
+#endif /*__SPDAXIALFIELDMAP_H__ */
diff --git a/field/SpdAxialFieldMapData.cxx b/field/SpdAxialFieldMapData.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..21d874bd1165aa9f8395245b08b04c7105bbfb67
--- /dev/null
+++ b/field/SpdAxialFieldMapData.cxx
@@ -0,0 +1,809 @@
+// $Id$
+// Author: artur   2020/07/04
+
+
+//_____________________________________________________________________________
+//
+// SpdAxialFieldMapData
+//_____________________________________________________________________________
+
+#include "SpdAxialFieldMapData.h"
+
+#include <TMath.h>
+#include <TVector3.h>
+
+#include "SpdAxialFieldMapData.h"
+
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+
+using std::cout;
+using std::endl;
+
+using TMath::DegToRad;
+
+ClassImp(SpdAxialFieldMapData)
+
+//_____________________________________________________________________________
+SpdAxialFieldMapData::SpdAxialFieldMapData():
+fMapName("SpdAxialFieldMapData"),
+fPathToData(""),fFileName(""),
+fScaleUnit(1.),fFieldUnit(1.),
+fInitLevel(0),
+fMapRegion(0),
+fNr(0),fNz(0), 
+fBr(0),fBz(0)
+{
+ 
+}
+
+//_____________________________________________________________________________________
+SpdAxialFieldMapData::SpdAxialFieldMapData(const Char_t* name, const Char_t* type):
+fMapName(name),
+fPathToData(""),fFileName(""),
+fScaleUnit(1.),fFieldUnit(1.),
+fInitLevel(0),
+fMapRegion(0),
+fNr(0),fNz(0), 
+fBr(0),fBz(0)     
+{  
+   SetMapType(type);
+}
+
+
+//_____________________________________________________________________________
+SpdAxialFieldMapData::~SpdAxialFieldMapData() 
+{
+   if (fBr) delete fBr;
+   if (fBz) delete fBz;
+   
+   if (fMapRegion) delete fMapRegion;
+}
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::Clear()
+{  
+   fPathToData = "";
+   fFileName = "";
+ 
+   ClearData();
+}
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::ClearData() 
+{
+   fMapType = "undefined";
+   
+   fFieldUnit = 1.;
+   fScaleUnit = 1.;
+   
+   if (fMapRegion) { delete fMapRegion; fMapRegion = 0; }
+     
+   fNr = 0; 
+   fNz = 0;
+   
+   if (fBr) { delete fBr; fBr = 0; }
+   if (fBz) { delete fBz; fBz = 0; }
+   
+   fInitLevel = 0;
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::IsGridInit() const
+{ 
+   if (fNr < 2 || fNz < 2) return kFALSE; 
+   if (!fMapRegion || !fMapRegion->IsRegionInit()) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::IsDataInit() const
+{
+   return (fBr && fBz); 
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::IsInsideMapRegion(Double_t x, Double_t y, Double_t z) const
+{
+   return (fMapRegion) ? fMapRegion->IsInside(x,y,z) : kFALSE;
+}
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::IsInsideMapRegion(Double_t r, Double_t z) const
+{
+   return (fMapRegion) ? fMapRegion->IsInside(r,z) : kFALSE;
+}
+
+//_____________________________________________________________________________________
+Double_t SpdAxialFieldMapData::GetRstep() const 
+{ 
+   if (!IsGridInit()) return 0;
+   return fMapRegion->GetDR()/(fNr - 1); 
+}
+
+//_____________________________________________________________________________________
+Double_t SpdAxialFieldMapData::GetZstep() const 
+{ 
+   if (!IsGridInit()) return 0;
+   return fMapRegion->GetLz()/(fNz - 1);
+}
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::SetPathToData(TString path)
+{
+   if (path.IsWhitespace()) {
+       fPathToData = "";
+       return;
+   }
+   
+   fPathToData = path;
+   
+   if (!path.EndsWith("/")) fPathToData += "/";
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::MultiplyField(Double_t v)
+{
+   MultiplyField(v,v);
+}
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::MultiplyField(Double_t vr, Double_t vz)
+{
+   if (GetInitLevel() < 1) return;
+
+   for (Int_t i(0); i < GetNTotal(); i++) {    
+        fBr->AddAt(fBr->At(i)*vr,i);
+        fBz->AddAt(fBz->At(i)*vz,i);   
+   }
+}
+
+//_____________________________________________________________________________
+Bool_t SpdAxialFieldMapData::GetMinMaxStat(Double_t* B) const
+{
+   // fill (B,Bz,Br)[min,max]
+  
+   if (!B) return kFALSE;
+     
+   memset(B,0,6*sizeof(Double_t));
+   
+   if (!IsDataInit()) return kFALSE;
+   
+   Int_t nTot = GetNTotal();
+   
+   for (Int_t i(0); i<3; i++) { B[2*i] = 1e20; B[2*i+1] = -1e20; }
+   
+   Double_t br, bz, b;
+   
+   for (Int_t i(0); i<nTot; i++) 
+   {
+        br = fBr->At(i);
+        bz = fBz->At(i);
+        b  = TMath::Sqrt(br*br+bz*bz);
+        
+        if (B[0] > b)  B[0] = b; // min  
+        if (B[1] < b)  B[1] = b; // max
+        
+        if (B[2] > bz) B[2] = bz;
+        if (B[3] < bz) B[3] = bz;
+        
+        if (B[4] > br) B[4] = br;
+        if (B[5] < br) B[5] = br;
+   }
+   
+   return kTRUE;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+void SpdAxialFieldMapData::SetMapType(TString type) // protected
+{ 
+   if (!type.IsWhitespace()) fMapType = type;
+   else fMapType = "undefined";
+}  
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::SetScaleUnit(TString unit) // protected
+{
+        if (unit == "mm") fScaleUnit = 0.1;
+   else if (unit == "m")  fScaleUnit = 100.0;
+   else if (unit == "cm") fScaleUnit = 1.0;
+   else {
+       cout << "-E- <SpdAxialFieldMapData::SetScaleUnit> Unknown unit: " << unit << endl;
+       fScaleUnit = 1;
+       return kFALSE;
+   }
+   return kTRUE;
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::SetFieldUnit(TString unit) // protected
+{
+        if (unit == "G")  fFieldUnit = 0.001;
+   else if (unit == "T")  fFieldUnit = 10.0;
+   else if (unit == "kG") fFieldUnit = 1.0;
+   else {
+       cout << "-E- <SpdAxialFieldMapData::SetFieldUnit> Unknown unit: " << unit << endl;
+       fFieldUnit = 1;
+       return kFALSE;
+   }
+   return kTRUE;
+}
+
+//_____________________________________________________________________________________
+TString SpdAxialFieldMapData::GetScaleUnitAsString() const 
+{
+   if (fScaleUnit == 0.1)   return "mm";
+   if (fScaleUnit == 100.0) return "m";
+   if (fScaleUnit == 1.0)   return "cm";
+  
+   cout << "-E- <SpdAxialFieldMapData::GetScaleUnitString> Unknown unit: " << fScaleUnit << endl;
+   return "unknown";
+}
+
+//_____________________________________________________________________________________
+TString SpdAxialFieldMapData::GetFieldUnitAsString() const 
+{
+   if (fFieldUnit == 0.001) return "G";
+   if (fFieldUnit == 10.0)  return "T";
+   if (fFieldUnit == 1.0)   return "kG";
+  
+   cout << "-E- <SpdAxialFieldMapData::GetFieldUnitString> Unknown unit: " << fFieldUnit << endl;
+   return "unknown";
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::InitData(TString fileName, TString path)
+{
+   Clear();
+  
+   if (fileName.IsWhitespace()) {
+       cout << "-E- <SpdAxialFieldMapData::Init> No data file " << endl;
+       return kFALSE;
+   }
+   
+   SetPathToData(path);
+   fFileName = fileName;
+       
+   if (fileName.EndsWith(".dat")) {
+       if (!ReadAsciiFile()) {
+           cout << "-F- <SpdAxialFieldMapData::Init> Bad data (*.dat) file " << endl;
+           exit(1);
+       }
+   }
+   else if (fileName.EndsWith(".bin")) { 
+       if (!ReadBinaryFile()) {
+           cout << "-F- <SpdAxialFieldMapData::Init> Bad data (*.bin) file " << endl;
+           exit(1);
+       }
+   }
+   else {
+       cout << "-E- <SpdFieldMapData::Init> No proper file name defined: "
+            << fileName << endl;         
+       Clear();
+       return kFALSE;
+   }
+   
+   fInitLevel = 1;
+   return InitData();
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::InitData(const SpdAxialFieldMapData* data)
+{
+   Clear();
+   
+   if (!data) {
+       cout << "-E- <SpdAxialFieldMapData::Init> No data " << endl;
+       return kFALSE;
+   }
+   
+   fPathToData = data->GetPathToData();
+   fFileName = data->GetFileName();
+   
+   fMapName = data->GetMapName();
+   fMapType = data->GetMapType();
+   
+   fScaleUnit = data->GetScaleUnit();
+   fFieldUnit = data->GetFieldUnit();
+   
+   // init grid
+   
+   if (fMapRegion) delete fMapRegion;
+   fMapRegion = new SpdTubeRegion();
+   
+   fMapRegion->SetTubeRegion(data->GetRmin(),data->GetRmax(),
+                             data->GetZmin(),data->GetZmax());
+  
+   fNr = data->GetNr();
+   fNz = data->GetNz();
+   
+   if (!IsGridInit()) {
+       cout << "-E- <SpdFieldMapData::Init> Bad grid parameters " << endl;
+       Clear();
+       return kFALSE;
+   }
+
+   // init data arrays
+
+   if (data->IsDataInit()) {
+       fBr = new TArrayD(*(data->GetBr()));
+       fBz = new TArrayD(*(data->GetBz()));
+   }   
+   else {
+       Int_t nt = GetNTotal();
+       fBr = new TArrayD(nt);
+       fBz = new TArrayD(nt);
+   }
+   
+   fInitLevel = 1;
+   return InitData();
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::InitData(Double_t rmin, Double_t rmax, Int_t nr,
+                                      Double_t zmin, Double_t zmax, Int_t nz)
+{
+   ClearData();
+   
+   if (fMapRegion) delete fMapRegion;
+   fMapRegion = new SpdTubeRegion();
+   
+   fMapRegion->SetTubeRegion(rmin,rmax,zmin,zmax);  
+
+   fNr = nr; 
+   fNz = nz;
+   
+   if (!IsGridInit()) {
+       cout << "-E- <SpdAxialFieldMapData::Init> Bad grid parameters " << endl;
+       ClearData();
+       return kFALSE;
+   }
+   
+   Int_t nt = GetNTotal();
+   
+   fBr = new TArrayD(nt);
+   fBz = new TArrayD(nt);
+   
+   fInitLevel = 1;
+   return InitData();
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::InitData()
+{
+   return kTRUE;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+Bool_t SpdAxialFieldMapData::ReadAsciiFile()  // protected
+{
+  TString fileName = fFileName; 
+  
+  if (!fPathToData.IsWhitespace()) fileName = fPathToData + fileName;
+ 
+  cout << "-I- <SpdAxialFieldMapData::ReadAsciiFile> Reading file: " 
+       << fileName << endl;
+      
+  std::ifstream mapFile(fileName);
+
+  if (!mapFile.is_open()) {
+      cout << "-E- <SpdAxialFieldMapData:ReadAsciiFile> Could not open file: " << fileName << endl;
+      return kFALSE;
+  }
+  
+  // Read map type
+  mapFile >> fMapType;
+  
+  // Read Units
+  TString unit;
+  
+  mapFile >> unit; 
+  if (!SetScaleUnit(unit)) return kFALSE;
+  
+  mapFile >> unit; 
+  if (!SetFieldUnit(unit)) return kFALSE;
+   
+  // Read grid parameters
+  
+  Double_t rmin, rmax, zmin, zmax;
+  
+  mapFile >> rmin >> rmax >> fNr;
+  mapFile >> zmin >> zmax >> fNz;
+  
+  if (fMapRegion) delete fMapRegion;
+  fMapRegion = new SpdTubeRegion();
+  
+  fMapRegion->SetTubeRegion(rmin*fScaleUnit, rmax*fScaleUnit,
+                            zmin*fScaleUnit, zmax*fScaleUnit);  
+  
+  if (!IsGridInit()) {
+      cout << "-E- <SpdAxialFieldMapData:ReadAsciiFile> Bad grid parameters: ";
+      cout << "N(r,z) = " << fNr << ", " << fNz << endl;
+      cout << "[min,max] = R[" << rmin << ", " << rmax << "], " 
+                     << "  Z[" << zmin << ", " << zmax << "]" << endl;
+      return kFALSE;
+  }
+ 
+  // Create field arrays
+  
+  Int_t nTot = GetNTotal();
+     
+  fBr = new TArrayD(nTot);
+  fBz = new TArrayD(nTot);
+  
+  // Read the field values
+ 
+  Double_t rr, zz;
+  Double_t br, bz;
+ 
+  Int_t n = 0;    
+  for (; n < nTot; n++) {    
+
+       if (!mapFile.good()) {
+           cout << "-E- <SpdAxialFieldMapData::ReadAsciiFile> I/O Error at position " << n << endl;
+           break;
+       }
+      
+       mapFile >> rr >> zz;
+       mapFile >> br >> bz;
+      
+       //cout << n << "/" << nTot << " "
+       //     << " point: " << rr << " " << zz 
+       //     << " field: " << br << " " << bz 
+       //     << endl;
+               
+       fBr->AddAt(br*fFieldUnit, n);
+       fBz->AddAt(bz*fFieldUnit, n);
+    
+       if (mapFile.eof()) {
+           cout << "-E- <SpdAxialFieldMapData::ReadAsciiFile> End of file reached at position " << n << endl;
+           break;
+       }     
+  }
+  
+  mapFile.close();
+  
+  //cout << fBr->At(0) << " " <<  fBz->At(0) << endl; 
+  //cout << fBr->At(n-1) << " " <<  fBz->At(n-1) << endl; 
+  
+  cout << "-I- <SpdAxialFieldMapData::ReadAsciiFile> Read field values: "
+       << n  << "/" << nTot << endl;  
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________ 
+Bool_t SpdAxialFieldMapData::ReadBinaryFile()
+{
+  TString fileName = fFileName; 
+  
+  if (!fPathToData.IsWhitespace()) fileName = fPathToData + fileName;
+ 
+  cout << "-I- <SpdAxialFieldMapData::ReadBinaryFile> Reading file: " 
+       << fileName << endl;
+      
+  FILE* fl = fopen(fileName.Data(),"rb");
+  
+  if (!fl) {
+      cout << "-E- <SpdAxialFieldMapData::ReadBinaryFile> File cannot be opened: " 
+           << fileName << endl;
+      return kFALSE;     
+  }
+  
+  Int_t len;
+  char  sdata[256];
+  Int_t si = sizeof(Int_t);
+  Int_t sd = sizeof(Double_t);
+ 
+   // Read map type
+  fread(&len,si,1,fl);
+  fgets(sdata,len,fl); 
+  
+  fMapType = sdata;
+  
+  // Read Units
+  
+  fread(&len,si,1,fl);
+  fgets(sdata,len,fl); 
+  
+  if (!SetScaleUnit(TString(sdata,len-1))) return kFALSE;
+ 
+  fread(&len,si,1,fl);
+  fgets(sdata,len,fl); 
+  
+  if (!SetFieldUnit(TString(sdata,len-1))) return kFALSE;
+  
+  // Read grid parameters
+  
+  Double_t rmin, rmax, zmin, zmax;
+  
+  fread(&rmin,sd,1,fl); 
+  fread(&rmax,sd,1,fl);
+  fread(&fNr,si,1,fl);
+  
+  fread(&zmin,sd,1,fl); 
+  fread(&zmax,sd,1,fl);
+  fread(&fNz,si,1,fl);
+  
+  if (fMapRegion) delete fMapRegion;
+  fMapRegion = new SpdTubeRegion();
+  
+  fMapRegion->SetTubeRegion(rmin*fScaleUnit, rmax*fScaleUnit,
+                            zmin*fScaleUnit, zmax*fScaleUnit);  
+  
+  if (!IsGridInit()) {
+      cout << "-E- <SpdAxialFieldMapData:ReadBinaryFile> Bad grid parameters: ";
+      cout << "N(r,z) = " << fNr << ", " << fNz << endl;
+      cout << "[min,max] = R[" << rmin << ", " << rmax << "], " 
+                     << "  Z[" << zmin << ", " << zmax << "]" << endl;
+           
+      fclose(fl);
+     
+      return kFALSE;
+  }
+
+  // Create field arrays
+  
+  Int_t nTot = GetNTotal();
+  
+  fBr = new TArrayD(nTot);
+  fBz = new TArrayD(nTot);
+  
+  // Read the field values
+  
+  Double_t vd;
+  
+  Int_t n = 0;    
+  for (; n < nTot; n++) {               
+       fread(&vd,sd,1,fl); fBr->AddAt(vd*fFieldUnit, n);
+       fread(&vd,sd,1,fl); fBz->AddAt(vd*fFieldUnit, n);
+  }
+ 
+  fclose(fl);     
+  
+  //cout << fBr->At(0) << " " <<  fBz->At(0) << endl; 
+  //cout << fBr->At(n-1) << " " <<  fBz->At(n-1) << endl; 
+   
+  cout << "-I- <SpdAxialFieldMapData::ReadBinaryFile> Read field values: "
+       << n  << "/" << nTot << endl;  
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________ 
+Bool_t SpdAxialFieldMapData::WriteAsciiFile(TString fileName, TString dirName) const
+{
+  // Write the field map to an ASCII file    
+    
+  if (fileName.IsWhitespace()) {
+      cout << "-E- <SpdAxialFieldMapData::WriteAsciiFile> File is not defined " << endl;
+      return kFALSE;
+  }
+  
+  if (!fileName.EndsWith(".dat")) fileName += ".dat"; 
+  
+  if (!dirName.IsWhitespace()) {
+      if (!dirName.EndsWith("/")) dirName += "/"; 
+      fileName = dirName + fileName;
+  }
+  
+  cout << "-I- <SpdAxialFieldMapData::WriteAsciiFile> Write field map data to an ASCII file: "
+       << fileName << endl;
+       
+  std::ofstream mapFile(fileName);
+  if (!mapFile.is_open()) {
+      cout << "-E- <SpdAxialFieldMapData::WriteAsciiFile> Could not open file: " 
+           << fileName << endl;
+      return kFALSE;
+  }
+     
+  /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */
+//   Double_t sunit_tmp = fScaleUnit;
+//   Double_t funit_tmp = fFieldUnit;
+//   
+//   Double_t& su_tmp = const_cast<Double_t&>(fScaleUnit);
+//   Double_t& fu_tmp = const_cast<Double_t&>(fFieldUnit);
+//   
+//   su_tmp = 1.;
+//   fu_tmp = 1.;
+  /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */
+ 
+  mapFile << fMapType << endl;
+  
+  mapFile << GetScaleUnitAsString() << " " << GetFieldUnitAsString() << endl;
+   
+  if (!IsDataInit()) {
+    
+      mapFile << GetRmin()/fScaleUnit << " " << GetRmax()/fScaleUnit << " " << 0 << endl;
+      mapFile << GetZmin()/fScaleUnit << " " << GetZmax()/fScaleUnit << " " << 0 << endl;
+      
+      mapFile.close();
+      
+      /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */
+//       su_tmp = sunit_tmp;
+//       fu_tmp = funit_tmp;
+      /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */ 
+              
+      cout << "-W- <SpdAxialFieldMapData::WriteAsciiFile> Empty data arrays " << endl;
+      
+      return kFALSE;
+  }
+    
+  mapFile << GetRmin()/fScaleUnit << " " << GetRmax()/fScaleUnit << " " << fNr << endl;
+  mapFile << GetZmin()/fScaleUnit << " " << GetZmax()/fScaleUnit << " " << fNz << endl;
+  
+  Double_t dr = GetRstep();
+  Double_t dz = GetZstep();
+  
+  Int_t index;
+  
+  for (Int_t ir(0); ir < fNr; ir++) {
+  for (Int_t iz(0); iz < fNz; iz++) {
+
+        index = ir*fNz + iz;
+     
+        mapFile << Form("%20.14f %20.14f %20.14f %20.14f \n",
+                        (GetRmin() + ir*dr)/fScaleUnit,
+                        (GetZmin() + iz*dz)/fScaleUnit,
+                        fBr->At(index)/fFieldUnit,
+                        fBz->At(index)/fFieldUnit);        
+    
+  }}
+  
+  /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */
+//   su_tmp = sunit_tmp;
+//   fu_tmp = funit_tmp;
+  /* FIXME  *  FIXME *  FIXME  *  FIXME   *  FIXME  */
+  
+  mapFile.close(); 
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________ 
+Bool_t SpdAxialFieldMapData::WriteBinaryFile(TString fileName, TString dirName) const
+{
+  // Write the field map to an ASCII file    
+    
+  if (fileName.IsWhitespace()) {
+      cout << "-E- <SpdAxialFieldMapData::WriteBinaryFile> File is not defined " << endl;
+      return kFALSE;
+  }
+  
+  if (!fileName.EndsWith(".bin")) fileName += ".bin"; 
+  
+  if (!dirName.IsWhitespace()) {
+      if (!dirName.EndsWith("/")) dirName += "/"; 
+      fileName = dirName + fileName;
+  }
+  
+  cout << "-I- <SpdAxialFieldMapData::WriteBinaryFile> Write field map data to an BINARY file: "
+       << fileName << endl;
+
+  FILE* fl = fopen(fileName.Data(),"wb");
+  
+  if (!fl) {
+      cout << "-E- <SpdAxialFieldMapData::WriteBinaryFile> File cannot be written: " 
+           << fileName << endl;
+      return kFALSE;     
+  }
+   
+  Int_t len , vi;
+  TString sdata;
+  Double_t vd;
+  Int_t si = sizeof(Int_t);
+  Int_t sd = sizeof(Double_t);
+  
+  len = fMapType.Length()+1;
+  fwrite(&len,si,1,fl);
+  fputs(fMapType.Data(),fl);
+  
+  sdata = GetScaleUnitAsString();
+ 
+  len = sdata.Length()+1;
+  fwrite(&len,si,1,fl);
+  fputs(sdata.Data(),fl);
+  
+  sdata = GetFieldUnitAsString();
+ 
+  len = sdata.Length()+1;
+  fwrite(&len,si,1,fl);
+  fputs(sdata.Data(),fl);
+  
+  Double_t value;
+  
+  // Save grid
+
+  if (!IsDataInit()) {
+     
+      vi = 0;
+     
+      vd = GetRmin()/fScaleUnit; fwrite(&vd,sd,1,fl);
+      vd = GetRmax()/fScaleUnit; fwrite(&vd,sd,1,fl);
+      fwrite(&vi,si,1,fl);
+      
+      vd = GetZmin()/fScaleUnit; fwrite(&vd,sd,1,fl);
+      vd = GetZmax()/fScaleUnit; fwrite(&vd,sd,1,fl);
+      fwrite(&vi,si,1,fl);
+     
+      fclose(fl);
+   
+      cout << "-W- <SpdAxialFieldMapData::WriteBinaryFile> Empty data arrays " << endl;
+      
+      return kFALSE;
+  }
+  
+  vd = GetRmin()/fScaleUnit; fwrite(&vd,sd,1,fl);
+  vd = GetRmax()/fScaleUnit; fwrite(&vd,sd,1,fl);
+  fwrite(&fNr,si,1,fl);
+  
+  vd = GetZmin()/fScaleUnit; fwrite(&vd,sd,1,fl);
+  vd = GetZmax()/fScaleUnit; fwrite(&vd,sd,1,fl);
+  fwrite(&fNz,si,1,fl);
+    
+  // Save field values
+   
+  Int_t nTot = GetNTotal();
+  
+  for (Int_t n(0); n < nTot; n++) {    
+    
+       vd = fBr->At(n)/fFieldUnit; fwrite(&vd,sd,1,fl);
+       vd = fBz->At(n)/fFieldUnit; fwrite(&vd,sd,1,fl);   
+  }
+ 
+  fclose(fl);
+  
+  return kTRUE;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________ 
+void SpdAxialFieldMapData::PrintData() const
+{
+  cout << "<SpdAxialFieldMapData::Print> " << endl;
+  
+  cout << "\t Data map name: " << fMapName << endl; 
+  cout << "\t Path to data:  " << fPathToData << endl;
+  cout << "\t File name:     " << fFileName << endl;
+  cout << "\t Map type:      " << fMapType << endl; 
+  cout << endl;
+  cout << "\t Original Scale unit: " << fScaleUnit 
+       << " [" << GetScaleUnitAsString() << "] " << endl;
+  cout << "\t Original Field unit: " << fFieldUnit << " [" 
+       << GetFieldUnitAsString() << "] " << endl;
+  cout << endl;
+  cout << "\t [Grid]        " << endl;
+  cout << "\t N(r,z):     " << fNr << ", " << fNz 
+       << "   [TOTAL = " << GetNTotal() << "] "<< endl;
+       
+  if (fMapRegion) {     
+      cout << "\t R[min,max]:   " << fMapRegion->GetRmin() << ", " 
+           << fMapRegion->GetRmax() << " [cm]" << "  (dr = " << GetRstep() << " cm) " << endl;
+      cout << "\t Z[min,max]:   " << fMapRegion->GetZmin() << ", " 
+           << fMapRegion->GetZmax() << " [cm]" << "  (dz = " << GetZstep() << " cm) " << endl;
+  }
+  else {
+      cout << "\t MAP REGION is not defined " << endl; 
+  }
+  
+  cout << endl;
+}
diff --git a/field/SpdAxialFieldMapData.h b/field/SpdAxialFieldMapData.h
new file mode 100644
index 0000000000000000000000000000000000000000..1612a757421f923415dcd7589ca41258cc284ac9
--- /dev/null
+++ b/field/SpdAxialFieldMapData.h
@@ -0,0 +1,142 @@
+// $Id$
+// Author: artur   2020/07/04
+
+#ifndef __SPDAXIALFIELDMAPDATA_H__
+#define __SPDAXIALFIELDMAPDATA_H__
+
+#include <TString.h>
+#include <TArrayD.h>
+#include "SpdRegion.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRadialField                                                             //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+//  Base units:                                                               //
+//                                                                            //
+//       - FIELD   [kG]                                                       //
+//       - SPACING [cm]                                                       //                                                                            
+//       - ANGLES  [deg]                                                      //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdAxialFieldMapData {
+
+public:
+
+    SpdAxialFieldMapData();
+    SpdAxialFieldMapData(const Char_t* name, const Char_t* type = "");
+     
+    virtual ~SpdAxialFieldMapData();
+    
+    virtual void Clear();
+    virtual void ClearData();
+    
+    virtual Bool_t InitData(TString fileName, TString path = "");
+    virtual Bool_t InitData(const SpdAxialFieldMapData* data);
+    virtual Bool_t InitData(Double_t rmin, Double_t rmax, Int_t nr,
+                            Double_t zmin, Double_t zmax, Int_t nz);
+  
+    void SetPathToData(TString path);
+    
+    /* ----- transform field data ----- */
+  
+    virtual void MultiplyField(Double_t v);
+    virtual void MultiplyField(Double_t vr, Double_t vz);
+    
+    /* ----- getters ----- */
+
+    inline TString  GetPathToData() const { return fPathToData; }
+    inline TString  GetFileName()   const { return fFileName;   }  
+    
+    inline TString  GetMapName()    const { return fMapName; }
+    inline TString  GetMapType()    const { return fMapType; }
+ 
+    inline Double_t GetScaleUnit()  const { return fScaleUnit; }
+    inline Int_t    GetFieldUnit()  const { return fFieldUnit; }
+    
+    TString GetFieldUnitAsString()  const;
+    TString GetScaleUnitAsString()  const;
+    
+    inline Bool_t GetInitLevel() const { return fInitLevel; }
+    
+    Bool_t IsGridInit() const;
+    Bool_t IsDataInit() const;
+    
+    Bool_t IsInsideMapRegion(Double_t x, Double_t y, Double_t z) const;
+    Bool_t IsInsideMapRegion(Double_t r, Double_t z) const;
+    
+    inline  Int_t GetNr() const { return fNr; }
+    virtual Int_t GetNz() const { return fNz; }
+      
+    inline Int_t GetNTotal() const { return fNr*fNz; } 
+    
+    inline const SpdRegion* GetMapRegion() const { return fMapRegion; }
+    
+    inline  Double_t GetRmin() const { return (fMapRegion) ? fMapRegion->GetRmin() : 0; }
+    inline  Double_t GetRmax() const { return (fMapRegion) ? fMapRegion->GetRmax() : 0; }
+    
+    virtual Double_t GetZmin() const { return (fMapRegion) ? fMapRegion->GetZmin() : 0; }
+    virtual Double_t GetZmax() const { return (fMapRegion) ? fMapRegion->GetZmax() : 0; }
+    
+    Double_t GetRstep() const;
+    Double_t GetZstep() const;
+      
+    inline TArrayD* GetBr() const { return fBr; }
+    inline TArrayD* GetBz() const { return fBz; }
+    
+    inline Double_t GetBr(Int_t n) const { return (fBr && (n > -1) && (n < GetNTotal()) ) ? fBr->At(n) : 0; }
+    inline Double_t GetBz(Int_t n) const { return (fBz && (n > -1) && (n < GetNTotal()) ) ? fBz->At(n) : 0; }
+    
+    virtual Bool_t GetMinMaxStat(Double_t* B /* array of size 6: (B,Bz,Br)[min,max]*/ ) const;
+   
+    /* ----- write data to a file ----- */
+
+    virtual Bool_t WriteAsciiFile(TString fileName, TString dirName = "") const;
+    virtual Bool_t WriteBinaryFile(TString fileName, TString dirName = "") const;
+  
+    /* ----- print data ----- */
+
+    virtual void PrintData() const;
+    
+protected:
+    
+    virtual Bool_t InitData();
+  
+    virtual void   SetMapType(TString type = "");  
+    virtual Bool_t SetScaleUnit(TString unit); 
+    virtual Bool_t SetFieldUnit(TString unit); 
+  
+    TString    fMapName;       // Map name
+    
+    TString    fPathToData;    // File name
+    TString    fFileName;      // File name
+
+    TString    fMapType;       // Map type
+    
+    Double_t   fScaleUnit;     // Original grid scale factor (spatial); default = 1 (cm) 
+    Double_t   fFieldUnit;     // Original field units of the map; default = 1 (kG) 
+    
+    Int_t      fInitLevel;     // Initialization level
+    
+    SpdTubeRegion* fMapRegion; // Field region
+    
+    Int_t      fNr;            // Grid points in radial direction
+    Int_t      fNz;            // Grid points along Z-axis
+
+    /* Arrays with the field values */
+    TArrayD*   fBr;
+    TArrayD*   fBz;
+      
+    virtual Bool_t ReadAsciiFile();   // Read a field map from ASCII file  
+    virtual Bool_t ReadBinaryFile();  // Read a field map from BINARY file  
+    
+    friend class SpdField;
+
+    ClassDef(SpdAxialFieldMapData,1)
+};
+
+#endif  /* __SPDAXIALFIELDMAPDATA_H__ */
+
diff --git a/field/SpdFieldCreator.cxx b/field/SpdFieldCreator.cxx
index 52e6f9e60ec313079765ae7466322efa9cd80ea9..b460cc3efcb088e377e989274899453d290363fd 100644
--- a/field/SpdFieldCreator.cxx
+++ b/field/SpdFieldCreator.cxx
@@ -10,6 +10,7 @@
 #include "SpdConstField.h"
 #include "SpdRadialField.h"
 #include "SpdFieldMap.h"
+#include "SpdAxialFieldMap.h"
 #include "SpdMultiField.h"
 
 #include <iostream>
@@ -93,6 +94,7 @@ FairField* SpdFieldCreator::CreateSingleField(TString name, Int_t type)
   else if (type == 0) MagneticField = new SpdConstField(fFieldPar,name);
   else if (type == 1) MagneticField = new SpdRadialField(fFieldPar,name);
   else if (type == 2) MagneticField = new SpdFieldMap(fFieldPar,name);
+  else if (type == 3) MagneticField = new SpdAxialFieldMap(fFieldPar,name);
   else { 
     
       MagneticField = new SpdField();
diff --git a/field/SpdFieldMap.cxx b/field/SpdFieldMap.cxx
index ad1db5622f5a52b44f85e3bb277880f95af2a63f..79906ac8b2f2403e24015ad21ddb68feea7cc183 100644
--- a/field/SpdFieldMap.cxx
+++ b/field/SpdFieldMap.cxx
@@ -5,6 +5,7 @@
 
 #include "SpdFieldMap.h"
 #include "SpdFieldPar.h"
+#include <TSystem.h>
 #include <TMath.h>
 
 #include <iostream>
@@ -44,7 +45,7 @@ fApproxMethod(0)
 {
    fType = 2;
    SetTitle("Map");
-
+   
    if (!fieldPar) {
        cout << "-E- <SpdField::SpdFieldMap> Empty parameter container " << endl;
        SetNFieldParameters(6);
@@ -54,13 +55,7 @@ fApproxMethod(0)
    GetFieldParameters(fieldPar);
    GetRegionParameters(fieldPar); 
 
-   TString workdir = getenv("VMCWORKDIR");
-   if (workdir.IsNull()) 
-      workdir = "../";
-   workdir += "/input/";
-   workdir.ReplaceAll("//","/");
-
-   SpdFieldMapData::InitData(fFileName, workdir);
+   InitData(fFileName);
    
    if (Abs(fParams[0]-1.) > 1e-9 || 
        Abs(fParams[1]-1.) > 1e-9 || 
@@ -86,14 +81,51 @@ void SpdFieldMap::Clear()
 //_____________________________________________________________________________
 Bool_t SpdFieldMap::InitData(TString fileName, TString path)
 {
-   TString pathToData = path;
-   if(pathToData.IsNull()) {
-      pathToData = getenv("VMCWORKDIR");
-      if (pathToData.IsNull())
-        pathToData = "../";
-      pathToData += "/input/";
-      pathToData.ReplaceAll("//","/");
-   } 
+   TString pathToData;
+   Bool_t found = false;
+   
+   while (true) 
+   {
+      // if absolute path to magnetic field map
+      if (path.BeginsWith("/") ) {
+         if (!gSystem->AccessPathName(path.Data())) { 
+             pathToData = path;
+             found = true; 
+             cout << "-I- <SpdFieldMap::InitData> Path to the field map: " << pathToData << endl;
+             break; 
+         }
+      }
+      
+      // if MAGFPATH (path to magnetic field map) is set
+      path = getenv("MAGFPATH");
+      path.ReplaceAll("//","/");
+      if (!path.IsNull() ) {
+          if (!gSystem->AccessPathName(path.Data())) { 
+              pathToData = path;
+              found = true; 
+              cout << "-I- <SpdFieldMap::InitData> Path to the field map ($MAGFPATH): " << pathToData << endl;
+              break; 
+          }
+      }
+      
+      // if file was not found look it in the standard path
+      path = TString(getenv("VMCWORKDIR"));
+      path.ReplaceAll("//","/");
+      if (!path.IsNull() ) {
+          (path.EndsWith("/")) ? path += "input/" : path += "/input/";
+          if (!gSystem->AccessPathName(path.Data())) { 
+              pathToData = path;
+              cout << "-I- <SpdFieldMap::InitData> Path to the field map ($VMCWORKDIR/input): " << pathToData << endl;
+              found = true; 
+              break; 
+          }
+      }
+      
+      break;
+   }
+   
+   if (!found) cout << "-I- <SpdFieldMap::InitData> Search for the field map in a current directory: " << endl;
+   
    return SpdFieldMapData::InitData(fileName,pathToData);
 }
 
diff --git a/field/SpdFieldMapData.cxx b/field/SpdFieldMapData.cxx
index 53922e11773df42de00d738b3d0be0c7a9dcdd62..9f409019123c964c4cd9eb5c5fc75ab46c88bebf 100644
--- a/field/SpdFieldMapData.cxx
+++ b/field/SpdFieldMapData.cxx
@@ -164,7 +164,7 @@ Bool_t SpdFieldMapData::SetScaleUnit(TString unit) // protected
    else if (unit == "m")  fScaleUnit = 100.0;
    else if (unit == "cm") fScaleUnit = 1.0;
    else {
-       cout << "-E- <SpdFieldMap::SetScaleUnit> Unknown unit: " << unit << endl;
+       cout << "-E- <SpdFieldMapData::SetScaleUnit> Unknown unit: " << unit << endl;
        fScaleUnit = 1;
        return kFALSE;
    }
@@ -178,7 +178,7 @@ Bool_t SpdFieldMapData::SetFieldUnit(TString unit) // protected
    else if (unit == "T")  fFieldUnit = 10.0;
    else if (unit == "kG") fFieldUnit = 1.0;
    else {
-       cout << "-E- <SpdFieldMap::SetFieldUnit> Unknown unit: " << unit << endl;
+       cout << "-E- <SpdFieldMapData::SetFieldUnit> Unknown unit: " << unit << endl;
        fFieldUnit = 1;
        return kFALSE;
    }
@@ -192,7 +192,7 @@ TString SpdFieldMapData::GetScaleUnitAsString() const
    if (fScaleUnit == 100.0) return "m";
    if (fScaleUnit == 1.0)   return "cm";
   
-   cout << "-E- <SpdFieldMap::GetScaleUnitString> Unknown unit: " << fScaleUnit << endl;
+   cout << "-E- <SpdFieldMapData::GetScaleUnitString> Unknown unit: " << fScaleUnit << endl;
    return "unknown";
 }
 
@@ -203,7 +203,7 @@ TString SpdFieldMapData::GetFieldUnitAsString() const
    if (fFieldUnit == 10.0)  return "T";
    if (fFieldUnit == 1.0)   return "kG";
   
-   cout << "-E- <SpdFieldMap::GetFieldUnitString> Unknown unit: " << fFieldUnit << endl;
+   cout << "-E- <SpdFieldMapData::GetFieldUnitString> Unknown unit: " << fFieldUnit << endl;
    return "unknown";
 }
 
@@ -226,19 +226,18 @@ Bool_t SpdFieldMapData::InitData(TString fileName, TString path)
        
    if (fileName.EndsWith(".dat")) {
        if (!ReadAsciiFile()) {
-           cout << "-F- <SpdFieldMap::Init> Bad data (*.dat) file " << endl;
+           cout << "-F- <SpdFieldMapData::Init> Bad data (*.dat) file " << endl;
            exit(1);
        }
    }
    else if (fileName.EndsWith(".bin")) { 
        if (!ReadBinaryFile()) {
-           cout << "-F- <SpdFieldMap::Init> Bad data (*.bin) file " << endl;
+           cout << "-F- <SpdFieldMapData::Init> Bad data (*.bin) file " << endl;
            exit(1);
        }
    }
-   
    else {
-       cout << "-E- <SpdFieldMap::Init> No proper file name defined: "
+       cout << "-E- <SpdFieldMapData::Init> No proper file name defined: "
             << fileName << endl;         
        Clear();
        return kFALSE;
@@ -461,7 +460,7 @@ Bool_t SpdFieldMapData::ReadAsciiFile()  // protected
   std::ifstream mapFile(fileName);
 
   if (!mapFile.is_open()) {
-      cout << "-E- <SpdFieldMap:ReadAsciiFile> Could not open file: " << fileName << endl;
+      cout << "-E- <SpdFieldMapData:ReadAsciiFile> Could not open file: " << fileName << endl;
       return kFALSE;
   }
   
@@ -493,7 +492,7 @@ Bool_t SpdFieldMapData::ReadAsciiFile()  // protected
                            zmin*fScaleUnit, zmax*fScaleUnit);  
   
   if (!IsGridInit()) {
-      cout << "-E- <SpdFieldMap:ReadAsciiFile> Bad grid parameters: ";
+      cout << "-E- <SpdFieldMapData:ReadAsciiFile> Bad grid parameters: ";
       cout << "N(x,y,z) = " << fNx << ", " << fNy << ", " << fNz << endl;
       cout << "[min,max] = X[" << xmin << ", " << xmax << "], " 
            << "  Y[" << ymin << ", " << ymax << "]," 
@@ -617,7 +616,7 @@ Bool_t SpdFieldMapData::ReadBinaryFile()
                            zmin*fScaleUnit, zmax*fScaleUnit);  
   
   if (!IsGridInit()) {
-      cout << "-E- <SpdFieldMap:ReadAsciiFile> Bad grid parameters: ";
+      cout << "-E- <SpdFieldMapData:ReadBinaryFile> Bad grid parameters: ";
       cout << "N(x,y,z) = " << fNx << ", " << fNy << ", " << fNz << endl;
       cout << "[min,max] = X[" << xmin << ", " << xmax << "], " 
            << "  Y[" << ymin << ", " << ymax << "]," 
diff --git a/field/SpdFieldMapData.h b/field/SpdFieldMapData.h
index e6ec447f8f6d5e456bbaf943b9b266fdd1a84fbf..85008648c3cdd1587a3993852dc23f9a4fa93c5f 100644
--- a/field/SpdFieldMapData.h
+++ b/field/SpdFieldMapData.h
@@ -38,7 +38,7 @@ public:
   virtual void Clear();
   virtual void ClearData();
   
-  virtual Bool_t InitData(TString fileName, TString path = "../input");
+  virtual Bool_t InitData(TString fileName, TString path = "");
   virtual Bool_t InitData(const SpdFieldMapData* data);
   virtual Bool_t InitData(Double_t xmin, Double_t xmax, Int_t nx,
                           Double_t ymin, Double_t ymax, Int_t ny,
@@ -82,7 +82,7 @@ public:
     
   inline Int_t GetNTotal() const { return fNx*fNy*fNz; } 
   
-  inline const SpdRegion* GetMapRegion() const { return fMapRegion; }
+  inline const SpdBoxRegion* GetMapRegion() const { return fMapRegion; }
   
   inline Double_t GetXmin() const { return (fMapRegion) ? fMapRegion->GetXmin() : 0; }
   inline Double_t GetXmax() const { return (fMapRegion) ? fMapRegion->GetXmax() : 0; }
@@ -134,7 +134,7 @@ protected:
   
   Int_t      fInitLevel;     // Initialization level
   
-  SpdRegion* fMapRegion;     // Field region
+  SpdBoxRegion* fMapRegion;  // Field region
   
   Int_t      fNx;            // Grid points along X-axis
   Int_t      fNy;            // Grid points along Y-axis
diff --git a/gconfig/DecayConfig.C b/gconfig/DecayConfig.C
index 47e8c9de397a54b3239b069001244f03b83a04e4..21f02782575acaf2262bb40ae924e4613232e2b2 100644
--- a/gconfig/DecayConfig.C
+++ b/gconfig/DecayConfig.C
@@ -6,12 +6,16 @@
  *                  copied verbatim in the file "LICENSE"                       *
  ********************************************************************************/
 
-void Config(TPythia6Decayer* decayer);
+void Config1(SpdPythia6Decayer* decayer);
 
+void Config2(TPythia6Decayer* decayer);
+void Config3(TPythia6Decayer* decayer);
+
+//________________________________________________________________________________________
 void DecayConfig() 
 {
     cout << "-I- <DecayConfig> " << endl;
-    
+
     // This script uses the external decayer in place of the
     // concrete Monte Carlo native decay mechanisms only for the
     // specific types of decays defined below.
@@ -19,67 +23,123 @@ void DecayConfig()
     // Access the external decayer singleton and initialize it  
     
     //TPythia6Decayer* decayer = TPythia6Decayer::Instance();
-    //Config(decayer);
-     
+    //Config3(decayer);
+    
     //SpdPythia6Decayer* decayer = new SpdPythia6Decayer();
-    //Config(decayer);
-   
+    //Config3(decayer);
+
     SpdDecayer* spd_decayer = SpdDecayer::Instance();
     
     if (!spd_decayer->GetDecayer()) spd_decayer->SetDecayer("SpdPythia6Decayer",1);
    
     SpdPythia6Decayer* decayer = dynamic_cast<SpdPythia6Decayer*>(spd_decayer->GetDecayer());
-    if (decayer) {
-      
-        //decayer->SetSeed(123456789);
-      
-        TPythia6& pythia6 = *(decayer->GetPythia());
-        // .... make Pythia6 settings here if necessary ...
-        
+
+//    if (decayer) {
+//      
+//        //decayer->SetSeed(123456789);
+//      
+//        TPythia6& pythia6 = *(decayer->GetPythia());
+//        
+//      // .... make Pythia6 settings here if necessary ...
+//        
 //  activate decays       
 //
 //         pythia6.SetMDCY(pythia6.Pycomp(211),1,1);   // pi+
 //         pythia6.SetMDCY(pythia6.Pycomp(-211),1,1);  // pi-
 //        
-//  force decays for particles of a such type   
+//  force user decayer for particles of a such type   
 //
 //         gMC->SetUserDecay(211);  // pi+
 //         gMC->SetUserDecay(-211); // pi-
-        
-    }
+//        
+//    }
+    
+//    Config1(decayer); // FIXME
     
+    //exit(1);
+        
     if (!spd_decayer->IsInit()) spd_decayer->Init(); 
 }
 
 //________________________________________________________________________________________
-void Config(TPythia6Decayer* decayer) 
+void Config1(SpdPythia6Decayer* decayer) 
 {    
-   // The following just tells pythia6 to not decay particles only to certain channels.
+    decayer->Init();
+
+    gMC->SetExternalDecayer(decayer);
     
-   decayer->SetForceDecay(TPythia6Decayer::kAll);
+    // ===== Print all decay channels ====== 
     
-//     /* EXAMPLE:  Force the J/PSI decay channel e+e- */
-//
-//     Int_t products[2], mult[2];    
-//     Int_t npart = 2;
+    decayer->PrintParticleDecayChannels(421);   // D0
+    decayer->PrintParticleDecayChannels(411);   // D+
+    decayer->PrintParticleDecayChannels(-313);  // K*0_bar
+    
+    //decayer->PrintParticleDecayChannels(-421); // D0_bar (the same as D0)
+    //decayer->PrintParticleDecayChannels(-411); // D- (the same as D+)
+    //decayer->PrintParticleDecayChannels(313);  // K*0 (the same as K*_0_bar)
+
+    // ===== Select decay channels ====== 
+    
+    // -> Fix primary vertices:
+   
+    // D0 (D0_bar) -> K-, pi+
+    decayer->SelectForcedDecay(421,17); // pdg number, channel
+    //decayer->SelectForcedDecay(-421,17); 
+    
+    // D+ (D-) -> K*0_bar, pi+ 
+    decayer->SelectForcedDecay(411,24);  // pdg number, channel
+    //decayer->SelectForcedDecay(-411,24);
+    
+    // D+ (D-) -> K-, pi+, pi+ 
+    decayer->SelectForcedDecay(411,47);  // pdg number, channel
+    //decayer->SelectForcedDecay(-421,47);
+    
+    // -> Fix secondary vertices (if necessary!):
+    
+    // K*0_bar (K*0) -> K+, pi- 
+    decayer->SelectForcedDecay(-313,1);  // pdg number, channel
+    
+      // just tells concrete monte carlo generator (for example, Geant4)
+      // to use external decayer for these type of particles
+      gMC->SetUserDecay(-313); // K*0_bar
+      gMC->SetUserDecay(313);  // K*0
+    
+    // ====== Force selected decay channels ====== 
+    
+    decayer->ForceSelectedDecays();
+}
+
+//________________________________________________________________________________________
+void Config2(TPythia6Decayer* decayer) 
+{    
+   /* EXAMPLE:  Force the J/PSI decay channel e+e- */
+
+//    Int_t products[2], mult[2];    
+//    Int_t npart = 2;
 // 
-//     /* decay products */ 
-//     products[0] =  11;
-//     products[1] = -11;
-//     
-//     /* multiplicity */
-//     mult[0] = 1;
-//     mult[1] = 1;
-//           
-//     /* force the decay channel */
-//     decayer->ForceParticleDecay(443,products,mult,npart);
+//    /* decay products */ 
+//    products[0] =  11;
+//    products[1] = -11;
+//    
+//    /* minimal multiplicity in final state */
+//    mult[0] = 1;
+//    mult[1] = 1;
+//          
+//    /* force J/PSI decay channel */
+//    decayer->ForceParticleDecay(443,products,mult,npart); 
 
    decayer->Init();
 
    gMC->SetExternalDecayer(decayer);
-   
-   //return;
+}
+
+//________________________________________________________________________________________
+void Config3(TPythia6Decayer* decayer) 
+{    
+   // The following just tells pythia6 to not decay particles only to certain channels.
     
+   decayer->SetForceDecay(TPythia6Decayer::kAll);
+
    //--------------------------------------------------------------------
    // Tell the concrete monte carlo to use the external decayer.  
    // The external decayer will be used for:
diff --git a/gconfig/DecayConfigSpecV0.C b/gconfig/DecayConfigSpecV0.C
new file mode 100644
index 0000000000000000000000000000000000000000..7f2e04e41500d8c6084307b27d8d1981c601ad9f
--- /dev/null
+++ b/gconfig/DecayConfigSpecV0.C
@@ -0,0 +1,80 @@
+/********************************************************************************
+ *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
+ *                                                                              *
+ *              This software is distributed under the terms of the             *
+ *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *
+ *                  copied verbatim in the file "LICENSE"                       *
+ ********************************************************************************/
+
+void Config(SpdPythia6Decayer* decayer);
+
+//________________________________________________________________________________________
+void DecayConfig() 
+{
+    cout << "-I- <DecayConfigSpecV0:DecayConfig> " << endl;
+
+    // This script uses the external decayer in place of the
+    // concrete Monte Carlo native decay mechanisms only for the
+    // specific types of decays defined below.
+
+    SpdDecayer* spd_decayer = SpdDecayer::Instance();
+    
+    if (!spd_decayer->GetDecayer()) spd_decayer->SetDecayer("SpdPythia6Decayer",1);
+   
+    SpdPythia6Decayer* decayer = dynamic_cast<SpdPythia6Decayer*>(spd_decayer->GetDecayer());
+    
+    Config(decayer); // FIXME
+        
+    if (!spd_decayer->IsInit()) spd_decayer->Init(); 
+}
+
+//________________________________________________________________________________________
+void Config(SpdPythia6Decayer* decayer) 
+{    
+    decayer->Init();
+
+    gMC->SetExternalDecayer(decayer);
+    
+    // ===== Print all decay channels ====== 
+    
+    //decayer->PrintParticleDecayChannels(421);   // D0
+    //decayer->PrintParticleDecayChannels(411);   // D+
+    //decayer->PrintParticleDecayChannels(-313);  // K*0_bar
+    
+    //decayer->PrintParticleDecayChannels(-421); // D0_bar (the same as D0)
+    //decayer->PrintParticleDecayChannels(-411); // D- (the same as D+)
+    //decayer->PrintParticleDecayChannels(313);  // K*0 (the same as K*_0_bar)
+
+    // ===== Select decay channels ====== 
+    
+    // -> Fix primary vertices:
+   
+    // D0 (D0_bar) -> K-, pi+
+    decayer->SelectForcedDecay(421,17); // pdg number, channel
+    //decayer->SelectForcedDecay(-421,17); 
+
+/*    
+    // D+ (D-) -> K*0_bar, pi+ 
+    decayer->SelectForcedDecay(411,24);  // pdg number, channel
+    //decayer->SelectForcedDecay(-411,24);
+    
+    // D+ (D-) -> K-, pi+, pi+ 
+    decayer->SelectForcedDecay(411,47);  // pdg number, channel
+    //decayer->SelectForcedDecay(-421,47);
+    
+    // -> Fix secondary vertices (if necessary!):
+    
+    // K*0_bar (K*0) -> K+, pi- 
+    decayer->SelectForcedDecay(-313,1);  // pdg number, channel
+    
+      // just tells concrete monte carlo generator (for example, Geant4)
+      // to use external decayer for these type of particles
+      gMC->SetUserDecay(-313); // K*0_bar
+      gMC->SetUserDecay(313);  // K*0
+*/
+
+    // ====== Force selected decay channels ====== 
+    
+    decayer->ForceSelectedDecays();
+}
+
diff --git a/gconfig/g4Config.C b/gconfig/g4Config.C
index 9a3f837c91f6de7ec7e2da835960daecdc51870c..f0264778896f5a8c24afe71ee1d634cd9e7781e1 100644
--- a/gconfig/g4Config.C
+++ b/gconfig/g4Config.C
@@ -53,7 +53,9 @@ void Config()
    TG4RunConfiguration* runConfiguration =
      new TG4RunConfiguration("geomRoot", 
                              "QGSP_FTFP_BERT", 
-                             "stepLimiter+specialCuts+specialControls+stackPopper");
+                             "stepLimiter+specialCuts+specialControls+stackPopper",
+                              false
+                            );
    
 //    TG4RunConfiguration* runConfiguration =
 //      new TG4RunConfiguration("geomRoot", 
@@ -65,11 +67,13 @@ void Config()
    
    cout << "Geant4 has been created." << endl;
 
+   //geant4->ProcessGeantCommand("/mcTracking/skipNeutrino true"); 
+
    /* Create the Specific stack */
    
    SpdStack* stack = new SpdStack(1000);
    
-   stack->StoreSecondaries(kTRUE);
+   stack->StoreSecondaries(true);
    stack->SetMinPoints(0);
    
    geant4->SetStack(stack);
diff --git a/gconfig/g4config.in b/gconfig/g4config.in
index 97aac92fbae1aab2503e40a57c1ebb9b4e01b217..e1abff6ac25b751f09add7278e7a4fda8081d46f 100644
--- a/gconfig/g4config.in
+++ b/gconfig/g4config.in
@@ -19,10 +19,10 @@
 
 /run/particle/applyCuts
 
-#/mcPhysics/rangeCutForGamma    0.1 mm    
-#/mcPhysics/rangeCutForElectron 0.1 mm
-#/mcPhysics/rangeCutForPositron 0.1 mm
-#/mcPhysics/rangeCuts 0.1 mm
+/mcPhysics/rangeCutForGamma    0.1 mm    
+/mcPhysics/rangeCutForElectron 0.1 mm
+/mcPhysics/rangeCutForPositron 0.1 mm
+/mcPhysics/rangeCuts 0.1 mm
 
 #/mcRegions/print 1
 
diff --git a/geometry/cave_precise.geo b/geometry/cave_precise.geo
index 9f4b66660790f6bbeed6e293e285285920fe6943..2e0822aef1d6ffd7c8651c3f4aadfe3a8f542f79 100644
--- a/geometry/cave_precise.geo
+++ b/geometry/cave_precise.geo
@@ -9,4 +9,4 @@ vacuum2
  10000  -10000   10000
  10000   10000   10000
 -10000   10000   10000
--10000  -10000   10000
\ No newline at end of file
+-10000  -10000   10000
diff --git a/geometry/media.geo b/geometry/media.geo
index 40073a7f88bbf2ddb77c02d14be1bf24ed76bc5c..969a9f3be1ee1d2fddc6493006eff8d66687c3be 100644
--- a/geometry/media.geo
+++ b/geometry/media.geo
@@ -1,19 +1,16 @@
-//----------------------------------------------------------
+//----------------------------------------------------------                   
 air                3  14.01  16.  39.95  7.  8.  18.  1.205e-3  .755  .231  .014
                    0  1  30.  .001
-                   0
+                   0            
 
 // 1.205e-3 g/cmВі eq 1e3 mbar (see air)
 // 1e-8 mbar eq 1.205e-6 * 1e-8 g/cmВі
-
-vacuumX            1  1.008   1.0  1.e-30
-                   0  1  30.  .001
-                   0        
+                   
 vacuum0            3  14.01  16.  39.95  7.  8.  18.  1.e-16     .755  .231  .014
                    0  1  30.  .001
                    0
 vacuum             3  14.01  16.  39.95  7.  8.  18.  1.205e-14  .755  .231  .014
-                   0  1  30.  .001
+                   0  1  30.  .01
                    0
 vacuum7            3  14.01  16.  39.95  7.  8.  18.  1.205e-13  .755  .231  .014
                    0  1  30.  .001
@@ -2187,11 +2184,29 @@ ArCO2               3  39.948 12.01 15.9994 18. 6. 8. 0.00346 0.9 0.0333 0.0667
 // Argon CO2 (70/30)                                                                                                                        
 arco27030          -3  39.948 12.01 15.9994 18. 6. 8. 0.0019 700 100 200                                                                    
                     1 1   20. 0.001                                                                                                          
-                   0                                                                                                                        
+                   0
+                   
+// Argon CO2 (70/30), density x 1.5                                                                                                                       
+arco27030x1p5      -3  39.948 12.01 15.9994 18. 6. 8. 0.00285 700 100 200                                                                    
+                    1 1   20. 0.001                                                                                                          
+                    0             
+// Argon CO2 (70/30), density x 2.0                                                                                                                       
+arco27030x2p0      -3  39.948 12.01 15.9994 18. 6. 8. 0.0038 700 100 200                                                                    
+                    1 1   20. 0.001                                                                                                          
+                    0         
+                    
 // Argon CO2 (80/20)                                                                                                                        
 arco28020          -3  39.948 12.01 15.9994 18. 6. 8. 0.0019 800 66.66 133.33                                                               
                    1 1   20. 0.001                     
                    0
+// Argon CO2 (80/20), density x 1.5                                                                                                                       
+arco28020x1p5      -3  39.948 12.01 15.9994 18. 6. 8. 0.00285 800 66.66 133.33                                                                 
+                    1 1   20. 0.001                                                                                                          
+                    0             
+// Argon CO2 (80/20), density x 2.0                                                                                                                       
+arco28020x2p0      -3  39.948 12.01 15.9994 18. 6. 8. 0.0038 800 66.66 133.33                                                                   
+                    1 1   20. 0.001                                                                                                          
+                    0                           
 //rohacell	    1 		  
 
 rohacell	   -3 1.0079 12.011 15.999 1. 6. 8. 0.052 8. 5. 2. 
@@ -2271,8 +2286,29 @@ MCoilSubAl        -9  92.9  47.867  63.54   26.98    54.938  28.09  51.996  58.6
                    41    22      29       13       25      14     24      28      26   4.3
                    0.038  0.038  0.064   0.688    0.003  0.002   0.033  0.017    0.117
                    0  1  30.  .001
-                   0                      
-
+                   0  
+                   
+// "air" and "vacuum" for a different drawing prperties (for example, transparency) 
+//-------------------------------------------------------------------------------------
+airX               3  14.01  16.  39.95  7.  8.  18.  1.205e-3  .755  .231  .014
+                   0  1  30.  .001
+                   0   
+airX1              3  14.01  16.  39.95  7.  8.  18.  1.205e-3  .755  .231  .014
+                   0  1  30.  .001
+                   0 
+airX2              3  14.01  16.  39.95  7.  8.  18.  1.205e-3  .755  .231  .014
+                   0  1  30.  .001
+                   0                    
+vacuumX            3  14.01  16.  39.95  7.  8.  18.  1.205e-14  .755  .231  .014
+                   0  1  30.  .001
+                   0
+vacuumX1           3  14.01  16.  39.95  7.  8.  18.  1.205e-14  .755  .231  .014
+                   0  1  30.  .001
+                   0
+vacuumX2           3  14.01  16.  39.95  7.  8.  18.  1.205e-14  .755  .231  .014
+                   0  1  30.  .001
+                   0                  
+ 
 // ----- Caution with putting materials below that line -----
 // The next materials must specify additional parameters!
 
diff --git a/input/map_qsolRZ_6cls2cm.bin b/input/map_qsolRZ_6cls2cm.bin
new file mode 100644
index 0000000000000000000000000000000000000000..fa1cea94502fbbb45f2fbf5bac6ff3a4e795dcb4
Binary files /dev/null and b/input/map_qsolRZ_6cls2cm.bin differ
diff --git a/input/urqmd_pdg.dat b/input/urqmd_pdg.dat
new file mode 100644
index 0000000000000000000000000000000000000000..8241a430601c01230fb8f7e8cc9327df5c4a1bbe
--- /dev/null
+++ b/input/urqmd_pdg.dat
@@ -0,0 +1,316 @@
+   1017   1114
+   1018   31114
+   1019   1112
+   1020   11114
+   1021   11112
+   1022   1116
+   1023   21112
+   1024   21114
+   1025   11116
+   1026   1118
+   1040   3112
+   1041   3114
+   1042   13112
+   1043   13114
+   1044   23112
+   1045   3116
+   1046   13116
+   1047   23114
+   1048   3118
+   1049   3312
+   1050   3314
+   1051   23314
+   1052   13314
+   1053   33314
+   1054   13316
+   1055   3334
+   1101   -211
+   1104   -213
+   1111   -9000211
+   1114   -20213
+   1118   -215
+   1122   -10213
+   1126   -100213
+   1130   -30213
+   2001   2112
+   2002   12112
+   2003   1214
+   2004   22112
+   2005   32112
+   2006   2116
+   2007   12116
+   2008   21214
+   2009   42112
+   2010   31214
+   2011   41214
+   2012   12118
+   2013   52114
+   2016   100012110
+   2017   2114
+   2018   32114
+   2019   1212
+   2020   12114
+   2021   11212
+   2022   1216
+   2023   21212
+   2024   22114
+   2025   11216
+   2026   2118
+   2027   3122
+   2028   13122
+   2029   3124
+   2030   23122
+   2031   33122
+   2032   13124
+   2033   43122
+   2034   53122
+   2035   3126
+   2036   13126
+   2037   23124
+   2038   3128
+   2039   23126
+   2040   3212
+   2041   3214
+   2042   13212
+   2043   13214
+   2044   23212
+   2045   3216
+   2046   13216
+   2047   23214
+   2048   3218
+   2049   3322
+   2050   3324
+   2051   23324
+   2052   13324
+   2053   33324
+   2054   13326
+   2100   22
+   2101   111
+   2102   221
+   2103   223
+   2104   113
+   2105   9000221
+   2106   311
+   2107   331
+   2108   313
+   2109   333
+   2110   333
+   2111   9000111
+   2112   10221
+   2113   20313
+   2114   20113
+   2115   20223
+   2116   20333
+   2117   315
+   2118   115
+   2119   225
+   2120   335
+   2121   10313
+   2122   10113
+   2123   10223
+   2124   10333
+   2125   100313
+   2126   100113
+   2127   100223
+   2128   100333
+   2129   30313
+   2130   30113
+   2131   30223
+   2132   337
+   3001   2212
+   3002   12212
+   3003   2124
+   3004   22212
+   3005   32212
+   3006   2216
+   3007   12216
+   3008   22124
+   3009   42212
+   3010   32124
+   3011   42124
+   3012   12218
+   3013   52214
+   3016   100012210
+   3017   2214
+   3018   32214
+   3019   2122
+   3020   12214
+   3021   12122
+   3022   2126
+   3023   22122
+   3024   22214
+   3025   12126
+   3026   2218
+   3040   3222
+   3041   3224
+   3042   13222
+   3043   13224
+   3044   23222
+   3045   3226
+   3046   13226
+   3047   23224
+   3048   3228
+   3101   211
+   3104   213
+   3106   321
+   3108   323
+   3110   10321
+   3111   9000211
+   3113   20323
+   3114   20213
+   3117   325
+   3118   215
+   3121   10323
+   3122   10213
+   3125   100323
+   3126   100213
+   3129   30323
+   3130   30213
+   4017   2224
+   4018   32224
+   4019   2222
+   4020   12224
+   4021   12222
+   4022   2226
+   4023   22222
+   4024   22224
+   4025   12226
+   4026   2228
+   -3055   -3334
+   -3054   -13316
+   -3053   -33314
+   -3052   -13314
+   -3051   -23314
+   -3050   -3314
+   -3049   -3312
+   -3048   -3118
+   -3047   -23114
+   -3046   -13116
+   -3045   -3116
+   -3044   -23112
+   -3043   -13114
+   -3042   -13112
+   -3041   -3114
+   -3040   -3112
+   -3026   -1118
+   -3025   -11116
+   -3024   -21114
+   -3023   -21112
+   -3022   -1116
+   -3021   -11112
+   -3020   -11114
+   -3019   -1112
+   -3018   -31114
+   -3017   -1114
+   -2129   -30313
+   -2125   -100313
+   -2121   -10313
+   -2117   -315
+   -2113   -20313
+   -2110   -10311
+   -2108   -313
+   -2106   -311
+   -2055   -3334
+   -2054   -13326
+   -2053   -33324
+   -2052   -13324
+   -2051   -23324
+   -2050   -3324
+   -2049   -3322
+   -2048   -3218
+   -2047   -23214
+   -2046   -13216
+   -2045   -3216
+   -2044   -23212
+   -2043   -13214
+   -2042   -13212
+   -2041   -3214
+   -2040   -3212
+   -2039   -23126
+   -2038   -3128
+   -2037   -23124
+   -2036   -13126
+   -2035   -3126
+   -2034   -53122
+   -2033   -43122
+   -2032   -13124
+   -2031   -33122
+   -2030   -23122
+   -2029   -3124
+   -2028   -13122
+   -2027   -3122
+   -2026   -2118
+   -2025   -11216
+   -2024   -22114
+   -2023   -21212
+   -2022   -1216
+   -2021   -11212
+   -2020   -12114
+   -2019   -1212
+   -2018   -32114
+   -2017   -2114
+   -2016   -100012110
+   -2013   -52114
+   -2012   -12118
+   -2011   -41214
+   -2010   -31214
+   -2009   -42112
+   -2008   -21214
+   -2007   -12116
+   -2006   -2116
+   -2005   -32112
+   -2004   -22112
+   -2003   -1214
+   -2002   -12112
+   -2001   -2112
+   -1129   -30323
+   -1125   -100323
+   -1121   -10323
+   -1117   -325
+   -1113   -20323
+   -1110   -10321
+   -1108   -323
+   -1106   -321
+   -1048   -3228
+   -1047   -23224
+   -1046   -13226
+   -1045   -3226
+   -1044   -23222
+   -1043   -13224
+   -1042   -13222
+   -1041   -3224
+   -1040   -3222
+   -1026   -2218
+   -1025   -12126
+   -1024   -22214
+   -1023   -22122
+   -1022   -2126
+   -1021   -12122
+   -1020   -12214
+   -1019   -2122
+   -1018   -32214
+   -1017   -2214
+   -1016   -100012210
+   -1013   -52214
+   -1012   -12218
+   -1011   -42124
+   -1010   -32124
+   -1009   -42212
+   -1008   -22124
+   -1007   -12216
+   -1006   -2216
+   -1005   -32212
+   -1004   -22212
+   -1003   -2124
+   -1002   -12212
+   -1001   -2212
+   -26   -2228
+   -25   -12226
+   -24   -22224
+   -23   -22222
+   -22   -2226
+   -21   -12222
+   -20   -12224
+   -19   -2222
+   -18   -32224
+   -17   -2224
diff --git a/its/CMakeLists.txt b/its/CMakeLists.txt
index 74f9f6a328779fc16785f278611ca9f6b2125d86..aca12b25a8c28f0e8123b8b200df9dab18a15089 100644
--- a/its/CMakeLists.txt
+++ b/its/CMakeLists.txt
@@ -40,6 +40,14 @@ SpdItsPoint.cxx
 
 )
 
+set(HEADERS
+SpdItsContFact.h
+SpdIts.h
+SpdItsParSet.h
+SpdItsPoint.h
+)
+
+
 Set(LINKDEF SpdItsLinkDef.h)
 Set(LIBRARY_NAME SpdIts)
 Set(DEPENDENCIES Base SpdData SpdCommon SpdGeometry SpdField)
diff --git a/its/SpdIts.cxx b/its/SpdIts.cxx
index 703c4b8dfad56793fb820046f02696fffc3948bb..0d0ba4bf6d3c593ee9ec8426610a021dd7a15d32 100644
--- a/its/SpdIts.cxx
+++ b/its/SpdIts.cxx
@@ -109,7 +109,7 @@ void SpdIts::Initialize()
 //_____________________________________________________________________________________
 void SpdIts::Reset()
 {
-  fPointCollection->Clear();
+  if (fPointCollection) fPointCollection->Clear();
 }
 
 //_____________________________________________________________________________________
@@ -124,9 +124,8 @@ void SpdIts::Register()
 //_____________________________________________________________________________________
 Bool_t SpdIts::ProcessHits(FairVolume* vol)
 {
-  
   //cout << "<SpdIts::ProcessHits> " << endl;
- 
+    
   // Set parameters at entrance of volume
   
   if (gMC->IsTrackEntering()) {
diff --git a/its/SpdItsPoint.cxx b/its/SpdItsPoint.cxx
index c6a490aaab3043d1d52b42ce6dd9bcfb8c42141f..b13a8f862367b62bae8c5282b6088d57dbb80e17 100644
--- a/its/SpdItsPoint.cxx
+++ b/its/SpdItsPoint.cxx
@@ -49,6 +49,32 @@ void SpdItsPoint::GetPosTime(TVector3& pos, Double_t& t) const
     t = fTime;
 }
 
+//_____________________________________________________________________________
+Double_t SpdItsPoint::GetSegLength() const
+{
+    Double_t s2 = (fXOut-fX)*(fXOut-fX) + (fYOut-fY)*(fYOut-fY) + (fZOut-fZ)*(fZOut-fZ);
+    return TMath::Sqrt(s2);
+}
+
+//_____________________________________________________________________________
+Bool_t SpdItsPoint::IsSpecialPoint(Int_t& vid, Double_t& dep) const
+{
+    vid = -1; 
+    dep = 0.;
+    
+    if (fVid.size() != 2) return kFALSE;
+ 
+    vid = fVid[0];
+    if (vid < 0) {
+        if (fVid[1] < 0) return kFALSE;
+        vid = fVid[1];
+    }
+    
+    dep = fVed[0] + fVed[1];
+    
+    return kTRUE;
+}
+
 //_____________________________________________________________________________________
 void SpdItsPoint::Print(const Option_t* opt) const
 {
@@ -59,7 +85,8 @@ void SpdItsPoint::Print(const Option_t* opt) const
   cout << " Node(ID):                " << fNodeId << endl;
   cout << " Position, (in):          " << fX << ", " << fY << ", " << fZ << " [cm] " << endl;
   cout << " Position, (out):         " << fXOut << ", " << fYOut << ", " << fZOut << " [cm] " << endl;              
-  cout << " Time, Length:            " << fTime << " [ns] " << fLength << " [s] " << endl;                    
+  cout << " Time, Length:            " << fTime << " [ns] " << fLength << " [s] " << endl;     
+  cout << " Segment length:          " << GetSegLength()*10 << " [mm] " << endl;     
   cout << " Momentum (in):           " << fPx << ", " << fPy << ", " << fPz << " [GeV]" << endl;
   cout << " Momentum (out):          " << fPxOut << ", " << fPyOut << ", " << fPzOut << " [GeV]" << endl;
   cout << " Energy loss:             " << fELoss*1.0e06 << " [keV] " << endl;
diff --git a/its/SpdItsPoint.h b/its/SpdItsPoint.h
index 9f0dc10049421f72d2817621b676640088266af0..38f742611d2ccf2feb9822664c103fab85c99ef9 100644
--- a/its/SpdItsPoint.h
+++ b/its/SpdItsPoint.h
@@ -65,7 +65,10 @@ public:
     Int_t    GetVid(Int_t i) const { return (i > -1 && i < Int_t(fVid.size())) ? fVid[i] : -1; }
     Double_t GetVed(Int_t i) const { return (i > -1 && i < Int_t(fVed.size())) ? fVed[i] :  0; }
  
-    virtual void GetPosTime(TVector3& pos, Double_t& t) const;
+    virtual void     GetPosTime(TVector3& pos, Double_t& t) const;
+    virtual Double_t GetSegLength() const;
+    
+    virtual Bool_t   IsSpecialPoint(Int_t& vid, Double_t& dep) const;
     
     virtual void Print(const Option_t* opt) const;
 
diff --git a/macro/SimuHyb.C b/macro/SimuHyb.C
index 4ed27f931ba8f6382358f918de0b3df26ca71617..4270716c662df7e30502aedbe72b50102b262967 100644
--- a/macro/SimuHyb.C
+++ b/macro/SimuHyb.C
@@ -44,6 +44,9 @@ void SimuHyb(Int_t nEvents = 1)
   SpdRunSim* run = new SpdRunSim();
   
   run->SetName("TGeant4");       
+  //run->SetMaterials("media.geo");
+  
+  //gSystem->Setenv("GEOMPATH","/home/artur/Projects/1/");
   run->SetMaterials("media.geo");
   
   run->SetOutputFile(outFile);      
@@ -61,10 +64,10 @@ void SimuHyb(Int_t nEvents = 1)
   /* ++++++++++++++++++ CAVE ++++++++++++++++++ */
   
   FairModule* cave = new SpdCave("CAVE");
-  //cave->SetGeometryFileName("cave.geo");
-  cave->SetGeometryFileName("cave_precise.geo");
+  cave->SetGeometryFileName("cave.geo");
+  //cave->SetGeometryFileName("cave_precise.geo");
   run->AddModule(cave);
-  
+//   return;
   /* ++++++++++++++++++ PIPE ++++++++++++++++++ */
   
   SpdPipe* Pipe = new SpdPipe();
@@ -72,25 +75,24 @@ void SimuHyb(Int_t nEvents = 1)
   
   /* +++++++++++++++++ MAGNET +++++++++++++++++ */
   
-  SpdHybMagnet* Magnet = new SpdHybMagnet();
-  Magnet->SetGeometryType(1); // 1 (hybrid, deafult), 2 (qsolenoid)
+  SpdHybMagnet* Magnet = new SpdHybMagnet(); // default geometry type = 2
   run->AddModule(Magnet);
   
   /* +++++++++++++++++ DETECTORS ++++++++++++++ */
  
-  SpdTsTB*    ts_barrel   = new SpdTsTB();     /* +++++++++ TST (BARREL) ++++++++++++ */ 
-  SpdTsTEC*   ts_ecps     = new SpdTsTEC();    /* +++++++++ TST (ENDCAPS) +++++++++++ */     
-  SpdEcalTB*  ecal_barrel = new SpdEcalTB();   /* +++++++++ ECALT (BARREL) ++++++++++ */      
-  SpdEcalTEC* ecal_ecps   = new SpdEcalTEC();  /* +++++++++ ECALT (ENDCAPS) +++++++++ */  
-  SpdRsTB*    rs_barrel   = new SpdRsTB();     /* +++++++++ RST (BARREL) ++++++++++++ */  
-  SpdRsTEC*   rs_ecps     = new SpdRsTEC();    /* +++++++++ RST (ENDCAPS) +++++++++++ */
-    
-  run->AddModule(ts_barrel);  
-  run->AddModule(ecal_barrel);
-  run->AddModule(rs_barrel);
-  run->AddModule(ts_ecps);   
-  run->AddModule(ecal_ecps);
-  run->AddModule(rs_ecps);
+   SpdTsTB*    ts_barrel   = new SpdTsTB();     /* +++++++++ TST (BARREL) ++++++++++++ */ 
+   SpdTsTEC*   ts_ecps     = new SpdTsTEC();    /* +++++++++ TST (ENDCAPS) +++++++++++ */     
+   SpdEcalTB*  ecal_barrel = new SpdEcalTB();   /* +++++++++ ECALT (BARREL) ++++++++++ */      
+   SpdEcalTEC* ecal_ecps   = new SpdEcalTEC();  /* +++++++++ ECALT (ENDCAPS) +++++++++ */  
+   SpdRsTB*    rs_barrel   = new SpdRsTB();     /* +++++++++ RST (BARREL) ++++++++++++ */  
+   SpdRsTEC*   rs_ecps     = new SpdRsTEC();    /* +++++++++ RST (ENDCAPS) +++++++++++ */
+     
+   run->AddModule(ts_barrel);  
+   run->AddModule(ecal_barrel);
+   run->AddModule(rs_barrel);
+   run->AddModule(ts_ecps);   
+   run->AddModule(ecal_ecps);
+   run->AddModule(rs_ecps);
 
   //ts_barrel->SetParametersType("SpdTsTBParSet"); // TsTBParSet (default), SpdTsTBParSet
   //ts_barrel->SaveDetIdOption(1); // 1, 2 (default)
@@ -119,8 +121,8 @@ void SimuHyb(Int_t nEvents = 1)
   /* --- field map --- */
   SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
   
-  MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
-  //MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
+  //MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+  MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
   
   //MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
   //MagField->MultiplyField(1);
@@ -160,17 +162,18 @@ void SimuHyb(Int_t nEvents = 1)
         
       //-----------------------------------------------------------
       // Set seed:
+      //gRandom->SetSeed(0);
+      gRandom->SetSeed(54545);
       
-      gRandom->SetSeed(0);
       Int_t seed = gRandom->Integer(Int_t(1e9));
-      P6gen->SetSeed(seed);
+      //P6gen->SetSeed(seed);
        
       //P6gen->SetSeed(0);
       //P6gen->SetSeed(144135822, 2);
       
       //P6gen->SetSeed(12995,0);
       //P6gen->SetSeed(19949278, 1);
-      //P6gen->SetSeed(13495);
+      P6gen->SetSeed(13495);
       //P6gen->SetSeed(127472);
       
 
@@ -181,7 +184,7 @@ void SimuHyb(Int_t nEvents = 1)
 
        
       /* --- Pythia6 initialization --- */
-      P6gen->Initialize("cms","p","p",26/*GeV*/);
+      P6gen->Initialize("cms","p","p",27/*GeV*/);
        
       primGen->AddGenerator(P6gen);
      
@@ -206,7 +209,7 @@ void SimuHyb(Int_t nEvents = 1)
   
   //run->SetStoreTraj(kTRUE);
  
-  SpdCommonGeoMapper::Instance()->SaveEmptyHits();
+  //SpdCommonGeoMapper::Instance()->SaveEmptyHits();
   
   //run->ForceParticleLifetime(-211, 26.033/5.); // pdg, life time [ns]
   //run->ForceParticleLifetime( 211, 26.033/5.); // pdg, life time [ns]
@@ -265,12 +268,13 @@ void SimuHyb(Int_t nEvents = 1)
   
   cout << endl << endl;
   cout << "Macro finished succesfully." << endl;
-  cout << "Output file is "             << outFile << endl;
-  cout << "Parameter file is "          << parFile << endl;
+  cout << "Output file is             " << outFile << endl;
+  cout << "Parameter file is          " << parFile << endl;
+  cout << "Seed (prim.gen.) is        " << seed << endl;
   cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << endl;
   cout << endl;
   
-  cout << " seed = " << seed << endl;
+
   /*--------------------------------------------------*/
   
   //SpdCommonGeoMapper::Instance()->PrintGeometryList();
diff --git a/macro/SimuQsl.C b/macro/SimuQsl.C
new file mode 100644
index 0000000000000000000000000000000000000000..633653077d4025cd68b29161ea8bb96abf826bc8
--- /dev/null
+++ b/macro/SimuQsl.C
@@ -0,0 +1,323 @@
+
+//#define _COMPILE_MACRO_
+
+#if defined(_COMPILE_MACRO_) 
+
+#include <TRint.h>
+#include <TStopwatch.h>
+
+#include "FairParRootFileIo.h"
+
+#include "SpdRunSim.h"
+#include "SpdMCEventHeader.h"
+
+#include "SpdCommonGeoMapper.h"
+
+#include "SpdFields.hh"
+#include "SpdGenerators.hh"
+
+#include "SpdCave.h"
+#include "SpdPipe.h"
+
+#include "SpdIts.h"
+#include "SpdTsTB.h"
+#include "SpdTsTEC.h"
+#include "SpdEcalTB.h"
+#include "SpdEcalTEC.h"
+#include "SpdRsTB.h"
+#include "SpdRsTEC.h"
+
+#include "SpdItsGeoMapperX.h"
+#include "SpdTsTBGeoBuilder.h"
+
+#endif
+
+//_________________________________________________________________________
+void SimuQsl(Int_t nEvents = 1)
+{
+  TString outFile = "run_tor.root";    // Output data file name
+  TString parFile = "params_tor.root"; // Output parameters file name
+   
+  SpdRunSim* run = new SpdRunSim();
+  
+  run->SetName("TGeant4");       
+  //run->SetMaterials("media.geo");
+  
+  //gSystem->Setenv("GEOMPATH","/home/artur/Projects/1/");
+  run->SetMaterials("media.geo");
+  
+  run->SetOutputFile(outFile);      
+  
+  run->SetPythiaDecayer("DecayConfig.C");
+ 
+  run->SetMCEventHeader(new SpdMCEventHeader);
+   /*--------------------------------------------------*/
+  /* +++++++++     GEOMETRY (QSOLENOID)      ++++++++ */
+  /*--------------------------------------------------*/
+  
+  SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+  
+  /* ++++++++++++++++++ CAVE ++++++++++++++++++ */
+  
+  FairModule* cave = new SpdCave("CAVE");
+  //cave->SetGeometryFileName("cave.geo");
+  //cave->SetGeometryFileName("cave_precise.geo");
+  run->AddModule(cave);
+  
+  /* ++++++++++++++++++ PIPE ++++++++++++++++++ */
+  
+  SpdPipe* Pipe = new SpdPipe();
+  //Pipe->UnsetMaterials("air");
+  run->AddModule(Pipe);
+  
+  /* +++++++++ MAGNET +++++++++ */
+
+  SpdHybMagnet* Magnet = new SpdHybMagnet();
+  run->AddModule(Magnet);
+    
+  /* +++++++++++++++++ DETECTORS ++++++++++++++ */
+  SpdEcalTB2*  ecal_barrel = new SpdEcalTB2();   /* +++++++++ ECAL (BARREL) ++++++++++ */      
+  SpdEcalTEC2* ecal_ecps   = new SpdEcalTEC2();  /* +++++++++ ECAL (ENDCAPS) +++++++++ */  
+  SpdRsTB2*    rs_barrel   = new SpdRsTB2();     /* +++++++++ RS (BARREL) ++++++++++++ */  
+  SpdRsTEC2*   rs_ecps     = new SpdRsTEC2();    /* +++++++++ RS (ENDCAPS) +++++++++++ */ 
+  SpdTsTB*     ts_barrel   = new SpdTsTB();      /* +++++++++ TS (BARREL) ++++++++++++ */ 
+  SpdTsTEC*    ts_ecps     = new SpdTsTEC();     /* +++++++++ TS (ENDCAPS) +++++++++++ */     
+ 
+  run->AddModule(ts_barrel);  
+  run->AddModule(ecal_barrel);
+  run->AddModule(rs_barrel);
+  run->AddModule(ts_ecps);   
+  run->AddModule(ecal_ecps);
+  run->AddModule(rs_ecps);
+
+  /* ===== Vertex detector ===== */
+    
+  SpdIts* its = new SpdIts(); 
+  run->AddModule(its);
+  
+  //SpdItsGeoMapperX::Instance()->SetGeometryPars(1);
+  //SpdItsGeoMapperX::Instance()->EnableEndcaps(); // enable(1)/disable(0) Inner Tracker (Its) endcaps ; default = enable
+  
+  //its->SaveEmptyHits();
+
+  /*--------------------------------------------------*/
+  /* ++++++++++++  CUSTOMIZE GEOMETRY   +++++++++++++ */
+  /*--------------------------------------------------*/
+  
+  // Chose TsTEC configuration 
+  //   
+  // option = 1: 2 endcaps x 3 modules, 1 module =  8x2 = 16 layers, total = 48 layers (default)
+  // option = 2: 2 endcaps x 2 modules, 1 module =  8x2 = 16 layers, total = 32 layers  
+  // option = 3: 2 endcaps x 1 modules, 1 module = 26x2 = 52 layers, total = 52 layers (actual!)
+   
+  SpdTsTECGeoMapper::Instance()->SetGeometryPars(3); 
+
+  /*--------------------------------------------------*/
+  /* ++++++++++++  CUSTOMIZE MATERIALS  +++++++++++++ */
+  /*--------------------------------------------------*/
+
+  //SpdParameter* par;
+
+  /* --- alter TsTB straw active media (gas) --- */
+  //par = ts_barrel->GetMapper()->AddParameter("TsTBBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+  
+  /* --- alter TsTEC straw active media (gas) --- */
+  //par = ts_ecps->GetMapper()->AddParameter("TsTECBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+ 
+  /* --- reset all module's materials ---*/
+  //ts_barrel->GetMapper()->UnsetMaterials("air");  // "air" or "vacuum"
+  //ts_ecps->GetMapper()->UnsetMaterials("air");    // "air" or "vacuum"
+  //its->GetMapper()->UnsetMaterials("air");        // "air" or "vacuum"
+  
+  /*--------------------------------------------------*/
+  /* ++++++++++++++   MAGNETIC FIELD   ++++++++++++++ */
+  /*--------------------------------------------------*/
+  
+  /* --- axial field map --- */
+  SpdAxialFieldMap* MagField = new SpdAxialFieldMap("QSolenoidal field");
+  MagField->InitData("map_qsolRZ_6cls2cm.bin");
+  MagField->MultiplyField(0.8);
+
+  /* --- const field --- */
+  //SpdConstField* MagField = new SpdConstField();  
+  //MagField->SetField(0., 0., 8.0); //  kG
+  
+  /* --- field map --- */
+  //SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
+  
+  //MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+  //MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
+   
+  //MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
+  //MagField->MultiplyField(1);
+
+  /* === define field region === */
+  SpdRegion* reg = 0;
+  
+  //reg = MagField->CreateFieldRegion("box");
+  //reg->SetBoxRegion(-1000, 1000, -1000, 1000, -1000, 1000); // (X,Y,Z)_(min,max), cm
+  
+  reg = MagField->CreateFieldRegion("tube");
+  reg->SetTubeRegion(0, 174, -246, 246); // (R,Z)_(min,max), cm 
+  
+  run->SetField(MagField);
+  
+  MagField->Print();
+  
+  /*--------------------------------------------------*/
+  /* ++++++++++ DEFINE PRIMARY GENERATORS +++++++++++ */
+  /*--------------------------------------------------*/
+ 
+  SpdPrimaryGenerator* primGen = new SpdPrimaryGenerator();
+
+      //============================
+      //    PYTHIA 6 GENERATOR
+      //============================
+      
+      SpdPythia6Generator* P6gen = new SpdPythia6Generator();
+      
+      //-----------------------------------------------------------
+      // Option: (decayer for vertex meson- and baryon- resonances)
+      // 0 = Transport generator + External decayer (particles don't decay in the vertex) 
+      // 1 = Primary generator (DEFAULT value, more safely)
+      
+      P6gen->SetVGenOpt(1);
+        
+      //-----------------------------------------------------------
+      // Set seed:
+      
+      gRandom->SetSeed(0);
+      Int_t seed = gRandom->Integer(Int_t(1e9));
+      P6gen->SetSeed(seed,0);
+       
+      //P6gen->SetSeed(0);
+      //P6gen->SetSeed(144135822, 2);
+      
+      //P6gen->SetSeed(12995,0);
+      //P6gen->SetSeed(19949278, 1);
+      //P6gen->SetSeed(13495);
+      //P6gen->SetSeed(127472);
+      
+
+      /* --- Set Pythia6 options --- */
+      SpdPythia6* gg = (SpdPythia6*)P6gen->GetGenerator();
+       
+      gg->SetMSEL(1);  // set miminum bias 
+
+       
+      /* --- Pythia6 initialization --- */
+      P6gen->Initialize("cms","p","p",27/*GeV*/);
+       
+      primGen->AddGenerator(P6gen);
+     
+      primGen->SetVerboseLevel(-10);
+      primGen->SetVerbose(0);
+       
+      //============================
+      
+   run->SetGenerator(primGen);
+
+   primGen->SetBeam(0., 0., 0.1, 0.1); // (X,Y)- position, (X,Y)- (2*delta or sigma) [cm]
+   primGen->SmearVertexXY(kTRUE);
+//   //primGen->SmearGausVertexXY(kTRUE);
+//    
+   primGen->SetTarget(0.,5.);  // Z- position, 2*delta or sigma [cm]
+   primGen->SmearVertexZ(kTRUE);
+//   //primGen->SmearGausVertexZ(kTRUE);
+ 
+  /* ------------------------------------------------ */ 
+  /* +++++++++++++++ GLOBAL OPTIONS +++++++++++++++++ */
+  /* ------------------------------------------------ */ 
+  
+  //run->SetStoreTraj(kTRUE);
+ 
+  //SpdCommonGeoMapper::Instance()->SaveEmptyHits();
+  
+  //run->ForceParticleLifetime(-211, 26.033/5.); // pdg, life time [ns]
+  //run->ForceParticleLifetime( 211, 26.033/5.); // pdg, life time [ns]
+  
+  //SpdCommonGeoMapper::Instance()->UnsetMaterials(false);
+  
+  /* ----------------------------------------------------------------------- */ 
+  /* >>>>>>>>>>>>>>>>>>>>>>>>>>> INITALIZE RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+  /* ----------------------------------------------------------------------- */ 
+  
+  cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++" << endl;
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "+           Init Run (start)               +" << endl; 
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+     
+  run->Init();
+  
+  cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++" << endl;
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "+           Init Run (finish)              +" << endl; 
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+ 
+  /*--------------------------------------------------*/
+  /* +++++++++++++ CREATE RUN PARAMETERS  +++++++++++ */
+  /*--------------------------------------------------*/
+  
+  Bool_t MergePars = kFALSE;
+  FairParRootFileIo* parOut = new FairParRootFileIo(MergePars);
+  if (MergePars) parOut->open(parFile.Data());
+  else parOut->open(parFile.Data(),"RECREATE");
+  
+  FairRuntimeDb* rtdb = run->GetRuntimeDb();
+  rtdb->setOutput(parOut);
+   
+  /* ----------------------------------------------------------------------- */ 
+  /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+  /* ----------------------------------------------------------------------- */ 
+  
+  TStopwatch timer;
+  timer.Start();
+  
+  run->Run(nEvents);
+  
+  timer.Stop();
+ 
+  /*--------------------------------------------------*/
+  /* ++++++++++++  SAVE RUN PARAMETERS  +++++++++++++ */
+  /*--------------------------------------------------*/
+ 
+  rtdb->saveOutput();
+  
+  /*--------------------------------------------------*/
+  
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+
+  cout << endl << endl;
+  cout << "Macro finished succesfully." << endl;
+  cout << "Output file is             " << outFile << endl;
+  cout << "Parameter file is          " << parFile << endl;
+  cout << "Seed (prim.gen.) is        " << seed << endl;
+  cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << endl;
+  cout << endl;
+  
+  /*--------------------------------------------------*/
+  
+  //SpdCommonGeoMapper::Instance()->PrintGeometryList();
+  SpdCommonGeoMapper::Instance()->PrintGeometry();
+  
+  //SpdItsGeoMapperX::Instance()->PrintVolPars(); 
+  //SpdItsGeoMapperX::Instance()->PrintGeoTable(); 
+  //SpdItsGeoMapperX::Instance()->Print("");
+  
+  /*--------------------------------------------------*/
+  
+  gApplication->Terminate();
+}
+
+
diff --git a/macro/analysis/CheckNodePath.C b/macro/analysis/CheckNodePath.C
new file mode 100644
index 0000000000000000000000000000000000000000..8e577e6b6414d0b160b435b470df01ac307554cb
--- /dev/null
+++ b/macro/analysis/CheckNodePath.C
@@ -0,0 +1,46 @@
+
+
+void Print(SpdGeopathParser& ppath);
+
+void CheckNodePath() 
+{
+    
+ SpdGeopathParser ppath;
+ TString nodepath;
+ 
+ nodepath = "/cave_1/SideSVol_8/LayerSideSVol_2/L4930EnvelopeVol_5/L4930MDTSVol_1/L4930CellVol_3/L4930GasCellVol_1";
+
+ ppath.ParsePath(nodepath);
+ cout << "MODULE NUMBER: " << ppath.Num(2) << endl;
+  
+ Print(ppath);
+ 
+ nodepath = "/cave_1/SideSVol_3/LayerSideSVol_2/L4930EnvelopeVol_5/L4930MDTSVol_1/L4930CellVol_3/L4930GasCellVol_1";
+
+ ppath.ParsePath(nodepath);
+ cout << "MODULE NUMBER: " << ppath.Num(2) << endl;
+  
+ Print(ppath);
+ 
+ nodepath = "/cave_1/TsTBModule3_6/TsTBLayer127_25/TsTBStraw89_2/TsTBStraw89Shell_1";
+ 
+ ppath.ParsePath(nodepath);
+ cout << "MODULE NUMBER: " << ppath.Num(2) << endl;
+  
+ Print(ppath);
+ 
+}
+
+void Print(SpdGeopathParser& ppath)
+{
+   Int_t max_geo_level = ppath.GetCurrentPathLevel();
+   cout << ppath.GetCurrentPathString() << endl;
+   
+   for (Int_t i(1); i<=max_geo_level; i++) {
+        cout << i << " " <<  ppath.Num(i) << " "<< ppath.VNum(i) << " "<< ppath.Name(i) << "    :: " << ppath.Path(i) << endl; 
+       
+   }
+   
+  
+    
+}
diff --git a/macro/analysis/CheckOutputData.C b/macro/analysis/CheckOutputData.C
index d71d6b5b282b0b959a1961dc1f840704083c36de..f10c16e22ea4b21249044ab919bffbf17021673c 100644
--- a/macro/analysis/CheckOutputData.C
+++ b/macro/analysis/CheckOutputData.C
@@ -3,12 +3,15 @@ void check_headers();
 void check_mctracks();
 
 void check_points_tstb();
-void check_points_tssb();
-
 void check_points_tstec();
-
 void check_points_its();
 
+void check_points_ecaltb2();
+void check_points_ecaltec2();
+
+void check_points_rstb2();
+void check_points_rstec2();
+
 void check_geotracks();
 
 void readparams(TString stype); 
@@ -18,19 +21,20 @@ TTree* t = 0;
 TString inFile, inParFile;
 
 //________________________________________________________________________________
-void CheckOutputData(TString stype = "tor") {
+void CheckOutputData(TString path = "", TString stype = "tor") {
   //
-  
+  if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
+   
   // Input data & parameters files   
   if (stype == "tor" || stype == "hyb") 
   { 
-      inFile    = "run_tor.root";   
-      inParFile = "params_tor.root";
+      inFile    = path+"run_tor.root";   
+      inParFile = path+"params_tor.root";
   }
   else if (stype == "sol") 
   {  
-      inFile    = "run_sol.root";   
-      inParFile = "params_sol.root";
+      inFile    = path+"run_sol.root";   
+      inParFile = path+"params_sol.root";
   }
   else {
       cout << "<CheckOutputData> Unknown data type: " << stype << endl;
@@ -50,10 +54,16 @@ void CheckOutputData(TString stype = "tor") {
   check_headers(); 
   check_mctracks();
   
-  //check_points_tstb();
-  //check_points_tstec();
+  check_points_tstb();
+  check_points_tstec();
   check_points_its(); 
   
+  check_points_rstb2();
+  check_points_rstec2();
+  
+  check_points_ecaltb2();
+  check_points_ecaltec2();
+  
   //check_geotracks();
 }
 
@@ -321,27 +331,192 @@ void check_points_its()
 }
 
 //______________________________________________________________________________
-void check_points_tssb() 
+void check_points_rstb2() 
+{
+   // 
+   if (!t) return;  
+    
+   TBranch* branch = t->GetBranch("SpdRsTB2Point");
+   if (!branch) return;
+   
+   cout << "\n+++++++++++++++++ <check_points_rstb> ++++++++++++++++++";
+   cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;  
+  
+   TClonesArray *fT = 0; 
+   t->SetBranchAddress("SpdRsTB2Point",&fT) ;
+   
+   int entries = branch->GetEntries();
+  
+   cout << "Total number of RSTB2-point COLLECTIONS in the TREE = " << entries << endl;    
+   
+   if (entries == 0) return;
+   
+   SpdRsTB2Point* point;
+   Int_t ne;
+
+   for (int j(0); j <entries; j++) {
+     
+        branch->GetEntry(j);      
+        
+        ne = fT->GetEntriesFast();
+        
+        cout << "entry: " << j << " points = " << ne << endl;
+        
+        if (j == 0) {
+            cout << ">>>>>>>>>>>>>>>>> Print FIRST entry: " << j << endl;
+            
+            for (int i(0); i < ne; i++) {
+                 point = (SpdRsTB2Point*)fT->At(i);            
+                 if (i < 2) point->Print("");   
+            }
+            
+        }
+        
+        if (j == entries-1) {
+            cout << ">>>>>>>>>>>>>>>>> Print LAST entry:  " << j << endl;
+          
+            for (int i(0); i < ne; i++) {
+                point = (SpdRsTB2Point*)fT->At(i);            
+                if (i < 2) point->Print("");   
+            }
+        }
+   }
+   
+   cout << "Total number of RSTB2-point COLLECTIONS in the TREE = " << entries << endl;    
+}
+
+//______________________________________________________________________________
+void check_points_rstec2() 
+{
+   // 
+   if (!t) return;  
+    
+   TBranch* branch = t->GetBranch("SpdRsTEC2Point");
+   if (!branch) return;
+   
+   cout << "\n+++++++++++++++++ <check_points_rstec> +++++++++++++++++";
+   cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;  
+  
+   TClonesArray *fT = 0; 
+   t->SetBranchAddress("SpdRsTEC2Point",&fT) ;
+   
+   int entries = branch->GetEntries();
+  
+   cout << "Total number of RSTEC2-point COLLECTIONS in the TREE = " << entries << endl;    
+   
+   if (entries == 0) return;
+   
+   SpdRsTEC2Point* point;
+   Int_t ne;
+
+   for (int j(0); j <entries; j++) {
+     
+        branch->GetEntry(j);      
+        
+        ne = fT->GetEntriesFast();
+        
+        cout << "entry: " << j << " points = " << ne << endl;
+        
+        if (j == 0) {
+            cout << ">>>>>>>>>>>>>>>>> Print FIRST entry: " << j << endl;
+            
+            for (int i(0); i < ne; i++) {
+                 point = (SpdRsTEC2Point*)fT->At(i);            
+                 if (i < 2) point->Print("");   
+            }
+            
+        }
+        
+        if (j == entries-1) {
+            cout << ">>>>>>>>>>>>>>>>> Print LAST entry:  " << j << endl;
+          
+            for (int i(0); i < ne; i++) {
+                point = (SpdRsTEC2Point*)fT->At(i);            
+                if (i < 2) point->Print("");   
+            }
+        }
+   }
+   
+   cout << "Total number of RSTEC2-point COLLECTIONS in the TREE = " << entries << endl;    
+}
+
+//______________________________________________________________________________
+void check_points_ecaltb2() 
+{
+   // 
+   if (!t) return;  
+    
+   TBranch* branch = t->GetBranch("SpdEcalTB2Point");
+   if (!branch) return;
+   
+   cout << "\n+++++++++++++++ <check_points_ecaltb> +++++++++++++++++";
+   cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;  
+  
+   TClonesArray *fT = 0; 
+   t->SetBranchAddress("SpdEcalTB2Point",&fT) ;
+   
+   int entries = branch->GetEntries();
+  
+   cout << "Total number of ECALTB2-point COLLECTIONS in the TREE = " << entries << endl;    
+   
+   if (entries == 0) return;
+   
+   SpdEcalTB2Point* point;
+   Int_t ne;
+
+   for (int j(0); j <entries; j++) {
+     
+        branch->GetEntry(j);      
+        
+        ne = fT->GetEntriesFast();
+        
+        cout << "entry: " << j << " points = " << ne << endl;
+        
+        if (j == 0) {
+            cout << ">>>>>>>>>>>>>>>>> Print FIRST entry: " << j << endl;
+            
+            for (int i(0); i < ne; i++) {
+                 point = (SpdEcalTB2Point*)fT->At(i);            
+                 if (i < 2) point->Print("");   
+            }
+            
+        }
+        
+        if (j == entries-1) {
+            cout << ">>>>>>>>>>>>>>>>> Print LAST entry:  " << j << endl;
+          
+            for (int i(0); i < ne; i++) {
+                point = (SpdEcalTB2Point*)fT->At(i);            
+                if (i < 2) point->Print("");   
+            }
+        }
+   }
+   
+   cout << "Total number of ECALTB2-point COLLECTIONS in the TREE = " << entries << endl;    
+}
+
+//______________________________________________________________________________
+void check_points_ecaltec2() 
 {
    // 
    if (!t) return;  
     
-   TBranch* branch = t->GetBranch("SpdTsSBPoint");
+   TBranch* branch = t->GetBranch("SpdEcalTEC2Point");
    if (!branch) return;
    
-   cout << "\n+++++++++++++++++ <check_points_tssb> ++++++++++++++++++";
+   cout << "\n+++++++++++++++ <check_points_ecaltec> +++++++++++++++++";
    cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;  
   
    TClonesArray *fT = 0; 
-   t->SetBranchAddress("SpdTsSBPoint",&fT) ;
+   t->SetBranchAddress("SpdEcalTEC2Point",&fT) ;
    
    int entries = branch->GetEntries();
   
-   cout << "Total number of TSSB-point COLLECTIONS in the TREE = " << entries << endl;    
+   cout << "Total number of ECALTEC2-point COLLECTIONS in the TREE = " << entries << endl;    
    
    if (entries == 0) return;
    
-   SpdTsSBPoint* point;
+   SpdEcalTEC2Point* point;
    Int_t ne;
 
    for (int j(0); j <entries; j++) {
@@ -356,7 +531,7 @@ void check_points_tssb()
             cout << ">>>>>>>>>>>>>>>>> Print FIRST entry: " << j << endl;
             
             for (int i(0); i < ne; i++) {
-                 point = (SpdTsSBPoint*)fT->At(i);            
+                 point = (SpdEcalTEC2Point*)fT->At(i);            
                  if (i < 2) point->Print("");   
             }
             
@@ -366,13 +541,13 @@ void check_points_tssb()
             cout << ">>>>>>>>>>>>>>>>> Print LAST entry:  " << j << endl;
           
             for (int i(0); i < ne; i++) {
-                point = (SpdTsSBPoint*)fT->At(i);            
+                point = (SpdEcalTEC2Point*)fT->At(i);            
                 if (i < 2) point->Print("");   
             }
         }
    }
    
-   cout << "Total number of TSSB-point COLLECTIONS in the TREE = " << entries << endl;    
+   cout << "Total number of ECALTEC2-point COLLECTIONS in the TREE = " << entries << endl;    
 }
 
 //______________________________________________________________________________
diff --git a/macro/analysis/CheckOutputParams.C b/macro/analysis/CheckOutputParams.C
index 538761ba2a262d5a38db42cf96643ff3450a941c..875ce1dca5688d0b74fe03e0c2014e7b19abc3b9 100644
--- a/macro/analysis/CheckOutputParams.C
+++ b/macro/analysis/CheckOutputParams.C
@@ -2,19 +2,21 @@
 void ReadGeometry();
 void ReadModules();
 void ReadFieldPars();
-void ReadParameters(TString stype);
+void ReadPassivePars();
+void ReadActivePars(TString stype);
 
 TString inParFile;
 TFile* fp;
 
 //________________________________________________________________________________
-void CheckOutputParams(TString stype = "tor") {
+void CheckOutputParams(TString path = "", TString stype = "tor") {
   //
+  if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
   
   // Input data & parameters files   
   if (stype == "tor" || stype == "hyb") 
   { 
-      inParFile = "params_tor.root";
+      inParFile = path+"params_tor.root";
   }
   else if (stype == "sol") 
   {  
@@ -33,7 +35,8 @@ void CheckOutputParams(TString stype = "tor") {
   ReadGeometry();
   ReadModules();
   ReadFieldPars();
-  ReadParameters(stype);
+  ReadPassivePars();
+  ReadActivePars(stype);
   
   //fp->Close();
 }
@@ -65,11 +68,26 @@ void ReadModules()
 void ReadFieldPars()
 {
   SpdFieldPar* field_pars = (SpdFieldPar*)fp->Get("SpdFieldPar");
-  if (field_pars) field_pars->print(1);  
+  if (!field_pars) return;
+  
+  field_pars->print(1);  
+  
+  SpdFieldCreator* fieldCreator = new SpdFieldCreator();    
+  SpdField* field = (SpdField*)fieldCreator->createFairField(field_pars);
+  if (!field) return; 
+      
+  field->Print(""); 
+}
+
+//________________________________________________________________________
+void ReadPassivePars()
+{
+  SpdPassiveGeoParSet* passive_pars = (SpdPassiveGeoParSet*)fp->Get("PassiveGeoParSet");
+  if (passive_pars) passive_pars->print(1);  
 }
 
 //________________________________________________________________________
-void ReadParameters(TString stype)
+void ReadActivePars(TString stype)
 {
   if (stype == "tor" || stype == "hyb") 
   { 
diff --git a/macro/analysis/RestoreInput.C b/macro/analysis/RestoreInput.C
index f21cd8c196e4d3516cd2261ccd20f75a85152700..041b7b8316659a96ccf81cdf7fd4fa61b1dc888e 100644
--- a/macro/analysis/RestoreInput.C
+++ b/macro/analysis/RestoreInput.C
@@ -130,9 +130,11 @@ void restore_modules()
    
   // load materials and create geometry top level (cave)
   SpdCommonGeoMapper::Instance()->OpenGeometry();
+  
+  SpdPassiveGeoParSet* paspars = (SpdPassiveGeoParSet*)fp->Get("PassiveGeoParSet");
    
-  FairModule* Cave = new SpdCave();
-  Cave->SetGeometryFileName("cave.geo");
+  SpdCave* Cave = new SpdCave();
+  Cave->LoadParsFrom(paspars);
   Cave->ConstructGeometry();
 
   // load full set of modules (passive and active)
@@ -187,4 +189,4 @@ void restore_modules()
 }
 
 
-   
\ No newline at end of file
+   
diff --git a/macro/analysis/ecalt/CheckEcalTB2Points.C b/macro/analysis/ecalt/CheckEcalTB2Points.C
new file mode 100644
index 0000000000000000000000000000000000000000..837ef44ccb0bf7b759aebd3d77f4a9e127b74ac6
--- /dev/null
+++ b/macro/analysis/ecalt/CheckEcalTB2Points.C
@@ -0,0 +1,186 @@
+TTree* Tree_ = 0;
+
+SpdParSet*         EcalTBPars_;
+SpdPrimGenParSet*  GenPars_;
+
+TGeoNavigator* Ntor_ = 0; 
+
+SpdMCEventHeader*  Header_    = 0;
+TClonesArray*      MCTracks_  = 0;
+TClonesArray*      EcalPoints_ = 0;
+
+Int_t  GeoLevel_ = 0;
+
+Bool_t  LoadGeometryAndPars(TString inParFile);
+Bool_t  RegisterRunData(TString inFile);
+
+void    AnalyseEvent(Int_t nevent);
+Bool_t  AnalysePoint(SpdEcalTB2Point* point);
+
+TTree* t = 0;
+
+TString inFile, inParFile;
+
+//________________________________________________________________________________
+void CheckEcalTB2Points() {
+    
+  TString inParFile  = "test_params.root";
+  TString inDataFile = "test_data.root";   
+  
+  if (!LoadGeometryAndPars(inParFile)) {
+      cout << "Bad geometry or parameters " << endl;
+      return;
+  }
+
+  if (!RegisterRunData(inDataFile)) {
+      cout << "Bad data in the file " << endl;
+      return;
+  }
+  
+  Int_t entries = Tree_->GetEntries();
+  
+  cout << "Entries(tree): " << entries << endl;
+  
+  if (entries == 0) return;
+   
+  //return;
+  
+  cout << "\n>>>>>>>>>>>>>>>> DATA : Ok! <<<<<<<<<<<<<<<<< " << endl;
+   
+  //entries = 1; // FIXME
+  
+  for (Int_t i(0); i < entries; i++) {
+       Tree_->GetEntry(i);
+       AnalyseEvent(i);
+  }
+}
+
+//________________________________________________________________________________
+void AnalyseEvent(Int_t nevent)
+{
+    
+//   Header_->Print(1);
+   
+   //-------------------------- MC-TRACKS ---------------------------------
+//   Int_t ntracks = MCTracks_->GetEntriesFast();
+       
+//    cout << "\n<Analyse> mctracks = " << ntracks << endl;
+// 
+//    SpdMCTrack* track;
+//    for (int i(0); i < ntracks; i++) {
+//         track = (SpdMCTrack*)MCTracks_->At(i);              
+//         //if (i < 30) track->Print(i);   
+//         if (track->GetMotherId() < 0) track->Print(i);
+//    }
+   
+   //--------------------------- EcalTB POINTS ---------------------------
+  
+   Int_t npoints = EcalPoints_->GetEntriesFast();
+  
+   cout << "\n<Analyse> ecalQEC-points = " << npoints << " event: " << nevent << endl;
+   
+   SpdEcalTB2Point* point;
+   
+   for (Int_t i(0); i < npoints; i++) {
+        
+        point = (SpdEcalTB2Point*)EcalPoints_->At(i); 
+        
+        AnalysePoint(point);
+   }
+}
+
+//________________________________________________________________________________
+Bool_t AnalysePoint(SpdEcalTB2Point* point)
+{
+   if (!point) return false;
+   
+   cout << ">>>>>>>>>>>>>>>>> ANALYSE POINT >>>>>>>>>>>>>>>>>>>>>" << "\n\n";
+   
+   point->Print("");   
+    
+   TString node_path = point->GetNodePath();
+   
+   if (!Ntor_->cd(node_path)) {
+       cout << "No such node: " << node_path << endl;
+       return false;  
+   }
+   else cout << "Current node path: " << Ntor_->GetPath() << "\n\n";
+      
+   cout << "Energy deposited: " << point->GetEloss() << "\n";
+   
+   SpdGeopathParser ppath;
+   ppath.ParsePath(node_path);
+   
+   cout << "\n";
+
+   return true;  
+}
+
+//________________________________________________________________________________
+Bool_t LoadGeometryAndPars(TString inParFile)
+{
+  TFile* fp = new TFile(inParFile);
+  if (!fp) return kFALSE;
+      
+  /* PRIMARY GENERATOR PARAMETERS */
+  
+  GenPars_ = (SpdPrimGenParSet*)fp->Get("PrimGenParSet");
+  if (!GenPars_) {
+      cout << "No PrimGen parameters " << endl;
+      return kFALSE;
+  }
+      
+  //GenPars_->print(1);
+
+  /* RANGE SYSTEM BARREL (EcalTB) PARAMETERS */
+  
+  EcalTBPars_ = (SpdParSet*)fp->Get("EcalTBParSet");
+  if (!EcalTBPars_) {
+      cout << "No ECAL parameters " << endl;
+      return kFALSE;
+  }
+  
+  //EcalTBPars_->print(1);
+  
+  /* +++++++++++++++ LOAD GEOMETRY  +++++++++++++++ */
+
+  FairGeoParSet* geoset = (FairGeoParSet*)fp->Get("FairGeoParSet");
+  
+  Ntor_ = gGeoManager->GetCurrentNavigator();
+  
+  /* DRAW GEOMETRY */
+  //gGeoManager->SetVisLevel(2);
+  //gGeoManager->GetMasterVolume()->Draw("ogl");
+   
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Bool_t RegisterRunData(TString inFile)
+{
+  TFile* f = new TFile(inFile);
+  if (!f) return kFALSE;
+  
+  TTree* t = (TTree*)f->Get("cbmsim");  
+  if (!t) return kFALSE;
+
+  TBranch* branch;
+  
+  branch = t->GetBranch("MCEventHeader.");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("MCEventHeader.",&Header_) ;
+  
+  //branch = t->GetBranch("SpdMCTrack");
+  //if (!branch) return kFALSE;
+  //t->SetBranchAddress("SpdMCTrack",&MCTracks_);       
+  
+  branch = t->GetBranch("SpdEcalTB2Point");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdEcalTB2Point",&EcalPoints_) ;
+ 
+  cout << "\n>>>>>>>>>>>>>>>> FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;
+  
+  Tree_ = t;
+  
+  return kTRUE;
+}
diff --git a/macro/analysis/ecalt/CheckEcalTEC2Points.C b/macro/analysis/ecalt/CheckEcalTEC2Points.C
new file mode 100644
index 0000000000000000000000000000000000000000..f15fc1c93bd829b598ed3d8efded3c9991df80b1
--- /dev/null
+++ b/macro/analysis/ecalt/CheckEcalTEC2Points.C
@@ -0,0 +1,187 @@
+TTree* Tree_ = 0;
+
+SpdParSet*         EcalTBPars_;
+SpdPrimGenParSet*  GenPars_;
+
+TGeoNavigator* Ntor_ = 0; 
+
+SpdMCEventHeader*  Header_    = 0;
+TClonesArray*      MCTracks_  = 0;
+TClonesArray*      EcalPoints_ = 0;
+
+Int_t  GeoLevel_ = 0;
+
+Bool_t  LoadGeometryAndPars(TString inParFile);
+Bool_t  RegisterRunData(TString inFile);
+
+void    AnalyseEvent(Int_t nevent);
+Bool_t  AnalysePoint(SpdEcalTEC2Point* point);
+
+TTree* t = 0;
+
+TString inFile, inParFile;
+
+//________________________________________________________________________________
+void CheckEcalTEC2Points() {
+    
+  TString inParFile  = "params_tor.root";
+  TString inDataFile = "run_tor.root";   
+  
+  if (!LoadGeometryAndPars(inParFile)) {
+      cout << "Bad geometry or parameters " << endl;
+      return;
+  }
+
+  if (!RegisterRunData(inDataFile)) {
+      cout << "Bad data in the file " << endl;
+      return;
+  }
+  
+  Int_t entries = Tree_->GetEntries();
+  
+  cout << "Entries(tree): " << entries << endl;
+  
+  if (entries == 0) return;
+   
+  //return;
+  
+  cout << "\n>>>>>>>>>>>>>>>> DATA : Ok! <<<<<<<<<<<<<<<<< " << endl;
+   
+  //entries = 1; // FIXME
+  
+  for (Int_t i(0); i < entries; i++) {
+       Tree_->GetEntry(i);
+       AnalyseEvent(i);
+  }
+}
+
+//________________________________________________________________________________
+void AnalyseEvent(Int_t nevent)
+{
+    
+//   Header_->Print(1);
+   
+   //-------------------------- MC-TRACKS ---------------------------------
+//   Int_t ntracks = MCTracks_->GetEntriesFast();
+       
+//    cout << "\n<Analyse> mctracks = " << ntracks << endl;
+// 
+//    SpdMCTrack* track;
+//    for (int i(0); i < ntracks; i++) {
+//         track = (SpdMCTrack*)MCTracks_->At(i);              
+//         //if (i < 30) track->Print(i);   
+//         if (track->GetMotherId() < 0) track->Print(i);
+//    }
+   
+   //--------------------------- EcalTEC POINTS ---------------------------
+  
+   Int_t npoints = EcalPoints_->GetEntriesFast();
+  
+   cout << "\n<Analyse> ecalQEC-points = " << npoints << " event: " << nevent << endl;
+   
+   SpdEcalTEC2Point* point;
+   
+   for (Int_t i(0); i < npoints; i++) {
+        
+        point = (SpdEcalTEC2Point*)EcalPoints_->At(i); 
+        
+        AnalysePoint(point);
+   }
+}
+
+//________________________________________________________________________________
+Bool_t AnalysePoint(SpdEcalTEC2Point* point)
+{
+   if (!point) return false;
+   
+   cout << ">>>>>>>>>>>>>>>>> ANALYSE POINT >>>>>>>>>>>>>>>>>>>>>" << "\n\n";
+   
+   point->Print("");   
+    
+   TString node_path = point->GetNodePath();
+   
+   if (!Ntor_->cd(node_path)) {
+       cout << "No such node: " << node_path << endl;
+       return false;  
+   }
+   else cout << "Current node path: " << Ntor_->GetPath() << "\n\n";
+      
+   cout << "Energy deposited: " << point->GetEloss() << "\n";
+   
+   SpdGeopathParser ppath;
+   ppath.ParsePath(node_path);
+   
+   cout << "\n";
+
+   return true;  
+}
+
+//________________________________________________________________________________
+Bool_t LoadGeometryAndPars(TString inParFile)
+{
+  TFile* fp = new TFile(inParFile);
+  if (!fp) return kFALSE;
+      
+  /* PRIMARY GENERATOR PARAMETERS */
+  
+  GenPars_ = (SpdPrimGenParSet*)fp->Get("PrimGenParSet");
+  if (!GenPars_) {
+      cout << "No PrimGen parameters " << endl;
+      return kFALSE;
+  }
+      
+  //GenPars_->print(1);
+
+  /* RANGE SYSTEM BARREL (EcalTB) PARAMETERS */
+  
+  EcalTBPars_ = (SpdParSet*)fp->Get("EcalTECParSet");
+  if (!EcalTBPars_) {
+      cout << "No ECAL parameters " << endl;
+      return kFALSE;
+  }
+  
+  //EcalTBPars_->print(1);
+  
+  /* +++++++++++++++ LOAD GEOMETRY  +++++++++++++++ */
+
+  FairGeoParSet* geoset = (FairGeoParSet*)fp->Get("FairGeoParSet");
+  
+  Ntor_ = gGeoManager->GetCurrentNavigator();
+  
+  /* DRAW GEOMETRY */
+  //gGeoManager->SetVisLevel(2);
+  //gGeoManager->GetMasterVolume()->Draw("ogl");
+   
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Bool_t RegisterRunData(TString inFile)
+{
+  TFile* f = new TFile(inFile);
+  if (!f) return kFALSE;
+  
+  TTree* t = (TTree*)f->Get("cbmsim");  
+  if (!t) return kFALSE;
+
+  TBranch* branch;
+  
+  branch = t->GetBranch("MCEventHeader.");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("MCEventHeader.",&Header_) ;
+  
+  //branch = t->GetBranch("SpdMCTrack");
+  //if (!branch) return kFALSE;
+  //t->SetBranchAddress("SpdMCTrack",&MCTracks_);       
+  
+  branch = t->GetBranch("SpdEcalTEC2Point");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdEcalTEC2Point",&EcalPoints_) ;
+ 
+  cout << "\n>>>>>>>>>>>>>>>> FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;
+  
+  Tree_ = t;
+  
+  return kTRUE;
+}
+
diff --git a/macro/analysis/its/CheckItsData.C b/macro/analysis/its/CheckItsData.C
index 734ee30357fdcbaf49ea57708cd753904bd334da..b125c719bf6e316580f969006697e9ed333692f6 100644
--- a/macro/analysis/its/CheckItsData.C
+++ b/macro/analysis/its/CheckItsData.C
@@ -69,7 +69,7 @@ void CheckItsData()
   
   if (entries == 0) return;
    
-  return;
+  //return;
   
   cout << "\n>>>>>>>>>>>>>>>> DATA : Ok! <<<<<<<<<<<<<<<<< " << endl;
    
@@ -130,12 +130,12 @@ void AnalyseEvent()
         
         point->Print("");   
         
-        //--------------- EXTRUCT CHANNEL DATA  ---------------------------
+        //--------------- EXTRACT CHANNEL DATA  ---------------------------
         
         cout << ">>>>>> Extract chip data: >>>>>>" << endl;
         
         ItsGeoBuilder_->SetNodePath(point->GetNodeId()); // set node (chip)
-        
+    
         ItsGeoBuilder_->GetDetectorPosition(pos_chip);   // get chip position
         
         cout << "chip full path:     " << ItsGeoBuilder_->GetNodePath() << endl;
diff --git a/macro/analysis/rst/CheckRsTB2Data.C b/macro/analysis/rst/CheckRsTB2Data.C
new file mode 100644
index 0000000000000000000000000000000000000000..a8723dfe8304ba0641de72fedd23398ddece30d4
--- /dev/null
+++ b/macro/analysis/rst/CheckRsTB2Data.C
@@ -0,0 +1,286 @@
+// #define _COMPILE_MACRO_
+// 
+// #if defined(_COMPILE_MACRO_) 
+
+#include <TStopwatch.h>
+#include <TTree.h>
+#include <TClonesArray.h>
+#include <TGeoManager.h>
+#include <TGeoNavigator.h>
+
+#include "FairGeoParSet.h"
+#include "FairBaseParSet.h"
+#include "SpdPrimGenParSet.h"
+
+#include "SpdCommonGeoMapper.h"
+#include "SpdCave.h"
+#include "SpdDetector.h"
+
+#include "SpdMCEventHeader.h"
+#include "SpdMCTrack.h"
+
+#include "SpdRsTB2.h"
+#include "SpdRsTB2Point.h"
+
+//#endif
+
+TTree* Tree_ = 0;
+
+SpdParSet*         RsTBPars_;
+SpdPrimGenParSet*  GenPars_;
+
+TGeoNavigator* Ntor_ = 0; 
+
+SpdMCEventHeader*  Header_    = 0;
+TClonesArray*      MCTracks_  = 0;
+TClonesArray*      RsTBPoints_ = 0;
+
+Int_t  GeoLevel_ = 0;
+
+Bool_t  LoadGeometryAndPars(TString inParFile);
+Bool_t  RegisterRunData(TString inFile);
+
+void    AnalyseEvent(Int_t nevent);
+Bool_t  AnalysePoint(SpdRsTB2Point* point);
+
+Bool_t  DetectorPosition(Double_t* p);
+Bool_t  DetectorOrientation(Double_t* v, Char_t dir);
+
+TTree* t = 0;
+
+TString inFile, inParFile;
+
+//________________________________________________________________________________
+void CheckRsTB2Data() {
+  //  
+  TString inParFile  = "params_tor.root";
+  TString inDataFile = "run_tor.root";   
+  
+  if (!LoadGeometryAndPars(inParFile)) {
+      cout << "Bad geometry or parameters " << endl;
+      return;
+  }
+
+  if (!RegisterRunData(inDataFile)) {
+      cout << "Bad data in the file " << endl;
+      return;
+  }
+  
+  Int_t entries = Tree_->GetEntries();
+  
+  cout << "Entries(tree): " << entries << endl;
+  
+  if (entries == 0) return;
+   
+  //return;
+  
+  cout << "\n>>>>>>>>>>>>>>>> DATA : Ok! <<<<<<<<<<<<<<<<< " << endl;
+   
+  //entries = 1; // FIXME
+  
+  for (Int_t i(0); i < entries; i++) {
+       Tree_->GetEntry(i);
+       AnalyseEvent(i);
+  }
+  
+}
+
+//________________________________________________________________________________
+void AnalyseEvent(Int_t nevent)
+{
+    
+//   Header_->Print(1);
+   
+   //-------------------------- MC-TRACKS ---------------------------------
+   Int_t ntracks = MCTracks_->GetEntriesFast();
+       
+//    cout << "\n<Analyse> mctracks = " << ntracks << endl;
+// 
+//    SpdMCTrack* track;
+//    for (int i(0); i < ntracks; i++) {
+//         track = (SpdMCTrack*)MCTracks_->At(i);              
+//         //if (i < 30) track->Print(i);   
+//         if (track->GetMotherId() < 0) track->Print(i);
+//    }
+   
+   //--------------------------- RsTB POINTS -------------------------------
+  
+   Int_t npoints = RsTBPoints_->GetEntriesFast();
+  
+   cout << "\n<Analyse> rstb-points = " << npoints << " event: " << nevent << endl;
+   
+   SpdRsTB2Point* point;
+   
+   for (Int_t i(0); i < npoints; i++) {
+        
+        point = (SpdRsTB2Point*)RsTBPoints_->At(i); 
+        
+        AnalysePoint(point);
+
+   }
+}
+
+//________________________________________________________________________________
+Bool_t AnalysePoint(SpdRsTB2Point* point)
+{
+   if (!point) return false;
+   
+   cout << ">>>>>>>>>>>>>>>>> ANALYSE POINT >>>>>>>>>>>>>>>>>>>>>" << "\n\n";
+   
+   point->Print("");   
+    
+   TString node_path = point->GetHitGeoPath();
+   
+   if (!Ntor_->cd(node_path)) {
+       cout << "No such node: " << node_path << endl;
+       return false;  
+   }
+   else cout << "Current node path: " << Ntor_->GetPath() << "\n\n";
+   
+   Double_t detpos[3];           // hit node position in global CS
+   Double_t ax[3], ay[3], az[3]; // hit node axis (global CS)
+   
+   SpdGeopathParser ppath;
+   ppath.ParsePath(node_path);
+   
+   cout << "RS module number: " << ppath.Num(2) << "\n\n";
+   
+   // print node geometry levels:
+   for (Int_t i(1); i<= ppath.GetCurrentPathLevel(); i++) {
+        cout << i << " " <<  ppath.Num(i) << " "<< ppath.Name(i) << "    :: " << ppath.Path(i) << endl; 
+   }
+   cout << "\n";
+
+   // Hit detector
+   DetectorPosition(detpos);
+   DetectorOrientation(ax,'x');
+   DetectorOrientation(ay,'y');
+   DetectorOrientation(az,'z'); 
+   
+   cout << "HIT NODE: " << Ntor_->GetPath() << "\n\n";
+   cout << "\t position:   " << detpos[0] << " " << detpos[1] << " " << detpos[2] << " " << endl;
+   cout << "\t   x-axis:   " << ax[0] << " " << ax[1] << " " << ax[2] << " " << endl;
+   cout << "\t   y-axis:   " << ay[0] << " " << ay[1] << " " << ay[2] << " " << endl;
+   cout << "\t   z-axis:   " << az[0] << " " << az[1] << " " << az[2] << " " << endl;
+   cout << "\n";
+   
+   // Module
+   Ntor_->cd(ppath.Path(2));
+   
+   DetectorPosition(detpos);
+   DetectorOrientation(ax,'x');
+   DetectorOrientation(ay,'y');
+   DetectorOrientation(az,'z'); 
+   
+   cout << "HIT MODULE: " << Ntor_->GetPath() << "\n\n";
+   cout << "\t position:   " << detpos[0] << " " << detpos[1] << " " << detpos[2] << " " << endl; // always (0,0,0) caused by using TGeoArb8! 
+   cout << "\t   x-axis:   " << ax[0] << " " << ax[1] << " " << ax[2] << " " << endl;
+   cout << "\t   y-axis:   " << ay[0] << " " << ay[1] << " " << ay[2] << " " << endl;
+   cout << "\t   z-axis:   " << az[0] << " " << az[1] << " " << az[2] << " " << endl;
+   cout << "\n";
+   
+   return true;  
+}
+
+//_____________________________________________________________________________
+Bool_t DetectorPosition(Double_t* p)
+{
+  if (!Ntor_) return false;
+  Double_t ploc[3] = {0, 0, 0};
+  Ntor_->LocalToMaster(ploc,p);
+  return true;
+}
+
+//_____________________________________________________________________________ 
+Bool_t DetectorOrientation(Double_t* v, Char_t dir)
+{
+  if (!Ntor_) return false;
+  
+  Double_t vloc[3];
+  
+       if (dir == 'x' || dir == 'X') { vloc[0] = 1.; vloc[1] = 0.; vloc[2] = 0.; }
+  else if (dir == 'y' || dir == 'Y') { vloc[0] = 0.; vloc[1] = 1.; vloc[2] = 0.; }
+  else if (dir == 'z' || dir == 'Z') { vloc[0] = 0.; vloc[1] = 0.; vloc[2] = 1.; }
+  else return kFALSE;
+  
+  Ntor_->LocalToMasterVect(vloc,v);
+  
+  if (TMath::Abs(v[0]) < 1e-15) v[0] = 0.;
+  if (TMath::Abs(v[1]) < 1e-15) v[1] = 0.;
+  if (TMath::Abs(v[2]) < 1e-15) v[2] = 0.;
+  
+  return true;
+}
+
+//________________________________________________________________________________
+Bool_t RegisterRunData(TString inFile)
+{
+  TFile* f = new TFile(inFile);
+  if (!f) return kFALSE;
+  
+  TTree* t = (TTree*)f->Get("cbmsim");  
+  if (!t) return kFALSE;
+
+  TBranch* branch;
+  
+  branch = t->GetBranch("MCEventHeader.");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("MCEventHeader.",&Header_) ;
+  
+  branch = t->GetBranch("SpdMCTrack");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdMCTrack",&MCTracks_);       
+  
+  branch = t->GetBranch("SpdRsTB2Point");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdRsTB2Point",&RsTBPoints_) ;
+ 
+  cout << "\n>>>>>>>>>>>>>>>> FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;
+  
+  Tree_ = t;
+  
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Bool_t LoadGeometryAndPars(TString inParFile)
+{
+  TFile* fp = new TFile(inParFile);
+  if (!fp) return kFALSE;
+      
+  /* PRIMARY GENERATOR PARAMETERS */
+  
+  GenPars_ = (SpdPrimGenParSet*)fp->Get("PrimGenParSet");
+  if (!GenPars_) {
+      cout << "No PrimGen parameters " << endl;
+      return kFALSE;
+  }
+      
+  //GenPars_->print(1);
+
+  /* RANGE SYSTEM BARREL (RsTB) PARAMETERS */
+  
+  RsTBPars_ = (SpdParSet*)fp->Get("RsTBParSet");
+  if (!RsTBPars_) {
+      cout << "No RsTB parameters " << endl;
+      return kFALSE;
+  }
+  
+  //RsTBPars_->print(1);
+  
+  /* +++++++++++++++ LOAD GEOMETRY  +++++++++++++++ */
+
+  FairGeoParSet* geoset = (FairGeoParSet*)fp->Get("FairGeoParSet");
+  
+  Ntor_ = gGeoManager->GetCurrentNavigator();
+  
+  /* DRAW GEOMETRY */
+  //gGeoManager->SetVisLevel(2);
+  //gGeoManager->GetMasterVolume()->Draw("ogl");
+   
+  return kTRUE;
+}
+
+
+
+
diff --git a/macro/analysis/rst/CheckRsTEC2Data.C b/macro/analysis/rst/CheckRsTEC2Data.C
new file mode 100644
index 0000000000000000000000000000000000000000..dda5c71c2cf29fa2cbf51fc14ee72f610bdbafc0
--- /dev/null
+++ b/macro/analysis/rst/CheckRsTEC2Data.C
@@ -0,0 +1,286 @@
+// #define _COMPILE_MACRO_
+// 
+// #if defined(_COMPILE_MACRO_) 
+
+#include <TStopwatch.h>
+#include <TTree.h>
+#include <TClonesArray.h>
+#include <TGeoManager.h>
+#include <TGeoNavigator.h>
+
+#include "FairGeoParSet.h"
+#include "FairBaseParSet.h"
+#include "SpdPrimGenParSet.h"
+
+#include "SpdCommonGeoMapper.h"
+#include "SpdCave.h"
+#include "SpdDetector.h"
+
+#include "SpdMCEventHeader.h"
+#include "SpdMCTrack.h"
+
+#include "SpdRsTEC2.h"
+#include "SpdRsTEC2Point.h"
+
+//#endif
+
+TTree* Tree_ = 0;
+
+SpdParSet*         RsTECPars_;
+SpdPrimGenParSet*  GenPars_;
+
+TGeoNavigator* Ntor_ = 0; 
+
+SpdMCEventHeader*  Header_    = 0;
+TClonesArray*      MCTracks_  = 0;
+TClonesArray*      RsTECPoints_ = 0;
+
+Int_t  GeoLevel_ = 0;
+
+Bool_t  LoadGeometryAndPars(TString inParFile);
+Bool_t  RegisterRunData(TString inFile);
+
+void    AnalyseEvent(Int_t nevent);
+Bool_t  AnalysePoint(SpdRsTEC2Point* point);
+
+Bool_t  DetectorPosition(Double_t* p);
+Bool_t  DetectorOrientation(Double_t* v, Char_t dir);
+
+TTree* t = 0;
+
+TString inFile, inParFile;
+
+//________________________________________________________________________________
+void CheckRsTEC2Data() {
+  //  
+  TString inParFile  = "params_tor.root";
+  TString inDataFile = "run_tor.root";   
+  
+  if (!LoadGeometryAndPars(inParFile)) {
+      cout << "Bad geometry or parameters " << endl;
+      return;
+  }
+
+  if (!RegisterRunData(inDataFile)) {
+      cout << "Bad data in the file " << endl;
+      return;
+  }
+  
+  Int_t entries = Tree_->GetEntries();
+  
+  cout << "Entries(tree): " << entries << endl;
+  
+  if (entries == 0) return;
+   
+  //return;
+  
+  cout << "\n>>>>>>>>>>>>>>>> DATA : Ok! <<<<<<<<<<<<<<<<< " << endl;
+   
+  //entries = 1; // FIXME
+  
+  for (Int_t i(0); i < entries; i++) {
+       Tree_->GetEntry(i);
+       AnalyseEvent(i);
+  }
+  
+}
+
+//________________________________________________________________________________
+void AnalyseEvent(Int_t nevent)
+{
+    
+//   Header_->Print(1);
+   
+   //-------------------------- MC-TRACKS ---------------------------------
+   Int_t ntracks = MCTracks_->GetEntriesFast();
+       
+//    cout << "\n<Analyse> mctracks = " << ntracks << endl;
+// 
+//    SpdMCTrack* track;
+//    for (int i(0); i < ntracks; i++) {
+//         track = (SpdMCTrack*)MCTracks_->At(i);              
+//         //if (i < 30) track->Print(i);   
+//         if (track->GetMotherId() < 0) track->Print(i);
+//    }
+   
+   //--------------------------- RsTEC POINTS -------------------------------
+  
+   Int_t npoints = RsTECPoints_->GetEntriesFast();
+  
+   cout << "\n<Analyse> rstec-points = " << npoints << " event: " << nevent << endl;
+   
+   SpdRsTEC2Point* point;
+   
+   for (Int_t i(0); i < npoints; i++) {
+        
+        point = (SpdRsTEC2Point*)RsTECPoints_->At(i); 
+        
+        AnalysePoint(point);
+
+   }
+}
+
+//________________________________________________________________________________
+Bool_t AnalysePoint(SpdRsTEC2Point* point)
+{
+   if (!point) return false;
+   
+   cout << ">>>>>>>>>>>>>>>>> ANALYSE POINT >>>>>>>>>>>>>>>>>>>>>" << "\n\n";
+   
+   point->Print("");   
+    
+   TString node_path = point->GetHitGeoPath();
+   
+   if (!Ntor_->cd(node_path)) {
+       cout << "No such node: " << node_path << endl;
+       return false;  
+   }
+   else cout << "Current node path: " << Ntor_->GetPath() << "\n\n";
+   
+   Double_t detpos[3];           // hit node position in global CS
+   Double_t ax[3], ay[3], az[3]; // hit node axis (global CS)
+   
+   SpdGeopathParser ppath;
+   ppath.ParsePath(node_path);
+   
+   cout << "RS module number: " << ppath.Num(2) << "\n\n";
+   
+   // print node geometry levels:
+   for (Int_t i(1); i<= ppath.GetCurrentPathLevel(); i++) {
+        cout << i << " " <<  ppath.Num(i) << " "<< ppath.Name(i) << "    :: " << ppath.Path(i) << endl; 
+   }
+   cout << "\n";
+
+   // Hit detector
+   DetectorPosition(detpos);
+   DetectorOrientation(ax,'x');
+   DetectorOrientation(ay,'y');
+   DetectorOrientation(az,'z'); 
+   
+   cout << "HIT NODE: " << Ntor_->GetPath() << "\n\n";
+   cout << "\t position:   " << detpos[0] << " " << detpos[1] << " " << detpos[2] << " " << endl;
+   cout << "\t   x-axis:   " << ax[0] << " " << ax[1] << " " << ax[2] << " " << endl;
+   cout << "\t   y-axis:   " << ay[0] << " " << ay[1] << " " << ay[2] << " " << endl;
+   cout << "\t   z-axis:   " << az[0] << " " << az[1] << " " << az[2] << " " << endl;
+   cout << "\n";
+   
+   // Module
+   Ntor_->cd(ppath.Path(2));
+   
+   DetectorPosition(detpos);
+   DetectorOrientation(ax,'x');
+   DetectorOrientation(ay,'y');
+   DetectorOrientation(az,'z'); 
+   
+   cout << "HIT MODULE: " << Ntor_->GetPath() << "\n\n";
+   cout << "\t position:   " << detpos[0] << " " << detpos[1] << " " << detpos[2] << " " << endl; // always (0,0,0) caused by using TGeoArb8! 
+   cout << "\t   x-axis:   " << ax[0] << " " << ax[1] << " " << ax[2] << " " << endl;
+   cout << "\t   y-axis:   " << ay[0] << " " << ay[1] << " " << ay[2] << " " << endl;
+   cout << "\t   z-axis:   " << az[0] << " " << az[1] << " " << az[2] << " " << endl;
+   cout << "\n";
+   
+   return true;  
+}
+
+//_____________________________________________________________________________
+Bool_t DetectorPosition(Double_t* p)
+{
+  if (!Ntor_) return false;
+  Double_t ploc[3] = {0, 0, 0};
+  Ntor_->LocalToMaster(ploc,p);
+  return true;
+}
+
+//_____________________________________________________________________________ 
+Bool_t DetectorOrientation(Double_t* v, Char_t dir)
+{
+  if (!Ntor_) return false;
+  
+  Double_t vloc[3];
+  
+       if (dir == 'x' || dir == 'X') { vloc[0] = 1.; vloc[1] = 0.; vloc[2] = 0.; }
+  else if (dir == 'y' || dir == 'Y') { vloc[0] = 0.; vloc[1] = 1.; vloc[2] = 0.; }
+  else if (dir == 'z' || dir == 'Z') { vloc[0] = 0.; vloc[1] = 0.; vloc[2] = 1.; }
+  else return kFALSE;
+  
+  Ntor_->LocalToMasterVect(vloc,v);
+  
+  if (TMath::Abs(v[0]) < 1e-15) v[0] = 0.;
+  if (TMath::Abs(v[1]) < 1e-15) v[1] = 0.;
+  if (TMath::Abs(v[2]) < 1e-15) v[2] = 0.;
+  
+  return true;
+}
+
+//________________________________________________________________________________
+Bool_t RegisterRunData(TString inFile)
+{
+  TFile* f = new TFile(inFile);
+  if (!f) return kFALSE;
+  
+  TTree* t = (TTree*)f->Get("cbmsim");  
+  if (!t) return kFALSE;
+
+  TBranch* branch;
+  
+  branch = t->GetBranch("MCEventHeader.");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("MCEventHeader.",&Header_) ;
+  
+  branch = t->GetBranch("SpdMCTrack");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdMCTrack",&MCTracks_);       
+  
+  branch = t->GetBranch("SpdRsTEC2Point");
+  if (!branch) return kFALSE;
+  t->SetBranchAddress("SpdRsTEC2Point",&RsTECPoints_) ;
+ 
+  cout << "\n>>>>>>>>>>>>>>>> FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;
+  
+  Tree_ = t;
+  
+  return kTRUE;
+}
+
+//________________________________________________________________________________
+Bool_t LoadGeometryAndPars(TString inParFile)
+{
+  TFile* fp = new TFile(inParFile);
+  if (!fp) return kFALSE;
+      
+  /* PRIMARY GENERATOR PARAMETERS */
+  
+  GenPars_ = (SpdPrimGenParSet*)fp->Get("PrimGenParSet");
+  if (!GenPars_) {
+      cout << "No PrimGen parameters " << endl;
+      return kFALSE;
+  }
+      
+  //GenPars_->print(1);
+
+  /* RANGE SYSTEM BARREL (RsTEC) PARAMETERS */
+  
+  RsTECPars_ = (SpdParSet*)fp->Get("RsTECParSet");
+  if (!RsTECPars_) {
+      cout << "No RsTEC parameters " << endl;
+      return kFALSE;
+  }
+  
+  //RsTECPars_->print(1);
+  
+  /* +++++++++++++++ LOAD GEOMETRY  +++++++++++++++ */
+
+  FairGeoParSet* geoset = (FairGeoParSet*)fp->Get("FairGeoParSet");
+  
+  Ntor_ = gGeoManager->GetCurrentNavigator();
+  
+  /* DRAW GEOMETRY */
+  //gGeoManager->SetVisLevel(2);
+  //gGeoManager->GetMasterVolume()->Draw("ogl");
+   
+  return kTRUE;
+}
+
+
+
+
diff --git a/macro/field/CheckAxialFieldMapData.C b/macro/field/CheckAxialFieldMapData.C
new file mode 100644
index 0000000000000000000000000000000000000000..5dd1225fadcd23c84d6a596d14c79900912f8399
--- /dev/null
+++ b/macro/field/CheckAxialFieldMapData.C
@@ -0,0 +1,93 @@
+
+
+void CheckAxialFieldMapData() 
+{
+
+    Int_t n;
+    Double_t bx, by, bz, br, bb;
+    
+    Int_t N = 10;
+    const Int_t rnum = 4534343;
+  
+    // default path to a field maps
+    TString path = getenv("VMCWORKDIR");
+    path += "/input/";
+    
+    cout << path << endl;
+    
+    SpdAxialFieldMapData* mdata = new SpdAxialFieldMapData();
+
+//---------------------------------------------- INIT 1
+    mdata->InitData("map_qsolRZ_6cls2cm.bin",path);
+    
+    mdata->PrintData();
+         
+    //return;
+    gRandom->SetSeed(rnum);
+    
+    N = mdata->GetNTotal();
+
+    for (Int_t i(1); i<=N; i++) {
+      
+         //n = gRandom->Integer(mdata->GetNTotal()); 
+         n = i-1;
+        
+         //cout << i << "/" << N << ": " << mdata->GetBr(n) << " " << mdata->GetBz(n) << endl;
+                     
+         br = mdata->GetBr(n);
+         bz = mdata->GetBz(n);
+         bb = TMath::Sqrt(br*br + bz*bz);
+         
+         printf("%4d: Br = %9.2e; Bz = %9.2e; |B| = %9.2e; \n",i,br,bz,bb);   
+         
+         if (i%124 == 0) cout << endl;
+         if (i == 124) break;          
+    }
+    
+//---------------------------------------------- 
+    
+//    mdata->WriteAsciiFile("map_qsolRZ_6cls2cm_1.dat"); 
+//   mdata->WriteBinaryFile("map_qsolRZ_6cls2cm_1.bin"); 
+
+    //return;
+    
+  //----------------------------------------------  INIT 2  
+   
+//     mdata->InitData("map_qsolRZ_6cls2cm_1.dat","../macro");  
+// 
+//     mdata->PrintData();
+//     
+//     gRandom->SetSeed(rnum);
+//     
+//     for (Int_t i(0); i<N; i++) {
+//       
+//          //n = gRandom->Integer(mdata->GetNTotal()); 
+//          n = i;
+//          
+//          cout << i+1 << " " << mdata->GetBr(n) 
+//                    << " " << mdata->GetBz(n) 
+//                    << endl;
+//          if (i == 20) break;                    
+//     }
+    
+  //----------------------------------------------  INIT 3 
+ 
+//     mdata->InitData("map_qsolRZ_6cls2cm_1.bin","../macro");
+//     
+//     mdata->PrintData();
+//     
+//     gRandom->SetSeed(rnum);
+//     
+//     for (Int_t i(0); i<N; i++) {
+//       
+//          //n = gRandom->Integer(mdata->GetNTotal()); 
+//          n = i;
+//          
+//          cout << i+1 << " " << mdata->GetBr(n) 
+//                    << " " << mdata->GetBz(n) 
+//                    << endl;
+//          if (i == 20) break;                             
+//     }   
+
+}
+
diff --git a/macro/field/CheckField.C b/macro/field/CheckField.C
index de745e81af1fce9707e224468a99ba79a642c279..ef37c53bca104aa03e6d66b9b669fd4d05014e0e 100644
--- a/macro/field/CheckField.C
+++ b/macro/field/CheckField.C
@@ -1,5 +1,19 @@
 
+
+// #include "SpdFieldMap.h"
+// #include "SpdAxialFieldMap.h"
+// #include "SpdMultiField.h"
+// #include "SpdConstField.h"
+// #include "SpdRadialField.h"
+// #include "SpdFieldCreator.h"
+// #include "SpdFieldPar.h"
+// #include <TFile.h>
+// #include <TRandom.h>
+// 
+//  
 void check0();
+void check0axial();
+
 void check1();  // set_of_fields ->  set_of_fields
 void check2();  // set_of_fields ->  multi_field
 void check3();  // multi_field ->  multi_field
@@ -10,7 +24,8 @@ void readparams(TString filename = "params_tor.root");
 
 void CheckField() 
 {
-   check0();  
+   //check0(); 
+   check0axial(); 
   
    //check1();  
    //check2();  
@@ -25,13 +40,16 @@ void CheckField()
 void check0()
 {
     SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
-    MagField->InitData("map_hyb_1T5cm.bin");
+    //MagField->InitData("map_hyb_2T5cm.bin");
+    MagField->InitData("map_sol_6cls5cm2.bin");
+    
     MagField->PrintData();
-  
+    //MagField->Print();
+    
     Double_t x, y, z;
     Double_t bx, by, bz;
     
-    const Int_t N = 10;
+    const Int_t N = 20;
     
     gRandom->SetSeed(1234);
     
@@ -41,15 +59,104 @@ void check0()
          y = gRandom->Uniform(MagField->GetYmin(),MagField->GetYmax()); 
          z = gRandom->Uniform(MagField->GetZmin(),MagField->GetZmax()); 
          
+         x = 0; y = 0;
+         
+         MagField->GetBx(bx,x,y,z);
+         MagField->GetBy(by,x,y,z);
+         MagField->GetBz(bz,x,y,z);
+              
+         printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; ",
+                x,y,z,bx,by,bz,TMath::Sqrt(bx*bx+by*by));   
+         
+         z = -z;     
+              
+         MagField->GetBx(bx,x,y,z);
+         MagField->GetBy(by,x,y,z);
+         MagField->GetBz(bz,x,y,z);
+         
+         cout << " z->-z: ";
+     
+         printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; ",
+                x,y,z,bx,by,bz,TMath::Sqrt(bx*bx+by*by));   
+           
+         cout << endl;
+                  
+     }
+}
+
+//_______________________________________________________________________
+void check0axial()
+{
+    SpdAxialFieldMap* MagField = new SpdAxialFieldMap("QSolenoidal field");
+    MagField->InitData("map_qsolRZ_6cls2cm.bin");
+
+    MagField->PrintData();
+    //MagField->Print();
+    
+    Double_t x, y, z, r, phi;
+    Double_t bx, by, bz;
+    
+    const Int_t N = 20;
+    
+    gRandom->SetSeed(0);
+    
+    Double_t point[3], Field[3];
+    
+    for (Int_t i(0); i<N; i++) {
+      
+         r = gRandom->Uniform(MagField->GetRmin(),MagField->GetRmax()); 
+         z = gRandom->Uniform(MagField->GetZmin(),MagField->GetZmax()); 
+         
+         phi = gRandom->Uniform(0,TMath::TwoPi());
+         x = r*TMath::Sin(phi);
+         y = r*TMath::Cos(phi);
+             
+         //x = 0; y = 0;
+         
+//          point[0] = x;
+//          point[1] = y;
+//          point[2] = z;
+//          
+//          MagField->GetField(point,Field);
+//          
+//          printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; ",
+//                point[0],point[1],point[2],Field[0],Field[1],Field[2],TMath::Sqrt(Field[0]*Field[0]+Field[1]*Field[1]));   
+// 
+//          point[2] = -point[2];     
+//         
+//          MagField->GetField(point,Field);
+//          
+//          cout << " z->-z: ";
+//          
+//          printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; \n",
+//                point[0],point[1],point[2],Field[0],Field[1],Field[2],TMath::Sqrt(Field[0]*Field[0]+Field[1]*Field[1]));   
+         
+         
+         MagField->GetBx(bx,x,y,z);
+         MagField->GetBy(by,x,y,z);
+         MagField->GetBz(bz,x,y,z);
+                       
+         printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; ",
+               x,y,z,bx,by,bz,TMath::Sqrt(bx*bx+by*by));   
+        
+         z = -z;     
+              
          MagField->GetBx(bx,x,y,z);
          MagField->GetBy(by,x,y,z);
          MagField->GetBz(bz,x,y,z);
          
-         cout << " ( " << x  << ", " << y  << ", " << z  << ")  B = " 
-              << " ( " << bx << ", " << by << ", " << bz << ") " 
-              << endl;
+         cout << " z->-z: ";
+     
+         printf("(%8.3f, %8.3f, %8.3f); B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; ",
+                x,y,z,bx,by,bz,TMath::Sqrt(bx*bx+by*by));   
+           
+         cout << endl;
                   
-    }
+     }
+     
+//     cout  << " X[min,max]: " << MagField->GetXmin() << " " << MagField->GetXmax() << " Nx = " << MagField->GetNx() << endl;
+//     cout  << " Y[min,max]: " << MagField->GetYmin() << " " << MagField->GetYmax() << " Ny = " << MagField->GetNy() << endl;
+//     cout  << " Z[min,max]: " << MagField->GetZmin() << " " << MagField->GetZmax() << " Nz = " << MagField->GetNz() << endl;
 }
 
 //________________________________________________________________________
diff --git a/macro/field/CheckFieldMapData.C b/macro/field/CheckFieldMapData.C
index 7c04f35a2b59b6e1e7b83dd2d53c220ebdfee54d..18c1344d634c4ef1279d12667fabaa75d166887f 100644
--- a/macro/field/CheckFieldMapData.C
+++ b/macro/field/CheckFieldMapData.C
@@ -19,26 +19,45 @@ void check_0()
     Int_t N = 10;
     const Int_t rnum = 4534343;
   
+    // default path to a field maps
+    TString path = getenv("VMCWORKDIR");
+    path += "/input/";
+    
+    cout << path << endl;
+    
     SpdFieldMapData* mdata = new SpdFieldMapData();
 
 //---------------------------------------------- INIT 1
-    //mdata->InitData("map_sol_6cls5cm2.bin");  
-    mdata->InitData("map_hyb_1T5cm.bin");  
+    //mdata->InitData("map_sol_6cls5cm2.bin",path);
+    
+    mdata->InitData("map_hyb_1T5cm.bin",path);  
  
     mdata->PrintData();
          
+    //return;
+    
     gRandom->SetSeed(rnum);
     
     N = mdata->GetNTotal();
+    
     for (Int_t i(0); i<N; i++) {
       
          //n = gRandom->Integer(mdata->GetNTotal()); 
          n = i;
-         
-         cout << i << " " << mdata->GetBx(n) 
-                   << " " << mdata->GetBy(n) 
-                   << " " << mdata->GetBz(n)           
-                   << endl;
+
+//          cout << i+1 << "/" << N << ": " << mdata->GetBx(n) 
+//                      << " " << mdata->GetBy(n) 
+//                      << " " << mdata->GetBz(n)           
+//                      << endl;
+                     
+         bx = mdata->GetBx(n);
+         by = mdata->GetBy(n);
+         bz = mdata->GetBz(n);
+                     
+         printf("%4d:  B = (%9.2e, %9.2e, %9.2e); Br = %9.2e; \n",
+                i+1,bx,by,bz,TMath::Sqrt(bx*bx+by*by));   
+        
+         if (i == 20) break;          
     }
 //---------------------------------------------- 
     
diff --git a/macro/field/DrawFieldMap.C b/macro/field/DrawFieldMap.C
index 5893a8db73dced91514836689a81ad9e7cc21413..736bb2d5e41308100a11509c95363de9182acbd9 100644
--- a/macro/field/DrawFieldMap.C
+++ b/macro/field/DrawFieldMap.C
@@ -35,8 +35,17 @@ TH2D* MakeRPlane(Double_t R, TString fvtype, Int_t in = 1, Double_t zcut = 1000.
 TH2D* MakePhiAveraged(Double_t Rmax, TString fvtype, Int_t in = 1, Double_t zcut = 1000., TH1D* hh = 0);
 TH2D* MakeZAveraged(Double_t Zmax, TString fvtype, Int_t in = 1, Double_t rcut = 1000., TH1D* hh = 0);
 
+
+#define AXIAL_FIELD // !!!FIXME!!! FIXME!!! FIXME!!!
+
+
 TString      FieldMap_;
-SpdFieldMap* MagField_;
+
+#ifndef AXIAL_FIELD
+SpdFieldMap* MagField_ = 0;
+#else
+SpdAxialFieldMap* MagField_ = 0;
+#endif
 
 TString GetFtype(TString fvtype);
 
@@ -63,12 +72,15 @@ void SetStyle()
 //__________________________________________________________________________
 void DrawFieldMap() 
 {  
-    FieldMap_ = "map_hyb_1T2cm.bin";     // hybrid HQ, B = 1 T,  grid = 2 cm
+    
+#ifndef AXIAL_FIELD  
+    
+    //FieldMap_ = "map_tor_rot.bin";       // toroid (rotated), grid = 5 cm
+    //FieldMap_ = "map_hyb_1T2cm.bin";     // hybrid HQ, B = 1 T,  grid = 2 cm
     //FieldMap_ = "map_hyb_1T5cm.bin";     // hybrid LQ, B = 1 T,  grid = 5 cm 
     //FieldMap_ = "map_hyb_2T5cm.bin";     // hybrid LQ, B = 2 T,  grid = 5 cm
-    //FieldMap_ = "map_sol_6cls5cm.bin";   // solenoid [3+3-],  grid = 5 cm
-    //FieldMap_ = "map_sol_6cls5cm2.bin";  // solenoid [6+],    grid = 5 cm
-    //FieldMap_ = "map_tor_rot.bin";       // toroid (rotated), grid = 5 cm
+    //FieldMap_ = "map_sol_6cls5cm.bin";   // qsolenoid [3+3-],  grid = 5 cm
+    FieldMap_ = "map_sol_6cls5cm2.bin";  // qsolenoid [6+],    grid = 5 cm
       
     MagField_ = new SpdFieldMap("Hybrid field");
     MagField_->InitData(FieldMap_);
@@ -85,9 +97,29 @@ void DrawFieldMap()
     cout << "\t Bx (min,max) = " << Bstat[8] << " " << Bstat[9] << " [kG] " << endl;
     
     cout << endl;
+
+#else    
     
-    SetStyle();
+    FieldMap_ = "map_qsolRZ_6cls2cm.bin"; // qsolenoid [6+],    grid = 2 cm
+    
+    MagField_ = new SpdAxialFieldMap("QSolenoidal field");
+    MagField_->InitData(FieldMap_);  
+    MagField_->PrintData();
+     
+    Double_t Bstat[8];
+    MagField_->GetMinMaxStat(Bstat);
+    
+    cout << "\t Field map statistics (nodes): " << "\n\n"; 
+    cout << "\t B  (min,max) = " << Bstat[0] << " " << Bstat[1] << " [kG] " << endl;
+    cout << "\t Bz (min,max) = " << Bstat[2] << " " << Bstat[3] << " [kG] " << endl;
+    cout << "\t Br (min,max) = " << Bstat[4] << " " << Bstat[5] << " [kG] " << endl;
     
+    cout << endl;
+ 
+#endif
+    
+    SetStyle();
+        
     DrawHistos();
     
     //CheckPhiSym();
diff --git a/macro/fullchain/FitIdealTracks.C b/macro/fullchain/FitIdealTracks.C
index c1905947a4836d32268d66434d0cb5fae31dc043..402cf57946365e4b192468ff2074b3177bef6300 100644
--- a/macro/fullchain/FitIdealTracks.C
+++ b/macro/fullchain/FitIdealTracks.C
@@ -39,9 +39,10 @@ void FitIdealTracks()
   // standard options: 
   KalmanFitter->SetSeedMomentum(1.);           // Start vertex momentum for fit, GeV/c (default = 1 GeV/c) 
   
-  KalmanFitter->SetResolution(0.005);          // Vertex detector (Its) resolution, cm (default = 0.005 cm)   
-  KalmanFitter->SetWireResolution(0.015);      // Wire tracker (TsTB, TsTEC) resolution , cm (default = 0.015 cm) 
-
+  KalmanFitter->SetHitRepresentation(kSpdIts,pkPixel);   // options: pkPixel, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTB,pkWire);   // options: pkWire, pkWirePoint, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTEC,pkWire);  // options: pkWire, pkWirePoint, pkSpacepoint
+  
   // advanced options:
   KalmanFitter->SetVertexFindingMethod(1);     // <1 (vertex will not be found), (default = 1)   
   KalmanFitter->SetVertexFindingAngleCut(3.0); // skip tracks with theta 90+-cut degree (default = 3[deg])
diff --git a/macro/fullchain/MakeIdealTracks.C b/macro/fullchain/MakeIdealTracks.C
index cd3147b3050124a0c252870c0a15b33af9e877b8..a3aadfb19eddfb0d745b9b7fffbb7be63b1b15a5 100644
--- a/macro/fullchain/MakeIdealTracks.C
+++ b/macro/fullchain/MakeIdealTracks.C
@@ -41,6 +41,25 @@ void MakeIdealTracks()
   TrackFinder->SetMinVertexNHits(1);  // its hits number cut; default = 1; absiolute min. value = 0;  
   TrackFinder->SetMinTrackerNHits(2); // tstb+tstec hits number cut; default = 2; absiolute min. value = 2;  
   
+  // set hits resolution
+  Double_t mkm = 1e-4;
+ 
+  // ------ INNER TRACKER -----
+ 
+  TrackFinder->SetHitResolution(kSpdIts,  'p',  50*mkm,  50*mkm); // ENDCAP: POINT  (u=x,v=y)
+  TrackFinder->SetHitResolution(kSpdIts,  'm',  50*mkm,  50*mkm); // BARREL: MAPS   (u,v)
+  TrackFinder->SetHitResolution(kSpdIts,  's',  50*mkm,  50*mkm); // BARREL: DSSD   (u,v)
+  
+  // ----- STRAW TRACKER -----
+  
+  // --- barrel ---
+  TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm);                  // Wire(1D)    (r,z)
+  //TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+ 
+  //--- endcaps ---
+  TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm);                  // Wire(1D)    (r,z)
+  //TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+  
   //------------------------------------//
   Run->AddTask(TrackFinder);
   
diff --git a/macro/geom/CheckGeoLoader.C b/macro/geom/CheckGeoLoader.C
index 2646a1915236099e25190231de768d4fac53a336..4a47771c1af1b0406a11ccd69b5f40cd9d6ce68a 100644
--- a/macro/geom/CheckGeoLoader.C
+++ b/macro/geom/CheckGeoLoader.C
@@ -4,33 +4,48 @@ void CheckGeoLoader()
 {
    SpdGeoLoader* loader = new SpdGeoLoader();
    
-   loader->LoadGeometry("params_tor.root");
-   //loader->LoadGeometry("params_sol.root");
-   //loader->LoadGeometry("");
+   /* ---- special loader settings ---- */
    
-   //loader->LoadGeometry();
+   //SpdGeoLoader::ForceTopGeoFile("cave_precise.geo"); // force CAVE geometry (material = vacuum)
+   //SpdGeoLoader::ForceTopGeoFile("cave.geo");         // force CAVE geometry (material = air)
    
-   //loader->LoadModule("All");
-   //loader->LoadModule("Actives");
+   //SpdGeoLoader::ForceMediaFile(TString(getenv("VMCWORKDIR"))+"/geometry/media1.geo");    
    
-   //loader->LoadModule("Pipe");
+   //SpdGeoLoader::ResetMediaFromParams(false); // actives: false = use basic module's materials, true (default) = use actual parameters 
+   //SpdGeoLoader::ResetPassivesMedia(true);    // passives: false (default) = use actual simu materials, true = use deafult materials
    
-   loader->LoadModule("Passives");
+   //SpdGeoLoader::UnsetMaterials(true);        // true = set ALL module's materials as vacuum, false (default) = geometry materials 
+   
+   /* ---- LoadGeometry: load list of modules and construct TOP (cave) volume ---- */
+   
+   loader->LoadGeometry("params_tor.root");  // load all modules using its parameters, construct TOP volume
+   //loader->LoadGeometry();                   // load all modules, construct TOP volume 
+
+   /* ---- LoadModule: construct modules; parameters = [module id, unset materials (default = false)] ---- */
+   
+   // loader->LoadModule("All",false);
+   // loader->LoadModule("Actives",false);
+   
+   loader->LoadModule("Passives",false);
   
-   loader->LoadModule("Inner tracker system"); // id = 12
-   loader->LoadModule("TS barrel (tor)");      // id = 2
-   loader->LoadModule("TS endcaps (tor)");     // id = 3
+   // loader->LoadModule("Pipe",false);
+   
+//    loader->LoadModule("Inner tracker system",false); // id = 12
+//    loader->LoadModule("TS barrel (tor)",false);      // id = 2
+//    loader->LoadModule("TS endcaps (tor)",false);     // id = 3
     
-   //loader->LoadModule(2);
-   //loader->LoadModule(3);
-   //loader->LoadModule(12);
+   loader->LoadModule(2,false); 
+   loader->LoadModule(3,false); 
+   loader->LoadModule(12,false); 
    
+   /* ---- darwing and dumping ---- */
+    
    loader->DrawGeometry();
    
    //loader->PrintGeometry();
    loader->PrintActualGeometry();
    
-   //return;
+   return;
    
    Int_t DetId = 12; 
    
@@ -38,12 +53,14 @@ void CheckGeoLoader()
    SpdGeoMapper* mapper = 0;
    SpdGeoBuilder* builder = 0;
    
-   pars = loader->GetParameters(DetId);
+   pars    = loader->GetActiveParameters(DetId);
    mapper  = loader->GetMapper(DetId);
    builder = loader->GetBuilder(DetId);
-   
+      
    if (pars) pars->print(1);
-   if (mapper) cout << "MAPPER: " << mapper->GetName() << endl;
+   if (mapper)  cout << "MAPPER:  " << mapper->GetName() << endl;
    if (builder) cout << "BUILDER: " << builder->GetName() << endl;
    
+   delete loader;
+   
 }
diff --git a/macro/geom/ConstructEcalTB2.C b/macro/geom/ConstructEcalTB2.C
new file mode 100644
index 0000000000000000000000000000000000000000..17c85e64a038c26e3c5e37778c3600d7dcd77876
--- /dev/null
+++ b/macro/geom/ConstructEcalTB2.C
@@ -0,0 +1,139 @@
+
+void DefaultGeometryTight();
+void DefaultGeometryTightBasket();
+void DefaultGeometryForceCellSize();
+
+void CustomizeGeometry();
+
+//______________________________________________________________
+void ConstructEcalTB2() 
+{
+   // 
+   SpdCommonGeoMapper::Instance()->OpenGeometry();
+  
+   FairModule* Cave = new SpdCave();
+   Cave->SetGeometryFileName("cave.geo");
+   Cave->ConstructGeometry();
+   
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+ 
+    //SpdPipe* Pipe = new SpdPipe();
+    //Pipe->ConstructGeometry();
+    //Pipe->Print("");
+   
+    //SpdEcalTEC2* ecaltec = new SpdEcalTEC2();
+    //ecaltec->ConstructGeometry();
+    //ecaltec->Print("");
+   
+   SpdEcalTB2* ecaltb = new SpdEcalTB2();
+  
+   CustomizeGeometry();
+
+   ecaltb->ConstructGeometry(); 
+  
+   /* ~~~~~~~~~~~~~ DRAW GEOMETRY  ~~~~~~~~~~~~~~~~~ */
+   
+   TGeoManager *geoMan = gGeoManager;
+   geoMan->SetVisLevel(3);
+  
+   //geoMan->GetMasterVolume()->SetVisContainers();
+   geoMan->GetMasterVolume()->Draw("ogl");
+  
+   //ecaltb->GetBasket()->Draw("ogl");
+   
+   TGeoVolume* module; 
+   module = ecaltb->GetModule(0);
+   
+   //if (module) module->SetVisContainers();
+   //if (module) module->Draw("ogl");
+   
+   ecaltb->Print("");
+}
+
+//______________________________________________________________
+void CustomizeGeometry()
+{
+   // 1. recommended default: fixed cell length, automatically calculated cell width
+    
+   //DefaultGeometryTight();      
+   
+   // 2. trimming cell length (cell length automatically calculated to fit into basket), 
+   //    automatically calculated cell width
+    
+   //DefaultGeometryTightBasket(); 
+   
+   // 3. force cell size
+    
+   //DefaultGeometryForceCellSize(); 
+}
+
+//______________________________________________________________
+void DefaultGeometryTight() 
+{
+   //
+   // Fill baskets(barrel) with modules tightly (automatically selecting cell transverse size)
+   // Module length and number of layers are constant
+   // 
+   SpdEcalTB2GeoMapper* mapper = SpdEcalTB2GeoMapper::Instance();
+   
+   //rough guideline: size will be chosen as close as possible to these values
+   mapper->SetCellZSize(5.5);        // [cm] z-size of cell
+   mapper->SetCellInnerPhiSize(5.5); // [cm] П†-size of the cell face closer to beam axis
+   mapper->SetNLayers(200);
+   mapper->SetAbsorberLayerThickness(0.05);
+   mapper->SetScintLayerThickness(0.15);
+   
+   //additional
+   mapper->SetModuleClearance(0.1); // [cm] clerance between modules (default: 0.1)
+   mapper->SetCellClearance(0.05);  // [cm] clerance between cells in a module (default: 0.05)
+}
+
+//______________________________________________________________
+void DefaultGeometryTightBasket() 
+{
+   //
+   // Fill baskets(barrel) with modules tightly (automatically selecting cell transverse size)
+   // Trim cell length to be inside basket and select number of layers accordingly    
+   //
+    
+   SpdEcalTB2GeoMapper* mapper = SpdEcalTB2GeoMapper::Instance();
+   mapper->SetForceInsideBasket(true);
+   mapper->SetCellZSize(5.5);         // [cm] z-size of cell
+   mapper->SetCellInnerPhiSize(5.5);  // [cm] П†-size of the cell face closer to beam axis
+   mapper->SetAbsorberLayerThickness(0.05);
+   mapper->SetScintLayerThickness(0.15);
+   
+   //additional
+   mapper->SetModuleClearance(0.1); // [cm] clerance between modules (default: 0.1)
+   mapper->SetCellClearance(0.05);  // [cm] clerance between cells in a module (default: 0.05)
+}
+
+//______________________________________________________________
+void DefaultGeometryForceCellSize() 
+{
+   //  
+   // Fill baskets(barrel) with modules, using the given cell size
+   // 
+   SpdEcalTB2GeoMapper* mapper = SpdEcalTB2GeoMapper::Instance();
+   mapper->SetForceCellSize(true);
+   
+   //strict values: size will be forced to be this value, but the ECAL may have lots of empty space - choose with caution
+   mapper->SetCellZSize(5.5);        // [cm] z-size of cell
+   mapper->SetCellInnerPhiSize(5.1); // [cm] П†-size of the cell face closer to beam axis
+   mapper->SetCellOuterPhiSize(6.6); // [cm] П†-size of the cell face closer to beam axis
+  
+   mapper->SetNLayers(200);
+   mapper->SetAbsorberLayerThickness(0.05); // [cm]
+   mapper->SetScintLayerThickness(0.15);    // [cm]
+  
+   //additional
+   mapper->SetModuleClearance(0.1); // [cm] clerance between modules (default: 0.1)
+   mapper->SetCellClearance(0.05);  // [cm] clerance between cells in a module (default: 0.05)
+}
+
+
+
+
+
+
+
diff --git a/macro/geom/ConstructEcalTEC2.C b/macro/geom/ConstructEcalTEC2.C
new file mode 100644
index 0000000000000000000000000000000000000000..f2b469054d62b267f4779ec45de2a365d041062f
--- /dev/null
+++ b/macro/geom/ConstructEcalTEC2.C
@@ -0,0 +1,50 @@
+//______________________________________________________________
+void ConstructEcalTEC2() 
+{
+   // 
+   SpdCommonGeoMapper::Instance()->OpenGeometry();
+  
+   FairModule* Cave = new SpdCave();
+   Cave->SetGeometryFileName("cave.geo");
+   Cave->ConstructGeometry();
+   
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+ 
+   SpdPipe* Pipe = new SpdPipe();
+   Pipe->ConstructGeometry();
+   
+   SpdEcalTEC2* ecaltec = new SpdEcalTEC2();
+   
+   // customize geometry
+   SpdEcalTEC2GeoMapper* mapper = SpdEcalTEC2GeoMapper::Instance();
+   
+   mapper->SetCellSize(5.5);                 // [cm], X/Y size of endcap cell (default: 5.5) 
+   mapper->SetAbsorberLayerThickness(0.05);  // [cm], thickness of absorber layer (material hardcoded as lead) (default: 0.05)
+   mapper->SetScintLayerThickness(0.15);     // [cm], thickness of scintillator layer (polystyrene(?)) (default: 0.15)
+   
+   // additional:
+   mapper->SetCellClearance(1.5);      // [cm], clerance between cells in a module (default: 0.05)
+   mapper->SetModuleClearance(1.5);    // [cm], clearance between modules (2x2 cells) (default: 0.1)
+      
+   // construct geometry
+   ecaltec->ConstructGeometry();
+   
+   /* ~~~~~~~~~~~~~ PRINT GEOMETRY INFO ~~~~~~~~~~~~~*/
+   
+   SpdEcalTEC2GeoMapper::Instance()->Print("");           // print all parameteecal
+   
+   /* ~~~~~~~~~~~~~ DRAW GEOMETRY  ~~~~~~~~~~~~~~~~~ */
+   
+   TGeoManager *geoMan = gGeoManager;
+   geoMan->SetVisLevel(2);
+  
+   //geoMan->GetMasterVolume()->SetVisContainers();
+   geoMan->GetMasterVolume()->Draw("ogl");
+
+   //ecaltec->GetEndcap()->Draw("ogl");
+   //ecaltec->GetModule()->Draw("ogl");
+   //ecaltec->GetCell()->Draw("ogl");
+   
+   return;
+
+}
diff --git a/macro/geom/ConstructHybGeo.C b/macro/geom/ConstructHybGeo.C
index 9abc90e0f423e040f98a5e1dba06ae7812e41453..775558458a00c4f308dac717e66414f8d16f30e4 100644
--- a/macro/geom/ConstructHybGeo.C
+++ b/macro/geom/ConstructHybGeo.C
@@ -11,15 +11,15 @@ void ConstructHybGeo() {
    Cave->SetGeometryFileName("cave.geo");
    Cave->ConstructGeometry();
    
-   Int_t HybGeoSetType = 2;
+   Int_t HybGeoSetType = 2;  // 1, 2
    
    SpdCommonGeoMapper::Instance()->DefineHybGeometrySet(HybGeoSetType);
    
-   //SpdCommonGeoMapper::Instance()->SetNGeoSectors(10);
+   //SpdCommonGeoMapper::Instance()->SetNGeoSectors(4);
  
    /* +++++++++ PIPE +++++++++ */
    
-   //SpdPipe* Pipe = new SpdPipe();
+   SpdPipe* Pipe = new SpdPipe();
    
    //Pipe->SetPipeType("tor");
    //Pipe->SetPipeType("sol");
@@ -32,15 +32,12 @@ void ConstructHybGeo() {
    
    SpdHybMagnet* Magnet = new SpdHybMagnet(); 
    
-   //Magnet->SetGeometryType(2);             // type = 1 (default) or type = 2 
+   //Magnet->SetGeometryType(1);             // type = 1 (hybrid) or type = 2 (qsolenoid)
          
    //Magnet->SetCoilsMaterial("silicon");  // see avaliable materials: geometry/media.geo
    //Magnet->UnsetMaterials(0);
+
   
-//    /* +++++++++ BASKET +++++++++ */
-//    
-    //SpdTorBasket* Basket = new SpdTorBasket(); 
-//    
 //    /* +++++++++ DETECTORS +++++++++ */
 //   
        SpdEcalTB*  ecal_barrel = new SpdEcalTB();   /* +++++++++ ECALT (BARREL) ++++++++++ */      
@@ -59,17 +56,13 @@ void ConstructHybGeo() {
            //tracker->ConstructGeometry();
        }
   
-//    /* ===== Vertex detector ===== */
- 
-      SpdIts* vxd = new SpdIts(); 
-      vxd->ConstructGeometry();
+      SpdIts* vxd = new SpdIts();    /* +++++++++ VERTEX TRACKER ++++++++++ */
       
-   // SpdTsTECGeoMapper::Instance()->SetGeometryPars(1); // 1,2 
       
+   // SpdTsTECGeoMapper::Instance()->SetGeometryPars(1); // 1,2 
    // SpdTsTBGeoBuilder::Instance()->SetMaxBuildGeoLevel(2);
    
-// //    SpdCommonGeoMapper::Instance()->UnsetMaterials(1);
-// //    
+//   SpdCommonGeoMapper::Instance()->UnsetMaterials(1);   
     SpdCommonGeoMapper::Instance()->ConstructGeometry(); 
   
     //SpdCommonGeoMapper::Instance()->PrintGeometryList();
diff --git a/macro/geom/ConstructIts.C b/macro/geom/ConstructIts.C
index a26e310fae909cc1bf8e435517328620ef7f88b8..1664bc9c37a8f5dbfaeea56c5af6b06e8ee9bcf4 100644
--- a/macro/geom/ConstructIts.C
+++ b/macro/geom/ConstructIts.C
@@ -5,7 +5,8 @@ void TestMapper();
 void TestBuilder();
 
 //______________________________________________________________
-void ConstructIts() {
+void ConstructIts() 
+{
    // 
    //TestMapper();
    //return;
@@ -18,9 +19,9 @@ void ConstructIts() {
    
    SpdCommonGeoMapper::Instance()->DefineHybGeometrySet();
    
-   SpdPipe* Pipe = new SpdPipe();
-   Pipe->ConstructGeometry();
-   Pipe->Print("");
+   //SpdPipe* Pipe = new SpdPipe();
+   //Pipe->ConstructGeometry();
+   //Pipe->Print("");
    
    SpdItsGeoMapperX::Instance()->SetGeometryPars(3); //1, 2, (3 = default)
    
diff --git a/macro/geom/ConstructQslGeo.C b/macro/geom/ConstructQslGeo.C
new file mode 100644
index 0000000000000000000000000000000000000000..7c598ba18b3ef1e59e24714fd534dcb71c9f75ae
--- /dev/null
+++ b/macro/geom/ConstructQslGeo.C
@@ -0,0 +1,86 @@
+
+//______________________________________________________________
+void ConstructQslGeo()
+{
+   //       
+   SpdCommonGeoMapper::Instance()->OpenGeometry();
+   
+   //FairGeoMedia* media = FairGeoLoader::Instance()->getGeoInterface()->getMedia();
+   //media->print();
+   
+   FairModule* Cave = new SpdCave();
+   Cave->SetGeometryFileName("cave.geo");
+   Cave->ConstructGeometry();
+   
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+ 
+   /* +++++++++ PIPE +++++++++ */
+   
+   SpdPipe* Pipe = new SpdPipe();
+   
+   //Pipe->SetPipeMaterial("silicon");
+   //Pipe->UnsetMaterials(1);
+   
+   /* +++++++++ MAGNET +++++++++ */
+
+   SpdHybMagnet* Magnet = new SpdHybMagnet();
+   Magnet->ConstructGeometry();
+       
+   /* +++++++++ DETECTORS +++++++++ */
+   
+   SpdEcalTB2*  ecal_barrel = new SpdEcalTB2();   /* +++++++++ ECALT (BARREL) ++++++++++ */      
+   SpdEcalTEC2* ecal_ecps   = new SpdEcalTEC2();  /* +++++++++ ECALT (ENDCAPS) +++++++++ */  
+   SpdRsTB2*    rs_barrel   = new SpdRsTB2();     /* +++++++++ RST (BARREL) ++++++++++++ */  
+   SpdRsTEC2*   rs_ecps     = new SpdRsTEC2();    /* +++++++++ RST (ENDCAPS) +++++++++++ */
+   SpdTsTB*     ts_barrel   = new SpdTsTB();      /* +++++++++ TST (BARREL) ++++++++++++ */ 
+   SpdTsTEC*    ts_ecps     = new SpdTsTEC();     /* +++++++++ TST (ENDCAPS) +++++++++++ */
+   SpdIts*      vxd         = new SpdIts();       /* +++++++++ VERTEX TRACKER ++++++++++ */
+   
+   /*--------------------------------------------------*/
+   /* ++++++++++++  CASTOMIZE GEOMETRY   +++++++++++++ */
+   /*--------------------------------------------------*/
+   
+   SpdParameter* par;
+   
+   //--------------------------------------------------------------------------
+   // Chose TsTEC configuration 
+   //   
+   // option = 1: (2x)3 modules, 1 module =  8x2 = 16 layers, total = 48 layers (default)
+   // option = 2: (2x)2 modules, 1 module =  8x2 = 16 layers, total = 32 layers  
+   // option = 3: (2x)1 modules, 1 module = 26x2 = 52 layers, total = 52 layers (actual!)
+   
+   SpdTsTECGeoMapper::Instance()->SetGeometryPars(3); 
+   
+   /*++++++++++++++++++++++++++++++*/
+   
+//    SpdCommonGeoMapper::Instance()->UnsetMaterials(1);    
+    SpdCommonGeoMapper::Instance()->ConstructGeometry(); 
+  
+    //SpdCommonGeoMapper::Instance()->PrintGeometryList();
+    //SpdCommonGeoMapper::Instance()->PrintGeometry();
+//    
+//   SpdTsTBGeoMapper::Instance()->PrintVolPars(); 
+//   SpdTsTBGeoMapper::Instance()->PrintGeoTable(); 
+  
+   /* DRAW GEOMETRY */
+   
+   TGeoManager *geoMan = gGeoManager;
+   geoMan->SetVisLevel(2);
+   geoMan->GetMasterVolume()->Draw("ogl");
+   //geoMan->GetMasterVolume()->Draw();
+   
+   // return;
+   
+   /* Save Geometry into the file */
+   
+//    TFile* file = new TFile("geofile_full.root","RECREATE");
+//    file->cd();
+//    gGeoManager->Write();
+//    file->Close();
+
+   //geoMan->Export("geofile_full.root");  // save as *.root
+   //geoMan->Export("geofile_full.gdml");  // save as *.gdml
+ 
+}
+
+
diff --git a/macro/geom/ConstructRsTB.C b/macro/geom/ConstructRsTB.C
index e7bc71b965443db6b3e449dc109e4919cbcd6526..f990709c8db8cd11eccc4beb457922a810a3997b 100644
--- a/macro/geom/ConstructRsTB.C
+++ b/macro/geom/ConstructRsTB.C
@@ -8,13 +8,17 @@ void ConstructRsTB()
    Cave->SetGeometryFileName("cave.geo");
    Cave->ConstructGeometry();
    
-   SpdCommonGeoMapper::Instance()->DefineHybGeometrySet();
+   //SpdCommonGeoMapper::Instance()->DefineHybGeometrySet();
+   SpdCommonGeoMapper::Instance()->DefineQSolGeometrySet();
    
    //SpdPipe* Pipe = new SpdPipe();
    //Pipe->ConstructGeometry();
    //Pipe->Print("");
    
-   SpdRsTBGeoMapper::Instance()->SetGeoType(1);
+   //SpdRsTBGeoMapper::Instance()->SetGeoType(1);
+   
+   //SpdParameter* par = SpdRsTBGeoMapper::Instance()->AddParameter("RsTBClearance");
+   //*par = 0.;
    
    SpdRsTB* rs = new SpdRsTB();
    
diff --git a/macro/geom/ConstructRsTB2.C b/macro/geom/ConstructRsTB2.C
new file mode 100644
index 0000000000000000000000000000000000000000..304815f2ccb8b1607f1bee4a5a9bf1b19650923f
--- /dev/null
+++ b/macro/geom/ConstructRsTB2.C
@@ -0,0 +1,32 @@
+//______________________________________________________________
+void ConstructRsTB2() {
+   // 
+   SpdCommonGeoMapper::Instance()->OpenGeometry();
+  
+   FairModule* Cave = new SpdCave();
+   Cave->SetGeometryFileName("cave.geo");
+   Cave->ConstructGeometry();
+   
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+ 
+   //SpdPipe* Pipe = new SpdPipe();
+   //Pipe->ConstructGeometry();
+   //Pipe->Print("");
+   
+   SpdRsTB2* rstb = new SpdRsTB2();
+   rstb->ConstructGeometry();
+   
+   /* ~~~~~~~~~~~~~ PRINT GEOMETRY INFO ~~~~~~~~~~~~~~~~~ */
+   
+   SpdRsTB2GeoMapper::Instance()->Print("");           // print all parameters
+   
+   /* ~~~~~~~~~~~~~ DRAW GEOMETRY  ~~~~~~~~~~~~~~~~~ */
+   
+   TGeoManager *geoMan = gGeoManager;
+   geoMan->SetVisLevel(3);
+  
+   //geoMan->GetMasterVolume()->SetVisContainers();
+   geoMan->GetMasterVolume()->Draw("ogl");
+   return;
+
+}
diff --git a/macro/geom/ConstructRsTEC2.C b/macro/geom/ConstructRsTEC2.C
new file mode 100644
index 0000000000000000000000000000000000000000..b920fa6b1172fa2f0f125bc8c9df44569cd35cb7
--- /dev/null
+++ b/macro/geom/ConstructRsTEC2.C
@@ -0,0 +1,31 @@
+//______________________________________________________________
+void ConstructRsTEC2() {
+   // 
+   SpdCommonGeoMapper::Instance()->OpenGeometry();
+  
+   FairModule* Cave = new SpdCave();
+   Cave->SetGeometryFileName("cave.geo");
+   Cave->ConstructGeometry();
+   
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+ 
+   SpdPipe* Pipe = new SpdPipe();
+   Pipe->ConstructGeometry();
+   
+   SpdRsTEC2* rstec = new SpdRsTEC2();
+   rstec->ConstructGeometry();
+   
+   /* ~~~~~~~~~~~~~ PRINT GEOMETRY INFO ~~~~~~~~~~~~~~~~~ */
+   
+   SpdRsTEC2GeoMapper::Instance()->Print("");           // print all parameters
+   
+   /* ~~~~~~~~~~~~~ DRAW GEOMETRY  ~~~~~~~~~~~~~~~~~ */
+   
+   TGeoManager *geoMan = gGeoManager;
+   geoMan->SetVisLevel(2);
+  
+   //geoMan->GetMasterVolume()->SetVisContainers();
+   geoMan->GetMasterVolume()->Draw("ogl");
+   return;
+
+}
diff --git a/macro/geom/ConstructTsTB.C b/macro/geom/ConstructTsTB.C
index bda3393540caedf2fdb4c28dc1f6ed8f1f040528..a0f94d28d7efcf46e46a327d7833be45083afb33 100644
--- a/macro/geom/ConstructTsTB.C
+++ b/macro/geom/ConstructTsTB.C
@@ -17,8 +17,8 @@ void ConstructTsTB() {
    // /* change number of sectors */
    //SpdCommonGeoMapper::Instance()->SetNGeoSectors(9);  // > 2 && < 13
  
-   //Standard();
-   Custom();
+   Standard();
+   //Custom();
    
    /* ~~~~~~~~~~~~~ PRINT GEOMETRY INFO ~~~~~~~~~~~~~~~~~ */
    
@@ -160,18 +160,18 @@ void Standard()
    cout << "\t tid = " << geotable->GetNodeTableNum(path) << " path = " << path << endl; 
    
    //---------------------------------------------------------------------------------------------
-   // 6275   3 2563    1 [    1     1]   TsTBStraw692Wire     TsTBStraw692         [  2564   2564]
-   // 2296   2 2157    1 [    6     6]   TsTBStraw692         TsTBLayer128         [ 11401  11401]
-   //  138   1 135    21 [   22    42]   TsTBLayer128         TsTBModule3          [   440    460]
+   // 6275   3 1274    1 [    1     1]   TsTBStraw89Shell     TsTBStraw89          [  1275   1275]
+   // 1217   2 1078    1 [    2     2]   TsTBStraw89          TsTBLayer127         [  4632   4632]
+   //  137   1 134    21 [   22    42]   TsTBLayer127         TsTBModule3          [   419    439]
    //    2   0   2     8 [    1     8]   TsTBModule3          cave                 [    17     24]
-
-
-   path = "/cave_1/TsTBModule3_6/TsTBLayer128_25/TsTBStraw692_6/TsTBStraw692Wire_1";
+   
+   path = "/cave_1/TsTBModule3_6/TsTBLayer127_25/TsTBStraw89_2/TsTBStraw89Shell_1";
    
    cout << "\n" << path << endl;
    tid = geotable->GetNodeTableNum(path);
    path = geotable->GetNodeGeoPath(tid);
    cout << "\t tid = " << tid << " path = " << path << endl;
+   cout << endl;
 }
 
 //________________________________________________________________________________________________
diff --git a/macro/geom/ConstructTsTEC.C b/macro/geom/ConstructTsTEC.C
index d0c710c49a1a8d39ac5cbcd0ccbfa4844212bf80..8c671eb61557b1e7796922a4e3e90112bb971ed4 100644
--- a/macro/geom/ConstructTsTEC.C
+++ b/macro/geom/ConstructTsTEC.C
@@ -71,7 +71,7 @@ void ConstructTsTEC() {
    /* ~~~~~~~~~~~~~ DRAW GEOMETRY  ~~~~~~~~~~~~~~~~~ */
    
    TGeoManager *geoMan = gGeoManager;
-   geoMan->SetVisLevel(3);
+   geoMan->SetVisLevel(2);
   
    geoMan->GetMasterVolume()->SetVisContainers();
    geoMan->GetMasterVolume()->Draw("ogl");
@@ -108,7 +108,7 @@ void Standard(Int_t goption)
    {
        mapper->SetGeoType(3); 
           
-       mapper->SetGeometryPars(1); // 3x8+3x8 modules*layers (default)
+       //mapper->SetGeometryPars(1); // 3x8+3x8 modules*layers (default)
        //mapper->SetGeometryPars(2); // 1+1 modules 
        //mapper->SetGeometryPars(3); // 3x24+3x24 modules*layers 
        //mapper->SetGeometryPars(4); // 6x4+6x4 modules*layers 
@@ -291,9 +291,11 @@ void Custom_1(Int_t goption)
    mapper->AddIdentModules( 1, 1, 1,  0. /*deg*/);
    mapper->AddIdentModules(-1, 2, 1, 90. /*deg*/);
    
-   //mapper->AddForwardModule(1,0,0);
-   //mapper->AddBackwardModule(2,0,45.);
-   //mapper->RecalculateDistance();
+//    mapper->AddForwardModule(1,0,0);
+//    mapper->AddForwardModule(1,0,0);
+//    mapper->AddBackwardModule(2,0,45.);
+//    mapper->AddBackwardModule(2,0,45.);
+//    mapper->RecalculateDistance();
 }
 
 
diff --git a/macro/geom/build_magnet.C b/macro/geom/build_magnet.C
index 7705d0e208b7aeb80093a2ec952b308a72a485da..c4dd89447ed194f76a101475e0156a298c45485f 100644
--- a/macro/geom/build_magnet.C
+++ b/macro/geom/build_magnet.C
@@ -5,6 +5,7 @@ void pipe();
 void magnet_tor();
 void magnet_sol();
 void magnet_hyb();
+void magnet_qsl();
 
 //________________________________________________________________________
 void build_magnet() 
@@ -24,7 +25,8 @@ void build_magnet()
    
    //magnet_tor();
    //magnet_sol();
-   magnet_hyb();
+   //magnet_hyb();
+   magnet_qsl();
    
    //--------------------------------------------------
    
@@ -52,7 +54,7 @@ void magnet_tor()
    //Magnet->PurseCoilsAlongZ(30 /*dz, cm*/);     // [cm], new Z_size >= width + rounding
    //Magnet->SetCoilsMaterial("silicon");  // see avaliable materials in geometry/media.geo
    
-   //Magnet->UnsetMaterials(1);
+   //Magnet->UnsetMaterials();
    
    Magnet->ConstructGeometry();
    
@@ -66,7 +68,7 @@ void magnet_sol()
 {
    SpdSolMagnet* Magnet = new SpdSolMagnet();
    
-   //Magnet->SetGeometryType(1);   // type = 1 (default) or type = 2
+   Magnet->SetGeometryType(1);   // type = 1 (default) or type = 2
    
    //Magnet->SetWidth(50);         // [cm], width >= 1 cm 
    //Magnet->SetMaterial("iron");
@@ -85,8 +87,21 @@ void magnet_hyb()
 {
    SpdHybMagnet* Magnet = new SpdHybMagnet();
    
-   Magnet->SetGeometryType(1);             // type = 1 (default) or type = 2
+   Magnet->SetGeometryType(1);            // geometry type = 1: hybrid, 
+   //Magnet->SetGeometryType(2);            // geometry type = 2: qsolenoid-large
+      
+   Magnet->ConstructGeometry();
+   
+   //Magnet->Print("");
+}
+
+//________________________________________________________________________
+void magnet_qsl()
+{
+   SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();  // default geometry type = 3:  qsolenoid-actual
    
+   SpdHybMagnet* Magnet = new SpdHybMagnet();
+  
    Magnet->ConstructGeometry();
    
    //Magnet->Print("");
@@ -105,7 +120,8 @@ void pipe()
    //Pipe->SetPipeType("hybrid");
    
    //Pipe->SetPipeMaterial("silicon");
-   //Pipe->UnsetMaterials(1);
+   
+   //Pipe->UnsetMaterials("vacuum");
  
    Pipe->ConstructGeometry();
    
diff --git a/macro/geom/build_pipe.C b/macro/geom/build_pipe.C
index e16e260b1a55355fd912227473e92b40f5a5b84a..65866e2fb80d4ce63c0009f6767f6c4f88e321c6 100644
--- a/macro/geom/build_pipe.C
+++ b/macro/geom/build_pipe.C
@@ -1,11 +1,12 @@
 
-
 void pipe();
 
 void magnet_tor();
 void magnet_sol();
 void magnet_hyb();
 
+void pipe_volume();
+
 //________________________________________________________________________
 void build_pipe() 
 {
@@ -47,15 +48,18 @@ void pipe()
    //Pipe->SetPipeType("hyb");
    
    //Pipe->SetPipeMaterial("silicon");
-   //Pipe->UnsetMaterials(1);
+   
+   Pipe->UnsetMaterials("vacuum");
  
    Pipe->ConstructGeometry();
    
    //Pipe->Print();
 }
+
 //________________________________________________________________________
 void pipe_volume()
 {
+  gSystem->Load("libGeom.so");
   
   SpdPipe* Pipe = new SpdPipe();
    
@@ -63,11 +67,11 @@ void pipe_volume()
    
   TGeoVolume* vol;
   
-  vol = Pipe->GetHybPipeISpace();
-  //vol = Pipe->GetHybPipeC();       
-  //vol = Pipe->GetHybPipeLZminus();
-  //vol = Pipe->GetHybPipeLZPlus();  
+  vol = const_cast<TGeoVolume*>(Pipe->GetHybPipeISpace());
+  //vol = const_cast<TGeoVolume*>(Pipe->GetHybPipeC());       
+  //vol = const_cast<TGeoVolume*>(Pipe->GetHybPipeLZminus());
+  //vol = const_cast<TGeoVolume*>(Pipe->GetHybPipeLZPlus());  
   
   if (vol) vol->Draw("ogl");
   
-}
\ No newline at end of file
+}
diff --git a/macro/primgen/TestEvtBaseGenerator.C b/macro/primgen/TestEvtBaseGenerator.C
index 599dd337caaef85892ac0c8554b768afb484b03c..1d967c8e185c168846c48ccd5eedecabd5d8ef93 100644
--- a/macro/primgen/TestEvtBaseGenerator.C
+++ b/macro/primgen/TestEvtBaseGenerator.C
@@ -2,6 +2,7 @@
 
 SpdGenerator* InitPythia6();
 SpdGenerator* InitFTF(Int_t nevents, Double_t Elab = 25 /*GeV*/);
+SpdGenerator* InitUrqmd(TString data);
 
 //______________________________________________________________
 void TestEvtBaseGenerator(Int_t ngevents = 5, Int_t nevents = 10)
@@ -11,13 +12,18 @@ void TestEvtBaseGenerator(Int_t ngevents = 5, Int_t nevents = 10)
    ingen = InitPythia6();
    //ingen = InitFTF(nevents);
    
+   //ingen = InitUrqmd("../input/AuAu_ecm9gev_hydroON_EoS1PT_mbias_1000ev_10.f13.gz");
+   
    if (!ingen) return;
    
-   ingen->SetVerboseLevel(-10);
+   //ingen->SetVerboseLevel(-10);
    
    ingen->CreateAsciiFile(nevents,"EvtBaseEvents");
    //ingen->CreateRootFile(nevents,""EvtBaseEvents");
-
+   
+   //ingen->CreateRootFile(1,"UrqmdEvents");
+   //ingen->CreateAsciiFile(1,"UrqmdEvents");
+   
    return;
    
    //----------------------------------------------------  
@@ -88,4 +94,14 @@ SpdGenerator* InitFTF(Int_t nevents, Double_t Elab)
   
   return ftfgen;      
 }
+//______________________________________________________________
+SpdGenerator* InitUrqmd(TString data)
+{
+   SpdUrqmdGenerator* gen = new SpdUrqmdGenerator("../input/AuAu_ecm9gev_hydroON_EoS1PT_mbias_1000ev_10.f13.gz");
+    
+   gen->SetVerboseLevel(2); // 0 ("minimal" printing) or 1
+   gen->SetKeepEvent(kFALSE); 
+   
+   return gen;
+}
 
diff --git a/macro/primgen/TestIsotropic.C b/macro/primgen/TestIsotropic.C
index 5463265b89169c78d780f91c5e38129c3aa8fdf2..aad1c430b8f9cd78bc11c94f6209b8e0931aa9ea 100644
--- a/macro/primgen/TestIsotropic.C
+++ b/macro/primgen/TestIsotropic.C
@@ -6,7 +6,7 @@ TH3D* DP_(0);
 TH1D *Theta_(0), *Phi_(0);
 
 void FillH(TParticle* part);
-void DrawH(Int_t mark_size = 0.3);
+void DrawH(Double_t mark_size = 0.3);
 
 const Double_t R_ = 1.;
 
@@ -108,7 +108,7 @@ void check_pythia6()
        }
    }
    
-   DrawH(0.5 /*size of marker */);
+   DrawH(0.5 /* marker size */);
     
    delete gen;
 }
@@ -148,7 +148,7 @@ void FillH(TParticle* part)
 }
 
 //______________________________________________________________
-void DrawH(Int_t mark_size)
+void DrawH(Double_t mark_size)
 {
     if (DP_) {
         TCanvas* cDP = new TCanvas("Direction","Direction",800,800);
diff --git a/macro/primgen/TestUrqmd.C b/macro/primgen/TestUrqmd.C
new file mode 100644
index 0000000000000000000000000000000000000000..5b5c847ff37998bddf3cea4699798b0799c44291
--- /dev/null
+++ b/macro/primgen/TestUrqmd.C
@@ -0,0 +1,121 @@
+#include "TParticle.h"
+
+void check_urqmd();
+
+TH3D* DP_(0);
+TH1D *Theta_(0), *Phi_(0);
+
+void FillH(TParticle* part);
+void DrawH(Double_t mark_size = 0.3);
+
+const Double_t R_ = 1.;
+
+//______________________________________________________________
+void TestUrqmd() 
+{
+   gStyle->SetOptStat("e");
+
+   check_urqmd();
+}
+
+//______________________________________________________________
+void check_urqmd()
+{ 
+    SpdUrqmdGenerator* gen = new SpdUrqmdGenerator("../input/AuAu_ecm9gev_hydroON_EoS1PT_mbias_1000ev_10.f13.gz");
+    
+    //--------------------------------------------------------------------------------
+    gen->SetVerboseLevel(2); // 0 ("minimal" printing) or 1
+    gen->SetKeepEvent(kTRUE); 
+    //gen->Initialize(211,1,10000);   
+//    gen->Initialize(211,1,5); 
+    
+    /* ----------- GENERATE EVENT ----------- */
+    
+    Int_t skip_events = 0;
+    while (true) {
+      gen->ReadEvent(0);
+      if (++skip_events == 1) break;
+    }
+    
+    const TClonesArray* event = gen->GetEvent();
+    
+    if (event) {
+        Int_t size = event->GetEntriesFast();
+        for (Int_t i(0); i<size; i++) {
+             FillH((TParticle*)event->At(i));
+        }
+    }
+    
+    DrawH(1.0 /*size of marker */);
+    
+    delete gen;
+}
+
+//______________________________________________________________
+void FillH(TParticle* part)
+{
+    if (!part) return;
+    
+    //cout << part->GetPdgCode() << " "  <<  part->GetFirstMother()<< endl;
+    
+    if (!DP_) {
+        DP_ = new TH3D("Direction","", 
+        100 , -1.5*R_, 1.5*R_, 150, -1.5*R_, 1.5*R_ , 150, -1.5*R_, 1.5*R_ );
+    }
+    
+    double dd = 0.;
+    
+    if (!Theta_) {
+        Theta_ = new TH1D("Theta","Theta",18,0+dd,180+dd);
+        Theta_->SetFillColor(kRed);
+        Theta_->SetMinimum(0);
+    }
+   
+    if (!Phi_) {
+        Phi_ = new TH1D("Phi","Phi",36,-180+dd,180+dd);
+        Phi_->SetFillColor(kRed);
+        Phi_->SetMinimum(0);
+    }
+    
+    TVector3 v(part->Px(),part->Py(),part->Pz());
+    v.SetMag(R_);
+    
+    DP_->Fill(v.X(),v.Y(),v.Z());
+    Theta_->Fill(v.Theta()*TMath::RadToDeg());
+    Phi_->Fill(v.Phi()*TMath::RadToDeg());
+}
+
+//______________________________________________________________
+void DrawH(Double_t mark_size)
+{
+    if (DP_) {
+        TCanvas* cDP = new TCanvas("Direction","Direction",800,800);
+        DP_->SetMarkerStyle(8);
+        DP_->SetMarkerSize(mark_size);
+        DP_->Draw();
+        
+        TPolyMarker3D* center = new TPolyMarker3D(1);
+        center->SetPoint(0,0,0,0);
+        center->SetMarkerStyle(8);
+        center->SetMarkerColor(kRed);
+        center->SetMarkerSize(2);
+        center->Draw("same");
+    }
+    
+    if (Theta_) {
+        TCanvas* cTh = new TCanvas("Theta","Theta",1000,700);
+        Theta_->Draw();
+    }
+    
+    if (Phi_) {
+        TCanvas* cPh = new TCanvas("Phi","Phi",1000,700);
+        Phi_->Draw();
+    }
+}
+
+
+
+
+
+
+
diff --git a/macro/rootlogon.C b/macro/rootlogon.C
index 6128517f066e6d7af6dc4e92f32002e7ea2d8c35..7c7cb069b312210dbaf07b94366860d9e5831c2f 100644
--- a/macro/rootlogon.C
+++ b/macro/rootlogon.C
@@ -51,6 +51,7 @@ void SetMacroPath()
   macropath += mpath + "/geom" + ":";
   macropath += mpath + "/analysis" + ":";
   macropath += mpath + "/tracking" + ":";
+  macropath += mpath + "/vertexrec" + ":";
   //macropath += mpath + "/analysis/its" + ":";
   //macropath += mpath + "/analysis/tst" + ":";
   
@@ -101,9 +102,12 @@ void LoadLibraries()
   gSystem->Load("libGenFit2");
   gSystem->Load("libTrackingGF");
   gSystem->Load("libSpdReco");
-
+  
+  gSystem->Load("libKFParticle");
+  gSystem->Load("libVertexKF");
+  
   //gSystem->ListLibraries();
-    
+  
   cout << "Ok " << endl;     
 }
 
@@ -166,6 +170,11 @@ void LoadIncludes()
   
   gROOT->ProcessLine(".include ../proc/clustering");
   gROOT->ProcessLine(".include ../proc/tracking");
+  gROOT->ProcessLine(".include ../proc/vertex");
+  
+  
+  gROOT->ProcessLine(".include ../external/KFParticle/KFParticle");
+  gROOT->ProcessLine(".include ../external/KFParticle/KFParticleTest");
   
   cout << " Ok " << endl;
 }  
diff --git a/macro/run/SimuEvtBase.C b/macro/run/SimuEvtBase.C
index b3c822af47d7bd302deba6674d3331e396b5090a..2b27f5826f2c51a7e969abc101574d05a5cc4cbc 100644
--- a/macro/run/SimuEvtBase.C
+++ b/macro/run/SimuEvtBase.C
@@ -62,7 +62,7 @@ void SimuEvtBase(Int_t nEvents = 1, Int_t nSkipEvents = 0)
   
   /* --- field map --- */
   SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
-  MagField->InitData("map_hyb_1T5cm.dat");
+  MagField->InitData("map_hyb_1T2cm.bin");
   
   run->SetField(MagField);
   
diff --git a/macro/run/XSimuHyb.C b/macro/run/XSimuHyb.C
index c8a034ea60a2a9c61f4f7be1e1ad71304ee85573..62ae71714fbc08686b83061bd4cb91d7700e9108 100644
--- a/macro/run/XSimuHyb.C
+++ b/macro/run/XSimuHyb.C
@@ -32,7 +32,7 @@ void XSimuHyb(Int_t nEvents = 1)
   SpdPipe* Pipe = new SpdPipe();
   
   //Pipe->SetPipeMaterial("silicon");
-  //Pipe->UnsetMaterials(1);
+  //Pipe->UnsetMaterials("vacuum2");
   
   run->AddModule(Pipe);
   
diff --git a/macro/run/XSimuSol.C b/macro/run/XSimuSol.C
index aa067f6c640e8174042fdd6b8f6056c5025dd009..6a166f0d807dfa9b7f1721efe574baedf29a462a 100644
--- a/macro/run/XSimuSol.C
+++ b/macro/run/XSimuSol.C
@@ -32,7 +32,7 @@ void XSimuSol(Int_t nEvents = 1)
   SpdPipe* Pipe = new SpdPipe();
   
   //Pipe->SetPipeMaterial("silicon");
-  //Pipe->UnsetMaterials(1);
+  //Pipe->UnsetMaterials("vacuum2");
   
   run->AddModule(Pipe);
    
diff --git a/macro/run/XSimuTor.C b/macro/run/XSimuTor.C
index 91815537d3d783edab850bae31b86825fd779d98..25499e699204b6fa4a953acd98e552d61faa9ad8 100644
--- a/macro/run/XSimuTor.C
+++ b/macro/run/XSimuTor.C
@@ -32,7 +32,7 @@ void XSimuTor(Int_t nEvents = 1)
   SpdPipe* Pipe = new SpdPipe();
   
   //Pipe->SetPipeMaterial("silicon");
-  //Pipe->UnsetMaterials(1);
+  //Pipe->UnsetMaterials("vacuum2");
   
   run->AddModule(Pipe);
   
diff --git a/macro/testmisc/SPD_RS_Barrel_Flexible.C b/macro/testmisc/SPD_RS_Barrel_Flexible.C
new file mode 100644
index 0000000000000000000000000000000000000000..f3af7565f60962f56c416f4ae2649d4b4132e472
--- /dev/null
+++ b/macro/testmisc/SPD_RS_Barrel_Flexible.C
@@ -0,0 +1,519 @@
+// $Id$
+// Author: georgy   2020/06/24
+
+//_____________________________________________________________________________
+//
+// Creates geometry of SPD RS Barrel segment and fills it with MDT detectors
+//_____________________________________________________________________________
+
+
+TGeoVolume* createMDT(Double_t length = 493.0) {
+//_____________________________________________________________________________
+//
+// Creates MDT of given length;
+// Envelope Dimensions(L x W x H): length x 8.5cm x 1.64cm.
+// Note: Adopted from Panda Muon System
+//_____________________________________________________________________________
+
+    // Medium description
+    TGeoMaterial* mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium*   pair = new TGeoMedium("air",1,mat_air);
+
+    TGeoMaterial* mat_mix = new TGeoMaterial("MDTMixture",0,0,0);
+    TGeoMedium*   pMDTMixture = new TGeoMedium("MDTMixture",1,mat_mix);
+
+    TGeoMaterial* mat_Al = new TGeoMaterial("Aluminium",0,0,0);
+    TGeoMedium*   paluminium = new TGeoMedium("Aluminium",1,mat_Al);
+
+    TGeoMaterial* mat = new TGeoMaterial("Vacuum",0,0,0);
+    TGeoMedium*   pvacuum = new TGeoMedium("Vacuum",1,mat);
+
+    TGeoMaterial* mat_pvc = new TGeoMaterial("PVC",0,0,0);
+    TGeoMedium*   pPVC = new TGeoMedium("PVC",1,mat_pvc);
+
+    TGeoMaterial* mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium*   piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial* mat_g10 = new TGeoMaterial("G10",0,0,0);
+    TGeoMedium*   pg10 = new TGeoMedium("G10",1,mat_g10);
+
+    TGeoMaterial* mat_copper = new TGeoMaterial("copper",0,0,0);
+    TGeoMedium*   pcopper = new TGeoMedium("copper",1,mat_copper);
+
+    // Shapes and volumes ---------------------------------------------------------------
+    // General dimensions
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+    Double_t xSize = 1.0;
+    Double_t shiftZ = 3.5/2; //distance between layers is 35mm
+
+    TString transName;
+    Int_t Nenvelopes;
+    Int_t IncEnv = 0;
+
+    //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    TGeoRotation* rotZ180 = new TGeoRotation("rotZ180", 0., 0., 180.);
+    rotZ180->RegisterYourself();
+
+    //check!
+    TGeoCombiTrans* M0 = new TGeoCombiTrans("M0", 0., 0, 0., rotNoRot);
+    TGeoCombiTrans* M1 = new TGeoCombiTrans("M1", 0., -170.5, 0., rotNoRot);
+    TGeoCombiTrans* M2 = new TGeoCombiTrans("M2", 0., -45.0, 0., rotNoRot);
+    TGeoCombiTrans* M3 = new TGeoCombiTrans("M3", 0., -184.5, 0., rotNoRot);
+    M0->RegisterYourself();
+    M1->RegisterYourself();
+    M2->RegisterYourself();
+    M3->RegisterYourself();
+
+    Double_t empty_value = (2.0+2.0+8.5)+6.5*2;
+    Double_t L_MDT_Envelope = length; //493.0;
+    Double_t L_MDT_Envelope_sensitive = L_MDT_Envelope-empty_value;
+
+
+Int_t ind = int(length*10);
+    //Shapes
+    //<box name="Indent20_PartBody" x="(42.500000)*2" y="(10.000000)*2" z="(8.200000)*2" lunit="mm"/>
+    TGeoBBox* Indent20_Shape = new TGeoBBox("Indent20_Shape", widthEnv/2,
+                                                            1.0,
+                                                            thicknessEnv/2);
+    //<box name="FEB_box_PartBody" x="(42.500000)*2" y="(42.500000)*2" z="(8.200000)*2" lunit="mm"/>
+    TGeoBBox* FEB_box_Shape = new TGeoBBox("FEB_box_Shape", widthEnv/2,
+                                                            widthEnv/2,
+                                                            thicknessEnv/2);
+    //<box name="DeadMat_PartBody" x="(40.700000)*2" y="(32.500000)*2" z="(5.150000)*2" lunit="mm"/>
+    TGeoBBox* DeadMat_Shape = new TGeoBBox("DeadMat_Shape", 4.07,
+                                                            3.25,
+                                                            0.515);
+    TGeoVolume* Indent20_Vol = new TGeoVolume("Indent20_Vol", Indent20_Shape, pair);
+    TGeoVolume* FEB_box_Vol = new TGeoVolume("FEB_box_Vol", FEB_box_Shape, pair);
+    TGeoVolume* DeadMat_Vol = new TGeoVolume("DeadMat_Vol", DeadMat_Shape, pMDTMixture);
+
+    //----------------------4930------------------------------------//
+    TGeoBBox* L_Al_A_Shape = new TGeoBBox(Form("L%d_Al_A_Shape",ind), 4.03,
+                                                                L_MDT_Envelope_sensitive/2,
+                                                                0.03);
+    TGeoBBox* L_Al_B_Shape = new TGeoBBox(Form("L%d_Al_B_Shape",ind), 0.03,
+                                                                L_MDT_Envelope_sensitive/2,
+                                                                0.42);
+    TGeoBBox* L_GasCell_Shape = new TGeoBBox(Form("L%d_GasCell_Shape",ind), 0.47,
+                                                                        L_MDT_Envelope_sensitive/2,
+                                                                        0.46);
+    TGeoBBox* L_Cell_Shape = new TGeoBBox(Form("L%d_Cell_Shape",ind), 0.5,
+                                                                L_MDT_Envelope_sensitive/2,
+                                                                0.46);
+    TGeoBBox* L_MDT_S_Shape = new TGeoBBox(Form("L%d_MDT_S_Shape",ind), 4.0,
+                                                                    L_MDT_Envelope_sensitive/2,
+                                                                    0.46);
+    TGeoBBox* L_Envelope_Shape = new TGeoBBox(Form("L%d_Envelope_Shape",ind), widthEnv/2,
+                                                                        L_MDT_Envelope/2,
+                                                                        thicknessEnv/2);
+                                                                                 
+    //Volumes
+    TGeoVolume* L_Al_A_Vol = new TGeoVolume(Form("L%d_Al_A_Vol",ind), L_Al_A_Shape, paluminium);
+    TGeoVolume* L_Al_B_Vol = new TGeoVolume(Form("L%d_Al_B_Vol",ind), L_Al_B_Shape, paluminium);
+    TGeoVolume* L_GasCell_Vol = new TGeoVolume(Form("L%d_GasCell_Vol",ind), L_GasCell_Shape, pMDTMixture);
+    TGeoVolume* L_Cell_Vol = new TGeoVolume(Form("L%d_Cell_Vol",ind), L_Cell_Shape, pMDTMixture);
+    TGeoVolume* L_MDT_S_Vol = new TGeoVolume(Form("L%d_MDT_S_Vol",ind), L_MDT_S_Shape, pMDTMixture);
+    TGeoVolume* L_Envelope_Vol = new TGeoVolume(Form("L%d_Envelope_Vol",ind), L_Envelope_Shape, pair);
+   
+    // Volume hierarchy -----------------------------------------------------------------
+    //Structure
+    //GasCell and Al_B in Cell
+    L_Cell_Vol->AddNode(L_GasCell_Vol, 1,
+                            new TGeoCombiTrans("", -0.03, 0, 0, rotNoRot));
+    L_Cell_Vol->AddNode(L_Al_B_Vol, 1,
+                            new TGeoCombiTrans("", 0.47, 0, -0.04, rotNoRot));
+
+    //8 Cells in MDT_S
+    for (UInt_t i=0; i<8; i++) {
+        transName.Form("trans_cell_%d", i);
+        TGeoCombiTrans* trans1 = new TGeoCombiTrans(transName.Data(), -4.0 + xSize/2. + (Double_t)i*xSize, 0, 0., rotNoRot);
+        trans1->RegisterYourself();
+        L_MDT_S_Vol->AddNode(L_Cell_Vol, i+1, trans1);
+    }
+
+    L_Envelope_Vol->AddNode(Indent20_Vol, 1,
+                                new TGeoCombiTrans("", 0, L_MDT_Envelope/2 - 1.0, 0, rotNoRot));
+    L_Envelope_Vol->AddNode(Indent20_Vol, 2,
+                                new TGeoCombiTrans("", 0, 1.0 - L_MDT_Envelope/2, 0, rotNoRot));
+    L_Envelope_Vol->AddNode(FEB_box_Vol, 1,
+                                new TGeoCombiTrans("", 0, L_MDT_Envelope/2-2.0-8.5*0.5, 0, rotNoRot));
+    L_Envelope_Vol->AddNode(DeadMat_Vol, 1,
+                                new TGeoCombiTrans("", 0, ((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, 0, rotNoRot));
+    L_Envelope_Vol->AddNode(DeadMat_Vol, 2,
+                                new TGeoCombiTrans("", 0, -((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, 0, rotNoRot));
+    L_Envelope_Vol->AddNode(L_Al_A_Vol, 1,
+                                new TGeoCombiTrans("", 0, -widthEnv/2, -0.36, rotNoRot));
+    L_Envelope_Vol->AddNode(L_Al_B_Vol, 1,
+                                new TGeoCombiTrans("", -4.0, -widthEnv/2, 0.09, rotNoRot));
+    L_Envelope_Vol->AddNode(L_MDT_S_Vol, 1,
+                                new TGeoCombiTrans("", 0.03, -widthEnv/2, 0.13, rotNoRot));                                                          
+    //----------------------4930------------------------------------//
+
+    return L_Envelope_Vol;
+}
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createBottomLayer(Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing bottom layer of the RS Barrel part
+// (6.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Outer radius of RS from collision point (rsRadius);
+//             2. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 6.0+3.5; //cm
+
+    Double_t Sector_dy = rsLength/2.0;
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+    Double_t shiftZ = 3.5/2; //distance between layers is 35mm
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    TGeoRotation* rotZ180 = new TGeoRotation("rotZ180", 0., 0., 180.);
+    rotZ180->RegisterYourself();
+
+    Double_t Layer1_Sector_dz = layerThickness/2; // z-coord of the layer center 
+    Double_t Layer1_Sector_dx1 = 1.0*(rsRadius-rsThickness)*(sqrt(2.0)-1.0); // X-coord of the bottom base
+    Double_t Layer1_Sector_dx2 = 1.0*(rsRadius-rsThickness+layerThickness)*(sqrt(2.0)-1.0); // X-coord of the top base
+    Double_t Layer1_Sector_dy = Sector_dy; // y-coord of the layer center
+    cout<<"Layer #1 dimensions (bottom base): ["
+        << Layer1_Sector_dx1*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    cout<<"Layer #1 dimensions (top base): ["
+        <<Layer1_Sector_dx2*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    
+
+
+    TGeoTrd2* Layer1_SideS_Shape = new TGeoTrd2("Layer_SideS_Shape", 
+                                                1.0*Layer1_Sector_dx1, 
+                                                1.0*Layer1_Sector_dx2, 
+                                                Layer1_Sector_dy, 											 
+                                                Layer1_Sector_dy,
+                                                Layer1_Sector_dz);
+
+    TGeoBBox* Layer1_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        1.0*Layer1_Sector_dx1, 
+                                                        Layer1_Sector_dy, 
+                                                        Layer1_Sector_dz-3.5/2);
+                                                            
+    TGeoVolume* Layer1_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer1_SideS_Shape, pair);
+    TGeoVolume* Layer1_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer1_SideS_Abs_Base_Shape, piron);
+
+    Layer1_SideS_Vol->AddNode(Layer1_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, -1.75, rotNoRot));
+
+
+    Double_t Layer1_Envelope_startX = -1.0*Layer1_Sector_dx1;
+    Double_t Layer1_Envelope_shiftX = Layer1_Envelope_startX + widthEnv/2;
+
+    Double_t Layer1_length = 2*abs(Layer1_Envelope_startX);
+    cout<<"Layer #1 length: " << Layer1_length << endl;
+
+    int Nenvelopes = int(Layer1_length/widthEnv);
+    cout << "Number of MDT detector in Layer #1: " << Nenvelopes << endl;
+    for (UInt_t i=0; i<Nenvelopes; i++) {
+    //for (UInt_t i=0; i<1; i++) {
+
+        Layer1_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer1_Envelope_shiftX, 0, 1.75+thicknessEnv/2, rotNoRot)); 
+        Layer1_Envelope_shiftX = Layer1_Envelope_shiftX + widthEnv;
+    }
+
+    // Zero Bi-Layer Geometry (currently disabled) 
+    // Layer1_Envelope_shiftX = -60.0-0.5;
+    // Layer1_Envelope_shiftX = Layer1_Envelope_startX + widthEnv/2;
+
+    // Nenvelopes = 14;
+    // for (UInt_t i=0; i<Nenvelopes; i++) 
+    // {
+    // Layer1_SideS_Vol->AddNode(createMDT(493.0), i+15, new TGeoCombiTrans("", Layer1_Envelope_shiftX, 0, 1.2+thicknessEnv/2+thicknessEnv, rotNoRot)); 
+    // Layer1_Envelope_shiftX = Layer1_Envelope_shiftX + widthEnv;
+    // }
+
+
+    return Layer1_SideS_Vol;
+}
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createRegularLayer(Int_t layerN, Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing regular layer of the RS Barrel part
+// (3.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Number of layer in a sector
+//             2. Outer radius of RS from collision point (rsRadius);
+//             3. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 3.0+3.5; //cm
+
+    Double_t Sector_dy = rsLength/2.0;
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+    Double_t shiftZ = 3.5/2; //distance between layers is 35mm
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    TGeoRotation* rotZ180 = new TGeoRotation("rotZ180", 0., 0., 180.);
+    rotZ180->RegisterYourself();
+
+    Double_t Layer1_Sector_dz = layerThickness/2; // z-coord of the layer center 
+    Double_t Layer1_Sector_dx1 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN-2)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the bottom base
+    Double_t Layer1_Sector_dx2 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the top base
+    Double_t Layer1_Sector_dy = Sector_dy; // y-coord of the layer center
+    cout<<"Layer #"<< layerN << " dimensions (bottom base): ["
+        <<Layer1_Sector_dx1*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    cout<<"Layer #"<< layerN << " dimensions (top base): ["
+        <<Layer1_Sector_dx2*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    
+
+
+    TGeoTrd2* Layer1_SideS_Shape = new TGeoTrd2("Layer_SideS_Shape", 
+                                                1.0*Layer1_Sector_dx1, 
+                                                1.0*Layer1_Sector_dx2, 
+                                                Layer1_Sector_dy, 											 
+                                                Layer1_Sector_dy,
+                                                Layer1_Sector_dz);
+
+    TGeoBBox* Layer1_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        1.0*Layer1_Sector_dx1, 
+                                                        Layer1_Sector_dy, 
+                                                        3.0/2);
+                                                            
+    TGeoVolume* Layer1_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer1_SideS_Shape, pair);
+    TGeoVolume* Layer1_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer1_SideS_Abs_Base_Shape, piron);
+
+    Layer1_SideS_Vol->AddNode(Layer1_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, -1*Layer1_Sector_dz+3.0/2, rotNoRot));
+
+    if (layerN % 2 != 0) {
+        Double_t Layer1_Envelope_startX = Layer1_Sector_dx1;
+        Double_t Layer1_Envelope_shiftX = Layer1_Envelope_startX - widthEnv/2;
+
+        Double_t Layer1_length = 2*abs(Layer1_Envelope_startX);
+        cout<<"Layer #" << layerN << " length: " << Layer1_length << endl;
+
+        int Nenvelopes = int((Layer1_length - widthEnv/2)/widthEnv);
+        cout << "Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+        for (UInt_t i=0; i<Nenvelopes; i++) {
+
+            Layer1_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer1_Envelope_shiftX, 0, 0.75+thicknessEnv/2, rotNoRot)); 
+            Layer1_Envelope_shiftX = Layer1_Envelope_shiftX - widthEnv;
+        }
+    }
+    else {
+
+        Double_t Layer1_Envelope_startX = -1.0*abs(Layer1_Sector_dx1);
+        Double_t Layer1_Envelope_shiftX = Layer1_Envelope_startX + widthEnv/2;
+
+        Double_t Layer1_length = 2*abs(Layer1_Envelope_startX);
+        cout<<"Layer #" << layerN << " length: " << Layer1_length << endl;
+
+        int Nenvelopes = int((Layer1_length)/widthEnv);
+        cout << "Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+        for (UInt_t i=0; i<Nenvelopes; i++) {
+
+            Layer1_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer1_Envelope_shiftX, 0, 0.75+thicknessEnv/2, rotNoRot)); 
+            Layer1_Envelope_shiftX = Layer1_Envelope_shiftX + widthEnv;
+        }
+    }
+
+    return Layer1_SideS_Vol;
+}
+
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createTopLayer(Int_t layerN, Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing regular layer of the RS Barrel part
+// (3.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Number of layer in a sector
+//             2. Outer radius of RS from collision point (rsRadius);
+//             3. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 3.0+3.0; //cm
+
+    Double_t Sector_dy = rsLength/2.0;
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+    Double_t shiftZ = 3.5/2; //distance between layers is 35mm
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    TGeoRotation* rotZ180 = new TGeoRotation("rotZ180", 0., 0., 180.);
+    rotZ180->RegisterYourself();
+
+    Double_t Layer1_Sector_dz = layerThickness/2; // z-coord of the layer center 
+    Double_t Layer1_Sector_dx1 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the bottom base
+    Double_t Layer1_Sector_dx2 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the top base
+    Double_t Layer1_Sector_dy = Sector_dy; // y-coord of the layer center
+    cout<<"Layer #"<< layerN << " dimensions (bottom base): ["
+        <<Layer1_Sector_dx1*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    cout<<"Layer #"<< layerN << " dimensions (top base): ["
+        <<Layer1_Sector_dx2*2<<" x " 
+        << Layer1_Sector_dz*2 << " x " 
+        << Layer1_Sector_dy*2 << "] cm" << endl;
+    
+
+
+    TGeoTrd2* Layer1_SideS_Shape = new TGeoTrd2("Layer_SideS_Shape", 
+                                                1.0*Layer1_Sector_dx1, 
+                                                1.0*Layer1_Sector_dx2, 
+                                                Layer1_Sector_dy, 											 
+                                                Layer1_Sector_dy,
+                                                Layer1_Sector_dz);
+
+    TGeoBBox* Layer1_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        1.0*Layer1_Sector_dx1, 
+                                                        Layer1_Sector_dy, 
+                                                        Layer1_Sector_dz);
+                                                            
+    TGeoVolume* Layer1_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer1_SideS_Shape, pair);
+    TGeoVolume* Layer1_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer1_SideS_Abs_Base_Shape, piron);
+
+    Layer1_SideS_Vol->AddNode(Layer1_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+
+
+    return Layer1_SideS_Vol;
+}
+
+//_____________________________________________________________________________
+//
+void SPD_RS_Barrel_Flexible() {
+//_____________________________________________________________________________
+//
+// Main:
+// Creates a segment of Range System Barrel with a given number of layers
+// and fills each layer with MDT detectors.
+// Parameters: distance from collision point, barrel size.
+//_____________________________________________________________________________
+
+    gSystem->Load("libGeom");
+
+    TGeoManager* geoM = new TGeoManager("World", "Barrel");
+
+    //--- make the top container volume
+    TGeoVolume *top = new TGeoVolumeAssembly("RS_Barrel");
+    gGeoManager->SetTopVolume(top);
+
+
+    TGeoRotation* rotTest = new TGeoRotation("", 180., 90., 0.);
+    rotTest->RegisterYourself();
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    TGeoRotation* rotZ180 = new TGeoRotation("rotZ180", 0., 0., 180.);
+    rotZ180->RegisterYourself();
+
+    TGeoMaterial* mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium*   pair = new TGeoMedium("air",1,mat_air);
+
+    //top->AddNode(SideS_Vol, 1, new TGeoCombiTrans("", 0, 0, 45.0, rotTest));
+    //top->AddNode(SideS_Vol, 1);
+
+    //top->AddNode(L4930_Envelope_Vol, 1);
+    //top->AddNode(createMDT(493.0), 1);
+
+    // Fill top volume with Range System layers
+    // Parameters of the Range System size and position
+    Double_t rsRadius = 314.4; // cm (Outer radium of the Range System)
+    Double_t rsThickness = 139.0; //25.7; //139.0; // cm (Thickness of the Range System)
+    Double_t rsLength = 493.0; // cm (Length of the sector along beam axis)
+
+    TGeoTrd2* SideS_Shape = new TGeoTrd2("SideS_Shape", 
+									  (rsRadius - rsThickness)*(sqrt(2.0)-1.0), 
+									  (rsRadius )*(sqrt(2.0)-1.0), //1234 Fe without bilayer MDTs
+									  rsLength/2, 											 
+									  rsLength/2,
+									  rsThickness/2); //805 only Fe (without bilayer MDTs)
+    TGeoVolume* SideS_Vol = new TGeoVolume("SideS_Vol", SideS_Shape, pair);
+    cout<<"Layer #"<< (rsRadius - rsThickness)*(sqrt(2.0)-1.0) << " dimensions (bottom base): ["
+     << endl;
+    cout<<"Layer #"<< (rsRadius )*(sqrt(2.0)-1.0) << " dimensions (top base): ["
+    << endl;
+
+
+    // Number of layers calcluation within RS thickness:
+    // (Thickness - top absorber - bottom absorber/mdt)/LayerThickness + 1(bottom layer)
+    Int_t nLayers = int((rsThickness - 6. - 9.5)/6.5) + 1; 
+    cout << "# of Layers within " << rsThickness << " cm: " << nLayers << endl;
+
+    // Add bottom layer (absrober(6.0cm) + mdt detectors(3.5cm))
+    SideS_Vol->AddNode(createBottomLayer(rsRadius, rsThickness, rsLength), 1, 
+                 new TGeoCombiTrans("", 0, 0,  -1.*(rsThickness)/2 + 4.75, rotNoRot));
+    
+    // Add regular layers (3.0cm absorber + 3.5cm mdt detectors)
+//     for (Int_t i=2; i < nLayers+1; ++i) {   
+//         
+//         SideS_Vol->AddNode(createRegularLayer(i, rsRadius, rsThickness, rsLength), i, 
+//                     //new TGeoCombiTrans("", 0, 0, rsRadius - rsThickness + (i-1)*6.5, rotNoRot));
+//                     new TGeoCombiTrans("", 0, 0, -1.*(rsThickness)/2 + (i-1)*6.5 + 9.5 - 3.25, rotNoRot));
+//     }
+    // Add top absorber (6.0cm)
+    SideS_Vol->AddNode(createTopLayer(nLayers+1, rsRadius, rsThickness, rsLength), nLayers+1, 
+                new TGeoCombiTrans("", 0, 0, 1.0*(rsThickness)/2 - 6.0/2, rotNoRot));
+
+
+    top->AddNode(SideS_Vol,1);
+
+    gGeoManager->CloseGeometry();
+    top->SetLineColor(kMagenta);
+    //gGeoManager->SetTopVisible(); // the TOP is invisible
+    top->Draw();
+
+    //gGeoManager->CheckGeometry();
+    //gGeoManager->CheckGeometryFull();
+    //gGeoManager->Test();
+
+    TString outGeoFilenameRoot = "./Barrel_cm.root";
+    TFile* outGeoFileRoot = new TFile(outGeoFilenameRoot, "RECREATE");
+    geoM->GetTopVolume()->Write();
+    outGeoFileRoot->Close();
+
+}
+
+
+
+
diff --git a/macro/testmisc/SPD_RS_Barrel_Flexible2.C b/macro/testmisc/SPD_RS_Barrel_Flexible2.C
new file mode 100644
index 0000000000000000000000000000000000000000..1df4580524846ce4d28cf1ffb6abcb7a2a434d73
--- /dev/null
+++ b/macro/testmisc/SPD_RS_Barrel_Flexible2.C
@@ -0,0 +1,521 @@
+// $Id$
+// Author: georgy   2020/06/24
+
+//_____________________________________________________________________________
+//
+// Creates geometry of SPD RS Barrel segment and fills it with MDT detectors
+//_____________________________________________________________________________
+
+
+TGeoVolume* createMDT(Double_t length = 493.0) {
+//_____________________________________________________________________________
+//
+// Creates MDT of given length;
+// Envelope Dimensions(L x W x H): length x 8.5cm x 1.64cm.
+// Note: Adopted from Panda Muon System
+//_____________________________________________________________________________
+
+    // Medium description
+    TGeoMaterial* mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium*   pair = new TGeoMedium("air",1,mat_air);
+
+    TGeoMaterial* mat_mix = new TGeoMaterial("MDTMixture",0,0,0);
+    TGeoMedium*   pMDTMixture = new TGeoMedium("MDTMixture",1,mat_mix);
+
+    TGeoMaterial* mat_Al = new TGeoMaterial("Aluminium",0,0,0);
+    TGeoMedium*   paluminium = new TGeoMedium("Aluminium",1,mat_Al);
+
+//     TGeoMaterial* mat = new TGeoMaterial("Vacuum",0,0,0);
+//     TGeoMedium*   pvacuum = new TGeoMedium("Vacuum",1,mat);
+//    
+//     TGeoMaterial* mat_pvc = new TGeoMaterial("PVC",0,0,0);
+//     TGeoMedium*   pPVC = new TGeoMedium("PVC",1,mat_pvc);
+//    
+//     TGeoMaterial* mat_iron = new TGeoMaterial("iron",0,0,0);
+//     TGeoMedium*   piron = new TGeoMedium("iron",1,mat_iron);
+// 
+//     TGeoMaterial* mat_g10 = new TGeoMaterial("G10",0,0,0);
+//     TGeoMedium*   pg10 = new TGeoMedium("G10",1,mat_g10);
+// 
+//     TGeoMaterial* mat_copper = new TGeoMaterial("copper",0,0,0);
+//     TGeoMedium*   pcopper = new TGeoMedium("copper",1,mat_copper);
+
+    // Shapes and volumes ---------------------------------------------------------------
+    // General dimensions
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+    Double_t xSize = 1.0;
+
+    TString transName;
+    Int_t Nenvelopes;
+    Int_t IncEnv = 0;
+
+    //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    
+    Double_t empty_value = (2.0+2.0+8.5)+6.5*2;
+    Double_t L_MDT_Envelope = length; //493.0;
+    Double_t L_MDT_Envelope_sensitive = L_MDT_Envelope-empty_value;
+
+
+    Int_t ind = int(length*10);
+    //Shapes
+    //<box name="Indent20_PartBody" x="(42.500000)*2" y="(10.000000)*2" z="(8.200000)*2" lunit="mm"/>
+    TGeoBBox* Indent20_Shape = new TGeoBBox("Indent20_Shape", widthEnv/2,
+                                                            thicknessEnv/2,
+                                                            1.0);
+    //<box name="FEB_box_PartBody" x="(42.500000)*2" y="(42.500000)*2" z="(8.200000)*2" lunit="mm"/>
+    TGeoBBox* FEB_box_Shape = new TGeoBBox("FEB_box_Shape", widthEnv/2,
+                                                            thicknessEnv/2,
+                                                            widthEnv/2);
+    //<box name="DeadMat_PartBody" x="(40.700000)*2" y="(32.500000)*2" z="(5.150000)*2" lunit="mm"/>
+    TGeoBBox* DeadMat_Shape = new TGeoBBox("DeadMat_Shape", 4.07,
+                                                            0.515,
+                                                            3.25);
+    TGeoVolume* Indent20_Vol = new TGeoVolume("Indent20_Vol", Indent20_Shape, pair);
+    TGeoVolume* FEB_box_Vol = new TGeoVolume("FEB_box_Vol", FEB_box_Shape, pair);
+    TGeoVolume* DeadMat_Vol = new TGeoVolume("DeadMat_Vol", DeadMat_Shape, pMDTMixture);
+
+    //----------------------4930------------------------------------//
+    TGeoBBox* L_Al_A_Shape = new TGeoBBox(Form("L%d_Al_A_Shape",ind), 4.03,
+                                                                0.03,
+                                                                L_MDT_Envelope_sensitive/2);
+    TGeoBBox* L_Al_B_Shape = new TGeoBBox(Form("L%d_Al_B_Shape",ind), 0.03,
+                                                                0.42,
+                                                                L_MDT_Envelope_sensitive/2);
+    TGeoBBox* L_GasCell_Shape = new TGeoBBox(Form("L%d_GasCell_Shape",ind), 0.47,
+                                                                        0.46,
+                                                                        L_MDT_Envelope_sensitive/2);
+    TGeoBBox* L_Cell_Shape = new TGeoBBox(Form("L%d_Cell_Shape",ind), 0.5,
+                                                                0.46,
+                                                                L_MDT_Envelope_sensitive/2);
+    TGeoBBox* L_MDT_S_Shape = new TGeoBBox(Form("L%d_MDT_S_Shape",ind), 4.0,
+                                                                    0.46,
+                                                                    L_MDT_Envelope_sensitive/2);
+    TGeoBBox* L_Envelope_Shape = new TGeoBBox(Form("L%d_Envelope_Shape",ind), widthEnv/2,
+                                                                        thicknessEnv/2,
+                                                                        L_MDT_Envelope/2);
+                                                                                 
+    //Volumes
+    TGeoVolume* L_Al_A_Vol = new TGeoVolume(Form("L%d_Al_A_Vol",ind), L_Al_A_Shape, paluminium);
+    TGeoVolume* L_Al_B_Vol = new TGeoVolume(Form("L%d_Al_B_Vol",ind), L_Al_B_Shape, paluminium);
+    TGeoVolume* L_GasCell_Vol = new TGeoVolume(Form("L%d_GasCell_Vol",ind), L_GasCell_Shape, pMDTMixture);
+    TGeoVolume* L_Cell_Vol = new TGeoVolume(Form("L%d_Cell_Vol",ind), L_Cell_Shape, pMDTMixture);
+    TGeoVolume* L_MDT_S_Vol = new TGeoVolume(Form("L%d_MDT_S_Vol",ind), L_MDT_S_Shape, pMDTMixture);
+    TGeoVolume* L_Envelope_Vol = new TGeoVolume(Form("L%d_Envelope_Vol",ind), L_Envelope_Shape, pair);
+   
+    // Volume hierarchy -----------------------------------------------------------------
+    //Structure
+    //GasCell and Al_B in Cell
+    L_Cell_Vol->AddNode(L_GasCell_Vol, 1,
+                            new TGeoCombiTrans("", -0.03, 0, 0, rotNoRot));
+    L_Cell_Vol->AddNode(L_Al_B_Vol, 1,
+                            new TGeoCombiTrans("", 0.47, -0.04, 0, rotNoRot));
+
+    //8 Cells in MDT_S
+    for (UInt_t i=0; i<8; i++) {
+        transName.Form("trans_cell_%d", i);
+        TGeoCombiTrans* trans1 = new TGeoCombiTrans(transName.Data(), -4.0 + xSize/2. + (Double_t)i*xSize, 0, 0., rotNoRot);
+        trans1->RegisterYourself();
+        L_MDT_S_Vol->AddNode(L_Cell_Vol, i+1, trans1);
+    }
+
+    L_Envelope_Vol->AddNode(Indent20_Vol, 1,
+                                new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2 - 1.0, rotNoRot));
+    L_Envelope_Vol->AddNode(Indent20_Vol, 2,
+                                new TGeoCombiTrans("", 0, 0, 1.0 - L_MDT_Envelope/2, rotNoRot));
+    L_Envelope_Vol->AddNode(FEB_box_Vol, 1,
+                                new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2-2.0-8.5*0.5, rotNoRot));
+    L_Envelope_Vol->AddNode(DeadMat_Vol, 1,
+                                new TGeoCombiTrans("", 0, 0, ((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+    L_Envelope_Vol->AddNode(DeadMat_Vol, 2,
+                                new TGeoCombiTrans("", 0, 0, -((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+    L_Envelope_Vol->AddNode(L_Al_A_Vol, 1,
+                                new TGeoCombiTrans("", 0, -0.36, -widthEnv/2, rotNoRot));
+    L_Envelope_Vol->AddNode(L_Al_B_Vol, 1,
+                                new TGeoCombiTrans("", -4.0, 0.09, -widthEnv/2, rotNoRot));
+    L_Envelope_Vol->AddNode(L_MDT_S_Vol, 1,
+                                new TGeoCombiTrans("", 0.03, 0.13, -widthEnv/2, rotNoRot));                                                          
+    //----------------------4930------------------------------------//
+
+    return L_Envelope_Vol;
+}
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createBottomLayer(Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing bottom layer of the RS Barrel part
+// (6.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Outer radius of RS from collision point (rsRadius);
+//             2. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 6.0+3.5; //cm
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    
+    Double_t v_bottom[16];
+    Double_t lmin = (rsRadius - rsThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+    Double_t lmax = (rsRadius - rsThickness + layerThickness)*(sqrt(2.0)-1.0); // dimensions (top base)
+    Double_t hmin = (rsRadius - rsThickness); 
+    Double_t hmax = (rsRadius - rsThickness + layerThickness);
+
+    cout<<"lmin: "<<lmin<<endl;
+    cout<<"lmax: "<<lmax<<endl;
+    cout<<"hmin: "<<hmin<<endl;
+    cout<<"hmax: "<<hmax<<endl;
+  
+    v_bottom[0] =  lmin; v_bottom[1] = hmin;
+    v_bottom[2] = -lmin; v_bottom[3] = hmin;
+    v_bottom[4] = -lmax; v_bottom[5] = hmax;
+    v_bottom[6] =  lmax; v_bottom[7] = hmax;
+  
+    v_bottom[8]  =  lmin; v_bottom[9]  = hmin;
+    v_bottom[10] = -lmin; v_bottom[11] = hmin;
+    v_bottom[12] = -lmax; v_bottom[13] = hmax;
+    v_bottom[14] =  lmax; v_bottom[15] = hmax;
+
+    TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_bottom);
+
+    Double_t Layer_Sector_Abs_dx = lmin;
+    Double_t Layer_Sector_Abs_dy = 6./2;
+    Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+
+    cout<<"Layer_SideS_Abs_Base_Shape: "<<2*Layer_Sector_Abs_dx<<"   "<<2*Layer_Sector_Abs_dy<<"  "<<2*Layer_Sector_Abs_dz<<endl;
+
+    
+    TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        Layer_Sector_Abs_dx, 
+                                                        Layer_Sector_Abs_dy, 
+                                                        Layer_Sector_Abs_dz);
+                                                            
+    TGeoVolume* Layer_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer_SideS_Shape, pair);
+    TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer_SideS_Abs_Base_Shape, piron);
+
+    Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+
+
+    Double_t Layer_Envelope_startX = -1.0*lmin;
+    Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+
+    Double_t Layer_length = 2*abs(Layer_Envelope_startX);
+    cout<<"Layer #1 length: " << Layer_length << endl;
+
+    int Nenvelopes = int(Layer_length/widthEnv);
+    cout << "Number of MDT detector in Layer #1: " << Nenvelopes << endl;
+
+    
+    for (UInt_t i=0; i<Nenvelopes; i++) {
+    //for (UInt_t i=0; i<1; i++) {
+
+        Layer_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin+6+3.5/2, 0, rotNoRot)); 
+        Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+    }
+
+    return Layer_SideS_Vol;
+}
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createRegularLayer(Int_t layerN, Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing regular layer of the RS Barrel part
+// (3.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Number of layer in a sector
+//             2. Outer radius of RS from collision point (rsRadius);
+//             3. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 3.0+3.5; //cm
+
+    Double_t Sector_dy = rsLength/2.0;
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    
+    Double_t Layer_Sector_dz = layerThickness/2; // z-coord of the layer center 
+    Double_t Layer_Sector_dx1 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN-2)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the bottom base
+    Double_t Layer_Sector_dx2 = 1.0*(rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the top base
+    Double_t Layer_Sector_dy = Sector_dy; // y-coord of the layer center
+    cout<<"Layer #"<< layerN << " dimensions (bottom base): ["
+        <<Layer_Sector_dx1*2<<" x " 
+        << Layer_Sector_dz*2 << " x " 
+        << Layer_Sector_dy*2 << "] cm" << endl;
+    cout<<"Layer #"<< layerN << " dimensions (top base): ["
+        <<Layer_Sector_dx2*2<<" x " 
+        << Layer_Sector_dz*2 << " x " 
+        << Layer_Sector_dy*2 << "] cm" << endl;
+    
+    Double_t v_regular[16];
+    Double_t lmin = (rsRadius - rsThickness + 9.5 + (layerN-2)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+    Double_t lmax = (rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (top base)
+    Double_t hmin = (rsRadius - rsThickness + 9.5 + (layerN-2)*layerThickness); 
+    Double_t hmax = (rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness);
+
+    cout<<"Layer #"<< layerN << " dimensions (bottom base, lmin): [" << -lmin << "," << lmin << "]" << endl;
+    cout<<"Layer #"<< layerN << " dimensions (bottom base, lmax): [" << -lmax << "," << lmax << "]" << endl;
+    cout<<"hmin: "<<hmin<<endl;
+    cout<<"hmax: "<<hmax<<endl;
+  
+    v_regular[0] =  lmin; v_regular[1] = hmin;
+    v_regular[2] = -lmin; v_regular[3] = hmin;
+    v_regular[4] = -lmax; v_regular[5] = hmax;
+    v_regular[6] =  lmax; v_regular[7] = hmax;
+  
+    v_regular[8]  =  lmin; v_regular[9]  = hmin;
+    v_regular[10] = -lmin; v_regular[11] = hmin;
+    v_regular[12] = -lmax; v_regular[13] = hmax;
+    v_regular[14] =  lmax; v_regular[15] = hmax;
+
+    TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_regular);
+
+    Double_t Layer_Sector_Abs_dx = lmin;
+    Double_t Layer_Sector_Abs_dy = 3./2;
+    Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+
+    TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        Layer_Sector_Abs_dx, 
+                                                        Layer_Sector_Abs_dy, 
+                                                        Layer_Sector_Abs_dz);
+   
+                                                            
+    TGeoVolume* Layer_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer_SideS_Shape, pair);
+    TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer_SideS_Abs_Base_Shape, piron);
+
+    Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+
+    if (layerN % 2 == 0) {
+        Double_t Layer_Envelope_startX = lmin;
+        Double_t Layer_Envelope_shiftX = Layer_Envelope_startX - widthEnv/2;
+
+        Double_t Layer_length = 2*abs(Layer_Envelope_startX);
+        cout<<"Layer #" << layerN << " length: " << Layer_length << endl;
+
+        int Nenvelopes = int((Layer_length)/widthEnv);
+        cout << "Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+        for (UInt_t i=0; i<Nenvelopes; i++) {
+
+            Layer_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin + 3 + 3.5/2, 0, rotNoRot)); 
+            Layer_Envelope_shiftX = Layer_Envelope_shiftX - widthEnv;
+        }
+    }
+    else {
+
+        Double_t Layer_Envelope_startX = -1.0*abs(lmin);
+        Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+
+        Double_t Layer_length = 2*abs(Layer_Envelope_startX);
+        cout<<"Layer #" << layerN << " length: " << Layer_length << endl;
+
+        int Nenvelopes = int((Layer_length)/widthEnv);
+        cout << "Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+        for (UInt_t i=0; i<Nenvelopes; i++) {
+
+            Layer_SideS_Vol->AddNode(createMDT(493.0), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin + 3 + 3.5/2, 0, rotNoRot)); 
+            Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+        }
+    }
+
+    return Layer_SideS_Vol;
+}
+
+
+//_____________________________________________________________________________
+//
+TGeoVolume* createTopLayer(Int_t layerN, Double_t rsRadius, Double_t rsThickness, Double_t rsLength) {
+//_____________________________________________________________________________
+//
+// Creates trapezoid representing regular layer of the RS Barrel part
+// (3.0cm thick iron absorber and a layer of MDT detectors)
+// Parameters: 1. Number of layer in a sector
+//             2. Outer radius of RS from collision point (rsRadius);
+//             3. Thickness of RS rsThickness.
+// Returns: TGeoVolume object of the layer with absorber and MDTs.
+//_____________________________________________________________________________
+
+    Double_t layerThickness = 3.0+3.0; //cm
+
+    Double_t Sector_dy = rsLength/2.0;
+
+    Double_t widthEnv = 8.5; //cm xAxis
+    Double_t thicknessEnv = 1.64; //cm zAxis
+
+    TGeoMaterial *mat_iron = new TGeoMaterial("iron",0,0,0);
+    TGeoMedium   *piron = new TGeoMedium("iron",1,mat_iron);
+
+    TGeoMaterial *mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium   *pair = new TGeoMedium("air",1,mat_air);
+
+     //Matrices
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    
+    Double_t v_top[16];
+    Double_t lmin = (rsRadius - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+    Double_t lmax = (rsRadius - rsThickness + 9.5 + (layerN)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (top base)
+    Double_t hmin = (rsRadius - rsThickness + 9.5 + (layerN-2)*6.5); 
+    Double_t hmax = (rsRadius - rsThickness + 9.5 + (layerN-2)*6.5 + layerThickness);
+
+    cout<<"Layer #"<< layerN << " dimensions (bottom base, lmin): [" << -lmin << "," << lmin << "]" << endl;
+    cout<<"Layer #"<< layerN << " dimensions (bottom base, lmax): [" << -lmax << "," << lmax << "]" << endl;
+    cout<<"hmin: "<<hmin<<endl;
+    cout<<"hmax: "<<hmax<<endl;
+  
+    v_top[0] =  lmin; v_top[1] = hmin;
+    v_top[2] = -lmin; v_top[3] = hmin;
+    v_top[4] = -lmax; v_top[5] = hmax;
+    v_top[6] =  lmax; v_top[7] = hmax;
+  
+    v_top[8]  =  lmin; v_top[9]  = hmin;
+    v_top[10] = -lmin; v_top[11] = hmin;
+    v_top[12] = -lmax; v_top[13] = hmax;
+    v_top[14] =  lmax; v_top[15] = hmax;
+
+    TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_top);
+
+    Double_t Layer_Sector_Abs_dx = lmin;
+    Double_t Layer_Sector_Abs_dy = layerThickness/2;
+    Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+
+    TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                        Layer_Sector_Abs_dx, 
+                                                        Layer_Sector_Abs_dy, 
+                                                        Layer_Sector_Abs_dz);
+   
+                                                            
+    TGeoVolume* Layer_SideS_Vol = new TGeoVolume("Layer_SideS_Vol", Layer_SideS_Shape, pair);
+    TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("Layer_SideS_Abs_Base_Vol", Layer_SideS_Abs_Base_Shape, piron);
+
+    Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+
+    return Layer_SideS_Vol;
+}
+
+//_____________________________________________________________________________
+//
+void SPD_RS_Barrel_Flexible2() {
+//_____________________________________________________________________________
+//
+// Main:
+// Creates a segment of Range System Barrel with a given number of layers
+// and fills each layer with MDT detectors.
+// Parameters: distance from collision point, barrel size.
+//_____________________________________________________________________________
+
+    gSystem->Load("libGeom");
+
+    TGeoManager* geoM = new TGeoManager("World", "Barrel");
+
+    //--- make the top container volume
+    TGeoVolume *top = new TGeoVolumeAssembly("RS_Barrel");
+    gGeoManager->SetTopVolume(top);
+
+
+    TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+    rotNoRot->RegisterYourself();
+    
+    TGeoMaterial* mat_air = new TGeoMaterial("air",0,0,0);
+    TGeoMedium*   pair = new TGeoMedium("air",1,mat_air);
+
+    //top->AddNode(SideS_Vol, 1);
+
+    //top->AddNode(L4930_Envelope_Vol, 1);
+    
+    // Fill top volume with Range System layers
+    // Parameters of the Range System size and position
+    Double_t rsRadius = 314.4; // cm (Size of the Range System)
+    Double_t rsThickness = 139.0; //25.7; //139.0; // cm (Thickness of the Range System)
+    Double_t rsLength = 493.0; // cm (Length of the sector along beam axis)
+
+    Double_t v[16];
+    Double_t lmin = (rsRadius - rsThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+    Double_t lmax = (rsRadius )*(sqrt(2.0)-1.0); // dimensions (top base)
+    Double_t hmin = (rsRadius-rsThickness); 
+    Double_t hmax = rsRadius;
+  
+    v[0] =  lmin; v[1] = hmin;
+    v[2] = -lmin; v[3] = hmin;
+    v[4] = -lmax; v[5] = hmax;
+    v[6] =  lmax; v[7] = hmax;
+  
+    v[8]  =  lmin; v[9]  = hmin;
+    v[10] = -lmin; v[11] = hmin;
+    v[12] = -lmax; v[13] = hmax;
+    v[14] =  lmax; v[15] = hmax;
+
+    TGeoArb8* SideS_Shape = new TGeoArb8("SideS_Shape", rsLength/2, v);
+    TGeoVolume* SideS_Vol = new TGeoVolume("SideS_Vol", SideS_Shape, pair);
+
+    // Number of layers calcluation within RS thickness:
+    // (Thickness - top absorber - bottom absorber/mdt)/LayerThickness + 1(bottom layer)
+    Int_t nLayers = int((rsThickness - 6. - 9.5)/6.5) + 1; 
+    cout << "# of Layers within " << rsThickness << " cm: " << nLayers << endl;
+
+    cout<<"Layer #"<< (rsRadius - rsThickness)*(sqrt(2.0)-1.0) << " dimensions (bottom base): ["
+     << endl;
+    cout<<"Layer #"<< (rsRadius )*(sqrt(2.0)-1.0) << " dimensions (top base): ["
+    << endl;
+
+    // Add bottom layer (absrober(6.0cm) + mdt detectors(3.5cm))
+    SideS_Vol->AddNode(createBottomLayer(rsRadius, rsThickness, rsLength), 1, 
+                 new TGeoCombiTrans("",  0, 0, 0, rotNoRot));
+        
+    // Add regular layers (3.0cm absorber + 3.5cm mdt detectors)
+
+    for (Int_t i=2; i < nLayers+1; ++i) {   
+        SideS_Vol->AddNode(createRegularLayer(i, rsRadius, rsThickness, rsLength), i, 
+                    new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+    }
+
+    // Add top absorber (6.0cm)
+    SideS_Vol->AddNode(createTopLayer(nLayers+1, rsRadius, rsThickness, rsLength), nLayers+1, 
+                new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+
+
+    top->AddNode(SideS_Vol,1);
+    //top->AddNode(createMDT(493.0), 1);
+    gGeoManager->CloseGeometry();
+    top->SetLineColor(kMagenta);
+    //gGeoManager->SetTopVisible(); // the TOP is invisible
+    top->Draw();
+
+    //gGeoManager->CheckGeometry();
+    //gGeoManager->CheckGeometryFull();
+    //gGeoManager->Test();
+
+    TString outGeoFilenameRoot = "./Barrel_cm.root";
+    TFile* outGeoFileRoot = new TFile(outGeoFilenameRoot, "RECREATE");
+    geoM->GetTopVolume()->Write();
+    outGeoFileRoot->Close();
+
+}
diff --git a/macro/testmisc/check_tor.C b/macro/testmisc/check_tor.C
index 6eeb15500eaa866a45f56a6bd07ba67d83e5a9ae..2d05b7cb4f6c04deb71d66b45a1d95b326c2dcfe 100644
--- a/macro/testmisc/check_tor.C
+++ b/macro/testmisc/check_tor.C
@@ -136,6 +136,7 @@ void MakeBarrel(const char* name, TGeoMedium* med,
   }
 }
 
+
 //________________________________________________________________________________
 void MakeBarrel_1(const char* name_c, const char* name_s, TGeoMedium* med, int nsec, 
                   double dz, double hmin_c, double hmin_s, double hmax, 
diff --git a/macro/tracking/CheckFittedTracks.C b/macro/tracking/CheckFittedTracks.C
index d72aa37e9428d9ecf7051747b11261b5903025de..663fc73e95619e5ab91c4c20e722fe75117e1503 100644
--- a/macro/tracking/CheckFittedTracks.C
+++ b/macro/tracking/CheckFittedTracks.C
@@ -12,15 +12,16 @@ TTree* Tree_ = 0;
 
 void check_KFres();
 void check_geometry();
-void check_tracks(Int_t nevent = 0);
 
 TString inFile, inParFile;
 
 //______________________________________________________________________________
-void CheckFittedTracks() 
+void CheckFittedTracks(TString path = "") 
 {
-  inFile = "IdealFittedTracks.root";   
-  inParFile = "params_tor.root";
+  if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
+    
+  inFile    = path + "IdealFittedTracks.root";   
+  inParFile = path + "params_tor.root";
   
   TFile* f = new TFile(inFile);
   if (!f) return;
@@ -63,7 +64,7 @@ void check_KFres() {
    for (int j(0); j < entries; j++)   {
         branch->GetEntry(j);
         cout << "\n------------------------------------------------------------------------------\n";
-        Res->PrintData(0);  // 0(default), 1, 2
+        Res->PrintData(2);  // 0(default), 1, 2
         if (Res->IsWellFittedEvent()) NWellFittedEvents++;
         Res->ClearData();
    }
@@ -84,50 +85,3 @@ void check_geometry()
    gGeoManager->GetMasterVolume()->Draw("ogl");  
 }
 
-//______________________________________________________________________________
-void check_tracks(Int_t nevent)
-{
-   if (!Tree_) return;  
-   
-   TBranch* branch = Tree_->GetBranch("genfit::Track");
-   if (!branch) return;
-   
-   int entries = branch->GetEntries();
-   
-   if (nevent < 0 || nevent >= entries) return;
-      
-   TClonesArray *fT = 0; 
-   Tree_->SetBranchAddress("genfit::Track",&fT) ; 
-   
-   branch->GetEntry(nevent);  
-   
-   genfit::Track* track = 0;
-   
-   Int_t ntr = fT->GetEntriesFast();
-   
-   cout << "event = " << nevent << " tracks = " << ntr << endl;
-  
-   for (Int_t i(0); i<ntr; i++) {
-       track = (genfit::Track*)fT->At(i);
-       cout << i << " track " << track << endl;
-       //if (track && i == 4) track->Print();
-   }
-   
-   //genfit::EventDisplay* display = genfit::EventDisplay::getInstance();
-   
-   //genfit::Track* trackX = new genfit::Track();
-   //*trackX = *(genfit::Track*)fT->At(3);
-   
-   //track = (genfit::Track*)fT->At(0);
-   //track->fillPointsWithMeasurement();
-   //track->checkConsistency();
-   
-   //track->Print();
-   
-   //display->addEvent(track);
-   
-   //display->open();
-}
-
-
-
diff --git a/macro/tracking/CheckFittedTracks_1.C b/macro/tracking/CheckFittedTracks_1.C
new file mode 100644
index 0000000000000000000000000000000000000000..5cf89e5b4654bc3fc62430c555cbc86c4b3385a2
--- /dev/null
+++ b/macro/tracking/CheckFittedTracks_1.C
@@ -0,0 +1,423 @@
+#include <TFile.h>
+#include <TTree.h>
+#include <Riostream.h>
+#include <TGeoManager.h>
+#include <TClonesArray.h>
+#include "FairGeoParSet.h"
+#include "SpdKFSimpleRes.h"
+#include "SpdBaseParSet.h"
+#include <vector>
+#include <TStyle.h>
+#include <TCanvas.h>
+#include <TH1D.h>
+#include <TH2D.h>
+#include <TProfile.h>
+#include <TProfile2D.h>
+
+TTree* Tree_ = 0;
+
+void check_KFres();
+void check_geometry();
+
+TString inFile, inParFile;
+
+//______________________________________________________________________________
+void CheckFittedTracks_1(TString path = "") 
+{
+   if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
+    
+   inFile    = path + "IdealFittedTracks.root";   
+   inParFile = path + "params_tor.root";
+   
+   TFile* fp = new TFile(inParFile);
+   if (fp) {
+      SpdPassiveGeoParSet* passive_pars = (SpdPassiveGeoParSet*)fp->Get("PassiveGeoParSet");
+      if (passive_pars) passive_pars->print(1);  
+      fp->Close();
+   }
+   
+   TFile* f = new TFile(inFile);
+   if (!f) return;
+   
+   Tree_ = (TTree*)f->Get("cbmsim");  
+   if (!Tree_) return;
+ 
+   SpdBaseParSet* pars = (SpdBaseParSet*)f->Get("IdealKalmanFitterParams");
+   if (pars) pars->print(1);
+   
+   cout << "\n>>>>>>>>>>>>>>>> DATA FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;  
+   
+   check_KFres();
+}
+
+//-----------------------------------------------------------------------------
+Bool_t AcceptTrack(SpdKFSimpleRes* res, Int_t ntrack) 
+{
+   
+    //if (res->GetIsFitted(ntrack))
+    //if (res->GetIsFullyConvergent(ntrack))    
+    //if (res->HasNoErrors(ntrack))         
+    if (res->GetIsGood(ntrack)) 
+    //if (res->GetMCPtheta(ntrack) > 25.  &&  res->GetMCPtheta(ntrack) < 155.)
+    //if (res->GetMCPtheta(ntrack) > 100. ||  res->GetMCPtheta(ntrack) < 80.)    
+    {
+        return true;
+    }
+
+    return false;    
+}
+
+//______________________________________________________________________________
+void check_KFres() 
+{
+   if (!Tree_) return;  
+   
+   TBranch* branch = Tree_->GetBranch("SpdKFSimpleRes.");
+   if (!branch) return;
+   
+   int entries = branch->GetEntries();
+   
+   cout << "Total number of ENTRIES in the TREE = " << entries << endl;    
+   
+   if (entries == 0) return;
+   
+   SpdKFSimpleRes* Res = 0;
+   
+   Tree_->SetBranchAddress("SpdKFSimpleRes.",&Res) ;       
+
+   Int_t NWellFittedEvents = 0;
+   Int_t NTotalTracks = 0;
+   Int_t NWellFittedTracks = 0;
+   Int_t ntracks = 0;
+   
+   TH1D* hN = new TH1D("Multiplicity (mc)","n_{tracks}/event (mc)",25,0,25);
+   TH1D* hn = new TH1D("Multiplicity (mc,selected)","n_{tracks}/event (mc)",25,0,25);
+   
+   TH1D* hchi2ndf = new TH1D("chi2/ndf","#chi^{2}/ndf ",100,0,2);
+   
+   // seed values
+   TH1D* hp  = new TH1D("p (mc)","p (mc)",100,0,10);
+   TH1D* hpt = new TH1D("pt (mc)","p_{T} (mc)",100,0,5);
+   TH1D* hpz = new TH1D("pz (mc)","p_{z} (mc)",100,-10,10);
+   TH1D* hth = new TH1D("theta (mc)","#theta (mc)",180,0,180);
+   TH1D* hfi = new TH1D("phi (mc)","#phi (mc)",180,-180,180);
+   
+   // resolution
+   TH1D* hpr   = new TH1D("dp/p","|dp|/p",50,0,1);
+   TH1D* hptr  = new TH1D("dpt/pt","|dp_{T}|/p_{T}",50,0,1);
+   TH1D* hpzr  = new TH1D("dpz/pz","|dp_{z}/p_{z}|",50,0,1);
+   TH1D* hthr  = new TH1D("dtheta","|d#theta|",180,0,45);
+   TH1D* hfir  = new TH1D("dphi","|d#phi|",180,0,180);
+
+   // dp/p
+   TProfile*   hppr   = new TProfile("dp/p vs. p "," |dp|/p vs. p ",20,0,10, 0,1.0);
+   TProfile*   hpthr  = new TProfile("dp/p vs. theta"," |dp|/p vs. #theta",60,0,180, 0,1.0);
+   TProfile*   hpfir  = new TProfile("dp/p vs. phi"," |dp|/p vs. #phi",90,-180,180, 0,1.0);
+   TProfile2D* hhppth = new TProfile2D("dp/p(theta,p)","|dp|/p (#theta,p)", 40,0,180, 40,0,10, 0,0.1);
+   
+   // dpt/pt
+   TProfile*   hptpr   = new TProfile("dpt/pt vs. p "," |dp_{T}|/p_{T} vs. p ",20,0,10, 0,1.0);
+   TProfile*   hptthr  = new TProfile("dpt/pt vs. theta"," |dp_{T}|/p_{T} vs. #theta",60,0,180, 0,1.0); 
+   TProfile*   hptfir  = new TProfile("dpt/pt vs. phi"," |dp_{T}|/p_{T} vs. #phi",90,-180,180, 0,1.0);
+   TProfile2D* hhptpth = new TProfile2D("dpt/pt(theta,p)","|dp_{T}|/p_{T} (#theta,p)", 40,0,180, 40,0,10, 0,0.1);
+   
+   // dpz/pz
+   TProfile*   hpzpr   = new TProfile("dpz/pz vs. p "," |dp_{z}/p_{z}| vs. p ",20,0,10, 0,1.0);
+   TProfile*   hpzthr  = new TProfile("dpz/pz vs. theta"," |dp_{z}/p_{z}| vs. #theta",60,0,180, 0,1.0);
+   TProfile*   hpzfir  = new TProfile("dpz/pz vs. phi"," |dp_{z}|/p_{z} vs. #phi",90,-180,180, 0,1.0);
+   TProfile2D* hhpzpth = new TProfile2D("dpz/p(theta,p})","|dp_{z}/p_{z}| (#theta,p)", 40,0,180, 40,0,10, 0,0.1);
+   
+   // dtheta
+   TProfile*   hthpr   = new TProfile("dtheta vs. p ","|d#theta| vs. p ",20,0,1, 0,1.0);
+   TProfile*   hththr  = new TProfile("dtheta vs. theta"," |d#theta| vs. #theta",60,0,180, 0,1.0);
+   TProfile*   hthfir  = new TProfile("dtheta vs. phi"," |d#theta| vs. #phi",90,-180,180, 0,1.0);
+   TProfile2D* hhthpth = new TProfile2D("d#theta(theta,p)","|d#theta}| (#theta,p)", 40,0,180, 40,0,10, 0,0.1);
+   
+   //chisquare
+   TProfile2D* hhchi2pth = new TProfile2D("chisquare(theta,p)","#chi^{2} (#theta,p)", 100,0,180, 100,0,10, 0,2.);
+   TProfile*   hchi2pr   = new TProfile("chisquare vs. dp/p","#chi^{2} vs. |dp|/p", 50,0,0.1, 0,2);
+   TProfile*   hchi2ptr  = new TProfile("chisquare vs. dpt/pt","#chi^{2} vs. |dp_{T}|/p_{T}", 50,0,0.1, 0,2);
+   TProfile*   hchi2pzr  = new TProfile("chisquare vs. dpz/pz","#chi^{2} vs. |dp_{z}/p_{z}|", 50,0,0.1, 0,2);
+   TProfile*   hchi2thr  = new TProfile("chisquare vs. d#theta","#chi^{2} vs. |d#theta|", 50,0,5., 0,2);
+   
+   // additional
+   TProfile*   hpptr  = new TProfile("dp/p vs. pt"," |dp|/p vs. p_{T}",20,0, 5, 0,1.0);
+   TProfile*   hppzr  = new TProfile("dp/p vs. pz"," |dp|/p vs. |p_{z}|",20,0,10, 0,1.0);
+   TProfile*   hptptr = new TProfile("dpt/pt vs. pt"," |dp_{T}|/p_{T} vs. p_{T}",20,0, 5, 0,1.0);
+   TProfile*   hptpzr = new TProfile("dpt/pt vs. pz"," |dp_{T}|/p_{T} vs. |p_{z}|",20,0,10, 0,1.0);
+   TProfile*   hpzptr = new TProfile("dpz/pz vs. pt"," |dp_{z}/p_{z}| vs. p_{T}",20,0, 5, 0,1.0);
+   TProfile*   hpzpzr = new TProfile("dpz/pz vs. pz"," |dp_{z}/p_{z}| vs. |p_{z}|",20,0,10, 0,1.0);
+ 
+   // vertex 
+   TH1D* hvr    = new TH1D("Vertex: r (mc)","Vertex:  r (mc)",100,0,3.0);
+   TH1D* hvdr   = new TH1D("Vertex: dr","Vertex: |dr| ",100,0,1.); 
+   TH1D* hvz    = new TH1D("Vertex: Z (mc)","Vertex: Z (mc)",100,-2.5,2.5);
+   TH1D* hvdz   = new TH1D("Vertex: dZ","Vertex: dZ ",200,-1,1); 
+   TH1D* hvrt   = new TH1D("Vertex: rt","Vertex: r_{T} ",100,0,0.071);  // 0.071 = ~Sqrt(2*0.05*0.05)
+   TH1D* hvdphi = new TH1D("Vertex: dphi","Vertex: |d#phi_{r}| ",180,0,180); 
+   
+   // hits
+   TH1D* hitsh   = new TH1D("itsNH","Its hits/track",10,0,10);
+   TH1D* htstbh  = new TH1D("tstbNH","TsTB hits/track",120,0,120);
+   TH1D* htstech = new TH1D("tstecNH","TsTEC hits/track",75,0,75);
+   TH1D* htotalh = new TH1D("totalNH","Total hits/track",140,0,140);
+   
+   TProfile2D* hpthh      = new TProfile2D("nh/track(theta,p)","total: hits/track(#theta,p)", 90,0,180, 90,0,10, 0,150);
+   TProfile2D* hitspthh   = new TProfile2D("its nh/track(theta,p)","its: hits/track(#theta,p)", 90,0,180, 90,0,10, 0,150);
+   TProfile2D* htstbpthh  = new TProfile2D("tstb nh/track(theta,p)","tstb: hits/track(#theta,p)", 90,0,180, 90,0,10, 0,150);
+   TProfile2D* htstecpthh = new TProfile2D("tstec nh/track(theta,p)","tstec: hits/track(#theta,p)", 90,0,180, 90,0,10, 0,150);
+    
+   for (int j(0); j < entries; j++) {
+        
+        branch->GetEntry(j);
+        //cout << "\n------------------------------------------------------------------------------\n";
+        
+        //Res->PrintData(1);  // 0(default) or 1
+        
+        if (Res->IsWellFittedEvent()) NWellFittedEvents++;
+        //else continue;
+        
+        ntracks = Res->GetNTracks();
+        NTotalTracks += ntracks;
+        
+        Int_t nm(0);
+        
+        for (Int_t i(0); i<ntracks; i++) {
+             if (AcceptTrack(Res,i))  
+             { 
+                 NWellFittedTracks++;
+                 
+                 hchi2ndf->Fill(Res->GetChi2toNDF(i));
+                 
+                 // seed values
+                 hp->Fill(Res->GetMomentumMC(i));
+                 hth->Fill(Res->GetMCPtheta(i));
+                 hfi->Fill(Res->GetMCPphi(i));
+                 hpt->Fill(Res->GetMCPt(i));
+                 hpz->Fill(Res->GetMCPz(i));
+                 
+                 // resolution
+                 hpr->Fill(Res->GetMomRes(i));
+                 hptr->Fill(Res->GetPtRes(i));
+                 hpzr->Fill(Res->GetPzRes(i));
+                 hthr->Fill(Res->GetDTheta(i));
+                 hfir->Fill(Res->GetDPhi(i));
+           
+                 // dp/p
+                 hppr->Fill(Res->GetMomentumMC(i),Res->GetMomRes(i),1);
+                 hpthr->Fill(Res->GetMCPtheta(i),Res->GetMomRes(i),1);
+                 hpfir->Fill(Res->GetMCPphi(i),Res->GetMomRes(i),1);
+                 hhppth->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetMomRes(i));
+                 
+                 // dpt/pt
+                 hptpr->Fill(Res->GetMomentumMC(i),Res->GetPtRes(i),1);
+                 hptthr->Fill(Res->GetMCPtheta(i),Res->GetPtRes(i),1);
+                 hptfir->Fill(Res->GetMCPphi(i),Res->GetPtRes(i),1);
+                 hhptpth->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetPtRes(i));
+             
+                 // dpz/pz
+                 hpzpr->Fill(Res->GetMomentumMC(i),Res->GetPzRes(i),1);
+                 hpzthr->Fill(Res->GetMCPtheta(i),Res->GetPzRes(i),1);
+                 hpzfir->Fill(Res->GetMCPphi(i),Res->GetPzRes(i),1);
+                 hhpzpth->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetPzRes(i));
+ 
+                 // dtheta
+                 hthpr->Fill(Res->GetMomentumMC(i),Res->GetDTheta(i),1);
+                 hththr->Fill(Res->GetMCPtheta(i),Res->GetDTheta(i),1);
+                 hthfir->Fill(Res->GetMCPphi(i),Res->GetDTheta(i),1);
+                 hhthpth->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetDTheta(i));
+                                  
+                 // chisquare
+                 hhchi2pth->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetChi2toNDF(i));
+                 hchi2pr->Fill(Res->GetMomRes(i),Res->GetChi2toNDF(i),1);
+                 hchi2ptr->Fill(Res->GetPtRes(i),Res->GetChi2toNDF(i),1);
+                 hchi2pzr->Fill(Res->GetPzRes(i),Res->GetChi2toNDF(i),1);
+                 hchi2thr->Fill(Res->GetDTheta(i),Res->GetChi2toNDF(i),1);
+                 
+                 // additional
+                 hpptr->Fill(Res->GetMCPt(i),Res->GetMomRes(i),1);
+                 hppzr->Fill(TMath::Abs(Res->GetMCPz(i)),Res->GetMomRes(i),1);
+                 hptptr->Fill(Res->GetMCPt(i),Res->GetPtRes(i),1);
+                 hptpzr->Fill(TMath::Abs(Res->GetMCPz(i)),Res->GetPtRes(i),1);
+                 hpzptr->Fill(Res->GetMCPt(i),Res->GetPzRes(i),1);
+                 hpzpzr->Fill(TMath::Abs(Res->GetMCPz(i)),Res->GetPzRes(i),1);
+                 
+                 // hits
+                 hitsh->Fill(Res->GetNVhits(i));
+                 htstbh->Fill(Res->GetNTBhits(i));
+                 htstech->Fill(Res->GetNTEChits(i));
+                 htotalh->Fill(Res->GetNTThits(i));
+                 
+                 hpthh->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetNTThits(i));
+                 hitspthh->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetNVhits(i));
+                 htstbpthh->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetNTBhits(i));
+                 htstecpthh->Fill(Res->GetMCPtheta(i),Res->GetMomentumMC(i),Res->GetNTEChits(i));
+                
+                 nm++;
+             }
+        }
+        
+        hN->Fill(ntracks);
+        hn->Fill(nm);
+    
+        // vertex
+        hvr->Fill(Res->GetVertexMCr());
+        hvz->Fill(Res->GetVertexMCz());
+        hvrt->Fill(Res->GetVertexMCrt());
+        
+        hvdr->Fill(Res->GetVertexDMag());
+        hvdz->Fill(Res->GetVertexDZ());
+        hvdphi->Fill(Res->GetVertexDPhi());
+        
+        Res->ClearData();
+   }
+   
+   gStyle->SetOptStat("ermou");
+   
+   // seed values
+//    TCanvas* cp = new TCanvas("cp","cp",750,850);
+//    cp->Divide(2,3);
+//    cp->cd(1); hn->SetFillColor(kBlue-7); hn->Draw(); 
+//               hN->SetLineColor(kBlack); hN->SetLineWidth(3);  hN->Draw("same"); 
+//    cp->cd(2); hp->SetFillColor(kBlue+1);  hp->Draw();
+//    cp->cd(3); hpt->SetFillColor(kBlue+2); hpt->Draw();
+//    cp->cd(4); hpz->SetFillColor(kBlue+2); hpz->Draw();
+//    cp->cd(5); hth->SetFillColor(kBlue+3); hth->Draw();
+//    cp->cd(6); hfi->SetFillColor(kBlue+3); hfi->SetMinimum(0); hfi->Draw();
+//    cp->cd(0);
+   
+   // resolution
+   TCanvas* cr = new TCanvas("cr","cr",750,850);
+   cr->Divide(2,3);
+   cr->cd(1); hchi2ndf->SetFillColor(kMagenta+3); hchi2ndf->Draw();
+   cr->cd(2); hpr->SetFillColor(kMagenta);     hpr->Draw(); cr->cd(2)->SetLogy();
+   cr->cd(3); hptr->SetFillColor(kMagenta+1); hptr->Draw(); cr->cd(3)->SetLogy();
+   cr->cd(4); hpzr->SetFillColor(kMagenta+1); hpzr->Draw(); cr->cd(4)->SetLogy();
+   cr->cd(5); hthr->SetFillColor(kMagenta+2); hthr->Draw(); cr->cd(5)->SetLogy();
+   cr->cd(6); hfir->SetFillColor(kMagenta+2); hfir->Draw(); cr->cd(6)->SetLogy();
+   cr->cd(0);
+
+   // dp/p
+   TCanvas* cpr = new TCanvas("cpr","cpr",900,600);
+   cpr->Divide(2,2);
+   cpr->cd(1); hppr->Draw("e1");
+   cpr->cd(2); hpthr->Draw(); cpr->cd(2)->SetLogy();
+   cpr->cd(3); hpfir->Draw(); hpfir->SetMinimum(0);
+   cpr->cd(4); hhppth->Draw("colz");
+   cpr->cd(0);
+   
+   // dpt/pt
+   TCanvas* cptr = new TCanvas("cptr","cptr",900,600);
+   cptr->Divide(2,2);
+   cptr->cd(1); hptpr->Draw("e1");
+   cptr->cd(2); hptthr->Draw(); cptr->cd(2)->SetLogy();
+   cptr->cd(3); hptfir->Draw(); hptfir->SetMinimum(0);
+   cptr->cd(4); hhptpth->Draw("colz");
+   cptr->cd(0);
+   
+   // dpz/pz
+   TCanvas* cpzr = new TCanvas("cpzr","cpzr",900,600);
+   cpzr->Divide(2,2);
+   cpzr->cd(1); hpzpr->Draw("e1");
+   cpzr->cd(2); hpzthr->Draw(); cpzr->cd(2)->SetLogy();
+   cpzr->cd(3); hpzfir->Draw(); hpzfir->SetMinimum(0);
+   cpzr->cd(4); hhpzpth->Draw("colz");
+   cpzr->cd(0);
+   
+   // dtheta  
+//    TCanvas* cthr = new TCanvas("cthr","cthr",900,600);
+//    cthr->Divide(2,2);
+//    cthr->cd(1); hthpr->Draw("e1");
+//    cthr->cd(2); hththr->Draw(); cthr->cd(2)->SetLogy();
+//    cthr->cd(3); hthfir->Draw(); hthfir->SetMinimum(0); 
+//    cthr->cd(4); hhthpth->Draw("colz");
+//    cpzr->cd(0);
+         
+   // vertex
+   TCanvas* cv = new TCanvas("cv","cv",750,850);
+   cv->Divide(2,3);
+   cv->cd(1); hvr->SetFillColor(kGreen+1);   hvr->SetMinimum(0); hvr->Draw();
+   cv->cd(2); hvdr->SetFillColor(kGreen+1);  hvdr->Draw();
+   cv->cd(3); hvz->SetFillColor(kGreen+2);   hvz->SetMinimum(0); hvz->Draw();
+   cv->cd(4); hvdz->SetFillColor(kGreen+2);  hvdz->Draw();
+   cv->cd(5); hvrt->SetFillColor(kGreen+3);  hvrt->Draw();
+   cv->cd(6); hvdphi->SetFillColor(kGreen);  hvdphi->Draw(); 
+   cv->cd(0);
+   
+   // chisquare
+//    TCanvas* cchi2pth = new TCanvas("cchi2pth","cchi2pth",600,600);
+//    Double_t dd = 0.5; hhchi2pth->SetMinimum(0.98-dd); hhchi2pth->SetMaximum(0.98+dd);  
+//    hhchi2pth->Draw("colz");
+//    cchi2pth->cd(0);
+   
+//   TCanvas* cchi2r = new TCanvas("cchi2r","cchi2r",900,600);
+//    cchi2r->Divide(2,2);
+//    cchi2r->cd(1); hchi2pr->Draw("e1");
+//    cchi2r->cd(2); hchi2ptr->Draw("e1");
+//    cchi2r->cd(3); hchi2pzr->Draw("e1");
+//    cchi2r->cd(4); hchi2thr->Draw("e1");
+//    cchi2r->cd(0); 
+ 
+//     // additional   
+//    TCanvas* cr2 = new TCanvas("cr2","cr2",750,850);
+//    cr2->Divide(2,3);
+//    cr2->cd(1); hpptr->Draw("e1");
+//    cr2->cd(2); hppzr->Draw("e1");
+//    cr2->cd(3); hptptr->Draw("e1");
+//    cr2->cd(4); hptpzr->Draw("e1");
+//    cr2->cd(5); hpzptr->Draw("e1");
+//    cr2->cd(6); hpzpzr->Draw("e1");
+//    cr2->cd(0);
+   
+   // hits
+//    TCanvas* chh = new TCanvas("chh","chh",900,600);
+//    chh->Divide(2,2);
+//    Double_t hhscale = 1./hitsh->GetEntries();
+//    chh->cd(1)->SetLogy(); hitsh->SetFillColor(kRed+2); hitsh->GetXaxis()->CenterLabels(); hitsh->Scale(hhscale); hitsh->Draw("h");
+//    chh->cd(2)->SetLogy(); htstbh->SetFillColor(kRed+2); htstbh->GetXaxis()->CenterLabels(); htstbh->Scale(hhscale); htstbh->Draw("h");
+//    chh->cd(3)->SetLogy(); htstech->SetFillColor(kRed+2); htstech->GetXaxis()->CenterLabels(); htstech->Scale(hhscale); htstech->Draw("h");
+//    chh->cd(4)->SetLogy(); htotalh->SetFillColor(kRed+4); htotalh->GetXaxis()->CenterLabels(); htotalh->Scale(hhscale); htotalh->Draw("h"); 
+//    chh->cd(0);
+   
+   TCanvas* chhpth = new TCanvas("chhpth","chhpth",900,900);
+   chhpth->Divide(2,2);
+   chhpth->cd(1); hpthh->Draw("colz");
+   chhpth->cd(2); hitspthh->Draw("colz");
+   chhpth->cd(3); htstbpthh->Draw("colz");
+   chhpth->cd(4); htstecpthh->Draw("colz");
+   chhpth->cd(0);
+   
+   if (hp) {
+       
+       Double_t sump(0), q(0.5);
+       
+       if (hp->GetQuantiles(1,&sump,&q)) {
+           cout << "\n";
+           cout << "Median (p_mc) = " << sump << " [GeV/c] \n"; 
+           cout << "Mean   (p_mc) = " << hp->GetMean() << " [GeV/c] \n"; 
+           cout << "Dev.   (p_mc) = " << hp->GetRMS() << " [GeV/c] \n"; 
+       }
+       
+       if (hpr->GetQuantiles(1,&sump,&q)) {
+           cout << "\n";
+           cout << "Median (|dp|/p) = " << 100.*sump << " [%] \n"; 
+           cout << "Mean   (|dp|/p) = " << 100.*hpr->GetMean() << " [%] \n"; 
+           cout << "Dev.   (|dp|/p) = " << 100.*hpr->GetRMS() << " [%] \n"; 
+       }
+       
+        if (hptr->GetQuantiles(1,&sump,&q)) {
+           cout << "\n";
+           cout << "Median (|dpt|/pt) = " << 100.*sump << " [%] \n"; 
+           cout << "Mean   (|dpt|/pt) = " << 100.*hptr->GetMean() << " [%] \n"; 
+           cout << "Dev.   (|dpt|/pt) = " << 100.*hptr->GetRMS() << " [%] \n"; 
+       }
+   }
+     
+   cout << "\nEVENTS [nice/total]:         " << NWellFittedEvents << "/" << entries 
+        << "  (" << 100.*NWellFittedEvents/Double_t(entries) << " %)" << "\n";
+   cout <<   "TRACKS [selected/total]:     " << NWellFittedTracks << "/" << NTotalTracks
+        << "  (" << 100*NWellFittedTracks/Double_t(NTotalTracks) << "%)" << "\n\n";     
+        
+}
+
+
diff --git a/macro/tracking/CheckGFTracks.C b/macro/tracking/CheckGFTracks.C
new file mode 100644
index 0000000000000000000000000000000000000000..c39052aea8f6e1a6f673a0d8dd48b045b67d6d16
--- /dev/null
+++ b/macro/tracking/CheckGFTracks.C
@@ -0,0 +1,108 @@
+// #include <TFile.h>
+// #include <TTree.h>
+// #include <TGeoManager.h>
+// #include <TClonesArray.h>
+// #include "FairGeoParSet.h"
+// #include "SpdKFSimpleRes.h"
+// #include "GFCore.hh"
+// #include "EventDisplay.h"
+// #include "SpdGFTrackW.h"
+// #include <vector>
+
+TTree* Tree_ = 0;
+
+void check_tracks(Int_t nevent = 0);
+
+TString inFile, inParFile;
+
+//______________________________________________________________________________
+void CheckGFTracks(TString path = "") 
+{
+  if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
+    
+  inFile    = path + "IdealFittedTracks.root";   
+  inParFile = path + "params_tor.root";
+  
+  TFile* f = new TFile(inFile);
+  if (!f) return;
+  
+  Tree_ = (TTree*)f->Get("cbmsim");  
+  if (!Tree_) return;
+  
+  cout << "\n >>>>>>>>>>>>>>>> DATA FILE & TREE: Ok! <<<<<<<<<<<<<<<<< " << endl;  
+  
+  check_tracks(0);
+  
+  //SpdBaseParSet* pars = (SpdBaseParSet*)f->Get("IdealKalmanFitterParams");
+  //if (pars) pars->print(1);
+}
+
+//______________________________________________________________________________
+void check_tracks(Int_t nevent)
+{
+   if (!Tree_) return;  
+   
+   TBranch* branch = Tree_->GetBranch("SpdGFTrackW.");
+   if (!branch) { cout << " no \"GF tracks\" branch " << endl; return; }
+   
+   Int_t entries = branch->GetEntries();
+   
+   cout << "Total entries in the \"GF tracks\" branch: " << entries << endl; 
+   
+   if (nevent < 0 || nevent >= entries) return;
+  
+   TObjArray *fT = 0; 
+   Tree_->SetBranchAddress("SpdGFTrackW.",&fT) ; 
+   
+   //------------------------
+   
+   TBranch* data_branch = Tree_->GetBranch("SpdKFSimpleRes.");
+   if (!data_branch) { cout << " no \"KF data\" branch " << endl; return; }
+   
+   SpdKFSimpleRes* Res = 0;
+   Tree_->SetBranchAddress("SpdKFSimpleRes.",&Res) ;  
+   
+   //------------------------
+      
+   branch->GetEntry(nevent);  
+   data_branch->GetEntry(nevent);  
+   
+   if (Res) Res->PrintData(2);
+         
+   SpdGFTrackW* wtrack = 0;
+   genfit::Track* track = 0;
+   
+   Int_t ntr = fT->GetEntriesFast();
+   
+   cout << "\nevent = " << nevent << " tracks = " << ntr << endl;
+  
+   for (Int_t i(0); i<ntr; i++) {
+       wtrack = (SpdGFTrackW*)fT->At(i);
+       if (!wtrack) continue;
+       cout << "wtrack " << i << " data: " << wtrack->GetDataID() << endl;
+       track = wtrack->GetTrack();
+       if (!track) continue;
+       
+       //if (track && i == 4) 
+       //    track->Print();
+           
+       cout<< "------ track: " << i+1 << "/" << ntr << endl;   
+   }
+   
+   //genfit::EventDisplay* display = genfit::EventDisplay::getInstance();
+   
+   //genfit::Track* trackX = new genfit::Track();
+   //*trackX = *(genfit::Track*)fT->At(3);
+   
+   //track = (genfit::Track*)fT->At(0);
+   //track->fillPointsWithMeasurement();
+   //track->checkConsistency();
+   
+   //track->Print();
+   
+   //display->addEvent(track);
+   
+   //display->open();
+}
+
+
diff --git a/macro/tracking/CheckIdealTracks.C b/macro/tracking/CheckIdealTracks.C
index 2c8a8e23f414d40d7b4a010d08382a6fc809a4c2..eff37a88cf0b74cb0b310853dd9fa4d6c72590b1 100644
--- a/macro/tracking/CheckIdealTracks.C
+++ b/macro/tracking/CheckIdealTracks.C
@@ -9,11 +9,12 @@ void check_params();
 TString inFile, inParFile;
 
 //______________________________________________________________________________
-void CheckIdealTracks() 
+void CheckIdealTracks(TString path = "") 
 {
+  if (!path.IsWhitespace() && !path.EndsWith("/")) path += "/";
 
-  inFile = "IdealTracks.root";   
-  inParFile =  "params_tor.root";
+  inFile    = path + "IdealTracks.root";   
+  inParFile = path + "params_tor.root";
   
   TFile* f = new TFile(inFile);
   if (!f) return;
@@ -97,8 +98,8 @@ void check_events() {
         
         if (Event->GetNTracks() > 0) {
           track = (SpdIdealTrack*)Event->GetTrack(0);
-          //track->PrintTrack(true);
-          track->PrintTrack(false);
+          if (track) track->PrintTrack(true);
+          //if (track) track->PrintTrack(false);
         }
         
         Event->DeleteAll(); // clear event
diff --git a/macro/tracking/FitIdealTracks.C b/macro/tracking/FitIdealTracks.C
index ba8b0e6f30dfb9c6dd1a93d64c8a710903b32bbd..ec93ec5dbe3543508090041a626668004d21f4e3 100644
--- a/macro/tracking/FitIdealTracks.C
+++ b/macro/tracking/FitIdealTracks.C
@@ -30,17 +30,18 @@ void FitIdealTracks()
   
   KalmanFitter->SetVerboseLevel(2); // level = <1 (no prints), 1(default), 2, 3, 4
   
-  KalmanFitter->SetTrackingGeoModules(); // add Its,TsTB,TsTEC modules to analysis
+  //KalmanFitter->SetTrackingGeoModules(); // add Its,TsTB,TsTEC modules to analysis
   
-  //KalmanFitter->AddModule(12); // Its
-  //KalmanFitter->AddModule(2);  // TsTB
-  //KalmanFitter->AddModule(3);  // TsTEC
+  KalmanFitter->AddModule(12); // Its
+  KalmanFitter->AddModule(2);  // TsTB
+  KalmanFitter->AddModule(3);  // TsTEC
   
   // standard options: 
   KalmanFitter->SetSeedMomentum(1.);           // Start vertex momentum for fit, GeV/c (default = 1 GeV/c) 
-  
-  KalmanFitter->SetResolution(0.005);          // Vertex detector (Its) resolution, cm (default = 0.005 cm)   
-  KalmanFitter->SetWireResolution(0.015);      // Wire tracker (TsTB, TsTEC) resolution , cm (default = 0.015 cm) 
+    
+  KalmanFitter->SetHitRepresentation(kSpdIts,pkPixel);   // options: pkPixel, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTB,pkWire);   // options: pkWire, pkWirePoint, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTEC,pkWire);  // options: pkWire, pkWirePoint, pkSpacepoint
 
   // advanced options:
   KalmanFitter->SetVertexFindingMethod(1);     // <1 (vertex will not be found), (default = 1)   
@@ -53,14 +54,22 @@ void FitIdealTracks()
   KalmanFitter->SetSmearingAngleDelta(3.0);    // [SeedMethod = 1] track start angle smearing  (+-)value, deg (default = 3.0 deg)
   KalmanFitter->SetSmearingVertexDelta(0.5);   // [SeedMethod = 1] track start vertex position smearing (+-)value, cm (default = 0.5 cm)
   KalmanFitter->SetNPointsVertexUse(0);        // [SeedMethod = 2] <1 (default): number of points is the maximum possible (usually 5-6 )
+  
+  KalmanFitter->SetFitterMaxIterations(8);     // default: 8,  minimum: 4
+  KalmanFitter->SetFitterMaxTrials(2);         // default: 10, minimum: 1
 
   // Material effects option: <  1 : fit without materials;
   //                          >= 1 : fit taking into accont material effects (default);
   
   KalmanFitter->SetMaterialEffectsOption(1);
+  
+  //SpdGeoLoader::ForceTopGeoFile("cave_precise.geo"); // force top volume (Cave) geometry (default: parameters will be used); 
 
   // method to update covariance matrix (default = 1)  
-  KalmanFitter->SetFitterOption(1);      
+  KalmanFitter->SetFitterOption(1);    
+
+  //store fitted tracks (full fitter info, by default = false) 
+  KalmanFitter->SetStoreTracks(true);
   
   //------------------------------------//
   Run->AddTask(KalmanFitter);
@@ -71,12 +80,38 @@ void FitIdealTracks()
   
   Run->Initialize();
   
-  //return;
+  // advanced settings
+  SpdGFMeasurementCreator* mcreator = KalmanFitter->GetMeasurementCreator();
+  
+  // +++++ ADVANCED OPTIONS +++++ 
+  
+      // change hit representation (if needed)
+      //KalmanFitter->SetHitRepresentation(kSpdIts,pkSpacepoint);    // pkPixel -> pkSpacepoint
+      //KalmanFitter->SetHitRepresentation(kSpdTsTB,pkSpacepoint);   // pkWire  -> pkSpacepoint
+      //KalmanFitter->SetHitRepresentation(kSpdTsTEC,pkSpacepoint);  // pkWire  -> pkSpacepoint
+      
+      // force hit resolution (if needed)
+      //Double_t mkm = 1e-4;
+      
+      //mcreator->SetPointHitResolutionXYZ(50*mkm, 50*mkm, 50*mkm);  // res(x(u),y(v),z): pkPixel -> (x=u,y=v); pkSpacepoint -> (x,y,z)
+      //mcreator->SetWireHitResolutionRZ(150*mkm, 150*mkm);          // res(r,z): pkWire -> (r); pkWirePoint -> (r,z)
+      
+      //mcreator->ForcePointHitResolution();    // use specified by SetPointHitResolutionXYZ resolution for all point-like hits  
+      //mcreator->ForceWireHitResolution();     // use specified by SetWireHitResolutionRZ resolution for all wire-like hits  
+      
+      // use mc-point as hit
+      //mcreator->UseMCPointAsPointHit(true);   // if option = true, smear point using defined resolution (default option = false)
+      //mcreator->UseMCPointAsWireHit(true);    // if option = true, smear point using defined resolution (default option = false)
+
        
-  Run->Run(0, nEvents);
-  //Run->Run(0,1000);
-  //Run->Run(0,10);
-   
+  // Run fitting
+  
+  //Run->Run(0, nEvents);
+  //Run->Run(100,200);
+  Run->Run(0,100);
+  
+  KalmanFitter->DeleteGeoLoader();
+  
   timer.Stop();
   
   Double_t rtime = timer.RealTime();
@@ -88,6 +123,6 @@ void FitIdealTracks()
   cout << "Parameter file is " << parFile << endl;
   cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
   cout << endl;
-    
+  
   gApplication->Terminate();
 }
diff --git a/macro/tracking/MakeIdealTracks.C b/macro/tracking/MakeIdealTracks.C
index 93a6e5999842e6b16b444c19a382deae9d9fdff6..0b63e007a34b735bdf3c672e688cdc0c8cb904b8 100644
--- a/macro/tracking/MakeIdealTracks.C
+++ b/macro/tracking/MakeIdealTracks.C
@@ -7,7 +7,7 @@ void MakeIdealTracks()
   
   TString inFile  = "run_tor.root";       // Input file (MC events)
   TString parFile = "params_tor.root";    // Parameter file
-  TString outFile = "IdealTracks.root";  // Output file
+  TString outFile = "IdealTracks.root";   // Output file
   
   SpdRunAna* Run = new SpdRunAna();
   
@@ -38,9 +38,30 @@ void MakeIdealTracks()
   // set cuts
   TrackFinder->SetMinMomentum(1e-2);  // momentum cut;  default = 1e-2 (10 Mev); absiolute min. value = 4e-3 (4 MeV)
   TrackFinder->SetMinGammaBeta(0.5);  // p/m cut; default = 0.5; absiolute min. value = 0.05
-  TrackFinder->SetMinVertexNHits(1);  // its hits number cut; default = 1; absiolute min. value = 0;  
+  TrackFinder->SetMinVertexNHits(1);  // its hits number cut; default = 1; absolute min. value = 0;  
   TrackFinder->SetMinTrackerNHits(2); // tstb+tstec hits number cut; default = 2; absiolute min. value = 2;  
   
+  // set hits resolution
+  Double_t mkm = 1e-4;
+ 
+  // ------ INNER TRACKER -----
+ 
+  TrackFinder->SetHitResolution(kSpdIts,  'p',  50*mkm,  50*mkm); // ENDCAP: POINT  (u=x,v=y)
+  TrackFinder->SetHitResolution(kSpdIts,  'm',  50*mkm,  50*mkm); // BARREL: MAPS   (u,v)
+  TrackFinder->SetHitResolution(kSpdIts,  's',  50*mkm,  50*mkm); // BARREL: DSSD   (u,v)
+  
+  // ----- STRAW TRACKER -----
+  
+  // --- barrel ---
+  TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm);                  // Wire(1D) (r)
+  //TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+ 
+  //--- endcaps ---
+  TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm);                  // Wire(1D) (r)
+  //TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+  
+  //TrackFinder->AppendSecondaryTracks();
+  
   //------------------------------------//
   Run->AddTask(TrackFinder);
   
@@ -48,11 +69,15 @@ void MakeIdealTracks()
   
   cout << "Start ... " << endl;
   
-  Run->LoadGeoParSet(kFALSE);
+  Run->LoadGeoParSet(false);
   Run->Initialize();
+  
+  //return;
        
   Run->Run(0, nEvents);
   
+  TrackFinder->DeleteGeoLoader();
+  
   timer.Stop();
   
   Double_t rtime = timer.RealTime();
@@ -64,7 +89,7 @@ void MakeIdealTracks()
   cout << "Parameter file is " << parFile << endl;
   cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
   cout << endl;
-  
+    
   /* DRAW GEOMETRY */
    
 //   TGeoManager *geoMan = gGeoManager;
diff --git a/macro/tracking/Simu_tr11.C b/macro/tracking/SimuDmesons.C
similarity index 90%
rename from macro/tracking/Simu_tr11.C
rename to macro/tracking/SimuDmesons.C
index b22c980e9b0e5b956c61df07d626e404f371f376..3b4f2cbe7c2bfc066e653607de4886f2a0e6e140 100644
--- a/macro/tracking/Simu_tr11.C
+++ b/macro/tracking/SimuDmesons.C
@@ -38,7 +38,7 @@ void CustomizeGeometryTsTB();
 void CustomizeGeometryTsTEC();
 
 //_________________________________________________________________________
-void Simu_tr11(Int_t nEvents = 1)
+void SimuDmesons(Int_t nEvents = 1)
 {
   TString outFile = "run_tor.root";    // Output data file name
   TString parFile = "params_tor.root"; // Output parameters file name
@@ -112,13 +112,11 @@ void Simu_tr11(Int_t nEvents = 1)
   /* --- field map --- */
   SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
   
-//  MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+  //MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
   MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
   
-//  MagField->InitData("map_tor_rot.bin");
-     
   //MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
-  //MagField->MultiplyField(2.0);
+  //MagField->MultiplyField(1);
   
   /* === define field region === */
   SpdRegion* reg = 0;
@@ -145,32 +143,46 @@ void Simu_tr11(Int_t nEvents = 1)
       
       SpdIsotropicGenerator* isogen1 = new SpdIsotropicGenerator("isogen1");
       
-      isogen1->Initialize(-2212,3.0,50);  // pdg number, momentum (GeV/c), particles per event or LEVEL 2212
+      // D+
+      isogen1->Initialize(411,5.,1);  // pdg number, momentum (GeV/c), particles per event or LEVEL
       isogen1->SetVerboseLevel(1);
-      isogen1->SetVGenOpt(1);  // (+-)1, (+-)2
-      isogen1->SetSpherical(146.5,153.500,0,360);
+      isogen1->SetVGenOpt(-1);  // (+-)1, (+-)2
       
       primGen->AddGenerator(isogen1);
-      
+
       //===========================
       //   ISOTROPIC GENERATOR (2)
       //===========================
          
       SpdIsotropicGenerator* isogen2 = new SpdIsotropicGenerator("isogen2");
       
-      isogen2->Initialize(2212,3.0,50);  // pdg number, momentum (GeV/c), particles per event or LEVEL
+      // D-
+      isogen2->Initialize(-411,1.5,1);  // pdg number, momentum (GeV/c), particles per event or LEVEL
       isogen2->SetVerboseLevel(1);
-      isogen2->SetVGenOpt(1);  // (+-)1, (+-)2 
-      isogen2->SetSpherical(26.5,33.500,0,360);
+      isogen2->SetVGenOpt(-1);  // (+-)1, (+-)2 
       
       primGen->AddGenerator(isogen2);
       
-      //============================
+      //===========================
+      //   ISOTROPIC GENERATOR (3)
+      //===========================
       
-  run->SetGenerator(primGen); 
-  
-  gRandom->SetSeed(0); // reset "global" random generator
+      SpdIsotropicGenerator* isogen3 = new SpdIsotropicGenerator("isogen3");
+      
+      // D0
+      isogen3->Initialize(421,5.,1);  // pdg number, momentum (GeV/c), particles per event or LEVEL
+      isogen3->SetVerboseLevel(1);
+      isogen3->SetVGenOpt(-1);  // (+-)1, (+-)2
+      
+      primGen->AddGenerator(isogen3);
+      
+      //============================
+    
+  run->SetGenerator(primGen);  
   
+  primGen->SetVerboseLevel(-10);
+  //primGen->SetVerbose(0);
+      
   primGen->SetBeam(0., 0., 0.1, 0.1); // (X,Y)- position, (X,Y)- (0.5*delta or sigma) [cm]
   primGen->SmearVertexXY(kTRUE);
   //primGen->SmearGausVertexXY(kTRUE);
@@ -183,7 +195,7 @@ void Simu_tr11(Int_t nEvents = 1)
   /* +++++++++++++++ GLOBAL OPTIONS +++++++++++++++++ */
   /* ------------------------------------------------ */ 
   
-  run->SetStoreTraj(kTRUE);
+  //run->SetStoreTraj(kTRUE);
  
   //SpdCommonGeoMapper::Instance()->SaveEmptyHits();
   
diff --git a/macro/tracking/SimuHyb_1.C b/macro/tracking/SimuHyb_1.C
index b3faa64064564c94ea69c0f189f151f17541950d..9ed29fe044731bf468e686cf028d86c3b0d22e22 100644
--- a/macro/tracking/SimuHyb_1.C
+++ b/macro/tracking/SimuHyb_1.C
@@ -23,10 +23,6 @@
 #include "SpdIts.h"
 #include "SpdTsTB.h"
 #include "SpdTsTEC.h"
-#include "SpdEcalTB.h"
-#include "SpdEcalTEC.h"
-#include "SpdRsTB.h"
-#include "SpdRsTEC.h"
 
 #include "SpdItsGeoMapperX.h"
 #include "SpdTsTBGeoBuilder.h"
@@ -48,7 +44,7 @@ void SimuHyb_1(Int_t nEvents = 1)
   
   run->SetOutputFile(outFile);      
   
-  run->SetPythiaDecayer("DecayConfig.C");
+  //run->SetPythiaDecayer("DecayConfig.C");
  
   run->SetMCEventHeader(new SpdMCEventHeader);
  
@@ -61,66 +57,86 @@ void SimuHyb_1(Int_t nEvents = 1)
   /* ++++++++++++++++++ CAVE ++++++++++++++++++ */
   
   FairModule* cave = new SpdCave("CAVE");
-  cave->SetGeometryFileName("cave.geo");
+  //cave->SetGeometryFileName("cave.geo");
   //cave->SetGeometryFileName("cave_precise.geo");
   run->AddModule(cave);
   
   /* ++++++++++++++++++ PIPE ++++++++++++++++++ */
   
   SpdPipe* Pipe = new SpdPipe();
+  //Pipe->UnsetMaterials("air");
   run->AddModule(Pipe);
   
   /* +++++++++++++++++ MAGNET +++++++++++++++++ */
   
-  //SpdHybMagnet* Magnet = new SpdHybMagnet();
-  //Magnet->SetGeometryType(2); // 1 = "hybrid" (deafult), 2 = "qsolenoid"
-  //run->AddModule(Magnet);
+//   SpdHybMagnet* Magnet = new SpdHybMagnet();  //default geometry type = 2
+//   run->AddModule(Magnet);
   
   /* +++++++++++++++++ DETECTORS ++++++++++++++ */
  
   SpdTsTB*    ts_barrel   = new SpdTsTB();     /* +++++++++ TST (BARREL) ++++++++++++ */ 
   SpdTsTEC*   ts_ecps     = new SpdTsTEC();    /* +++++++++ TST (ENDCAPS) +++++++++++ */     
-  //SpdEcalTB*  ecal_barrel = new SpdEcalTB();   /* +++++++++ ECALT (BARREL) ++++++++++ */      
-  //SpdEcalTEC* ecal_ecps   = new SpdEcalTEC();  /* +++++++++ ECALT (ENDCAPS) +++++++++ */  
-  //SpdRsTB*    rs_barrel   = new SpdRsTB();     /* +++++++++ RST (BARREL) ++++++++++++ */  
-  //SpdRsTEC*   rs_ecps     = new SpdRsTEC();    /* +++++++++ RST (ENDCAPS) +++++++++++ */
-    
+ 
   run->AddModule(ts_barrel);  
-  //run->AddModule(ecal_barrel);
-  //run->AddModule(rs_barrel);
   run->AddModule(ts_ecps);   
-  //run->AddModule(ecal_ecps);
-  //run->AddModule(rs_ecps);
 
   //ts_barrel->SetParametersType("SpdTsTBParSet"); // TsTBParSet (default), SpdTsTBParSet
   //ts_barrel->SaveDetIdOption(1); // 1, 2 (default)
-    
+  
   /* ===== Vertex detector ===== */
     
   SpdIts* its = new SpdIts(); 
   run->AddModule(its);
   
-  SpdItsGeoMapperX::Instance()->EnableEndcaps(); // enable(1)/disable(0) Inner Tracker (Its) endcaps
+  //SpdItsGeoMapperX::Instance()->SetGeometryPars(1);
+  
+  //SpdItsGeoMapperX::Instance()->EnableEndcaps(); // enable(1)/disable(0) Inner Tracker (Its) endcaps ; default = enable
+  //its->SaveEmptyHits();
 
   /*--------------------------------------------------*/
-  /* ++++++++++++  CASTOMIZE GEOMETRY   +++++++++++++ */
+  /* ++++++++++++  CUSTOMIZE GEOMETRY   +++++++++++++ */
   /*--------------------------------------------------*/
   
   CustomizeGeometry();
-   
+ 
+  /*--------------------------------------------------*/
+  /* ++++++++++++  CUSTOMIZE MATERIALS  +++++++++++++ */
+  /*--------------------------------------------------*/
+
+  //SpdParameter* par;
+
+  /* --- alter TsTB straw active media (gas) --- */
+  //par = ts_barrel->GetMapper()->AddParameter("TsTBBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+  
+  /* --- alter TsTEC straw active media (gas) --- */
+  //par = ts_ecps->GetMapper()->AddParameter("TsTECBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+ 
+  /* --- reset all module's materials ---*/
+  //ts_barrel->GetMapper()->UnsetMaterials("air");  // "air" or "vacuum"
+  //ts_ecps->GetMapper()->UnsetMaterials("air");    // "air" or "vacuum"
+  //its->GetMapper()->UnsetMaterials("air");        // "air" or "vacuum"
+  
   /*--------------------------------------------------*/
   /* ++++++++++++++   MAGNETIC FIELD   ++++++++++++++ */
   /*--------------------------------------------------*/
    
   /* --- const field --- */
   //SpdConstField* MagField = new SpdConstField();  
-  //MagField->SetField(0., 0. , 2.5); //  kG
+  //MagField->SetField(0., 0., 4); //  kG
 
   /* --- field map --- */
   SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
   
-  //MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
-  MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
+  MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+  //MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
    
   //MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
   //MagField->MultiplyField(1);
@@ -160,9 +176,9 @@ void SimuHyb_1(Int_t nEvents = 1)
       //-----------------------------------------------------------
       // Set seed:
       
-      gRandom->SetSeed(0);
-      Int_t seed = gRandom->Integer(Int_t(1e9));
-      P6gen->SetSeed(seed);
+      gRandom->SetSeed(12345);
+      Int_t seed = 127472;//gRandom->Integer(Int_t(1e9));
+      P6gen->SetSeed(seed,0);
        
       //P6gen->SetSeed(0);
       //P6gen->SetSeed(144135822, 2);
@@ -180,7 +196,7 @@ void SimuHyb_1(Int_t nEvents = 1)
 
        
       /* --- Pythia6 initialization --- */
-      P6gen->Initialize("cms","p","p",26/*GeV*/);
+      P6gen->Initialize("cms","p","p",27/*GeV*/);
        
       primGen->AddGenerator(P6gen);
      
@@ -210,8 +226,8 @@ void SimuHyb_1(Int_t nEvents = 1)
   //run->ForceParticleLifetime(-211, 26.033/5.); // pdg, life time [ns]
   //run->ForceParticleLifetime( 211, 26.033/5.); // pdg, life time [ns]
   
-  //SpdCommonGeoMapper::Instance()->UnsetMaterials(1);  // set all materials = vacuum (precise)
-    
+  //SpdCommonGeoMapper::Instance()->UnsetMaterials(true);
+  
   /* ----------------------------------------------------------------------- */ 
   /* >>>>>>>>>>>>>>>>>>>>>>>>>>> INITALIZE RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
   /* ----------------------------------------------------------------------- */ 
@@ -263,15 +279,15 @@ void SimuHyb_1(Int_t nEvents = 1)
   
   Double_t rtime = timer.RealTime();
   Double_t ctime = timer.CpuTime();
-  
+
   cout << endl << endl;
   cout << "Macro finished succesfully." << endl;
-  cout << "Output file is "             << outFile << endl;
-  cout << "Parameter file is "          << parFile << endl;
+  cout << "Output file is             " << outFile << endl;
+  cout << "Parameter file is          " << parFile << endl;
+  cout << "Seed (prim.gen.) is        " << seed << endl;
   cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << endl;
   cout << endl;
   
-  cout << " seed = " << seed << endl;
   /*--------------------------------------------------*/
   
   //SpdCommonGeoMapper::Instance()->PrintGeometryList();
diff --git a/macro/tracking/SimuQsl_1.C b/macro/tracking/SimuQsl_1.C
new file mode 100644
index 0000000000000000000000000000000000000000..903b0c42292b16036375f7cb6b0d842f434cf638
--- /dev/null
+++ b/macro/tracking/SimuQsl_1.C
@@ -0,0 +1,316 @@
+
+//#define _COMPILE_MACRO_
+
+#if defined(_COMPILE_MACRO_) 
+
+#include <TRint.h>
+#include <TStopwatch.h>
+
+#include "FairParRootFileIo.h"
+
+#include "SpdRunSim.h"
+#include "SpdMCEventHeader.h"
+
+#include "SpdCommonGeoMapper.h"
+
+#include "SpdFields.hh"
+#include "SpdGenerators.hh"
+
+#include "SpdCave.h"
+#include "SpdPipe.h"
+
+#include "SpdIts.h"
+#include "SpdTsTB.h"
+#include "SpdTsTEC.h"
+
+#include "SpdItsGeoMapperX.h"
+#include "SpdTsTBGeoBuilder.h"
+
+#endif
+
+//_________________________________________________________________________
+void SimuQsl_1(Int_t nEvents = 1)
+{
+  TString outFile = "run_tor.root";    // Output data file name
+  TString parFile = "params_tor.root"; // Output parameters file name
+   
+  SpdRunSim* run = new SpdRunSim();
+  
+  run->SetName("TGeant4");       
+  run->SetMaterials("media.geo");
+  
+  run->SetOutputFile(outFile);      
+  
+  //run->SetPythiaDecayer("DecayConfig.C");
+ 
+  run->SetMCEventHeader(new SpdMCEventHeader);
+ 
+  /*--------------------------------------------------*/
+  /* +++++++++     GEOMETRY (QSOLENOID)      ++++++++ */
+  /*--------------------------------------------------*/
+  
+  SpdCommonGeoMapper::Instance()->DefineQslGeometrySet();
+  
+  /* ++++++++++++++++++ CAVE ++++++++++++++++++ */
+  
+  FairModule* cave = new SpdCave("CAVE");
+  //cave->SetGeometryFileName("cave.geo");
+  //cave->SetGeometryFileName("cave_precise.geo");
+  run->AddModule(cave);
+  
+  /* ++++++++++++++++++ PIPE ++++++++++++++++++ */
+  
+  SpdPipe* Pipe = new SpdPipe();
+  //Pipe->UnsetMaterials("air");
+  run->AddModule(Pipe);
+    
+  /* +++++++++++++++++ DETECTORS ++++++++++++++ */
+ 
+  SpdTsTB*    ts_barrel   = new SpdTsTB();     /* +++++++++ TST (BARREL) ++++++++++++ */ 
+  SpdTsTEC*   ts_ecps     = new SpdTsTEC();    /* +++++++++ TST (ENDCAPS) +++++++++++ */     
+ 
+  run->AddModule(ts_barrel);  
+  run->AddModule(ts_ecps);   
+
+  /* ===== Vertex detector ===== */
+    
+  SpdIts* its = new SpdIts(); 
+  run->AddModule(its);
+  
+  //SpdItsGeoMapperX::Instance()->SetGeometryPars(1);
+  
+  //SpdItsGeoMapperX::Instance()->EnableEndcaps(); // enable(1)/disable(0) Inner Tracker (Its) endcaps ; default = enable
+  //its->SaveEmptyHits();
+
+  /*--------------------------------------------------*/
+  /* ++++++++++++  CUSTOMIZE GEOMETRY   +++++++++++++ */
+  /*--------------------------------------------------*/
+  
+  // Chose TsTEC configuration 
+  //   
+  // option = 1: (2x)3 modules, 1 module =  8x2 = 16 layers, total = 48 layers (default)
+  // option = 2: (2x)2 modules, 1 module =  8x2 = 16 layers, total = 32 layers  
+  // option = 3: (2x)1 modules, 1 module = 26x2 = 52 layers, total = 52 layers (actual!)
+   
+  SpdTsTECGeoMapper::Instance()->SetGeometryPars(3); 
+   
+  SpdParameter* parg;
+   
+  // RsTB geo. parameters
+  parg = SpdRsTBGeoMapper::Instance()->AddParameter("RsTBClearance");
+  *parg = 0.;
+   
+  // EcalTB geo. parameters
+  parg = SpdEcalTBGeoMapper::Instance()->AddParameter("EcalTBClearance");
+  *parg = 0.;
+  
+  /*--------------------------------------------------*/
+  /* ++++++++++++  CUSTOMIZE MATERIALS  +++++++++++++ */
+  /*--------------------------------------------------*/
+
+  //SpdParameter* par;
+
+  /* --- alter TsTB straw active media (gas) --- */
+  //par = ts_barrel->GetMapper()->AddParameter("TsTBBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+  
+  /* --- alter TsTEC straw active media (gas) --- */
+  //par = ts_ecps->GetMapper()->AddParameter("TsTECBaseStrawMaterial");
+  //if (par) *par = "arco28020x1p5"; // ArCO2, 80/20 %, density x 1.5  
+  //if (par) *par = "arco28020x2p0"; // ArCO2, 80/20 %, density x 2.0
+  //if (par) *par = "arco27030x1p5"; // ArCO2, 70/30 %, density x 1.5  
+  //if (par) *par = "arco27030x2p0"; // ArCO2, 70/30 %, density x 2.0  
+ 
+  /* --- reset all module's materials ---*/
+  //ts_barrel->GetMapper()->UnsetMaterials("air");  // "air" or "vacuum"
+  //ts_ecps->GetMapper()->UnsetMaterials("air");    // "air" or "vacuum"
+  //its->GetMapper()->UnsetMaterials("air");        // "air" or "vacuum"
+  
+  /*--------------------------------------------------*/
+  /* ++++++++++++++   MAGNETIC FIELD   ++++++++++++++ */
+  /*--------------------------------------------------*/
+  
+  /* --- axial field map --- */
+  SpdAxialFieldMap* MagField = new SpdAxialFieldMap("QSolenoidal field");
+  MagField->InitData("map_qsolRZ_6cls2cm.bin");
+  MagField->MultiplyField(0.8);
+   
+  /* --- const field --- */
+  //SpdConstField* MagField = new SpdConstField();  
+  //MagField->SetField(0., 0., 8.0); //  kG
+
+  /* --- field map --- */
+  //SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
+  
+  //MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+  //MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
+   
+  //MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
+  //MagField->MultiplyField(1);
+  
+  /* === define field region === */
+  SpdRegion* reg = 0;
+  
+  //reg = MagField->CreateFieldRegion("box");
+  //reg->SetBoxRegion(-1000, 1000, -1000, 1000, -1000, 1000); // (X,Y,Z)_(min,max), cm
+  
+  reg = MagField->CreateFieldRegion("tube");
+  reg->SetTubeRegion(0, 174, -246, 246); // (R,Z)_(min,max), cm 
+  
+  run->SetField(MagField);
+  
+  MagField->Print();
+  
+  /*--------------------------------------------------*/
+  /* ++++++++++ DEFINE PRIMARY GENERATORS +++++++++++ */
+  /*--------------------------------------------------*/
+ 
+  SpdPrimaryGenerator* primGen = new SpdPrimaryGenerator();
+
+      //============================
+      //    PYTHIA 6 GENERATOR
+      //============================
+      
+      SpdPythia6Generator* P6gen = new SpdPythia6Generator();
+      
+      //-----------------------------------------------------------
+      // Option: (decayer for vertex meson- and baryon- resonances)
+      // 0 = Transport generator + External decayer (particles don't decay in the vertex) 
+      // 1 = Primary generator (DEFAULT value, more safely)
+      
+      P6gen->SetVGenOpt(1);
+        
+      //-----------------------------------------------------------
+      // Set seed:
+      
+      gRandom->SetSeed(12345);
+      Int_t seed = gRandom->Integer(Int_t(1e9));
+      P6gen->SetSeed(seed,0);
+       
+      //P6gen->SetSeed(0);
+      //P6gen->SetSeed(144135822, 2);
+      
+      //P6gen->SetSeed(12995,0);
+      //P6gen->SetSeed(19949278, 1);
+      //P6gen->SetSeed(13495);
+      //P6gen->SetSeed(127472);
+      
+
+      /* --- Set Pythia6 options --- */
+      SpdPythia6* gg = (SpdPythia6*)P6gen->GetGenerator();
+       
+      gg->SetMSEL(1);  // set miminum bias 
+
+       
+      /* --- Pythia6 initialization --- */
+      P6gen->Initialize("cms","p","p",27/*GeV*/);
+       
+      primGen->AddGenerator(P6gen);
+     
+      primGen->SetVerboseLevel(-10);
+      primGen->SetVerbose(0);
+       
+      //============================
+      
+   run->SetGenerator(primGen);
+
+   primGen->SetBeam(0., 0., 0.1, 0.1); // (X,Y)- position, (X,Y)- (2*delta or sigma) [cm]
+   primGen->SmearVertexXY(kTRUE);
+//   //primGen->SmearGausVertexXY(kTRUE);
+//    
+   primGen->SetTarget(0.,5.);  // Z- position, 2*delta or sigma [cm]
+   primGen->SmearVertexZ(kTRUE);
+//   //primGen->SmearGausVertexZ(kTRUE);
+ 
+  /* ------------------------------------------------ */ 
+  /* +++++++++++++++ GLOBAL OPTIONS +++++++++++++++++ */
+  /* ------------------------------------------------ */ 
+  
+  //run->SetStoreTraj(kTRUE);
+ 
+  //SpdCommonGeoMapper::Instance()->SaveEmptyHits();
+  
+  //run->ForceParticleLifetime(-211, 26.033/5.); // pdg, life time [ns]
+  //run->ForceParticleLifetime( 211, 26.033/5.); // pdg, life time [ns]
+  
+  //SpdCommonGeoMapper::Instance()->UnsetMaterials(true);
+  
+  /* ----------------------------------------------------------------------- */ 
+  /* >>>>>>>>>>>>>>>>>>>>>>>>>>> INITALIZE RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+  /* ----------------------------------------------------------------------- */ 
+  
+  cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++" << endl;
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "+           Init Run (start)               +" << endl; 
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+     
+  run->Init();
+  
+  cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++" << endl;
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "+           Init Run (finish)              +" << endl; 
+  cout << "\t"   << "+                                          +" << endl;
+  cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+ 
+  //return;
+  
+  /*--------------------------------------------------*/
+  /* +++++++++++++ CREATE RUN PARAMETERS  +++++++++++ */
+  /*--------------------------------------------------*/
+  
+  Bool_t MergePars = kFALSE;
+  FairParRootFileIo* parOut = new FairParRootFileIo(MergePars);
+  if (MergePars) parOut->open(parFile.Data());
+  else parOut->open(parFile.Data(),"RECREATE");
+  
+  FairRuntimeDb* rtdb = run->GetRuntimeDb();
+  rtdb->setOutput(parOut);
+   
+  /* ----------------------------------------------------------------------- */ 
+  /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+  /* ----------------------------------------------------------------------- */ 
+  
+  TStopwatch timer;
+  timer.Start();
+  
+  run->Run(nEvents);
+  
+  timer.Stop();
+ 
+  /*--------------------------------------------------*/
+  /* ++++++++++++  SAVE RUN PARAMETERS  +++++++++++++ */
+  /*--------------------------------------------------*/
+ 
+  rtdb->saveOutput();
+  
+  /*--------------------------------------------------*/
+  
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+
+  cout << endl << endl;
+  cout << "Macro finished succesfully." << endl;
+  cout << "Output file is             " << outFile << endl;
+  cout << "Parameter file is          " << parFile << endl;
+  cout << "Seed (prim.gen.) is        " << seed << endl;
+  cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << endl;
+  cout << endl;
+  
+  /*--------------------------------------------------*/
+  
+  //SpdCommonGeoMapper::Instance()->PrintGeometryList();
+  SpdCommonGeoMapper::Instance()->PrintGeometry();
+  
+  //SpdItsGeoMapperX::Instance()->PrintVolPars(); 
+  //SpdItsGeoMapperX::Instance()->PrintGeoTable(); 
+  //SpdItsGeoMapperX::Instance()->Print("");
+  
+  /*--------------------------------------------------*/
+  
+  gApplication->Terminate();
+}
+
diff --git a/macro/tracking/TestKFParticle.C b/macro/tracking/TestKFParticle.C
new file mode 100644
index 0000000000000000000000000000000000000000..721b53d655c00127e72a8be59bfccd5497fbdeb2
--- /dev/null
+++ b/macro/tracking/TestKFParticle.C
@@ -0,0 +1,7 @@
+
+void TestKFParticle() {
+
+  SpdKFParticleTest  kfptest;
+  kfptest.RunTest();
+  
+}
diff --git a/macro/vertexrec/FitIdealTracksV0exam.C b/macro/vertexrec/FitIdealTracksV0exam.C
new file mode 100644
index 0000000000000000000000000000000000000000..5edb11f13a7b41c4cd009f1b7949eae6e34bff99
--- /dev/null
+++ b/macro/vertexrec/FitIdealTracksV0exam.C
@@ -0,0 +1,127 @@
+
+
+void FitIdealTracksV0exam() 
+{
+  //  
+  Int_t nEvents = 0; 
+  
+  TString inFile  = "IdealTracksV0exam.root";         // Input file (MC trakcs)
+  TString parFile = "params_torV0exam.root";          // Parameter file
+  TString outFile = "IdealFittedTracksV0exam.root";   // Output file for tracks
+
+  TString userOutFile = "IdealFindedV0exam.root";     // Output file for V0
+
+  SpdRunAna* Run = new SpdRunAna();
+  
+  Run->SetInputFile(inFile);
+  Run->SetOutputFile(outFile);
+  Run->SetUserOutputFileName(userOutFile);
+  
+  FairRuntimeDb* rtdb = Run->GetRuntimeDb();
+  FairParRootFileIo* parInput = new FairParRootFileIo();
+  parInput->open(parFile.Data());
+  rtdb->setFirstInput(parInput);
+  
+  TStopwatch timer;
+  timer.Start();
+ 
+  //-------------------------------------//
+  // Make task                           //
+  //-------------------------------------//
+ 
+  SpdIdealV0Finder* KalmanFitter = new SpdIdealV0Finder();
+  
+  KalmanFitter->SetVerboseLevel(2); // level = <1 (no prints), 1(default), 2, 3, 4
+  
+  //KalmanFitter->SetTrackingGeoModules(); // add Its,TsTB,TsTEC modules to analysis
+  
+  KalmanFitter->AddModule(12); // Its
+  KalmanFitter->AddModule(2);  // TsTB
+  KalmanFitter->AddModule(3);  // TsTEC
+  
+  // standard options: 
+  KalmanFitter->SetSeedMomentum(1.);           // Start vertex momentum for fit, GeV/c (default = 1 GeV/c) 
+    
+//  KalmanFitter->SetHitRepresentation(kSpdIts,pkPixel);   // options: pkPixel, pkSpacepoint
+//  KalmanFitter->SetHitRepresentation(kSpdTsTB,pkWire);   // options: pkWire, pkWirePoint, pkSpacepoint
+//  KalmanFitter->SetHitRepresentation(kSpdTsTEC,pkWire);  // options: pkWire, pkWirePoint, pkSpacepoint
+
+  KalmanFitter->SetHitRepresentation(kSpdIts,pkSpacepoint);   // options: pkPixel, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTB,pkSpacepoint);   // options: pkWire, pkWirePoint, pkSpacepoint
+  KalmanFitter->SetHitRepresentation(kSpdTsTEC,pkSpacepoint);  // options: pkWire, pkWirePoint, pkSpacepoint
+
+  // advanced options:
+  KalmanFitter->SetVertexFindingMethod(1);     // <1 (vertex will not be found), (default = 1)   
+  KalmanFitter->SetVertexFindingAngleCut(3.0); // skip tracks with theta 90+-cut degree (default = 3[deg])
+  
+  KalmanFitter->SetStartSeedMethod(2);         // set [SeedMethod]: choose start value initialization method (1, 2 = default)
+  
+  KalmanFitter->SetSmearSeedValues(true);      // [SeedMethod = 1,2] start values smearing flag (default = true)
+  KalmanFitter->SetSmearingMomDelta(0.1);      // [SeedMethod = 1,2] track start momentum smearing (+-)value, GeV/c (default = 0.1 GeV/c) 
+  KalmanFitter->SetSmearingAngleDelta(3.0);    // [SeedMethod = 1] track start angle smearing  (+-)value, deg (default = 3.0 deg)
+  KalmanFitter->SetSmearingVertexDelta(0.5);   // [SeedMethod = 1] track start vertex position smearing (+-)value, cm (default = 0.5 cm)
+  KalmanFitter->SetNPointsVertexUse(0);        // [SeedMethod = 2] <1 (default): number of points is the maximum possible (usually 5-6 )
+  
+  KalmanFitter->SetFitterMaxIterations(8);     // default: 8,  minimum: 4
+  KalmanFitter->SetFitterMaxTrials(2);         // default: 10, minimum: 1
+
+// option for V0 finder
+//-----------------------
+  KalmanFitter->SetFirstDaughter(321);         // PDG code for the first daughter
+  KalmanFitter->SetSecondDaughter(211);        // PDG code for the second daughter
+  KalmanFitter->SetUsedTypeOfPV(1);            // = 0 => use sim PV or = 1 => use reco PV
+  KalmanFitter->SetConstrainToPV(1);           // = 0 => without constrain, = 1 with PV constrain
+  KalmanFitter->SetMinTrackPVchi2(2.0);        // minimum topo Chi2 of track to PV 
+  KalmanFitter->SetMinDistDaughter(0.075);     // minimum distance between daughter particles  
+  KalmanFitter->SetMinimumMass(0.00);          // minimum mass of mother (V0) particle  
+  KalmanFitter->SetMaximumMass(2.50);          // maximum mass of mother (V0) particle  
+
+  // Material effects option: <  1 : fit without materials;
+  //                          >= 1 : fit taking into accont material effects (default);
+  
+  KalmanFitter->SetMaterialEffectsOption(1);
+//  KalmanFitter->SetMaterialEffectsOption(0);
+  
+  //SpdGeoLoader::ForceTopGeoFile("cave_precise.geo"); // force top volume (Cave) geometry (default: parameters will be used); 
+
+  // method to update covariance matrix (default = 1)  
+  KalmanFitter->SetFitterOption(1);    
+
+  //store fitted tracks (full fitter info, by default = false) 
+  KalmanFitter->SetStoreTracks(true);
+  
+  //------------------------------------//
+  Run->AddTask(KalmanFitter);
+  
+  //return;
+  
+  cout << "Start ... " << endl;
+  
+  Run->Initialize();
+  
+  //return;
+       
+  Run->Run(0, nEvents);
+  //Run->Run(100,200);
+//  Run->Run(0,500);
+//  Run->Run(0,100);
+//  Run->Run(0,50);
+//  Run->Run(0,10);
+//  Run->Run(0,5);
+  
+  KalmanFitter->DeleteGeoLoader();
+  
+  timer.Stop();
+  
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  
+  cout << endl << endl;
+  cout << "Macro finished succesfully." << endl;
+  cout << "Output file is "    << outFile << endl;
+  cout << "Parameter file is " << parFile << endl;
+  cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
+  cout << endl;
+  
+  gApplication->Terminate();
+}
diff --git a/macro/vertexrec/MakeIdealTracksAndV0.C b/macro/vertexrec/MakeIdealTracksAndV0.C
new file mode 100644
index 0000000000000000000000000000000000000000..86dc7f22ac9f3aa7c430e13f6fdb4624e0557b1e
--- /dev/null
+++ b/macro/vertexrec/MakeIdealTracksAndV0.C
@@ -0,0 +1,115 @@
+
+
+void MakeIdealTracksAndV0() 
+{
+  //  
+  Int_t nEvents = 0; 
+  
+//  TString inFile  = "run_torV02.root";       // Input file (MC events)
+//  TString parFile = "params_torV02.root";    // Parameter file
+//  TString outFile = "IdealTracksV02.root";   // Output file
+
+  TString inFile  = "run_torV0exam.root";       // Input file (MC events)
+  TString parFile = "params_torV0exam.root";    // Parameter file
+  TString outFile = "IdealTracksV0exam.root";   // Output file
+
+  SpdRunAna* Run = new SpdRunAna();
+  
+  Run->SetInputFile(inFile);
+  Run->SetOutputFile(outFile);
+  
+  FairRuntimeDb* rtdb = Run->GetRuntimeDb();
+  FairParRootFileIo* parInput = new FairParRootFileIo();
+  parInput->open(parFile.Data());
+  rtdb->setFirstInput(parInput);
+  
+  TStopwatch timer;
+  timer.Start();
+ 
+  //-------------------------------------//
+  // Make task                           //
+  //-------------------------------------//
+ 
+  SpdIdealTrackFinder* TrackFinder = new SpdIdealTrackFinder();
+  
+  // set geometry
+  //TrackFinder->SetTrackingGeoModules(); // Its,TsTB,TsTEC
+  
+  TrackFinder->AddModule(12); // Its
+  TrackFinder->AddModule(2);  // TsTB
+  TrackFinder->AddModule(3);  // TsTEC
+  
+  // set cuts
+//  TrackFinder->SetMinMomentum(1e-2);  // momentum cut;  default = 1e-2 (10 Mev); absiolute min. value = 4e-3 (4 MeV)
+//  TrackFinder->SetMinGammaBeta(0.5);  // p/m cut; default = 0.5; absiolute min. value = 0.05
+//  TrackFinder->SetMinVertexNHits(1);  // its hits number cut; default = 1; absolute min. value = 0;  
+//  TrackFinder->SetMinTrackerNHits(2); // tstb+tstec hits number cut; default = 2; absiolute min. value = 2;  
+
+  TrackFinder->SetMinMomentum(0.350);  // momentum cut;  default = 1e-2 (10 Mev); absiolute min. value = 4e-3 (4 MeV)
+  TrackFinder->SetMinGammaBeta(0.50);  // p/m cut; default = 0.5; absiolute min. value = 0.05
+  TrackFinder->SetMinVertexNHits(3);   // its hits number cut; default = 1; absolute min. value = 0;  
+  TrackFinder->SetMinTrackerNHits(10); // tstb+tstec hits number cut; default = 2; absiolute min. value = 2;  
+  
+  // set hits resolution
+  Double_t mkm = 1e-4;
+ 
+  // ------ INNER TRACKER -----
+ 
+  TrackFinder->SetHitResolution(kSpdIts,  'p',  50*mkm,  50*mkm); // ENDCAP: POINT  (u=x,v=y)
+  TrackFinder->SetHitResolution(kSpdIts,  'm',  50*mkm,  50*mkm); // BARREL: MAPS   (u,v)
+  TrackFinder->SetHitResolution(kSpdIts,  's',  50*mkm,  50*mkm); // BARREL: DSSD   (u,v)
+  
+  // ----- STRAW TRACKER -----
+  
+  // --- barrel ---
+  TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm);                  // Wire(1D)    (r,z)
+  //TrackFinder->SetHitResolution(kSpdTsTB, 'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+ 
+  //--- endcaps ---
+  TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm);                  // Wire(1D)    (r,z)
+  //TrackFinder->SetHitResolution(kSpdTsTEC,'w', 150*mkm, 2. /*cm*/);       // Wire(1D,2D) (r,z)
+  
+  TrackFinder->AppendSecondaryTracks();
+  
+  //------------------------------------//
+  Run->AddTask(TrackFinder);
+  
+  //return;
+  
+  cout << "Start ... " << endl;
+  
+  Run->LoadGeoParSet(false);
+  Run->Initialize();
+  
+  //return;
+       
+  Run->Run(0, nEvents);
+//  Run->Run(0, 10);
+  
+  TrackFinder->DeleteGeoLoader();
+  
+  timer.Stop();
+  
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  
+  cout << endl << endl;
+  cout << "Macro finished succesfully." << endl;
+  cout << "Output file is "    << outFile << endl;
+  cout << "Parameter file is " << parFile << endl;
+  cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << endl;
+  cout << endl;
+    
+  /* DRAW GEOMETRY */
+   
+//   TGeoManager *geoMan = gGeoManager;
+//   
+//   if (geoMan && geoMan->GetMasterVolume()) {    
+//       geoMan->SetVisLevel(2);
+//       geoMan->GetMasterVolume()->Draw("ogl");
+//       //geoMan->GetMasterVolume()->Draw();
+//   }
+  
+   gApplication->Terminate();
+}
+
diff --git a/macro/vertexrec/SimuV0IdealExam.C b/macro/vertexrec/SimuV0IdealExam.C
new file mode 100644
index 0000000000000000000000000000000000000000..5934a89cd09027b27506535699c32d6a68f47985
--- /dev/null
+++ b/macro/vertexrec/SimuV0IdealExam.C
@@ -0,0 +1,347 @@
+
+//#define _COMPILE_MACRO_
+
+#if defined(_COMPILE_MACRO_) 
+
+#include <TRint.h>
+#include <TStopwatch.h>
+
+#include "FairParRootFileIo.h"
+
+#include "SpdRunSim.h"
+#include "SpdMCEventHeader.h"
+
+#include "SpdCommonGeoMapper.h"
+
+#include "SpdFields.hh"
+#include "SpdGenerators.hh"
+
+#include "SpdCave.h"
+#include "SpdPipe.h"
+#include "SpdHybMagnet.h"
+
+#include "SpdIts.h"
+#include "SpdTsTB.h"
+#include "SpdTsTEC.h"
+#include "SpdEcalTB.h"
+#include "SpdEcalTEC.h"
+#include "SpdRsTB.h"
+#include "SpdRsTEC.h"
+
+#include "SpdItsGeoMapperX.h"
+#include "SpdTsTBGeoBuilder.h"
+
+#endif
+
+void CustomizeGeometryIts();
+void CustomizeGeometryTsTB();
+void CustomizeGeometryTsTEC();
+
+//_________________________________________________________________________
+void SimuV0IdealExam(Int_t nEvents = 200)
+{
+   TString outFile = "run_torV0exam.root";     // Output data file name
+   TString parFile = "params_torV0exam.root";  // Output parameters file name
+   
+   SpdRunSim* run = new SpdRunSim();
+  
+   run->SetName("TGeant4");       
+   run->SetMaterials("media.geo");
+  
+   run->SetOutputFile(outFile);      
+  
+   TString decayer = "DecayConfigSpecV0.C";
+   run->SetPythiaDecayer(decayer);
+ 
+   run->SetMCEventHeader(new SpdMCEventHeader);
+ 
+   /*--------------------------------------------------*/
+   /* +++++++++     GEOMETRY (HYBRID)      +++++++++++ */
+   /*--------------------------------------------------*/
+  
+   SpdCommonGeoMapper::Instance()->DefineHybGeometrySet();
+
+//   SpdCommonGeoMapper::Instance()->UnsetMaterials(1);   // all geom is vacuum
+  
+   /* ++++++++++++++++++ CAVE ++++++++++++++++++ */
+  
+   FairModule* cave = new SpdCave("CAVE");
+   //cave->SetGeometryFileName("cave.geo");
+   cave->SetGeometryFileName("cave_precise.geo");
+   run->AddModule(cave);
+  
+   /* ++++++++++++++++++ PIPE ++++++++++++++++++ */
+  
+   SpdPipe* Pipe = new SpdPipe();
+   run->AddModule(Pipe);
+  
+   /* +++++++++++++++++ MAGNET +++++++++++++++++ */
+  
+//   SpdHybMagnet* Magnet = new SpdHybMagnet();
+//   //Magnet->SetGeometryType(2); // 1 = "hybrid" (deafult), 2 = "qsolenoid"
+//   run->AddModule(Magnet);
+  
+   /* +++++++++++++++++ DETECTORS ++++++++++++++ */
+ 
+   SpdTsTB*    ts_barrel   = new SpdTsTB();     /* +++++++++ TST (BARREL) ++++++++++++ */ 
+   SpdTsTEC*   ts_ecps     = new SpdTsTEC();    /* +++++++++ TST (ENDCAPS) +++++++++++ */     
+    
+   run->AddModule(ts_barrel);
+   run->AddModule(ts_ecps);   
+    
+   /* ===== Vertex detector ===== */
+
+   SpdIts* its = new SpdIts(); 
+   run->AddModule(its);
+  
+   SpdItsGeoMapperX::Instance()->EnableEndcaps(); // enable(1)/disable(0) endcaps
+
+   /*--------------------------------------------------*/
+   /* ++++++++++++  CASTOMIZE GEOMETRY   +++++++++++++ */
+   /*--------------------------------------------------*/
+  
+   CustomizeGeometryIts();
+   CustomizeGeometryTsTB();
+   CustomizeGeometryTsTEC();
+   
+   /*--------------------------------------------------*/
+   /* ++++++++++++++   MAGNETIC FIELD   ++++++++++++++ */
+   /*--------------------------------------------------*/
+   
+   /* --- const field --- */
+   SpdConstField* MagField = new SpdConstField();  
+   MagField->SetField(0., 0. , 10.0); //  kG
+
+   /* --- field map --- */
+//   SpdFieldMap* MagField = new SpdFieldMap("Hybrid field");
+  
+  // MagField->InitData("map_hyb_1T2cm.bin");       // standard "hybrid" field
+//   MagField->InitData("map_sol_6cls5cm2.bin");  // "quasi-solenoid"
+  
+  // MagField->SetApproxMethod(0); // 0 (linear,default) or 1 (nearest vertex)
+  // MagField->MultiplyField(1);
+
+//   MagField->MultiplyField(1);
+  
+   /* === define field region === */
+   SpdRegion* reg = 0;
+  
+   //reg = MagField->CreateFieldRegion("box");
+   //reg->SetBoxRegion(-1000, 1000, -1000, 1000, -1000, 1000); // (X,Y,Z)_(min,max), cm
+  
+   reg = MagField->CreateFieldRegion("tube");
+   reg->SetTubeRegion(0, 250, -300, 300); // (R,Z)_(min,max), cm 
+  
+   run->SetField(MagField);
+  
+   MagField->Print();
+  
+   /*--------------------------------------------------*/
+   /* ++++++++++ DEFINE PRIMARY GENERATORS +++++++++++ */
+   /*--------------------------------------------------*/
+ 
+   SpdPrimaryGenerator* primGen = new SpdPrimaryGenerator();
+
+   //============================
+   //    PYTHIA 6 GENERATOR
+   //============================
+      
+   SpdPythia6Generator* P6gen = new SpdPythia6Generator();
+      
+   //-----------------------------------------------------------
+   // Option: (decayer for vertex meson- and baryon- resonances)
+   // 0 = Transport generator + External decayer (particles don't decay in the vertex) 
+   // 1 = Primary generator (DEFAULT value, more safely)
+      
+   P6gen->SetVGenOpt(1);
+
+   //-----------------------------------------------------------
+   // Set seed:
+   gRandom->SetSeed(54545);
+      
+   Int_t seed = gRandom->Integer(Int_t(1e9));
+   //P6gen->SetSeed(seed);
+   P6gen->SetSeed(13495);
+
+   /* --- Set Pythia6 options --- */
+   SpdPythia6* gg = (SpdPythia6*)P6gen->GetGenerator();
+       
+   gg->SetMSEL(1);  // set miminum bias 
+       
+   /* --- Pythia6 initialization --- */
+   P6gen->Initialize("cms","p","p",27/*GeV*/);
+       
+   primGen->AddGenerator(P6gen);
+
+   //===========================
+   //   ISOTROPIC GENERATOR (1)
+   //===========================
+
+   SpdIsotropicGenerator* isogen = new SpdIsotropicGenerator("isogen");
+      
+//   isogen->Initialize(310, 1.5, 1);  // Ks^0
+   isogen->Initialize(421, 1.5, 1);  // D^0
+//   isogen->Initialize(411, 1.5, 1);  // D^+
+   isogen->SetVerboseLevel(1);
+   isogen->SetSeed(39211); 
+//   isogen->SetVGenOpt(-1);  // (+-)1, (+-)2
+   isogen->SetVGenOpt(1);  // (+-)1, (+-)2
+
+//   isogen->SetSpherical(70.0, 110.0, 0.0, 360.0); // theta[min,max], phi[min,max]
+   primGen->AddGenerator(isogen);
+
+   /* run generator */
+
+   run->SetGenerator(primGen);  
+  
+   primGen->SetVerboseLevel(-10);
+//   primGen->SetVerbose(0);
+      
+//   primGen->SetBeam(0., 0., 0.1, 0.1); // (X,Y)- position, (X,Y)- (0.5*delta or sigma) [cm]
+   primGen->SetBeam(0., 0., 0.0, 0.0); // (X,Y)- position, (X,Y)- (0.5*delta or sigma) [cm]
+   primGen->SmearVertexXY(kFALSE);
+//   primGen->SmearVertexXY(kTRUE);
+//   primGen->SmearGausVertexXY(kTRUE);
+   
+//   primGen->SetTarget(0.,5.);  // Z- position, 0.5*delta or sigma [cm]
+   primGen->SetTarget(0., 0.);  // Z- position, 0.5*delta or sigma [cm]
+   primGen->SmearVertexZ(kFALSE);
+   // primGen->SmearVertexZ(kTRUE);
+   // primGen->SmearGausVertexZ(kTRUE);
+ 
+   /* ------------------------------------------------ */ 
+   /* +++++++++++++++ GLOBAL OPTIONS +++++++++++++++++ */
+   /* ------------------------------------------------ */ 
+  
+   //run->SetStoreTraj(kTRUE);
+ 
+//   SpdCommonGeoMapper::Instance()->SaveEmptyHits();
+  
+   //SpdCommonGeoMapper::Instance()->UnsetMaterials(1);  // set all materials = vacuum (precise)
+      
+   /* ----------------------------------------------------------------------- */ 
+   /* >>>>>>>>>>>>>>>>>>>>>>>>>>> INITALIZE RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+   /* ----------------------------------------------------------------------- */ 
+  
+   cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++"   << endl;
+   cout << "\t"   << "+                                          +"   << endl;
+   cout << "\t"   << "+           Init Run (start)               +"   << endl; 
+   cout << "\t"   << "+                                          +"   << endl;
+   cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+     
+   run->Init();
+  
+   cout << "\n\t" << "++++++++++++++++++++++++++++++++++++++++++++"   << endl;
+   cout << "\t"   << "+                                          +"   << endl;
+   cout << "\t"   << "+           Init Run (finish)              +"   << endl; 
+   cout << "\t"   << "+                                          +"   << endl;
+   cout << "\t"   << "++++++++++++++++++++++++++++++++++++++++++++\n" << endl;
+ 
+   /*--------------------------------------------------*/
+   /* +++++++++++++ CREATE RUN PARAMETERS  +++++++++++ */
+   /*--------------------------------------------------*/
+  
+   Bool_t MergePars = kFALSE;
+   FairParRootFileIo* parOut = new FairParRootFileIo(MergePars);
+   if (MergePars) parOut->open(parFile.Data());
+   else parOut->open(parFile.Data(),"RECREATE");
+  
+   FairRuntimeDb* rtdb = run->GetRuntimeDb();
+   rtdb->setOutput(parOut);
+   
+   /* ----------------------------------------------------------------------- */ 
+   /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> RUN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+   /* ----------------------------------------------------------------------- */ 
+  
+   TStopwatch timer;
+   timer.Start();
+  
+   run->Run(nEvents);
+  
+   timer.Stop();
+ 
+   /*--------------------------------------------------*/
+   /* ++++++++++++  SAVE RUN PARAMETERS  +++++++++++++ */
+   /*--------------------------------------------------*/
+ 
+   rtdb->saveOutput();
+  
+   /*--------------------------------------------------*/
+  
+   Double_t rtime = timer.RealTime();
+   Double_t ctime = timer.CpuTime();
+  
+   cout << endl << endl;
+   cout << "Macro finished succesfully." << endl;
+   cout << "Output file is "             << outFile << endl;
+   cout << "Parameter file is "          << parFile << endl;
+   cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << endl;
+   cout << endl;
+  
+   /*--------------------------------------------------*/
+  
+   //SpdCommonGeoMapper::Instance()->PrintGeometryList();
+   SpdCommonGeoMapper::Instance()->PrintGeometry();
+  
+   //SpdItsGeoMapperX::Instance()->PrintVolPars(); 
+   //SpdItsGeoMapperX::Instance()->PrintGeoTable(); 
+   //SpdItsGeoMapperX::Instance()->Print("");
+  
+   /*--------------------------------------------------*/
+  
+   gApplication->Terminate();
+
+}
+
+//________________________________________________________________________________________________
+void CustomizeGeometryTsTB()
+{
+   //return;
+  
+   //SpdTsTECGeoMapper::Instance()->SetGeometryPars(2);
+  
+   SpdTsTBGeoBuilder* builder = SpdTsTBGeoBuilder::Instance();
+     
+   // ---------------------------------------------------
+   // SpdTsTBGeoBuilder::AddRejection(volname ,nmin, nmax, lcycle).
+   // Remove nj = n + j*lcycle layers, where 
+   // n = [nmin,nmax], j = 0,1,... , lcycle >= n.
+   // volname = unique part of volume name placed 
+   // before its number (for example SpdTsTBLayer23 ->
+   // SpdTsTBLayer, TsTBLayer, TBLayer or Layer).
+   // ---------------------------------------------------
+   
+    Int_t lcycle = 8; // number of different layer (layer cycle)
+   
+    builder->AddRejection("Layer", 1, 2, lcycle);
+    builder->AddRejection("Layer", 3, 4, lcycle);
+    //builder->AddRejection("Layer", 5, 6, lcycle);
+    builder->AddRejection("Layer", 7, 8, lcycle);
+     
+   
+//     builder->AddRejection("Layer", 16);
+//     builder->AddRejection("Layer", 30);
+//     builder->AddRejection("Layer", 35, 45);
+//     builder->AddRejection("Layer", 56, 67);
+//     builder->AddRejection("Layer", 80, 88);
+    
+}
+
+//________________________________________________________________________________________________
+void CustomizeGeometryTsTEC()
+{
+    
+    
+}
+
+//________________________________________________________________________________________________
+void CustomizeGeometryIts()
+{
+    
+    
+}
+
+
+
+
+
diff --git a/passive/CMakeLists.txt b/passive/CMakeLists.txt
index b535ca8dd596c5d1f74d4b6c3464ed4a22f2e159..6ac6e2637ab81f5a0fa2ddea8c4e721f004e8360 100644
--- a/passive/CMakeLists.txt
+++ b/passive/CMakeLists.txt
@@ -32,10 +32,19 @@ SpdTorBasket.cxx
 SpdSolMagnet.cxx  
 SpdTorMagnet.cxx  
 SpdHybMagnet.cxx  
-SpdPassiveContFact.cxx
 )
 
-Set(HEADERS )
+Set(HEADERS 
+SpdCave.h
+SpdGeoCave.h
+SpdGeoFrame.h
+SpdHybMagnet.h
+SpdPipe.h
+SpdSolMagnet.h
+SpdTorBasket.h
+SpdTorMagnet.h
+)
+
 Set(LINKDEF PassiveLinkDef.h)
 Set(LIBRARY_NAME SpdPassive)
 Set(DEPENDENCIES Base GeoBase ParBase SpdCommon SpdData)
diff --git a/passive/PassiveLinkDef.h b/passive/PassiveLinkDef.h
index 5d5ff94fefca9296f7ef2b512d4e9d1ca2cde4bc..bc3e49659149013d0489a91da9e92e062adf1ce6 100644
--- a/passive/PassiveLinkDef.h
+++ b/passive/PassiveLinkDef.h
@@ -14,7 +14,6 @@
 
 #pragma link C++ class  SpdCave+;
 #pragma link C++ class  SpdGeoCave+;
-#pragma link C++ class  SpdPassiveContFact+;
 #pragma link C++ class  SpdGeoFrame+;
 #pragma link C++ class  SpdTorBasket+;
 #pragma link C++ class  SpdPipe+;
diff --git a/passive/SpdCave.cxx b/passive/SpdCave.cxx
index bf3e06da1bd51afdfebe4b8e0b7d3f1cf8aa07d3..4b8bb07e18906c28ee726a592c07b2f1e60fe1e7 100644
--- a/passive/SpdCave.cxx
+++ b/passive/SpdCave.cxx
@@ -2,13 +2,20 @@
 #include "SpdCave.h"
 #include "SpdGeoCave.h"       
 
-#include "FairGeoInterface.h"    
-#include "FairGeoLoader.h"       
+#include "SpdParSetContFact.h"
+#include "SpdPassiveGeoParSet.h"
+
+#include "FairGeoMedia.h"
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
 
 ClassImp(SpdCave)
 
 //_____________________________________________________________________________________
-SpdCave::SpdCave(): FairModule()
+SpdCave::SpdCave():FairModule()
 {
   
 }
@@ -32,11 +39,135 @@ void SpdCave::ConstructGeometry()
   
     Bool_t rc = GeoInterface->readSet(MGeo);
     if (rc) MGeo->create(loader->getGeoBuilder());  
+    
+    FillParsIn(GetParameters());
+    
+    cout << "-I- <SpdCave::ConstructGeometry> actual geometry: " << fgeoName << endl;
 }
 
+//_____________________________________________________________________________________
+void SpdCave::SetGeometryFileName(TString fname, TString geoVer)
+{
+    if (fgeoName == "Not defined" || fgeoName.IsWhitespace()) {
+        FairModule::SetGeometryFileName(fname);
+        cout << "-I- <SpdCave::SetGeometryFileName> Geometry: " << fgeoName << endl;
+        return;
+    }
+    
+    if (fname == fgeoName) {
+        cout << "-I- <SpdCave::SetGeometryFileName> Geometry has already been defined: " 
+             << fgeoName << endl;
+        return;
+    }
+        
+    FairModule::SetGeometryFileName(fname);
+    cout << "-I- <SpdCave::SetGeometryFileName> New geomery: " << fgeoName << endl;
+}
 
+//_____________________________________________________________________________________
+TString SpdCave::GetGeometryFileName()
+{
+    SpdPassiveGeoParSet* pars = GetParameters();
+    
+    if (fgeoName != "Not defined" && !fgeoName.IsWhitespace()) {
+    
+        if (!pars) return fgeoName;
+        
+        TString s = fgeoName;
+        if (s.Contains("/")) s.Remove(0,s.Last('/')+1);
 
+        TString ss;
+        if (pars->GetParameter("SpdCave/GeometryFileName",ss)) {
+            if (s != ss) {
+                cout << "-W- <SpdCave::GetGeometryFileName> geometry is changed: " 
+                     << ss << " -> " << s << endl;
+            }
+            else return fgeoName;
+        }
+        else {
+            pars->SetParameter("SpdCave/GeometryFileName",s.Data()); // save user geometry
+            pars->setChanged();
+            pars->setInputVersion(FairRun::Instance()->GetRunId(),1);
+        }
 
+        cout << "-I- <SpdCave::GetGeometryFileName> set user geometry: " << fgeoName << endl;
+    }
+    else {
+        TString s;
+        if (pars) {
+            if (pars->GetParameter("SpdCave/GeometryFileName",s)) {
+                cout << "-I- <SpdCave::GetGeometryFileName> set geometry from parameters: " << s << endl;
+            }
+            else {
+                s = "cave.geo";
+                cout << "-W- <SpdCave::GetGeometryFileName> set default geometry: " << s << endl;
+                pars->SetParameter("SpdCave/GeometryFileName",s.Data()); // save default geometry
+                pars->setChanged();
+                pars->setInputVersion(FairRun::Instance()->GetRunId(),1);
+            }
+        }
+        else {
+            s = "cave.geo";
+            cout << "-W- <SpdCave::GetGeometryFileName> set default geometry (*): " << s << endl;
+        }
+        SetGeometryFileName(s);
+    }
+    
+    return fgeoName;
+}
 
+//_____________________________________________________________________________________
+Bool_t SpdCave::FillParsIn(SpdPassiveGeoParSet* params)
+{
+    if (!params) return kFALSE;
+    
+    FairGeoLoader* loader = FairGeoLoader::Instance();
+    FairGeoInterface* GeoInterface = loader->getGeoInterface();
+    
+    TString s = GeoInterface->getMedia()->getInputFile();
+    if (s.Contains("/")) s.Remove(0,s.Last('/')+1);
+    
+    TString ss;
+    if (params->GetParameter("Global/MediaFileName",ss)) {
+        if (s != ss) {
+            cout << "-W- <SpdCave::FillParsIn> media file is changed: " 
+                 << ss << " -> " << s << endl;
+        }
+    }
+    else {
+        params->SetParameter("Global/MediaFileName",s.Data());
+    }
+    
+    return kTRUE;
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdCave::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+    if (!params) return kFALSE;
+    
+    TString s;
+    if (!params->GetParameter("SpdCave/GeometryFileName",s)) {
+        cout << "-W- <SpdCave::LoadParsFrom> geometry is not defined: " << endl; 
+        return kFALSE;
+    }
+    
+    SetGeometryFileName(s);
+    
+    cout << "-I- <SpdCave::LoadParsFrom> load geometry: " << fgeoName << endl;
+
+    return kTRUE;
+}
+
+//_____________________________________________________________________________________
+SpdPassiveGeoParSet* SpdCave::GetParameters()
+{
+    FairRun* run = FairRun::Instance();
+    if (!run) return 0;
+    FairRuntimeDb* rtdb = run->GetRuntimeDb(); 
+    if (!rtdb) return 0;
+    SpdPassiveGeoParSet* pars = (SpdPassiveGeoParSet*)(rtdb->getContainer("PassiveGeoParSet"));
+    return pars;
+}
 
 
diff --git a/passive/SpdCave.h b/passive/SpdCave.h
index 3dcec1cd89bc8bd646a546bad801a179647110f4..7b303de709f75b6212e242a6c58d32aa1e80116c 100644
--- a/passive/SpdCave.h
+++ b/passive/SpdCave.h
@@ -3,6 +3,7 @@
 #define __SPDCAVE_H__
 
 #include "FairModule.h"            
+#include "SpdPassiveGeoParSet.h"
 
 /////////////////////////////////////////////////////////////////////////////////
 //
@@ -22,9 +23,18 @@ public:
     virtual ~SpdCave() {}
     
     virtual void ConstructGeometry();
+    
+    virtual TString GetGeometryFileName();
+    virtual void SetGeometryFileName(TString fname, TString geoVer = "0");
 
+    SpdPassiveGeoParSet* GetParameters();
+    TString GetActualGeometryFileName() const { return fgeoName; }
+    
+    Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
+    
 private:
-   
+    
     ClassDef(SpdCave,1) 
 };
 
diff --git a/passive/SpdGeoFrame.cxx b/passive/SpdGeoFrame.cxx
index acc9fc9481a11d22c5cb05f6bdd76bc1e4c40368..fe244a6d1c94b738f3a744d1f1a560d70ca0dc9d 100644
--- a/passive/SpdGeoFrame.cxx
+++ b/passive/SpdGeoFrame.cxx
@@ -72,9 +72,9 @@ Double_t SpdGeoFrame::GetMass() const
 }
 
 //_____________________________________________________________________________________
-void SpdGeoFrame::UnsetMaterials(Bool_t precise)
+void SpdGeoFrame::UnsetMaterials(TString media)
 {
-  
+   fUnsetMedia = media;
 }
 
 //_____________________________________________________________________________________
@@ -85,3 +85,18 @@ void SpdGeoFrame::Print(Option_t*) const
    cout <<"\n";
 }
 
+//_____________________________________________________________________________
+Bool_t SpdGeoFrame::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdGeoFrame::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}
+
+
diff --git a/passive/SpdGeoFrame.h b/passive/SpdGeoFrame.h
index e2882a811d1dd82756a50c496ddcac15a9a542fc..ec6a8e9746363138401fb704d5dfea083234ca2c 100644
--- a/passive/SpdGeoFrame.h
+++ b/passive/SpdGeoFrame.h
@@ -30,9 +30,12 @@ public:
     virtual Double_t GetCapacity() const;  // cm^3
     virtual Double_t GetMass()     const;  // g
   
-    virtual void UnsetMaterials(Bool_t precise = kTRUE);
+    virtual void UnsetMaterials(TString media = "vacuum2");
     
     virtual void Print(Option_t*) const;
+    
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
  
 private:
     
diff --git a/passive/SpdHybMagnet.cxx b/passive/SpdHybMagnet.cxx
index 082b516c5503963fe278d22e569f78656886b04a..55989fc18a4a4acd80aaeda7bb52577774d97598 100644
--- a/passive/SpdHybMagnet.cxx
+++ b/passive/SpdHybMagnet.cxx
@@ -8,6 +8,7 @@
 
 #include "SpdHybMagnet.h"
 #include "SpdCommonGeoMapper.h"
+#include "SpdPassiveGeoParSet.h"
 
 #include <TGeoManager.h>
 #include <TGeoTube.h>
@@ -142,13 +143,16 @@ void SpdHybMagnet::ConstructGeometry()
        return;
    }
    
-   if (fGeoType == 1) fLockGeom = ConstructGeometry_1();
+        if (fGeoType == 1) fLockGeom = ConstructGeometry_1();
    else if (fGeoType == 2) fLockGeom = ConstructGeometry_2();
+   else if (fGeoType == 3) fLockGeom = ConstructGeometry_2();
    else {
        cout << "-E- <SpdHybMagnet::ConstructGeometry> "
             << " Unknown geometry type: " << fGeoType << endl; 
        fGeoType = 0;     
    }
+   
+   FillParsIn(GetParameters());
 }
  
 //_____________________________________________________________________________
@@ -198,7 +202,7 @@ Bool_t SpdHybMagnet::ConstructGeometry_1() // private
    
    fRingCoil.counts_ = 4;
   
-   cout << "-I- <SpdHybMagnet::ConstructGeometry_1> "<< endl;
+   cout << "-I- <SpdHybMagnet::ConstructGeometry_1> Geometry type: " << fGeoType << endl;
    
    return kTRUE;
 }
@@ -221,7 +225,7 @@ Bool_t SpdHybMagnet::ConstructGeometry_2() // private
    
    fRingCoil.counts_ = 6;
   
-   cout << "-I- <SpdHybMagnet::ConstructGeometry_2> "<< endl;
+   cout << "-I- <SpdHybMagnet::ConstructGeometry_2> Geometry type: " << fGeoType << endl;
    
    return kTRUE;
 }
@@ -357,8 +361,9 @@ void SpdHybMagnet::SetGeometryType(Int_t type)
        SetGeoPars(0);
        return;
    }
-   else if (type == 1) SetGeoPars(1);
-   else if (type == 2) SetGeoPars(2);
+   else if (type == 1) SetGeoPars(type);
+   else if (type == 2) SetGeoPars(type);
+   else if (type == 3) SetGeoPars(type);
    else {
        cout << "-E- <SpdHybMagnet::SetGeometryType> "
             << " Unknown geometry type: " << type << endl; 
@@ -367,7 +372,7 @@ void SpdHybMagnet::SetGeometryType(Int_t type)
 }
 
 //_____________________________________________________________________________
-void SpdHybMagnet::UnsetMaterials(Bool_t precise)
+void SpdHybMagnet::UnsetMaterials(TString media)
 {
    if (fLockGeom) {
        cout << "-E- <SpdHybMagnet::UnsetMaterials> "
@@ -375,13 +380,20 @@ void SpdHybMagnet::UnsetMaterials(Bool_t precise)
        return;
    }  
    
-   TString material;
-   
-   (precise) ? material = "vacuum2" : material = "vacuum";
+   //cout << "-I- <SpdHybMagnet::UnsetMaterials> " << media << endl;
+     
+   fLoopCoil.base_material_ = media;
+   fLoopCoil.coil_material_ = media;   
+   fRingCoil.coil_material_ = media;
    
-   fLoopCoil.base_material_ = material;
-   fLoopCoil.coil_material_ = material;   
-   fRingCoil.coil_material_ = material;
+   fUnsetMedia = media;
+}
+
+//_____________________________________________________________________________
+void SpdHybMagnet::ResetMaterials()
+{
+   if (fLockGeom) return;
+   SetDefaultMaterials(fGeoType);
 }
 
 //_____________________________________________________________________________
@@ -734,6 +746,7 @@ void SpdHybMagnet::Print(Option_t*) const
    
    cout << "\tGeometry type:           " << fGeoType << endl;
    cout << "\tUnique module Id:        " << fModuleId << endl; 
+   cout << "\tUnset media:             " << fUnsetMedia << endl;
    
    if (fGeoType < 1) { cout << endl; return; }
    
@@ -801,7 +814,7 @@ void SpdHybMagnet::SetGeoPars(Int_t geotype) // private
    fRingCoilAxialDistanceL2 = 0;    
    fRingCoilAxialDistanceC  = 0;
        
-   if (geotype != 1 && geotype != 2) {
+   if (geotype < 1 && geotype > 3) {
        cout << "-I- <SpdHybMagnet::SetGeoPars> No geometry will be built " << endl;          
        return;
    }
@@ -860,9 +873,74 @@ void SpdHybMagnet::SetGeoPars(Int_t geotype) // private
        //fRingCoil.line_color_ = kBlue+3;
        //fRingCoil.transparency_ = 10;
    }
+   
+   else if (fGeoType == 3) {
+      
+       fRingCoil.coil_max_radius_ = SpdCommonGeoMapper::GetHybMagnetRingSize(); 
+       fRingCoil.coil_width_      = SpdCommonGeoMapper::GetHybMagnetCoilWidth();
+       fRingCoil.coil_thickness_  = SpdCommonGeoMapper::GetHybMagnetCoilThickness();  
+     
+       fRingCoilAxialDistanceC  = SpdCommonGeoMapper::GetHybMagnetDistToAxis();  
+       fRingCoilAxialDistanceL1 = SpdCommonGeoMapper::GetHybMagnetDistToAxis1();  
+       fRingCoilAxialDistanceL2 = SpdCommonGeoMapper::GetHybMagnetDistToAxis2();  
+       
+       fRingCoil.coil_material_   = SpdCommonGeoMapper::GetHybMagnetCoilMaterial(); 
+       
+       //fRingCoil.fill_color_ = kBlue+3;
+       //fRingCoil.line_color_ = kBlue+3;
+       //fRingCoil.transparency_ = 10;
+   }
 }
 
+//_____________________________________________________________________________
+void SpdHybMagnet::SetDefaultMaterials(Int_t geotype) // private
+{ 
+   //cout <<"<SpdHybMagnet::SetDefaultMaterials> geometry type: " << geotype << endl;
+    
+   if (geotype != 1 && geotype != 2) {
+       cout << "-I- <SpdHybMagnet::DefaultMaterials> No geometry will be built " << endl;          
+       return;
+   }
+    
+   if (geotype == 1) {
+    
+       fLoopCoil.base_material_ = "air";
+       fLoopCoil.coil_material_ = SpdCommonGeoMapper::GetHybMagnetCoilMaterial();
+       
+       //fLoopCoil.fill_color_ = kBlue+3;
+       //fLoopCoil.line_color_ = kBlue+3;
+       //fLoopCoil.transparency_ = 10;
+       
+       fRingCoil.coil_material_   = SpdCommonGeoMapper::GetHybMagnetCoilMaterial();
+       
+       //fRingCoil.fill_color_ = kBlue+3;
+       //fRingCoil.line_color_ = kBlue+3;
+       //fRingCoil.transparency_ = 10;
+   }
+   
+   else if (fGeoType == 2) {
+     
+       fRingCoil.coil_material_   = SpdCommonGeoMapper::GetHybMagnetCoilMaterial(); 
+       
+       //fRingCoil.fill_color_ = kBlue+3;
+       //fRingCoil.line_color_ = kBlue+3;
+       //fRingCoil.transparency_ = 10;
+   }
+}
 
+//_____________________________________________________________________________
+Bool_t SpdHybMagnet::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdHybMagnet::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}
 
 
 
diff --git a/passive/SpdHybMagnet.h b/passive/SpdHybMagnet.h
index 8700fa93aec863403d1f678f3a22176679bee7ca..7904eee58e2341440a1c94b707c96d876bd42f9d 100644
--- a/passive/SpdHybMagnet.h
+++ b/passive/SpdHybMagnet.h
@@ -14,7 +14,6 @@
 //                                                                            //
 ////////////////////////////////////////////////////////////////////////////////
 
-
 class SpdHybMagnet: public SpdPassiveModule {
 
 public:
@@ -30,7 +29,8 @@ public:
   
     virtual void SetGeometryType(Int_t type);
      
-    virtual void UnsetMaterials(Bool_t precise = kTRUE);  // (all coils)
+    virtual void UnsetMaterials(TString media = "vacuum2");
+    virtual void ResetMaterials(/*set dafault materials*/);
     
     void  SetCoilsMaterial(TString material);             // (all coils)
     
@@ -145,6 +145,9 @@ public:
            
            ClassDef(SpdHybMagnet::LoopCoil,1)
     };
+    
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
        
 private:
   
@@ -159,6 +162,7 @@ private:
     RingCoil fRingCoil;
 
     void SetGeoPars(Int_t geotype);
+    void SetDefaultMaterials(Int_t geotype);
     
     Bool_t ConstructGeometry_1();
     Bool_t ConstructGeometry_2();
diff --git a/passive/SpdPassiveContFact.cxx b/passive/SpdPassiveContFact.cxx
deleted file mode 100644
index afa2a4ab549a9f12aca7e07df845260eaaef3303..0000000000000000000000000000000000000000
--- a/passive/SpdPassiveContFact.cxx
+++ /dev/null
@@ -1,59 +0,0 @@
-
-#include "SpdPassiveContFact.h"
-#include "SpdPassiveGeoPar.h"
-#include "FairRuntimeDb.h"
-
-ClassImp(SpdPassiveContFact)
-
-static SpdPassiveContFact gSpdPassiveContFact;
-
-//_____________________________________________________________________________
-SpdPassiveContFact::SpdPassiveContFact():FairContFact()
-{
-  fName = "SpdPassiveContFact";
-  fTitle = "Factory for parameter containers in libSpdPassive";
-  
-  setAllContainers();
-  
-  FairRuntimeDb::instance()->addContFactory(this); 
-}
-
-//_____________________________________________________________________________
-FairParSet* SpdPassiveContFact::createContainer(FairContainer* c)
-{
-  /*
-      Calls the constructor of the corresponding parameter container.
-      For an actual context, which is not an empty string and not
-      the default context of this container, the name is concatenated 
-      with the context.
-  */
-  
-  const char* name = c->GetName();
-  FairParSet* p = 0;
-  
-//   if (strcmp(name,"SpdPassiveGeoPar") == 0) {
-//       p = new SpdPassiveGeoPar(c->getConcatName().Data(),
-//                                c->GetTitle(),
-//                                c->getContext());
-//   }
-  
-  return p;
-}
-
-//_____________________________________________________________________________
-void SpdPassiveContFact::setAllContainers() 
-{ 
-  /* 
-      Creates the Container objects with all accepted
-      contexts and adds them to
-      the list of containers for the SpdPassive library.
-  */
- 
-  FairContainer* p = new FairContainer("FairGeoPassivePar",
-                                       "SpdPassive Geometry Parameters",
-                                       "TestDefaultContext");
-  p->addContext("TestNonDefaultContext");
-
-  containers->Add(p);
-}
-
diff --git a/passive/SpdPassiveContFact.h b/passive/SpdPassiveContFact.h
deleted file mode 100644
index ab0154543ef0901c545d4b1b81fd5c9309c95f56..0000000000000000000000000000000000000000
--- a/passive/SpdPassiveContFact.h
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#ifndef __SPDPASSIVECONTFACT_H__
-#define __SPDPASSIVECONTFACT_H__
-
-#include "FairContFact.h"  
-
-/////////////////////////////////////////////////////////////////////////////////
-//                                                                             //
-//  SpdPassiveContFact                                                         //
-//                                                                             //
-//  Factory for the parameter containers in library SpdPassive                 //
-//                                                                             //
-/////////////////////////////////////////////////////////////////////////////////
-
-class FairParSet;
-
-class SpdPassiveContFact : public FairContFact {
-  
-public:
-    
-    SpdPassiveContFact();
-   ~SpdPassiveContFact() {}
-    
-    virtual FairParSet* createContainer(FairContainer*);
-    
-    ClassDef(SpdPassiveContFact,1)
-    
-private:
-    
-    void setAllContainers();
-  
-};
-
-#endif 
diff --git a/passive/SpdPipe.cxx b/passive/SpdPipe.cxx
index b2864ad3a578dfa91e818f63be2f15d4bb04036a..a8e37d76071f3128fc4379308db62dd2c5c141f0 100644
--- a/passive/SpdPipe.cxx
+++ b/passive/SpdPipe.cxx
@@ -1,13 +1,13 @@
 
 #include "SpdPipe.h"
+#include "SpdCommonGeoMapper.h"
+#include "SpdPassiveGeoParSet.h"
 
 #include <TGeoPcon.h>
 #include <TGeoCone.h>
 #include <TGeoManager.h>
 #include <TMath.h>
 
-#include "SpdCommonGeoMapper.h"
-
 #include <iostream>
 using std::cout;
 using std::endl;
@@ -44,7 +44,7 @@ void SpdPipe::SetPipeType(TString type)
 
 //_____________________________________________________________________________________
 void SpdPipe::ConstructGeometry()
-{ 
+{  
    if (fGeoType < 1 || fGeoType > 4) return; 
      
    if (fPipe) {
@@ -85,6 +85,8 @@ void SpdPipe::ConstructGeometry()
        fMasterVolume->AddNode(fHybPipeLZplus,1);
        fMasterVolume->AddNode(fHybPipeISpace,1);
    }
+   
+   FillParsIn(GetParameters());
 }
 
 //_____________________________________________________________________________________
@@ -250,20 +252,24 @@ void SpdPipe::SetPipeMaterial(TString material, Int_t n)
 }
 
 //_____________________________________________________________________________
-void SpdPipe::UnsetMaterials(Bool_t precise)
+void SpdPipe::UnsetMaterials(TString media)
 {
    if (fPipe) return;
    
-   if (precise) {
-       fBaseMaterial = "vacuum2";
-       fMaterial[0]  = "vacuum2";
-       fMaterial[1]  = "vacuum2";
-   }
-   else {
-       fBaseMaterial = "vacuum2";
-       fMaterial[0]  = "vacuum";
-       fMaterial[1]  = "vacuum";
-   }
+   //cout << "-I- <SpdPipe::UnsetMaterials> " << media << endl;
+      
+   fBaseMaterial = media;
+   fMaterial[0]  = media;
+   fMaterial[1]  = media;
+   
+   fUnsetMedia = media;
+}
+
+//_____________________________________________________________________________
+void SpdPipe::ResetMaterials()
+{
+   if (fPipe) return;
+   SetDefaultMaterials(fGeoType);
 }
 
 //_____________________________________________________________________________________
@@ -374,6 +380,25 @@ void SpdPipe::SetDefault(Int_t geotype)
    }
 }
 
+//_____________________________________________________________________________________
+void SpdPipe::SetDefaultMaterials(Int_t geotype)
+{
+   //cout <<"<SpdPipe::SetDefaultMaterials> " << geotype << endl;
+   
+   fBaseMaterial = "vacuum";
+   
+   if (geotype < 1 || geotype > 4) {
+    
+       fMaterial[0] = "vacuum2";
+       fMaterial[1] = "vacuum2";
+       
+       return;
+   }
+    
+   fMaterial[0] = SpdCommonGeoMapper::GetPipeMaterial1();
+   fMaterial[1] = SpdCommonGeoMapper::GetPipeMaterial2();
+}
+
 //_____________________________________________________________________________________
 void SpdPipe::Print(Option_t*) const
 {
@@ -382,6 +407,7 @@ void SpdPipe::Print(Option_t*) const
    cout <<"\n";
    cout << "\tGeometry type:    " << fPipeType << endl;
    cout << "\tUnique module Id: " << fModuleId << endl;
+   cout << "\tUnset media:      " << fUnsetMedia << endl;
    
    if (fGeoType < 1) { cout << endl; return; }
         
@@ -443,3 +469,17 @@ void SpdPipe::Print(Option_t*) const
   
    cout <<"\n";
 }
+
+//_____________________________________________________________________________
+Bool_t SpdPipe::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdPipe::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}
diff --git a/passive/SpdPipe.h b/passive/SpdPipe.h
index d969d90cbe7947fc250fc15bf2265c85558c99f8..c95e4d5845610d9b511dfad6f7f3bd396852cce7 100644
--- a/passive/SpdPipe.h
+++ b/passive/SpdPipe.h
@@ -35,7 +35,8 @@ public:
   
   void SetPipeMaterial(TString material, Int_t n = 0);
   
-  virtual void UnsetMaterials(Bool_t precise = kTRUE);
+  virtual void UnsetMaterials(TString media = "vacuum2");
+  virtual void ResetMaterials(/*set dafault materials*/);
   
   /* ----- getters ------ */
   
@@ -63,17 +64,21 @@ public:
  
   virtual void Print(Option_t*) const;
   
+  virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+  virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
+  
 protected:
     
   void SetDefault(Int_t geotype);  
+  void SetDefaultMaterials(Int_t geotype);  
   void BuildHybridPipe();
-   
-  TString  fPipeType;    // pipe type
-  TString  fPipeName;    // pipe volume name
 
-  Double_t fR;           // outer radius of the pipe [cm]
-  Double_t fThickness;   // pipe thicknes [cm]
-  Double_t fHalfLength;  // pipe half length [cm] 
+  TString  fPipeType;     // pipe type
+  TString  fPipeName;     // pipe volume name
+
+  Double_t fR;            // outer radius of the pipe [cm]
+  Double_t fThickness;    // pipe thicknes [cm]
+  Double_t fHalfLength;   // pipe half length [cm] 
   
   TString  fBaseMaterial; // base pipe material
   TString  fMaterial[2];  // pipe material
@@ -82,10 +87,10 @@ protected:
   
   /* For "hybrid" geometry */
   
-  TGeoVolume* fHybPipeC;        // central part of the "hybrid" pipe 
-  TGeoVolume* fHybPipeLZminus;  // lateral(z-) part of the "hybrid" pipe 
-  TGeoVolume* fHybPipeLZplus;   // lateral(z+) part of the "hybrid" pipe 
-  TGeoVolume* fHybPipeISpace;   // inner space of the "hybrid" pipe 
+  TGeoVolume* fHybPipeC;        //! central part of the "hybrid" pipe 
+  TGeoVolume* fHybPipeLZminus;  //! lateral(z-) part of the "hybrid" pipe 
+  TGeoVolume* fHybPipeLZplus;   //! lateral(z+) part of the "hybrid" pipe 
+  TGeoVolume* fHybPipeISpace;   //! inner space of the "hybrid" pipe 
     
   ClassDef(SpdPipe,1)
 
diff --git a/passive/SpdSolMagnet.cxx b/passive/SpdSolMagnet.cxx
index c891573d7290be68af34644cbb24babd20d05c2d..ca8c48fe433a6ee43ddb2358e7a7a7c8150ccc3c 100644
--- a/passive/SpdSolMagnet.cxx
+++ b/passive/SpdSolMagnet.cxx
@@ -154,11 +154,21 @@ Double_t SpdSolMagnet::GetCryoMass() const
 }
 
 //_____________________________________________________________________________
-void SpdSolMagnet::UnsetMaterials(Bool_t precise)
+void SpdSolMagnet::UnsetMaterials(TString media)
 {
    if (fMagnetSection) return;
-   (precise) ? fBaseMaterial = "vacuum2" : fBaseMaterial = "vacuum";
-   (precise) ? fCryoMaterial = "vacuum2" : fCryoMaterial = "vacuum";
+   
+   fBaseMaterial = media;
+   fCryoMaterial = media;
+   
+   fUnsetMedia = media;
+}
+
+//_____________________________________________________________________________
+void SpdSolMagnet::ResetMaterials()
+{
+   if (fMagnetSection) return;
+   SetDefaultMaterials(fGeoType);
 }
 
 //_____________________________________________________________________________
@@ -189,6 +199,8 @@ void SpdSolMagnet::ConstructGeometry()
             << " Unknown geometry type: " << fGeoType << endl;  
        fGeoType = 0;     
    }
+   
+   FillParsIn(GetParameters());
 }
 
 //_____________________________________________________________________________
@@ -420,6 +432,46 @@ void SpdSolMagnet::SetGeoPars(Int_t geotype)
    }   
 }
 
+//_____________________________________________________________________________
+void SpdSolMagnet::SetDefaultMaterials(Int_t geotype)
+{
+   //cout <<"<SpdSolMagnet::SetDefaultMaterials> " << geotype << endl;
+    
+   if (geotype < 1 || geotype > 2) {
+       //cout << "-I- <SpdSolMagnet::SetDefaultMaterials> No geometry will be built" << endl;
+       
+       fBaseMaterial = "vacuum2"; 
+   
+       fFillColor = 0;
+       fLineColor = 0;
+       fTransparency = 0;
+ 
+       return;
+   }
+   
+   fBaseMaterial = SpdCommonGeoMapper::GetSolMagnetBaseMaterial();
+         
+   if (fGeoType == 1) {
+     
+       fCryoMaterial  = SpdCommonGeoMapper::GetSolMagnetCryoMaterial();
+     
+       fFillColor = kRed+3;
+       fLineColor = kRed+3;
+       fTransparency = 50;
+       
+       return;
+   }
+    
+   if (fGeoType == 2) {
+ 
+       fFillColor = kRed+3;
+       fLineColor = kRed+3;
+       fTransparency = 50;
+
+       return;
+   }   
+}
+
 //_____________________________________________________________________________    
 void SpdSolMagnet::Print(Option_t*) const
 {
@@ -431,6 +483,7 @@ void SpdSolMagnet::Print(Option_t*) const
    
    cout << "\tGeometry type:      " << fGeoType   << endl;
    cout << "\tUnique module Id:   " << fModuleId << endl; 
+   cout << "\tUnset media:        " << fUnsetMedia << endl;
    
    if (fGeoType < 1) { cout << endl; return; }
    
@@ -452,7 +505,19 @@ void SpdSolMagnet::Print(Option_t*) const
    cout <<"\n";
 }
     
-    
+ //_____________________________________________________________________________
+Bool_t SpdSolMagnet::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdSolMagnet::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}   
     
     
     
diff --git a/passive/SpdSolMagnet.h b/passive/SpdSolMagnet.h
index 7e0e11fdee4141b7ea9341bc0dfb607f4b283ea9..3f47119e3b9d8d7c459b9e2c278f2735cec6498d 100644
--- a/passive/SpdSolMagnet.h
+++ b/passive/SpdSolMagnet.h
@@ -32,7 +32,8 @@ public:
     void  SetWidth(Double_t width /*cm*/);  // width >= 1 cm 
     void  SetBaseMaterial(TString material);
    
-    virtual void UnsetMaterials(Bool_t precise = kTRUE);
+    virtual void UnsetMaterials(TString media = "vacuum2");
+    virtual void ResetMaterials(/*set dafault materials*/);
     
     /* ----- getters ------ */
     
@@ -55,6 +56,9 @@ public:
     inline const TGeoVolume* GetSection() const { return fMagnetSection; }
        
     virtual void Print(Option_t*) const;
+    
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
 
 private:
   
@@ -86,6 +90,7 @@ private:
     Int_t       fTransparency;
     
     void   SetGeoPars(Int_t geotype);
+    void   SetDefaultMaterials(Int_t geotype);
     
     void   ConstructGeometry_1();
     void   ConstructGeometry_2();
diff --git a/passive/SpdTorBasket.cxx b/passive/SpdTorBasket.cxx
index 2342d52c87cfa9d351ce242a57e2fcf5d72fa7b7..b425e0a7f1dc21bdf58ebfd1c1e2eaef9375bd1c 100644
--- a/passive/SpdTorBasket.cxx
+++ b/passive/SpdTorBasket.cxx
@@ -79,6 +79,8 @@ void SpdTorBasket::ConstructGeometry()
    BuildSection(2, 2*fLeafBoxHalfZ);
  
    fLockGeom = kTRUE;
+   
+   FillParsIn(GetParameters());
 }
 
 //_____________________________________________________________________________
@@ -152,7 +154,7 @@ Double_t SpdTorBasket::GetCasingWallDensity() const
 }
 
 //_____________________________________________________________________________________
-void SpdTorBasket::UnsetMaterials(Bool_t precise)
+void SpdTorBasket::UnsetMaterials(TString media)
 {
    if (fLockGeom) {
        cout << "-E- <SpdTorBasket::UnsetMaterials> "
@@ -160,14 +162,18 @@ void SpdTorBasket::UnsetMaterials(Bool_t precise)
        return;
    }  
    
-   TString material;
-   
-   (precise) ? material = "vacuum2" : material = "vacuum";
+   fLeafMaterial   = media;
+   fCasingMaterial = media;
    
-   fLeafMaterial = material;
-   fCasingMaterial = material;
+   fUnsetMedia = media;
 }
 
+//_____________________________________________________________________________
+void SpdTorBasket::ResetMaterials()
+{
+   if (fLockGeom) return;
+   SetDefaultMaterials(fGeoType);
+}
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -348,6 +354,24 @@ void SpdTorBasket::SetGeoPars(Int_t geotype) // private
    fLeafBoxHalfZ = width/2.;
 }
 
+//_____________________________________________________________________________
+void SpdTorBasket::SetDefaultMaterials(Int_t geotype) // private
+{ 
+   //cout <<"<SpdTorBasket::SetDefaultMaterials> " << geotype << endl;
+    
+   if (geotype != 1) return;
+   
+   if (SpdCommonGeoMapper::Instance()->GetTorMagnetDefGeoType() != 1) return;
+    
+   fBaseMaterial = SpdCommonGeoMapper::Instance()->GetTorBasketBaseMaterial();
+   
+   //fLeafMaterial = fBaseMaterial;
+   //fCasingMaterial = fBaseMaterial;
+   
+   fLeafMaterial = SpdCommonGeoMapper::Instance()->GetTorBasketLeafMaterial();
+   fCasingMaterial = SpdCommonGeoMapper::Instance()->GetTorBasketCasingMaterial();
+}
+
 //_____________________________________________________________________________________
 void SpdTorBasket::Print(Option_t*) const
 {
@@ -359,6 +383,7 @@ void SpdTorBasket::Print(Option_t*) const
    
    cout << "\tGeometry type:           " << fGeoType << endl;
    cout << "\tUnique module Id:        " << fModuleId << endl; 
+   cout << "\tUnset media:             " << fUnsetMedia << endl;
    
    if (fGeoType < 1) { cout << endl; return; }
    
@@ -395,3 +420,16 @@ void SpdTorBasket::Print(Option_t*) const
    cout << "\n";
 }
 
+//_____________________________________________________________________________
+Bool_t SpdTorBasket::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
+
+//_____________________________________________________________________________    
+Bool_t SpdTorBasket::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}
diff --git a/passive/SpdTorBasket.h b/passive/SpdTorBasket.h
index 3e2d7c3c10cafebb88639ee26bdce678f89f1369..61edb086d0bb2ac342a68e0049b454791a3df4c3 100644
--- a/passive/SpdTorBasket.h
+++ b/passive/SpdTorBasket.h
@@ -25,21 +25,25 @@ public:
     
     virtual void ConstructGeometry();
     
-    virtual Bool_t   IsGeometryLocked() const { return kFALSE; }
+    virtual Bool_t   IsGeometryLocked() const { return fLockGeom; }
   
     virtual Double_t GetCapacity() const;  // cm^3
     virtual Double_t GetMass()     const;  // g
   
-    virtual void UnsetMaterials(Bool_t precise = kTRUE);
+    virtual void UnsetMaterials(TString media = "vacuum2");
+    virtual void ResetMaterials(/*set dafault materials*/);
     
     virtual void Print(Option_t*) const; 
+    
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
 
 private:
   
     Bool_t   fLockGeom; //! if true, prevent geometry modifications
     
-    TGeoVolume* fLeafBox;
-    TGeoVolume* fCasingWall;
+    TGeoVolume* fLeafBox;    //!
+    TGeoVolume* fCasingWall; //!
     
     TString  fBaseMaterial;
     TString  fLeafMaterial;
@@ -70,6 +74,7 @@ private:
     Bool_t   BuildCasingWall(); 
     
     void SetGeoPars(Int_t geotype);
+    void SetDefaultMaterials(Int_t geotype);
     
     TGeoVolume* BuildArb(TString volname, TString matname, Double_t HalfLen,
                          Double_t Hmin, Double_t Hmax, 
diff --git a/passive/SpdTorMagnet.cxx b/passive/SpdTorMagnet.cxx
index 0b4fa8b310fd1ebc27c3f7b2f29dfd61cdab3e51..4f62ae69a9b3ce9a3febacba307ea032a08a434f 100644
--- a/passive/SpdTorMagnet.cxx
+++ b/passive/SpdTorMagnet.cxx
@@ -116,6 +116,8 @@ void SpdTorMagnet::ConstructGeometry()
             << " Unknown geometry type: " << fGeoType << endl; 
        fGeoType = 0;     
    }
+   
+   FillParsIn(GetParameters());
 }
 
 //_____________________________________________________________________________
@@ -560,7 +562,7 @@ void SpdTorMagnet::PurseCoilsAlongZ(Double_t dz /*cm*/)
 }
 
 //_____________________________________________________________________________
-void SpdTorMagnet::UnsetMaterials(Bool_t precise)
+void SpdTorMagnet::UnsetMaterials(TString media)
 {
    if (fLockGeom) {
        cout << "-E- <SpdTorMagnet::UnsetMaterials> "
@@ -568,14 +570,19 @@ void SpdTorMagnet::UnsetMaterials(Bool_t precise)
        return;
    }  
    
-   TString material;
-   
-   (precise) ? material = "vacuum2" : material = "vacuum";
-   
    for (int i(0); i<SPD_TORMAGNET_NDCOILS; i++) {
-        fCoil[i].base_material_ = material;
-        fCoil[i].coil_material_ = material;
+        fCoil[i].base_material_ = media;
+        fCoil[i].coil_material_ = media;
    }
+   
+   fUnsetMedia = media;
+}
+
+//_____________________________________________________________________________
+void SpdTorMagnet::ResetMaterials()
+{
+   if (fLockGeom) return;
+   SetDefaultMaterials(fGeoType);
 }
 
 //_____________________________________________________________________________
@@ -613,6 +620,7 @@ void SpdTorMagnet::Print(Option_t*) const
    
    cout << "\tGeometry type:           " << fGeoType << endl;
    cout << "\tUnique module Id:        " << fModuleId << endl; 
+   cout << "\tUnset media:             " << fUnsetMedia << endl;
    
    if (fGeoType < 1) { cout << endl; return; }
    
@@ -725,7 +733,52 @@ void SpdTorMagnet::SetGeoPars(Int_t geotype) // private
    //fCoil[2].transparency_ = 10;
 }
 
+//_____________________________________________________________________________
+void SpdTorMagnet::SetDefaultMaterials(Int_t geotype) // private
+{ 
+   //cout <<"<SpdTorMagnet::SetDefaultMaterials> " << geotype << endl;
+    
+   if (geotype < 1 || geotype > 2) return;
+   
+   fCoil[0].base_material_ = "air";
+   fCoil[0].coil_material_ = SpdCommonGeoMapper::GetTorMagnetCoilMaterial();
+   
+   //fCoil[0].fill_color_ = kBlue+3;
+   //fCoil[0].line_color_ = kBlue+3;
+   //fCoil[0].transparency_ = 10;
+   
+   //------------------------------------
+   
+   fCoil[1].base_material_ = "air";
+   fCoil[1].coil_material_ =  SpdCommonGeoMapper::GetTorMagnetCoilMaterial();
+   
+   //fCoil[1].fill_color_ = kBlue+3;
+   //fCoil[1].line_color_ = kBlue+3;
+   //fCoil[1].transparency_ = 10;   
+   
+   //------------------------------------
+ 
+   fCoil[2].base_material_ = "air";
+   fCoil[2].coil_material_ =  SpdCommonGeoMapper::GetTorMagnetCoilMaterial();
+      
+   //fCoil[2].fill_color_ = kBlue+3;
+   //fCoil[2].line_color_ = kBlue+3;
+   //fCoil[2].transparency_ = 10;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdTorMagnet::FillParsIn(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::FillParsIn(params)) return kFALSE;
+   return kTRUE;
+}
 
+//_____________________________________________________________________________    
+Bool_t SpdTorMagnet::LoadParsFrom(SpdPassiveGeoParSet* params)
+{
+   if (!SpdPassiveModule::LoadParsFrom(params)) return kFALSE;
+   return kTRUE;
+}
 
 
 
diff --git a/passive/SpdTorMagnet.h b/passive/SpdTorMagnet.h
index cc8f2642e5f4ca50c15a86efdfe7f29b4b866a34..6af1ba17ed0090cac264847f3983669d282469ec 100644
--- a/passive/SpdTorMagnet.h
+++ b/passive/SpdTorMagnet.h
@@ -42,13 +42,14 @@ public:
     void  StretchCoilsAlongR(Double_t dr /*cm*/);       // dr: > or < 0; new R_size >= width + ROUNDING
     void  PurseCoilsAlongZ(Double_t dz /*cm*/);         // dz -> |dz|;   new Z_size >= width + ROUNDING
     
-    virtual void UnsetMaterials(Bool_t precise = kTRUE);
+    virtual void UnsetMaterials(TString media = "vacuum2");
+    virtual void ResetMaterials(/*set dafault materials*/);
     
     /* ----- getters ------ */
     
-    virtual Bool_t IsGeometryLocked() const { return fLockGeom; }
+    virtual Bool_t   IsGeometryLocked() const { return fLockGeom; }
     
-    inline Double_t GetAxialDistance() const { return fAxialDistance; }
+    inline Double_t  GetAxialDistance() const { return fAxialDistance; }
     
     virtual Double_t GetCapacity()   const;  // cm^3
     virtual Double_t GetMass()       const;  // g
@@ -70,6 +71,9 @@ public:
    
     virtual void Print(Option_t*) const; 
     
+    virtual Bool_t FillParsIn(SpdPassiveGeoParSet* params);
+    virtual Bool_t LoadParsFrom(SpdPassiveGeoParSet* params);
+    
     //______________________________________________________________//
     struct tmcoil_ : public TObject {
       
@@ -115,6 +119,7 @@ private:
     tmcoil_ fCoil[SPD_TORMAGNET_NDCOILS];
 
     void SetGeoPars(Int_t geotype);
+    void SetDefaultMaterials(Int_t geotype);
     
     Bool_t ConstructGeometry_1();
     Bool_t ConstructGeometry_2();
diff --git a/proc/CMakeLists.txt b/proc/CMakeLists.txt
index 274560ec0c1ebb5d73ca296f2ee29cad626c61cd..d07ffe2054b11482e85285df4eb8a4bfdb422291 100644
--- a/proc/CMakeLists.txt
+++ b/proc/CMakeLists.txt
@@ -8,6 +8,4 @@ ELSE()
     MESSAGE(STATUS "PROC: the \"Tracking\" dictionary could not be built; \"GenFit2\" is required")   
 ENDIF()
 
-
-
-
+add_subdirectory (vertex)
diff --git a/proc/clustering/CMakeLists.txt b/proc/clustering/CMakeLists.txt
index 619592f5ac41ba9864aa095f78475aaf41bfc365..819375af75047a204747cdacab6a38942d93ed03 100644
--- a/proc/clustering/CMakeLists.txt
+++ b/proc/clustering/CMakeLists.txt
@@ -29,6 +29,13 @@ ClusterCollection.cxx
 ClManager.cxx
 )
 
+set(HEADERS
+ClManager.h
+ClusterCollection.h
+ClusterElement.h
+Cluster.h
+)
+
 Set(LINKDEF ClusterLinkDef.h)
 Set(LIBRARY_NAME Clustering)
 Set(DEPENDENCIES Base)
diff --git a/proc/tracking/CMakeLists.txt b/proc/tracking/CMakeLists.txt
index d52505f775950b82552b43b921ac840400c4a2a3..87bddc06f1d86245327e304a7d0672e85a637c30 100644
--- a/proc/tracking/CMakeLists.txt
+++ b/proc/tracking/CMakeLists.txt
@@ -45,6 +45,13 @@ SpdGFMeasurementCreator.cxx
 SpdKalmanFitterRefTrack.cxx
 )
 
+set(HEADERS
+SpdGFMagneticField.h
+SpdGFMeasurementCreator.h
+SpdGFTrackW.h
+SpdKalmanFitterRefTrack.h
+)
+
 Set(LINKDEF TrackingGFLinkDef.h)
 Set(LIBRARY_NAME TrackingGF)
 Set(DEPENDENCIES Base GenFit2 SpdData SpdField SpdCommon SpdGeometry)
diff --git a/proc/tracking/SpdGFMeasurementCreator.cxx b/proc/tracking/SpdGFMeasurementCreator.cxx
index 5a0c307375d4d337f436744ddbc42c07e6cd4881..b391acd42b479a8b7b88aff8e177a44a098fbbc6 100644
--- a/proc/tracking/SpdGFMeasurementCreator.cxx
+++ b/proc/tracking/SpdGFMeasurementCreator.cxx
@@ -7,8 +7,8 @@
 // SpdGFMeasurementCreator
 //_____________________________________________________________________________
 
-#include "SpdGFMeasurementCreator.h"
 #include "GFmeasurements.h"
+#include "SpdGFMeasurementCreator.h"
 
 #include <TRandom.h>
 #include <TMath.h>
@@ -24,9 +24,12 @@ ClassImp(SpdGFMeasurementCreator)
 
 //_____________________________________________________________________________
 SpdGFMeasurementCreator::SpdGFMeasurementCreator():fMeasurementCounter_(0),
-fResolution_(0.01),fResolutionWire_(0.1)
-{
- 
+fForcePointHitResolution(false),fForceWireHitResolution(false),
+fUseMCPointAsPointHit(false),fUseMCPointAsWireHit(false),
+fSmearPointHitResolution(false),fSmearWireHitResolution(false)
+{   
+   SetPointHitResolutionXYZ(0.005,0.005,0.005); // -> 50 mkm
+   SetWireHitResolutionRZ(0.005,0.005);         // -> 50 mkm
 }
 
 //_____________________________________________________________________________
@@ -35,52 +38,415 @@ SpdGFMeasurementCreator::~SpdGFMeasurementCreator()
  
 }
 
+//_____________________________________________________________________________
+void SpdGFMeasurementCreator::ResetOptions() 
+{
+   fForcePointHitResolution = false;
+   fForceWireHitResolution = false;
+   fUseMCPointAsPointHit = false;
+   fUseMCPointAsWireHit = false;
+   fSmearPointHitResolution = false;
+   fSmearWireHitResolution = false;
+}
+
 //_____________________________________________________________________________
 std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateHit(SpdIdealHit* hit, GFMeasurementType mtype)
 {
-   SpdIdealSpacepointHit* shit = dynamic_cast<SpdIdealSpacepointHit*>(hit); 
-   if (shit) return CreateHit(shit,mtype);
+   SpdIdealSpacepointHit* sphit = dynamic_cast<SpdIdealSpacepointHit*>(hit); 
+   if (sphit) return CreateHit(sphit,mtype);
    
-   SpdIdealWirepointHit* whit = dynamic_cast<SpdIdealWirepointHit*>(hit); 
-   if (whit) return CreateHit(whit,mtype);
+   SpdIdealWirepointHit* wphit = dynamic_cast<SpdIdealWirepointHit*>(hit); 
+   if (wphit) return CreateHit(wphit,mtype);
 
-   return CreateSpacepointHit(hit->GetPoint());
+   return CreateSpacepointHit(hit->GetPoint(),hit->GetResolution());
 }
 
 //_____________________________________________________________________________
 std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateHit(SpdIdealSpacepointHit* hit, GFMeasurementType mtype)
 {
-   return CreateSpacepointHit(hit->GetPoint());
+   if (mtype == pkPixel) return CreatePixelHit(hit);      
+   if (mtype == pkSpacepoint) return CreateSpacepointHitP(hit);
+   
+   // default
+   return CreatePixelHit(hit);
 }
 
 //_____________________________________________________________________________
 std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateHit(SpdIdealWirepointHit* hit, GFMeasurementType mtype)
 {
-   return CreateSpacepointHit(hit->GetPoint());
+   if (mtype == pkWire) return CreateWireHit(hit);
+   if (mtype == pkWirePoint) return CreateWirePointHit(hit);   
+   if (mtype == pkSpacepoint) return CreateSpacepointHitW(hit); 
+
+   // default 
+   return CreateWireHit(hit);   
 }
     
 //_____________________________________________________________________________
-std::vector<AbsMeasurement*> SpdGFMeasurementCreator::CreateSpacepointHit(TVector3 point) // private 
+std::vector<AbsMeasurement*> SpdGFMeasurementCreator::CreateSpacepointHit(TVector3 point, TVector3 res, Char_t spec) 
 {   
-   std::vector<AbsMeasurement*> retVal;
+   std::vector<AbsMeasurement*> mm;
 
-   //cout << "-I- <SpdGFMeasurementCreator::CreateSpacepointHit> create SpacepointHit" << endl;
+   //cout << "-I- <SpdGFMeasurementCreator::CreateSpacepointHit> " << endl;
+   //cout << "\t specifity: " << spec << " resolution: " << res.X() << " " << res.Y() << " " << res.Z() << endl;
 
    TVectorD hitCoords(3);
    
-   hitCoords(0) = gRandom->Gaus(point.X(),fResolution_);
-   hitCoords(1) = gRandom->Gaus(point.Y(),fResolution_);
-   hitCoords(2) = gRandom->Gaus(point.Z(),fResolution_);
+   if (spec == 'n' || spec == 'p' || fSmearPointHitResolution) { 
+       hitCoords(0) = gRandom->Gaus(point.X(),res.X());
+       hitCoords(1) = gRandom->Gaus(point.Y(),res.Y());
+       hitCoords(2) = gRandom->Gaus(point.Z(),res.Z());
+   }
+   else {
+       hitCoords(0) = point.X();
+       hitCoords(1) = point.Y();
+       hitCoords(2) = point.Z();
+   }
+   
+   TMatrixDSym hitCov(3);
+
+   hitCov(0,0) = res.X()*res.X();
+   hitCov(1,1) = res.Y()*res.Y();
+   hitCov(2,2) = res.Z()*res.Z();
+
+   AbsMeasurement* measurement = new SpacepointMeasurement(hitCoords, hitCov, pkSpacepoint, 
+                                                           fMeasurementCounter_, nullptr);
+   mm.push_back(measurement);
+
+   return mm;
+}
+
+//_____________________________________________________________________________
+std::vector<AbsMeasurement*> SpdGFMeasurementCreator::CreateSpacepointHitP(SpdIdealSpacepointHit* hit) 
+{   
+   std::vector<AbsMeasurement*> mm;
+
+   //cout << "-I- <SpdGFMeasurementCreator::CreateSpacepointHitP> " << endl;
+      
+   TVector3 pos;
+   if (fUseMCPointAsPointHit) hit->GetPoint(pos);
+   else hit->GetHit(pos);   
+   
+   TVector3 res;
+   if (fForcePointHitResolution) res = fPointHitResolution;
+   else res = hit->GetResolution();
+   
+   Char_t spec = hit->GetSpecifity();
+   
+   //cout << "\t specifity: " << spec 
+   //     << "  position: " << pos.X() << " " << pos.Y() << " " << pos.Z() 
+   //     << "  resolution: " << res.X() << " " << res.Y() << " " << res.Z() << endl;
 
+   TVectorD hitCoords(3);
+   
+   if (spec == 'n' || spec == 'p' || fSmearPointHitResolution) { 
+       hitCoords(0) = gRandom->Gaus(pos.X(),res.X());
+       hitCoords(1) = gRandom->Gaus(pos.Y(),res.Y());
+       hitCoords(2) = gRandom->Gaus(pos.Z(),res.Z());
+   }
+   else {
+       hitCoords(0) = pos.X();
+       hitCoords(1) = pos.Y();
+       hitCoords(2) = pos.Z();
+   }
+    
    TMatrixDSym hitCov(3);
 
-   hitCov(0,0) = fResolution_*fResolution_;
-   hitCov(1,1) = fResolution_*fResolution_;
-   hitCov(2,2) = fResolution_*fResolution_;
+   hitCov(0,0) = res.X()*res.X();
+   hitCov(1,1) = res.Y()*res.Y();
+   hitCov(2,2) = res.Z()*res.Z();
 
    AbsMeasurement* measurement = new SpacepointMeasurement(hitCoords, hitCov, pkSpacepoint, 
                                                            fMeasurementCounter_, nullptr);
-   retVal.push_back(measurement);
+   mm.push_back(measurement);
+
+   return mm;
+}
+
+//_____________________________________________________________________________
+std::vector<AbsMeasurement*> SpdGFMeasurementCreator::CreateSpacepointHitW(SpdIdealWirepointHit* hit) 
+{   
+   std::vector<AbsMeasurement*> mm;
+
+   //cout << "-I- <SpdGFMeasurementCreator::CreateSpacepointHitW> " << endl;
+      
+   TVector3 pos;
+   if (fUseMCPointAsPointHit) hit->GetPoint(pos);
+   else hit->GetHit(pos);   
+   
+   TVector3 res;
+   if (fForcePointHitResolution) res = fPointHitResolution;
+   else res = hit->GetResolution();
+   
+   Char_t spec = hit->GetSpecifity();
+   
+   //cout << "\t specifity: " << spec 
+   //     << "  position: " << pos.X() << " " << pos.Y() << " " << pos.Z()
+   //     << "  resolution: " << res.X() << " " << res.Y() << " " << res.Z() << endl;
+   
+   TVectorD hitCoords(3);
+   
+   if (spec == 'n' || spec == 'p' || fSmearPointHitResolution) { 
+       hitCoords(0) = gRandom->Gaus(pos.X(),res.X());
+       hitCoords(1) = gRandom->Gaus(pos.Y(),res.Y());
+       hitCoords(2) = gRandom->Gaus(pos.Z(),res.Z());
+   }
+   else {
+       hitCoords(0) = pos.X();
+       hitCoords(1) = pos.Y();
+       hitCoords(2) = pos.Z();
+   }
+    
+   TMatrixDSym hitCov(3);
+
+   hitCov(0,0) = res.X()*res.X();
+   hitCov(1,1) = res.Y()*res.Y();
+   hitCov(2,2) = res.Z()*res.Z();
+
+   AbsMeasurement* measurement = new SpacepointMeasurement(hitCoords, hitCov, pkSpacepoint, 
+                                                           fMeasurementCounter_, nullptr);
+   mm.push_back(measurement);
+
+   return mm;
+}
+
+//_____________________________________________________________________________
+std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreatePixelHit(SpdIdealSpacepointHit* hit)
+{
+   std::vector<AbsMeasurement*> mm;
+
+   //cout << "-I- <SpdGFMeasurementCreator::CreatePixelHit> " << endl;
+      
+   Char_t spec = hit->GetSpecifity();
+   
+   if (spec != 'p' && spec != 'm' && spec != 's') {
+       cout << "<SpdGFMeasurementCreator::CreatePixelHit> Unexpected hit specifity: '" << spec 
+            << "' , create point-like hit " << endl;  
+       return CreateSpacepointHit(hit->GetHit(),hit->GetResolution(),spec);
+   }
+   
+   Double_t pos[2];
+   if (fUseMCPointAsPointHit) { pos[0] = hit->GetPointU(); pos[1] = hit->GetPointV(); }
+   else { pos[0] = hit->GetHitU(); pos[1] = hit->GetHitV(); }
+   
+   Double_t res[2];
+   if (fForcePointHitResolution) { res[0] = fPointHitResolution.X(); res[1] = fPointHitResolution.Y(); } 
+   else { res[0] = hit->GetResolutionU(); res[1] = hit->GetResolutionV(); }
+   
+   //cout << "\t specifity: " << spec << " detector: " << hit->GetDetId() 
+   //     << " resolution (U,V): " << res.X() << " " << res.Y()
+   //     << " [U, V, N]: " << pos.X() << " " << pos.Y() << " " << pos.Z() << endl;
+   
+   //hit->PrintHit();
+    
+   TVectorD hitCoords(2);
+      
+   if (fSmearPointHitResolution) { 
+       hitCoords(0) = gRandom->Gaus(pos[0],res[0]);
+       hitCoords(1) = gRandom->Gaus(pos[1],res[1]);
+   }
+   else {
+       hitCoords(0) = pos[0];
+       hitCoords(1) = pos[1]; 
+   }
+       
+   TMatrixDSym hitCov(2);
+   
+   hitCov(0,0) = res[0]*res[0];
+   hitCov(1,1) = res[1]*res[1];
 
-   return retVal;
+   PlanarMeasurement* measurement = new PlanarMeasurement(hitCoords, hitCov, hit->GetDetId(), fMeasurementCounter_, nullptr);
+   
+   SharedPlanePtr plane(new DetPlane(hit->GetDetPos(),hit->GetU(),hit->GetV()));
+   
+   measurement->setPlane(plane, fMeasurementCounter_);
+   
+   mm.push_back(measurement);
+   
+   return mm; 
 }
+
+//_____________________________________________________________________________
+std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateWireHit(SpdIdealWirepointHit* hit)
+{
+    std::vector<AbsMeasurement*> mm;
+    
+    //cout << "-I- <SpdGFMeasurementCreator::CreateWireHit> " << endl;
+
+    Char_t spec = hit->GetSpecifity();
+   
+    if (spec != 'w') {
+        cout << "<SpdGFMeasurementCreator::CreateWireHit> Unexpected hit specifity: '" << spec 
+            << "' , create point-like hit " << endl;   
+        return CreateSpacepointHit(hit->GetHit(),hit->GetResolution(),spec);
+    }
+    
+    Double_t rdrift;
+    if (fUseMCPointAsWireHit) rdrift = hit->GetPointRdrift();
+    else rdrift = hit->GetRdrift();
+   
+    Double_t res;
+    if (fForceWireHitResolution) res = fWireHitResolution.X();
+    else res = hit->GetResolutionR();
+    
+    //cout << "\t specifity: " << spec << " detector: " << hit->GetDetId() 
+    //     << " resolution (R): " << res << " [R]: " << rdrift << endl;
+
+    TVector3 wirepoint;
+    
+    TVectorD hitCoords(7);
+
+    wirepoint = hit->GetWirePoint1();
+    
+    hitCoords(0) = wirepoint.X();
+    hitCoords(1) = wirepoint.Y();
+    hitCoords(2) = wirepoint.Z();
+    
+    wirepoint = hit->GetWirePoint2();
+
+    hitCoords(3) = wirepoint.X();
+    hitCoords(4) = wirepoint.Y();
+    hitCoords(5) = wirepoint.Z();
+
+    Double_t rmax = hit->GetWireMaxRadius();
+    
+    if (fSmearWireHitResolution) 
+    {
+        static Double_t ktol = 0.99999;
+    
+        if (res < rmax/TMath::Sqrt(12)) {
+            hitCoords(6) = rdrift + gRandom->Gaus(0,res);
+            if (hitCoords(6) < 0) hitCoords(6) = 0;
+            else if (!(hitCoords(6) < rmax)) hitCoords(6) = ktol*rmax;
+        }
+        else hitCoords(6) = gRandom->Uniform(0,ktol*rmax); 
+    }
+    else hitCoords(6) = rdrift; 
+
+    TMatrixDSym hitCov(7);
+    
+    hitCov(6,6) = res*res;
+
+    WireMeasurement* measurement = new WireMeasurement(hitCoords, hitCov, hit->GetDetId(), fMeasurementCounter_, nullptr);
+      
+    measurement->setMaxDistance(rmax);
+    //measurement->setLeftRightResolution(hit->GetLRtype());
+    
+    mm.push_back(measurement);
+    
+    return mm;
+}
+
+//_____________________________________________________________________________
+std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateWirePointHit(SpdIdealWirepointHit* hit)
+{
+    std::vector<AbsMeasurement*> mm;
+    
+    //cout << "-I- <SpdGFMeasurementCreator::CreateWirePointHit> " << endl;
+    
+    Char_t spec = hit->GetSpecifity();
+   
+    if (spec != 'w') {
+        cout << "<SpdGFMeasurementCreator::CreateWirePointHit> Unexpected hit specifity: '" << spec 
+            << "' , create point-like hit " << endl;   
+        return CreateSpacepointHit(hit->GetHit(),hit->GetResolution(),spec);
+    }
+    
+    Double_t rdrift, zwire;
+    if (fUseMCPointAsWireHit) { rdrift = hit->GetPointRdrift(); zwire = hit->GetPointZwire(); }
+    else { rdrift = hit->GetRdrift(); zwire = hit->GetPointZwire(); }
+   
+    Double_t resR, resZ;
+    if (fForceWireHitResolution) { resR = fWireHitResolution.X(); resZ = fWireHitResolution.Y(); }
+    else { resR = hit->GetResolutionR(); resR = hit->GetResolutionZ(); }
+    
+    //cout << "\t specifity: " << spec << " detector: " << hit->GetDetId() 
+    //     << " resolution (R,Z): " << resR << " " << resZ
+    //     << "\t [R, Z]: " << rdrift << " " << zwire << " Wire length: " << hit->GetWireLength() << endl;   
+         
+    TVectorD hitCoords(8);
+    
+    TVector3 wirepoint;
+    
+    wirepoint = hit->GetWirePoint1();
+    
+    hitCoords(0) = wirepoint.X();
+    hitCoords(1) = wirepoint.Y();
+    hitCoords(2) = wirepoint.Z();
+    
+    wirepoint = hit->GetWirePoint2();
+
+    hitCoords(3) = wirepoint.X();
+    hitCoords(4) = wirepoint.Y();
+    hitCoords(5) = wirepoint.Z();
+    
+    Double_t rmax = hit->GetWireMaxRadius();
+    Double_t zmax = hit->GetWireLength();
+    
+    if (fSmearWireHitResolution) 
+    {
+        static Double_t ktol = 0.99999;
+        
+        if (resR < rmax/TMath::Sqrt(12)) {
+            hitCoords(6) = rdrift + gRandom->Gaus(0,resR);
+            if (hitCoords(6) < 0) hitCoords(6) = 0;
+            else if (!(hitCoords(6) < rmax)) hitCoords(6) = ktol*rmax;
+        }
+        else hitCoords(6) = gRandom->Uniform(0,ktol*rmax);
+        
+        if (resZ < zmax/TMath::Sqrt(12)) {
+            hitCoords(7) = zwire + gRandom->Gaus(0,resZ);
+            if (hitCoords(7) < 0) hitCoords(7) = 0;
+            else if (!(hitCoords(7) < zmax)) hitCoords(7) = ktol*zmax;
+        }
+        else hitCoords(7) = gRandom->Uniform(0,ktol*zmax); 
+    }
+    else {
+        hitCoords(6) = rdrift;
+        hitCoords(7) = zwire;        
+    }
+        
+    TMatrixDSym hitCov(8);
+    
+    hitCov(6,6) = resR*resR;
+    hitCov(7,7) = resZ*resZ;
+
+    WirePointMeasurement* measurement = new WirePointMeasurement(hitCoords, hitCov, hit->GetDetId(), fMeasurementCounter_, nullptr);
+      
+    measurement->setMaxDistance(rmax);
+    //measurement->setLeftRightResolution(hit->GetLRtype());
+    
+    mm.push_back(measurement);   
+         
+   return mm;      
+}
+
+// //_____________________________________________________________________________
+// std::vector<genfit::AbsMeasurement*> SpdGFMeasurementCreator::CreateWireHit2(SpdIdealWirepointHit* hit)
+// {
+//     std::vector<AbsMeasurement*> mm;
+//     
+//     Char_t spec = hit->GetSpecifity();
+//    
+//     if (spec != 'w') {
+//         cout << "<SpdGFMeasurementCreator::CreateWireHit2> Unexpected hit specifity: '" << spec 
+//             << "' , create point-like hit " << endl;   
+//         return CreateSpacepointHit(hit->GetHit(),hit->GetResolution(),spec);
+//     }
+//     
+// //     cout << "\t specifity: " << spec << " detector: " << hit->GetDetId() 
+// //         << " resolution (R): " << hit->GetResolutionR()  
+// //         << " [R]: " << hit->GetRdrift() << endl;
+// 
+//     WireMeasurementNew* measurement = new WireMeasurementNew(hit->GetRdrift(),hit->GetResolutionR(),
+//                                                              hit->GetWirePoint1(),hit->GetWirePoint2(), 
+//                                                              hit->GetDetId(), fMeasurementCounter_, nullptr);
+//     
+//     measurement->setMaxDistance(hit->GetWireMaxRadius());
+//     //measurement->setLeftRightResolution(hit->GetLRtype());
+//     
+//     mm.push_back(measurement);
+//             
+//     return mm;      
+// }
+
diff --git a/proc/tracking/SpdGFMeasurementCreator.h b/proc/tracking/SpdGFMeasurementCreator.h
index 0bef6dbd2437eb418afd60220a03375d16bb21df..b6d5613fd1f70386b9bcbba832d87dad5ddf55ac 100644
--- a/proc/tracking/SpdGFMeasurementCreator.h
+++ b/proc/tracking/SpdGFMeasurementCreator.h
@@ -42,21 +42,64 @@ public:
     std::vector<genfit::AbsMeasurement*> CreateHit(SpdIdealHit* hit, GFMeasurementType mtype = pkSpacepoint);
     std::vector<genfit::AbsMeasurement*> CreateHit(SpdIdealSpacepointHit* hit, GFMeasurementType mtype = pkSpacepoint);
     std::vector<genfit::AbsMeasurement*> CreateHit(SpdIdealWirepointHit* hit, GFMeasurementType mtype = pkSpacepoint);
-
-    void SetResolution(double res)     { fResolution_     = res; }
-    void SetResolutionWire(double res) { fResolutionWire_ = res; }
+    
+    inline void SetPointHitResolutionXYZ(Double_t rx /*cm*/, Double_t ry /*cm*/, Double_t rz /*cm*/);
+    inline void SetWireHitResolutionRZ(Double_t rr /*cm*/, Double_t rz = -1/*cm*/);
+    
+    inline void ForcePointHitResolution() { fForcePointHitResolution = true; }
+    inline void ForceWireHitResolution()  { fForceWireHitResolution = true;  }
+    
+    inline void UseMCPointAsPointHit(Bool_t smear = false) { fUseMCPointAsPointHit = true; fSmearPointHitResolution = smear; }
+    inline void UseMCPointAsWireHit(Bool_t smear = false)  { fUseMCPointAsWireHit = true; fSmearWireHitResolution = smear;  }
+    
+    void ResetOptions(); 
 
 private:
 
-    std::vector<genfit::AbsMeasurement*> CreateSpacepointHit(TVector3 pos);
+    std::vector<genfit::AbsMeasurement*> CreateSpacepointHit(TVector3 pos, TVector3 res, Char_t spec = 'n');
+    
+    std::vector<genfit::AbsMeasurement*> CreateSpacepointHitP(SpdIdealSpacepointHit* hit);
+    std::vector<genfit::AbsMeasurement*> CreateSpacepointHitW(SpdIdealWirepointHit* hit);
+    
+    std::vector<genfit::AbsMeasurement*> CreatePixelHit(SpdIdealSpacepointHit* hit);
+    std::vector<genfit::AbsMeasurement*> CreateWireHit(SpdIdealWirepointHit* hit);
+    std::vector<genfit::AbsMeasurement*> CreateWirePointHit(SpdIdealWirepointHit* hit);
   
+    //std::vector<genfit::AbsMeasurement*> CreateWireHit2(SpdIdealWirepointHit* hit);
+    
     Int_t    fMeasurementCounter_;
     
-    Double_t fResolution_;      // cm; resolution of generated measurements
-    Double_t fResolutionWire_;  // cm; resolution in wire direction (wire and prolate spacepoint measurements)
-
+    TVector3 fPointHitResolution;
+    TVector3 fWireHitResolution;
+    
+    Bool_t   fForcePointHitResolution;
+    Bool_t   fForceWireHitResolution;
+    
+    Bool_t   fUseMCPointAsPointHit;
+    Bool_t   fUseMCPointAsWireHit;
+    
+    Bool_t   fSmearPointHitResolution;
+    Bool_t   fSmearWireHitResolution;
+    
     ClassDef(SpdGFMeasurementCreator,1)
 };
 
+void SpdGFMeasurementCreator::SetPointHitResolutionXYZ(Double_t rx, Double_t ry, Double_t rz) 
+{
+    // set resolution for x(u), y(v), z: pkPixel -> (x=u,y=v); pkSpacepoint -> (x,y,z)
+    // for example r(x,y,z) = 0.005 = 50*1e-4 = 50 mkm 
+    
+    fPointHitResolution.SetXYZ(rx,ry,rz);
+}
+
+void SpdGFMeasurementCreator::SetWireHitResolutionRZ(Double_t rr, Double_t rz) 
+{
+    // set resolution for r,z: pkWire -> (r); pkWirePoint -> (r,z) 
+    // for example r(x,y,z) = 0.005 = 50*1e-4 = 50 mkm 
+    
+    if (rz < 0) rz = rr;
+    fWireHitResolution.SetXYZ(rr,rz,0.);
+}
+
 #endif  /* __SPDGFMEASUREMENTCREATOR_H__ */
 
diff --git a/proc/tracking/SpdGFTrackW.h b/proc/tracking/SpdGFTrackW.h
index 4ee9d49c690c1af40a856d25c06124188576c866..9ac33d59ae06086c23d4d764d7d320ab392adf96 100644
--- a/proc/tracking/SpdGFTrackW.h
+++ b/proc/tracking/SpdGFTrackW.h
@@ -34,7 +34,7 @@ public:
     void SetDataID(Int_t id) { fDataID = id; }
     
     genfit::Track* GetTrack() { return fTrackGF; }
-    Int_t GetDataID() const   { return fDataID;}
+    Int_t GetDataID() const   { return fDataID; }
     
     genfit::Track* ReplaceTrack(genfit::Track* track);
 
diff --git a/proc/tracking/SpdKalmanFitterRefTrack.cxx b/proc/tracking/SpdKalmanFitterRefTrack.cxx
index a8193a6a07bf2a2114f7e7ba932208e60748b139..c3f4dde0ad86b5f8be7192d2347d8ce89426c777 100644
--- a/proc/tracking/SpdKalmanFitterRefTrack.cxx
+++ b/proc/tracking/SpdKalmanFitterRefTrack.cxx
@@ -251,7 +251,7 @@ void SpdKalmanFitterRefTrack::processTrackWithRep(Track* tr, const AbsTrackRep*
 
       cout << "\n<SpdKalmanFitterRefTrack::processTrackWithRep> (2.7) end iteration " << nIt   
            << "; fit: converged = " << converged << " " << "finished = " << finished 
-           << " failed hits: " << nFailedHits << endl;
+           << " failed hits: " << nFailedHits << " points: " << tr->getNumPoints() << endl;
 
       if (finished) 
       {
@@ -295,7 +295,7 @@ void SpdKalmanFitterRefTrack::processTrackWithRep(Track* tr, const AbsTrackRep*
   // fill FitStatus
   
   TrackPoint* tp = tr->getPointWithMeasurementAndFitterInfo(0, rep);
-
+ 
   double charge(0);
   if (tp != nullptr) {
       if (static_cast<KalmanFitterInfo*>(tp->getFitterInfo(rep))->hasBackwardUpdate()) {
@@ -319,7 +319,6 @@ void SpdKalmanFitterRefTrack::processTrackWithRep(Track* tr, const AbsTrackRep*
   status->setBackwardChi2(chi2BW);
   status->setForwardNdf(ndfFW);
   status->setBackwardNdf(ndfBW);
-  
 }
 
 //______________________________________________________________________________________________________________________
diff --git a/proc/vertex/CMakeLists.txt b/proc/vertex/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82a96091e17ac51631cbaf03162dcbf943d8d3b1
--- /dev/null
+++ b/proc/vertex/CMakeLists.txt
@@ -0,0 +1,44 @@
+
+#
+# Create a library called "VertexKF" 
+# 
+
+set(INCLUDE_DIRECTORIES
+${ROOT_INCLUDE_DIR} 
+${BASE_INCLUDE_DIRECTORIES}
+${CMAKE_SOURCE_DIR}/proc/
+${CMAKE_SOURCE_DIR}/proc/vertex
+${CMAKE_SOURCE_DIR}/external/KFParticle/
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticle
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticlePerformance
+${CMAKE_SOURCE_DIR}/spddata/
+${CMAKE_SOURCE_DIR}/spddata/IdealTrackData
+)
+
+include_directories( ${INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
+
+set(LINK_DIRECTORIES
+${ROOT_LIBRARY_DIR}
+${FAIRROOT_LIBRARY_DIR}
+) 
+
+link_directories( ${LINK_DIRECTORIES})
+
+set(SRCS
+SpdKFParticleTest.cxx
+)
+
+set(HEADERS
+SpdKFParticleTest.h
+)
+
+ADD_DEFINITIONS(-DHomogeneousField)
+#ADD_DEFINITIONS(-DNonhomogeneousField)
+
+Set(LINKDEF VertexKFLinkDef.h)
+Set(LIBRARY_NAME VertexKF)
+Set(DEPENDENCIES Base)
+
+GENERATE_LIBRARY()
+
diff --git a/proc/vertex/SpdKFParticleTest.cxx b/proc/vertex/SpdKFParticleTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1d84cf8ad439732e0580a8a6f5afb7c6404226f7
--- /dev/null
+++ b/proc/vertex/SpdKFParticleTest.cxx
@@ -0,0 +1,231 @@
+
+//_____________________________________________________________________________
+//
+// SpdKFParticleTest
+//_____________________________________________________________________________
+
+#include "SpdKFParticleTest.h"
+
+#include "KFParticle.h"
+#include "KFPTrack.h"
+#include "KFPVertex.h"
+#include "KFParticleSIMD.h"
+
+#include <iostream>
+#include <iomanip>
+#include <cmath>
+
+ClassImp(SpdKFParticleTest)
+
+
+std::ostream&  operator<<(std::ostream& os, const KFParticleBase& particle) {
+  static const char *vn[14] = {"x","y","z","px","py","pz","E","S","M","t","p","Q","Chi2","NDF"};
+
+  for (Int_t i = 0; i < 8; i++) {
+    if (i == 6) continue;                                    // E
+    if (i == 7 && particle.GetParameter(i) <= 0.0) continue; // S
+    if (particle.GetParameter(i) == 0. && particle.GetCovariance(i,i) == 0) continue;
+    if (particle.GetCovariance(i,i) > 0) 
+      os << " " << vn[i]<<": "<< std::setw(8) << particle.GetParameter(i)<< " +/- " << std::setw(6) << sqrt(particle.GetCovariance(i,i));
+    else 
+      os << " " << vn[i] << ": " << std::setw(8) << particle.GetParameter(i);
+  }
+  float Mtp[3], MtpErr[3];
+  particle.GetMass(Mtp[0], MtpErr[0]);     if (MtpErr[0] < 1e-7 || MtpErr[0] > 1e10) MtpErr[0] = -13;
+  particle.GetLifeTime(Mtp[1], MtpErr[1]); if (MtpErr[1] <=   0 || MtpErr[1] > 1e10) MtpErr[1] = -13;
+  particle.GetMomentum(Mtp[2], MtpErr[2]); if (MtpErr[2] <=   0 || MtpErr[2] > 1e10) MtpErr[2] = -13;
+  for (Int_t i = 8; i < 11; i++) {
+    if (i == 9 && Mtp[i-8] <= 0.0) continue; // t
+    if (MtpErr[i-8] > 0 && MtpErr[i-8] < 1e10) os << " " << vn[i] << ": " << std::setw(8) << Mtp[i-8] << " +/-" << std::setw(7) << MtpErr[i-8];
+    else                                       os << " " << vn[i] << ": " << std::setw(8) << Mtp[i-8];
+  }
+  os << " pdg:" << std::setw(5) << particle.GetPDG() << " Q: "<< std::setw(2) << int(particle.GetQ()) << " chi2/NDF: " << std::setw(8) << particle.GetChi2() << "/" << std::setw(2) << particle.GetNDF();
+  return os;
+}
+
+//_____________________________________________________________________________
+SpdKFParticleTest::SpdKFParticleTest():fMotherSingle(0),fMotherSIMD(0)
+{
+  fMotherSingle = new KFParticle();
+  fMotherSIMD   = new KFParticleSIMD();
+}
+
+//_____________________________________________________________________________
+SpdKFParticleTest::~SpdKFParticleTest() 
+{
+  if (fMotherSingle) delete fMotherSingle;
+  if (fMotherSIMD) delete fMotherSIMD;
+}
+
+//_____________________________________________________________________________
+void SpdKFParticleTest::RunTest() 
+{
+  RunTestSingle();
+  RunTestSIMD();
+}
+
+//_____________________________________________________________________________
+void SpdKFParticleTest::RunTestSingle()
+{
+    
+std::cout << "----------------------------------------------------------------------------" <<std::endl;
+#ifdef HomogeneousField 
+  std::cout << "\n ---- HomogeneousField  \n" << std::endl;
+#endif 
+
+#ifdef NonhomogeneousField 
+  std::cout << "\n ---- NonhomogeneousField  \n" << std::endl;  
+#endif  
+std::cout << "----------------------------------------------------------------------------" <<std::endl;  
+    
+  std::cout.setf(std::ios::fixed);
+  std::cout.setf(std::ios::showpoint);
+  std::cout.precision(3);
+    
+  std::cout << "Try different constructors" << std::endl<< std::endl;
+  std::cout << "1. Construction from Vertex" << std::endl<< std::endl;
+  KFPVertex vert;
+  vert.SetXYZ(0.0, 0.0, 10.0);
+  vert.SetCovarianceMatrix( 0.01,
+                            0.00,  0.01,
+                            0.00,  0.00, 0.01 );
+  vert.SetNContributors(2);
+  vert.SetChi2(1.01);
+  
+  KFParticle p1(vert);
+  std::cout << "Vertex Particle p1" << std::endl << "  " << p1 << std::endl;
+
+  ///  *****************************************************************************************
+  
+#ifdef HomogeneousField 
+  KFParticle::SetField(4.9797992706298828);
+#endif
+  
+  float point[3]={0.f};
+  float b[3] = {0.f};
+  p1.GetFieldValue(point,b);
+  std::cout << "Set Field " <<  std::setw(6) << b[2] << std::endl;
+ 
+  std::cout << std::endl << "2. Construction from Track" << std::endl<< std::endl;
+  
+  KFPTrack track;
+  track.SetParameters(-0.061996019110347252, -1.3579236865955473,   27.147283554077148, 
+    		       0.62539337626870062,  -0.028552340672283318, -0.18467358509984011);
+  float C[21]= {3.3055800809774214e-05, 
+		   0.00098316976438185002,    0.04740889543423539, 
+		  -8.5596097466772512e-05, -0.0037516094381694971,    0.032156504690647125, 
+		  -2.2812597903705375e-05, -0.0012121012247057524,  3.0646383360925928e-05, 6.1388628418184652e-05, 
+		  -4.4071909055788304e-06,-0.00048870318030618627,  3.8062554692505919e-05, 1.2177141510445709e-05, 7.6900178535210476e-06, 
+		   6.6224441962932268e-06, 0.00034363110217286891, -0.00031520420397528146,-1.6277704753223909e-05,-3.4322154557097545e-06, 1.027411488502718e-05};
+  track.SetCovarianceMatrix(C);
+  track.SetNDF(1);
+  track.SetChi2(1.5);
+  track.SetCharge(-1);
+  
+  KFParticle p2(track, -211);
+  
+  std::cout << "Track Particle p2" << std::endl <<"  "<< p2 << std::endl;
+  
+  ///  *****************************************************************************************
+  
+  std::cout << std::endl << "3. Now we will create one more particle from track and call the construction from these 2 particles" << std::endl<< std::endl;
+  
+  KFPTrack track2;
+  track2.SetParameters(-0.20371287092090862,   3.0678058943547839,  -19.93988037109375, 
+		        0.37533048135363339, 0.024923235867488316, 0.19031024520542122);
+  float C2[21]=
+    { 0.00022312908970259721, 
+     -0.00064291160449645151,   0.089331037457232143, 
+      0.00047880877483649206,  -0.045478494677353445,     0.11199165135622025, 
+      4.6362085390124077e-07, 0.00070978326424729935, -0.00014164977426380486, 1.7553871209443515e-05, 
+     -2.2044831998838091e-05,-0.00059994741249631909,  0.00030148707952079015,-4.6574515272730461e-06, 7.2618497455845866e-06, 
+     -1.2427988441207971e-06, 0.00030830063771211896, -0.00061853865528922161, 5.4390968700069889e-06,-1.9914477627292868e-06, 8.9837108094398403e-06};
+
+  track2.SetCovarianceMatrix(C2);
+  track2.SetNDF(2);
+  track2.SetChi2(2.5);
+  track2.SetCharge(+1);
+  KFParticle p3(track2, 211); // PDG = 11
+  std::cout << "Track Particle p3 " << std::endl <<"  "<< p3 << std::endl;
+  
+  KFParticle p4(p2, p3);
+  std::cout << "Particle p4(p2,p3)" << std::endl << "  " << p4 << std::endl;
+
+  ///  *****************************************************************************************
+  std::cout << std::endl << "4. Construction with constrained Mass or (and) vertex position values" << std::endl<< std::endl;
+
+/// This is the example of the KFParticleBase::Construct function usage.
+/// parameter 1 - array of the daughter particles
+/// parameter 2 - number of the daughter particles
+/// parameter 3 - vertex (it should be the object of the KFParticle class)
+/// parameter 4 - the value we force the particle mass to be equial to.
+
+  const KFParticle pVertex = p1;
+  int NDaughters = 2;
+  const KFParticle *vDaughters[2] = {&p2, &p3};
+  
+  Double_t Mass = 0.497614;
+  
+  std::cout << "4.1 Construction with constrained Mass, without vertex hypothesis " << std::endl<< std::endl;
+/// we assume Mass to be the mass of the constructed particle
+  KFParticle K0;
+  K0.Construct(vDaughters,NDaughters,0,Mass);
+  std::cout << "Dauthers" << std::endl
+	    << "  " << *vDaughters[0] << std::endl
+	    << "  " << *vDaughters[1] << std::endl
+	    << "Mass    " << Mass << std::endl;
+  std::cout << "Particle K0" << std::endl << K0 << std::endl;
+  K0.SetProductionVertex(pVertex);
+  std::cout << " Add parent Vertex" << std::endl;
+  std::cout << " K0 with vertex  " << K0 << std::endl;
+  std::cout << std::endl << "4.2 Construction without constrained Mass, with vertex hypothesis " << std::endl<< std::endl;
+/// we assume p1 to be the vertex of the constructed particle
+  KFParticle K0_1;
+  K0_1.Construct(vDaughters,NDaughters,&pVertex,-1);
+
+  std::cout << "Dauthers" << std::endl
+	    << "  " << *vDaughters[0] << std::endl
+	    << "  " << *vDaughters[1] << std::endl
+	    << "PV " << std::endl << "  " << pVertex        << std::endl;
+  std::cout << "K0_1" << std::endl <<"  " << K0_1 << std::endl;
+  std::cout << std::endl << "4.3 Construction with constrained Mass, with vertex hypothesis " << std::endl<< std::endl;
+///we assume p1 to be the vertex of the constructed particle, Mass to be the mass of the constructed particle
+  KFParticle K0_2;
+  K0_2.Construct(vDaughters,NDaughters,&pVertex,Mass);
+
+  std::cout << "Dauthers" << std::endl
+	    << "  " << *vDaughters[0] << std::endl
+	    << "  " << *vDaughters[1] << std::endl
+	    << "PV " << std::endl << "  " << pVertex        << std::endl
+	    << "Mass    " << Mass << std::endl;
+  std::cout << "K0_2" << std::endl <<  "  " << K0_2 << std::endl;
+
+  std::cout << std::endl << "4.4 Construction K0_3(p2,p3) without constrained Mass, without vertex hypothesis " << std::endl<< std::endl;
+///we assume p1 to be the vertex of the constructed particle, Mass to be the mass of the constructed particle
+  KFParticle K0_3;
+  K0_3.Construct(vDaughters,NDaughters,0,-1);
+
+  std::cout << "Dauthers" << std::endl
+       << "  " << *vDaughters[0] << std::endl
+       << "  " << *vDaughters[1] << std::endl;
+  std::cout << "K0_3" << std::endl << "  " <<  K0_3 << std::endl;
+  
+  std::cout << "----------------------------------------------------------------------------" <<std::endl;
+}
+
+//_____________________________________________________________________________
+void SpdKFParticleTest::RunTestSIMD()
+{
+}
+
+//_____________________________________________________________________________
+void SpdKFParticleTest::CompareSingleAndSIMDResults()
+{
+}
+
+//_____________________________________________________________________________
+void SpdKFParticleTest::PrintTutorial()
+{
+}
+
+
diff --git a/proc/vertex/SpdKFParticleTest.h b/proc/vertex/SpdKFParticleTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..f948c684ab6604955385d4158f1a934c96e21995
--- /dev/null
+++ b/proc/vertex/SpdKFParticleTest.h
@@ -0,0 +1,50 @@
+
+#ifndef __SPDKFPARTICLETEST_H__
+#define __SPDKFPARTICLETEST_H__
+
+#include <TObject.h>
+ 
+class KFParticle;
+class KFParticleSIMD;
+
+//---------------------------------------------------------------------------------
+// The KFParticle class
+// .
+// @author  Maksym Zyzak
+// @version 1.0
+// @since   13.05.07
+// 
+// Class to reconstruct and store the decayed particle parameters.
+// The method is described in CBM-SOFT note 2007-003, 
+// ``Reconstruction of decayed particles based on the Kalman filter'', 
+// http://www.gsi.de/documents/DOC-2007-May-14-1.pdf
+//
+// This class is ALICE interface to general mathematics in KFParticleBase
+// 
+//  -= Copyright &copy ALICE HLT and CBM L1 Groups =-
+//_________________________________________________________________________________
+
+class SpdKFParticleTest: public TObject {
+
+public:
+
+    SpdKFParticleTest();
+    virtual ~SpdKFParticleTest();
+ 
+    void PrintTutorial();
+    void RunTest();
+  
+private:
+    
+    void RunTestSingle();
+    void RunTestSIMD();
+    void CompareSingleAndSIMDResults();
+  
+    KFParticle*     fMotherSingle;
+    KFParticleSIMD* fMotherSIMD;
+  
+    ClassDef(SpdKFParticleTest,1)
+};
+
+#endif  /* __SPDKFPARTICLETEST_H__ */
+
diff --git a/proc/vertex/VertexKFLinkDef.h b/proc/vertex/VertexKFLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..9840348c034841bd5b6611ec9f3dc8d8200a8462
--- /dev/null
+++ b/proc/vertex/VertexKFLinkDef.h
@@ -0,0 +1,10 @@
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class SpdKFParticleTest+;
+
+#endif
diff --git a/procmc/SpdIdealTrackFinder.cxx b/procmc/SpdIdealTrackFinder.cxx
index 67ba16dc67ac0337f7beda1340a7529a285f0343..f9a7f11204e370476d4155b820e67c82aa491b5c 100644
--- a/procmc/SpdIdealTrackFinder.cxx
+++ b/procmc/SpdIdealTrackFinder.cxx
@@ -8,6 +8,7 @@
 
 #include "SpdIdealTrackFinder.h"
 
+#include <TRandom.h>
 #include <TClonesArray.h>
 #include <TGeoManager.h>
 #include <TDatabasePDG.h>
@@ -45,25 +46,72 @@ ClassImp(SpdIdealTrackFinder)
 //_____________________________________________________________________________
 SpdIdealTrackFinder::SpdIdealTrackFinder():
 FairTask("SPD Ideal track finder"),
+fOwnGeoLoader(false),
 fGeoLoader(0),
 fEventHeader(0),
 fMCTracksArray(0),
 fEvent(0),
 fParameters(0),
-fNErrors(0)
+fPrimVertexOnly(true),
+fNErrors(0),
+fNFailedHits(0)
 {
     fMinMomentum[0]     = 4e-3; fMinMomentum[1]     = 1e-2; // pmin = [4,10] MeV
     fMinGammaBeta[0]    = 0.05; fMinGammaBeta[1]    = 0.5;  // p/m
     fMinVertexNHits[0]  = 0;    fMinVertexNHits[1]  = 1;    
     fMinTrackerNHits[0] = 2;    fMinTrackerNHits[1] = 2;
     
+    Double_t mkm = 1e-4;
+    
+    // set hits resolution (undefined type): x, y, z
+    SetHitResolution(kSpdIts,  'n', 100*mkm, 100*mkm, 100*mkm); 
+    SetHitResolution(kSpdTsTB, 'n', 150*mkm, 150*mkm, 150*mkm); 
+    SetHitResolution(kSpdTsTEC,'n', 150*mkm, 150*mkm, 150*mkm); 
+    
+    // set hits resolution default point-like hits   
+    SetHitResolution(kSpdTsTB,  'p', 150*mkm, 150*mkm, 150*mkm);  
+    SetHitResolution(kSpdTsTEC, 'p', 150*mkm, 150*mkm, 150*mkm); 
+    
     fParameters = new SpdBaseParSet();
 }
 
 //_____________________________________________________________________________
 SpdIdealTrackFinder::~SpdIdealTrackFinder() 
 {
-    if (fGeoLoader) delete fGeoLoader;
+}
+
+//_____________________________________________________________________________
+void SpdIdealTrackFinder::DeleteGeoLoader()
+{
+    if (fOwnGeoLoader && fGeoLoader) {
+        cout << "-I- <SpdIdealTrackFinder::DeleteGeoLoader> Remove geometry loader" << endl;
+        delete fGeoLoader;
+        fGeoLoader = 0;
+        fOwnGeoLoader = false;
+    }
+}
+
+//_____________________________________________________________________________
+void SpdIdealTrackFinder::SetHitResolution(Int_t det, Char_t spec, Double_t res1, Double_t res2, Double_t res3)
+{
+    TVector3 res(res1,res2,res3);
+    
+    if (res2 < 0) res.SetY(res1);
+    if (res3 < 0) res.SetZ(TMath::Max(res1,res2));
+    
+    fResolution[DetResKey(det,spec)] = res;
+    
+    //cout << fResolution.size() << " "<< fResolution[DetResKey(det,spec)].X() << " " 
+    //     << fResolution[DetResKey(det,spec)].Y() << " " 
+    //     << fResolution[DetResKey(det,spec)].Z() << "\n";
+}
+
+//_____________________________________________________________________________
+TVector3 SpdIdealTrackFinder::GetHitResolution(Int_t det, Char_t spec)
+{
+    TString reskey = DetResKey(det,spec);
+    std::map< TString, TVector3 >::const_iterator it = fResolution.find(reskey);
+    return (it != fResolution.end()) ? it->second : TVector3(0.01,0.01,0.01);
 }
 
 //_____________________________________________________________________________
@@ -80,9 +128,14 @@ void SpdIdealTrackFinder::SetTrackingGeoModules(Bool_t add_passives)
 //_____________________________________________________________________________
 void SpdIdealTrackFinder::LoadGeometry() 
 { 
-    if (fGeoLoader) delete fGeoLoader;
+    fGeoLoader = SpdGeoLoader::Instance();
+
+    if (!fGeoLoader) { 
+        fGeoLoader = new SpdGeoLoader(); 
+        fOwnGeoLoader = true; 
+    }
+    else fOwnGeoLoader = false;
     
-    fGeoLoader = new SpdGeoLoader();
     fGeoLoader->LoadGeometry();    // load TOP level only (cave)
     
     Int_t n = fGeoModules.size();
@@ -186,7 +239,7 @@ InitStatus SpdIdealTrackFinder::Init()
     std::map<Int_t,ITF_info*>::iterator it = fInputData.begin();
     for (; it != fInputData.end(); it++) {
          
-         pars = fGeoLoader->GetParameters(it->first);
+         pars = fGeoLoader->GetActiveParameters(it->first);
          
          pars->GetParameter("Detector/NOutData",NDataOut);
          if (NDataOut < 1) {
@@ -223,6 +276,7 @@ InitStatus SpdIdealTrackFinder::Init()
     cout << "-I- <SpdIdealTrackFinder:Init> Intialization successfull " << endl;
     
     fNErrors = 0;
+    fNFailedHits = 0;
     
     return kSUCCESS;
 }
@@ -235,6 +289,8 @@ void SpdIdealTrackFinder::Exec(Option_t* opt)
     
     fEvent->ClearData();
     
+    Int_t nfailedhits = fNFailedHits;
+    
     // >>>>> Fill event <<<<< 
     
     fEvent->SetRunId(fEventHeader->GetRunID());
@@ -278,14 +334,15 @@ void SpdIdealTrackFinder::Exec(Option_t* opt)
     }
     
     if (Nt == 0) {
-        cout << "<SpdIdealTrackFinder::Exec> No data for the event: " << fEventHeader->GetEventID() << endl;
+        cout << "<SpdIdealTrackFinder::Exec> No accepted data for the event: " << fEventHeader->GetEventID() << endl;
+        fEventHeader->Reset();
         return;
     }
     
-    cout << "<SpdIdealTrackFinder::Exec> event: " << fEventHeader->GetEventID()
-         << "; add tracks: " << Nt << "/" << Nmc << endl;
+    //cout << "<SpdIdealTrackFinder::Exec> event: " << fEventHeader->GetEventID()
+    //     << "; add tracks: " << Nt << "/" << Nmc << endl;
     
-    fEvent->SetInfoNTracks(Nt); 
+    fEvent->SetInfoNTracks(Nt);  
     
     // +++++ +++++ CREATE HITS +++++ +++++
     
@@ -332,10 +389,15 @@ void SpdIdealTrackFinder::Exec(Option_t* opt)
 
     std::map< Int_t,std::map<Double_t, SpdIdealHit*> >::iterator itx = htracks.begin();
     Int_t n(0); 
+    Int_t hit_uid(0);
     for ( ; itx != htracks.end(); itx++) {
          track = fEvent->GetTrack(n);
          std::map<Double_t, SpdIdealHit*>::iterator itxx = itx->second.begin();
-         for (; itxx != itx->second.end(); itxx++) track->AddHit(itxx->second);
+         for (; itxx != itx->second.end(); itxx++) {
+              itxx->second->AddTrackId(n);
+              itxx->second->SetId(hit_uid++);
+              track->AddHit(itxx->second);
+         }
          n++;
     }
      
@@ -357,11 +419,11 @@ void SpdIdealTrackFinder::Exec(Option_t* opt)
              track = fEvent->GetTrack(htrnums[i]);
              
              np1 = mctrack->GetNPoints(DetectorId(it->first));
-             np2 = dinfo->GetTrackHits(htrnums[i]);
+             np2 = dinfo->GetTrackHits(htrnums[i]); 
             
              nn += np1;
              
-             if (np1 != np2) {
+             if (np1 != np2) { 
                  cout << "-W- <SpdIdealTrackFinder::Exec> Number of hits: " 
                       << np1 << "/"<< np2 << endl;
                  nerrrors++;    
@@ -379,8 +441,13 @@ void SpdIdealTrackFinder::Exec(Option_t* opt)
     }
  
     if (fEvent->GetErrorFlag() != 0) fNErrors++;
+    
+    if (fNFailedHits > nfailedhits) {
+        if (fEvent->GetErrorFlag() == 0) fEvent->SetErrorFlag(2);
+        else fEvent->SetErrorFlag(3);
+    }
  
-    fEvent->PrintData();
+    //fEvent->PrintData();
     
     fEventHeader->Reset();
 }
@@ -398,7 +465,7 @@ SpdIdealTrack* SpdIdealTrackFinder::CreateTrack(Int_t id, SpdMCTrack* mctrack, B
     
     // check track number
     if (fTracksSelected.empty()) {
-        if (mctrack->GetFirstMotherId() != -1) 
+        if (fPrimVertexOnly && mctrack->GetFirstMotherId() != -1) 
         {
             accept_track = kFALSE; //ATTENTION 
             selmark = kVertexParticle;
@@ -477,7 +544,12 @@ SpdIdealHit* SpdIdealTrackFinder::CreateHit(FairMCPoint* point, Int_t DetId, ITF
 SpdIdealHit* SpdIdealTrackFinder::CreateItsHit(FairMCPoint* point, ITF_info* info)
 {
     info->htype = kSpacepoint;
+    
+    if (!fGeoLoader) return 0;
         
+    SpdDetector* det = fGeoLoader->GetActive(kSpdIts);
+    if (!det) return 0;
+    
     SpdItsPoint* p = dynamic_cast<SpdItsPoint*>(point);
     if (!p) return 0;
     
@@ -492,21 +564,272 @@ SpdIdealHit* SpdIdealTrackFinder::CreateItsHit(FairMCPoint* point, ITF_info* inf
     
     hit->SetDetId(1,id);
     
-    TVector3 v;
-    Double_t x[3], t;
+    TVector3 v;  // MC-hit position
+    Double_t t;  // MC-hit time
     
     p->GetPosTime(v,t);
 
-    hit->SetPoint(v);
+    hit->SetPoint(v);   // ATTENTION set MC-POINT position
     hit->SetTimeStamp(t);
+   
+    TString path = builder->GetNodePath();
+    
+    // check detector part (barrel or endcap) ATTENTION
+    Bool_t barrel_part = true;
+    if (path.Contains("EClayer")) barrel_part = false; 
     
+    Double_t x[3];
+    
+    // set detector position
     if (builder->GetDetectorPosition(x)) hit->SetDetPos(x[0],x[1],x[2]);
-    if (builder->GetDetectorOrientation(x,'z')) hit->SetU(TVector3(x[0],x[1],x[2]));
-    if (builder->GetDetectorOrientation(x,'x')) hit->SetV(TVector3(x[0],x[1],x[2]));
+        
+    // set chip local axis
+    if (barrel_part) {
+        // BARREL: (z->u, x->v, y->n)
+        if (builder->GetDetectorOrientation(x,'z')) hit->SetU(TVector3(x[0],x[1],x[2]));
+        if (builder->GetDetectorOrientation(x,'x')) hit->SetV(TVector3(x[0],x[1],x[2]));
+        if (builder->GetNodeSize(x)) hit->SetL(x[2],x[0],x[1]); //u,v,n-sizes 
+    }
+    else {
+        // ENDCAPS: (x->u, y->v, z->n)
+        if (builder->GetDetectorOrientation(x,'x')) hit->SetU(TVector3(x[0],x[1],x[2]));
+        if (builder->GetDetectorOrientation(x,'y')) hit->SetV(TVector3(x[0],x[1],x[2]));
+        if (builder->GetNodeSize(x)) hit->SetL(x[0],x[1],x[2]); //u,v,n-sizes  
+    }
     
-    if (builder->GetNodeSize(x)) hit->SetL(x[2],x[0],x[1]);
+    //===============================================
+    // searching for HIT position and specification
+    //===============================================
     
-    return hit;   
+    //cout << "\n<SpdIdealTrackFinder::CreateItsHit> Check specifity, find hit position " << "\n\n";
+    
+    SpdGeoVVolumeBox2D* vvol = dynamic_cast<SpdGeoVVolumeBox2D*>(builder->GetNodeVVolume()); 
+    
+    //if (vvol) vvol->PrintVolume();
+    //p->Print("");
+    
+    Bool_t nehits = !det->GetSaveEmptyHits();
+    
+    Char_t spec = 'n';    // hit specification    
+    Int_t  submod_id(0);  // submodule id for vertex detector: 0 = barrel part, 1 = endcaps  
+    
+    // check submodule id 
+    if (!barrel_part) {
+        submod_id = 1;
+        hit->SetDetId(2,submod_id);
+        hit->SetSpecifity('p'); // specification = "point"
+        
+        //hit->SetHit(v); // ATTENTION set HIT position = MC-POINT for ITS endcaps
+        hit->SetHit(v[0],v[1],hit->GetDetPosZ()); // ATTENTION set HIT position = MC-POINT(X,Y)+DET_POS(Z) for ITS endcaps
+        
+        hit->SetResolution(GetHitResolution(kSpdIts,hit->GetSpecifity())); // set hit resolution
+        
+        // ATTENTION
+        if (TMath::Abs(hit->GetHitN()) > 1e-14) {
+            hit->SetSpecifity('n');
+            fNFailedHits++;
+            //cout << "(1) spec  "<< hit->GetSpecifity() << " U, V, N: " 
+            //     << hit->GetHitU() << " " << hit->GetHitV() << " " << hit->GetHitN() << endl;            
+        }
+        return hit;     
+    }
+    
+    // check if hit is empty
+    if (nehits && !(point->GetEnergyLoss() > 0)) {
+        
+        hit->SetDetId(2,submod_id);
+        hit->SetSpecifity('n');  // specification = "undefined"
+        hit->SetHit(v); // ATTENTION set HIT position = MC-POINT 
+        hit->SetResolution(GetHitResolution(kSpdIts,hit->GetSpecifity())); // set hit resolution
+        fNFailedHits++;
+        return hit;      
+    }
+        
+    // check hit specification
+    if (vvol) {
+        TString vvolname = vvol->GetName();
+        if (vvolname.Contains("DSSD")) spec = 's';
+        else if (vvolname.Contains("MAPS")) spec = 'm';
+    }
+    
+    Double_t hit_pos[3] = {0, 0, 0};    // chip channel global position (x,y,z)
+    
+    //cout << "Hit production; spec = " << hit->GetSpecifity() << " " << vvol << " " << path << endl;
+    
+    // standard hit specifications
+    if (spec == 's' || spec == 'm') 
+    {
+        Int_t nchan = p->GetVDataSize();   // number of hitted channels in the chip
+        Int_t vid;                         // chip channel id 
+        if (nchan < 1) spec = 'n';
+        else if (nchan == 1) {
+            if (nehits && !(p->GetVed(0) > 0)) spec = 'n';
+            else {
+                vid = p->GetVid(0); 
+                if (vid < 0) spec = 'n';
+                else {
+                    builder->SetVid(vid); // set channel C.S.
+                    if (!builder->GetDetectorPosition(hit_pos)) spec = 'n';
+                }
+            }
+        }
+        else {
+            Int_t iz_ch, iphi_ch;  // chip channel id's: iz_ch = id1, iphi_ch = id2
+            Int_t nc(0), az_ch(0), aphi_ch(0);
+            for (Int_t j(0); j < nchan; j++) {
+                 vid = p->GetVid(j);
+                 if (vid < 0) continue;
+                 if (nehits && !(p->GetVed(j) > 0)) continue;
+                 vvol->CellId(vid, iz_ch, iphi_ch);
+                 az_ch += iz_ch;
+                 aphi_ch += iphi_ch;
+                 nc++;
+                 //cout << j << "  (z,phi):  " << iz_ch << "  " << iphi_ch << endl;
+            }  
+            //cout << "  a(z,phi):  " << az_ch/Double_t(nc) << "  " << aphi_ch/Double_t(nc) << " nc = " << nc << endl;
+            if (nc == 0) {
+                Double_t dep = 0;
+                if (p->IsSpecialPoint(vid,dep)) { // special case: very short (~several mkm) track segment 
+                    if (nehits && !(dep > 0)) spec = 'n';
+                    else {
+                        builder->SetVid(vid); // set channel C.S.
+                        if (!builder->GetDetectorPosition(hit_pos)) spec = 'n';
+                        //cout << "spec: " << spec << " vid = " << vid << " dep =  " << dep << endl;
+                    }
+                }
+                else spec = 'n';
+            }
+            else if (nc == 1) {
+                vid = vvol->CellId(az_ch,iphi_ch);
+                builder->SetVid(vid); // set channel C.S.
+                if (!builder->GetDetectorPosition(hit_pos)) spec = 'n';
+            }
+            else {
+                Double_t pos[3];
+                vvol->GetPos(az_ch/Double_t(nc),aphi_ch/Double_t(nc),pos);
+                builder->SetVid(-1);  // set chip C.S.
+                if (!builder->LocalToGlobalP(pos,hit_pos)) spec = 'n'; 
+            }
+        }
+        
+//         cout << "\t vol.name = " << vvol->GetName() << ";  specifity: " << spec << ";  sub_mod: " << submod_id 
+//              << ";  nchannels: " << nchan << ";  " << builder->GetNodePath() << "\n\n";
+//         printf("\t its point (1): %14.8f  %14.8f  %14.8f\n",v.X(),v.Y(),v.Z());
+//         printf("\t its point (2): %14.8f  %14.8f  %14.8f\n",hit_pos[0],hit_pos[1],hit_pos[2]);
+//         printf("\n");
+
+    }
+ 
+    if (spec == 'n') {
+        hit->SetDetId(2,submod_id);
+        hit->SetSpecifity('n');   // specification = "undefined"
+        hit->SetHit(v); // ATTENTION set HIT position = MC-POINT 
+        hit->SetResolution(GetHitResolution(kSpdIts,hit->GetSpecifity()));
+        fNFailedHits++;
+        //p->Print("");
+        return hit;          
+    }
+    
+    hit->SetDetId(2,submod_id);
+    hit->SetSpecifity(spec); // specification = 'm' (MAPS) or 's' (DSSD)
+    hit->SetHit(hit_pos[0],hit_pos[1],hit_pos[2]); // ATTENTION set hit position
+    hit->SetResolution(GetHitResolution(kSpdIts,hit->GetSpecifity()));
+    
+    // ATTENTION
+    if (TMath::Abs(hit->GetHitN()) > 1e-14) {
+        hit->SetSpecifity('n');
+        fNFailedHits++;
+        //cout << "(2) spec  "<< hit->GetSpecifity() << " U, V, N: " 
+        //       << hit->GetHitU() << " " << hit->GetHitV() << " " << hit->GetHitN() << endl;
+    }
+    
+    return hit; 
+    
+    // calculate resolution "on the fly" 
+//     if (spec == 'm') 
+//     {
+//         static Int_t nr = 0; 
+//         static Double_t rsum = 0;
+//         static Double_t rsum2 = 0;
+//         static Double_t dd = -1.;
+//   
+//         Double_t r2 = (v.X()-hit_pos[0])*(v.X()-hit_pos[0])+
+//                       (v.Y()-hit_pos[1])*(v.Y()-hit_pos[1])+
+//                       (v.Z()-hit_pos[2])*(v.Z()-hit_pos[2]);
+//         Double_t r = TMath::Sqrt(r2);
+//        
+//         nr++;
+//         rsum2 += r2;
+//         rsum  += r;
+//         if (r > dd) dd = r;
+//         
+//         cout << "[ITS] specifity: " << spec
+//              << "  diff. distance (current, max, ave) = " << r*1e4 
+//              << "  " << dd*1e4 << "  " << 1e4*rsum/nr << " [mkm] " 
+//              << " sigma = " << 1e4*TMath::Sqrt(TMath::Abs(rsum2/nr-rsum*rsum/(nr*nr))) << " [mkm] " << endl;
+//         
+//         //printf("\t its point (1): %14.8f  %14.8f  %14.8f\n",v.X(),v.Y(),v.Z());
+//         //printf("\t its point (2): %14.8f  %14.8f  %14.8f\n",hit_pos[0],hit_pos[1],hit_pos[2]);
+//         //p->Print("");            
+//     }
+//     else if (spec == 's') 
+//     {
+//         static Int_t nr = 0; 
+//         static Double_t rsum = 0;
+//         static Double_t rsum2 = 0;
+//         static Double_t dd = -1.;
+//         
+//         static Double_t xsum2[3] = {0,0,0};
+//         static Double_t xsum[3]  = {0,0,0};
+//         static Double_t xd[3]    = {-1,-1,-1};
+//   
+//         Double_t r2 = (v.X()-hit_pos[0])*(v.X()-hit_pos[0])+
+//                       (v.Y()-hit_pos[1])*(v.Y()-hit_pos[1])+
+//                       (v.Z()-hit_pos[2])*(v.Z()-hit_pos[2]);
+//         Double_t r = TMath::Sqrt(r2);
+//         
+//         Double_t du = TMath::Abs(hit->GetHitU()-hit->GetPointU());
+//         Double_t dv = TMath::Abs(hit->GetHitV()-hit->GetPointV());
+//         Double_t dn = TMath::Abs(hit->GetHitN()-hit->GetPointN());
+//         
+//         nr++;
+//         
+//         rsum2 += r2;
+//         rsum  += r;
+//         if (r > dd) dd = r;
+//        
+//         xsum[0] += du;
+//         xsum[1] += dv;
+//         xsum[1] += dv;
+//         
+//         xsum2[0] += du*du;
+//         xsum2[1] += dv*dv;
+//         xsum2[2] += dn*dn;
+//         
+//         if (du > xd[0]) xd[0] = du;
+//         if (dv > xd[1]) xd[1] = dv;
+//         if (dn > xd[2]) xd[2] = dn;
+//          
+//         cout << "[ITS] specifity: " << spec
+//              << "  diff. distance (current, max, ave) = " << r*1e4 
+//              << "  " << dd*1e4 << "  " << 1e4*rsum/nr << " [mkm] " 
+//              << " sigma = " << 1e4*TMath::Sqrt(TMath::Abs(rsum2/nr-rsum*rsum/(nr*nr))) << " [mkm] " 
+//              << "\n\t (du,dv,dn) = " << du*1e4 << ", " << dv*1e4 << ", " << dn*1e4 << " [mkm] "
+//              << "  max(du,dv,dn) = " << xd[0]*1e4 << "," << xd[1]*1e4 << "," << xd[2]*1e4 << " [mkm] "
+//              << " sigma(du,dv,dn) = " << 1e4*TMath::Sqrt(TMath::Abs(xsum2[0]/nr-xsum[0]*xsum[0]/(nr*nr)))
+//                               << ", " << 1e4*TMath::Sqrt(TMath::Abs(xsum2[1]/nr-xsum[1]*xsum[1]/(nr*nr)))
+//                               << ", " << 1e4*TMath::Sqrt(TMath::Abs(xsum2[2]/nr-xsum[2]*xsum[2]/(nr*nr)))
+//              << endl;
+//              
+//         //printf("\t its point (1): %14.8f  %14.8f  %14.8f\n",v.X(),v.Y(),v.Z());
+//         //printf("\t its point (2): %14.8f  %14.8f  %14.8f\n",hit_pos[0],hit_pos[1],hit_pos[2]);
+//         //cout << hit->GetHitN() << " " << hit->GetPointN() << endl;
+//     }
+    
+    //p->Print(""); 
+    //hit->PrintHit();
+       
+//    return hit;   
 }
 
 //________________________________________________________________________________________
@@ -526,20 +849,15 @@ SpdIdealHit* SpdIdealTrackFinder::CreateTsTBHit(FairMCPoint* point, ITF_info* in
 
     SpdIdealWirepointHit* hit = new SpdIdealWirepointHit();
     
-    hit->SetDetId(1,id);
-    
-    TVector3 v;
-    Double_t x[3],t;
-    
-    p->GetPosTime(v,t);
+    hit->SetSpecifity('w');
     
-    hit->SetPoint(v);
-    hit->SetTimeStamp(t);
+    hit->SetDetId(1,id);
+    hit->SetDetId(2,0); // barrel
     
-    t = p->GetPointDir(v);
-    hit->SetDirInPoint(v,t);
+    Double_t x[3], s, t, rmax, zmax, resR, resZ, R(0), Z(0);
+    TVector3 pos, dir, size, res, Lr, Lz;
     
-    TVector3 pos, dir, size;
+    // --- detector 
     if (builder->GetDetectorPosition(x)) pos.SetXYZ(x[0],x[1],x[2]);
     if (builder->GetDetectorOrientation(x,'z')) dir.SetXYZ(x[0],x[1],x[2]);
     if (builder->GetNodeSize(x)) size.SetXYZ(x[0],x[1],x[2]);
@@ -548,7 +866,80 @@ SpdIdealHit* SpdIdealTrackFinder::CreateTsTBHit(FairMCPoint* point, ITF_info* in
     
     hit->SetWireMaxRadius(size.X());
     hit->SetWire(pos,dir,size.Z());
-        
+    
+    rmax = hit->GetWireMaxRadius();
+    zmax = hit->GetWireLength();
+    
+    // ---
+    p->GetPosTime(pos,t);        // point position and time
+    s = p->GetPointDir(dir);     // s = segment length, dir = track direction in the point
+    
+    // --- point 
+    hit->SetPoint(pos);          // position
+    hit->SetDirInPoint(dir,s);   // track direction in the point, segment length
+  
+    // --- hit resolution
+    hit->SetResolution(GetHitResolution(kSpdTsTB,hit->GetSpecifity()));
+    
+    // --- hit time & position
+    hit->SetTimeStamp(t);  // time
+    hit->SetHit(pos);      // position FIXME
+    
+    //--------------------------------------------
+    // ATTENTION >>>> create hit position >>>>  ATTENTION
+    resR = hit->GetResolutionR();
+    resZ = hit->GetResolutionZ();
+    
+    Lr = hit->GetDriftDirR(); 
+    Lz = hit->GetWireDirZ();
+    
+    R = Lr.Mag();
+    Z = Lz.Mag();
+    
+    Double_t ktol = 0.99999;
+    if (resR > 0) {
+        if (resR < rmax/TMath::Sqrt(12)) {
+            R += gRandom->Gaus(0,resR);
+            if (R < 0) R = 0;
+            else if (!(R < rmax)) R = ktol*rmax;
+        }
+        else R = gRandom->Uniform(0,ktol*rmax); 
+        if (R > 0) Lr.SetMag(R);
+    }
+    
+    if (resZ > 0) {
+        if (resZ < zmax/TMath::Sqrt(12)) {
+            Z += gRandom->Gaus(0,resZ);
+            if (Z < 0) Z = 0;
+            else if (!(Z < zmax)) Z = ktol*zmax;
+        }
+        else Z = gRandom->Uniform(0,ktol*zmax); 
+        if (Z > 0) Lz.SetMag(Z);
+    }
+    
+    pos = hit->GetWirePoint1();
+    if (Z > 0) pos += Lz;
+    if (R > 0) pos += Lr;
+    //  ATTENTION <<<< create hit position <<<<<  ATTENTION
+    //--------------------------------------------
+    
+    hit->SetHit(pos);  // new position FIXME
+   
+    // ATTENTION
+    if (hit->GetRdrift() > rmax || 
+        hit->GetZwire() > zmax ) {
+        hit->SetSpecifity('n');
+        fNFailedHits++;  
+        //cout << "<TsTB> R drift = " << hit->GetRdrift() << " Max. R = " << rmax
+        //     << " z = " << hit->GetZwire() << " Length = " << zmax << endl;
+    } 
+    
+    //cout << "<TsTB> R drift = " << hit->GetRdrift() << " / " <<  hit->GetDriftDirR().Mag() 
+    //     << " resolution (r,z): " << resR << "," << resZ << " R,Z = " << R << ", " << Z << "\n\n";
+             
+    //p->Print(""); 
+    //hit->PrintHit();
+    
     return hit;   
 }
 
@@ -569,29 +960,92 @@ SpdIdealHit* SpdIdealTrackFinder::CreateTsTECHit(FairMCPoint* point, ITF_info* i
         
     SpdIdealWirepointHit* hit = new SpdIdealWirepointHit();
     
-    hit->SetDetId(1,id);
-    
-    TVector3 v;
-    Double_t x[3],t;
+    hit->SetSpecifity('w');
     
-    p->GetPosTime(v,t);
-    
-    hit->SetPoint(v);
-    hit->SetTimeStamp(t);
-    
-    t = p->GetPointDir(v);
-    hit->SetDirInPoint(v,t);
+    hit->SetDetId(1,id);
+    hit->SetDetId(2,1); // endcap 
+  
+    Double_t x[3], s, t, rmax, zmax, resR, resZ, R(0), Z(0);
+    TVector3 pos, dir, size, res, Lr, Lz;
     
-    TVector3 pos, dir, size;
+    // --- detector 
     if (builder->GetDetectorPosition(x)) pos.SetXYZ(x[0],x[1],x[2]);
     if (builder->GetDetectorOrientation(x,'z')) dir.SetXYZ(x[0],x[1],x[2]);
     if (builder->GetNodeSize(x)) size.SetXYZ(x[0],x[1],x[2]);
     
-    dir.SetMag(1);
-    
     hit->SetWireMaxRadius(size.X());
     hit->SetWire(pos,dir,size.Z());
     
+    rmax = hit->GetWireMaxRadius();
+    zmax = hit->GetWireLength();
+    
+    // ---
+    p->GetPosTime(pos,t);        // point position and time
+    s = p->GetPointDir(dir);     // s = segment length, dir = track direction in the point
+    
+    // --- point 
+    hit->SetPoint(pos);          // position 
+    hit->SetDirInPoint(dir,s);   // track direction in the point, segment length
+
+    // --- hit resolution
+    hit->SetResolution(GetHitResolution(kSpdTsTEC,hit->GetSpecifity()));
+    
+    // --- hit time & position
+    hit->SetTimeStamp(t);        // time
+    hit->SetHit(pos);            // position FIXME
+  
+    //--------------------------------------------
+    // ATTENTION >>>> create hit position >>>>  ATTENTION
+    resR = hit->GetResolutionR();
+    resZ = hit->GetResolutionZ();
+    
+    Lr = hit->GetDriftDirR(); 
+    Lz = hit->GetWireDirZ();
+    
+    R = Lr.Mag();
+    Z = Lz.Mag();
+    
+    Double_t ktol = 0.99999;
+    if (resR > 0) {
+        if (resR < rmax/TMath::Sqrt(12)) {
+            R += gRandom->Gaus(0,resR);
+            if (R < 0) R = 0;
+            else if (!(R < rmax)) R = ktol*rmax;
+        }
+        else R = gRandom->Uniform(0,ktol*rmax); 
+        if (R > 0) Lr.SetMag(R);
+    }
+    
+    if (resZ > 0) {
+        if (resZ < zmax/TMath::Sqrt(12)) {
+            Z += gRandom->Gaus(0,resZ);
+            if (Z < 0) Z = 0;
+            else if (!(Z < zmax)) Z = ktol*zmax;
+        }
+        else Z = gRandom->Uniform(0,ktol*zmax); 
+        if (Z > 0) Lz.SetMag(Z);
+    }
+    
+    pos = hit->GetWirePoint1();
+    if (Z > 0) pos += Lz;
+    if (R > 0) pos += Lr;
+    //  ATTENTION <<<< create hit position <<<<<  ATTENTION
+    //--------------------------------------------
+    
+    hit->SetHit(pos);  // new position FIXME
+
+    // ATTENTION
+    if (hit->GetRdrift() > hit->GetWireMaxRadius() || 
+        hit->GetZwire() > hit->GetWireLength() ) {
+        hit->SetSpecifity('n');
+        fNFailedHits++;  
+        //cout << "<TsTEC> R drift = " << hit->GetRdrift() << " Max. R = " << hit->GetWireMaxRadius() << " z = " 
+        //     << hit->GetZwire() << " Length = " << hit->GetWireLength() << endl;
+    }
+             
+    //p->Print(""); 
+    //hit->PrintHit();
+    
     return hit;   
 }
 
@@ -605,7 +1059,8 @@ SpdIdealTrackFinder::ITF_info* SpdIdealTrackFinder::FindInfo(Int_t id) // protec
 //________________________________________________________________________________________
 void SpdIdealTrackFinder::Finish() 
 {
-    cout << "-I- <SpdIdealTrackFinder::Finish> Errors: " << fNErrors << endl;
+    cout << "-I- <SpdIdealTrackFinder::Finish> errors: " << fNErrors 
+         << "; failed hits: " << fNFailedHits << endl;
 }
 
 //________________________________________________________________________________________
@@ -624,8 +1079,11 @@ void SpdIdealTrackFinder::FillParametersIn(SpdBaseParSet* params)
     params->SetParameter("IdealTrackFinder/MinVertexNHits",fMinVertexNHits[1]);
     params->SetParameter("IdealTrackFinder/MinTrackerNHits",fMinTrackerNHits[1]);
     
-    if (fTracksSelected.empty()) params->SetParameter("IdealTrackFinder/TrackSelection","vertex");
-    else params->SetParameter("IdealTrackFinder/TrackSelection","id");
+    if (!fTracksSelected.empty()) params->SetParameter("IdealTrackFinder/TrackSelection","selected");
+    else {
+        if (fPrimVertexOnly) params->SetParameter("IdealTrackFinder/TrackSelection","prim");
+        else params->SetParameter("IdealTrackFinder/TrackSelection","all");
+    }
 }
 
 //________________________________________________________________________________________
diff --git a/procmc/SpdIdealTrackFinder.h b/procmc/SpdIdealTrackFinder.h
index 9ae3819f7ea48d8504a5b3c1078e5b5605bcd797..141c0939c6b94856d959f06d368e3e2cebbeb7a4 100644
--- a/procmc/SpdIdealTrackFinder.h
+++ b/procmc/SpdIdealTrackFinder.h
@@ -40,6 +40,8 @@ public:
     virtual void Exec(Option_t* opt);
     virtual void Finish();
     
+    void DeleteGeoLoader();
+    
     void SetTrackingGeoModules(Bool_t add_passives = kFALSE);
     
     void AddModule(TString module) { fGeoModules.push_back(module);  }
@@ -51,12 +53,18 @@ public:
     inline Int_t    GetMinVertexNHits()  const { return fMinVertexNHits[1];  }
     inline Int_t    GetMinTrackerNHits() const { return fMinTrackerNHits[1]; }
            Bool_t   FindSelectedTrack(Int_t eid, Int_t tid) const;
+     
+    inline void AppendPrimaryTracksOnly(Bool_t prim = true)  { fPrimVertexOnly = prim; }      
+    inline void AppendSecondaryTracks(Bool_t sec = true)     { fPrimVertexOnly = !sec; }        
            
     inline void SetMinMomentum(Double_t pmin);
     inline void SetMinGammaBeta(Double_t gbmin);
     inline void SetMinVertexNHits(Int_t nhits);
     inline void SetMinTrackerNHits(Int_t nhits);
     
+    virtual void     SetHitResolution(Int_t det, Char_t spec, Double_t res1, Double_t res2 = -1, Double_t res3 = -1);
+    virtual TVector3 GetHitResolution(Int_t det, Char_t spec);
+  
     virtual void AddTrackAsSelected(Int_t event /* >=1 */, Int_t track /*>= 0*/); 
            
     virtual void PrintInput() const;
@@ -77,7 +85,8 @@ public:
     void FillParametersIn(SpdBaseParSet* params);
     void LoadParametersFrom(SpdBaseParSet* params);
     
-    inline Int_t GetNErrors() const { return fNErrors; }
+    inline Int_t GetNErrors()     const { return fNErrors; }
+    inline Int_t GetNFailedHits() const { return fNFailedHits; }
     
 protected:
 
@@ -96,6 +105,7 @@ protected:
     
     /* Geometry */
     
+    Bool_t               fOwnGeoLoader;   //! indicates geometry loader owning
     SpdGeoLoader*        fGeoLoader;      //! SPD geometry
     std::vector<TString> fGeoModules;     //! geometry modules are to be built
   
@@ -116,9 +126,15 @@ protected:
     Int_t    fMinVertexNHits[2];  // number of hits in ITS
     Int_t    fMinTrackerNHits[2]; // total number of hits in TSTB+TSTEC
 
+    Bool_t   fPrimVertexOnly;     // if true, select tracks which belong to primary vertex only (default = true)
+
     std::map< Int_t, std::set<Int_t> > fTracksSelected; // list of selected tracks (id's) <event, set of tracks>
     
     Int_t    fNErrors;
+    Int_t    fNFailedHits;
+    
+    TString DetResKey(Int_t d, Char_t s) { return Form("Det%d_%c",d,s); }
+    std::map< TString, TVector3 > fResolution; // hit's resolution table
     
     ClassDef(SpdIdealTrackFinder,1)
 };
diff --git a/reco/CMakeLists.txt b/reco/CMakeLists.txt
index f739d9080211b740ff8f143fe0d201ae488b4765..accb7825a11d2b643819de1d1d03fea10fa982d6 100644
--- a/reco/CMakeLists.txt
+++ b/reco/CMakeLists.txt
@@ -34,7 +34,10 @@ ${CMAKE_SOURCE_DIR}/external/GenFit2/fitters/include
 ${CMAKE_SOURCE_DIR}/external/GenFit2/measurements/include
 ${CMAKE_SOURCE_DIR}/external/GenFit2/trackReps/include
 ${CMAKE_SOURCE_DIR}/external/GenFit2/utilities/include
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticle
+${CMAKE_SOURCE_DIR}/external/KFParticle/KFParticlePerformance
 ${CMAKE_SOURCE_DIR}/proc/tracking
+${CMAKE_SOURCE_DIR}/proc/vertex
 )
 
 include_directories( ${INCLUDE_DIRECTORIES})
@@ -49,14 +52,18 @@ link_directories( ${LINK_DIRECTORIES})
 set(SRCS
 
 SpdIdealKalmanFitter.cxx
+SpdIdealV0Finder.cxx
 
 )
 
+ADD_DEFINITIONS(-DHomogeneousField)
+#ADD_DEFINITIONS(-DNonhomogeneousField)
+
 Set(HEADERS )
 set(LINKDEF SpdRecoLinkDef.h)
 set(LIBRARY_NAME SpdReco)
 
-set(DEPENDENCIES Base GenFit2 SpdCommon SpdData SpdGeometry TrackingGF)
+set(DEPENDENCIES Base GenFit2 SpdCommon SpdData SpdGeometry TrackingGF KFParticle)
 
 GENERATE_LIBRARY()
 
diff --git a/reco/SpdIdealKalmanFitter.cxx b/reco/SpdIdealKalmanFitter.cxx
index d5cc1e538a57c77868a61e67bd0c32aeec526da6..bc78d4430ab2d65a87ca883d3c0e9624b1af047b 100644
--- a/reco/SpdIdealKalmanFitter.cxx
+++ b/reco/SpdIdealKalmanFitter.cxx
@@ -25,10 +25,11 @@
 
 #include "SpdIdealTrackData.hh"
 
-#include "SpdGFMeasurementCreator.h"
 #include "SpdGFMagneticField.h"
+
 #include "SpdKalmanFitterRefTrack.h"
 #include "KalmanFitterRefTrack.h"
+#include "KalmanFitter.h"
 
 #include "RKTrackRep.h"
 #include "MeasuredStateOnPlane.h"
@@ -57,14 +58,12 @@ ClassImp(SpdIdealKalmanFitter)
 
 //_____________________________________________________________________________
 SpdIdealKalmanFitter::SpdIdealKalmanFitter():FairTask("SPD Ideal Kalman fitter"),
-fField(0),fMeasCreator(0),fFitter(0),fGeoLoader(0),
+fField(0),fMeasCreator(0),fFitter(0),fOwnGeoLoader(false),fGeoLoader(0),
 fEvent(0),fKFres(0),fTracks(0),fParameters(0),
 fVerboseLevel(1),
 // Fitter options: 
 fMaterialsOpt(1),
 fSeedMomentum(1.),
-fResolution(0.005),
-fWireResolution(0.015),
 fVertexFitMethod(1),
 fVertexFitAngleCut(3.0),
 fStartSeedMethod(2),
@@ -95,6 +94,17 @@ SpdIdealKalmanFitter::~SpdIdealKalmanFitter()
     if (fTracks) delete fTracks;  
 }
 
+//_____________________________________________________________________________
+void SpdIdealKalmanFitter::DeleteGeoLoader()
+{
+    if (fOwnGeoLoader && fGeoLoader) {
+        cout << "-I- <SpdIdealKalmanFitter::DeleteGeoLoader> Remove geometry loader" << endl;
+        delete fGeoLoader;
+        fGeoLoader = 0;
+        fOwnGeoLoader = false;
+    }
+}
+
 //_____________________________________________________________________________
 void SpdIdealKalmanFitter::SetTrackingGeoModules(Bool_t add_passives)
 {
@@ -109,8 +119,17 @@ void SpdIdealKalmanFitter::SetTrackingGeoModules(Bool_t add_passives)
 //_____________________________________________________________________________
 void SpdIdealKalmanFitter::LoadGeometry() 
 { 
-    fGeoLoader = new SpdGeoLoader();
-    fGeoLoader->LoadGeometry();   // load TOP level only (cave)
+    fGeoLoader = SpdGeoLoader::Instance();
+
+    if (!fGeoLoader) { 
+        fGeoLoader = new SpdGeoLoader(); 
+        fOwnGeoLoader = true; 
+    }
+    else fOwnGeoLoader = false;
+
+    if (fMaterialsOpt < 1) fGeoLoader->UnsetMaterials(true); // ATTENTION
+    
+    fGeoLoader->LoadGeometry();   // construct TOP level only (cave)
     
     //return;
     
@@ -153,6 +172,7 @@ void SpdIdealKalmanFitter::InitFitter()
     if (fFitter) delete fFitter;
     if (fFitterOption == 1) fFitter = new KalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,true);
     else fFitter = new KalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,false);
+    //fFitter = new SpdKalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,true);
 }
 
 //_____________________________________________________________________________
@@ -206,9 +226,8 @@ InitStatus SpdIdealKalmanFitter::Init()
     fKFres = new SpdKFSimpleRes();
     ioman->Register("SpdKFSimpleRes.", "IdealKFres", fKFres, kTRUE);
     
-    //fTracks = new TClonesArray("GFTrack",100);
     fTracks = new TObjArray(100);
-    //ioman->Register("GFTrack", "GFTracks", fTracks, kTRUE);
+    if (fStoreTracks) ioman->Register("SpdGFTrackW.", "GFTracks", fTracks, kTRUE);
     
     cout << "-I- <SpdIdealKalmanFitter::Init> Intialization successfull " << endl;
     
@@ -218,7 +237,7 @@ InitStatus SpdIdealKalmanFitter::Init()
 //________________________________________________________________________________________
 void SpdIdealKalmanFitter::Exec(Option_t* opt) 
 {
-    cout << "-I- <SpdIdealKalmanFitter::Exec> " << endl;
+    //cout << "-I- <SpdIdealKalmanFitter::Exec> " << endl;
     
     if (!fEvent) return;
     if (!fTracks) return;
@@ -349,7 +368,7 @@ void SpdIdealKalmanFitter::Exec(Option_t* opt)
                  cout << "-W- <SpdIdealKalmanFitter::Exec> Fitter errors: " << emsg << endl; 
              }
          }
-        
+  
          if (!is_fitted) { 
              not_fitted++; 
              mcMom = itrack->GetStartMomentum();
@@ -359,7 +378,7 @@ void SpdIdealKalmanFitter::Exec(Option_t* opt)
          }
         
          status = (KalmanFitStatus*)track->getFitStatus();
-    
+  
          if (status) {
 
              is_fitted = status->isFitted();
@@ -387,7 +406,7 @@ void SpdIdealKalmanFitter::Exec(Option_t* opt)
                  cout << "-W- <SpdIdealKalmanFitter::Exec> Fitter errors: " << fKFres->GetErrorMessage(n) << endl;
              }
          }
-         
+     
          if (fVerboseLevel > 3) {
              cout << " >>>>>>>  <SpdIdealKalmanFitter::Exec> track (finish): " << i << " is fitted: " << is_fitted << endl;
          }
@@ -396,14 +415,34 @@ void SpdIdealKalmanFitter::Exec(Option_t* opt)
              not_fitted++; 
              mcMom = itrack->GetStartMomentum();
              fKFres->SetPmc(n,mcMom);
+             fKFres->AddErrorMessage(n,"not_fitted_track");
              delete track; 
              continue; 
          }
-         
+ 
          if (fKFres->GetConvergency(n)) nconv_tracks++;
-         
+        
          mcMom  = itrack->GetStartMomentum();
-         recMom = track->getFittedState().getMom();
+         
+         track->checkConsistency();
+         
+         // let's try to get averaged final state
+         try {
+             recMom = track->getFittedState().getMom();
+         }
+         catch (Exception& e) {
+             is_fitted = false;
+         }
+        
+         // ill-conditioned covariance matrix (KalmanFitterInfo::calcAverageState)
+         if (!is_fitted) {
+             fKFres->SetIsFitted(n,is_fitted);
+             not_fitted++; 
+             fKFres->SetPmc(n,mcMom);
+             fKFres->AddErrorMessage(n,"ill-conditioned_cov._matrix_in_the_final_state");
+             delete track; 
+             continue; 
+         }
          
          if (fVerboseLevel > 3) {
              cout << " >>>>>>>>>  <SpdIdealKalmanFitter::Exec> (finish 1): track = " << i << " / event: " << fEvent->GetEventId() 
@@ -544,46 +583,39 @@ genfit::Track* SpdIdealKalmanFitter::BuildTrack(Int_t n, genfit::Track* track)
 
     track = new Track(rep, seedState, seedCov);
 
-    // fill track  
+    // add hits to the track  
      
     Int_t NTrackHits = itrack->GetNHits();
           
     for (Int_t j(0); j<NTrackHits; j++) {
     
          ihit = (SpdIdealHit*)itrack->GetHit(j);
-    
-         //if (ihit->GetDetId(0) == kSpdIts) continue;  //FIXME
-         
-         fMeasCreator->SetResolution(HitResolution(ihit));
-    
-         vector<AbsMeasurement*> measurements = fMeasCreator->CreateHit(ihit);
+         vector<AbsMeasurement*> measurements = fMeasCreator->CreateHit(ihit,GetHitRepresentation(ihit->GetDetId()));
          point = new TrackPoint(measurements,track);
-         
          track->insertPoint(point);
     }
-
-    //track->checkConsistency();
     
     return track;
 }
 
 //________________________________________________________________________________________
-Double_t SpdIdealKalmanFitter::HitResolution(const SpdIdealHit* hit) const
+void SpdIdealKalmanFitter::SetHitRepresentation(Int_t DetId, GFMeasurementType GFhitType)
 {
-    SpdHitType detID = SpdHitType(hit->GetDetId(0)); 
-    
-    // cm
-    switch (detID) 
-    {
-        case kSpdIts:   return fResolution; 
-        case kSpdTsTB:  return fWireResolution;
-        case kSpdTsTEC: return fWireResolution; 
-        default: break;
-    }
-    
-    return 0.010; // 100 mkm
+  fHitRepresentation[DetId] = GFhitType;
+  
+//   for (auto& it1 : fHitRepresentation) {
+//        cout << "Size: " << fHitRepresentation.size() 
+//             << "  Detector/Hit: " << it1.first << " " << it1.second << endl;
+//   }
 }
 
+//________________________________________________________________________________________
+GFMeasurementType SpdIdealKalmanFitter::GetHitRepresentation(Int_t DetId) const
+{
+  auto it = fHitRepresentation.find(DetId);
+  return (it != fHitRepresentation.end()) ? GFMeasurementType(it->second) : pkSpacepoint;
+}
+ 
 //________________________________________________________________________________________
 void SpdIdealKalmanFitter::DefineTrackStartVertexAndMom(const SpdIdealTrack* track)
 {
@@ -635,7 +667,7 @@ void SpdIdealKalmanFitter::DefineTrackStartVertexAndMom(const Int_t ntrack, cons
          hit = static_cast<SpdIdealSpacepointHit*>(xhit);
          if (!hit) continue;
          if (++npx > np) nerr = 1;
-         points.push_back(hit->GetPoint());
+         points.push_back(hit->GetHit()); 
     }
     
     TVector3 p1(0,0,0), n1(0,0,1);
@@ -965,12 +997,22 @@ void SpdIdealKalmanFitter::FillParametersIn(SpdBaseParSet* params)
     params->SetParameter("IdealKalmanFitter/MaterialsOpt",fMaterialsOpt);
     
     params->SetParameter("IdealKalmanFitter/SeedMomentum",fSeedMomentum);
-    params->SetParameter("IdealKalmanFitter/Resolution",fResolution);
-    params->SetParameter("IdealKalmanFitter/WireResolution",fWireResolution);
-    
     params->SetParameter("IdealKalmanFitter/VertexFitMethod",fVertexFitMethod);
     params->SetParameter("IdealKalmanFitter/VertexFitAngleCut",fVertexFitAngleCut);
     
+    Int_t n = fHitRepresentation.size();
+
+    params->SetParameter("IdealKalmanFitter/NHRepresentations",n);
+    
+    if (n > 0) {
+        Int_t i(0);
+        for (auto& it : fHitRepresentation) {
+             params->SetParameter(Form("IdealKalmanFitter/HitRepDetId[%d]",i),it.first);
+             params->SetParameter(Form("IdealKalmanFitter/HitRepDet[%d]",i),it.second);
+             i++;
+        }  
+    }
+
     params->SetParameter("IdealKalmanFitter/fStartSeedMethod",fStartSeedMethod);
     params->SetParameter("IdealKalmanFitter/fSmearSeedValues",fSmearSeedValues);
     
@@ -999,6 +1041,8 @@ void SpdIdealKalmanFitter::LoadParametersFrom(SpdBaseParSet* params)
 {
     if (!params) return;
     
+    fHitRepresentation.clear();
+    
     Int_t pi;
     Double_t pd;
     Bool_t pb;
@@ -1006,12 +1050,20 @@ void SpdIdealKalmanFitter::LoadParametersFrom(SpdBaseParSet* params)
     if (params->GetParameter("IdealKalmanFitter/MaterialsOpt",pi)) SetMaterialEffectsOption(pi);
     
     if (params->GetParameter("IdealKalmanFitter/SeedMomentum",pd)) SetSeedMomentum(pd);
-    if (params->GetParameter("IdealKalmanFitter/Resolution",pd)) SetResolution(pd);
-    if (params->GetParameter("IdealKalmanFitter/WireResolution",pd)) SetWireResolution(pd);
-    
     if (params->GetParameter("IdealKalmanFitter/VertexFitMethod",pi)) SetVertexFindingMethod(pi);
     if (params->GetParameter("IdealKalmanFitter/VertexFitAngleCut",pd)) SetVertexFindingAngleCut(pd);
     
+    if (params->GetParameter("IdealKalmanFitter/NHRepresentations",pi)) {
+        if (pi > 0) {
+            Int_t pi2, pi3;
+            for (Int_t i(0); i<pi; i++) {
+                 params->GetParameter(Form("IdealKalmanFitter/HitRepDetId[%d]",i),pi2);
+                 params->GetParameter(Form("IdealKalmanFitter/HitRepDet[%d]",i),pi3);
+                 fHitRepresentation[pi2] = pi3;
+            }
+        }
+    }
+    
     if (params->GetParameter("IdealKalmanFitter/fStartSeedMethod",pi)) SetStartSeedMethod(pi);
     if (params->GetParameter("IdealKalmanFitter/fSmearSeedValues",pb)) SetSmearSeedValues(pb);
     
diff --git a/reco/SpdIdealKalmanFitter.h b/reco/SpdIdealKalmanFitter.h
index 3a020c33614f880d9d4fe031f556d4b49e536626..47c43285bdc9a96ec4cb83cf682d10f9186fcde8 100644
--- a/reco/SpdIdealKalmanFitter.h
+++ b/reco/SpdIdealKalmanFitter.h
@@ -11,7 +11,9 @@
 #include "SpdGeoLoader.h"
 #include "SpdIdealTrack.h"
 #include "SpdBaseParSet.h"
+#include "SpdGFMeasurementCreator.h"
 #include "AbsKalmanFitter.h"
+//#include <map>
 
 ////////////////////////////////////////////////////////////////////////////////
 //                                                                            //
@@ -44,6 +46,8 @@ public:
     virtual void Exec(Option_t* opt);
     virtual void Finish();
     
+    void DeleteGeoLoader();
+    
     /* SETTERS */
     
     void  SetVerboseLevel(Int_t level) { fVerboseLevel = level; } 
@@ -51,8 +55,7 @@ public:
     void  SetMaterialEffectsOption(Int_t opt /*-1,0(default),1 */) { fMaterialsOpt = opt; }
     
     void  SetSeedMomentum(Double_t mom /* GeV/c */) { fSeedMomentum = fabs(mom); } 
-    void  SetResolution(Double_t res /*cm*/)        { fResolution = res; }
-    void  SetWireResolution(Double_t res /*cm*/)    { fWireResolution = res; } 
+    void  SetHitRepresentation(Int_t DetId, GFMeasurementType GFhitType);
     
     void  SetVertexFindingMethod(Int_t method)            { fVertexFitMethod = method; } 
     void  SetVertexFindingAngleCut(Double_t acut /*deg*/) { fVertexFitAngleCut = acut; }
@@ -72,6 +75,11 @@ public:
   
     void  SetStoreTracks(Bool_t store = true) { fStoreTracks = store; }
     
+    /* GETTERS */
+    
+    SpdGFMeasurementCreator* GetMeasurementCreator() { return fMeasCreator; }
+    
+    // Parameters
     void  FillParametersIn(SpdBaseParSet* params);
     void  LoadParametersFrom(SpdBaseParSet* params);
 
@@ -89,7 +97,7 @@ private:
     
     genfit::Track* BuildTrack(Int_t n, genfit::Track* track = 0);
     
-    Double_t       HitResolution(const SpdIdealHit* hit) const;
+    GFMeasurementType GetHitRepresentation(Int_t DetId) const;
     
     void           DefineTrackStartVertexAndMom(const SpdIdealTrack* track);
     void           DefineTrackStartVertexAndMom(const Int_t ntrack, const SpdIdealTrack* track);
@@ -98,7 +106,7 @@ private:
     void FindVertex(TVector3& vertex); 
     
     /* Geometry */
-    
+    Bool_t                   fOwnGeoLoader;        //! indicates geometry loader owning
     SpdGeoLoader*            fGeoLoader;           //! SPD geometry
     std::vector<TString>     fGeoModules;          //! geometry modules are to be built
     
@@ -118,8 +126,7 @@ private:
         
     // standard
     Double_t                 fSeedMomentum;        // start track vertex momentum [GeV/c]
-    Double_t                 fResolution;          // cm
-    Double_t                 fWireResolution;      // cm
+    std::map<Int_t,Int_t>    fHitRepresentation;   // <Detector Id, GFMeasurementType>
     
     // advanced
     Int_t                    fVertexFitMethod;     // <1 (no fit); 1 (default)
diff --git a/reco/SpdIdealV0Finder.cxx b/reco/SpdIdealV0Finder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..44a653341486832cfcf63940087f54317f1410d3
--- /dev/null
+++ b/reco/SpdIdealV0Finder.cxx
@@ -0,0 +1,1424 @@
+// $Id$
+// Author: vladimir andreev   2020/08/29
+
+//_____________________________________________________________________________
+//
+// SpdIdealV0Finder
+//_____________________________________________________________________________
+
+#include <TRandom.h>
+#include <TVectorD.h>
+#include <TMatrixDSym.h>
+
+#include "FairRuntimeDb.h"
+#include "FairRootManager.h"
+#include "FairRun.h"
+#include "FairRunAna.h"
+
+#include "SpdFieldCreator.h"
+#include "SpdFieldPar.h"
+
+#include "SpdIdealV0Finder.h"
+
+#include "SpdGeoLoader.h"
+#include "SpdKFSimpleRes.h"
+
+#include "SpdIdealTrackData.hh"
+
+#include "SpdGFMagneticField.h"
+
+#include "SpdKalmanFitterRefTrack.h"
+#include "KalmanFitterRefTrack.h"
+#include "KalmanFitter.h"
+
+#include "RKTrackRep.h"
+#include "MeasuredStateOnPlane.h"
+#include "Track.h"
+#include "TrackPoint.h"
+#include "Exception.h"
+#include "KalmanFitStatus.h"
+
+#include <vector>
+#include <iostream>
+
+using std::cout;
+using std::endl;
+using std::vector;
+
+#include "GFCore.hh"
+#include "GFTrackReps.hh"
+
+#include "SpdGFTrackW.h"
+
+using namespace genfit;
+
+//using TMath::SignBit;
+
+ClassImp(SpdIdealV0Finder)
+
+//_____________________________________________________________________________
+SpdIdealV0Finder::SpdIdealV0Finder():FairTask("SPD Ideal V0 finder"),
+fField(0),fMeasCreator(0),fFitter(0),fOwnGeoLoader(false),fGeoLoader(0),
+fEvent(0),fKFres(0),fTracks(0),fParameters(0),
+fVerboseLevel(1),
+// Fitter options: 
+fMaterialsOpt(1),
+fSeedMomentum(1.),
+fVertexFitMethod(1),
+fVertexFitAngleCut(3.0),
+fStartSeedMethod(2),
+fSmearSeedValues(true), 
+fSmearingMomDelta(0.1),
+fSmearingAngleDelta(3.0),
+fSmearingVertexDelta(0.5),
+fNPointsVertexUse(0),
+fFitterMaxIterations(8),
+fFitterMaxTrials(10),
+fFitterOption(1),
+fStoreTracks(false),
+// V0 finder
+fFirstDaughter(321),
+fSecondDaughter(211),
+fUsedTypeOfPV(0),
+fConstrainToPV(1),
+fMinChi2PV(2.0),
+fMinDist(0.075),
+fMinMass(0.00),
+fMaxMass(2.50)
+{
+ 
+}
+
+//_____________________________________________________________________________
+SpdIdealV0Finder::~SpdIdealV0Finder() 
+{
+    if (fField) delete fField;
+    if (fMeasCreator) delete fMeasCreator;
+    if (fFitter) delete fFitter;
+
+    if (fGeoLoader) delete fGeoLoader;
+       
+    if (fEvent)  delete fEvent;  
+    if (fKFres)  delete fKFres; 
+    if (fTracks) delete fTracks;  
+
+    if (fV0file) delete fV0file;  
+    if (fV0tree) delete fV0tree;  
+}
+
+//_____________________________________________________________________________
+void SpdIdealV0Finder::DeleteGeoLoader()
+{
+    if (fOwnGeoLoader && fGeoLoader) {
+        cout << "-I- <SpdIdealD0Finder::DeleteGeoLoader> Remove geometry loader" << endl;
+        delete fGeoLoader;
+        fGeoLoader = 0;
+        fOwnGeoLoader = false;
+    }
+
+}
+
+//_____________________________________________________________________________
+void SpdIdealV0Finder::SetTrackingGeoModules(Bool_t add_passives)
+{
+    fGeoModules.clear(); 
+    if (add_passives) fGeoModules.push_back("Passives");
+    
+    fGeoModules.push_back("Inner tracker system");
+    fGeoModules.push_back("TS barrel (tor)");
+    fGeoModules.push_back("TS endcaps (tor)");
+}
+
+//_____________________________________________________________________________
+void SpdIdealV0Finder::LoadGeometry() 
+{ 
+    fGeoLoader = SpdGeoLoader::Instance();
+
+    if (!fGeoLoader) { 
+        fGeoLoader = new SpdGeoLoader(); 
+        fOwnGeoLoader = true; 
+    }
+    else fOwnGeoLoader = false;
+
+    if (fMaterialsOpt < 1) fGeoLoader->UnsetMaterials(true); // ATTENTION
+    
+    fGeoLoader->LoadGeometry();   // construct TOP level only (cave)
+    
+    //return;
+    
+    Int_t n = fGeoModules.size();
+    
+    if (n < 1) return;
+    
+    for (Int_t i(0); i<n; i++) {
+         if (fGeoModules[i].IsDigit()) fGeoLoader->LoadModule(fGeoModules[i].Atoi());
+         else fGeoLoader->LoadModule(fGeoModules[i]);
+    }
+
+    fGeoLoader->PrintActualGeometry();
+    
+    MaterialEffects::getInstance()->init(new TGeoMaterialInterface());
+}
+
+//_____________________________________________________________________________
+void SpdIdealV0Finder::LoadField()
+{
+    FairRuntimeDb* rtdb = FairRun::Instance()->GetRuntimeDb();  
+    SpdFieldCreator* fieldCreator = new SpdFieldCreator();    
+    SpdFieldPar *fpars = (SpdFieldPar*)rtdb->getContainer("SpdFieldPar");
+    
+    fField = new SpdGFMagneticField();
+    
+    if (fpars) {
+       ((FairParSet*)fpars)->init();
+        SpdField* field = (SpdField*)fieldCreator->createFairField(fpars);
+        fField->SetField(field,kTRUE);
+        if (field) field->Print(""); 
+    }
+    
+    FieldManager::getInstance()->init(fField);
+}
+
+//_____________________________________________________________________________
+void SpdIdealV0Finder::InitFitter()
+{
+    if (fFitter) delete fFitter;
+    if (fFitterOption == 1) fFitter = new KalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,true);
+    else fFitter = new KalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,false);
+    //fFitter = new SpdKalmanFitterRefTrack(fFitterMaxIterations,1e-3,1e3,true);
+}
+
+//_____________________________________________________________________________
+InitStatus SpdIdealV0Finder::Init() 
+{   
+    // get RootManager
+    
+    FairRootManager* ioman = FairRootManager::Instance();
+    if (!ioman) {
+        cout << "-E- <SpdIdealV0Finder::Init> "
+             << "RootManager not instantiated!" << endl;
+        return kFATAL;
+    }
+    
+    // Load Field, Geometry 
+   
+    LoadField();
+    LoadGeometry();
+    
+    // Init 
+    fMeasCreator = new SpdGFMeasurementCreator();
+   
+    // Init Fitter
+    InitFitter();
+    
+    // get Input data objects
+    
+    fEvent = (SpdIdealTrackColl*)ioman->GetObject("IdealTrackColl.");
+   
+    if (!fEvent) {
+        cout << "-E- <SpdIdealV0Finder::Init>" << "No HEADER object inside " << endl;
+        return kERROR;
+    }
+    
+    TFile* infile = ioman->GetInFile();
+    if (infile) fParameters = (SpdBaseParSet*)infile->Get("IdealTrackFinderParams");
+    if (!fParameters) fParameters = new SpdBaseParSet();
+    
+    fParameters->print(1);
+    
+    FillParametersIn(fParameters);
+    
+    TFile* f = gFile;
+    TFile* ff = ioman->GetOutFile();
+    ff->cd();
+//    fParameters->Write("IdealKalmanFitterParams",TObject::kOverwrite);
+    fParameters->Write("IdealV0FinderParams",TObject::kOverwrite);
+    gFile = f;
+
+    // Create and register output data objects
+    
+    fKFres = new SpdKFSimpleRes();
+    ioman->Register("SpdKFSimpleRes.", "IdealKFres", fKFres, kTRUE);
+    
+    fTracks = new TObjArray(100);
+    if (fStoreTracks) ioman->Register("SpdGFTrackW.", "GFTracks", fTracks, kTRUE);
+    
+    cout << "-I- <SpdIdealV0Finder::Init> Intialization successfull " << endl;
+
+    // name of output root-file for V0 particle
+    //--------------------------------------------
+    FairRunAna* userFile = FairRunAna::Instance();
+    if (!userFile) {
+        cout << "-E- <SpdIdealV0Finder::Init> "
+             << "FairRunAna not instantiated!" << endl;
+        return kFATAL;
+    }
+
+    TString v0_outfile_name = userFile->GetUserOutputFileName();
+    InitV0nTuple( v0_outfile_name);
+
+    return kSUCCESS;
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::Exec(Option_t* opt) 
+{
+    //cout << "-I- <SpdIdealV0Finder::Exec> " << endl;
+    
+    if (!fEvent)  return;
+    if (!fTracks) return;
+    if (!fKFres)  return;
+
+    //if (fVerboseLevel > 0) 
+        cout << "-I- <SpdIdealV0Finder::Exec> Event: " << fEvent->GetEventId() << endl;
+    
+    fKFres->ClearData();
+    fTracks->Delete();
+    
+    // Init Fitter
+    //InitFitter();
+    
+    fKFres->SetRunId(fEvent->GetRunId());
+    fKFres->SetEventId(fEvent->GetEventId());
+    fKFres->SetNPrimTracks(fEvent->GetNPrimTracks());
+    
+    TVector3 mcMom, recMom;
+    Track* track(0);
+   
+    TObjArray* tracks = fEvent->GetTracks(); 
+    Int_t NTracks = tracks->GetEntriesFast();
+    
+    fKFres->SetNSelectedTracks(NTracks);
+    
+    Int_t n;
+    
+    SpdIdealDataInfo* dinfo_its   = fEvent->FindDataInfo(kSpdIts);
+    SpdIdealDataInfo* dinfo_tstb  = fEvent->FindDataInfo(kSpdTsTB);
+    SpdIdealDataInfo* dinfo_tstec = fEvent->FindDataInfo(kSpdTsTEC);
+        
+    KalmanFitStatus* status;
+   
+    Bool_t material_effects;
+    
+    static Int_t ntotal_tracks = 0;
+    static Int_t nconv_tracks = 0;
+    static Int_t ncorrd = 0;
+    static Int_t not_fitted = 0;
+    static Int_t n_errors = 0;
+    static Int_t n_good = 0;
+  
+    Int_t  n_refit;
+    Bool_t refit_tracks = false;
+
+    if (fMaterialsOpt < 1) {
+        material_effects = false;
+        MaterialEffects::getInstance()->setNoEffects(true);
+    }
+    else {
+        material_effects = true;
+        MaterialEffects::getInstance()->setNoEffects(false);
+    }
+    
+    Exception::setEmessgflag(true);
+    
+    for (Int_t i(0); i<NTracks; i++) {
+    
+         SpdIdealTrack* itrack = (SpdIdealTrack*)tracks->At(i);
+         
+         if (fVerboseLevel > 3) {
+             cout << " >>>>>>>  <SpdIdealV0Finder::Exec> track (start): " << i << " / event: " << fEvent->GetEventId() 
+                  << " points = " << itrack->GetNPoints() << endl;
+         }
+         
+         //itrack->PrintTrack();
+         //continue;
+         
+         ntotal_tracks++;
+         
+         n = fKFres->AddTrack(itrack->GetTrackId(),itrack->GetPdgCode());
+  
+         if (dinfo_its) fKFres->SetNVhits(n,dinfo_its->GetTrackHits(n));
+         if (dinfo_tstb) fKFres->SetNTBhits(n,dinfo_tstb->GetTrackHits(n));
+         if (dinfo_tstec) fKFres->SetNTEChits(n,dinfo_tstec->GetTrackHits(n));
+
+         // build track
+         track = BuildTrack(i);
+         if (!track) continue;
+         
+         Bool_t is_fitted = false;
+         
+         n_refit = 0;
+         
+         while (true) {
+            
+            try
+            { 
+               fFitter->processTrack(track);
+               is_fitted = true;
+            }
+            catch(Exception& e)
+            {
+               is_fitted = false;
+            }
+    
+            if (n_refit < fFitterMaxTrials) {    
+                status = (KalmanFitStatus*)track->getFitStatus();
+                if (status && !status->isFitConverged()) {
+                    n_refit++;
+                    if (fVerboseLevel > 2) cout << "\t   Rebuild and refit track: " << n_refit << "/" << fFitterMaxTrials << endl;
+                    track = BuildTrack(i,track); 
+                    Exception::clearEmessg();
+                    continue;
+                }
+            }
+            
+            //track->checkConsistency();
+            
+            break;
+         }
+         
+         Int_t nem = Exception::getNEmessg();
+         if (nem > 0) {
+             n_errors++;
+             TString emsg;
+             for (Int_t j(0); j<nem; j++) {
+                  emsg += Exception::getEmessg(j); 
+                  if (j != nem-1) emsg += "/";
+             }
+             Exception::clearEmessg();
+            
+             fKFres->SetErrorFlag(n,1);
+             fKFres->SetErrorMessage(n,emsg);
+             
+             if (fVerboseLevel > 2) {
+                 cout << "-W- <SpdIdealV0Finder::Exec> Fitter errors: " << emsg << endl; 
+             }
+         }
+  
+         if (!is_fitted) { 
+             not_fitted++; 
+             mcMom = itrack->GetStartMomentum();
+             fKFres->SetPmc(n,mcMom);
+             delete track; 
+             continue; 
+         }
+        
+         status = (KalmanFitStatus*)track->getFitStatus();
+  
+         if (status) {
+
+             is_fitted = status->isFitted();
+             fKFres->SetIsFitted(n,is_fitted);
+             
+             fKFres->SetMaterialEffects(n,material_effects);
+             fKFres->SetNFailedHits(n,status->getNFailedPoints()); 
+             fKFres->SetConvergency(n,0);
+             if (status->isFitConvergedPartially()) fKFres->SetConvergency(n,-1);
+             if (status->isFitConvergedFully()) fKFres->SetConvergency(n,1);   
+         }
+         else {
+             
+             is_fitted = false;
+             fKFres->SetIsFitted(n,is_fitted);
+             
+             fKFres->SetMaterialEffects(n,material_effects);
+             fKFres->SetConvergency(n,0);
+             
+             fKFres->AddErrorMessage(n,"Unknown_error:_no_fit_status");
+             
+             if (!(nem > 0)) n_errors++;
+ 
+             if (fVerboseLevel > 2) {
+                 cout << "-W- <SpdIdealV0Finder::Exec> Fitter errors: " << fKFres->GetErrorMessage(n) << endl;
+             }
+         }
+     
+         if (fVerboseLevel > 3) {
+             cout << " >>>>>>>  <SpdIdealV0Finder::Exec> track (finish): " << i << " is fitted: " << is_fitted << endl;
+         }
+        
+         if (!is_fitted) { 
+             not_fitted++; 
+             mcMom = itrack->GetStartMomentum();
+             fKFres->SetPmc(n,mcMom);
+             fKFres->AddErrorMessage(n,"not_fitted_track");
+             delete track; 
+             continue; 
+         }
+ 
+         if (fKFres->GetConvergency(n)) nconv_tracks++;
+        
+         mcMom  = itrack->GetStartMomentum();
+         
+         track->checkConsistency();
+         
+         // let's try to get averaged final state
+         try {
+             recMom = track->getFittedState().getMom();
+         }
+         catch (Exception& e) {
+             is_fitted = false;
+         }
+        
+         // ill-conditioned covariance matrix (KalmanFitterInfo::calcAverageState)
+         if (!is_fitted) {
+             fKFres->SetIsFitted(n,is_fitted);
+             not_fitted++; 
+             fKFres->SetPmc(n,mcMom);
+             fKFres->AddErrorMessage(n,"ill-conditioned_cov._matrix_in_the_final_state");
+             delete track; 
+             continue; 
+         }
+         
+         if (fVerboseLevel > 3) 
+           {
+//             cout << " >>>>>>>>>  <SpdIdealV0Finder::Exec> (finish 1): track = " 
+             cout << " track = " 
+                  << i << " / event: " << fEvent->GetEventId() 
+                  << " mom (mc) = " << itrack->GetStartMomentumMag() 
+                  << " mom (rec) = "   << recMom.Mag() 
+                  << " pdg = " << itrack->GetPdgCode() << endl;
+         
+//             cout <<" >>>>>>>>>  <SpdIdealV0Finder::Exec> (finish 2): track = " << i  << " / event: " << fEvent->GetEventId() 
+//                  << " mom (rec) = " << recMom.Mag() << endl;
+         }
+        
+         // particle charge correction FIXME
+         if (mcMom.Dot(recMom) < 0) {
+             recMom *= -1; 
+             fKFres->AddErrorMessage(n,"Track_is_turned_out");
+             
+             ncorrd++;
+             if (!(nem > 0)) n_errors++;
+              
+             if (fVerboseLevel > 2) cout << "-W- <SpdIdealV0Finder::Exec> Fitter errors: " << fKFres->GetErrorMessage(n) << endl; 
+         }
+         
+         fKFres->SetSeedMomentum(n,fStartMomentum);
+         fKFres->SetSeedVertex(n,fStartVertex);
+         fKFres->SetSeedCov(n,fStartSeedCov); 
+         
+         fKFres->SetPmc(n,mcMom);
+         fKFres->SetPrec(n,recMom);
+         
+         if (fKFres->GetIsGood(n)) n_good++;
+         
+         Double_t chi2 = status->getForwardChi2();
+         Int_t ndf = status->getForwardNdf();
+      
+         if (chi2 > 0 && ndf > 0) {
+             fKFres->SetChi2(n,chi2);
+             fKFres->SetNDF(n,ndf);
+             if (TMath::Abs(chi2) > 1e-8) fKFres->SetChi2Delta(n,(chi2-status->getBackwardChi2())/chi2);
+         }
+         
+//         if (fVerboseLevel > 1) 
+         if (fVerboseLevel > 3) 
+         {
+             cout << " >>>>>>>  <SpdIdealV0Finder::Exec> Fitted tracks (nice/total): " 
+                  << n_good << "/" << ntotal_tracks << " = " << 0.01*Int_t(10000.*(1-n_good/Double_t(ntotal_tracks))) << " % "  
+                  << " (" << ncorrd << ") " 
+                  << " n/fitted: " << not_fitted 
+                  << "; n/converged: " << ntotal_tracks-nconv_tracks
+                  << "; errors: " << n_errors 
+                  << "; chi2/NDF: " << status->getForwardChi2() << "/" << status->getForwardNdf() 
+                  << " => " << fKFres->GetChi2toNDF(n) << ", d(chi2) = " << fKFres->GetChi2Delta(n) << endl;
+         }
+         
+         track->setMcTrackId(n); // ATTENTION here n is NOT mc-track id (mc-track id = itrack->GetTrackId())
+         
+         fTracks->Add(new SpdGFTrackW(track,n));
+    }
+    
+    Exception::setEmessgflag(false);
+    
+    if (fVerboseLevel > 2) cout << "\n >>>>>>> VERTEX RECONSTRUCTION " << endl;
+    
+    //return;
+  
+    // Interaction vertex
+    
+    TVector3 v_mc = fEvent->GetVertex();
+    TVector3 v_rec;
+
+    if (fVertexFitMethod > 0) FindVertex(v_rec); 
+    
+    fKFres->SetVertex(v_mc,v_rec);
+
+    NTracks = fTracks->GetEntriesFast();
+    SpdGFTrackW* t;
+     
+    for (Int_t i(0); i<NTracks; i++) 
+    {
+         t = (SpdGFTrackW*)fTracks->At(i);
+         n = t->GetDataID();
+    
+         MeasuredStateOnPlane s = t->GetTrack()->getFittedState(); 
+         TMatrixDSym cov = s.get6DCov().GetSub(3,5,3,5);
+        
+         fKFres->SetMomCov(n,cov);
+    }
+
+    FindDecayVertex();            // V0 vertex finder
+
+    //fKFres->PrintData();
+    //cout << "\n\n";
+    
+    fEvent->DeleteAll();
+}
+
+//________________________________________________________________________________________
+genfit::Track* SpdIdealV0Finder::BuildTrack(Int_t n, genfit::Track* track)
+{
+    if (track) {
+        delete track;
+        track = 0;
+    }
+    
+    TObjArray* tracks = fEvent->GetTracks(); 
+    if (!tracks) return 0;
+    
+    SpdIdealTrack* itrack = (SpdIdealTrack*)tracks->At(n);
+    if (!itrack) return 0;
+    
+    SpdIdealHit*  ihit;
+    TrackPoint*   point;
+ 
+    AbsTrackRep* rep = new RKTrackRep(itrack->GetPdgCode());
+ 
+    // (1) init start state
+ 
+    MeasuredStateOnPlane state(rep);
+    
+    // (2) init start position and momentum
+    
+         if (fStartSeedMethod == 1) DefineTrackStartVertexAndMom(itrack);
+    else if (fStartSeedMethod == 2) DefineTrackStartVertexAndMom(n,itrack);
+    else DefineTrackStartVertexAndMom(itrack);
+        
+    // (3) init covariance
+
+    DefineStartVertexCovariance();
+    
+    // set start values: state, position, momentum, covariance
+    
+    rep->setPosMomCov(state, fStartVertex, fStartMomentum, fStartSeedCov);
+    
+    // --------- create track --------- 
+    
+    TVectorD    seedState(6);
+    TMatrixDSym seedCov(6);
+    
+    rep->get6DStateCov(state, seedState, seedCov);
+
+    track = new Track(rep, seedState, seedCov);
+
+    // add hits to the track  
+     
+    Int_t NTrackHits = itrack->GetNHits();
+          
+    for (Int_t j(0); j<NTrackHits; j++) {
+    
+         ihit = (SpdIdealHit*)itrack->GetHit(j);
+         vector<AbsMeasurement*> measurements = fMeasCreator->CreateHit(ihit,GetHitRepresentation(ihit->GetDetId()));
+         point = new TrackPoint(measurements,track);
+         track->insertPoint(point);
+    }
+    
+    return track;
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::SetHitRepresentation(Int_t DetId, GFMeasurementType GFhitType)
+{
+  fHitRepresentation[DetId] = GFhitType;
+  
+//   for (auto& it1 : fHitRepresentation) {
+//        cout << "Size: " << fHitRepresentation.size() 
+//             << "  Detector/Hit: " << it1.first << " " << it1.second << endl;
+//   }
+}
+
+//________________________________________________________________________________________
+GFMeasurementType SpdIdealV0Finder::GetHitRepresentation(Int_t DetId) const
+{
+  auto it = fHitRepresentation.find(DetId);
+  return (it != fHitRepresentation.end()) ? GFMeasurementType(it->second) : pkSpacepoint;
+}
+ 
+//________________________________________________________________________________________
+void SpdIdealV0Finder::DefineTrackStartVertexAndMom(const SpdIdealTrack* track)
+{
+    fStartVertex = track->GetPrimVertex();
+    fStartMomentum = track->GetStartMomentum();
+     
+    fStartMomentum.SetMag(fSeedMomentum);
+    
+    if (!fSmearSeedValues) return;
+             
+    fStartVertex.SetX(gRandom->Uniform(fStartVertex.X()-fSmearingVertexDelta,fStartVertex.X()+fSmearingVertexDelta)); // cm
+    fStartVertex.SetY(gRandom->Uniform(fStartVertex.Y()-fSmearingVertexDelta,fStartVertex.X()+fSmearingVertexDelta)); // cm
+    fStartVertex.SetZ(gRandom->Uniform(fStartVertex.Z()-fSmearingVertexDelta,fStartVertex.X()+fSmearingVertexDelta)); // cm 
+
+    Double_t theta = gRandom->Gaus(fStartMomentum.Theta(),fSmearingAngleDelta*TMath::DegToRad());
+    Double_t phi = gRandom->Gaus(fStartMomentum.Phi(),fSmearingAngleDelta*TMath::DegToRad());
+    
+    fStartMomentum.SetMagThetaPhi(gRandom->Uniform(fSeedMomentum-fSmearingMomDelta,fSeedMomentum+fSmearingMomDelta),theta,phi);
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::DefineTrackStartVertexAndMom(const Int_t ntrack, const SpdIdealTrack* track) 
+{
+    SpdIdealDataInfo* info = fEvent->FindDataInfo(kSpdIts);
+    
+    Int_t np(0);
+    if (info) np = info->GetTrackHits(ntrack);
+        
+    if (np < 1) cout << "-W- <SpdIdealD0Finder::TrackStartVertexAndMom> Its points (data): " << np << endl;
+    
+    TObjArray* hits = track->GetHits();
+    Int_t nhits = hits->GetEntriesFast();
+    SpdIdealHit* xhit;
+    SpdIdealSpacepointHit* hit;
+    
+    Long_t id;
+      
+    std::vector<TVector3> points;
+    if (np > 0) points.reserve(np);
+    
+    Int_t na = nhits;
+    if (fNPointsVertexUse > 0 && fNPointsVertexUse < nhits) na = fNPointsVertexUse;
+    
+    Int_t npx(0), nerr(0);
+    for (Int_t i(0); i<na; i++) {
+         xhit = (SpdIdealHit*)hits->At(i);
+         id = xhit->GetDetId(0);
+         if (id != kSpdIts) continue;
+         hit = static_cast<SpdIdealSpacepointHit*>(xhit);
+         if (!hit) continue;
+         if (++npx > np) nerr = 1;
+         points.push_back(hit->GetHit()); 
+    }
+    
+    TVector3 p1(0,0,0), n1(0,0,1);
+    TVector3 p2 = points[0], n2;
+    
+    if (npx == 1) n2 = points[0];
+    else {
+        TVector3 nn;
+        for (Int_t i(0); i<npx-1; i++) {
+             p2 += points[i+1];
+             for (Int_t j = i+1; j<npx; j++) {
+                  nn = points[j]-points[i];
+                  nn.SetMag(1);
+                  n2 += nn;
+             }
+        }
+        p2 *= 1./npx;
+    }
+    
+    n2.SetMag(1);
+    
+    Double_t theta = n2.Theta();   
+    Double_t phi = points[0].Phi();     
+    
+    if (fSmearSeedValues) {
+        Double_t mmag = gRandom->Uniform(fSeedMomentum-fSmearingMomDelta,fSeedMomentum+fSmearingMomDelta);
+        fStartMomentum.SetMagThetaPhi(mmag,theta,phi);
+    }
+    else fStartMomentum.SetMagThetaPhi(fSeedMomentum,theta,phi);
+    
+    if (npx < 2) {
+        fStartVertex.SetXYZ(0,0,0);
+    }
+    else {
+        
+        fStartVertex = p2;
+        
+        Double_t c = n1.Dot(n2);
+        Double_t cc = 1.-c*c;
+
+        if (cc < 1.e-12) {
+            cout << "-W- <SpdIdealV0Finder::TrackStartVertexAndMom> Vertex is very far from origin: " << endl;
+            (p2.Z() < 0) ? fStartVertex.SetXYZ(0,0,1.e9) : fStartVertex.SetXYZ(0,0,-1.e9);
+            return;
+        }
+        
+        TVector3 p0 = p2-p1;
+        Double_t f = (c*p0.Dot(n1)-p0.Dot(n2))/cc;
+        
+        fStartVertex += f*n2;
+        
+        fStartVertex.SetX(0);
+        fStartVertex.SetY(0);
+    }
+    
+//     cout << "\t-I- <SpdIdealKalmanFitter::TrackStartVertexAndMom>"
+//          << " points: " << npx << "/" << np << ", warnings: " << nerr 
+//          << "; theta: " << track->GetStartMomentum().Theta()*TMath::RadToDeg() << " -> " << theta*TMath::RadToDeg()    
+//          << ", phi: "  << track->GetStartMomentum().Phi()*TMath::RadToDeg() << " -> "  << phi*TMath::RadToDeg() 
+//          << ", v(z): "  << track->GetPrimVertex().Z() << " -> "  << fStartVertex.Z() << endl; 
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::DefineStartVertexCovariance() 
+{    
+    fStartSeedCov.Clear();
+    fStartSeedCov.ResizeTo(6,6);
+    
+    for (Int_t i(0); i < 3; i++) fStartSeedCov(i,i) = 10.;  // position
+    for (Int_t i(3); i < 6; i++) fStartSeedCov(i,i) = 100.; // momentum
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::FindVertex(TVector3& vertex)
+{
+    vertex.SetXYZ(0,0,0);
+    
+    //---------------------------------------
+    // vertex fit program for CBM experiment
+    //---------------------------------------
+    
+    if (!fTracks) return;
+    
+    // Iterative fit of the vertex (CDM)
+    //----------------------------------
+    const Double_t CutChi2 = 3.5*3.5;
+    const Int_t MaxIter = 3;
+
+    // Vertex state vector and covariance matrix
+    //-------------------------------------------
+    Double_t r[3] = {0,0,0}; 
+    Double_t C[6];
+    
+    for(Int_t i = 0; i<6; i++) C[i] = 0;
+    C[0] = C[2] = 5.;
+    C[5] = 0.25;
+  
+    // Chi^2 & NDF
+    //-------------------------------------------
+    Int_t    refNDF;
+    Double_t refChi2;
+
+    // Iterative fit of the vertex
+    //-----------------------------
+    for (Int_t iteration = 0; iteration < MaxIter; ++iteration)
+    {
+       // Store the vertex from the previous iteration
+       //---------------------------------------------
+       Double_t r0[3], C0[6];
+       for( Int_t i=0; i<3; i++ ) r0[i] = r[i];
+       for( Int_t i=0; i<6; i++ ) C0[i] = C[i];
+
+       // Initialize the vertex covariance, Chi^2 & NDF
+       //-----------------------------------------------
+       C[0] = 100.;
+       C[1] =   0.; C[2] = 100.;
+       C[3] =   0.; C[4] =   0.; C[5] = 100.;
+
+       refNDF = -3;
+       refChi2 = 0.0;
+      
+       Int_t NTracks = fTracks->GetEntriesFast();
+
+       SpdGFTrackW* wtr;
+       Track* track;
+       Int_t  ntrack;
+       
+       TMatrixDSym vCov;
+       TVector3 vPos, vMom;
+        
+       // start loop over tracks
+       //-----------------------
+   
+       for (Int_t itrk(0); itrk < NTracks; ++itrk) {
+           
+            wtr = (SpdGFTrackW*)fTracks->At(itrk);
+            
+            track  = wtr->GetTrack();
+            ntrack = wtr->GetDataID();
+            
+            if (!fKFres->GetIsFitted(ntrack)) continue;        // FIXME
+            if (fKFres->GetConvergency(ntrack) != 1) continue; // FIXME
+            
+            MeasuredStateOnPlane stateF = track->getFittedState(); // copy
+        
+            Double_t mTheta = stateF.getDir().Theta();
+            
+            // skip tracks with theta 90+-fVertexFitAngleCut [degrees]
+            if (fabs(mTheta-TMath::PiOver2()) < fVertexFitAngleCut*TMath::DegToRad()) continue; // FIXME
+
+            TVector3 planePos(0.0, 0.0, r0[2]);
+            TVector3 planeDir(0.0, 0.0, 1.0);
+  
+            SharedPlanePtr plane(new DetPlane(planePos, planeDir));
+            
+            stateF.getPosMomCov(vPos, vMom, vCov);    // in global, before extrapolation 
+
+            // ATTENTION --- track extrapolation --- ATTENTION
+            try 
+            { 
+              stateF.extrapolateToPlane(plane); 
+            }
+            catch(Exception& e)
+            { 
+              fKFres->SetPrec(ntrack,vMom);
+              continue;
+            }
+                      
+            stateF.getPosMomCov(vPos, vMom, vCov);    // in global, after extrapolation  
+
+            if (iteration == MaxIter-1) { 
+                
+                // Update track momentum and its covariance
+                fKFres->SetPrec(ntrack,vMom);
+                 
+                // cout << "TRACK: " << itrk << endl;
+                // cout << "POS:   " << vPos.X() << " " << vPos.Y() << " " << vPos.Z() << endl;
+                // cout << "MOM:   " << vMom.X() << " " << vMom.Y() << " " << vMom.Z() << endl;
+                // cout << "pt =   " << vMom.Perp() << " p = " << vMom.Mag() << endl;
+
+            }
+            
+            TVectorD& state   = stateF.getState();    // on plane, 5
+            TMatrixDSym& covV = stateF.getCov();      // on plane, 5x5 
+            
+            TVector3 vMU(-state[1], -state[2], 1.0);
+
+            Double_t vV[10] = { covV[3][3], covV[3][4], covV[4][4],
+                                covV[1][3], covV[1][4], covV[1][1],
+                                covV[2][3], covV[2][4], covV[2][1],
+                                covV[2][2] };
+
+            Double_t a = 0, b = 0;
+            {
+               Double_t zeta[2] = { r0[0]-vPos.X(), r0[1]-vPos.Y() };
+
+               // Check the track Chi^2 deviation from the r0 vertex estimate    
+               //-------------------------------------------------------------
+               Double_t S[3] = { (C0[2]+vV[2]), -(C0[1]+vV[1]), (C0[0]+vV[0]) };
+               Double_t s = S[2]*S[0] - S[1]*S[1];
+               Double_t chi2 = zeta[0]*zeta[0]*S[0] + 2*zeta[0]*zeta[1]*S[1] 
+                                                  +   zeta[1]*zeta[1]*S[2];
+               // std::cout << " chi2 = " << chi2 << std::endl;
+
+               if ( chi2 > s*CutChi2 ) continue;
+
+               // Fit of the vertex track slopes (a,b) to the r0 vertex estimate
+               //-----------------------------------------------------------------
+               s = vV[0]*vV[2] - vV[1]*vV[1];
+               
+               if ( s < 1.E-20 ) continue;
+               
+               s = 1./s;
+            
+               a = vMU.X() + s*( ( vV[3]*vV[2] - vV[4]*vV[1])*zeta[0]
+                           +     (-vV[3]*vV[1] + vV[4]*vV[0])*zeta[1] );       
+
+               b = vMU.Y() + s*( ( vV[6]*vV[2] - vV[7]*vV[1])*zeta[0]
+                           +     (-vV[6]*vV[1] + vV[7]*vV[0])*zeta[1] );       
+            }        
+
+            // std::cout << " a = " << a << " b = " << b << std::endl; 
+
+            // Update the vertex (r,C) with the track estimate (m,V) :
+            //--------------------------------------------------------
+
+            // Linearized measurement matrix H = { { 1, 0, -a}, { 0, 1, -b} };
+            //-----------------------------------------------------------------
+
+            // Residual zeta (measured - estimated)
+            //--------------------------------------
+            Double_t zeta[2] = { vPos.X() - ( r[0] - a*(r[2]-r0[2]) ),
+                                 vPos.Y() - ( r[1] - b*(r[2]-r0[2]) ) };
+
+            // std::cout << " zeta[0] = " << zeta[0] << " zeta[1] = " << zeta[1]
+            //           << " zeta[2] = " << zeta[2] << std::endl;
+
+            // CHt = CH’
+            //----------
+            Double_t CHt[3][2] = { { C[0] - a*C[3], C[1] - b*C[3]},
+                                   { C[1] - a*C[4], C[2] - b*C[4]},
+                                   { C[3] - a*C[5], C[4] - b*C[5]} };
+
+            // S = (H*C*H’ + V )^{-1}
+            //-------------------------
+            Double_t S[3] = { vV[0] + CHt[0][0] - a*CHt[2][0],
+                              vV[1] + CHt[1][0] - b*CHt[2][0],
+                              vV[2] + CHt[1][1] - b*CHt[2][1] };
+
+            // Invert S
+            //----------
+            { 
+               Double_t s = S[0]*S[2] - S[1]*S[1];
+               if (s < 1.E-20) continue;
+               s = 1./s;
+               Double_t S0 = S[0];
+               S[0] = s*S[2];
+               S[1] = -s*S[1];
+               S[2] = s*S0;
+            }
+
+            // Calculate Chi^2
+            //-----------------
+            refChi2 += zeta[0]*zeta[0]*S[0] + 2*zeta[0]*zeta[1]*S[1]
+                                            +   zeta[1]*zeta[1]*S[2];
+            refNDF += 2; 
+
+            // std::cout << " refChi2 = " << refChi2 << " refNDF = " << refNDF << std::endl; 
+
+            // Kalman gain K = CH’*S
+            //------------------------
+            Double_t K[3][2];
+            for (Int_t i(0); i<3; ++i) { K[i][0] = CHt[i][0]*S[0] + CHt[i][1]*S[1] ; 
+                                         K[i][1] = CHt[i][0]*S[1] + CHt[i][1]*S[2] ; }
+
+            // New estimation of the vertex position r += K*zeta 
+            //---------------------------------------------------
+            for (Int_t i(0); i<3; ++i) r[i] += K[i][0]*zeta[0] + K[i][1]*zeta[1];
+
+            // std::cout << " trk = " << itrk << " r[0] = " << r[0] << " r[1] = " << r[1]
+            //           << " r[2] = " << r[2] << std::endl;
+
+            // New covariance matrix C -= K*(CH’)’
+            //--------------------------------------
+            C[0] -= K[0][0]*CHt[0][0] + K[0][1]*CHt[0][1];
+            C[1] -= K[1][0]*CHt[0][0] + K[1][1]*CHt[0][1];
+            C[2] -= K[1][0]*CHt[1][0] + K[1][1]*CHt[1][1];
+            C[3] -= K[2][0]*CHt[0][0] + K[2][1]*CHt[0][1];
+            C[4] -= K[2][0]*CHt[1][0] + K[2][1]*CHt[1][1];
+            C[5] -= K[2][0]*CHt[2][0] + K[2][1]*CHt[2][1];
+
+       }  // end loop over tracks
+
+    } // end loop over iteration  
+
+    vertex.SetX(r[0]);
+    vertex.SetY(r[1]);
+    vertex.SetZ(r[2]);
+    
+    //cout << "\nrefChi2 = " << refChi2 << " refNDF = " << refNDF << endl; 
+    
+    TMatrixDSym VC(3);
+    VC(0,0) = C[0]; VC(0,1) = C[1]; VC(0,2) = C[3];
+    VC(1,0) = C[1]; VC(1,1) = C[2]; VC(1,2) = C[4]; 
+    VC(2,0) = C[3]; VC(2,1) = C[4]; VC(2,2) = C[5];
+    
+    if (refNDF > 0) {
+        fKFres->SetVertexChi2overNDF(refChi2/refNDF); 
+        fKFres->SetVertexRECcov(VC);
+    }
+    else fKFres->ClearVertexData();
+    
+    //VC.Print();
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::FindDecayVertex()
+{
+    // set initial output values
+    //---------------------------
+    v0_mass    = -99.;
+    v0_massErr = -99.;
+    v0_pp      = -99.;
+    v0_energy  = -99.;
+    v0_eta     = -99.;
+    v0_theta   = -99.;
+    v0_phi     = -99.;
+    v0_length  = -99.;
+
+    Int_t nTracks = fTracks->GetEntriesFast();    // number of tracks     
+
+    // set primary vertex (reconstructed or simulated)
+    //-------------------------------------------------
+    TVector3    recVtx = fKFres->GetVertexRec();      // reconstructed PV
+    TMatrixDSym recCov = fKFres->GetVertexRECcov();
+
+    TVector3 pvVtx( fEvent->GetVertex() );           // simulated PV
+    if (fUsedTypeOfPV > 1) pvVtx = recVtx;           // set PV vertex   
+
+    // set field
+    //-----------
+    float fieldBz = (float)fField->GetField()->GetBz(pvVtx.X(), pvVtx.Y(), pvVtx.Z());
+    KFParticle::SetField(fieldBz);                 
+
+    // track parameters
+    //----------------
+    SpdGFTrackW* wtr;
+    Track* track;
+    Int_t  ntrack;
+
+    TVector3 trkPos, trkMom;
+    TMatrixDSym trkCov;
+
+    fKFparticles.clear();
+    for (Int_t itrk(0); itrk < nTracks; ++itrk)   // loop over tracks
+    {
+       wtr = (SpdGFTrackW*)fTracks->At(itrk);
+            
+       track  = wtr->GetTrack();
+       ntrack = wtr->GetDataID();
+            
+       if (!fKFres->GetIsFitted(ntrack))         continue;  // FIXME
+       if ( fKFres->GetConvergency(ntrack) != 1) continue;  // FIXME
+
+       int pdgTrk    = (int)fKFres->GetTrackPdg(ntrack);
+       TParticlePDG* part = TDatabasePDG::Instance()->GetParticle(pdgTrk);
+
+       // check only first or second daugter particle types
+       //---------------------------------------------------
+       if ( fabs(pdgTrk) != fFirstDaughter && fabs(pdgTrk) != fSecondDaughter) continue;
+
+       MeasuredStateOnPlane stateF = track->getFittedState(); // copy
+       stateF.getPosMomCov(trkPos, trkMom, trkCov);           // get track parameters at first  
+                                                              // hit position
+       // extrapolate to primary vertex (sim or rec)
+       //-------------------------------------------
+       try 
+       { 
+         stateF.extrapolateToPoint(pvVtx); 
+       }
+       catch(Exception& e)
+       {
+         cout << " bad track extrapolation " << endl; 
+         continue;
+       }
+
+       TMatrixDSym pvCov;
+       TVector3 pvPos, pvMom;
+       stateF.getPosMomCov(pvPos, pvMom, pvCov);    // in global, after extrapolation 
+
+       // track deviation from the  primary vertex
+       //-------------------------------------------
+
+       // track Cov matrix in DCA point
+       //-------------------------------
+       float mS[6] = { (float)pvCov(0,0)+(float)recCov(0,0), 
+                       (float)pvCov(1,0)+(float)recCov(1,0), (float)pvCov(1,1)+(float)recCov(1,1),
+                       (float)pvCov(2,0)+(float)recCov(2,0), (float)pvCov(2,1)+(float)recCov(2,1), 
+                                                             (float)pvCov(2,2)+(float)recCov(2,2) }; 
+       // deviation track from PV
+       //------------------------
+       float zeta[3] = { (float)(pvPos.X()-pvVtx.X()) , 
+                         (float)(pvPos.Y()-pvVtx.Y()) , 
+                         (float)(pvPos.Z()-pvVtx.Z()) };
+
+       InvertCholetsky3(mS);         // invert matrix  C => C^{-1}
+
+       // chi2 = (R_trk - R_pv)^{T} * (C_trk + C_pv)^{-1} * (R_trk - R_pv);
+       //-------------------------------------------------------------------
+       float fChi2 = (mS[0]*zeta[0] + mS[1]*zeta[1] + mS[3]*zeta[2]) * zeta[0]
+                   + (mS[1]*zeta[0] + mS[2]*zeta[1] + mS[4]*zeta[2]) * zeta[1]
+                   + (mS[3]*zeta[0] + mS[4]*zeta[1] + mS[5]*zeta[2]) * zeta[2];
+
+       if (fChi2 < fMinChi2PV) continue;                // check min topo Chi2
+
+       // set KF track parameters
+       //------------------------ 
+       KFPTrack kfTrack;
+       kfTrack.SetParameters( trkPos.X(), trkPos.Y(), trkPos.Z(), 
+                              trkMom.X(), trkMom.Y(), trkMom.Z() );
+
+       Double_t C[21] = { trkCov(0,0),
+                          trkCov(1,0),trkCov(1,1),
+                          trkCov(2,0),trkCov(2,1),trkCov(2,2),
+                          trkCov(3,0),trkCov(3,1),trkCov(3,2),trkCov(3,3),
+                          trkCov(4,0),trkCov(4,1),trkCov(4,2),trkCov(4,3),trkCov(4,4),
+                          trkCov(5,0),trkCov(5,1),trkCov(5,2),trkCov(5,3),trkCov(5,4),trkCov(5,5) };
+
+       kfTrack.SetCovarianceMatrix(C);
+
+       kfTrack.SetNDF( track->getFitStatus()->getNdf() );
+       kfTrack.SetChi2(track->getFitStatus()->getChi2());
+       kfTrack.SetCharge( (part->Charge())/3);
+
+       KFParticle p1(kfTrack, pdgTrk);        
+       fKFparticles.push_back(p1);
+    }
+
+    // check vector with daughter candidates
+    //--------------------------------------
+    if (fKFparticles.size() >= 2)                //  number of KF particles >= 2
+    {
+       for (int i=0; i<fKFparticles.size()-1; ++i)
+       {
+          for (int j=i+1; j<fKFparticles.size(); ++j)
+          { 
+             if (fKFparticles[i].GetQ()*fKFparticles[j].GetQ() > 0) continue;  
+
+             if ( ( fabs(fKFparticles[i].GetPDG())==fFirstDaughter    && 
+                    fabs(fKFparticles[j].GetPDG())!=fSecondDaughter ) ||
+                  ( fabs(fKFparticles[i].GetPDG())==fSecondDaughter   && 
+                    fabs(fKFparticles[j].GetPDG())!=fFirstDaughter )   ) continue;
+
+             // distance between two daughter particles
+             //----------------------------------------
+             float dist2part = fKFparticles[i].GetDistanceFromParticle(fKFparticles[j]);
+
+             if (dist2part > fMinDist) continue;      // check distance
+
+             // parameter 1 - array of the daughter particles
+             // parameter 2 - number of the daughter particles
+             // parameter 3 - vertex (it should be the object of the KFParticle class)
+
+              KFPVertex vert;
+              vert.SetXYZ( pvVtx.X(), pvVtx.Y(), pvVtx.Z() );
+              vert.SetCovarianceMatrix( (float)recCov(0,0),
+                                        (float)recCov(1,0), (float)recCov(1,1),
+                                        (float)recCov(2,0), (float)recCov(2,1), (float)recCov(2,2) ); 
+              vert.SetNContributors(nTracks-2);
+              float vtxChi2 = (nTracks-2)*fKFres->GetVertexChi2overNDF();
+              vert.SetChi2(vtxChi2);
+              KFParticle p0(vert);            // set primary vertex as KFParticle
+
+              const KFParticle pVertex = p0;
+              int   NDaughters = 2;
+              const KFParticle *vDaughters[2] = { &fKFparticles[i], &fKFparticles[j] };
+
+              // construct deacay V0 particle without PV and mass constrain
+              //------------------------------------------------------------
+              KFParticle K0_1;
+              K0_1.SetProductionVertex(pVertex);
+              K0_1.Construct(vDaughters,NDaughters,0,-1);
+
+              TVector3 v1;
+              v1.SetXYZ(K0_1.GetX(), K0_1.GetY(), K0_1.GetZ());  // decay vertex
+
+              float mass1    = K0_1.GetMass();
+              float massErr1 = K0_1.GetErrMass();
+              float mom1     = K0_1.GetP();
+              float ene1     = K0_1.GetE();
+              float eta1     = K0_1.GetRapidity();
+              float theta1   = K0_1.GetTheta();
+              float phi1     = K0_1.GetPhi();
+              float length1  = (v1-pvVtx).Mag();
+
+              // construct decay V0 particle with PV constrain
+              //-----------------------------------------------
+              KFParticle K0_2;
+              K0_2.SetProductionVertex(pVertex);
+              K0_2.Construct(vDaughters,NDaughters,&pVertex,-1);
+
+              v0_mass    = K0_2.GetMass();
+              v0_massErr = K0_2.GetErrMass();
+              v0_pp      = K0_2.GetP();
+              v0_energy  = K0_2.GetE();
+              v0_eta     = K0_2.GetRapidity();
+              v0_theta   = K0_2.GetTheta();
+              v0_phi     = K0_2.GetPhi();
+              v0_length  = K0_2.GetDecayLength();
+
+              if ( fConstrainToPV < 1)     // without PV constrain
+              {
+                 v0_mass    = mass1;
+                 v0_massErr = massErr1;
+                 v0_pp      = mom1;
+                 v0_energy  = ene1;
+                 v0_eta     = eta1;
+                 v0_theta   = theta1;
+                 v0_phi     = phi1;
+                 v0_length  = length1;
+              } 
+     
+              // check V0 mass window
+              //----------------------
+              if( v0_mass < fMinMass || v0_mass > fMaxMass) continue;  // mass window
+
+              fV0tree->Fill();
+          }
+       } 
+    }
+
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::InvertCholetsky3(float a[6])
+{
+  /* Inverts symmetric 3x3 matrix a using modified Choletsky decomposition. 
+     The result is stored to the same matrix a.
+      param[in,out] a - 3x3 symmetric matrix
+  */
+  
+  float d[3], uud, u[3][3];
+  for(int i=0; i<3; i++) 
+  {
+    d[i] = 0;
+    for(int j=0; j<3; j++) u[i][j] = 0;
+  }
+
+  for(int i=0; i<3 ; i++)
+  {
+    uud = 0;
+    for(int j=0; j<i; j++) uud += u[j][i]*u[j][i]*d[j];
+
+    uud = a[i*(i+3)/2] - uud;
+
+    if(fabs(uud)<1.e-12f) uud = 1.e-12f;
+
+    d[i] = uud/fabs(uud);
+    u[i][i] = sqrt(fabs(uud));
+
+    for(int j=i+1; j<3; j++) 
+    {
+      uud = 0;
+      for(int k=0; k<i; k++) uud += u[k][i]*u[k][j]*d[k];
+
+      uud = a[j*(j+1)/2+i] - uud;
+      u[i][j] = d[i]/u[i][i]*uud;
+    }
+  }
+
+  float u1[3];
+  for(int i=0; i<3; i++)
+  {
+    u1[i]   = u[i][i];
+    u[i][i] = 1/u[i][i];
+  }
+
+  for(int i=0; i<2; i++)
+  {
+    u[i][i+1] = - u[i][i+1]*u[i][i]*u[i+1][i+1];
+  }
+
+  for(int i=0; i<1; i++)
+  {
+    u[i][i+2] = u[i][i+1]*u1[i+1]*u[i+1][i+2]-u[i][i+2]*u[i][i]*u[i+2][i+2];
+  }
+
+  for(int i=0; i<3; i++) a[i+3] = u[i][2]*u[2][2]*d[2];
+
+  for(int i=0; i<2; i++) a[i+1] = u[i][1]*u[1][1]*d[1] + u[i][2]*u[1][2]*d[2];
+
+  a[0] = u[0][0]*u[0][0]*d[0] + u[0][1]*u[0][1]*d[1] + u[0][2]*u[0][2]*d[2];
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::Finish() 
+{
+    cout << "-I- <SpdIdealV0Finder::Finish>" << endl;
+
+    CloseOutputV0file();
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::FillParametersIn(SpdBaseParSet* params)
+{
+    if (!params) return;
+    
+    params->SetParameter("IdealKalmanFitter/MaterialsOpt",fMaterialsOpt);
+    
+    params->SetParameter("IdealKalmanFitter/SeedMomentum",fSeedMomentum);
+    params->SetParameter("IdealKalmanFitter/VertexFitMethod",fVertexFitMethod);
+    params->SetParameter("IdealKalmanFitter/VertexFitAngleCut",fVertexFitAngleCut);
+    
+    Int_t n = fHitRepresentation.size();
+
+    params->SetParameter("IdealKalmanFitter/NHRepresentations",n);
+    
+    if (n > 0) {
+        Int_t i(0);
+        for (auto& it : fHitRepresentation) {
+             params->SetParameter(Form("IdealKalmanFitter/HitRepDetId[%d]",i),it.first);
+             params->SetParameter(Form("IdealKalmanFitter/HitRepDet[%d]",i),it.second);
+             i++;
+        }  
+    }
+
+    params->SetParameter("IdealKalmanFitter/fStartSeedMethod",fStartSeedMethod);
+    params->SetParameter("IdealKalmanFitter/fSmearSeedValues",fSmearSeedValues);
+    
+    if (fSmearSeedValues) {
+        params->SetParameter("IdealKalmanFitter/fSmearingMomDelta",fSmearingMomDelta);
+        if (fStartSeedMethod == 2) {
+            params->SetParameter("IdealKalmanFitter/fNPointsVertexUse",fNPointsVertexUse);
+        }
+        else 
+        {
+            params->SetParameter("IdealKalmanFitter/fSmearingAngleDelta",fSmearingAngleDelta);
+            params->SetParameter("IdealKalmanFitter/fSmearingVertexDelta",fSmearingVertexDelta);
+        }
+    }
+    
+    params->SetParameter("IdealKalmanFitter/FitterOption",fFitterOption);
+    
+    params->SetParameter("IdealKalmanFitter/FitterMaxIterations",fFitterMaxIterations);
+    params->SetParameter("IdealKalmanFitter/FitterMaxTrials",fFitterMaxTrials);
+    
+    params->SetParameter("IdealKalmanFitter/StoreTracks",fStoreTracks);
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::LoadParametersFrom(SpdBaseParSet* params)
+{
+    if (!params) return;
+    
+    fHitRepresentation.clear();
+    
+    Int_t pi;
+    Double_t pd;
+    Bool_t pb;
+    
+    if (params->GetParameter("IdealKalmanFitter/MaterialsOpt",pi)) SetMaterialEffectsOption(pi);
+    
+    if (params->GetParameter("IdealKalmanFitter/SeedMomentum",pd)) SetSeedMomentum(pd);
+    if (params->GetParameter("IdealKalmanFitter/VertexFitMethod",pi)) SetVertexFindingMethod(pi);
+    if (params->GetParameter("IdealKalmanFitter/VertexFitAngleCut",pd)) SetVertexFindingAngleCut(pd);
+    
+    if (params->GetParameter("IdealKalmanFitter/NHRepresentations",pi)) {
+        if (pi > 0) {
+            Int_t pi2, pi3;
+            for (Int_t i(0); i<pi; i++) {
+                 params->GetParameter(Form("IdealKalmanFitter/HitRepDetId[%d]",i),pi2);
+                 params->GetParameter(Form("IdealKalmanFitter/HitRepDet[%d]",i),pi3);
+                 fHitRepresentation[pi2] = pi3;
+            }
+        }
+    }
+    
+    if (params->GetParameter("IdealKalmanFitter/fStartSeedMethod",pi)) SetStartSeedMethod(pi);
+    if (params->GetParameter("IdealKalmanFitter/fSmearSeedValues",pb)) SetSmearSeedValues(pb);
+    
+    if (fSmearSeedValues) {
+        if (params->GetParameter("IdealKalmanFitter/fSmearingMomDelta",pd)) SetSmearingMomDelta(pd);
+        if (fStartSeedMethod == 2) {
+            if (params->GetParameter("IdealKalmanFitter/fNPointsVertexUse",pi)) SetNPointsVertexUse(pi);
+        }
+        else {
+            if (params->GetParameter("IdealKalmanFitter/fSmearingAngleDelta",pd)) SetSmearingAngleDelta(pd);
+            if (params->GetParameter("IdealKalmanFitter/fSmearingVertexDelta",pd)) SetSmearingVertexDelta(pd);
+        }
+    }
+    
+    if (params->GetParameter("IdealKalmanFitter/FitterOption",pi)) SetFitterOption(pi);
+    
+    if (params->GetParameter("IdealKalmanFitter/FitterMaxIterations",pi)) SetFitterMaxIterations(pi);
+    if (params->GetParameter("IdealKalmanFitter/FitterMaxTrials",pi)) SetFitterMaxTrials(pi);
+      
+    if (params->GetParameter("IdealKalmanFitter/StoreTracks",pb)) SetStoreTracks(pb);
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::InitV0nTuple(TString name)
+{
+    fV0file = new TFile(name, "RECREATE");
+    fV0tree = new TTree("DecayV0Tree", "DecayV0Tree");
+
+    fV0tree->Branch("v0_mass",    &v0_mass,    "v0_mass/F"   );
+    fV0tree->Branch("v0_massErr", &v0_massErr, "v0_massErr/F");
+    fV0tree->Branch("v0_pp",      &v0_pp,      "v0_pp/F"     );
+    fV0tree->Branch("v0_energy",  &v0_energy,  "v0_energy/F" );
+    fV0tree->Branch("v0_eta",     &v0_eta,     "v0_eta/F"    );
+    fV0tree->Branch("v0_theta",   &v0_theta,   "v0_theta/F"  );
+    fV0tree->Branch("v0_phi",     &v0_phi,     "v0_phi/F"    );
+    fV0tree->Branch("v0_length",  &v0_length,  "v0_length/F" );
+}
+
+//________________________________________________________________________________________
+void SpdIdealV0Finder::CloseOutputV0file()
+{
+    fV0file->Write();
+    fV0file->Close();
+}
+
+
+
diff --git a/reco/SpdIdealV0Finder.h b/reco/SpdIdealV0Finder.h
new file mode 100644
index 0000000000000000000000000000000000000000..a39969177430589969138c7c1c27ba5898470809
--- /dev/null
+++ b/reco/SpdIdealV0Finder.h
@@ -0,0 +1,209 @@
+// $Id$
+// Author: vladimir andreevv   2020/08/29
+
+#ifndef __SPDIDEALV0FINDER_H__
+#define __SPDIDEALV0FINDER_H__
+
+#include <TString.h>
+#include "FairTask.h"
+#include "FairBaseParSet.h"
+#include "SpdFieldPar.h"
+#include "SpdGeoLoader.h"
+#include "SpdIdealTrack.h"
+#include "SpdBaseParSet.h"
+#include "SpdGFMeasurementCreator.h"
+#include "AbsKalmanFitter.h"
+
+// KFParticle
+#include "KFParticle.h"
+#include "KFPTrack.h"
+#include "KFPVertex.h"
+#include "KFParticleSIMD.h"
+
+#include <TTree.h>
+#include <TFile.h>
+
+//#include <map>
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdIdealV0Finder                                                           //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdGeoLoader;
+class SpdIdealTrackColl;
+class SpdKFSimpleRes;
+class SpdGFMeasurementCreator;
+class SpdGFMagneticField;
+
+class SpdIdealV0Finder: public FairTask  {
+
+public:
+
+    SpdIdealV0Finder();
+    virtual ~SpdIdealV0Finder();
+    
+    void SetTrackingGeoModules(Bool_t add_passives = kTRUE);
+    
+    void AddModule(TString module) { fGeoModules.push_back(module);  }
+    void AddModule(Int_t module)   { fGeoModules.push_back(Form("%d",module)); }
+    void ClearListOfGeoModules()   { fGeoModules.clear(); }
+    
+    virtual InitStatus Init();   
+    virtual void Exec(Option_t* opt);
+    virtual void Finish();
+    
+    void DeleteGeoLoader();
+    
+    /* SETTERS */
+    
+    void  SetVerboseLevel(Int_t level) { fVerboseLevel = level; } 
+    
+    void  SetMaterialEffectsOption(Int_t opt /*-1,0(default),1 */) { fMaterialsOpt = opt; }
+    
+    void  SetSeedMomentum(Double_t mom /* GeV/c */) { fSeedMomentum = fabs(mom); } 
+    void  SetHitRepresentation(Int_t DetId, GFMeasurementType GFhitType);
+    
+    void  SetVertexFindingMethod(Int_t method)            { fVertexFitMethod = method; } 
+    void  SetVertexFindingAngleCut(Double_t acut /*deg*/) { fVertexFitAngleCut = acut; }
+    
+    void  SetStartSeedMethod(Int_t method) { fStartSeedMethod = method; }
+    void  SetSmearSeedValues(Bool_t smear) { fSmearSeedValues = smear;  }
+    
+    void  SetSmearingAngleDelta(Double_t angle /*deg*/) { fSmearingAngleDelta = TMath::Abs(angle); }
+    void  SetSmearingVertexDelta(Double_t dpos /*cm*/)  { fSmearingVertexDelta = TMath::Abs(dpos); }
+    void  SetSmearingMomDelta(Double_t dp /*Gev/c*/)    { fSmearingMomDelta = TMath::Abs(dp); }
+    void  SetNPointsVertexUse(Int_t np /* < 1 = max */) { fNPointsVertexUse = np; }
+  
+    void  SetFitterOption(Int_t opt) { fFitterOption = opt; }
+  
+    void  SetFitterMaxIterations(Int_t niter) { fFitterMaxIterations = (niter > 2) ? niter : 4;  } 
+    void  SetFitterMaxTrials(Int_t ntrials) { fFitterMaxTrials = (ntrials > 1) ? ntrials : 1; } 
+  
+    void  SetStoreTracks(Bool_t store = true) { fStoreTracks = store; }
+    
+    void  FillParametersIn(SpdBaseParSet* params);
+    void  LoadParametersFrom(SpdBaseParSet* params);
+
+    /* V0 finder Setter */
+
+    void SetOutputFileName(TString m_outfile_name); 
+    void SetFirstDaughter(Int_t p)          { fFirstDaughter = p;  } 
+    void SetSecondDaughter(Int_t p)         { fSecondDaughter = p; } 
+    void SetUsedTypeOfPV(Int_t p)           { fUsedTypeOfPV = p;   } 
+    void SetConstrainToPV(Int_t p)          { fConstrainToPV = p;  } 
+    void SetMinTrackPVchi2(Double_t chi2)   { fMinChi2PV = chi2;   } 
+    void SetMinDistDaughter(Double_t dist)  { fMinDist = dist;     } 
+    void SetMinimumMass(Double_t m)         { fMinMass = m;        } 
+    void SetMaximumMass(Double_t m)         { fMaxMass = m;        } 
+
+private:
+    
+    SpdGFMagneticField*      fField;        //! Magnetic field
+    SpdGFMeasurementCreator* fMeasCreator;  //! GenFit measurements creator
+    genfit::AbsKalmanFitter* fFitter;       //! GenFit fitter
+    
+    /* methods */
+    
+    void LoadGeometry();
+    void LoadField();
+    void InitFitter();
+    
+    genfit::Track* BuildTrack(Int_t n, genfit::Track* track = 0);
+    
+    GFMeasurementType GetHitRepresentation(Int_t DetId) const;
+    
+    void           DefineTrackStartVertexAndMom(const SpdIdealTrack* track);
+    void           DefineTrackStartVertexAndMom(const Int_t ntrack, const SpdIdealTrack* track);
+    void           DefineStartVertexCovariance();
+    
+    void FindVertex(TVector3& vertex); 
+    
+    /* V0 finder */
+
+    void FindDecayVertex();                        // V0 vertex finder
+    void InvertCholetsky3(float a[6]);             // a => a^{-1}
+    void InitV0nTuple(TString name);               // V0 user nTuple 
+    void CloseOutputV0file();                      // V0 user nTuple 
+
+    /* Geometry */
+    Bool_t                   fOwnGeoLoader;        //! indicates geometry loader owning
+    SpdGeoLoader*            fGeoLoader;           //! SPD geometry
+    std::vector<TString>     fGeoModules;          //! geometry modules are to be built
+    
+    /* data memebers */ 
+     
+    SpdIdealTrackColl*       fEvent;               //! Input data 
+    SpdKFSimpleRes*          fKFres;               //! Output data 
+    TObjArray*               fTracks;              //! Output tracks
+    
+    SpdBaseParSet*           fParameters;
+
+    Int_t                    fVerboseLevel;
+        
+    /* FIT OPTIONS */
+
+    Int_t                    fMaterialsOpt;        // > 0 (+material effects, default), <=0 (no mat. effects)  
+        
+    // standard
+    Double_t                 fSeedMomentum;        // start track vertex momentum [GeV/c]
+    std::map<Int_t,Int_t>    fHitRepresentation;   // <Detector Id, GFMeasurementType>
+    
+    // advanced
+    Int_t                    fVertexFitMethod;     // <1 (no fit); 1 (default)
+    Double_t                 fVertexFitAngleCut;   // reject tracks with theta = 90+-cut, default cut = 3 [deg]
+    
+    Int_t                    fStartSeedMethod;     // 1, 2 = default
+    Bool_t                   fSmearSeedValues;     // start values smearing flag 
+  
+    Double_t                 fSmearingMomDelta;    // track start momentum smearing (+-)value, GeV/c
+    
+    Double_t                 fSmearingAngleDelta;  // [StartSeedMethod = 1] track start angle smearing  (+-)value, deg () 
+    Double_t                 fSmearingVertexDelta; // [StartSeedMethod = 1] track start vertex position smearing (+-)value, cm
+    
+    Int_t                    fNPointsVertexUse;    // [StartSeedMethod = ] number of vertex points are used to evaluate start parameters 
+    
+    Int_t                    fFitterMaxIterations; // max. number of iteration to reach convergency
+    Int_t                    fFitterMaxTrials;     // max. number of admissible track rebuilding trials to reach convergency
+    
+    Int_t                    fFitterOption;        // method to update covariance matrix (default = 1)
+    
+    Bool_t                   fStoreTracks;         // if true, store tracks in the output file  
+    
+    TVector3                 fStartMomentum;       // start track vertex momentum [GeV/c]
+    TVector3                 fStartVertex;         // start track vertex position [cm]
+    TMatrixDSym              fStartSeedCov;        // covariation matrix of size (6x6) 
+
+    /* V0 variables */ 
+    
+    TFile *fV0file;            // ROOT file 
+    TTree *fV0tree;            // Tree
+
+    Int_t    fFirstDaughter;   // first daugther
+    Int_t    fSecondDaughter;  // second daugther
+    Int_t    fUsedTypeOfPV;    // type of used PV 
+    Int_t    fConstrainToPV;   // constrain to PV
+    Double_t fMinChi2PV;       // minimum chi2 track to PV
+    Double_t fMinDist;         // minimum distance between 2 daughter particles
+    Double_t fMinMass;         // minimum mass for mother particle
+    Double_t fMaxMass;         // maximum mass for mother particle
+
+    std::vector<KFParticle> fKFparticles;
+
+    float v0_mass;             // mass od decay particle
+    float v0_massErr;          // error of mass decay particle
+    float v0_pp;               // momentum of decay particle
+    float v0_energy;           // energy of decay particle
+    float v0_eta;              // eta of decay particle
+    float v0_theta;            // theta of decay particle
+    float v0_phi;              // phi of decay particle
+    float v0_length;           // decay length
+
+    ClassDef(SpdIdealV0Finder,1)
+};
+
+#endif  /* __SPDIDEALV0FINDER_H__ */
+
diff --git a/reco/SpdRecoLinkDef.h b/reco/SpdRecoLinkDef.h
index 2f6cc2df4c49af2a832b07b4544c6ba06bc552e5..e7ab85211a83ff334ae196fca125b7b371e29f1b 100644
--- a/reco/SpdRecoLinkDef.h
+++ b/reco/SpdRecoLinkDef.h
@@ -6,5 +6,6 @@
 #pragma link off all functions;
 
 #pragma link C++ class SpdIdealKalmanFitter+;
+#pragma link C++ class SpdIdealV0Finder+;
 
 #endif
diff --git a/rst/CMakeLists.txt b/rst/CMakeLists.txt
index beee6bb21f3d97bb8e249ba24ad49f6dfcff175e..1a4f8e66711a952929399dcf92ecce519a2ab674 100644
--- a/rst/CMakeLists.txt
+++ b/rst/CMakeLists.txt
@@ -36,14 +36,18 @@ set(SRCS
 SpdRsTContFact.cxx
 
 barrel/SpdRsTB.cxx
+barrel/SpdRsTB2.cxx
 barrel/SpdRsTBParSet.cxx
 barrel/SpdRsTBPoint.cxx
+barrel/SpdRsTB2Point.cxx
 barrel/SpdRsTBHit.cxx
 barrel/SpdRsTBHitProducer.cxx
 
 ecps/SpdRsTEC.cxx
+ecps/SpdRsTEC2.cxx
 ecps/SpdRsTECParSet.cxx
 ecps/SpdRsTECPoint.cxx
+ecps/SpdRsTEC2Point.cxx
 ecps/SpdRsTECHit.cxx
 ecps/SpdRsTECHitProducer.cxx
 
diff --git a/rst/SpdRstLinkDef.h b/rst/SpdRstLinkDef.h
index 5b0dd0f7695279197ec65191cfb0066181f7e3ef..0a9d3da09cc0ef6f2b8974141153ea4eb1b95d96 100644
--- a/rst/SpdRstLinkDef.h
+++ b/rst/SpdRstLinkDef.h
@@ -13,10 +13,16 @@
 #pragma link C++ class SpdRsTBHit+;
 #pragma link C++ class SpdRsTBHitProducer+;
 
+#pragma link C++ class SpdRsTB2+;
+#pragma link C++ class SpdRsTB2Point+;
+
 #pragma link C++ class SpdRsTECParSet+;
 #pragma link C++ class SpdRsTEC+;
 #pragma link C++ class SpdRsTECPoint+;
 #pragma link C++ class SpdRsTECHit+;
 #pragma link C++ class SpdRsTECHitProducer+;
 
+#pragma link C++ class SpdRsTEC2+;
+#pragma link C++ class SpdRsTEC2Point+;
+
 #endif
diff --git a/rst/barrel/SpdRsTB.cxx b/rst/barrel/SpdRsTB.cxx
index 86affb3f0354da9feffa9be216154fd6da8c9f66..4270107f5dc0a9cd541e4440c927c755f1b35584 100644
--- a/rst/barrel/SpdRsTB.cxx
+++ b/rst/barrel/SpdRsTB.cxx
@@ -145,7 +145,7 @@ Bool_t SpdRsTB::ProcessHits(FairVolume* vol)
     
     fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
     
-    fVolumeID1 =  kSpdEcalTB;
+    fVolumeID1 =  kSpdRsTB;
     fVolumeID2 = -111111111;
     fVolumeID3 = -111111111;
     
diff --git a/rst/barrel/SpdRsTB2.cxx b/rst/barrel/SpdRsTB2.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f277e8e6acdbd5d01bdade34da0a675bf89aa900
--- /dev/null
+++ b/rst/barrel/SpdRsTB2.cxx
@@ -0,0 +1,894 @@
+// $Id$
+// Author: artur   2018/02/01
+
+//_____________________________________________________________________________
+//
+// SpdRsTB2
+//_____________________________________________________________________________
+
+#include "SpdRsTB2.h"
+
+#include "TRefArray.h"    
+#include "TClonesArray.h"
+#include "TParticle.h"
+#include "TVirtualMC.h"
+#include "TGeoManager.h"
+#include "TGeoBBox.h"
+#include "TGeoCompositeShape.h"
+#include "TGeoTube.h"
+#include "TGeoMaterial.h"
+#include "TGeoMedium.h"
+#include "TGeoArb8.h"
+
+#include "TMath.h"
+
+#include "SpdRsTB2Point.h"
+#include "SpdRsTB2GeoMapper.h"
+
+#include "SpdDetectorList.h"
+#include "SpdStack.h"
+#include "SpdMCEventHeader.h"
+#include "SpdCommonGeoMapper.h"
+#include "SpdGeoFactory.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace TMath;
+
+ClassImp(SpdRsTB2)
+
+//_____________________________________________________________________________________
+SpdRsTB2::SpdRsTB2(): 
+
+  SpdDetector("RS barrel (qsl)", kSpdRsTB, kTRUE),
+  fTrackID(-1),
+  fVolumeID(-1),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fPointCollection(0),
+  fModule(0)
+{
+  SetParametersType("RsTBParSet");
+   
+  fNDataOut = 1;
+  fOutDataPointObject = "SpdRsTB2Point"; 
+  
+  fBaseColor = kGreen+2;   // (air)
+  fAbsorbColor = kGreen+4; // (iron)
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2::SpdRsTB2(const char* name, Bool_t active):
+
+  SpdDetector(name, kSpdRsTB, active),
+  fTrackID(-1),
+  fVolumeID(-1),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fPointCollection(0),
+  fModule(0)
+{
+  SetParametersType("RsTBParSet");
+   
+  fNDataOut = 1;
+  fOutDataPointObject = "SpdRsTB2Point";
+  
+  fBaseColor = kGreen+2;   // (air)
+  fAbsorbColor = kGreen+4; // (iron)
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2::~SpdRsTB2()
+{
+  if (fPointCollection) {
+      fPointCollection->Delete();
+      delete fPointCollection;
+      fPointCollection = 0;
+  }
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::Initialize()
+{
+  cout << "\n*******************************************************************************" << endl;
+  cout << "************************* SpdRsTB2::Initialize ********************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+  
+  // data collections
+  fPointCollection = new TClonesArray(fOutDataPointObject);
+  
+  // Initialize module and fill parameters
+  SpdDetector::Initialize(); 
+ 
+  // SpdParSet* pars = GetParameters();
+  // if (pars) pars->printParams();  
+
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::Reset()
+{
+  fPointCollection->Clear();
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::Register()
+{
+  if (fGeoMapper && fGeoMapper->GetGeoType() < 1) return;
+    
+  FairRootManager::Instance()->Register(fOutDataPointObject,"SpdRsTB2", 
+                                        fPointCollection, kTRUE);
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdRsTB2::ProcessHits(FairVolume* vol)
+{
+  
+  //cout << "<SpdRsTB2::ProcessHits> " << gMC->CurrentVolPath() << endl;
+  
+  //Set parameters at entrance of volume. Reset ELoss.
+  if (gMC->IsTrackEntering()) {
+      fELoss  = 0.;
+      fTime   = gMC->TrackTime() * 1.e9;  // ns -> s
+      fLength = gMC->TrackLength();
+      gMC->TrackPosition(fPos);
+      gMC->TrackMomentum(fMom);
+  }
+
+  // Sum energy loss for all steps in the active volume
+  fELoss += gMC->Edep();
+
+  // Create SpdRsTB2Point at exit of active volume
+  if ( gMC->IsTrackExiting()    ||
+       gMC->IsTrackStop()       ||
+       gMC->IsTrackDisappeared()   ) 
+  {
+    
+    if (!fSaveEmptyHits && fELoss == 0.) { return kFALSE; }
+    
+    fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
+    fSegmentLength = gMC->TrackLength() - fLength;
+    fTimeOut   = gMC->TrackTime() * 1.e9;  // ns -> s
+    
+    fVolumeID   = kSpdRsTB;
+    fVolumePath = gMC->CurrentVolPath();
+    gMC->TrackPosition(fPosOut);
+    gMC->TrackMomentum(fMomOut);
+        
+    //cout << "path = " << fVolumePath << endl;
+   
+    AddHit();
+    
+    //cout << "<SpdRsTB2::AddHit> " << fPointCollection->GetEntriesFast() << endl;
+    
+    SpdStack* stack = (SpdStack*)gMC->GetStack();
+    stack->AddPoint(kSpdRsTB);
+  } 
+   
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::AddHit() 
+{
+  static Bool_t addhit = (fOutDataPointObject == "SpdRsTB2Point") ? kTRUE : kFALSE;
+  
+  if (!addhit) return;
+  
+  TClonesArray& clref = *fPointCollection;
+  Int_t size = clref.GetEntriesFast();
+  
+  new(clref[size]) SpdRsTB2Point(fTrackID,fVolumeID,fVolumePath,
+                                 TVector3(fPos.X(),fPos.Y(),fPos.Z()),
+                                 TVector3(fMom.Px(),fMom.Py(),fMom.Pz()),
+                                 TVector3(fPosOut.X(),fPosOut.Y(),fPosOut.Z()),
+                                 TVector3(fMomOut.Px(),fMomOut.Py(),fMomOut.Pz()),
+                                 fTime, fTimeOut,
+                                 fLength, fSegmentLength, fELoss);
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::EndOfEvent()
+{
+   Reset();
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::FinishRun() 
+{
+   //SpdDetector::FinishRun();
+   FillNodesTableIn(GetParameters());
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::ConstructGeometry()
+{   
+  // Create detector geometry
+  
+  fMasterVolume = SpdCommonGeoMapper::Instance()->GetMasterVolume();
+  
+  if (!fMasterVolume) {  
+      cout << "-E- <SpdTsTEC::ConstructGeometry> No MASTER volume " << endl;
+      return;
+  }
+  
+  if (!GetMapper()) return;
+  
+  if (!fGeoMapper->InitGeometry()) return;
+      
+  //fGeoMapper->Print("");
+  
+  Int_t geo_type = fGeoMapper->GetGeoType();
+
+  ConstructDetector();
+  
+  fGeoMapper->LockGeometry();
+      
+  cout << "\n*******************************************************************************" << endl;
+  cout << "********************** SpdRsTB2::ConstructGeometry ****************************" << endl;
+  cout << "********************** GEOMETRY TYPE: " << geo_type 
+       << " ***************************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2::ConstructDetector()
+{  
+  SpdParameter* par;
+  
+  SpdRsTB2GeoMapper* mapper = dynamic_cast<SpdRsTB2GeoMapper*>(fGeoMapper);
+  if (!mapper) return;
+  
+  Double_t mlen   = mapper->GetModuleLength();
+  
+  Double_t hmin   = mapper->GetModuleHmin();
+  Double_t hmax   = mapper->GetModuleHmax();;
+  Double_t lmin   = mapper->GetModuleLmin();
+  Double_t lmax   = mapper->GetModuleLmax(); 
+  
+  fModule = BuildModule("SideSVol", mapper->GetBaseMaterial(),
+                        0.5*mlen, hmin, hmax, 0.5*lmin, 0.5*lmax);
+  
+  if (!fModule) {
+      cout << "-E- <SpdRsTB2::ConstructGeometry> "
+           << "Volume " << fModule->GetName() << " cannot be created " << endl;
+      return;
+  }
+    
+  fModule->SetFillColor(kGreen);
+  fModule->SetLineColor(kGreen);
+  fModule->SetTransparency(30);  
+  
+  /*-----------------------------------------------------------*/
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+    
+  Double_t msize   = mapper->GetModuleSize();
+  Double_t mwidth  = mapper->GetModuleWidth();
+  
+  Int_t nLayers = mapper->GetNLayers();
+  
+  // Add bottom layer (absrober(6.0cm) + mdt detectors(3.5cm))
+  fModule->AddNode(CreateBottomLayer(msize, mwidth, mlen), 1, new TGeoCombiTrans("",  0, 0, 0, rotNoRot));
+  
+  // Add regular layers (3.0cm absorber + 3.5cm mdt detectors)
+  for (Int_t i(2); i < nLayers+1; ++i) {   
+       fModule->AddNode(CreateRegularLayer(i, msize, mwidth, mlen), i, new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+  }
+  
+  // Add top absorber (6.0cm)
+  fModule->AddNode(CreateTopLayer(nLayers+1, msize, mwidth, mlen), nLayers+1, new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+  
+  /*-----------------------------------------------------------*/
+
+  TGeoTranslation trans(0,0,0); 
+  TGeoRotation rot;
+  
+  Double_t angle = mapper->GetSecAngle();
+  Int_t nsectors = mapper->GetNSectors();
+  
+  for (int i(1); i<=nsectors; i++) {
+      
+       fMasterVolume->AddNode(fModule,i,new TGeoCombiTrans(trans,rot));   
+       rot.RotateZ(angle); 
+  }
+}
+
+//________________________________________________________________________________
+TGeoVolume* SpdRsTB2::BuildModule(const char* name, TString mat, Double_t length, 
+                                  Double_t hmin, Double_t hmax, Double_t lmin, Double_t lmax)
+{
+  //cout << "-I- <SpdRsTB2::BuildModule> " << length << "/" 
+  //     << hmin << "/" << hmax  << "/" <<  lmin << "/" << lmax << endl;
+  
+  Double_t v[16];
+  
+  v[0] =  lmin; v[1] = hmin;
+  v[2] = -lmin; v[3] = hmin;
+  v[4] = -lmax; v[5] = hmax;
+  v[6] =  lmax; v[7] = hmax;
+  
+  v[8]  =  lmin; v[9]  = hmin;
+  v[10] = -lmin; v[11] = hmin;
+  v[12] = -lmax; v[13] = hmax;
+  v[14] =  lmax; v[15] = hmax;
+
+  TGeoMedium* material = FindMedium(mat,"air");
+  
+  if (!material) {
+      cout << "-E- <SpdRsTB2::BuildModule> "
+            << "Unknown material: " << mat << endl;
+      return 0;
+  }
+  
+  TGeoVolume* vol = gGeoManager->MakeArb8(name,material,length,v);
+ 
+  //AddSensitiveVolume(vol); //ATTENTION FIXME ATTENTION
+  
+  return vol;
+}
+
+//________________________________________________________________________________
+TGeoVolume* SpdRsTB2::CreateBottomLayer(Double_t rsSize, Double_t rsThickness, Double_t rsLength) 
+{
+  //----------------------------------------------------------------------------
+  // Creates trapezoid representing bottom layer of the RS Barrel part
+  // (6.0cm thick iron absorber and a layer of MDT detectors)
+  // Parameters: 1. Size of RS from collision point (rsSize);
+  //             2. Thickness of RS rsThickness.
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //----------------------------------------------------------------------------
+    
+  SpdRsTB2GeoMapper* mapper = dynamic_cast<SpdRsTB2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTB2::CreateBottomLayer> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+  
+  Double_t layerThickness = 6.0+3.5; //cm
+  Double_t widthEnv = 8.5;           //cm xAxis
+  Double_t thicknessEnv = 1.64;      //cm zAxis
+
+  // Materials
+  TString mat;
+  
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");
+  
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium   *pair  = FindMedium(mat,"");
+  
+  // Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  Double_t lmin = (rsSize - rsThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+  Double_t lmax = (rsSize - rsThickness + layerThickness)*(sqrt(2.0)-1.0); // dimensions (top base)
+  Double_t hmin = (rsSize - rsThickness); 
+  Double_t hmax = (rsSize - rsThickness + layerThickness);
+
+//   cout << "lmin: " << lmin << endl;
+//   cout << "lmax: " << lmax << endl;
+//   cout << "hmin: " << hmin << endl;
+//   cout << "hmax: " << hmax << endl;
+
+  Double_t v_bottom[16];
+  
+  v_bottom[0] =  lmin; v_bottom[1] = hmin;
+  v_bottom[2] = -lmin; v_bottom[3] = hmin;
+  v_bottom[4] = -lmax; v_bottom[5] = hmax;
+  v_bottom[6] =  lmax; v_bottom[7] = hmax;
+  
+  v_bottom[8]  =  lmin; v_bottom[9]  = hmin;
+  v_bottom[10] = -lmin; v_bottom[11] = hmin;
+  v_bottom[12] = -lmax; v_bottom[13] = hmax;
+  v_bottom[14] =  lmax; v_bottom[15] = hmax;
+
+  TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_bottom);
+
+  Double_t Layer_Sector_Abs_dx = lmin;
+  Double_t Layer_Sector_Abs_dy = 6./2;
+  Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+  //cout << "Layer_SideS_Abs_Base_Shape: "
+  //     << 2*Layer_Sector_Abs_dx << ", " << 2*Layer_Sector_Abs_dy << ", " << 2*Layer_Sector_Abs_dz << endl;
+
+  TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                      Layer_Sector_Abs_dx, 
+                                                      Layer_Sector_Abs_dy, 
+                                                      Layer_Sector_Abs_dz);
+                                                          
+  TGeoVolume* Layer_SideS_Vol = new TGeoVolume("LayerSideSVol", Layer_SideS_Shape, pair);
+  TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("LayerSideSAbsBaseVol", Layer_SideS_Abs_Base_Shape, piron);
+
+  Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+
+  Double_t Layer_Envelope_startX = -1.0*lmin;
+  Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+  Double_t Layer_length          = 2*abs(Layer_Envelope_startX);
+  
+  Int_t    Nenvelopes = Int_t(Layer_length/widthEnv);
+  
+  //cout << "Layer #1 length: " << Layer_length << endl;
+  //cout << "Number of MDT detector in Layer #1: " << Nenvelopes << endl;
+
+  for (UInt_t i(0); i < Nenvelopes; i++) 
+  {
+      Layer_SideS_Vol->AddNode(CreateMDT(rsLength-0.2), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin+6+3.5/2, 0, rotNoRot)); 
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+  }
+  
+  Layer_SideS_Abs_Base_Vol->SetFillColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetLineColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetTransparency(30);  
+  
+  Layer_SideS_Vol->SetFillColor(fBaseColor);
+  Layer_SideS_Vol->SetLineColor(fBaseColor);
+  Layer_SideS_Vol->SetTransparency(30);  
+  
+  return Layer_SideS_Vol;
+}
+
+//________________________________________________________________________________
+TGeoVolume* SpdRsTB2::CreateTopLayer(Int_t layerN, Double_t rsSize, Double_t rsThickness, Double_t rsLength) 
+{
+  //----------------------------------------------------------------------------  
+  //
+  // Creates trapezoid representing regular layer of the RS Barrel part
+  // (3.0cm thick iron absorber and a layer of MDT detectors)
+  // Parameters: 1. Number of layer in a sector
+  //             2. Size of RS from collision point (rsSize);
+  //             3. Thickness of RS rsThickness.
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //----------------------------------------------------------------------------  
+  
+  SpdRsTB2GeoMapper* mapper = dynamic_cast<SpdRsTB2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTB2::CreateTopLayer> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+  
+  Double_t layerThickness = 3.0+3.0; // cm
+  Double_t Sector_dy = rsLength/2.0; // cm
+  Double_t widthEnv = 8.5;           // cm xAxis
+  Double_t thicknessEnv = 1.64;      // cm zAxis
+  
+  // Materials
+  TString mat;
+  
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");  
+  
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium   *pair  = FindMedium(mat,"");
+
+  // Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+  
+  Double_t lmin = (rsSize - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+  Double_t lmax = (rsSize - rsThickness + 9.5 + (layerN)*layerThickness)*(sqrt(2.0)-1.0);   // dimensions (top base)
+  Double_t hmin = (rsSize - rsThickness + 9.5 + (layerN-2)*6.5); 
+  Double_t hmax = (rsSize - rsThickness + 9.5 + (layerN-2)*6.5 + layerThickness);
+
+  //cout << "Layer #" << layerN << " dimensions (bottom base, lmin): [" << -lmin << "," << lmin << "]" << endl;
+  //cout << "Layer #" << layerN << " dimensions (bottom base, lmax): [" << -lmax << "," << lmax << "]" << endl;
+  //cout << "hmin: " << hmin <<endl;
+  //cout << "hmax: " << hmax <<endl;
+  
+  Double_t v_top[16];
+  
+  v_top[0] =  lmin; v_top[1] = hmin;
+  v_top[2] = -lmin; v_top[3] = hmin;
+  v_top[4] = -lmax; v_top[5] = hmax;
+  v_top[6] =  lmax; v_top[7] = hmax;
+  
+  v_top[8]  =  lmin; v_top[9]  = hmin;
+  v_top[10] = -lmin; v_top[11] = hmin;
+  v_top[12] = -lmax; v_top[13] = hmax;
+  v_top[14] =  lmax; v_top[15] = hmax;
+
+  TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_top);
+
+  Double_t Layer_Sector_Abs_dx = lmin;
+  Double_t Layer_Sector_Abs_dy = layerThickness/2;
+  Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+  TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                      Layer_Sector_Abs_dx, 
+                                                      Layer_Sector_Abs_dy, 
+                                                      Layer_Sector_Abs_dz);
+  
+                                                          
+  TGeoVolume* Layer_SideS_Vol = new TGeoVolume("LayerSideSVol", Layer_SideS_Shape, pair);
+  TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("LayerSideSAbsBaseVol", Layer_SideS_Abs_Base_Shape, piron);
+
+  Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+  
+  Layer_SideS_Abs_Base_Vol->SetFillColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetLineColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetTransparency(30);  
+  
+  Layer_SideS_Vol->SetFillColor(fBaseColor);
+  Layer_SideS_Vol->SetLineColor(fBaseColor);
+  Layer_SideS_Vol->SetTransparency(30);  
+  
+  return Layer_SideS_Vol;
+}
+
+//________________________________________________________________________________
+TGeoVolume* SpdRsTB2::CreateRegularLayer(Int_t layerN, Double_t rsSize, Double_t rsThickness, Double_t rsLength) 
+{
+  //----------------------------------------------------------------------------       
+  // Creates trapezoid representing regular layer of the RS Barrel part
+  // (3.0cm thick iron absorber and a layer of MDT detectors)
+  // Parameters: 1. Number of layer in a sector
+  //             2. Size of RS from collision point (rsSize);
+  //             3. Thickness of RS rsThickness.
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //----------------------------------------------------------------------------   
+  
+  SpdRsTB2GeoMapper* mapper = dynamic_cast<SpdRsTB2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTB2::CreateMDT> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+  
+  Double_t layerThickness = 3.0+3.5; // cm
+  Double_t Sector_dy = rsLength/2.0; // cm
+  Double_t widthEnv = 8.5;           // cm xAxis
+  Double_t thicknessEnv = 1.64;      // cm zAxis
+  
+  // Materials
+  TString mat;
+  
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");
+  
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium   *pair  = FindMedium(mat,"");
+
+  // Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+  
+  Double_t Layer_Sector_dz  = layerThickness/2; // z-coord of the layer center 
+  Double_t Layer_Sector_dx1 = 1.0*(rsSize - rsThickness + 9.5 + (layerN-2)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the bottom base
+  Double_t Layer_Sector_dx2 = 1.0*(rsSize - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // X-coord of the top base
+  Double_t Layer_Sector_dy  = Sector_dy;       // y-coord of the layer center
+  
+  //cout<<"Layer #"<< layerN << " dimensions (bottom base): ["
+  //    << Layer_Sector_dx1*2 << " x " << Layer_Sector_dz*2 << " x " << Layer_Sector_dy*2 << "] cm" << endl;
+  //cout<<"Layer #"<< layerN << " dimensions (top base): ["
+  //    << Layer_Sector_dx2*2 << " x " << Layer_Sector_dz*2 << " x " << Layer_Sector_dy*2 << "] cm" << endl;
+  
+  Double_t lmin = (rsSize - rsThickness + 9.5 + (layerN-2)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (bottom base)
+  Double_t lmax = (rsSize - rsThickness + 9.5 + (layerN-1)*layerThickness)*(sqrt(2.0)-1.0); // dimensions (top base)
+  Double_t hmin = (rsSize - rsThickness + 9.5 + (layerN-2)*layerThickness); 
+  Double_t hmax = (rsSize - rsThickness + 9.5 + (layerN-1)*layerThickness);
+
+  //cout << "Layer #" << layerN << " dimensions (bottom base, lmin): [" << -lmin << "," << lmin << "]" << endl;
+  //cout << "Layer #" << layerN << " dimensions (bottom base, lmax): [" << -lmax << "," << lmax << "]" << endl;
+  //cout << "hmin: " << hmin << endl;
+  //cout << "hmax: " << hmax << endl;
+  
+  Double_t v_regular[16];
+  
+  v_regular[0] =  lmin; v_regular[1] = hmin;
+  v_regular[2] = -lmin; v_regular[3] = hmin;
+  v_regular[4] = -lmax; v_regular[5] = hmax;
+  v_regular[6] =  lmax; v_regular[7] = hmax;
+  
+  v_regular[8]  =  lmin; v_regular[9]  = hmin;
+  v_regular[10] = -lmin; v_regular[11] = hmin;
+  v_regular[12] = -lmax; v_regular[13] = hmax;
+  v_regular[14] =  lmax; v_regular[15] = hmax;
+
+  TGeoArb8* Layer_SideS_Shape = new TGeoArb8("Layer_SideS_Shape", rsLength/2, v_regular);
+
+  Double_t Layer_Sector_Abs_dx = lmin;
+  Double_t Layer_Sector_Abs_dy = 3./2;
+  Double_t Layer_Sector_Abs_dz = rsLength/2;
+
+  TGeoBBox* Layer_SideS_Abs_Base_Shape = new TGeoBBox("Layer_SideS_Abs_Base_Shape", 
+                                                      Layer_Sector_Abs_dx, Layer_Sector_Abs_dy, Layer_Sector_Abs_dz);
+  
+                                                          
+  TGeoVolume* Layer_SideS_Vol          = new TGeoVolume("LayerSideSVol",        Layer_SideS_Shape,          pair);
+  TGeoVolume* Layer_SideS_Abs_Base_Vol = new TGeoVolume("LayerSideSAbsBaseVol", Layer_SideS_Abs_Base_Shape, piron);
+
+  Layer_SideS_Vol->AddNode(Layer_SideS_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, hmin+Layer_Sector_Abs_dy, 0, rotNoRot));
+
+  if (layerN % 2 == 0) 
+  {
+      Double_t Layer_Envelope_startX = lmin;
+      Double_t Layer_Envelope_shiftX = Layer_Envelope_startX - widthEnv/2;
+
+      Double_t Layer_length = 2*abs(Layer_Envelope_startX);
+      Int_t Nenvelopes = Int_t((Layer_length)/widthEnv);
+      
+      //cout << " Layer #" << layerN << " length: " << Layer_length << endl;
+      //cout << " Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+      
+      for (UInt_t i(0); i < Nenvelopes; i++) 
+      {
+           Layer_SideS_Vol->AddNode(CreateMDT(493.0), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin + 3 + 3.5/2, 0, rotNoRot)); 
+           Layer_Envelope_shiftX = Layer_Envelope_shiftX - widthEnv;
+      }
+  }
+  else 
+  {
+      Double_t Layer_Envelope_startX = -1.0*abs(lmin);
+      Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+
+      Double_t Layer_length = 2*abs(Layer_Envelope_startX);
+      Int_t Nenvelopes = Int_t((Layer_length)/widthEnv);
+      
+      //cout << " Layer #" << layerN << " length: " << Layer_length << endl;
+      //cout << " Number of MDT detector in Layer" << layerN << ": " << Nenvelopes << endl;
+      
+      for (UInt_t i(0); i < Nenvelopes; i++) 
+      {
+          Layer_SideS_Vol->AddNode(CreateMDT(493.0), i+1, new TGeoCombiTrans("", Layer_Envelope_shiftX, hmin + 3 + 3.5/2, 0, rotNoRot)); 
+          Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      }
+  }
+  
+  Layer_SideS_Abs_Base_Vol->SetFillColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetLineColor(fAbsorbColor);
+  Layer_SideS_Abs_Base_Vol->SetTransparency(30);  
+  
+  Layer_SideS_Vol->SetFillColor(fBaseColor);
+  Layer_SideS_Vol->SetLineColor(fBaseColor);
+  Layer_SideS_Vol->SetTransparency(30);  
+
+  return Layer_SideS_Vol;
+}
+
+//________________________________________________________________________________
+TGeoVolume* SpdRsTB2::CreateMDT(Double_t length) 
+{
+  //----------------------------------------------------------------------------     
+  // Creates MDT of given length;
+  // Envelope Dimensions(L x W x H): length x 8.5cm x 1.64cm.
+  // Note: Adopted from Panda Muon System
+  //----------------------------------------------------------------------------  
+ 
+  SpdRsTB2GeoMapper* mapper = dynamic_cast<SpdRsTB2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTB2::CreateMDT> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+  
+  // Materials ------------------------------------------------------------------------
+  
+  TString mat;
+  
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium* pair = FindMedium(mat,"");
+  
+  mat = mapper->GetActiveMaterialMDT();
+  TGeoMedium* pMDTMixture = FindMedium(mat,"");  
+  
+  mat = mapper->GetPassiveMaterialMDT();
+  TGeoMedium* paluminium = FindMedium(mat,"");  
+  
+  // Shapes and volumes ---------------------------------------------------------------
+  
+  // General dimensions
+  Double_t widthEnv = 8.5;      //cm xAxis
+  Double_t thicknessEnv = 1.64; //cm zAxis
+  Double_t xSize = 1.0;
+
+  TString transName;
+  Int_t Nenvelopes;
+  Int_t IncEnv = 0;
+
+  // Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+  
+  Double_t empty_value = (2.0+2.0+8.5)+6.5*2;
+  Double_t L_MDT_Envelope = length; //493.0;
+  Double_t L_MDT_Envelope_sensitive = L_MDT_Envelope-empty_value;
+
+  Int_t ind = Int_t(length*10);
+  
+  //---------------------------------------
+  
+  TGeoBBox* Indent20_Shape = new TGeoBBox("Indent20_Shape", widthEnv/2, thicknessEnv/2,  1.0);
+  TGeoBBox* FEB_box_Shape  = new TGeoBBox("FEBbox_Shape",  widthEnv/2, thicknessEnv/2,  widthEnv/2);
+  TGeoBBox* DeadMat_Shape  = new TGeoBBox("DeadMat_Shape",  4.07, 0.515,  3.25);
+  
+  TGeoVolume* Indent20_Vol = new TGeoVolume("Indent20Vol", Indent20_Shape, pair);
+  TGeoVolume* FEB_box_Vol  = new TGeoVolume("FEBboxVol",   FEB_box_Shape,  pair);
+  TGeoVolume* DeadMat_Vol  = new TGeoVolume("DeadMatVol",  DeadMat_Shape,  pMDTMixture);
+
+  //---------------------------------------
+  
+  TGeoBBox* L_Al_A_Shape     = new TGeoBBox(Form("L%d_Al_A_Shape",ind),    4.03, 0.03, L_MDT_Envelope_sensitive/2);
+  TGeoBBox* L_Al_B_Shape     = new TGeoBBox(Form("L%d_Al_B_Shape",ind),    0.03, 0.42, L_MDT_Envelope_sensitive/2);
+  TGeoBBox* L_GasCell_Shape  = new TGeoBBox(Form("L%d_GasCell_Shape",ind), 0.47, 0.46, L_MDT_Envelope_sensitive/2);
+  TGeoBBox* L_Cell_Shape     = new TGeoBBox(Form("L%d_Cell_Shape",ind),    0.5,  0.46, L_MDT_Envelope_sensitive/2);
+  TGeoBBox* L_MDT_S_Shape    = new TGeoBBox(Form("L%d_MDT_S_Shape",ind),   4.0,  0.46, L_MDT_Envelope_sensitive/2);
+  
+  TGeoVolume* L_Al_A_Vol     = new TGeoVolume(Form("L%dAlAVol",ind),     L_Al_A_Shape,    paluminium);
+  TGeoVolume* L_Al_B_Vol     = new TGeoVolume(Form("L%dAlBVol",ind),     L_Al_B_Shape,    paluminium);
+  TGeoVolume* L_GasCell_Vol  = new TGeoVolume(Form("L%dGasCellVol",ind), L_GasCell_Shape, pMDTMixture);
+  TGeoVolume* L_Cell_Vol     = new TGeoVolume(Form("L%dCellVol",ind),    L_Cell_Shape,    pMDTMixture);
+  TGeoVolume* L_MDT_S_Vol    = new TGeoVolume(Form("L%dMDTSVol",ind),    L_MDT_S_Shape,   pMDTMixture);
+  
+  //---------------------------------------
+  
+  TGeoBBox*   L_Envelope_Shape = new TGeoBBox(Form("L%d_Envelope_Shape",ind), widthEnv/2, thicknessEnv/2, L_MDT_Envelope/2);
+
+  TGeoVolume* L_Envelope_Vol   = new TGeoVolume(Form("L%dEnvelopeVol",ind), L_Envelope_Shape, pair);
+  
+  // Structure -----------------------------------------------------------------
+  
+  // GasCell and Al_B in Cell
+  L_Cell_Vol->AddNode(L_GasCell_Vol, 1, new TGeoCombiTrans("", -0.03,     0,  0, rotNoRot));
+  L_Cell_Vol->AddNode(L_Al_B_Vol,    1, new TGeoCombiTrans("",  0.47, -0.04,  0, rotNoRot));
+
+  // Cells in MDT_S
+  const Int_t NCells = 8;
+  for (UInt_t i(0); i < NCells; i++) 
+  {
+      transName.Form("trans_cell_%d", i);
+      TGeoCombiTrans* trans1 = new TGeoCombiTrans(transName.Data(), -4.0 + xSize/2. + (Double_t)i*xSize, 0, 0., rotNoRot);
+      trans1->RegisterYourself();
+      L_MDT_S_Vol->AddNode(L_Cell_Vol, i+1, trans1);
+  }
+
+  L_Envelope_Vol->AddNode(Indent20_Vol, 1, new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2 - 1.0, rotNoRot));
+  L_Envelope_Vol->AddNode(Indent20_Vol, 2, new TGeoCombiTrans("", 0, 0, 1.0 - L_MDT_Envelope/2, rotNoRot));
+  L_Envelope_Vol->AddNode(FEB_box_Vol,  1, new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2-2.0-8.5*0.5, rotNoRot));
+  L_Envelope_Vol->AddNode(DeadMat_Vol,  1, new TGeoCombiTrans("", 0, 0, ((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(DeadMat_Vol,  2, new TGeoCombiTrans("", 0, 0,-((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_Al_A_Vol,   1, new TGeoCombiTrans("", 0, -0.36, -widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_Al_B_Vol,   1, new TGeoCombiTrans("", -4.0, 0.09, -widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_MDT_S_Vol,  1, new TGeoCombiTrans("", 0.03, 0.13, -widthEnv/2, rotNoRot));  
+  
+  L_Envelope_Vol->SetFillColor(kGreen+1);
+  L_Envelope_Vol->SetLineColor(kGreen+1);
+  L_Envelope_Vol->SetTransparency(30);   
+  
+  AddSensitiveVolume(L_GasCell_Vol); //ATTENTION FIXME ATTENTION
+  
+  return L_Envelope_Vol;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+SpdGeoMapper* SpdRsTB2::GetMapper() 
+{
+  if (fGeoMapper) return fGeoMapper;
+  
+  SpdGeoFactory* factory = SpdGeoFactory::Instance();
+ 
+  // search for mapper
+  fGeoMapper = factory->SearchForMapper("SpdRsTB2GeoMapper");
+  
+  if (!fGeoMapper) fGeoMapper = factory->Mapper("SpdRsTB2GeoMapper");
+
+  return fGeoMapper; 
+}
+
+//_____________________________________________________________________________
+Bool_t SpdRsTB2::LoadParsFrom(SpdParSet* params) 
+{
+  if (!params) return kFALSE;
+ 
+  if (!SpdDetector::LoadParsFrom(params)) return kFALSE;
+  
+  TString mapper;
+  params->GetParameter("Mapper",mapper); 
+  fGeoMapper = SpdGeoFactory::Instance()->Mapper(mapper);  
+  if (fGeoMapper) fGeoMapper->LoadParametersFrom(params);
+   
+  fOutDataPointObject = "unknown";
+
+  if (fNDataOut < 1) return kTRUE;
+
+  params->GetParameter("Detector/NOutData_1",fOutDataPointObject);
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+TString SpdRsTB2::GetDataOut(Int_t n) const 
+{ 
+  if (n < 0 || n >= fNDataOut) return "unknown";
+  return fOutDataPointObject;
+}
+
+
+//_____________________________________________________________________________________
+TClonesArray* SpdRsTB2::GetCollection(Int_t iColl) const 
+{ 
+  return (iColl == 0) ? fPointCollection : 0; 
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+Double_t SpdRsTB2::GetCapacity() const 
+{ 
+  //return (fModule) ? fModule->GetShape()->Capacity() : 0;
+  return 0.;
+}
+   
+//_____________________________________________________________________________________
+Double_t SpdRsTB2::GetMass() const 
+{ 
+  return (fModule) ? GetCapacity()*GetDensity() : 0;
+}
+
+//_____________________________________________________________________________________
+Double_t SpdRsTB2::GetDensity() const 
+{ 
+  return (fModule) ? fModule->GetMaterial()->GetDensity() : 0;
+}
+
+//_____________________________________________________________________________________
+TString SpdRsTB2::GetMaterialName() const // private
+{ 
+  return (fModule) ? fModule->GetMaterial()->GetName() : "";
+}
+
+//_____________________________________________________________________________
+void SpdRsTB2::Print(Option_t*) const
+{
+   SpdDetector::Print("");
+   
+   if (!fGeoMapper) return;
+   
+   TString divider('-',150);
+   
+   cout << "\n";
+
+   fGeoMapper->Print("");
+
+   cout << "\n";
+   cout <<"\tCapacity (total):    " << GetCapacity()*1e-6 << " [m^3] " << endl;
+   cout <<"\tMass (total):        " << GetMass()*1e-3 << " [kg] " << endl;
+   cout <<"\tDensity (averaged):  " << GetDensity() << " [g/cm^3] " << endl;
+   cout << "\n";
+   
+   cout << "\n" << divider.Data() << "\n";
+   
+   printf("%6s %4s %15s %14s %14s %14s \n\n",
+          "Type","N","Material","Dens [g/cm^3]","Volume [m^3]","Mass [kg]"
+         );
+   
+   if (!fModule) {
+       cout << "\n";
+       return;
+   }
+   
+   printf("%6d %4d %15s %14.6f %14.6f %14.6f \n",
+           1, 1, GetMaterialName().Data(),
+           GetDensity(), GetCapacity()*1e-6, GetMass()*1e-3);
+   
+   cout << divider.Data() << "\n";
+   
+   printf("%6s %35s %14.3e %14.3e \n","TOTAL:","",GetCapacity()*1e-6,GetMass()*1e-3);
+    
+   cout << divider.Data() << "\n";
+   
+   cout << "\n";
+}
+
+
diff --git a/rst/barrel/SpdRsTB2.h b/rst/barrel/SpdRsTB2.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ec6976293caa0a073081e7c2cf24044562f361e
--- /dev/null
+++ b/rst/barrel/SpdRsTB2.h
@@ -0,0 +1,103 @@
+
+#ifndef __SPDRSTB2_H__
+#define __SPDRSTB2_H__
+
+#include <TLorentzVector.h>
+#include <TString.h>
+
+#include "SpdDetector.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTB2                                                                   //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class FairVolume;
+class TClonesArray;
+
+class SpdRsTB2: public SpdDetector { 
+
+public:
+
+    SpdRsTB2(const char* Name, Bool_t Active);
+    SpdRsTB2();
+  
+    virtual ~SpdRsTB2();
+  
+    virtual void  Initialize();
+    virtual void  Reset();
+    virtual void  Register();
+    
+    virtual Bool_t ProcessHits(FairVolume* v = 0);
+    
+    virtual TString GetDataOut(Int_t n) const;
+    virtual TClonesArray* GetCollection(Int_t iColl) const;
+    
+    virtual Double_t GetCapacity() const;  // cm^3
+    virtual Double_t GetMass()     const;  // g
+    virtual Double_t GetDensity()  const;  // g/cm^3
+    
+    virtual SpdGeoMapper* GetMapper();
+    
+    virtual void ConstructGeometry();
+     
+    virtual void  EndOfEvent();
+    virtual void  FinishRun(); 
+    
+    virtual Bool_t LoadParsFrom(SpdParSet* params);
+    
+    virtual void  Print(Option_t*) const;
+      
+private:
+  
+    void AddHit();
+    
+    /* Track information to be stored until the track leaves the active volume. */
+    
+    Int_t          fTrackID;           //!  track index
+    Int_t          fVolumeID;          //!  volume id (Detector Id)
+    TString        fVolumePath;        //!  full path to current volume
+    TLorentzVector fPos;               //!  position at entrance
+    TLorentzVector fMom;               //!  momentum at entrance
+    TLorentzVector fPosOut;            //!  position at exit
+    TLorentzVector fMomOut;            //!  momentum at exit
+    Double32_t     fTime;              //!  time
+    Double32_t     fTimeOut;           //!  time at exit
+    Double32_t     fLength;            //!  length
+    Double32_t     fSegmentLength;     //!  length of segment
+    Double32_t     fELoss;             //!  energy loss
+
+    /* containers for data */
+
+    TString        fOutDataPointObject; //!
+    TClonesArray*  fPointCollection;    //!
+    
+    SpdRsTB2(const SpdRsTB2&);
+    SpdRsTB2& operator=(const SpdRsTB2&);
+    
+    /* GEOMETRY */
+    
+    TGeoVolume* fModule; //!
+         
+    TGeoVolume* BuildModule(const Char_t* name, TString mat, 
+                Double_t length, Double_t hmin, Double_t hmax, Double_t lmin, Double_t lmax);
+
+    TGeoVolume* CreateBottomLayer(Double_t rsSize, Double_t rsThickness, Double_t rsLength);
+    TGeoVolume* CreateTopLayer(Int_t layerN, Double_t rsWidth, Double_t rsThickness, Double_t rsLength);
+    TGeoVolume* CreateRegularLayer(Int_t layerN, Double_t rsSize, Double_t rsThickness, Double_t rsLength);
+    TGeoVolume* CreateMDT(Double_t length);
+
+    void ConstructDetector();
+    
+    TString GetMaterialName() const;
+    
+    Int_t   fBaseColor;   // (air)
+    Int_t   fAbsorbColor; // (iron)
+    
+    ClassDef(SpdRsTB2,1)
+};
+
+#endif /* __SPDRSTB2_H__ */
diff --git a/rst/barrel/SpdRsTB2Point.cxx b/rst/barrel/SpdRsTB2Point.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ca19810183d42115ce295c7396f36748361e3cc8
--- /dev/null
+++ b/rst/barrel/SpdRsTB2Point.cxx
@@ -0,0 +1,78 @@
+// $Id$
+// Author: artur   2018/02/01
+
+#include "SpdRsTB2Point.h"
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+ClassImp(SpdRsTB2Point)
+
+//_____________________________________________________________________________________
+SpdRsTB2Point::SpdRsTB2Point():FairMCPoint(),fHitGeoPath("") 
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2Point::SpdRsTB2Point(Int_t trackID, Int_t detID,
+                             TVector3 pos, TVector3 mom, Double_t tof, 
+                             Double_t length, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fHitGeoPath("") 
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2Point::SpdRsTB2Point(Int_t trackID, Int_t detID, TString hpath,
+                             TVector3 pos, TVector3 mom, Double_t tof, 
+                             Double_t length, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fHitGeoPath(hpath) 
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2Point::SpdRsTB2Point(Int_t trackID, Int_t detID, TString hpath,
+                             TVector3 pos, TVector3 mom, TVector3 posOut, TVector3 momOut,
+                             Double_t tof, Double_t tofOut,
+                             Double_t length, Double_t segmentlength, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss),
+fHitGeoPath(hpath),
+fPosOut(posOut),
+fMomOut(momOut),
+fTimeOut(tofOut),
+fSegmentLength(segmentlength)
+{
+
+}
+
+//_____________________________________________________________________________________
+SpdRsTB2Point::~SpdRsTB2Point() 
+{ 
+  
+}
+
+//_____________________________________________________________________________________
+void SpdRsTB2Point::Print(const Option_t* opt) const
+{
+  cout << "<SpdRsTB2Point::Print> " << endl; 
+  cout << "\n";
+  cout << " Track/DetectorID:  " << fTrackID << "/" << fDetectorID << endl;
+  cout << " Hit node path:     " << fHitGeoPath << endl;
+  cout << " Position In, Time: " << fX << ", " << fY << ", " << fZ << " [cm]  " 
+                                 << fTime << " [ns] " << endl;
+  cout << " Position Out:      " << fPosOut.X() << ", " << fPosOut.Y() << ", " << fPosOut.Z() << " [cm]  " << endl;
+  cout << " Momentum In:       " << fPx << ", " << fPy << ", " << fPz << " [GeV]" << endl;
+  cout << " Momentum Out:      " << fMomOut.X() << ", " << fMomOut.Y() << ", " << fMomOut.Z() << " [GeV]" << endl;
+  cout << " Energy loss:       " << fELoss*1.0e06 << " keV " << endl;
+  cout << "\n";
+}
+
+
+
+
diff --git a/rst/barrel/SpdRsTB2Point.h b/rst/barrel/SpdRsTB2Point.h
new file mode 100644
index 0000000000000000000000000000000000000000..c57b9182712c12d0daba95350ffb14f8741481dc
--- /dev/null
+++ b/rst/barrel/SpdRsTB2Point.h
@@ -0,0 +1,86 @@
+// $Id$
+// Author: artur   2018/02/01
+//
+// added new variables for points 
+
+#ifndef __SPDRSTB2POINT_H__
+#define __SPDRSTB2POINT_H__ 
+
+#include "FairMCPoint.h"
+#include <TString.h>
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTB2Point2                                                             //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdRsTB2Point : public FairMCPoint {
+
+public:
+  
+   /** Constructor with arguments
+   *@param trackID  Index of MCTrack
+   *@param detID    Detector ID
+   *@param hpath    Hit node full geopath 
+   *@param pos      Ccoordinates at entrance to active volume [cm]
+   *@param mom      Momentum of track at entrance [GeV]
+   *@param posOut   Coordinates at exit to active volume [cm]
+   *@param momOut   Momentum of track at exit [GeV]   
+   *@param tof      Time since event start [ns]
+   *@param length   Track length since creation [cm]
+   *@param ELoss    Energy deposit [GeV]
+   **/
+  
+  SpdRsTB2Point();
+  
+  SpdRsTB2Point(Int_t trackID, Int_t detID, 
+                 TVector3 pos, TVector3 mom, 
+                 Double_t tof, Double_t length, Double_t ELoss);
+  
+  SpdRsTB2Point(Int_t trackID, Int_t detID,  TString hpath,
+                 TVector3 pos, TVector3 mom, 
+                 Double_t tof, Double_t length, Double_t ELoss);
+
+  SpdRsTB2Point(Int_t trackID, Int_t detID,  TString hpath,
+                 TVector3 pos, TVector3 mom, TVector3 posOut, TVector3 momOut,
+                 Double_t tof, Double_t tofOut,
+                 Double_t length, Double_t segmentlength, Double_t ELoss);
+
+  SpdRsTB2Point(const SpdRsTB2Point& point) { *this = point; };
+
+  virtual ~SpdRsTB2Point();
+
+    /** Accessors **/
+  inline TVector3 GetPosIn()            const { return TVector3(fX, fY, fZ);    }
+  inline TVector3 GetMomIn()            const { return TVector3(fPx, fPy, fPz); }
+  inline TVector3 GetPosOut()           const { return fPosOut;                 }
+  inline TVector3 GetMomOut()           const { return fMomOut;                 }
+  inline Double_t GetSegmentLength()    const { return fSegmentLength;          }
+  inline Double_t GetTimeIn()           const { return fTime;                   }
+  inline Double_t GetTimeOut()          const { return fTimeOut;                }
+
+  inline void  SetHitGeoPath(TString hpath) { fHitGeoPath = hpath; }
+  
+  inline TString GetHitGeoPath() const { return fHitGeoPath;  }
+
+  virtual void Print(const Option_t* opt) const;
+
+protected:
+
+  TVector3 fPosOut;
+  TVector3 fMomOut;
+  Double32_t    fTimeOut;                  // Time since event start at exit of detector [ns]
+  Double_t      fSegmentLength;            // Trajectory segment length inside the detector, [cm]
+  
+private:
+
+  TString  fHitGeoPath;
+
+  ClassDef(SpdRsTB2Point,1)
+
+};
+
+#endif  /* __SPDRSTB2POINT_H__ */
diff --git a/rst/ecps/SpdRsTEC2.cxx b/rst/ecps/SpdRsTEC2.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..21e70d313f61920c0904045f558bf45485daa726
--- /dev/null
+++ b/rst/ecps/SpdRsTEC2.cxx
@@ -0,0 +1,868 @@
+// $Id$
+// Author: artur   2018/02/01
+
+//_____________________________________________________________________________
+//
+// SpdRsTEC2
+//_____________________________________________________________________________
+
+#include "SpdRsTEC2.h"
+
+#include "TRefArray.h"    
+#include "TClonesArray.h"
+#include "TParticle.h"
+#include "TVirtualMC.h"
+#include "TGeoManager.h"
+#include "TGeoBBox.h"
+#include "TGeoPgon.h"
+#include "TGeoCompositeShape.h"
+#include "TGeoTube.h"
+#include "TGeoMaterial.h"
+#include "TGeoMedium.h"
+#include "TMath.h"
+
+#include "SpdRsTEC2Point.h"
+#include "SpdRsTEC2GeoMapper.h"
+
+#include "SpdDetectorList.h"
+#include "SpdStack.h"
+#include "SpdMCEventHeader.h"
+#include "SpdCommonGeoMapper.h"
+#include "SpdGeoFactory.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace TMath;
+
+ClassImp(SpdRsTEC2)
+
+//_____________________________________________________________________________________
+SpdRsTEC2::SpdRsTEC2(): 
+
+  SpdDetector("RS endcaps (qsl)", kSpdRsTEC, kTRUE),
+  fTrackID(-1),
+  fVolumeID(-1),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fPointCollection(0),
+  fModule(0)
+{
+  SetParametersType("RsTECParSet");
+   
+  fNDataOut = 1;
+  fOutDataPointObject = "SpdRsTEC2Point"; 
+
+  fBaseColor = kGreen+1;   // (air)   
+  fAbsorbColor = kGreen+3; // (iron)
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2::SpdRsTEC2(const char* name, Bool_t active):
+
+  SpdDetector(name, kSpdRsTEC, active),
+  fTrackID(-1),
+  fVolumeID(-1),
+  fPos(),
+  fMom(),
+  fTime(-1.),
+  fLength(-1.),
+  fELoss(-1),
+  fPointCollection(0),
+  fModule(0)
+{
+  SetParametersType("RsTECParSet");
+   
+  fNDataOut = 1;
+  fOutDataPointObject = "SpdRsTEC2Point";  
+
+  fBaseColor = kGreen+1;   // (air)   
+  fAbsorbColor = kGreen+3; // (iron)
+
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2::~SpdRsTEC2()
+{
+  if (fPointCollection) {
+      fPointCollection->Delete();
+      delete fPointCollection;
+      fPointCollection = 0;
+  }
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::Initialize()
+{
+  cout << "\n*******************************************************************************" << endl;
+  cout << "************************* SpdRsTEC2::Initialize *******************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+   
+  // data collections
+  fPointCollection = new TClonesArray(fOutDataPointObject);
+  
+  // Initialize module and fill parameters
+  SpdDetector::Initialize(); 
+ 
+  // SpdParSet* pars = GetParameters();
+  // if (pars) pars->printParams();
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::Reset()
+{
+  fPointCollection->Clear();
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::Register()
+{
+  if (fGeoMapper && fGeoMapper->GetGeoType() < 1) return;
+    
+  FairRootManager::Instance()->Register(fOutDataPointObject,"SpdRsTEC2", 
+                                        fPointCollection, kTRUE);
+}
+
+//_____________________________________________________________________________________
+Bool_t SpdRsTEC2::ProcessHits(FairVolume* vol)
+{
+  //cout << "<SpdRsTEC2::ProcessHits> " << gMC->CurrentVolPath() << endl;
+  
+  //Set parameters at entrance of volume. Reset ELoss.
+  if (gMC->IsTrackEntering()) {
+      fELoss  = 0.;
+      fTime   = gMC->TrackTime() * 1.e9;  // ns -> s
+      fLength = gMC->TrackLength();
+      gMC->TrackPosition(fPos);
+      gMC->TrackMomentum(fMom);
+  }
+
+  // Sum energy loss for all steps in the active volume
+  fELoss += gMC->Edep();
+
+  // Create SpdRsTEC2Point at exit of active volume
+  if ( gMC->IsTrackExiting()    ||
+       gMC->IsTrackStop()       ||
+       gMC->IsTrackDisappeared()   ) 
+  {
+    if (!fSaveEmptyHits && fELoss == 0.) { return kFALSE; }
+    
+    fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
+    fSegmentLength = gMC->TrackLength() - fLength;
+    fTimeOut   = gMC->TrackTime() * 1.e9;  // ns -> s
+
+    fVolumeID =  kSpdRsTEC;
+    fVolumePath = gMC->CurrentVolPath();
+    gMC->TrackPosition(fPosOut);
+    gMC->TrackMomentum(fMomOut);
+
+    //cout << "path = " << gMC->CurrentVolPath() << endl;
+   
+    AddHit();
+    
+    //cout << "<SpdRsTEC2::AddHit> " << fPointCollection->GetEntriesFast() << endl;
+   
+    SpdStack* stack = (SpdStack*)gMC->GetStack();
+    stack->AddPoint(kSpdRsTEC);
+  } 
+   
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::AddHit() 
+{
+  static Bool_t addhit = (fOutDataPointObject == "SpdRsTEC2Point") ? kTRUE : kFALSE;
+  
+  if (!addhit) return;
+  
+  TClonesArray& clref = *fPointCollection;
+  Int_t size = clref.GetEntriesFast();
+  
+  new(clref[size]) SpdRsTEC2Point(fTrackID,fVolumeID,fVolumePath,
+                                 TVector3(fPos.X(),fPos.Y(),fPos.Z()),
+                                 TVector3(fMom.Px(),fMom.Py(),fMom.Pz()),
+                                 TVector3(fPosOut.X(),fPosOut.Y(),fPosOut.Z()),
+                                 TVector3(fMomOut.Px(),fMomOut.Py(),fMomOut.Pz()),
+                                 fTime, fTimeOut, 
+				 fLength, fSegmentLength, fELoss);                                 
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::EndOfEvent()
+{
+  Reset();
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::FinishRun() 
+{
+  //SpdDetector::FinishRun();
+  FillNodesTableIn(GetParameters());
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::ConstructGeometry()
+{   
+  // Create detector geometry
+  
+  fMasterVolume = SpdCommonGeoMapper::Instance()->GetMasterVolume();
+  
+  if (!fMasterVolume) {  
+      cout << "-E- <SpdTsTEC2::ConstructGeometry> No MASTER volume " << endl;
+      return;
+  }
+
+  if (!GetMapper()) return;
+  
+  if (!fGeoMapper->InitGeometry()) return;
+      
+  //fGeoMapper->Print("");
+  
+  Int_t geo_type = fGeoMapper->GetGeoType();
+
+  ConstructDetector();
+
+  fGeoMapper->LockGeometry();
+  
+  cout << "\n*******************************************************************************" << endl;
+  cout << "********************** SpdRsTEC2::ConstructGeometry ***************************" << endl;
+  cout << "********************** GEOMETRY TYPE: " << geo_type 
+       << " ***************************************" << endl;
+  cout << "*******************************************************************************\n" << endl;
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2::ConstructDetector()
+{
+
+  SpdParameter* par;
+  SpdRsTEC2GeoMapper* mapper = dynamic_cast<SpdRsTEC2GeoMapper*>(fGeoMapper);
+  if (!mapper) return;
+
+  Int_t nsectors 		= mapper->GetNSectors();		//8;
+  Double_t rsInnerRadius 	= mapper->GetModuleInnerRadius();	//20.0/2;
+  Double_t rsOuterRadius 	= mapper->GetModuleOuterRadius(); 	//628.8/2.;
+  Double_t rsThickness 		= mapper->GetModuleThickness();		//139.0;
+
+  fModule = BuildModule("ECVol", mapper->GetBaseMaterial(),                         
+		  	nsectors, rsInnerRadius, rsOuterRadius, rsThickness);
+
+  if (!fModule) 
+  {       
+      cout << "-E- <SpdRsTEC2::ConstructGeometry> "            
+	   << "Volume " << fModule->GetName() << " cannot be created " << endl;       
+      return;   
+  }
+
+  fModule->SetFillColor(kGreen);   
+  fModule->SetLineColor(kGreen);   
+  fModule->SetTransparency(40); 
+
+  /*-----------------------------------------------------------*/
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  Int_t nLayers = mapper->GetNLayers();
+
+  // Add bottom layer (absrober(6.0cm) + mdt detectors(3.5cm))
+  fModule->AddNode(CreateFirstLayer(rsInnerRadius, rsOuterRadius, 0.5*rsThickness), 1, 
+                   new TGeoCombiTrans("",  0, 0, 0, rotNoRot));
+     
+  // Add regular layers (3.0cm absorber + 3.5cm mdt detectors)
+  for (Int_t i=2; i < nLayers+1; ++i) {   
+      fModule->AddNode(CreateRegularLayer(i, rsInnerRadius, rsOuterRadius, 0.5*rsThickness), i, 
+                       new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+  }
+
+  // Add top absorber (6.0cm)
+  fModule->AddNode(CreateLastLayer(nLayers+1, rsInnerRadius, rsOuterRadius, 0.5*rsThickness), nLayers+1, 
+                   new TGeoCombiTrans("", 0, 0, 0, rotNoRot));
+
+  /*-----------------------------------------------------------*/
+
+  Double_t mindist       = mapper->GetDist();       
+  Double_t angle	 = mapper->GetSecAngleOver2(); //pi/8    
+ 
+  Double_t shift = mindist+0.5*rsThickness;  // z-shift    
+  
+  TGeoTranslation trans;   
+  TGeoRotation rot;     
+  
+  rot.RotateZ(45+angle);     
+  trans.SetTranslation(0,0,shift);
+  fMasterVolume->AddNode(fModule,1,new TGeoCombiTrans(trans, rot));   
+  
+  trans.SetTranslation(0,0,-shift);   
+  rot.RotateX(180);
+  fMasterVolume->AddNode(fModule,2,new TGeoCombiTrans(trans, rot));   
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdRsTEC2::BuildModule(const char* name, TString mat, 
+				   Int_t nsectors, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness) 
+{   
+
+  TGeoMedium* material = FindMedium(mat,"air");
+
+  if (!material) {       
+      cout << "-E- <SpdRsTEC2::BuildModule> "             
+	   << "Unknown material: " << mat << endl;       
+      return 0;   
+  }
+
+  TGeoVolume* vol = gGeoManager->MakePgon(name, material, 0, 360, nsectors, 2);
+  TGeoPgon* pgon = (TGeoPgon*)vol->GetShape();
+  pgon->DefineSection(0, -0.5*rsThickness, rsInnerRadius, rsOuterRadius);
+  pgon->DefineSection(1,  0.5*rsThickness, rsInnerRadius, rsOuterRadius);
+  
+  return vol;
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdRsTEC2::CreateFirstLayer(Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness) 
+{
+  //
+  // Creates polygon representing bottom layer of the RS EC part
+  // (6.0cm thick iron absorber and a layer of MDT detectors)
+  // Parameters: 1. Inner radius of RS from collision point / tube radius (rsInnerRadius)
+  //             2. Outer radius of RS from collision point (rsOuterRadius)
+  //             3. Thickness of RS EC rsThickness
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //
+  SpdRsTEC2GeoMapper* mapper = dynamic_cast<SpdRsTEC2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTEC2::CreateFirstLayer> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+
+  Double_t layerThickness = 6.0+3.5; //cm
+
+  Double_t widthEnv = 8.5; //cm xAxis
+  Double_t thicknessEnv = 1.64; //cm zAxis
+
+  TString mat;
+
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium* pair = FindMedium(mat,"");
+
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");
+
+   //Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  TGeoRotation* rotMDTRot = new TGeoRotation("rotMDTRot", 45./2, 90, 0); 
+  rotMDTRot->RegisterYourself();
+
+  TGeoPgon* Layer_EC_Shape = new TGeoPgon("Layer_EC_Shape", 0, 360, 8, 2);
+  Layer_EC_Shape->DefineSection(0, -rsThickness, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Shape->DefineSection(1, -rsThickness+layerThickness, rsInnerRadius, rsOuterRadius);
+
+  //cout << "1 layer: " << -rsThickness << "    " << -rsThickness + layerThickness << endl;
+
+  TGeoVolume* Layer_EC_Vol = new TGeoVolume("LayerECVol", Layer_EC_Shape, pair);
+
+  TGeoPgon* Layer_EC_Abs_Base_Shape = new TGeoPgon("Layer_EC_Abs_Base_Shape", 0, 360, 8, 2);
+  Layer_EC_Abs_Base_Shape->DefineSection(0, -rsThickness, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Abs_Base_Shape->DefineSection(1, -rsThickness+6.0, rsInnerRadius, rsOuterRadius);
+
+  TGeoVolume* Layer_EC_Abs_Base_Vol = new TGeoVolume("LayerECAbsBaseVol", Layer_EC_Abs_Base_Shape, piron);
+  Layer_EC_Vol->AddNode(Layer_EC_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, 0, rotNoRot)); //
+
+
+  Int_t Nenvelopes = Int_t((rsOuterRadius-rsInnerRadius)/widthEnv);
+  Double_t shift = 0.5*(rsOuterRadius - rsInnerRadius - Nenvelopes*widthEnv);
+
+  Double_t minMDTsize = (rsOuterRadius)*(sqrt(2.0)-1.0); // min size of MDT
+  Int_t Nenvelopes_MDTvar = Int_t((rsOuterRadius-minMDTsize)/widthEnv); // number of MDTs with varying sizes
+
+  Double_t Layer_Envelope_startX = -rsOuterRadius+shift;
+  Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+
+
+  Double_t rotX = TMath::Cos(((Double_t)1)*TMath::ACos(-1.0)/8.0);
+  Double_t rotY = TMath::Sin(((Double_t)1)*TMath::ACos(-1.0)/8.0);
+
+  Double_t smMDT = minMDTsize;
+  Int_t NumberOfMDT = 1;
+  for (UInt_t i(0); i<Nenvelopes_MDTvar; i++) 
+  {
+      Layer_EC_Vol->AddNode(CreateMDT(int(2*smMDT)), NumberOfMDT, 
+                            new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, -rsThickness+6.0+3.5/2, rotMDTRot));
+
+      smMDT = Layer_Envelope_shiftX + (rsOuterRadius + minMDTsize); // y = x + b
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  for (UInt_t i=Nenvelopes_MDTvar; i<Nenvelopes; i++) 
+  {
+      Layer_EC_Vol->AddNode(CreateMDT(2*(rsOuterRadius-10)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, -rsThickness+6.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+
+  }
+
+  Layer_Envelope_shiftX = -(Layer_Envelope_shiftX - widthEnv);
+  for (UInt_t i=Nenvelopes_MDTvar; i<Nenvelopes; i++) 
+  {
+      Layer_EC_Vol->AddNode(CreateMDT(2*(rsOuterRadius-10)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, -rsThickness+6.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  for (UInt_t i=0; i<Nenvelopes_MDTvar; i++) 
+  {
+      smMDT = -Layer_Envelope_shiftX-widthEnv + (rsOuterRadius + minMDTsize); // y = -x + b
+      Layer_EC_Vol->AddNode(CreateMDT(int(2*smMDT)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, -rsThickness+6.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  Layer_EC_Abs_Base_Vol->SetFillColor(fAbsorbColor);   
+  Layer_EC_Abs_Base_Vol->SetLineColor(fAbsorbColor);   
+  Layer_EC_Abs_Base_Vol->SetTransparency(40);      
+  
+  Layer_EC_Vol->SetFillColor(fBaseColor);   
+  Layer_EC_Vol->SetLineColor(fBaseColor);   
+  Layer_EC_Vol->SetTransparency(40);  
+
+  return Layer_EC_Vol;
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdRsTEC2::CreateRegularLayer(Int_t layerN, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness) 
+{
+  //
+  // Creates trapezoid representing regular layer of the RS EC part
+  // (3.0cm thick iron absorber and a layer of MDT detectors)
+  // Parameters: 1. Number of layer in a sector
+  //             2. Inner radius of RS from collision point / tube radius (rsInnerRadius)
+  //             3. Outer radius of RS from collision point (rsOuterRadius)
+  //             4. Thickness of RS EC rsThickness
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //
+  SpdRsTEC2GeoMapper* mapper = dynamic_cast<SpdRsTEC2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTEC2::CreateRegularLayer> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+
+  TString mat;
+
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium* pair = FindMedium(mat,"");
+
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");
+
+  Double_t layerThickness = 3.0+3.5; //cm
+  Double_t widthEnv = 8.5; //cm xAxis
+  Double_t thicknessEnv = 1.64; //cm zAxis
+
+   //Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  TGeoRotation* rotMDTRot = new TGeoRotation("rotMDTRot", 45./2, 90, 0); // 
+  rotMDTRot->RegisterYourself();
+
+  Double_t shiftZ = -rsThickness + 9.5 + (layerN-2)*layerThickness;
+
+  TGeoPgon* Layer_EC_Shape = new TGeoPgon("Layer_EC_Shape", 0, 360, 8, 2);
+  Layer_EC_Shape->DefineSection(0, shiftZ, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Shape->DefineSection(1, shiftZ + layerThickness, rsInnerRadius, rsOuterRadius);
+
+  //cout << layerN << " layer: " << shiftZ << "    " <<  shiftZ + layerThickness << endl;
+
+  TGeoVolume* Layer_EC_Vol = new TGeoVolume("LayerECVol", Layer_EC_Shape, pair);
+
+
+  TGeoPgon* Layer_EC_Abs_Base_Shape = new TGeoPgon("Layer_EC_Abs_Base_Shape", 0, 360, 8, 2);
+  Layer_EC_Abs_Base_Shape->DefineSection(0, shiftZ, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Abs_Base_Shape->DefineSection(1, shiftZ + 3, rsInnerRadius, rsOuterRadius);
+
+  TGeoVolume* Layer_EC_Abs_Base_Vol = new TGeoVolume("LayerECAbsBaseVol", Layer_EC_Abs_Base_Shape, piron);
+  Layer_EC_Vol->AddNode(Layer_EC_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, 0, rotNoRot)); //
+
+
+  Int_t Nenvelopes = Int_t((rsOuterRadius-rsInnerRadius)/widthEnv);
+  Double_t shift = 0.5*(rsOuterRadius - rsInnerRadius - Nenvelopes*widthEnv);
+
+  Double_t minMDTsize = (rsOuterRadius)*(sqrt(2.0)-1.0); // min size of MDT
+  Int_t Nenvelopes_MDTvar = Int_t((rsOuterRadius-minMDTsize)/widthEnv); // number of MDTs with varying sizes
+
+  Double_t Layer_Envelope_startX;
+
+  if (layerN % 2 == 0) { Layer_Envelope_startX = -rsOuterRadius+shift; }
+  else 
+  {
+      shift = shift + 0.5; //shift for half of the size MPD cell
+      Layer_Envelope_startX = -rsOuterRadius+shift;
+  }
+
+
+  Double_t rotX = TMath::Cos(((Double_t)1)*TMath::ACos(-1.0)/8.0);
+  Double_t rotY = TMath::Sin(((Double_t)1)*TMath::ACos(-1.0)/8.0);
+
+  Double_t Layer_Envelope_shiftX = Layer_Envelope_startX + widthEnv/2;
+
+  Double_t smMDT = minMDTsize;
+  Int_t NumberOfMDT = 1;
+  for (UInt_t i=0; i<Nenvelopes_MDTvar; i++) 
+  {
+      Layer_EC_Vol->AddNode(CreateMDT(int(2*smMDT)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, shiftZ+3.0+3.5/2, rotMDTRot));
+
+      smMDT = Layer_Envelope_shiftX + (rsOuterRadius + minMDTsize); // y = x + b
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  for (UInt_t i=Nenvelopes_MDTvar; i<Nenvelopes; i++) 
+  {
+
+      Layer_EC_Vol->AddNode(CreateMDT(2*(rsOuterRadius-10)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, shiftZ+3.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+
+  }
+
+  Layer_Envelope_shiftX = -(Layer_Envelope_shiftX - widthEnv);
+  for (UInt_t i=Nenvelopes_MDTvar; i<Nenvelopes; i++) 
+  {
+
+      Layer_EC_Vol->AddNode(CreateMDT(2*(rsOuterRadius-10)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, shiftZ+3.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  for (UInt_t i=0; i<Nenvelopes_MDTvar; i++) 
+  {
+
+      smMDT = -Layer_Envelope_shiftX-widthEnv + (rsOuterRadius + minMDTsize); // y = -x + b
+      Layer_EC_Vol->AddNode(CreateMDT(int(2*smMDT)), NumberOfMDT, new TGeoCombiTrans("", Layer_Envelope_shiftX*rotX, Layer_Envelope_shiftX*rotY, shiftZ+3.0+3.5/2, rotMDTRot));
+      Layer_Envelope_shiftX = Layer_Envelope_shiftX + widthEnv;
+      NumberOfMDT++;
+  }
+
+  Layer_EC_Abs_Base_Vol->SetFillColor(fAbsorbColor);
+  Layer_EC_Abs_Base_Vol->SetLineColor(fAbsorbColor);
+  Layer_EC_Abs_Base_Vol->SetTransparency(40);
+
+  Layer_EC_Vol->SetFillColor(fBaseColor);
+  Layer_EC_Vol->SetLineColor(fBaseColor);
+  Layer_EC_Vol->SetTransparency(40);
+
+  return Layer_EC_Vol;
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdRsTEC2::CreateLastLayer(Int_t layerN, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness) 
+{
+  //
+  // Creates trapezoid representing top layer of the RS EC part
+  // (6.0cm thick iron absorber and no layer of MDT detectors)
+  // Parameters: 1. Number of layer in a sector
+  //             2. Inner radius of RS from collision point / tube radius (rsInnerRadius)
+  //             3. Outer radius of RS from collision point (rsOuterRadius)
+  //             4. Thickness of RS EC rsThickness
+  // Returns: TGeoVolume object of the layer with absorber and MDTs.
+  //
+  SpdRsTEC2GeoMapper* mapper = dynamic_cast<SpdRsTEC2GeoMapper*>(fGeoMapper);
+  if (!mapper) {
+      cout << "-E- <SpdRsTEC2::CreateLastLayer> Unknown mapper: " << mapper->ClassName() << endl;
+      return 0;
+  }
+
+  TString mat;
+
+  mat = mapper->GetBaseMaterial();
+  TGeoMedium* pair = FindMedium(mat,"");
+
+  mat = mapper->GetAbsorbMaterial();
+  TGeoMedium   *piron = FindMedium(mat,"");
+
+  Double_t layerThickness = 6.0; //cm
+
+
+   //Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  Double_t shiftZ = -rsThickness + 9.5 + (layerN-2)*6.5;
+
+  TGeoPgon* Layer_EC_Shape = new TGeoPgon("Layer_EC_Shape", 0, 360, 8, 2);
+  Layer_EC_Shape->DefineSection(0, shiftZ, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Shape->DefineSection(1, shiftZ + layerThickness, rsInnerRadius, rsOuterRadius);
+
+  //cout<<"Last layer: " << shiftZ << "    " <<  shiftZ + layerThickness << endl;
+
+  TGeoVolume* Layer_EC_Vol = new TGeoVolume("LayerECVol", Layer_EC_Shape, pair);
+
+
+  TGeoPgon* Layer_EC_Abs_Base_Shape = new TGeoPgon("Layer_EC_Abs_Base_Shape", 0, 360, 8, 2);
+  Layer_EC_Abs_Base_Shape->DefineSection(0, shiftZ, rsInnerRadius, rsOuterRadius);
+  Layer_EC_Abs_Base_Shape->DefineSection(1, shiftZ + layerThickness, rsInnerRadius, rsOuterRadius);
+
+  TGeoVolume* Layer_EC_Abs_Base_Vol = new TGeoVolume("LayerECAbsBaseVol", Layer_EC_Abs_Base_Shape, piron);
+  Layer_EC_Vol->AddNode(Layer_EC_Abs_Base_Vol, 1, new TGeoCombiTrans("", 0, 0, 0, rotNoRot)); //
+
+  Layer_EC_Abs_Base_Vol->SetFillColor(fAbsorbColor);
+  Layer_EC_Abs_Base_Vol->SetLineColor(fAbsorbColor);
+  Layer_EC_Abs_Base_Vol->SetTransparency(40);
+
+  Layer_EC_Vol->SetFillColor(fBaseColor);
+  Layer_EC_Vol->SetLineColor(fBaseColor);
+  Layer_EC_Vol->SetTransparency(40);
+
+  return Layer_EC_Vol;
+}
+
+//_____________________________________________________________________________________
+TGeoVolume* SpdRsTEC2::CreateMDT(Double_t length) 
+{
+  //
+  // Creates MDT of given length;
+  // Envelope Dimensions(L x W x H): length x 8.5cm x 1.64cm.
+  // Note: Adopted from Panda Muon System
+  //
+  SpdRsTEC2GeoMapper* mapper = dynamic_cast<SpdRsTEC2GeoMapper*>(fGeoMapper);   
+  if (!mapper) {       
+      cout << "-E- <SpdRsTEC2::CreateMDT> Unknown mapper: " << mapper->ClassName() << endl;       
+      return 0;   
+  } 
+
+   TString mat;     
+   
+   mat = mapper->GetBaseMaterial();   
+   TGeoMedium* pair = FindMedium(mat,"");     
+   
+   mat = mapper->GetActiveMaterialMDT();   
+   TGeoMedium* pMDTMixture = FindMedium(mat,"");      
+   
+   mat = mapper->GetPassiveMaterialMDT();   
+   TGeoMedium* paluminium = FindMedium(mat,"");
+
+  // Shapes and volumes ---------------------------------------------------------------
+  // General dimensions
+  Double_t widthEnv = 8.5; //cm xAxis
+  Double_t thicknessEnv = 1.64; //cm zAxis
+  Double_t xSize = 1.0;
+
+  TString transName;
+  Int_t Nenvelopes;
+  Int_t IncEnv = 0;
+
+  //Matrices
+  TGeoRotation* rotNoRot = new TGeoRotation("rotNoRot", 0., 0., 0.);
+  rotNoRot->RegisterYourself();
+
+  Double_t empty_value = (2.0+2.0+8.5)+6.5*2;
+  Double_t L_MDT_Envelope = length; //493.0;
+  Double_t L_MDT_Envelope_sensitive = L_MDT_Envelope-empty_value;
+
+
+  Int_t ind = int(length*10);
+
+  //Shapes
+  TGeoBBox* Indent20_Shape   	= new TGeoBBox("Indent20_Shape", widthEnv/2, thicknessEnv/2,  1.0);   
+  TGeoBBox* FEB_box_Shape    	= new TGeoBBox("FEBbox_Shape",  widthEnv/2, thicknessEnv/2,  widthEnv/2);   
+  TGeoBBox* DeadMat_Shape    	= new TGeoBBox("DeadMat_Shape",  4.07, 0.515,  3.25); 
+
+  TGeoVolume* Indent20_Vol   	= new TGeoVolume("Indent20Vol", Indent20_Shape, pair);
+  TGeoVolume* FEB_box_Vol    	= new TGeoVolume("FEBboxVol", FEB_box_Shape, pair);
+  TGeoVolume* DeadMat_Vol    	= new TGeoVolume("DeadMatVol", DeadMat_Shape, pMDTMixture);
+
+  //---------------------------------------     
+  
+  TGeoBBox* L_Al_A_Shape     	= new TGeoBBox(Form("L%d_Al_A_Shape",ind),    4.03, 0.03, L_MDT_Envelope_sensitive/2);   
+  TGeoBBox* L_Al_B_Shape     	= new TGeoBBox(Form("L%d_Al_B_Shape",ind),    0.03, 0.42, L_MDT_Envelope_sensitive/2);   
+  TGeoBBox* L_GasCell_Shape  	= new TGeoBBox(Form("L%d_GasCell_Shape",ind), 0.47, 0.46, L_MDT_Envelope_sensitive/2);   
+  TGeoBBox* L_Cell_Shape     	= new TGeoBBox(Form("L%d_Cell_Shape",ind),    0.5,  0.46, L_MDT_Envelope_sensitive/2);   
+  TGeoBBox* L_MDT_S_Shape    	= new TGeoBBox(Form("L%d_MDT_S_Shape",ind),   4.0,  0.46, L_MDT_Envelope_sensitive/2); 
+  TGeoBBox* L_Envelope_Shape 	= new TGeoBBox(Form("L%d_Envelope_Shape",ind), widthEnv/2, thicknessEnv/2, L_MDT_Envelope/2);
+
+  //Volumes
+  TGeoVolume* L_Al_A_Vol      = new TGeoVolume(Form("L%dAlAVol",ind), L_Al_A_Shape, paluminium);
+  TGeoVolume* L_Al_B_Vol 	= new TGeoVolume(Form("L%dAlBVol",ind), L_Al_B_Shape, paluminium);
+  TGeoVolume* L_GasCell_Vol 	= new TGeoVolume(Form("L%dGasCellVol",ind), L_GasCell_Shape, pMDTMixture);
+  TGeoVolume* L_Cell_Vol 	= new TGeoVolume(Form("L%dCellVol",ind), L_Cell_Shape, pMDTMixture);
+  TGeoVolume* L_MDT_S_Vol 	= new TGeoVolume(Form("L%dMDTSVol",ind), L_MDT_S_Shape, pMDTMixture);
+  TGeoVolume* L_Envelope_Vol 	= new TGeoVolume(Form("L%dEnvelopeVol",ind), L_Envelope_Shape, pair);
+
+  // Volume hierarchy -----------------------------------------------------------------
+  //Structure
+  //GasCell and Al_B in Cell
+  L_Cell_Vol->AddNode(L_GasCell_Vol, 1,
+                          new TGeoCombiTrans("", -0.03, 0, 0, rotNoRot));
+  L_Cell_Vol->AddNode(L_Al_B_Vol, 1,
+                          new TGeoCombiTrans("", 0.47, -0.04, 0, rotNoRot));
+
+  //8 Cells in MDT_S
+  const Int_t NCells = 8;
+  for (UInt_t i(0); i<NCells; i++) {
+      transName.Form("trans_cell_%d", i);
+      TGeoCombiTrans* trans1 = new TGeoCombiTrans(transName.Data(), -4.0 + xSize/2. + (Double_t)i*xSize, 0, 0., rotNoRot);
+      trans1->RegisterYourself();
+      L_MDT_S_Vol->AddNode(L_Cell_Vol, i+1, trans1);
+  }
+
+  L_Envelope_Vol->AddNode(Indent20_Vol, 1,
+                              new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2 - 1.0, rotNoRot));
+  L_Envelope_Vol->AddNode(Indent20_Vol, 2,
+                              new TGeoCombiTrans("", 0, 0, 1.0 - L_MDT_Envelope/2, rotNoRot));
+  L_Envelope_Vol->AddNode(FEB_box_Vol, 1,
+                              new TGeoCombiTrans("", 0, 0, L_MDT_Envelope/2-2.0-8.5*0.5, rotNoRot));
+  L_Envelope_Vol->AddNode(DeadMat_Vol, 1,
+                              new TGeoCombiTrans("", 0, 0, ((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(DeadMat_Vol, 2,
+                              new TGeoCombiTrans("", 0, 0, -((L_MDT_Envelope-(2.0+2.0+8.5))-6.5)/2-widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_Al_A_Vol, 1,
+                              new TGeoCombiTrans("", 0, -0.36, -widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_Al_B_Vol, 1,
+                              new TGeoCombiTrans("", -4.0, 0.09, -widthEnv/2, rotNoRot));
+  L_Envelope_Vol->AddNode(L_MDT_S_Vol, 1,
+                              new TGeoCombiTrans("", 0.03, 0.13, -widthEnv/2, rotNoRot));
+  
+  L_Envelope_Vol->SetFillColor(kGreen+1);
+  L_Envelope_Vol->SetLineColor(kGreen+1);
+  L_Envelope_Vol->SetTransparency(30);   
+
+  AddSensitiveVolume(L_GasCell_Vol); //ATTENTION FIXME ATTENTION
+
+  return L_Envelope_Vol;
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+SpdGeoMapper* SpdRsTEC2::GetMapper() 
+{
+  if (fGeoMapper) return fGeoMapper;
+  
+  SpdGeoFactory* factory = SpdGeoFactory::Instance();
+ 
+  // search for mapper
+  fGeoMapper = factory->SearchForMapper("SpdRsTEC2GeoMapper");
+  
+  // create default mapper
+  if (!fGeoMapper) fGeoMapper = factory->Mapper("SpdRsTEC2GeoMapper");
+     
+  return fGeoMapper;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdRsTEC2::LoadParsFrom(SpdParSet* params) 
+{
+  if (!params) return kFALSE;
+ 
+  if (!SpdDetector::LoadParsFrom(params)) return kFALSE;
+ 
+  TString mapper;
+  params->GetParameter("Mapper",mapper); 
+  fGeoMapper = SpdGeoFactory::Instance()->Mapper(mapper);  
+  if (fGeoMapper) fGeoMapper->LoadParametersFrom(params);
+  
+  fOutDataPointObject = "unknown";
+ 
+  if (fNDataOut < 1) return kTRUE;
+
+  params->GetParameter("Detector/NOutData_1",fOutDataPointObject);
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________________
+TString SpdRsTEC2::GetDataOut(Int_t n) const 
+{ 
+  if (n < 0 || n >= fNDataOut) return "unknown";
+  return fOutDataPointObject;
+}
+
+
+//_____________________________________________________________________________________
+TClonesArray* SpdRsTEC2::GetCollection(Int_t iColl) const 
+{ 
+   return (iColl == 0) ? fPointCollection : 0; 
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________________
+Double_t SpdRsTEC2::GetCapacity() const 
+{ 
+   // return (fModule) ? fModule->GetShape()->Capacity() : 0;
+   return 0;
+}
+   
+//_____________________________________________________________________________________
+Double_t SpdRsTEC2::GetMass() const 
+{ 
+   return (fModule) ? GetCapacity()*GetDensity() : 0;
+}
+
+//_____________________________________________________________________________________
+Double_t SpdRsTEC2::GetDensity() const 
+{   
+   return (fModule) ? fModule->GetMaterial()->GetDensity() : 0; 
+} 
+
+//_____________________________________________________________________________________ 
+TString SpdRsTEC2::GetMaterialName() const // private
+{ 
+   return (fModule) ? fModule->GetMaterial()->GetName() : "";
+}
+
+//_____________________________________________________________________________
+void SpdRsTEC2::Print(Option_t*) const
+{
+   SpdDetector::Print("");
+   
+   if (!fGeoMapper) return;
+   
+   TString divider('-',150);
+   
+   cout << "\n";
+
+   fGeoMapper->Print("");
+
+   cout << "\n";
+   cout <<"\tCapacity (total):    " << GetCapacity()*1e-6 << " [m^3] " << endl;
+   cout <<"\tMass (total):        " << GetMass()*1e-3 << " [kg] " << endl;
+   cout <<"\tDensity (averaged):  " << GetDensity() << " [g/cm^3] " << endl;
+   cout << "\n";
+
+   cout << "\n" << divider.Data() << "\n";       
+   printf("%6s %4s %15s %14s %14s %14s \n\n",           
+	  "Type","N","Material","Dens [g/cm^3]","Volume [m^3]","Mass [kg]"          
+	 );       
+   
+   if (!fModule) {        
+       cout << "\n";        
+       return;    
+   }
+
+   printf("%6d %4d %15s %14.6f %14.6f %14.6f \n",            
+	   1, 1, GetMaterialName().Data(),            
+	   GetDensity(), GetCapacity()*1e-6, GetMass()*1e-3);       
+   
+   cout << divider.Data() << "\n";       
+   
+   printf("%6s %35s %14.3e %14.3e \n","TOTAL:","",GetCapacity()*1e-6,GetMass()*1e-3);        
+   
+   cout << divider.Data() << "\n";       
+   
+   cout << "\n";
+
+}
+
+
diff --git a/rst/ecps/SpdRsTEC2.h b/rst/ecps/SpdRsTEC2.h
new file mode 100644
index 0000000000000000000000000000000000000000..75d4d3aba36643d5427f9f9409a324b55a547757
--- /dev/null
+++ b/rst/ecps/SpdRsTEC2.h
@@ -0,0 +1,102 @@
+
+#ifndef __SPDRSTEC2_H__
+#define __SPDRSTEC2_H__
+
+#include <TLorentzVector.h>
+#include <TString.h>
+
+#include "SpdDetector.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTEC2                                                                   //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class FairVolume;
+class TClonesArray;
+
+class SpdRsTEC2: public SpdDetector { 
+
+public:
+
+    SpdRsTEC2(const char* Name, Bool_t Active);
+    SpdRsTEC2();
+  
+    virtual ~SpdRsTEC2();
+  
+    virtual void  Initialize();
+    virtual void  Reset();
+    virtual void  Register();
+    
+    virtual Bool_t ProcessHits(FairVolume* v = 0);
+    
+    virtual TString GetDataOut(Int_t n) const;
+    virtual TClonesArray* GetCollection(Int_t iColl) const;
+    
+    virtual Double_t GetCapacity() const;  // cm^3
+    virtual Double_t GetMass()     const;  // g
+    virtual Double_t GetDensity()  const;  // g/cm^3
+
+    virtual SpdGeoMapper* GetMapper();
+
+    virtual void ConstructGeometry();
+         
+    virtual void  EndOfEvent();
+    virtual void  FinishRun();
+    
+    virtual Bool_t LoadParsFrom(SpdParSet* params);
+    
+    virtual void  Print(Option_t*) const;
+      
+private:
+  
+    void AddHit();
+    
+    /* Track information to be stored until the track leaves the active volume. */
+    
+    Int_t          fTrackID;           //!  track index
+    Int_t          fVolumeID;          //!  volume id (detector id)
+    TString        fVolumePath;        //!  full path to current volume
+    TLorentzVector fPos;               //!  position at entrance
+    TLorentzVector fMom;               //!  momentum at entrance
+    TLorentzVector fPosOut;            //!  position at exit
+    TLorentzVector fMomOut;            //!  momentum at exit
+    Double32_t     fTime;              //!  time
+    Double32_t     fTimeOut;           //!  time at exit
+    Double32_t     fLength;            //!  length
+    Double32_t     fSegmentLength;     //!  length of segment
+    Double32_t     fELoss;             //!  energy loss
+
+    /* containers for data */
+    
+    TString        fOutDataPointObject; //!
+    TClonesArray*  fPointCollection;    //!
+    
+    SpdRsTEC2(const SpdRsTEC2&);
+    SpdRsTEC2& operator=(const SpdRsTEC2&);
+    
+    /* GEOMETRY */
+
+    TGeoVolume* fModule; //!  
+    
+    TGeoVolume* BuildModule(const char* name, TString mat,
+                            Int_t nsectors, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness);
+    TGeoVolume* CreateFirstLayer(Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness);
+    TGeoVolume* CreateRegularLayer(Int_t layerN, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness);
+    TGeoVolume* CreateLastLayer(Int_t layerN, Double_t rsInnerRadius, Double_t rsOuterRadius, Double_t rsThickness);
+    TGeoVolume* CreateMDT(Double_t length);
+     
+    void ConstructDetector();
+    
+    TString  GetMaterialName() const;
+
+    Int_t   fBaseColor;   // (air)     
+    Int_t   fAbsorbColor; // (iron)
+
+    ClassDef(SpdRsTEC2,1)
+};
+
+#endif /* __SPDRSTEC2_H__ */
diff --git a/rst/ecps/SpdRsTEC2Point.cxx b/rst/ecps/SpdRsTEC2Point.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bda212272684050bb6d5ec929737e84a6a2d99f6
--- /dev/null
+++ b/rst/ecps/SpdRsTEC2Point.cxx
@@ -0,0 +1,78 @@
+// $Id$
+// Author: alver   2020/07/16
+
+#include "SpdRsTEC2Point.h"
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+ClassImp(SpdRsTEC2Point)
+
+//_____________________________________________________________________________________
+SpdRsTEC2Point::SpdRsTEC2Point():FairMCPoint(),fHitGeoPath("") 
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2Point::SpdRsTEC2Point(Int_t trackID, Int_t detID,
+                           TVector3 pos, TVector3 mom, Double_t tof, 
+                           Double_t length, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fHitGeoPath("")
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2Point::SpdRsTEC2Point(Int_t trackID, Int_t detID, TString hpath,
+                           TVector3 pos, TVector3 mom, Double_t tof, 
+                           Double_t length, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fHitGeoPath("")
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2Point::SpdRsTEC2Point(Int_t trackID, Int_t detID, TString hpath,
+                             TVector3 pos, TVector3 mom, TVector3 posOut, TVector3 momOut,
+                             Double_t tof, Double_t tofOut, 
+			     Double_t length, Double_t segmentlength, Double_t eLoss)
+:FairMCPoint(trackID, detID, pos, mom, tof, length, eLoss), 
+fHitGeoPath(hpath),
+fPosOut(posOut),
+fMomOut(momOut),
+fTimeOut(tofOut),
+fSegmentLength(segmentlength)
+{
+  
+}
+
+//_____________________________________________________________________________________
+SpdRsTEC2Point::~SpdRsTEC2Point() 
+{ 
+  
+}
+
+//_____________________________________________________________________________________
+void SpdRsTEC2Point::Print(const Option_t* opt) const
+{
+  cout << "<SpdRsTECPoint::Print> " << endl; 
+  cout << "\n";
+  cout << " Track/DetectorID:   " << fTrackID << "/" << fDetectorID << endl;
+  cout << " Hit node path:      " << fHitGeoPath << endl;
+  cout << " Position, Time In:  " << fX << ", " << fY << ", " << fZ << " [cm]  " 
+                                  << fTime << " [ns] " << endl;
+  cout << " Position, Time Out: " << fPosOut.X() << ", " << fPosOut.Y() << ", " << fPosOut.Z() << " [cm]  " << fTimeOut << " [ns] " << endl;
+  cout << " Momentum In:        " << fPx << ", " << fPy << ", " << fPz << " [GeV]" << endl;
+  cout << " Momentum Out:       " << fMomOut.X() << ", " << fMomOut.Y() << ", " << fMomOut.Z() << " [GeV]" << endl;
+  cout << " Energy loss:        " << fELoss*1.0e06 << " keV " << endl;
+  cout << "\n";
+}
+
+
+
+
diff --git a/rst/ecps/SpdRsTEC2Point.h b/rst/ecps/SpdRsTEC2Point.h
new file mode 100644
index 0000000000000000000000000000000000000000..6aed9b7d11d5854d41ff4f5f729c2994fdb57e24
--- /dev/null
+++ b/rst/ecps/SpdRsTEC2Point.h
@@ -0,0 +1,84 @@
+// $Id$
+// Author: alver   2020/07/16
+
+#ifndef __SPDRSTEC2POINT_H__
+#define __SPDRSTEC2POINT_H__ 
+
+#include "FairMCPoint.h"
+#include <TString.h>
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTEC2Point                                                              //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdRsTEC2Point : public FairMCPoint {
+
+public:
+  
+   /** Constructor with arguments
+   *@param trackID  Index of MCTrack
+   *@param detID    Detector ID
+   *@param modID    Module ID 
+   *@param submodID SubModule ID 
+   *@param pos      Ccoordinates at entrance to active volume [cm]
+   *@param mom      Momentum of track at entrance [GeV]
+   *@param posOut   Coordinates at exit to active volume [cm]
+   *@param momOut   Momentum of track at exit [GeV]   
+   *@param tof      Time since event start [ns]
+   *@param length   Track length since creation [cm]
+   *@param ELoss    Energy deposit [GeV]
+   **/
+  
+  SpdRsTEC2Point();
+  
+  SpdRsTEC2Point(Int_t trackID, Int_t detID, 
+                 TVector3 pos, TVector3 mom, 
+                 Double_t tof, Double_t length, Double_t ELoss);
+  
+  SpdRsTEC2Point(Int_t trackID, Int_t detID, TString hpath,
+                 TVector3 pos, TVector3 mom, 
+                 Double_t tof, Double_t length, Double_t ELoss);
+
+  SpdRsTEC2Point(Int_t trackID, Int_t detID,  TString hpath,
+                 TVector3 pos, TVector3 mom, TVector3 posOut, TVector3 momOut,
+                 Double_t tof, Double_t tofOut, 
+		 Double_t length, Double_t segmentlength, Double_t ELoss);
+  
+  SpdRsTEC2Point(const SpdRsTEC2Point& point) { *this = point; };
+
+  virtual ~SpdRsTEC2Point();
+  
+  inline void SetHitGeoPath(TString hpath) { fHitGeoPath = hpath; }
+
+  inline TString GetHitGeoPath() const { return fHitGeoPath;  }
+
+  virtual void Print(const Option_t* opt) const;
+  
+    /** Accessors **/
+  inline TVector3 GetPosIn()            const { return TVector3(fX, fY, fZ);    }
+  inline TVector3 GetMomIn()            const { return TVector3(fPx, fPy, fPz); }
+  inline TVector3 GetPosOut()           const { return fPosOut;                 }
+  inline TVector3 GetMomOut()           const { return fMomOut;                 }
+  inline Double_t GetSegmentLength() 	const { return fSegmentLength; 		}
+  inline Double_t GetTimeIn()  		const { return fTime;    		}   
+  inline Double_t GetTimeOut() 		const { return fTimeOut; 		} 
+protected:
+
+  TVector3 	fPosOut;
+  TVector3 	fMomOut;
+  Double32_t 	fTimeOut;                  // Time since event start at exit of detector [ns]
+  Double_t   	fSegmentLength;            // Trajectory segment length inside the detector, [cm]
+
+private:
+
+  TString  fHitGeoPath;
+
+  ClassDef(SpdRsTEC2Point,1)
+
+}; /* __SPDRSTEC2POINT_H__ */
+
+#endif
diff --git a/scripts/run.pbs b/scripts/run.pbs
deleted file mode 100644
index 8b9347542df0689618a507bc980cb3ed710aa79c..0000000000000000000000000000000000000000
--- a/scripts/run.pbs
+++ /dev/null
@@ -1,46 +0,0 @@
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-# SPDROOT FRAMEWORK 
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-#PBS -l cput=01:00:00
-#PBS -l walltime=01:00:00
-
-EVENTS=1
-
-#set output directory (SCRATCH)
-#OUTDIR=/scrc/u/avt/Projects/DATA/SIMU/spd
-OUTDIR=$PBS_O_WORKDIR
-
-#choosing output server
-SOUT=lxpub01
-
-#full path to folder spdroot were installed (AFS)
-SPDROOTPATH=/afs/jinr.ru/user/a/avt/spdroot
-
-#set input macro path (AFS)
-SPDMACROPATH=$SPDROOTPATH
-
-#-----------------------------------------
-
-cd $TMPDIR
-cp $SPDMACROPATH/macro/run_sim.C .
-cp $SPDROOTPATH/build/config.sh .   
-
-if test ! -e $TMPDIR/run_sim.C ; then
-   echo "ERROR: no $TMPDIR/run_sim.C"
-   ret=1
-fi
-if test ! -e $TMPDIR/config.sh ; then
-   echo "ERROR: no $TMPDIR/config.sh"
-   ret=1
-fi
-
-#[ ret > 0 ]; exit 1
-
-source config.sh
-
-root -b -q "run_sim.C($EVENTS)"
-
-scp -p2 *.root $SOUT:$OUTDIR/
-
-
diff --git a/scripts/spdrun.nx b/scripts/spdrun.nx
deleted file mode 100644
index 8bdf147c7172d23aaf54f45c810c0ec0f6e43691..0000000000000000000000000000000000000000
--- a/scripts/spdrun.nx
+++ /dev/null
@@ -1,34 +0,0 @@
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-# SPDROOT FRAMEWORK 
-#
-# the macro is provided only for scratch using (i.e. from /scrc/u/...)
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-#set number of RUNS
-NRUN=3
-
-#the files needed in current directory
-PBSSCRIPT=spdrun.pbs
-SPDMACRO=run_sim.C
-
-CDIR=$PWD
-
-PBSSCRIPTPATH=$CDIR
-SPDMACROPATH=$CDIR
-
-#-----------------------------------------
-
-for ((i=1; i <= NRUN; i++))
-do
- mkdir $CDIR/xrun_$i
- cd $CDIR/xrun_$i
- 
- cp $PBSSCRIPTPATH/$PBSSCRIPT .
- cp $SPDMACROPATH/$SPDMACRO .
- 
- qsub $PBSSCRIPT
- 
- #rm -f arun.pbs
- 
- cd $CDIR
-done
\ No newline at end of file
diff --git a/scripts/spdrun.pbs b/scripts/spdrun.pbs
deleted file mode 100644
index 83e45f32a695d184389bbc1600d9c17635fad722..0000000000000000000000000000000000000000
--- a/scripts/spdrun.pbs
+++ /dev/null
@@ -1,48 +0,0 @@
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-# SPDROOT FRAMEWORK 
-#
-# the macro is provided only for scratch using (i.e. from /scrc/u/...)
-#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-#PBS -l cput=99:00:00
-#PBS -l walltime=99:00:00
-
-#set number of events in the RUN
-EVENTS=1
-
-#full path to folder spdroot were installed (AFS)
-SPDROOTPATH=/afs/jinr.ru/user/a/avt/spdroot
-
-#choosing output server
-SOUT=lxpub01
-
-#set output directory (current directory, SCRATCH)
-OUTDIR=$PBS_O_WORKDIR
-
-#set input macro path (current directory, SCRATCH)
-SPDMACROPATH=$OUTDIR
-
-#-----------------------------------------
-
-cd $TMPDIR
-scp -p2 $SOUT:$SPDMACROPATH/run_sim.C .
-cp $SPDROOTPATH/build/config.sh .   
-
-if test ! -e $TMPDIR/run_sim.C ; then
-   echo "ERROR: no $TMPDIR/run_sim.C"
-   ret=1
-fi
-if test ! -e $TMPDIR/config.sh ; then
-   echo "ERROR: no $TMPDIR/config.sh"
-   ret=1
-fi
-
-#[ ret > 0 ]; exit 1
-
-source config.sh
-
-root -b -q "run_sim.C($EVENTS)"
-
-scp -p2 *.root $SOUT:$OUTDIR/
-
-
diff --git a/spddata/CMakeLists.txt b/spddata/CMakeLists.txt
index 9ac8329af746da2482e26ad51ab73eb829c4393b..ae358a79619f95db720f9407ab1395ebb880a69a 100644
--- a/spddata/CMakeLists.txt
+++ b/spddata/CMakeLists.txt
@@ -33,7 +33,7 @@ mcdata/SpdPrimGenData.cxx
 
 params/SpdParameter.cxx 
 params/SpdFieldPar.cxx
-params/SpdPassiveGeoPar.cxx
+params/SpdPassiveGeoParSet.cxx
 params/SpdBaseParSet.cxx
 params/SpdParSet.cxx
 params/SpdPrimGenParSet.cxx
@@ -50,11 +50,32 @@ kfdata/SpdKFSimpleRes.cxx
 
 )
 
-# Set(HEADERS 
-# 
-# SpdDetectorList.h
-# 
-# )
+Set(HEADERS 
+
+IdealTrackData/SpdIdealDataInfo.h
+IdealTrackData/SpdIdealHit.h
+IdealTrackData/SpdIdealSpacepointHit.h
+IdealTrackData/SpdIdealTrackColl.h
+IdealTrackData/SpdIdealTrack.h
+IdealTrackData/SpdIdealWirepointHit.h
+kfdata/SpdKFSimpleRes.h
+mcdata/SpdMCEventHeader.h
+mcdata/SpdMCTrack.h
+mcdata/SpdPrimGenData.h
+params/SpdBaseParSet.h
+params/SpdFieldPar.h
+params/SpdParameter.h
+params/SpdParSetContFact.h
+params/SpdParSet.h
+params/SpdPassiveGeoParSet.h
+params/SpdPrimGenParSet.h
+RWdata.h
+SpdDetectorList.h
+SpdGeopathParser.h
+#TrackData/SpdTrackCand.h
+#TrackData/SpdTrackCandHit.h
+#TrackData/SpdTrack.h
+)
 
 Set(LINKDEF SpdDataLinkDef.h)
 Set(LIBRARY_NAME SpdData)
diff --git a/spddata/IdealTrackData/SpdIdealDataInfo.cxx b/spddata/IdealTrackData/SpdIdealDataInfo.cxx
index 8cdb1244a7477b9e5d06bdb1f3a8ed45877dc40e..18fd3f65bcceffe663e26f4bd8c9d2eb9802c3f0 100644
--- a/spddata/IdealTrackData/SpdIdealDataInfo.cxx
+++ b/spddata/IdealTrackData/SpdIdealDataInfo.cxx
@@ -45,11 +45,11 @@ Int_t SpdIdealDataInfo::GetNHits() const
 //_____________________________________________________________________________
 void SpdIdealDataInfo::PrintInfo(TString opt) const
 {
-    
     if (opt == "short") {
         cout << "-I- <SpdIdealDataInfo::PrintInfo> " << fName << ", " << fTitle 
              << ";  module: " << fDetId << ";  hit type: " << fHitType
-             << ";  tracks/hits: " << GetNTracks() << "/" << GetNHits() << endl; 
+             << ";  tracks/hits: " << GetNTracks() << "/" << GetNHits() 
+             << endl; 
         return;
     }
         
diff --git a/spddata/IdealTrackData/SpdIdealHit.cxx b/spddata/IdealTrackData/SpdIdealHit.cxx
index 2a4ceb2fb5b038a9f98f1e1d2f87b6e56d2a3511..c4e42903f7ffa1bbbaa9612ef1b925b6326981a8 100644
--- a/spddata/IdealTrackData/SpdIdealHit.cxx
+++ b/spddata/IdealTrackData/SpdIdealHit.cxx
@@ -18,8 +18,8 @@ using std::endl;
 ClassImp(SpdIdealHit)
 
 //_____________________________________________________________________________
-SpdIdealHit::SpdIdealHit():FairTimeStamp(),
-fEdep(0.),fInfoNum(-1),fMotherPointNum(-1)
+SpdIdealHit::SpdIdealHit():FairTimeStamp(),fSpecifity('n'),
+fEdep(0.),fId(-1),fInfoNum(-1),fMotherPointNum(-1),fResolution(-1,-1,-1)
 {
   fDetId.assign(IDSIZE,0);
 }
@@ -38,35 +38,56 @@ void SpdIdealHit::Clear()
   fTimeStamp = -1.;
   fTimeStampError = -1.;
   
+  fId = -1;
   fInfoNum  = -1;
   fMotherPointNum = -1;
   
+  fTrackId.clear();
+  
   fDetId.assign(IDSIZE,0);
+  
+  fResolution.SetXYZ(-1,-1,-1);
 }
 
 //_____________________________________________________________________________
 void SpdIdealHit::SetDetId(Int_t i, Long_t id)
 {
-   if ( !(i < 0) && i < IDSIZE) fDetId[i] = id;
+   if (i < 0) return;
+    
+   if (i < IDSIZE) fDetId[i] = id;
+   else {
+       fDetId.resize(i+1,0);
+       fDetId[i] = id;
+   }
 }
 
 //_____________________________________________________________________________
 Long_t SpdIdealHit::GetDetId(Int_t i) const
 {
-   return ( !(i < 0) && i < IDSIZE) ? fDetId[i]: Int_t(kSpdUndefined);
+   if (i < 0) return Int_t(kSpdUndefined);
+   if (i < IDSIZE) return fDetId[i];
+   if (i < fDetId.size()) return fDetId[i];
+   return Int_t(kSpdUndefined);
 }
 
 //_____________________________________________________________________________
-void SpdIdealHit::PrintHit(Bool_t print_point) const
+void SpdIdealHit::PrintHit(Bool_t print_point, Bool_t print_res) const
 {
-   cout << "\t-I- <" << this->ClassName() << "::PrintHit>" << "\n";
-   cout << "\tDetector id:         " << fDetId[0] << " " << fDetId[1] << " " << fDetId[2] << endl;
+   cout << "\t<" << this->ClassName() << "::PrintHit>" << "\n\n";
+   cout << "\tHit unique ID:       " << fId << endl;
+   cout << "\tDetector id:         "; for (Int_t i(0); i<fDetId.size(); i++) { cout << fDetId[i] << " "; } cout << endl;
+   cout << "\tTrack id:            "; for (Int_t i(0); i<fTrackId.size(); i++) { cout << fTrackId[i] << " "; } cout << endl;
    cout << "\tInfo, mcpoint:       " << fInfoNum << ", " << fMotherPointNum << endl;
    cout << "\tEdep, Time:          " << fEdep << " [GeV],  " << fTimeStamp << " [ns] " << endl;
+   cout << "\tSpecifity:           " << fSpecifity << endl;
 
    if (print_point) {
        cout << "\tPoint(x,y,z):        " 
-            << GetPointX() << ", " << GetPointY() << ", " << GetPointZ() << " [cm] " << endl;
+            << fPoint.X() << ", " << fPoint.Y() << ", " << fPoint.Z() << " [cm] " << endl;
+   }
+   if (print_res) {
+       cout << "\tResolution:        " 
+            << fResolution.X() << ", " << fResolution.Y() << ", " << fResolution.Z() << " [cm] " << endl;
    }
    cout << "\n";
 }
diff --git a/spddata/IdealTrackData/SpdIdealHit.h b/spddata/IdealTrackData/SpdIdealHit.h
index 9a1566d2beb197b8bc17f19fe2403d50a3f58dea..66b9cb43e1799e6d585e96b8b37e72df55dd2885 100644
--- a/spddata/IdealTrackData/SpdIdealHit.h
+++ b/spddata/IdealTrackData/SpdIdealHit.h
@@ -34,42 +34,85 @@ public:
     virtual ~SpdIdealHit();
 
     void Clear();
+
+    // unable/disable methods (set/get)
+    virtual void   DisableHit(Bool_t disable) { fSpecifity = 'd'; }
+    virtual Bool_t IsHitDisabled() { return (fSpecifity == 'd'); }
     
     /* setters */
     
-    void SetDetId(Int_t i, Long_t id);
-    void SetEdep(Double_t edep)     { fEdep = edep; }
-    void SetInfoNum(Int_t n)        { fInfoNum = n; }
-    void SetMotherPointNum(Int_t n) { fMotherPointNum = n; }
+    virtual void  SetDetId(Int_t i, Long_t id);
+    virtual void  SetSpecifity(Char_t spec) { fSpecifity = spec; }
+    
+    void  SetEdep(Double_t edep)     { fEdep = edep; }
+    void  SetId(Int_t id)            { fId = id;     } 
+    void  SetInfoNum(Int_t n)        { fInfoNum = n; }
+    void  SetMotherPointNum(Int_t n) { fMotherPointNum = n; }
+    
+    void  AddTrackId(Int_t id) { fTrackId.push_back(id); }
     
-    virtual void SetPoint(Double_t /*x*/, Double_t /*y*/, Double_t /*z*/) {}
-    virtual void SetPoint(TVector3 /*point*/) {}
+    virtual void SetPoint(Double_t x, Double_t y, Double_t z) { fPoint.SetXYZ(x,y,z); }
+    virtual void SetPoint(TVector3 point) { fPoint = point; }
+    
+    virtual void SetHit(Double_t /*x*/, Double_t /*y*/, Double_t /*z*/) { }
+    virtual void SetHit(TVector3 /*hit*/) { }
+
+    virtual void SetResolution(Double_t r1, Double_t r2, Double_t r3) { fResolution.SetXYZ(r1,r2,r3); }
+    virtual void SetResolution(TVector3 res) { fResolution = res; }
     
     /* getters */
     
-    Long_t    GetDetId(Int_t i) const;
-    Double_t  GetEdep() const { return fEdep; }
-    Int_t     GetInfoNum() const { return fInfoNum; }
+    virtual Int_t  GetDetId() const { return Int_t(fDetId[0]); }
+    virtual Long_t GetDetId(Int_t i) const;
+    virtual Char_t GetSpecifity() const { return fSpecifity; }
+     
+    Double_t  GetEdep()           const { return fEdep; }
+    Int_t     GetId()             const { return fId; }
+    Int_t     GetInfoNum()        const { return fInfoNum; }
     Int_t     GetMotherPointNum() const { return fMotherPointNum; }
+   
+    virtual Bool_t    GetPoint(TVector3& point) const { point = fPoint;  return true; }
+    virtual TVector3  GetPoint()   const { return fPoint; }
     
-    virtual Double_t  GetPointX() const { return 0.; }
-    virtual Double_t  GetPointY() const { return 0.; }
-    virtual Double_t  GetPointZ() const { return 0.; }
+    Int_t  GetNTrakcs() const { return fTrackId.size(); }
+    Int_t  GetTrackId(Int_t i = 0) const { return (fTrackId.empty()) ? -1 : fTrackId[i]; }
     
-    virtual void      GetPoint(TVector3& point) const { point.SetXYZ(GetPointX(),GetPointY(),GetPointZ()); }
-    virtual TVector3  GetPoint() const { return TVector3(GetPointX(),GetPointY(),GetPointZ()); }
+    Double_t GetPointX() const { return fPoint.X(); }
+    Double_t GetPointY() const { return fPoint.Y(); }
+    Double_t GetPointZ() const { return fPoint.Z(); }
+   
+    virtual Bool_t    GetHit(TVector3& /*hit*/) const { return false; }
     
-    virtual void PrintHit(Bool_t print_point = kTRUE) const;
+    virtual TVector3  GetResolution()  const { return fResolution; }
     
-private:
-  
-    std::vector<Long_t> fDetId;  // geo. module id, detector id, subdectector id
+    virtual Double_t  GetResolution1() const { return fResolution.X(); }
+    virtual Double_t  GetResolution2() const { return fResolution.Y(); }
+    virtual Double_t  GetResolution3() const { return fResolution.Z(); }
     
+    virtual void PrintHit(Bool_t print_point = true, Bool_t print_res = false) const;
+    
+protected:
+  
+    std::vector<Long_t> fDetId;  // mc-digit: geo. module id, detector id, [subdectector id, submodule id, ... ]
+
     Double_t   fEdep;            // energy deposit, GeV
     
-    Int_t      fInfoNum;         // SpdIdealDataInfo number in SpdIdealTrackColl
+    Int_t      fId;              // hit unique id
+    Int_t      fInfoNum;         // SpdIdealDataInfo number (see SpdIdealTrackColl or SpdIEvent)
     Int_t      fMotherPointNum;  // mother mc-point number
     
+    std::vector<Int_t> fTrackId; // tracks (id's) to which the hit belong  
+  
+    // Additional parameter "specifity", for example: 
+    // 'f'(failed), 'd'(disabled), 'n'(undefined)
+    // spacepoint-like: 'p'(simple point),'m'(MAPS),'s'(DSSD), ...
+    //  wirepoint-like: 'p'(simple point),'w'(wire)
+    // ...
+    Char_t     fSpecifity; 
+    
+    TVector3   fPoint;       // mc-point coordinates
+    TVector3   fResolution;  // hit resolution
+    
     ClassDef(SpdIdealHit,1)
 };
 
diff --git a/spddata/IdealTrackData/SpdIdealSpacepointHit.cxx b/spddata/IdealTrackData/SpdIdealSpacepointHit.cxx
index fe0ebdf8838a861a288ab8bba2abca6a4b0dd1e3..5b590a9a39e91bc54830a6fea3ce39700301d434 100644
--- a/spddata/IdealTrackData/SpdIdealSpacepointHit.cxx
+++ b/spddata/IdealTrackData/SpdIdealSpacepointHit.cxx
@@ -8,10 +8,15 @@
 
 #include "SpdIdealSpacepointHit.h"
 
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
 ClassImp(SpdIdealSpacepointHit)
 
 //_____________________________________________________________________________
-SpdIdealSpacepointHit::SpdIdealSpacepointHit():SpdIdealHit(),fSpecifity('n'),
+SpdIdealSpacepointHit::SpdIdealSpacepointHit():SpdIdealHit(),
 fLn(1),fLu(1,0,0),fLv(0,1,0)
 {
 }
@@ -25,6 +30,49 @@ TVector3 SpdIdealSpacepointHit::GetN(Bool_t unit) const
   return N;
 }
 
+//_____________________________________________________________________________
+Double_t SpdIdealSpacepointHit::GetHitU() const
+{
+  TVector3 u = fLu.Unit(); 
+  TVector3 p = fHit - fDetPos;
+  return p.Dot(u);
+}
+
+//_____________________________________________________________________________   
+Double_t SpdIdealSpacepointHit::GetHitV() const
+{
+  TVector3 v = fLv.Unit();
+  TVector3 p = fHit - fDetPos;
+  return p.Dot(v);
+}
+
+//_____________________________________________________________________________    
+Double_t SpdIdealSpacepointHit::GetHitN() const
+{
+  TVector3 n = GetN(kTRUE);
+  TVector3 p = fHit - fDetPos;
+  return p.Dot(n);
+}
+
+//_____________________________________________________________________________    
+void SpdIdealSpacepointHit::GetHitUV(Double_t& xu, Double_t& xv) const
+{
+  TVector3 p = fHit - fDetPos;
+  TVector3 u = fLu.Unit(), v = fLv.Unit();
+  xu = p.Dot(u);
+  xv = p.Dot(v);
+}
+
+//_____________________________________________________________________________       
+void SpdIdealSpacepointHit::GetHitUVN(Double_t& xu, Double_t& xv, Double_t& xn) const
+{
+  TVector3 p = fHit - fDetPos;
+  TVector3 u = fLu.Unit(), v = fLv.Unit(), n = GetN(kTRUE);
+  xu = p.Dot(u);
+  xv = p.Dot(v);
+  xn = p.Dot(n);
+}
+
 //_____________________________________________________________________________
 Double_t SpdIdealSpacepointHit::GetPointU() const
 {
@@ -69,25 +117,41 @@ void SpdIdealSpacepointHit::GetPointUVN(Double_t& xu, Double_t& xv, Double_t& xn
 }
 
 //_____________________________________________________________________________    
-void SpdIdealSpacepointHit::PrintHit(Bool_t print_point) const
+void SpdIdealSpacepointHit::PrintHit(Bool_t print_point, Bool_t print_res) const
 {
-  SpdIdealHit::PrintHit(print_point);
+   cout << "\t<" << this->ClassName() << "::PrintHit>" << "\n\n";
+   cout << "\tHit unique ID:       " << fId << endl;
+   cout << "\tDetector id:         "; for (Int_t i(0); i<fDetId.size(); i++) { cout << fDetId[i] << " "; } cout << endl;
+   cout << "\tTrack id:            "; for (Int_t i(0); i<fTrackId.size(); i++) { cout << fTrackId[i] << " "; } cout << endl;
+   cout << "\tInfo, mcpoint:       " << fInfoNum << ", " << fMotherPointNum << endl;
+   cout << "\tEdep, Time:          " << fEdep << " [GeV],  " << fTimeStamp << " [ns] " << endl;
+   cout << "\tSpecifity:           " << fSpecifity << endl;
 
-  printf("\tSpecifity: '%c'\n", fSpecifity);
+   if (print_point) {
+       cout << "\n";
+       cout << "\tPoint(x,y,z):        " 
+            << fPoint.X() << ", " << fPoint.Y() << ", " << fPoint.Z() << " [cm] " << endl;
+       cout << "\tHit(x,y,z):          " 
+            << fHit.X()   << ", " << fHit.Y() << ", " << fHit.Z() << " [cm] " << endl;            
+   }
+   if (print_res) {
+       cout << "\tResolution:          " 
+            << fResolution.X()*1e4 << ", " << fResolution.Y()*1e4  << ", " << fResolution.Z()*1e4  << " [mkm] " << endl;
+   }
    
-  TVector3 v;
+   TVector3 v;
  
-  printf("\n");
-  v = GetU();
-  printf("\tu:    [%8.3f, %8.3f, %8.3f]  l(u) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLu());
-  v = GetV();
-  printf("\tv:    [%8.3f, %8.3f, %8.3f]  l(v) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLv());
-  v = GetN();
-  printf("\tn:    [%8.3f, %8.3f, %8.3f]  l(n) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLn());
+   printf("\n");
+   v = GetU();
+   printf("\tu:    [%8.3f, %8.3f, %8.3f]  l(u) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLu());
+   v = GetV();
+   printf("\tv:    [%8.3f, %8.3f, %8.3f]  l(v) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLv());
+   v = GetN();
+   printf("\tn:    [%8.3f, %8.3f, %8.3f]  l(n) = %8.3f [cm]\n",v.X(),v.Y(),v.Z(),GetLn());
   
-  printf("\n");
-  printf("\tdet:  [%8.3f, %8.3f, %8.3f]  Dr   = %8.3f [cm]\n",fDetPos.X(),fDetPos.Y(),fDetPos.Z(),
-                                                            fDetPos.XYvector().Mod());
-  printf("\n");
+   printf("\n");
+   printf("\tdet:  [%8.3f, %8.3f, %8.3f]  Dr   = %8.3f [cm]\n",fDetPos.X(),fDetPos.Y(),fDetPos.Z(),
+                                                               fDetPos.XYvector().Mod());
+   printf("\n");
 }
 
diff --git a/spddata/IdealTrackData/SpdIdealSpacepointHit.h b/spddata/IdealTrackData/SpdIdealSpacepointHit.h
index 24ec6fe323af7a8485ca9bff82c0c6c61c585dca..79b20db5aac77dde7b01085cd8dc8e190f53c1b5 100644
--- a/spddata/IdealTrackData/SpdIdealSpacepointHit.h
+++ b/spddata/IdealTrackData/SpdIdealSpacepointHit.h
@@ -21,13 +21,19 @@ public:
     SpdIdealSpacepointHit();
     virtual ~SpdIdealSpacepointHit() {}
     
-    /* setters */
-    
-    virtual void SetPoint(Double_t x, Double_t y, Double_t z) { fPoint.SetXYZ(x,y,z); }
-    virtual void SetPoint(TVector3 point) { fPoint = point; }
-    
-    void SetSpecifity(Char_t spec) { fSpecifity = spec; }
+    /* ========== SETTERS ========== */
     
+    // hit
+    virtual void SetHit(Double_t x, Double_t y, Double_t z) { fHit.SetXYZ(x,y,z); }
+    virtual void SetHit(TVector3 hit) { fHit = hit; }
+
+    void SetResolutionUVN(Double_t ru, Double_t rv, Double_t rn) { fResolution.SetXYZ(ru,rv,rn); }
+    void SetResolutionUV(Double_t ru, Double_t rv) { fResolution.SetXYZ(ru,rv,-1); }
+    void SetResolutionU(Double_t ru)  { fResolution.SetX(ru); }
+    void SetResolutionV(Double_t rv)  { fResolution.SetY(rv); }
+    void SetResolutionN(Double_t rn)  { fResolution.SetZ(rn); }
+       
+    // detector   
     void SetU(TVector3 x, Double_t mag = -1);
     void SetV(TVector3 x, Double_t mag = -1);
     
@@ -42,24 +48,32 @@ public:
     void SetDetPos(Double_t x, Double_t y, Double_t z) { fDetPos.SetXYZ(x,y,z); }
     void SetDetPos(TVector3 pos) { fDetPos = pos; }
     
-    /* getters */
+    /* ========== GETTERS ========== */
     
-    Double_t GetPointU() const;
-    Double_t GetPointV() const;
-    Double_t GetPointN() const;
+    Double_t GetResolutionU() const { return fResolution.X(); }
+    Double_t GetResolutionV() const { return fResolution.Y(); }
+    Double_t GetResolutionN() const { return fResolution.Z(); }   
     
-    void GetPointUV(Double_t& xu, Double_t& xv) const;
-    void GetPointUVN(Double_t& xu, Double_t& xv, Double_t& xn) const;
+    // hit
+    virtual Bool_t   GetHit(TVector3& hit) const { hit = fHit; return true; }
+            TVector3 GetHit() const { return fHit; }
+                
+    Double_t GetHitU() const;  // u coordinate (local CS)
+    Double_t GetHitV() const;  // v coordinate (local CS)
+    Double_t GetHitN() const;  // n coordinate (local CS)
     
-    virtual Double_t  GetPointX() const { return fPoint.X(); }
-    virtual Double_t  GetPointY() const { return fPoint.Y(); }
-    virtual Double_t  GetPointZ() const { return fPoint.Z(); }
+    void GetHitUV(Double_t& xu, Double_t& xv) const;
+    void GetHitUVN(Double_t& xu, Double_t& xv, Double_t& xn) const;
     
-    virtual void      GetPoint(TVector3& point) const { point = fPoint; }
-    virtual TVector3  GetPoint() const { return fPoint; }
+    // point
+    Double_t GetPointU() const;  // u coordinate (local РЎS)
+    Double_t GetPointV() const;  // v coordinate (local РЎS)
+    Double_t GetPointN() const;  // n coordinate (local РЎS)
     
-    Char_t    GetSpecifity() { return fSpecifity; }
+    void GetPointUV(Double_t& xu, Double_t& xv) const;
+    void GetPointUVN(Double_t& xu, Double_t& xv, Double_t& xn) const;
     
+    // detector  
     TVector3  GetU(Bool_t unit = kTRUE) const { return (unit) ? fLu.Unit() : fLu; }
     TVector3  GetV(Bool_t unit = kTRUE) const { return (unit) ? fLv.Unit() : fLv; }
     TVector3  GetN(Bool_t unit = kTRUE) const;
@@ -70,19 +84,22 @@ public:
     
     TVector3  GetDetPos() const { return fDetPos; }
     
-    virtual void PrintHit(Bool_t print_point = kTRUE) const;
+    Double_t  GetDetPosX() const { return fDetPos.X(); }
+    Double_t  GetDetPosY() const { return fDetPos.Y(); }
+    Double_t  GetDetPosZ() const { return fDetPos.Z(); }
+        
+    virtual void PrintHit(Bool_t print_point = true, Bool_t print_res = true) const;
 
 private:
 
     // hit
-    TVector3 fPoint;
-    Char_t   fSpecifity; // for example, 'n'(unknown),'p'(point),'m'(MAPS),'s'(DSSD), ...
+    TVector3 fHit;    // hit coordinates (global S.C.)
     
     // detector 
-    Double_t fLn;
-    TVector3 fLu;
-    TVector3 fLv;
-    TVector3 fDetPos;
+    Double_t fLn;     // n = [u x v] 
+    TVector3 fLu;     // u -direction
+    TVector3 fLv;     // v- direction
+    TVector3 fDetPos; // detector position
     
     ClassDef(SpdIdealSpacepointHit,1)
 };
diff --git a/spddata/IdealTrackData/SpdIdealWirepointHit.cxx b/spddata/IdealTrackData/SpdIdealWirepointHit.cxx
index 30728cbf7d71b148cb888481912df269d8ae85a3..848f30623f76a199977013f6c687de4aa370a468 100644
--- a/spddata/IdealTrackData/SpdIdealWirepointHit.cxx
+++ b/spddata/IdealTrackData/SpdIdealWirepointHit.cxx
@@ -22,18 +22,22 @@ SpdIdealWirepointHit::~SpdIdealWirepointHit()
 {
 }
 
+//***************************************************************************/
+//******************************** HIT **************************************/
+//***************************************************************************/
+
 //___________________________________________________________________________
 Double_t SpdIdealWirepointHit::GetRdrift() const
 {
-   TVector3 dir = GetWireDirection();
-   TVector3 l = (fPoint-fWirePoint1).Cross(dir);
-   return l.Mag();
+   TVector3 WireDirection = GetWireDirection();
+   TVector3 r = (fHit-fWirePoint1).Cross(WireDirection);
+   return r.Mag();
 }
 //___________________________________________________________________________
 Double_t SpdIdealWirepointHit::GetZwire()  const
 {
    TVector3 WireDirection = GetWireDirection();
-   return fabs(WireDirection.Dot(fPoint-fWirePoint1));
+   return fabs(WireDirection.Dot(fHit-fWirePoint1));
 }
 
 //___________________________________________________________________________
@@ -42,31 +46,100 @@ Int_t SpdIdealWirepointHit::GetLRtype() const
    TVector3 WireDirection = GetWireDirection(false);
    TVector3 U = fDirInPoint.Cross(WireDirection);
    TVector3 l = GetPointOnWire();
-   Double_t v = U.Dot(l-fPoint);
+   Double_t v = U.Dot(l-fHit);
    if (fabs(v) < 1.e-6) return 0;
    return (v > 0) ? 1 : -1;
 }
 
 //___________________________________________________________________________    
 TVector3 SpdIdealWirepointHit::GetPointOnWire() const
+{
+   TVector3 WireDirection = GetWireDirection();
+   return fWirePoint1 + WireDirection.Dot(fHit-fWirePoint1)*WireDirection;
+}
+
+//___________________________________________________________________________    
+TVector3 SpdIdealWirepointHit::GetDriftDirR() const
+{
+   TVector3 p = GetPointOnWire();
+   return fHit - p;
+}
+
+//___________________________________________________________________________    
+TVector3 SpdIdealWirepointHit::GetWireDirZ() const
+{
+   TVector3 WireDirection = GetWireDirection();
+   return WireDirection.Dot(fHit-fWirePoint1)*WireDirection;
+}
+
+//***************************************************************************/
+//****************************** POINT **************************************/
+//***************************************************************************/
+
+//___________________________________________________________________________
+Double_t SpdIdealWirepointHit::GetPointRdrift() const
+{
+   TVector3 WireDirection = GetWireDirection();
+   TVector3 r = (fPoint-fWirePoint1).Cross(WireDirection);
+   return r.Mag();
+}
+//___________________________________________________________________________
+Double_t SpdIdealWirepointHit::GetPointZwire()  const
+{
+   TVector3 WireDirection = GetWireDirection();
+   return fabs(WireDirection.Dot(fPoint-fWirePoint1));
+}
+
+//___________________________________________________________________________
+Int_t SpdIdealWirepointHit::GetPointLRtype() const
+{ 
+   TVector3 WireDirection = GetWireDirection(false);
+   TVector3 U = fDirInPoint.Cross(WireDirection);
+   TVector3 l = GetPointOnWire();
+   Double_t v = U.Dot(l-fPoint);
+   if (fabs(v) < 1.e-6) return 0;
+   return (v > 0) ? 1 : -1;
+}
+
+//___________________________________________________________________________    
+TVector3 SpdIdealWirepointHit::GetPointPointOnWire() const
 {
    TVector3 WireDirection = GetWireDirection();
    return fWirePoint1 + WireDirection.Dot(fPoint-fWirePoint1)*WireDirection;
 }
-    
+
+//___________________________________________________________________________    
+TVector3 SpdIdealWirepointHit::GetPointDriftDirR() const
+{
+   TVector3 p = GetPointOnWire();
+   return fPoint - p;
+}
+
+//___________________________________________________________________________    
+TVector3 SpdIdealWirepointHit::GetPointWireDirZ() const
+{
+   TVector3 WireDirection = GetWireDirection();
+   return WireDirection.Dot(fPoint-fWirePoint1)*WireDirection;
+}
+
 //_____________________________________________________________________________
-void SpdIdealWirepointHit::PrintHit(Bool_t print_point) const
+void SpdIdealWirepointHit::PrintHit(Bool_t print_point, Bool_t print_res) const
 {
-   SpdIdealHit::PrintHit(kFALSE);
+   SpdIdealHit::PrintHit(false,false);
    
    if (print_point) {
        printf("\tpoint:        [%8.3f, %8.3f, %8.3f]  [cm]\n",fPoint.X(),fPoint.Y(),fPoint.Z());
+       printf("\thit:          [%8.3f, %8.3f, %8.3f]  [cm]\n",fHit.X(),fHit.Y(),fHit.Z());
        printf("\tdir(point):   [%8.3f, %8.3f, %8.3f]  [cm]\n",fDirInPoint.X(),fDirInPoint.Y(),fDirInPoint.Z());
    }
-
+   if (print_res) {
+       printf("\tresolution:   [%8.0f, %8.0f, %8.0f] [mkm]\n",fResolution.X()*1e4 ,fResolution.Y()*1e4 ,fResolution.Z()*1e4);
+   }
+   
    printf("\n");
-    
-   printf("\tHit:  z,r,s       [%8.3f, %8.3f, %8.3f]  [cm] lr = %8d\n",GetZwire(),GetRdrift(),GetSegLen(),GetLRtype());
+   
+   printf("\tPoint: r,z,s      [%8.3f, %8.3f, %8.3f]  [cm] lr = %-8d\n",GetPointRdrift(),GetPointZwire(),GetSegLen(),GetPointLRtype());
+   printf("\tHit:   r,z,s      [%8.3f, %8.3f, %8.3f]  [cm] lr = %-8d\n",GetRdrift(),GetZwire(),GetSegLen(),GetLRtype());
    printf("\tWire: L,Theta,Phi [%8.3f, %8.3f, %8.3f]  [cm] r  = %8.3f [cm]\n",GetWireLength(),
           GetWireTheta(),GetWirePhi(),GetWireMaxRadius());
    
diff --git a/spddata/IdealTrackData/SpdIdealWirepointHit.h b/spddata/IdealTrackData/SpdIdealWirepointHit.h
index 471d94440a3d734f3ecc3873a7ae98f161362616..bedd23f5f8c6320c85d7cdaa333a525cdb0b77da 100644
--- a/spddata/IdealTrackData/SpdIdealWirepointHit.h
+++ b/spddata/IdealTrackData/SpdIdealWirepointHit.h
@@ -23,11 +23,16 @@ public:
     virtual ~SpdIdealWirepointHit();
   
     /* ========== SETTERS ========== */
-    
+
     // hit
-    virtual void SetPoint(Double_t x, Double_t y, Double_t z) { fPoint.SetXYZ(x,y,z); }
-    virtual void SetPoint(TVector3 point) { fPoint = point; }
-    
+    virtual void SetHit(Double_t x, Double_t y, Double_t z) { fHit.SetXYZ(x,y,z); }
+    virtual void SetHit(TVector3 hit) { fHit = hit; }
+
+    void SetResolutionRZ(Double_t rr, Double_t rz) { fResolution.SetXYZ(rr,rz,-1); }
+    void SetResolutionR(Double_t rr)  { fResolution.SetX(rr); }
+    void SetResolutionZ(Double_t rz)  { fResolution.SetY(rz); }
+
+    // point additional (hit)
     void SetDirInPoint(Double_t lx, Double_t ly, Double_t lz) { fDirInPoint.SetXYZ(lx,ly,lz); }
     void SetDirInPoint(Double_t l, Double_t nx, Double_t ny, Double_t nz) { fDirInPoint.SetXYZ(nx,ny,nz); fDirInPoint.SetMag(l); }
     void SetDirInPoint(TVector3 dir, Double_t s) { fDirInPoint = dir; dir.SetMag(1); fSegLength = s; }
@@ -37,28 +42,38 @@ public:
     // detector
     void SetWireMaxRadius(Double_t R) { fWireMaxRadius = fabs(R); }
     void SetWire(TVector3& point1, TVector3& point2) { fWirePoint1 = point1; fWirePoint2 = point2; }
-    void SetWire(TVector3& point, TVector3& dir, Double_t l) { fWirePoint1 = point-0.5*l*dir; fWirePoint2 = point+0.5*l*dir; }
+    void SetWire(TVector3& point, TVector3& dir, Double_t halfl) { fWirePoint1 = point-halfl*dir; fWirePoint2 = point+halfl*dir; }
     
     /* ========== GETTERS ========== */
     
-    // hit
-    virtual Double_t  GetPointX() const { return fPoint.X(); }
-    virtual Double_t  GetPointY() const { return fPoint.Y(); }
-    virtual Double_t  GetPointZ() const { return fPoint.Z(); }
-    
-    virtual void      GetPoint(TVector3& point) const { point = fPoint; }
-    virtual TVector3  GetPoint() const { return fPoint; }
-    
     void      GetDirInPoint(TVector3& dir) const { dir = fDirInPoint; }
     TVector3  GetDirInPoint() const { return fDirInPoint; }
-    
     Double_t  GetSegLen() const { return fSegLength; } // track segment length  
-    Double_t  GetRdrift() const;  // drift radius
-    Double_t  GetZwire()  const;  // coordinate along the wire
+    
+    Double_t  GetResolutionR() const { return fResolution.X(); }
+    Double_t  GetResolutionZ() const { return fResolution.Y(); }
+    
+    // hit
+    virtual Bool_t   GetHit(TVector3& hit) const { hit = fHit; return true; }
+            TVector3 GetHit() const { return fHit; }
+            
+    Double_t  GetRdrift() const;  // hit drift radius
+    Double_t  GetZwire()  const;  // hit coordinate along the wire
     Int_t     GetLRtype() const;  // hit type: -1(left), +1(right), 0(undefined) (to resolove left/right ambiguity)
      
-    TVector3  GetPointOnWire()    const; // hit projection on wire
-      
+    TVector3  GetPointOnWire() const; // hit projection on wire
+    TVector3  GetDriftDirR()   const; // hit radial component in the wire CS (orthohonal to the wire)
+    TVector3  GetWireDirZ()    const; // hit z componentin in the wire CS (along the wire)
+    
+    // point
+    Double_t  GetPointRdrift() const;  // point drift radius
+    Double_t  GetPointZwire()  const;  // point coordinate along the wire
+    Int_t     GetPointLRtype() const;  // point hit type: -1(left), +1(right), 0(undefined) (to resolove left/right ambiguity)
+     
+    TVector3  GetPointPointOnWire() const; // point projection on wire
+    TVector3  GetPointDriftDirR()   const; // point radial component in the wire CS (orthohonal to the wire)
+    TVector3  GetPointWireDirZ()    const; // point z component in the wire CS (along the wire)
+    
     // detector
     Double_t  GetWireMaxRadius()  const { return fWireMaxRadius; }
     TVector3  GetWirePoint1()     const { return fWirePoint1; }
@@ -72,20 +87,22 @@ public:
     TVector3  GetWirePosition()   const { return 0.5*(fWirePoint1+fWirePoint2);       }
     
     TVector3  GetWireDirection(Bool_t norm = true) const { return (norm) ? (fWirePoint2-fWirePoint1).Unit() : (fWirePoint2-fWirePoint1); } 
-    
-    virtual void PrintHit(Bool_t print_point = kTRUE) const;
+   
+    virtual void PrintHit(Bool_t print_point = true, Bool_t print_res = true) const;
     
 private:
     
-    // hit 
-    TVector3 fPoint;
-    TVector3 fDirInPoint;
-    Double_t fSegLength;
+    // hit
+    TVector3 fHit;           // hit coordinates (global S.C.)
+    
+    // additional point chars 
+    TVector3 fDirInPoint;    // track direction in mc-point
+    Double_t fSegLength;     // track segment length  
     
     // detector
-    Double_t fWireMaxRadius;
-    TVector3 fWirePoint1;
-    TVector3 fWirePoint2;
+    Double_t fWireMaxRadius; // max. drift radius
+    TVector3 fWirePoint1;    // first end of the wire
+    TVector3 fWirePoint2;    // second end of the wire
     
     ClassDef(SpdIdealWirepointHit,1)
 };
diff --git a/spddata/SpdDataLinkDef.h b/spddata/SpdDataLinkDef.h
index 0e365050127d1a7ec1bc337155c3a890e94964f5..b79b446b3e8ce415fb937723e9919041a4f6384a 100644
--- a/spddata/SpdDataLinkDef.h
+++ b/spddata/SpdDataLinkDef.h
@@ -14,7 +14,7 @@
 #pragma link C++ class SpdParameter+;
 #pragma link C++ class SpdFieldPar+;
 #pragma link C++ class SpdParSetContFact+;
-#pragma link C++ class SpdPassiveGeoPar+;
+#pragma link C++ class SpdPassiveGeoParSet+;
 #pragma link C++ class SpdBaseParSet+;
 #pragma link C++ class SpdParSet+;
 #pragma link C++ class SpdPrimGenParSet+;
diff --git a/spddata/SpdGeopathParser.cxx b/spddata/SpdGeopathParser.cxx
index 4233246ade6cde01ac7d792d4a5d872e853c131c..3188de1139c3644d9742fc3e8d42de95afa918e4 100644
--- a/spddata/SpdGeopathParser.cxx
+++ b/spddata/SpdGeopathParser.cxx
@@ -76,14 +76,14 @@ Int_t SpdGeopathParser::ParsePath(const TString& path)
       name = name(i+1,name.Length());  
       fPath[fPathLevel].second = name.Atoi();
       
-//       cout << "<SpdGeopathParser::ParsePath> " << path << " :: " << fPathLevel 
-//            << " | " << fPath[fPathLevel].first 
-//            << " | " << fPath[fPathLevel].second<< endl;
+      //cout << "<SpdGeopathParser::ParsePath> " << path << " :: " << fPathLevel 
+      //     << " | " << fPath[fPathLevel].first 
+      //     << " | " << fPath[fPathLevel].second<< endl;
       
       fPathLevel++; 
    }
    
-   //cout << "<SpdGeopathParser::ParsePath> " << GetCurrentPathString() << endl;
+   //cout << "-I- <SpdGeopathParser::ParsePath> " << GetCurrentPathString() << " Geometry level: " << fPathLevel << endl;
    
    return fPathLevel;
 }
@@ -95,11 +95,13 @@ TString SpdGeopathParser::GetCurrentPathString() const
    
    TString path;
    SPDGEOPATH::const_iterator it = fPath.begin();
-   Int_t n(0);
+   Int_t n(1);
    for (; it != fPath.end(); it++) {
         path += Form("/%s_%d",it->first.Data(),it->second);
-	if (n++ == fPathLevel) return path;
+        if (n == fPathLevel) break;
+        n++;
    }
+ 
    return path;
 }
 
diff --git a/spddata/SpdGeopathParser.h b/spddata/SpdGeopathParser.h
index 15c12e9543d706cbfeaecb3d75152873968517b9..7a945b9a686a0884fe826baea22eea5619e6d0d6 100644
--- a/spddata/SpdGeopathParser.h
+++ b/spddata/SpdGeopathParser.h
@@ -16,7 +16,7 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-typedef std::vector< std::pair<TString,Int_t> > SPDGEOPATH;
+typedef std::vector< std::pair< TString,Int_t> > SPDGEOPATH;
 
 class SpdGeopathParser: public TObject {
 
diff --git a/spddata/kfdata/SpdKFSimpleRes.cxx b/spddata/kfdata/SpdKFSimpleRes.cxx
index 4af88d64ef3bc5d6f4b54ccf979f5ce4a0223171..98ab02d0116bfbbc456305874597f37ba07b99aa 100644
--- a/spddata/kfdata/SpdKFSimpleRes.cxx
+++ b/spddata/kfdata/SpdKFSimpleRes.cxx
@@ -129,6 +129,25 @@ Int_t SpdKFSimpleRes::GetNTracks(Bool_t without_errors, Bool_t converged, Bool_t
     return n;
 }
 
+//_____________________________________________________________________________
+Double_t SpdKFSimpleRes::GetMomRes(Bool_t without_errors, Bool_t converged) const 
+{ 
+    Double_t res(0.), m;
+    Int_t n(0);
+    
+    for (Int_t i(0); i<fTracks.size(); i++) { 
+         if (!fTracks[i].IsFitted) continue;
+         if (converged && fTracks[i].Convergency != 1) continue;
+         if (without_errors && fTracks[i].ErrorFlag != 0) continue;
+         m = fTracks[i].MomentumMC.Mag();
+         if (!(m > 0)) continue;
+         res += TMath::Abs(m-fTracks[i].MomentumREC.Mag())/m;
+         n++;
+    }
+    
+    return (n > 1) ? res/n : 0.;
+}
+
 //_____________________________________________________________________________
 Double_t SpdKFSimpleRes::GetMomResN(Int_t& nres, Bool_t without_errors, Bool_t converged) const
 {
@@ -151,7 +170,7 @@ Double_t SpdKFSimpleRes::GetMomResN(Int_t& nres, Bool_t without_errors, Bool_t c
 }
 
 //_____________________________________________________________________________
-Double_t SpdKFSimpleRes::GetMomRes(Bool_t without_errors, Bool_t converged) const 
+Double_t SpdKFSimpleRes::GetMomTRes(Bool_t without_errors, Bool_t converged) const 
 { 
     Double_t res(0.), m;
     Int_t n(0);
@@ -160,15 +179,36 @@ Double_t SpdKFSimpleRes::GetMomRes(Bool_t without_errors, Bool_t converged) cons
          if (!fTracks[i].IsFitted) continue;
          if (converged && fTracks[i].Convergency != 1) continue;
          if (without_errors && fTracks[i].ErrorFlag != 0) continue;
-         m = fTracks[i].MomentumMC.Mag();
+         m = fTracks[i].MomentumMC.Perp();
          if (!(m > 0)) continue;
-         res += TMath::Abs(m-fTracks[i].MomentumREC.Mag())/m;
+         res += TMath::Abs(m-fTracks[i].MomentumREC.Perp())/m;
          n++;
     }
     
     return (n > 1) ? res/n : 0.;
 }
 
+//_____________________________________________________________________________
+Double_t SpdKFSimpleRes::GetMomTResN(Int_t& nres, Bool_t without_errors, Bool_t converged) const
+{
+    nres = 0;
+    
+    if (!fTracks.size() < 1) return 0.;
+        
+    Double_t  res(0), m;
+    for (Int_t i(0); i<fTracks.size(); i++) { 
+         if (!fTracks[i].IsFitted) continue;
+         if (converged && fTracks[i].Convergency != 1) continue;
+         if (without_errors && fTracks[i].ErrorFlag != 0) continue;
+         m = fTracks[i].MomentumMC.Perp();
+         if (!(m > 0)) continue;
+         res += TMath::Abs(m-fTracks[i].MomentumREC.Perp())/m;
+         nres++;
+    }
+    
+    return (nres > 1) ? res/nres : 0.;
+}
+
 //_____________________________________________________________________________
 Int_t SpdKFSimpleRes::GetRes(Double_t& rp, Double_t& rpt, Double_t& rpz, Double_t& rtheta, Double_t& rphi,
                              Bool_t without_errors, Bool_t converged) const 
@@ -403,9 +443,9 @@ void SpdKFSimpleRes::PrintData(Int_t opt) const
         }
         
         printf("\n%5s %8s %8s   %8s %8s %8s %8s %8s   %8s %8s %8s %8s %8s   %8s %8s %8s %8s %8s\n\n",
-               "N","chi2/ndf","|dp|/s","px(mc)","px(rec)","dpx","sigma(x)","|dpx|/sx",
-                                       "py(mc)","py(rec)","dpy","sigma(y)","|dpy|/sy",
-                                       "pz(mc)","pz(rec)","dpz","sigma(z)","|dpz|/sz");
+               "N","chi2/ndf","|dp|/s","px(mc)","px(rec)","dpx  ","sigma(x)","|dpx|/sx",
+                                       "py(mc)","py(rec)","dpy  ","sigma(y)","|dpy|/sy",
+                                       "pz(mc)","pz(rec)","dpz  ","sigma(z)","|dpz|/sz");
              
         for (Int_t i(0); i<ntracks; i++) { 
              printf("%5d %8.3f %8.4f   %8.4f %8.4f %8.4f %8.4f %8.4f   %8.4f %8.4f %8.4f %8.4f %8.4f   %8.4f %8.4f %8.4f %8.4f %8.4f\n",
@@ -418,9 +458,15 @@ void SpdKFSimpleRes::PrintData(Int_t opt) const
     }    
     
     printf("\n averaged values : \n");
-    printf("\n |dp/p| (fitted):                        %8.3f [%%] (%d)",GetMomRes(false,false)*100,GetNTracks(false,false));
-    printf("\n |dp/p| (fitted + converged):            %8.3f [%%] (%d)",GetMomRes(false,true)*100,GetNTracks(false,true));
-    printf("\n |dp/p| (fitted + converged + noerrors): %8.3f [%%] (%d)",GetMomRes(true,true)*100,GetNTracks(true,true));
+    printf("\n |dp/p| (fitted):                          %8.3f [%%] (%d)",GetMomRes(false,false)*100,GetNTracks(false,false));
+    printf("\n |dp/p| (fitted + converged):              %8.3f [%%] (%d)",GetMomRes(false,true)*100,GetNTracks(false,true));
+    printf("\n |dp/p| (fitted + converged + noerrors):   %8.3f [%%] (%d)",GetMomRes(true,true)*100,GetNTracks(true,true));
+    
+    printf("\n");
+    
+    printf("\n |dpt/pt| (fitted):                        %8.3f [%%] (%d)",GetMomTRes(false,false)*100,GetNTracks(false,false));
+    printf("\n |dpt/pt| (fitted + converged):            %8.3f [%%] (%d)",GetMomTRes(false,true)*100,GetNTracks(false,true));
+    printf("\n |dpt/pt| (fitted + converged + noerrors): %8.3f [%%] (%d)",GetMomTRes(true,true)*100,GetNTracks(true,true));
 
     printf("\n\n");
 }
diff --git a/spddata/kfdata/SpdKFSimpleRes.h b/spddata/kfdata/SpdKFSimpleRes.h
index 2e0888a29bb10cada07e2de64e5639af199fde70..d4f5f57cab2d055f5f4632f86d96aaf352bb099d 100644
--- a/spddata/kfdata/SpdKFSimpleRes.h
+++ b/spddata/kfdata/SpdKFSimpleRes.h
@@ -177,6 +177,7 @@ public:
     Int_t    GetNThits(Int_t i)   const { return (FindTrack(i)) ? (fTracks[i].NTBhits + fTracks[i].NTEChits) : 0; } 
     Int_t    GetNTBhits(Int_t i)  const { return (FindTrack(i)) ? fTracks[i].NTBhits : 0; } 
     Int_t    GetNTEChits(Int_t i) const { return (FindTrack(i)) ? fTracks[i].NTEChits : 0; } 
+    Int_t    GetNTThits(Int_t i)  const { return (FindTrack(i)) ? (fTracks[i].NVhits + fTracks[i].NTBhits + fTracks[i].NTEChits) : 0; } 
     
     // convergency + errors
     Bool_t   GetIsGood(Int_t i)   const;
@@ -233,6 +234,10 @@ public:
     Double_t GetMomRes(Bool_t without_errors = true, Bool_t converged = true) const; 
     Double_t GetMomResN(Int_t& nres, Bool_t without_errors = true, Bool_t converged = true) const; 
     
+    //  resolution: return  AVERAGED |dpt/pt| (fitted tracks only)
+    Double_t GetMomTRes(Bool_t without_errors = true, Bool_t converged = true) const; 
+    Double_t GetMomTResN(Int_t& nres, Bool_t without_errors = true, Bool_t converged = true) const; 
+    
     //  resolution: return number of tracks & AVERAGED values (fitted tracks only)
     Int_t    GetRes(Double_t& rp, Double_t& rpt, Double_t& rpz, Double_t& rtheta, Double_t& rphi,
                     Bool_t without_errors = true, Bool_t converged = true) const;  // !ATTENTION! NOT IMPLEMENTED YET! (return 0)
diff --git a/spddata/params/SpdParSetContFact.cxx b/spddata/params/SpdParSetContFact.cxx
index 4cab5256a1cc27c3b719da58118dba27c466723f..bdadcded708905a359536947c5b0cf4c9b2f014f 100644
--- a/spddata/params/SpdParSetContFact.cxx
+++ b/spddata/params/SpdParSetContFact.cxx
@@ -7,7 +7,7 @@
 #include "SpdBaseParSet.h"
 #include "SpdParSet.h"
 #include "SpdPrimGenParSet.h"
-#include "SpdPassiveGeoPar.h"
+#include "SpdPassiveGeoParSet.h"
 
 ClassImp(SpdParSetContFact)
 
@@ -45,7 +45,7 @@ void SpdParSetContFact::setAllContainers()
   
   containers->Add(p);
   
-  p = new FairContainer("PassiveGeoPar",
+  p = new FairContainer("PassiveGeoParSet",
                         "Spd Passive Geo Parameters",
                         "TestDefaultContext");
   
@@ -79,10 +79,10 @@ FairParSet* SpdParSetContFact::createContainer(FairContainer* c)
                         c->GetTitle(),
                         c->getContext());
   }
-  else if (strcmp(name,"PassiveGeoPar") == 0) {
-      p = new SpdPassiveGeoPar(c->getConcatName().Data(),
-                               c->GetTitle(),
-                               c->getContext());
+  else if (strcmp(name,"PassiveGeoParSet") == 0) {
+      p = new SpdPassiveGeoParSet(c->getConcatName().Data(),
+                                  c->GetTitle(),
+                                  c->getContext());
   }
   else if (strcmp(name,"PrimGenParSet") == 0) {
       p = new SpdPrimGenParSet(c->getConcatName().Data(),
diff --git a/spddata/params/SpdPassiveGeoPar.cxx b/spddata/params/SpdPassiveGeoParSet.cxx
similarity index 75%
rename from spddata/params/SpdPassiveGeoPar.cxx
rename to spddata/params/SpdPassiveGeoParSet.cxx
index c490ae68f2d1b2e8f97ca29dcaf5b30e59a43b56..9e32488aea8a715d8a30cc08a403296b50de41cb 100644
--- a/spddata/params/SpdPassiveGeoPar.cxx
+++ b/spddata/params/SpdPassiveGeoParSet.cxx
@@ -3,10 +3,10 @@
 
 //_____________________________________________________________________________
 //
-// SpdPassiveGeoPar
+// SpdPassiveGeoParSet
 //_____________________________________________________________________________
 
-#include "SpdPassiveGeoPar.h"
+#include "SpdPassiveGeoParSet.h"
 #include "FairParamList.h"
 #include "TObjArray.h"
 
@@ -15,18 +15,18 @@
 using std::cout;
 using std::endl;
 
-ClassImp(SpdPassiveGeoPar)
+ClassImp(SpdPassiveGeoParSet)
 
 //_____________________________________________________________________________________
-SpdPassiveGeoPar::SpdPassiveGeoPar(const char* name, const char* title, const char* context):
+SpdPassiveGeoParSet::SpdPassiveGeoParSet(const char* name, const char* title, const char* context):
 FairParGenericSet(name,title,context),fParams(0)
 {
-  //std::cout << "<SpdPassiveGeoPar::SpdPassiveGeoPar> CREATE CONTAINER" << std::endl;  
+  //std::cout << "<SpdPassiveGeoParSet::SpdPassiveGeoParSet> CREATE CONTAINER" << std::endl;  
   fParams = new TObjArray();
 }
  
 //_____________________________________________________________________________________
-SpdPassiveGeoPar::~SpdPassiveGeoPar()
+SpdPassiveGeoParSet::~SpdPassiveGeoParSet()
 {
   FairParGenericSet::clear();
   
@@ -38,32 +38,32 @@ SpdPassiveGeoPar::~SpdPassiveGeoPar()
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::clear()
+void SpdPassiveGeoParSet::clear()
 {
   if (fParams) fParams->Delete();
 }
 
 //_____________________________________________________________________________________
-Bool_t SpdPassiveGeoPar::GetParameter(const Text_t* par_name, Int_t& value)
+Bool_t SpdPassiveGeoParSet::GetParameter(const Text_t* par_name, Int_t& value)
 {
    return SpdParameter::GetParameter(fParams,par_name,value);
 }
 
 //_____________________________________________________________________________________
-Bool_t SpdPassiveGeoPar::GetParameter(const Text_t* par_name, Double_t& value)
+Bool_t SpdPassiveGeoParSet::GetParameter(const Text_t* par_name, Double_t& value)
 {
    return SpdParameter::GetParameter(fParams,par_name,value);
 }
 
 //_____________________________________________________________________________________
-Bool_t SpdPassiveGeoPar::GetParameter(const Text_t* par_name, TString& value)
+Bool_t SpdPassiveGeoParSet::GetParameter(const Text_t* par_name, TString& value)
 {
    value = SpdParameter::GetParameter(fParams,par_name); 
    return !value.IsWhitespace();
 }
     
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, Int_t value)
+void SpdPassiveGeoParSet::SetParameter(const Text_t* par_name, Int_t value)
 {
    SpdParameter* par = GetParameter(par_name);
    if (par) par->SetValue(value);
@@ -71,7 +71,7 @@ void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, Int_t value)
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, Double_t value) 
+void SpdPassiveGeoParSet::SetParameter(const Text_t* par_name, Double_t value) 
 {
    SpdParameter* par = GetParameter(par_name);
    if (par) par->SetValue(value);
@@ -79,7 +79,7 @@ void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, Double_t value)
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, const Char_t* value)
+void SpdPassiveGeoParSet::SetParameter(const Text_t* par_name, const Char_t* value)
 {
    SpdParameter* par = GetParameter(par_name);
    if (par) *par = value;  
@@ -87,7 +87,7 @@ void SpdPassiveGeoPar::SetParameter(const Text_t* par_name, const Char_t* value)
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::SetParameters(TObjArray* pars) 
+void SpdPassiveGeoParSet::SetParameters(TObjArray* pars) 
 {
    if (!pars) return;
    
@@ -103,7 +103,7 @@ void SpdPassiveGeoPar::SetParameters(TObjArray* pars)
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::FillParameters(TObjArray* pars) 
+void SpdPassiveGeoParSet::FillParameters(TObjArray* pars) 
 {
    if (!pars) return;
    
@@ -119,43 +119,43 @@ void SpdPassiveGeoPar::FillParameters(TObjArray* pars)
 }
 
 //_____________________________________________________________________________________
-Bool_t SpdPassiveGeoPar::FindParameter(const Text_t* par_name) 
+Bool_t SpdPassiveGeoParSet::FindParameter(const Text_t* par_name) 
 {
    if (!fParams) return kFALSE;
    return fParams->FindObject(par_name);
 }
 
 //_____________________________________________________________________________________
-SpdParameter* SpdPassiveGeoPar::GetParameter(const Text_t* par_name) 
+SpdParameter* SpdPassiveGeoParSet::GetParameter(const Text_t* par_name) 
 {
    if (!fParams) return 0;
    return (SpdParameter*)fParams->FindObject(par_name);
 }
 
 //_____________________________________________________________________________________
-Int_t SpdPassiveGeoPar::GetNParameters() 
+Int_t SpdPassiveGeoParSet::GetNParameters() 
 { 
    return fParams ? fParams->GetEntries() : 0; 
 }
        
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::putParams(FairParamList* l)
+void SpdPassiveGeoParSet::putParams(FairParamList* l)
 {
    if (!l || !fParams) return;
    l->addObject("Passive geometry parameters",fParams);
 }
 
 //_____________________________________________________________________________________
-Bool_t SpdPassiveGeoPar::getParams(FairParamList* l)
+Bool_t SpdPassiveGeoParSet::getParams(FairParamList* l)
 { 
    if (!l || !fParams) return kFALSE;
    return (l->fillObject("Passive geometry parameters",fParams)) ? kTRUE : kFALSE;
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::print(Int_t opt)
+void SpdPassiveGeoParSet::print(Int_t opt)
 {
-   cout << "<SpdPassiveGeoPar::print>" << endl;
+   cout << "<SpdPassiveGeoParSet::print>" << endl;
    cout << "Number of parameters = " << GetNParameters() << " " << endl; 
    cout << endl;
    
@@ -170,10 +170,10 @@ void SpdPassiveGeoPar::print(Int_t opt)
 }
 
 //_____________________________________________________________________________________
-void SpdPassiveGeoPar::printParams()
+void SpdPassiveGeoParSet::printParams()
 {
    cout << "---------------------------------------------\n";
-   cout << "<SpdPassiveGeoPar::printParams> Name: "<< GetName() << "\n";
+   cout << "<SpdPassiveGeoParSet::printParams> Name: "<< GetName() << "\n";
    if (!paramContext.IsNull()) { cout << "Context/Purpose:  " << paramContext << endl; }
    if (!author.IsNull())       { cout << "Author:           " << author << endl;      }
    if (!description.IsNull())  { cout << "Description:      " << description << endl;  }
diff --git a/spddata/params/SpdPassiveGeoPar.h b/spddata/params/SpdPassiveGeoParSet.h
similarity index 81%
rename from spddata/params/SpdPassiveGeoPar.h
rename to spddata/params/SpdPassiveGeoParSet.h
index 11089a02b08f44cc7fa48ee76ac0c5c28c57dab6..71c135e6ad3bd6aa513ac13dd628a32802aa3f6c 100644
--- a/spddata/params/SpdPassiveGeoPar.h
+++ b/spddata/params/SpdPassiveGeoParSet.h
@@ -1,15 +1,15 @@
 // $Id$
 // Author: artur   2018/01/23
 
-#ifndef __SPDPASSIVEGEOPAR_H__
-#define __SPDPASSIVEGEOPAR_H__
+#ifndef __SPDPASSIVEGEOPARSET_H__
+#define __SPDPASSIVEGEOPARSET_H__
 
 #include "FairParGenericSet.h"
 #include "SpdParameter.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //                                                                            //
-// SpdPassiveGeoPar                                                           //
+// SpdPassiveGeoParSet                                                        //
 //                                                                            //
 // <brief class description>                                                  //
 //                                                                            //
@@ -18,15 +18,15 @@
 class FairParamList;
 class TObjArray;
 
-class SpdPassiveGeoPar : public FairParGenericSet {
+class SpdPassiveGeoParSet : public FairParGenericSet  {
   
 public:
   
-    SpdPassiveGeoPar(const char* name = "SpdPassiveGeoPar",
-                     const char* title = "SpdPassive Geometry Parameters",
+    SpdPassiveGeoParSet(const char* name = "SpdPassiveGeoParSet",
+                     const char* title = "Spd Passive Geometry Parameters Set",
                      const char* context = "TestDefaultContext");
    
-   ~SpdPassiveGeoPar();
+   ~SpdPassiveGeoParSet();
     
     virtual void clear();
     virtual void printParams();
@@ -56,7 +56,7 @@ private:
    
     TObjArray* fParams;
     
-    ClassDef(SpdPassiveGeoPar,1)
+    ClassDef(SpdPassiveGeoParSet,1)
 };
 
 #endif
diff --git a/spddisplay/CMakeLists.txt b/spddisplay/CMakeLists.txt
index 74eb61c3cc54c4cbd30a3b335afbcbcc1cbd5ead..3acd2a5766c88dc865ed61585366bba40aba89d7 100644
--- a/spddisplay/CMakeLists.txt
+++ b/spddisplay/CMakeLists.txt
@@ -32,6 +32,13 @@ SpdMCTracks.cxx
 
 )
 
+set(HEADERS
+SpdEveEventViewer.h
+SpdEventManager.h
+SpdFairEventManager.h
+SpdMCTracks.h
+)
+
 Set(LINKDEF SpdDisplayLinkDef.h)
 Set(LIBRARY_NAME SpdDisplay)
 Set(DEPENDENCIES Base EventDisplay SpdData SpdField)
diff --git a/spdgenerators/CMakeLists.txt b/spdgenerators/CMakeLists.txt
index 9bddfc61bf1ad645d9feb42b7185bf3dd39c2028..a92bc49c9f2762f8d217e86d0bb937d89ff387fa 100644
--- a/spdgenerators/CMakeLists.txt
+++ b/spdgenerators/CMakeLists.txt
@@ -7,6 +7,7 @@ set(INCLUDE_DIRECTORIES
 ${SYSTEM_INCLUDE_DIRECTORIES}
 ${BASE_INCLUDE_DIRECTORIES}
 ${PYTHIA8_INCLUDE_DIR}
+${Geant4_INCLUDE_DIR}
 ${SIMPATH}/include
 ${CMAKE_SOURCE_DIR}/FtfEvtGen/
 ${CMAKE_SOURCE_DIR}/FtfEvtGen/include
@@ -24,6 +25,7 @@ set(LINK_DIRECTORIES
 ${ROOT_LIBRARY_DIR}
 ${FAIRROOT_LIBRARY_DIR}
 ${SIMPATH}/lib
+${GEANT4_LIBRARY_DIR}
 )
  
 link_directories( ${LINK_DIRECTORIES})
@@ -42,6 +44,24 @@ SpdFtfGenerator.cxx
 SpdIsotropicGenerator.cxx
 SpdPrimaryGenerator.cxx
 SpdPythia8Generator.cxx
+SpdUrqmdGenerator.cxx
+)
+
+set(HEADERS
+SpdDecayer.h
+SpdEvtBaseGenerator.h
+SpdFtfGenerator.h
+SpdGenerator.h
+SpdIsotropicGenerator.h
+SpdMultiParticleGenerator.h
+SpdParticleGenerator.h
+SpdPrimaryGenerator.h
+SpdPrimGenFactory.h
+SpdPythia6Decayer.h
+SpdPythia6Generator.h
+SpdPythia6.h
+SpdPythia8Generator.h
+SpdUrqmdGenerator.h
 )
 
 set(LINKDEF  GenLinkDef.h)
diff --git a/spdgenerators/FtfEvtGen/common.mk b/spdgenerators/FtfEvtGen/common.mk
index ecfb8eca3b898a8a717554191e7889baa3c373a2..da4f1d0fdd01a98296488f8cc92159dd6d4cbefc 100644
--- a/spdgenerators/FtfEvtGen/common.mk
+++ b/spdgenerators/FtfEvtGen/common.mk
@@ -42,8 +42,9 @@ F77FLAGS      = -fPIC
 
 
 CPPFLAGS += -Iinclude
-CPPFLAGS += -I$(CLHEP_INCLUDE_DIR)
-CPPFLAGS += -I$(GEANT4_INCLUDE_DIR)
+#CPPFLAGS += -I$(CLHEP_INCLUDE_DIR)
+#CPPFLAGS += -I$(GEANT4_INCLUDE_DIR)
+CPPFLAGS += -I$(Geant4_INCLUDE_DIRS)
 #LDFLAGS  += -L$(CLHEP_LIB_DIR)
 #LDFLAGS  += -L$(CLHEP_LIBRARY_DIR)
 #LDLIBS   += -l$(CLHEP_LIB)
@@ -55,7 +56,9 @@ GLIBS         = $(ROOTGLIBS) -lEG -lTreePlayer -lMinuit
 
 FTFLIB		= -L$(LIBDIR) -lFtfEvtGen
 
-LDLIBS		+= -L$(GEANT4_LIBRARY_DIR) -lG4clhep -lG4global -lG4geometry -lG4physicslists -lG4materials -lG4processes -lG4track -lG4particles -lEG $(GLIBS)
+#LDLIBS		+= -L$(GEANT4_LIBRARY_DIR) -lG4clhep -lG4global -lG4geometry -lG4physicslists -lG4materials -lG4processes -lG4track -#lG4particles -lEG $(GLIBS)
+
+LDLIBS		+= -L$(SIMPATH)/lib -lG4clhep -lG4global -lG4geometry -lG4physicslists -lG4materials -lG4processes -lG4track -lG4particles -lEG $(GLIBS)
 
 # Static pattern rule for object file dependency on sources:
 $(OBJDIR)/%.o: %.cc
diff --git a/spdgenerators/GenLinkDef.h b/spdgenerators/GenLinkDef.h
index e38061f94c0243b0edcfb2277b36eb78c60245d5..a808a2bb3268c2d3f79ea713a95893a281f5ef5a 100644
--- a/spdgenerators/GenLinkDef.h
+++ b/spdgenerators/GenLinkDef.h
@@ -13,6 +13,7 @@
 #pragma link C++ class SpdPythia8Generator+;
 #pragma link C++ class SpdIsotropicGenerator+;
 #pragma link C++ class SpdFtfGenerator+;
+#pragma link C++ class SpdUrqmdGenerator+;
 
 #pragma link C++ class SpdDecayer+;
 #pragma link C++ class SpdPythia6Decayer+;
diff --git a/spdgenerators/SpdGenerator.cxx b/spdgenerators/SpdGenerator.cxx
index 4dad68388fef8bdb04853efe72a6e2facb2e5157..ed9e11084807530a5ea8b25ae7bc39025cfb5c23 100644
--- a/spdgenerators/SpdGenerator.cxx
+++ b/spdgenerators/SpdGenerator.cxx
@@ -90,6 +90,7 @@ Bool_t SpdGenerator::AddTrack(FairPrimaryGenerator* primGen, Bool_t AddToStack,
                               Double_t e, Double_t time, Double_t weight)
 {
    if (fEvent != 0) {
+       
        Int_t n = fEvent->GetEntriesFast();
        TParticle* part = new ((*fEvent)[n]) TParticle(pdg, num, parent_num, AddToStack, 
                                     -1, -1, px, py, pz, e, vx, vy, vz, time); 
@@ -106,7 +107,7 @@ Bool_t SpdGenerator::AddTrack(FairPrimaryGenerator* primGen, Bool_t AddToStack,
    Int_t DataTrackId  = -1;
      
    if (fGenData) {
-           
+
        if (!primGen) StackTrackId = AddToStack;
          
        TParticle* part = new TParticle(pdg, num, parent_num, StackTrackId, 
@@ -129,10 +130,11 @@ Bool_t SpdGenerator::AddTrack(FairPrimaryGenerator* primGen, Bool_t AddToStack,
        delete part;
    }
    
+  
    if (primGen && AddToStack) {
-       
+    
        SpdPrimaryGenerator* gen = dynamic_cast<SpdPrimaryGenerator*>(primGen);
-     
+  
        if (gen) StackTrackId = gen->GetCurrentTrackId();
        
        primGen->AddTrack(pdg, px, py, pz, vx, vy, vz, DataTrackId, 
diff --git a/spdgenerators/SpdIsotropicGenerator.cxx b/spdgenerators/SpdIsotropicGenerator.cxx
index 6b61c3d1f0ace88752fee9e3ce8458fb1a96b637..0489647b740588c7d117f1940ef3ab82afbea1e3 100644
--- a/spdgenerators/SpdIsotropicGenerator.cxx
+++ b/spdgenerators/SpdIsotropicGenerator.cxx
@@ -257,7 +257,7 @@ void SpdIsotropicGenerator::Initialize(Int_t pdg, Double_t kenergy, Int_t np)
   
     TParticlePDG *part = TDatabasePDG::Instance()->GetParticle(pdg);
     if (!part) {
-        cout << "-E- <SpdIsotropicGenerator::Init> Unknown particle: " << pdg << endl;
+        cout << "-E- <SpdIsotropicGenerator::Initialize> Unknown particle: " << pdg << endl;
         return;
     }
        
diff --git a/spdgenerators/SpdPrimaryGenerator.cxx b/spdgenerators/SpdPrimaryGenerator.cxx
index 2e018d413ef7a61f4120a8f7ea50bdd3f169b549..e645538c683b36348e39dee0a27a41e081f87d50 100644
--- a/spdgenerators/SpdPrimaryGenerator.cxx
+++ b/spdgenerators/SpdPrimaryGenerator.cxx
@@ -565,6 +565,8 @@ Bool_t SpdPrimaryGenerator::FillParsIn(SpdPrimGenParSet* params)
   
   if (fExternalDecayer) params->SetParameter("DecayerStorageIndex",
                                              fExternalDecayer->GetStorageIndex(),0);
+
+  return kTRUE;
 }
 
 //_____________________________________________________________________________
diff --git a/spdgenerators/SpdPythia6Decayer.cxx b/spdgenerators/SpdPythia6Decayer.cxx
index e46fc5f983849f9fb20b642400e8ae5d65db1f69..5a423f6f32dc2537ca7c833556008b0c7955a1d0 100644
--- a/spdgenerators/SpdPythia6Decayer.cxx
+++ b/spdgenerators/SpdPythia6Decayer.cxx
@@ -11,6 +11,8 @@
 #include <TParticle.h>
 #include <TRandom3.h>
 #include <TMath.h>
+#include <TDatabasePDG.h>
+#include <TParticlePDG.h>
 
 #include <TPythia6.h>
 
@@ -108,7 +110,9 @@ void SpdPythia6Decayer::Decay(Int_t idpart, TLorentzVector* p)
 {
    // Decay a particle of type IDPART (PDG code) and momentum P.
     
-   //cout << "-I- <SpdPythia6Decayer::Decay> Particle (pdg): " << idpart << endl;
+   //cout << "-I- <SpdPythia6Decayer::Decay> Particle (pdg): " 
+   //     << TDatabasePDG::Instance()->GetParticle(idpart)->GetName()  
+   //     << " (" << idpart << ")" << endl;
    
    if (!fInit) Init();
     
@@ -120,7 +124,7 @@ void SpdPythia6Decayer::Decay(Int_t idpart, TLorentzVector* p)
    TPythia6::Instance()->GetPrimaries();
    
    fParticlePdg = idpart;
-  
+   
    fCycle++;
     
    if (fDecayer) fDecayer->FillDecay(idpart,p);
@@ -129,8 +133,7 @@ void SpdPythia6Decayer::Decay(Int_t idpart, TLorentzVector* p)
 //______________________________________________________________________________
 Int_t SpdPythia6Decayer::ImportParticles(TClonesArray *particles)
 {
-   // Get the decay products into the passed PARTICLES TClonesArray of
-   // TParticles
+   // Get the decay products into the passed PARTICLES TClonesArray of TParticles
    
    Int_t np = TPythia6::Instance()->ImportParticles(fParticles,"All"); 
 
@@ -151,13 +154,13 @@ Int_t SpdPythia6Decayer::ImportParticles(TClonesArray *particles)
    
    fParticles->Clear();
    
-//   cout << "-I- <SpdPythia6Decayer::ImportParticles> Particle (pdg): " << fParticlePdg 
-//        << " add: " << npp << "/" << np << endl;
+   //cout << "-I- <SpdPythia6Decayer::ImportParticles> Particle (pdg): " << fParticlePdg  
+   //     << " add: " << npp << "/" << np << " Particles list: " << endl;
    
-//    for (Int_t i(0); i<npp; i++) { 
-//         p = (TParticle*)parts.At(i);
-//         p->Print();
-//    }
+   //for (Int_t i(0); i<npp; i++) { 
+   //     p = (TParticle*)parts.At(i);
+   //     p->Print();
+   //}
    
    if (fDecayer) fDecayer->FillParticles(&parts);
         
@@ -189,13 +192,119 @@ Bool_t SpdPythia6Decayer::LoadParsFrom(SpdPrimGenParSet* params, Int_t index)
 //______________________________________________________________________________
 Float_t SpdPythia6Decayer::GetLifetime(Int_t pdg)
 {
-   Int_t kc = TPythia6::Instance()->Pycomp(TMath::Abs(pdg));
+   Int_t  kc = TPythia6::Instance()->Pycomp(TMath::Abs(pdg));
    Float_t t = TPythia6::Instance()->GetPMAS(kc,4) * 3.3333e-12;
    
-   cout << "pdg = " << pdg << " t = " << t << endl;
-   exit(1);
+   //cout << "pdg = " << pdg << " t = " << t << endl;
    
    return t;
 }
 
+//______________________________________________________________________________
+void SpdPythia6Decayer::SelectForcedDecay(Int_t particle, Int_t channel)
+{
+   std::map< Int_t, std::set<Int_t> >::iterator it = fSelectedDecays.find(particle);
+   if (it == fSelectedDecays.end()) {
+       std::set<Int_t> channels;
+       channels.insert(channel);
+       fSelectedDecays[particle] = channels;
+   }
+   else it->second.insert(channel);   
+}
+  
+//______________________________________________________________________________  
+void SpdPythia6Decayer::ForceSelectedDecays()
+{
+   if (fSelectedDecays.empty()) {
+       cout << "-W- <SpdPythia6Decayer::ForceSelectedDecays> Decays list is empty, nothing has been done. " << endl;
+       return;
+   }
+   
+   std::map< Int_t, std::set<Int_t> >::const_iterator it = fSelectedDecays.begin();
+   std::set< Int_t >::const_iterator its; 
+   
+   TPythia6* pythia = TPythia6::Instance();
+   
+   Int_t pdg, channel;
+   Int_t kc, ifirst, ilast;
+   
+   for (; it != fSelectedDecays.end(); it++) 
+   {
+       pdg = it->first;
+       
+       if (!TDatabasePDG::Instance()->GetParticle(pdg)) {
+           cout << "-W- <SpdPythia6Decayer::ForceSelectedDecays> [TDatabasePDG] unknown particle:  " 
+                << pdg << endl;
+           continue;
+       }
+       
+       kc = pythia->Pycomp(pdg);
+       ifirst = pythia->GetMDCY(kc,2);
+       ilast  = ifirst + pythia->GetMDCY(kc,3)-1;
+       
+       its = it->second.begin();
+       
+       fBraPart[kc] = 1.;
+       
+       cout << "\n-I- <SpdPythia6Decayer::ForceSelectedDecays> particle: " << pdg << " " << endl;
+       channel = 0;
+       for (Int_t ch = ifirst; ch <= ilast; ch++) {
+            channel++;
+            if (channel == *its) {
+                pythia->SetMDME(ch,1,1);
+                cout << "\t force channel: " << channel << endl;
+                its++;
+             
+            }
+            else {
+                pythia->SetMDME(ch,1,0);
+                fBraPart[kc] -= pythia->GetBRAT(ch);
+            }
+        }
+   }
+}
+
+//______________________________________________________________________________
+void SpdPythia6Decayer::PrintParticleDecayChannels(Int_t particle /*pdg number*/)
+{
+   TPythia6* pythia = TPythia6::Instance();
+
+   Int_t kc = pythia->Pycomp(particle);
+   
+   pythia->SetMDCY(kc,1,1);
+
+   Int_t ifirst = pythia->GetMDCY(kc,2);
+   Int_t ilast  = ifirst + pythia->GetMDCY(kc,3)-1;
+   
+   TDatabasePDG* db = TDatabasePDG::Instance();
+   TParticlePDG* p = db->GetParticle(particle);
+
+   if (!p) {
+       cout << "-W- <SpdPythia6Decayer::PrintParticleDecayBranching> [TDatabasePDG] unknown particle:  " 
+            << particle << endl;
+       return;
+   }
+   
+   cout << "\n-I- <SpdPythia6Decayer::PrintParticleDecayBranching> Particle (pdg): " 
+        <<  p->GetName() << " (" << particle << ")  Life time [s]: " << GetLifetime(particle) << endl;
+        
+   Double_t brsum(0);
+   
+   //  Loop over decay channels
+   Int_t n(0), pdg;
+   for (Int_t channel = ifirst; channel <= ilast; channel++) {
+        cout << "channel: " << ++n << "; particles: ";
+        for (Int_t i = 1; i <= 5; i++) {
+             pdg = pythia->GetKFDP(channel,i);
+             if (pdg == 0) continue;
+             p = db->GetParticle(pdg);
+             if (p) cout << p->GetName() << " (" << pdg << ") " << " ";
+             else cout << "unknown" << " (" << pdg << ") " << "; ";
+        }
+        cout << " branch ratio: " << pythia->GetBRAT(channel) << endl;
+        brsum += pythia->GetBRAT(channel);
+   }
+   
+   cout << "Braching (sum): " << brsum  << endl;
+}
 
diff --git a/spdgenerators/SpdPythia6Decayer.h b/spdgenerators/SpdPythia6Decayer.h
index b9a08927ddeae29220ea29ff825b7124ae76886c..aad6e871ae95136f43a71eb8f452afe60ad131b4 100644
--- a/spdgenerators/SpdPythia6Decayer.h
+++ b/spdgenerators/SpdPythia6Decayer.h
@@ -5,6 +5,11 @@
 #define __SPDPYTHIA6DECAYER_H__
 
 #include <TPythia6Decayer.h>
+#include <map>
+#include <set>
+
+//using std::map;
+//using std::set;
 
 ////////////////////////////////////////////////////////////////////////////////
 //                                                                            //
@@ -49,6 +54,11 @@ public:
     
     virtual Float_t GetLifetime(Int_t pdg);
    
+    void PrintParticleDecayChannels(Int_t particle /*pdg number*/);
+    void SelectForcedDecay(Int_t particle, Int_t channel);
+    void ForceSelectedDecays();
+    void ClearSelectedDecays() { fSelectedDecays.clear(); } 
+    
 protected:
   
     Int_t         fParticlePdg;  //! current particle id
@@ -60,6 +70,8 @@ protected:
     Bool_t        fInit;
     SpdDecayer*   fDecayer;
     
+    std::map< Int_t, std::set<Int_t> > fSelectedDecays;
+    
     ClassDef(SpdPythia6Decayer,1)
 };
 
diff --git a/spdgenerators/SpdPythia6Generator.cxx b/spdgenerators/SpdPythia6Generator.cxx
index 2737e0195c64ac8d11791d179e596270fbbb7345..40622dba3704ab25e3fb8f3862707c92b4b14d9d 100644
--- a/spdgenerators/SpdPythia6Generator.cxx
+++ b/spdgenerators/SpdPythia6Generator.cxx
@@ -290,7 +290,7 @@ Bool_t SpdPythia6Generator::GenerateDirectly(FairPrimaryGenerator* primGen)
     static const Float_t tmin = 1e-20;
     static const Float_t kmin = 1e-9;
     
-    static const Int_t Nattempt_max = 1000;
+    static const Int_t Nattempt_max = 100000;
     
     TClonesArray* ps;
     TMCParticle *part;
@@ -488,6 +488,10 @@ Bool_t SpdPythia6Generator::GenerateDirectly(FairPrimaryGenerator* primGen)
                 if (addpart) pnn.insert(*it);
            }
            
+           /* !ATTENTION! CHECK EVENT !ATTENTION!*/
+           
+           //if (!IsAcceptableEvent(ps,pnn,true)) continue;
+           
            /* CHECK SELECTED PARTICLES */
            
            for (it = pnn.begin(); it != pnn.end(); it++) {
@@ -657,13 +661,19 @@ bool SpdPythia6Generator::IsAcceptableParticle(Int_t pdg, Bool_t edump) const
        return kFALSE;
    }
    
-   if (ptype.Contains("Charmed")) {
-       if (fVerboseLevel > -2 && fVgenopt > 0) { 
-           cout << "-W- <SpdPythia6Generator::IsAcceptableParticle> Unacceptable particle: "
-                << pdg << " (" << ptype << ") " << endl; 
-       }
-       return kFALSE; 
-   }
+//    if (ptype.Contains("Charmed")) {
+//        if (fVerboseLevel > -2 && fVgenopt > 0) { 
+//            cout << "-W- <SpdPythia6Generator::IsAcceptableParticle> Unacceptable particle: "
+//                 << pdg << " (" << ptype << ") " << endl; 
+//        }
+//        return kFALSE; 
+//    }
+   
+//    if (ptype.Contains("Charmed")) {
+//        cout << "-I- <SpdPythia6Generator::IsAcceptableParticle> Charmed particle: " 
+//             << pdgpart->GetName() << " " << pdg << " (" << ptype << ") " << endl; 
+//        return kTRUE; 
+//    }
      
    if (ptype.Contains("Meson"))  return kTRUE;
    if (ptype.Contains("Baryon")) return kTRUE;
@@ -678,6 +688,34 @@ bool SpdPythia6Generator::IsAcceptableParticle(Int_t pdg, Bool_t edump) const
    return kFALSE;
 }
 
+//_____________________________________________________________________________
+bool SpdPythia6Generator::IsAcceptableEvent(TClonesArray* plist, const std::set<Int_t>& psel, Bool_t edump) const
+{
+     std::set<Int_t>::const_iterator it;
+     TMCParticle* part;
+     TParticlePDG* pdgpart;
+     Int_t pdg(0);
+     TString ptype;
+     
+     Bool_t is_ok = kFALSE;
+     
+     for (it = psel.begin(); it != psel.end(); it++) {
+          part = (TMCParticle*)plist->At(*it);
+          pdg = part->GetKF();
+          pdgpart = TDatabasePDG::Instance()->GetParticle(pdg); 
+          if (!pdgpart) return kFALSE;
+          ptype = pdgpart->ParticleClass();
+          if (ptype.Contains("Charmed")) { is_ok = kTRUE; break; }
+     }
+     
+     if (is_ok && edump) {
+         cout << "-I- <SpdPythia6Generator::IsAcceptableEvent> Accept event with particle: " 
+              << pdgpart->GetName() << " " << pdg << " (" << ptype << ") " << endl;
+     }
+     
+     return is_ok;
+}
+
 //_____________________________________________________________________________
 void SpdPythia6Generator::ClearTest()
 {
diff --git a/spdgenerators/SpdPythia6Generator.h b/spdgenerators/SpdPythia6Generator.h
index 1531d38e8c61d5b4663434eeb04c947d32156b32..dd94b2887470689f30dba3faab3a5c1a5c99671b 100644
--- a/spdgenerators/SpdPythia6Generator.h
+++ b/spdgenerators/SpdPythia6Generator.h
@@ -6,6 +6,7 @@
 
 #include <TRandom3.h>
 #include <map>
+#include <set>
 
 #include "SpdPythia6.h"
 #include "SpdGenerator.h"
@@ -123,7 +124,8 @@ private:
   void   InitSeeds();
   
   bool   IsAcceptableParticle(Int_t pdg, Bool_t edump) const;
-   
+  bool   IsAcceptableEvent(TClonesArray* plist, const std::set<Int_t>& psel, Bool_t edump) const; 
+  
   TString        fFrame;      // frame of the experiment
   TString        fBeam;       // beam particle
   TString        fTarget;     // target particle
diff --git a/spdgenerators/SpdUrqmdGenerator.cxx b/spdgenerators/SpdUrqmdGenerator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..171f3751948b0e700091fe1b7c54335fd6e54d9f
--- /dev/null
+++ b/spdgenerators/SpdUrqmdGenerator.cxx
@@ -0,0 +1,489 @@
+// -------------------------------------------------------------------------
+// -----                SpdUrqmdGenerator source file                  -----
+// -----                Created 24/06/04  by V. Friese                 -----
+// -------------------------------------------------------------------------
+#include "SpdUrqmdGenerator.h"
+
+#include "FairPrimaryGenerator.h"
+#include "FairMCEventHeader.h"
+//#include "constants.h"
+
+#include "TMCProcess.h"
+#include "TObjArray.h"
+#include "TPDGCode.h"
+#include "TParticle.h"
+#include "TRandom.h"
+#include "TString.h"
+#include "TVirtualMCStack.h"
+#include "TLorentzVector.h"
+#include "TDatabasePDG.h"
+#include "TParticlePDG.h"
+#include <iostream>
+#include <cstring>
+
+#include <stdio.h>
+
+using namespace std;
+using namespace TMath;
+
+//const Double_t kProtonMass = 0.938271998;
+
+
+// -----   Default constructor   ------------------------------------------
+
+SpdUrqmdGenerator::SpdUrqmdGenerator()
+: SpdGenerator("SPD URQMD Generator"),
+fInputFile(NULL),
+fParticleTable(),
+fFileName(NULL),
+fPhiMin(0.),
+fPhiMax(0.),
+fEventPlaneSet(kFALSE) {
+}
+// ------------------------------------------------------------------------
+
+
+
+// -----   Standard constructor   -----------------------------------------
+
+SpdUrqmdGenerator::SpdUrqmdGenerator(const char* fileName)
+: SpdGenerator("SPD URQMD Generator"),
+  fInputFile(NULL),
+  fParticleTable(),
+  fFileName(fileName),
+  fPhiMin(0.),
+  fPhiMax(0.),
+  fEventPlaneSet(kFALSE),
+  fParticles(0),
+  fVerbose(0),
+  fKeepEvent(kFALSE) {
+    //  fFileName = fileName;
+    cout << "-I SpdUrqmdGenerator: Opening input file " << fFileName << endl;
+    fInputFile = gzopen(fFileName, "rb");
+    if (!fInputFile) {
+        Fatal("SpdUrqmdGenerator", "Cannot open input file.");
+        exit(1);
+    }
+    cout << "done!" << endl;
+    ReadConversionTable();
+}
+// ------------------------------------------------------------------------
+
+
+
+// -----   Destructor   ---------------------------------------------------
+
+SpdUrqmdGenerator::~SpdUrqmdGenerator() {
+    //  cout<<"Enter Destructor of SpdUrqmdGenerator"<<endl;
+    if (fInputFile) {
+#ifdef GZIP_SUPPORT
+        gzclose(fInputFile);
+#else
+        fclose(fInputFile);
+#endif
+        fInputFile = NULL;
+    }
+    fParticleTable.clear();
+    //  cout<<"Leave Destructor of SpdUrqmdGenerator"<<endl;
+    if (fParticles) {
+        fParticles->Delete();
+        delete fParticles;
+    }
+}
+// ------------------------------------------------------------------------
+
+void SpdUrqmdGenerator::ResetEvent()
+{
+   if (fParticles) 
+      fParticles->Clear();
+}
+
+void SpdUrqmdGenerator::SetKeepEvent(Bool_t v)
+{
+    if (v) {
+        if (!fParticles) fParticles = new TClonesArray("TParticle");
+        else fParticles->Delete();
+    }
+    else {
+        if (fParticles) {
+            fParticles->Delete();
+            delete fParticles;
+            fParticles = 0;
+        }
+    }
+
+   fKeepEvent = v;
+}
+// -----   Public method ReadEvent   --------------------------------------
+
+Bool_t SpdUrqmdGenerator::ReadEvent(FairPrimaryGenerator* primGen) {
+
+    // ---> Check for input file
+    if (!fInputFile) {
+        cout << "-E SpdUrqmdGenerator: Input file not open! " << endl;
+        return kFALSE;
+    }
+
+    // ---> Check for primary generator
+    //if (!primGen) {
+    //    cout << "-E- SpdUrqmdGenerator::ReadEvent: "
+    //            << "No PrimaryGenerator!" << endl;
+    //    return kFALSE;
+    //}
+
+    // ---> Define event variables to be read from file
+    int evnr = 0, ntracks = 0, aProj = 0, zProj = 0, aTarg = 0, zTarg = 0;
+    float b = 0., ekin = 0.;
+
+    int ityp = 0, i3 = 0, ichg = 0, pid = 0;
+    float ppx = 0., ppy = 0., ppz = 0., m = 0.;
+
+    // ---> Read and check first event header line from input file
+    char read[200];
+#ifdef GZIP_SUPPORT
+    gzgets(fInputFile, read, 200); // line 1
+#else
+    fgets(read, 200, fInputFile);
+#endif
+    Int_t urqmdVersion = 0;
+    sscanf(read, "UQMD   version:       %d   1000  %d  output_file  14", &urqmdVersion, &urqmdVersion);
+    cout << "URQMD VERSION USED = " << urqmdVersion << endl;
+#ifdef GZIP_SUPPORT
+    if (gzeof(fInputFile)) {
+        cout << "-I SpdUrqmdGenerator : End of input file reached." << endl;
+        gzclose(fInputFile);
+#else
+    if ( feof(fInputFile) ) {
+        cout << "-I SpdUrqmdGenerator : End of input file reached." << endl;
+        fclose(fInputFile);
+#endif
+        fInputFile = NULL;
+        return kFALSE;
+    }
+    if (read[0] != 'U') {
+        cout << "-E SpdUrqmdGenerator: Wrong event header" << endl;
+        return kFALSE;
+    }
+
+    // ---> Read rest of event header
+#ifdef GZIP_SUPPORT
+    gzgets(fInputFile, read, 200); // line 2
+    sscanf(read, "projectile:  (mass, char) %d %d target:  (mass, char) %d %d",
+            &aProj, &zProj, &aTarg, &zTarg); // line 2
+    gzgets(fInputFile, read, 200); // line 3
+    gzgets(fInputFile, read, 36); // line 4
+    gzgets(fInputFile, read, 200); // line 4
+    sscanf(read, "%f", &b); // line 4
+    gzgets(fInputFile, read, 39); // line 5
+    gzgets(fInputFile, read, 200); // line 5
+    sscanf(read, "%e", &ekin); // line 5
+    gzgets(fInputFile, read, 7); // line 6
+    gzgets(fInputFile, read, 200); // line 6
+    sscanf(read, "%d", &evnr); // line 6
+
+    for (Int_t iline = 0; iline < ((urqmdVersion == 30400) ? 11 : 8); iline++)
+        gzgets(fInputFile, read, 200);
+
+    gzgets(fInputFile, read, 200); // line 18
+    sscanf(read, "%d", &ntracks); // line 18
+    gzgets(fInputFile, read, 200); // line 19
+#else
+    fgets(read, 26, fInputFile);
+    fscanf(fInputFile, "%d", &aProj);
+    fscanf(fInputFile, "%d", &zProj);
+    fgets(read, 25, fInputFile);
+    fscanf(fInputFile, "%d", &aTarg);
+    fscanf(fInputFile, "%d", &zTarg);
+    fgets(read, 200, fInputFile);
+    fgets(read, 200, fInputFile);
+    fgets(read, 36, fInputFile);
+    fscanf(fInputFile, "%f", &b);
+    fgets(read, 200, fInputFile);
+    fgets(read, 39, fInputFile);
+    fscanf(fInputFile, "%e", &ekin);
+    fgets(read, 200, fInputFile);
+    fgets(read, 7, fInputFile);
+    fscanf(fInputFile, "%d", &evnr);
+    fgets(read, 200, fInputFile);
+    for (int iline=0; iline<8; iline++)  { fgets(read, 200,fInputFile); }
+    fscanf(fInputFile, "%d", &ntracks);
+    fgets(read, 200, fInputFile);
+    fgets(read, 200, fInputFile);
+#endif
+
+    // ---> Calculate beta and gamma for Lorentztransformation
+    TDatabasePDG* pdgDB = TDatabasePDG::Instance();
+    TParticlePDG* kProton = pdgDB->GetParticle(2212);
+    Double_t kProtonMass = kProton->Mass();
+
+    Double_t eBeam = ekin + kProtonMass;
+    Double_t pBeam = TMath::Sqrt(eBeam * eBeam - kProtonMass * kProtonMass);
+    Double_t betaCM = pBeam / (eBeam + kProtonMass);
+    Double_t gammaCM = TMath::Sqrt(1. / (1. - betaCM * betaCM));
+
+    cout << "-I SpdUrqmdGenerator: Event " << evnr << ",  b = " << b
+            << " fm,  multiplicity " << ntracks << ", ekin: " << ekin << endl;
+
+
+    Double_t phi = 0.;
+    // ---> Generate rotation angle
+    if (fEventPlaneSet) {
+        phi = gRandom->Uniform(fPhiMin, fPhiMax);
+    }
+
+    // Set event id and impact parameter in MCEvent if not yet done
+
+    if(primGen){
+      FairMCEventHeader* event = primGen->GetEvent();
+      if (event && (!event->IsSet())) {
+        event->SetEventID(evnr);
+        event->SetB(b);
+        event->MarkSet(kTRUE);
+        event->SetRotZ(phi);
+       }
+    }
+
+    Int_t itr = 0;
+    // ---> Loop over tracks in the current event
+    for (int itrack = 0; itrack < ntracks; itrack++) {
+        if(fVerbose > 1) cout << "Read track " << itrack << endl;
+        // Read momentum and PID from file
+#ifdef GZIP_SUPPORT
+        gzgets(fInputFile, read, 81);
+        gzgets(fInputFile, read, 200);
+        sscanf(read, "%e %e %e %e %d %d %d", &ppx, &ppy, &ppz, &m, &ityp, &i3, &ichg);
+#else
+        fgets(read, 81, fInputFile);
+        fscanf(fInputFile, "%e", &ppx);
+        fscanf(fInputFile, "%e", &ppy);
+        fscanf(fInputFile, "%e", &ppz);
+        fscanf(fInputFile, "%e", &m);
+        fscanf(fInputFile, "%d", &ityp);
+        fscanf(fInputFile, "%d", &i3);
+        fscanf(fInputFile, "%d", &ichg);
+        fgets(read, 200, fInputFile);
+#endif
+
+        // Convert UrQMD type and charge to unique pid identifier
+        if (ityp >= 0) {
+            pid = 1000 * (ichg + 2) + ityp;
+        } else {
+            pid = -1000 * (ichg + 2) + ityp;
+        }
+
+        // Convert Unique PID into PDG particle code
+        if (fParticleTable.find(pid) == fParticleTable.end()) {
+            cout << "-W SpdUrqmdGenerator: PID " << ityp << " charge "
+                    << ichg << " not found in table (" << pid << ")" << endl;
+            continue;
+        }
+        Int_t pdgID = fParticleTable[pid];
+
+        // CM system
+        Double_t mass = Double_t(m);
+        Double_t px = Double_t(ppx);
+        Double_t py = Double_t(ppy);
+        Double_t pz = Double_t(ppz);
+        Double_t e = sqrt(mass * mass + px * px + py * py + pz * pz);
+    //  transform to laboratory
+    //    if (gCoordinateSystem == sysLaboratory) 
+    //        pz = gammaCM * (pz + betaCM * e);
+        Double_t ee = sqrt(mass * mass + px * px + py * py + pz * pz);
+
+        if (fEventPlaneSet) {
+            Double_t pt = Sqrt(px * px + py * py);
+            Double_t azim = ATan2(py, px);
+            azim += phi;
+            px = pt * Cos(azim);
+            py = pt * Sin(azim);
+        }
+
+        TLorentzVector pp;
+        pp.SetPx(px);
+        pp.SetPy(py);
+        pp.SetPz(pz);
+        pp.SetE(ee);
+
+        if (fKeepEvent && fParticles) {
+            Int_t np = fParticles->GetEntriesFast();
+            TParticle* particle = new ((*fParticles)[np]) TParticle();
+            particle->SetPdgCode(pdgID);
+            particle->SetProductionVertex(0, 0, 0, 0); 
+
+            if(fVerbose)
+                cout << "   PDG " << pdgID << " " << px << " " << py << " " << pz << endl;
+                        
+            TParticlePDG* pdgpart = TDatabasePDG::Instance()->GetParticle(pdgID); 
+            if (pdgpart) {
+                 Double_t pdgmass = pdgpart->Mass();
+                 Double_t te = TMath::Sqrt(px*px + py*py + pz*pz + pdgmass*pdgmass);   
+                 particle->SetMomentum(px, py, pz, te);
+            }
+            else {
+                 particle->SetMomentum(px, py, pz, -1);    
+            }
+        }
+
+
+
+
+      // Give track to PrimaryGenerator  (for FairGenerator only!)
+      // if(primGen) 
+	  // {
+      //        //primGen->AddTrack(pdgID, px, py, pz, 0., 0., 0.);
+      // }  
+      
+      AddTrack(primGen, 1, pdgID , itr++, -1, px, py, pz); 
+           
+    }
+
+    return kTRUE;
+}
+// ------------------------------------------------------------------------
+
+
+// -----   Public method ReadEvent   --------------------------------------
+
+Bool_t SpdUrqmdGenerator::SkipEvents(Int_t count) {
+    if (count <= 0) {
+        return kTRUE;
+    }
+
+    for (Int_t ii = 0; ii < count; ii++) {
+        // ---> Check for input file
+        if (!fInputFile) {
+            cout << "-E SpdUrqmdGenerator: Input file not open! " << endl;
+            return kFALSE;
+        }
+
+        // ---> Define event variables to be read from file
+        int evnr = 0, ntracks = 0, aProj = 0, zProj = 0, aTarg = 0, zTarg = 0;
+        float b = 0., ekin = 0.;
+
+        // ---> Read and check first event header line from input file
+        char read[200];
+#ifdef GZIP_SUPPORT
+        gzgets(fInputFile, read, 200); // line 1
+#else
+        fgets(read, 200, fInputFile);
+#endif
+        Int_t urqmdVersion = 0;
+        sscanf(read, "UQMD   version:       %d   1000  %d  output_file  14", &urqmdVersion, &urqmdVersion);
+        cout << "URQMD VERSION USED = " << urqmdVersion << endl;
+
+#ifdef GZIP_SUPPORT
+        if (gzeof(fInputFile)) {
+            cout << "-I SpdUrqmdGenerator : End of input file reached." << endl;
+            gzclose(fInputFile);
+#else
+        if ( feof(fInputFile) ) {
+            cout << "-I SpdUrqmdGenerator : End of input file reached." << endl;
+            fclose(fInputFile);
+#endif
+            fInputFile = NULL;
+            return kFALSE;
+        }
+        if (read[0] != 'U') {
+            cout << "-E SpdUrqmdGenerator: Wrong event header" << endl;
+            return kFALSE;
+        }
+
+        // ---> Read rest of event header
+#ifdef GZIP_SUPPORT
+        gzgets(fInputFile, read, 200); // line 2
+        sscanf(read, "projectile:  (mass, char) %d %d target:  (mass, char) %d %d",
+                &aProj, &zProj, &aTarg, &zTarg); // line 2
+        gzgets(fInputFile, read, 200); // line 3
+        gzgets(fInputFile, read, 36); // line 4
+        gzgets(fInputFile, read, 200); // line 4
+        sscanf(read, "%f", &b); // line 4
+        gzgets(fInputFile, read, 39); // line 5
+        gzgets(fInputFile, read, 200); // line 5
+        sscanf(read, "%e", &ekin); // line 5
+        gzgets(fInputFile, read, 7); // line 6
+        gzgets(fInputFile, read, 200); // line 6
+        sscanf(read, "%d", &evnr); // line 6
+
+        for (Int_t iline = 0; iline < ((urqmdVersion == 30400) ? 11 : 8); iline++)
+            gzgets(fInputFile, read, 200);
+
+        gzgets(fInputFile, read, 200); // line 15
+        sscanf(read, "%d", &ntracks); // line 15
+        gzgets(fInputFile, read, 200); // line 16
+#else
+        fgets(read, 26, fInputFile);
+        fscanf(fInputFile, "%d", &aProj);
+        fscanf(fInputFile, "%d", &zProj);
+        fgets(read, 25, fInputFile);
+        fscanf(fInputFile, "%d", &aTarg);
+        fscanf(fInputFile, "%d", &zTarg);
+        fgets(read, 200, fInputFile);
+        fgets(read, 200, fInputFile);
+        fgets(read, 36, fInputFile);
+        fscanf(fInputFile, "%f", &b);
+        fgets(read, 200, fInputFile);
+        fgets(read, 39, fInputFile);
+        fscanf(fInputFile, "%e", &ekin);
+        fgets(read, 200, fInputFile);
+        fgets(read, 7, fInputFile);
+        fscanf(fInputFile, "%d", &evnr);
+        fgets(read, 200, fInputFile);
+        for (int iline=0; iline<8; iline++)  { fgets(read, 200,fInputFile); }
+        fscanf(fInputFile, "%d", &ntracks);
+        fgets(read, 200, fInputFile);
+        fgets(read, 200, fInputFile);
+#endif
+
+        cout << "-I SpdUrqmdGenerator: Event " << evnr << " skipped!" << endl;
+
+        // ---> Loop over tracks in the current event
+        for (int itrack = 0; itrack < ntracks; itrack++) {
+
+            // Read momentum and PID from file
+#ifdef GZIP_SUPPORT
+            gzgets(fInputFile, read, 200);
+#else
+            fgets(read, 81, fInputFile);
+            fgets(read, 200, fInputFile);
+#endif
+        }
+    }
+    return kTRUE;
+}
+// ------------------------------------------------------------------------
+
+// -----   Private method ReadConverisonTable   ---------------------------
+
+void SpdUrqmdGenerator::ReadConversionTable() {
+
+    TString work = getenv("VMCWORKDIR");
+    TString fileName = work + "/input/urqmd_pdg.dat";
+    ifstream* pdgconv = new ifstream(fileName.Data());
+
+    Int_t index = 0;
+    Int_t pdgId = 0;
+
+    while (!pdgconv->eof()) {
+        index = pdgId = 0;
+        *pdgconv >> index >> pdgId;
+        fParticleTable[index] = pdgId;
+    }
+
+    pdgconv->close();
+    delete pdgconv;
+
+    cout << "-I SpdUrqmdGenerator: Particle table for conversion from "
+            << "UrQMD loaded" << endl;
+
+}
+// ------------------------------------------------------------------------
+
+void SpdUrqmdGenerator::SetEventPlane(Double_t phiMin, Double_t phiMax) {
+    fPhiMin = phiMin;
+    fPhiMax = phiMax;
+    fEventPlaneSet = kTRUE;
+}
+
+
+
+ClassImp(SpdUrqmdGenerator);
diff --git a/spdgenerators/SpdUrqmdGenerator.h b/spdgenerators/SpdUrqmdGenerator.h
new file mode 100644
index 0000000000000000000000000000000000000000..4cdfdd5541caa740ba8c61de2a9e1530a3985a41
--- /dev/null
+++ b/spdgenerators/SpdUrqmdGenerator.h
@@ -0,0 +1,109 @@
+// -------------------------------------------------------------------------
+// -----                SpdUrqmdGenerator header file                  -----
+// -----          Created 11/06/04  by V. Friese / D.Bertini           -----
+// -------------------------------------------------------------------------
+
+
+/** SpdUrqmdGenerator.h
+ *@ author V.Friese <v.friese@gsi.de>
+ *@author D.Bertini <d.bertini@gsi.de>
+ *
+ The SpdUrqmdGenerator reads the output file 14 (ftn14) from UrQMD. The UrQMD
+ calculation has to be performed in the CM system of the collision; Lorentz
+ transformation into the lab is performed by this class.
+ Derived from FairGenerator.
+**/
+#define GZIP_SUPPORT // version with gz support
+
+#ifndef SPDURQMDGENERATOR_H
+#define SPDURQMDGENERATOR_H
+
+#include "SpdGenerator.h"
+
+#include <fstream>
+#include <map>
+
+#include "TClonesArray.h"
+
+#ifdef GZIP_SUPPORT
+#ifndef __CINT__
+#include <zlib.h>
+#endif
+#endif
+
+class TVirtualMCStack;
+class FairPrimaryGenerator;
+
+class SpdUrqmdGenerator : public SpdGenerator
+{
+  public:
+
+    /** Default constructor without arguments should not be used. **/
+    SpdUrqmdGenerator();
+
+
+    /** Standard constructor.
+     * @param fileName The input file name
+     **/
+    SpdUrqmdGenerator(const char* fileName);
+
+
+    /** Destructor. **/
+    ~SpdUrqmdGenerator();
+
+    virtual Bool_t Init() { return kTRUE; }  //FIXME!!!
+
+    /** Reads on event from the input file and pushes the tracks onto
+     ** the stack. Abstract method in base class.
+     ** @param pStack    pointer to the stack
+     ** @param ver       not used
+     **/
+    Bool_t ReadEvent(FairPrimaryGenerator* primGen);
+
+    //Skip some events in file
+    Bool_t SkipEvents(Int_t count);
+
+    void SetEventPlane(Double_t phiMin, Double_t phiMax); //FIXME!!!
+
+   inline const TClonesArray* GetEvent() const { return fParticles; }
+   void SetKeepEvent(Bool_t v);
+   void ResetEvent();
+  
+   void SetVerboseLevel(Int_t vl) {fVerbose = vl;} //FIXME!!!
+
+  private:
+
+#ifdef GZIP_SUPPORT
+    #ifndef __CINT__
+    gzFile fInputFile;                    //!  Input file
+    #endif
+#else
+    FILE* fInputFile;                     //!  Input file
+#endif
+
+    std::map<Int_t,Int_t> fParticleTable;      //!  Map from UrQMD PID to PDGPID
+
+    Double32_t fPhiMin, fPhiMax; // Limits of event plane angle          //FIXME!!!
+    Bool_t fEventPlaneSet; // Flag whether event plane angle is used      //FIXME!!!
+
+    const Char_t* fFileName;              //!  Input file name
+
+    /** Private method ReadConversionTable. Reads the conversion table
+        from UrQMD particle code to PDG particle code and fills the
+        conversion map. Is called from the constructor. **/
+    void ReadConversionTable();
+
+    TClonesArray* fParticles; // local storage
+    Bool_t fKeepEvent;
+    Int_t fVerbose; //FIXME!!!
+
+    SpdUrqmdGenerator(const SpdUrqmdGenerator&);
+    SpdUrqmdGenerator& operator=(const SpdUrqmdGenerator&);
+
+    ClassDef(SpdUrqmdGenerator,1);
+
+};
+
+#endif
+
+
diff --git a/spdgeometry/CMakeLists.txt b/spdgeometry/CMakeLists.txt
index deb2e89d166e2b6f4b58d928378244983a88f0ac..64721d117bf2c683ba36dc41aaef72b55fd85b27 100644
--- a/spdgeometry/CMakeLists.txt
+++ b/spdgeometry/CMakeLists.txt
@@ -44,10 +44,14 @@ set(SRCS
 ./tst/SpdTsTECGeoBuilder.cxx
 
 ./ecalt/SpdEcalTBGeoMapper.cxx
+./ecalt/SpdEcalTB2GeoMapper.cxx
 ./ecalt/SpdEcalTECGeoMapper.cxx
+./ecalt/SpdEcalTEC2GeoMapper.cxx
 
 ./rst/SpdRsTBGeoMapper.cxx
+./rst/SpdRsTB2GeoMapper.cxx
 ./rst/SpdRsTECGeoMapper.cxx
+./rst/SpdRsTEC2GeoMapper.cxx
 
 ./sol/SpdTsSBGeoMapper.cxx
 ./sol/SpdTsSBGeoBuilder.cxx
@@ -63,6 +67,35 @@ SpdGeoFactory.cxx
 SpdGeoLoader.cxx
 )
 
+set(HEADERS
+ecalt/SpdEcalTB2GeoMapper.h
+ecalt/SpdEcalTBGeoMapper.h
+ecalt/SpdEcalTEC2GeoMapper.h
+ecalt/SpdEcalTECGeoMapper.h
+its/SpdItsGeoBuilder.h
+its/SpdItsGeoMapperX.h
+its/SpdItsVolPars.h
+rst/SpdRsTB2GeoMapper.h
+rst/SpdRsTBGeoMapper.h
+rst/SpdRsTEC2GeoMapper.h
+rst/SpdRsTECGeoMapper.h
+sol/SpdEcalSBGeoMapper.h
+sol/SpdEcalSECGeoMapper.h
+sol/SpdRsSBGeoMapper.h
+sol/SpdRsSECGeoMapper.h
+sol/SpdTsSBGeoBuilder.h
+sol/SpdTsSBGeoMapper.h
+sol/SpdTsSECGeoMapper.h
+SpdGeoFactory.h
+SpdGeoLoader.h
+tst/SpdTsBVolPars.h
+tst/SpdTsECVolPars.h
+tst/SpdTsTBGeoBuilder.h
+tst/SpdTsTBGeoMapper.h
+tst/SpdTsTECGeoBuilder.h
+tst/SpdTsTECGeoMapper.h
+)
+
 set(LINKDEF  SpdGeometryLinkDef.h)
 set(LIBRARY_NAME SpdGeometry)
 
diff --git a/spdgeometry/SpdGeoFactory.cxx b/spdgeometry/SpdGeoFactory.cxx
index bc8e953b296c26c523cb2800339a869d1b5fccb2..7254332aa8d93d65f72991afd7f254f6c2b38d02 100644
--- a/spdgeometry/SpdGeoFactory.cxx
+++ b/spdgeometry/SpdGeoFactory.cxx
@@ -12,12 +12,16 @@
 #include "SpdItsGeoMapperX.h"
 
 #include "SpdEcalTBGeoMapper.h"
+#include "SpdEcalTB2GeoMapper.h"
 #include "SpdEcalTECGeoMapper.h"
+#include "SpdEcalTEC2GeoMapper.h"
 #include "SpdEcalSBGeoMapper.h"
 #include "SpdEcalSECGeoMapper.h"
 
 #include "SpdRsTBGeoMapper.h"
+#include "SpdRsTB2GeoMapper.h"
 #include "SpdRsTECGeoMapper.h"
+#include "SpdRsTEC2GeoMapper.h"
 #include "SpdRsSBGeoMapper.h"
 #include "SpdRsSECGeoMapper.h"
 
@@ -78,55 +82,55 @@ SpdGeoMapper* SpdGeoFactory::SearchForMapper(DetectorId id)
   switch (id) {
     
     case  kSpdIts : {
-          mapper = SpdItsGeoMapperX::Instance()->GetMapper(); 
+          mapper = SpdItsGeoMapperX::GetMapper(); 
           break; 
     }
     case  kSpdEcalTB  : { 
-          mapper = SpdEcalTBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdEcalTBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdEcalTEC : { 
-          mapper = SpdEcalTECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdEcalTECGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdTsTB  : { 
-          mapper = SpdTsTBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdTsTBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdTsTEC : { 
-          mapper = SpdTsTECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdTsTECGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdRsTB  : { 
-          mapper = SpdRsTBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdRsTBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdRsTEC : { 
-          mapper = SpdRsTECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdRsTECGeoMapper::GetMapper(); 
           break; 
     } 
     case  kSpdEcalSB  : { 
-          mapper = SpdEcalSBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdEcalSBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdEcalSEC : { 
-          mapper = SpdEcalSECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdEcalSECGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdTsSB  : { 
-          mapper = SpdTsSBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdTsSBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdTsSEC : { 
-          mapper = SpdTsSECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdTsSECGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdRsSB  : { 
-          mapper = SpdRsSBGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdRsSBGeoMapper::GetMapper(); 
           break; 
     }
     case  kSpdRsSEC : { 
-          mapper = SpdRsSECGeoMapper::Instance()->GetMapper(); 
+          mapper = SpdRsSECGeoMapper::GetMapper(); 
           break; 
     }
     
@@ -141,21 +145,27 @@ SpdGeoMapper* SpdGeoFactory::SearchForMapper(TString classname)
 {
   SpdGeoMapper* mapper = 0;
   
-       if (classname == "SpdItsGeoMapperX")    mapper = SpdItsGeoMapperX::GetMapper();
+  //cout << "-I <SpdGeoFactory::SearchForMapper> " << classname << endl;
   
-  else if (classname == "SpdEcalTBGeoMapper")  mapper = SpdEcalTBGeoMapper::GetMapper();
-  else if (classname == "SpdEcalTECGeoMapper") mapper = SpdEcalTECGeoMapper::GetMapper();
-  else if (classname == "SpdTsTBGeoMapper")    mapper = SpdTsTBGeoMapper::GetMapper();
-  else if (classname == "SpdTsTECGeoMapper")   mapper = SpdTsTECGeoMapper::GetMapper();
-  else if (classname == "SpdRsTBGeoMapper")    mapper = SpdRsTBGeoMapper::GetMapper();
-  else if (classname == "SpdRsTECGeoMapper")   mapper = SpdRsTECGeoMapper::GetMapper();
+       if (classname == "SpdItsGeoMapperX")     mapper = SpdItsGeoMapperX::GetMapper();
   
-  else if (classname == "SpdEcalSBGeoMapper")  mapper = SpdEcalSBGeoMapper::GetMapper();
-  else if (classname == "SpdEcalSECGeoMapper") mapper = SpdEcalSECGeoMapper::GetMapper();
-  else if (classname == "SpdTsSBGeoMapper")    mapper = SpdTsSBGeoMapper::GetMapper();
-  else if (classname == "SpdTsSECGeoMapper")   mapper = SpdTsSECGeoMapper::GetMapper();
-  else if (classname == "SpdRsSBGeoMapper")    mapper = SpdRsSBGeoMapper::GetMapper();
-  else if (classname == "SpdRsSECGeoMapper")   mapper = SpdRsSECGeoMapper::GetMapper();
+  else if (classname == "SpdEcalTBGeoMapper")   mapper = SpdEcalTBGeoMapper::GetMapper();
+  else if (classname == "SpdEcalTB2GeoMapper")  mapper = SpdEcalTB2GeoMapper::GetMapper();
+  else if (classname == "SpdEcalTECGeoMapper")  mapper = SpdEcalTECGeoMapper::GetMapper();
+  else if (classname == "SpdEcalTEC2GeoMapper") mapper = SpdEcalTEC2GeoMapper::GetMapper();
+  else if (classname == "SpdTsTBGeoMapper")     mapper = SpdTsTBGeoMapper::GetMapper();
+  else if (classname == "SpdTsTECGeoMapper")    mapper = SpdTsTECGeoMapper::GetMapper();
+  else if (classname == "SpdRsTBGeoMapper")     mapper = SpdRsTBGeoMapper::GetMapper();
+  else if (classname == "SpdRsTB2GeoMapper")    mapper = SpdRsTB2GeoMapper::GetMapper();
+  else if (classname == "SpdRsTECGeoMapper")    mapper = SpdRsTECGeoMapper::GetMapper();
+  else if (classname == "SpdRsTEC2GeoMapper")   mapper = SpdRsTEC2GeoMapper::GetMapper();
+  
+  else if (classname == "SpdEcalSBGeoMapper")   mapper = SpdEcalSBGeoMapper::GetMapper();
+  else if (classname == "SpdEcalSECGeoMapper")  mapper = SpdEcalSECGeoMapper::GetMapper();
+  else if (classname == "SpdTsSBGeoMapper")     mapper = SpdTsSBGeoMapper::GetMapper();
+  else if (classname == "SpdTsSECGeoMapper")    mapper = SpdTsSECGeoMapper::GetMapper();
+  else if (classname == "SpdRsSBGeoMapper")     mapper = SpdRsSBGeoMapper::GetMapper();
+  else if (classname == "SpdRsSECGeoMapper")    mapper = SpdRsSECGeoMapper::GetMapper();
     
   return mapper;
 }
@@ -165,21 +175,25 @@ SpdGeoMapper* SpdGeoFactory::Mapper(TString classname)
 {
   SpdGeoMapper* mapper = 0;
   
-       if (classname == "SpdItsGeoMapperX")    mapper = SpdItsGeoMapperX::Instance();
+       if (classname == "SpdItsGeoMapperX")     mapper = SpdItsGeoMapperX::Instance();
    
-  else if (classname == "SpdEcalTBGeoMapper")  mapper = SpdEcalTBGeoMapper::Instance();
-  else if (classname == "SpdEcalTECGeoMapper") mapper = SpdEcalTECGeoMapper::Instance();
-  else if (classname == "SpdTsTBGeoMapper")    mapper = SpdTsTBGeoMapper::Instance();
-  else if (classname == "SpdTsTECGeoMapper")   mapper = SpdTsTECGeoMapper::Instance();
-  else if (classname == "SpdRsTBGeoMapper")    mapper = SpdRsTBGeoMapper::Instance();
-  else if (classname == "SpdRsTECGeoMapper")   mapper = SpdRsTECGeoMapper::Instance();
+  else if (classname == "SpdEcalTBGeoMapper")   mapper = SpdEcalTBGeoMapper::Instance();
+  else if (classname == "SpdEcalTB2GeoMapper")  mapper = SpdEcalTB2GeoMapper::Instance();
+  else if (classname == "SpdEcalTECGeoMapper")  mapper = SpdEcalTECGeoMapper::Instance();
+  else if (classname == "SpdEcalTEC2GeoMapper") mapper = SpdEcalTEC2GeoMapper::Instance();
+  else if (classname == "SpdTsTBGeoMapper")     mapper = SpdTsTBGeoMapper::Instance();
+  else if (classname == "SpdTsTECGeoMapper")    mapper = SpdTsTECGeoMapper::Instance();
+  else if (classname == "SpdRsTBGeoMapper")     mapper = SpdRsTBGeoMapper::Instance();
+  else if (classname == "SpdRsTB2GeoMapper")    mapper = SpdRsTB2GeoMapper::Instance();
+  else if (classname == "SpdRsTECGeoMapper")    mapper = SpdRsTECGeoMapper::Instance();
+  else if (classname == "SpdRsTEC2GeoMapper")   mapper = SpdRsTEC2GeoMapper::Instance();
   
-  else if (classname == "SpdEcalSBGeoMapper")  mapper = SpdEcalSBGeoMapper::Instance();
-  else if (classname == "SpdEcalSECGeoMapper") mapper = SpdEcalSECGeoMapper::Instance();
-  else if (classname == "SpdTsSBGeoMapper")    mapper = SpdTsSBGeoMapper::Instance();
-  else if (classname == "SpdTsSECGeoMapper")   mapper = SpdTsSECGeoMapper::Instance();
-  else if (classname == "SpdRsSBGeoMapper")    mapper = SpdRsSBGeoMapper::Instance();
-  else if (classname == "SpdRsSECGeoMapper")   mapper = SpdRsSECGeoMapper::Instance();
+  else if (classname == "SpdEcalSBGeoMapper")   mapper = SpdEcalSBGeoMapper::Instance();
+  else if (classname == "SpdEcalSECGeoMapper")  mapper = SpdEcalSECGeoMapper::Instance();
+  else if (classname == "SpdTsSBGeoMapper")     mapper = SpdTsSBGeoMapper::Instance();
+  else if (classname == "SpdTsSECGeoMapper")    mapper = SpdTsSECGeoMapper::Instance();
+  else if (classname == "SpdRsSBGeoMapper")     mapper = SpdRsSBGeoMapper::Instance();
+  else if (classname == "SpdRsSECGeoMapper")    mapper = SpdRsSECGeoMapper::Instance();
     
   return mapper;
 }
@@ -192,22 +206,22 @@ SpdGeoBuilder* SpdGeoFactory::SearchForBuilder(DetectorId id)
   switch (id) {
     
     case  kSpdIts : {
-          builder = SpdItsGeoBuilder::Instance()->GetBuilder(); 
+          builder = SpdItsGeoBuilder::GetBuilder(); 
           break; 
     }
  
     case  kSpdTsTB : { 
-          builder = SpdTsTBGeoBuilder::Instance()->GetBuilder(); 
+          builder = SpdTsTBGeoBuilder::GetBuilder(); 
           break; 
     }
     
     case  kSpdTsTEC : { 
-          builder = SpdTsTECGeoBuilder::Instance()->GetBuilder(); 
+          builder = SpdTsTECGeoBuilder::GetBuilder(); 
           break; 
     }
    
     case  kSpdTsSB : { 
-          builder = SpdTsSBGeoBuilder::Instance()->GetBuilder(); 
+          builder = SpdTsSBGeoBuilder::GetBuilder(); 
           break; 
     }
     
diff --git a/spdgeometry/SpdGeoFactory.h b/spdgeometry/SpdGeoFactory.h
index e30a0a3fa589fc785fb0375ae0509376624ed3d8..58af0f1f239936da7c69704c4593239d4e77240a 100644
--- a/spdgeometry/SpdGeoFactory.h
+++ b/spdgeometry/SpdGeoFactory.h
@@ -28,13 +28,13 @@ public:
     
     static SpdGeoFactory* Instance();
     
-    virtual SpdGeoMapper*  SearchForMapper(DetectorId id);      // search for mapper for the detector of a such id 
+    virtual SpdGeoMapper*  SearchForMapper(DetectorId id);      // search for default mapper for the detector of a such id 
     virtual SpdGeoMapper*  SearchForMapper(TString classname);  // search for mapper of a such type
-    virtual SpdGeoMapper*  Mapper(TString classname);           // get mapper (or create if doesn't exist) of a such type
+    virtual SpdGeoMapper*  Mapper(TString classname);           // get mapper (or create if doesn't exist!) of a such type
     
-    virtual SpdGeoBuilder* SearchForBuilder(DetectorId id);     // search for builder for the detector of a such id 
+    virtual SpdGeoBuilder* SearchForBuilder(DetectorId id);     // search for default builder for the detector of a such id 
     virtual SpdGeoBuilder* SearchForBuilder(TString classname); // search for builder of a such type
-    virtual SpdGeoBuilder* Builder(TString classname);          // get builder (or create if doesn't exist) of a such type
+    virtual SpdGeoBuilder* Builder(TString classname);          // get builder (or create if doesn't exist!) of a such type
     
     virtual SpdNodesIdTable* GetNodesIdTable(TString classname);
     
diff --git a/spdgeometry/SpdGeoLoader.cxx b/spdgeometry/SpdGeoLoader.cxx
index 81267a900e0dd417da46015b9d5a7d1ca7638bc0..95f6b5a7b59ee0caa9e221071dca5eae090654c9 100644
--- a/spdgeometry/SpdGeoLoader.cxx
+++ b/spdgeometry/SpdGeoLoader.cxx
@@ -12,6 +12,7 @@
 #include <TFile.h>
 
 #include "FairBaseParSet.h"
+#include "SpdPassiveGeoParSet.h"
 
 #include "SpdGeoLoader.h"
 #include "SpdGeoFactory.h"
@@ -25,12 +26,36 @@
 using std::cout;
 using std::endl;
 
+TString SpdGeoLoader::fTopGeoFile = "";
+TString SpdGeoLoader::fMediaFile  = "";
+Bool_t  SpdGeoLoader::fUnsetMaterials = false;
+Bool_t  SpdGeoLoader::fResetMediaFromPars = true;
+Bool_t  SpdGeoLoader::fResetPassivesMedia = false;
+
+//------------------------------------------------------ 
+void SpdGeoLoader::ForceTopGeoFile(TString fname) { fTopGeoFile = fname; }
+//------------------------------------------------------ 
+void SpdGeoLoader::ForceMediaFile(TString fname) { fMediaFile = fname; }
+//------------------------------------------------------
+void SpdGeoLoader::UnsetMaterials(Bool_t m) { fUnsetMaterials = m; }
+//------------------------------------------------------ 
+void SpdGeoLoader::ResetMediaFromParams(Bool_t r) { fResetMediaFromPars = r; } 
+//------------------------------------------------------ 
+void SpdGeoLoader::ResetPassivesMedia(Bool_t r) { fResetPassivesMedia = r; }
+
+SpdGeoLoader* SpdGeoLoader::fInstance = 0;
+
 ClassImp(SpdGeoLoader)
 
 //_____________________________________________________________________________
-SpdGeoLoader::SpdGeoLoader():fIsInit(kFALSE),fParFile(0)
+SpdGeoLoader::SpdGeoLoader():fIsInit(false),fLockGeom(false),fParFile(0)
 {
- 
+    if (fInstance) { 
+        cout << "-F- <SpdGeoLoader::SpdGeoLoader> Fatal error. " 
+             << "Singleton object has already been created." << endl;
+        exit;
+    }
+    fInstance = this;
 }
 
 //_____________________________________________________________________________
@@ -39,7 +64,16 @@ SpdGeoLoader::~SpdGeoLoader()
    if (fParFile) {
        fParFile->Close();
        delete fParFile;
+       fParFile = 0;
    }
+   
+   fTopGeoFile = "";
+   fMediaFile  = "";
+   fUnsetMaterials = false;
+   fResetMediaFromPars = true;
+   fResetPassivesMedia = false;
+
+   fInstance = 0;
 }
 
 //_____________________________________________________________________________
@@ -55,18 +89,27 @@ Bool_t SpdGeoLoader::LoadGeometry()
    nmodules += SpdCommonGeoMapper::Instance()->GetNPassives();
    
    if (nmodules == 0) {
-       cout << "-W- <SpdGeoLoader::LoadGeometry> No modules are loaded " << endl;
+       cout << "-W- <SpdGeoLoader::LoadBaseGeometry> No modules have been loaded " << endl;
        return fIsInit;
    }
    
-   cout << "-I- <SpdGeoLoader::LoadGeometry> Load SPD geometry " << endl;
+   cout << "-I- <SpdGeoLoader::LoadGeometry> Load SPD geometry; number of modules: " << nmodules << endl;
+ 
+   if (gGeoManager) delete gGeoManager; /*!ATTENTION! DELETE CURRENT GEOMETRY !ATTENTION!*/
    
-   if (gGeoManager) delete gGeoManager;
+   SpdPassiveGeoParSet* paspars = GetPassiveParameters();
    
-   SpdCommonGeoMapper::Instance()->OpenGeometry();
+   if (!fMediaFile.IsWhitespace()) SpdCommonGeoMapper::Instance()->OpenGeometry(fMediaFile);
+   else {
+       if (paspars->GetParameter("Global/MediaFileName",fMediaFile)) SpdCommonGeoMapper::Instance()->OpenGeometry(fMediaFile);
+       else SpdCommonGeoMapper::Instance()->OpenGeometry();
+   }
+   fMediaFile = SpdCommonGeoMapper::Instance()->GetActualMediaFileName();
    
-   FairModule* Cave = new SpdCave();
-   Cave->SetGeometryFileName("cave.geo");
+   SpdCave* Cave = new SpdCave();
+   Cave->LoadParsFrom(paspars);
+   if (!fTopGeoFile.IsWhitespace()) Cave->SetGeometryFileName(fTopGeoFile);
+   fTopGeoFile = Cave->GetActualGeometryFileName();
    Cave->ConstructGeometry();
    
    Int_t nmod, nm(0);
@@ -107,16 +150,7 @@ Bool_t SpdGeoLoader::LoadGeometry(TString parfile)
    }
     
    if (parfile.IsWhitespace()) {
-       cout << "-I- <SpdGeoLoader::LoadGeometry> Define \"empty\" geometry (the TOP volume only)" << endl; 
-       
-       SpdCommonGeoMapper::Instance()->OpenGeometry();
-   
-       FairModule* Cave = new SpdCave();
-       Cave->SetGeometryFileName("cave.geo");
-       Cave->ConstructGeometry();
-   
-       fIsInit = kTRUE;
-       
+       cout << "-W- <SpdGeoLoader::LoadGeometry> Geometry is not defined " << endl; 
        return fIsInit; 
    }
    
@@ -134,10 +168,21 @@ Bool_t SpdGeoLoader::LoadGeometry(TString parfile)
 
    cout << "-I- <SpdGeoLoader::LoadGeometry> Load SPD geometry from: " << parfile << endl;
    
-   SpdCommonGeoMapper::Instance()->OpenGeometry();
+   if (gGeoManager) delete gGeoManager; /*!ATTENTION! DELETE CURRENT GEOMETRY !ATTENTION!*/
+   
+   SpdPassiveGeoParSet* paspars = GetPassiveParameters();
    
-   FairModule* Cave = new SpdCave();
-   Cave->SetGeometryFileName("cave.geo");
+   if (!fMediaFile.IsWhitespace()) SpdCommonGeoMapper::Instance()->OpenGeometry(fMediaFile);
+   else {
+       if (paspars->GetParameter("Global/MediaFileName",fMediaFile)) SpdCommonGeoMapper::Instance()->OpenGeometry(fMediaFile);
+       else SpdCommonGeoMapper::Instance()->OpenGeometry();
+   }
+   fMediaFile = SpdCommonGeoMapper::Instance()->GetActualMediaFileName();
+   
+   SpdCave* Cave = new SpdCave();
+   Cave->LoadParsFrom(paspars);
+   if (!fTopGeoFile.IsWhitespace()) Cave->SetGeometryFileName(fTopGeoFile);
+   fTopGeoFile = Cave->GetActualGeometryFileName();
    Cave->ConstructGeometry();
 
    // load full set of modules (passive and active)
@@ -173,13 +218,18 @@ Bool_t SpdGeoLoader::LoadGeometry(TString parfile)
 }
 
 //_____________________________________________________________________________
- Bool_t SpdGeoLoader::LoadModule(Int_t id)
+ Bool_t SpdGeoLoader::LoadModule(Int_t id, Bool_t unsetmat)
 {
    if (!fIsInit) {
        cout << "-W- <SpdGeoLoader::LoadModule> Geometry is not initialized" << endl;
        return kFALSE;
    }
    
+   if (fLockGeom) {
+       cout << "-W- <SpdGeoLoader::LoadModule> Geomery is locked, disable protection to add module " << endl;
+       return kFALSE; 
+   }
+   
    if (id == Int_t(kSpdUndefined)) {
        cout << "-W- <SpdGeoLoader::LoadModule> Module is undefined" << endl;
        return kFALSE;
@@ -199,8 +249,19 @@ Bool_t SpdGeoLoader::LoadGeometry(TString parfile)
    }
 
    if (SpdCommonGeoMapper::IsActive(id)) {
-       SpdParSet* pars = GetParameters(id);
-       ((SpdDetector*)module)->LoadParsFrom(pars);
+       SpdParSet* pars = GetActiveParameters(id);
+       SpdDetector* active = (SpdDetector*)module;
+       active->LoadParsFrom(pars); 
+       SpdGeoMapper* mapper = active->GetMapper();
+       if (fResetMediaFromPars) mapper->ResetMediaFromParams();
+       if (unsetmat || fUnsetMaterials) mapper->UnsetMaterials(false,"base");
+   }
+   else {
+       SpdPassiveGeoParSet* pars = GetPassiveParameters();
+       SpdPassiveModule* passive = (SpdPassiveModule*)module;
+       if (fResetPassivesMedia) passive->ResetMaterials();
+       if (unsetmat || fUnsetMaterials) passive->UnsetMaterials("vacuum");
+       passive->Print("");
    }
 
    cout << "-I- <SpdGeoLoader::LoadModule> Construct module of id: " << id << endl;
@@ -213,12 +274,17 @@ Bool_t SpdGeoLoader::LoadGeometry(TString parfile)
 }
  
 //_____________________________________________________________________________
-Bool_t SpdGeoLoader::LoadModule(TString name)
+Bool_t SpdGeoLoader::LoadModule(TString name, Bool_t unsetmat)
 {
    if (!fIsInit) {
        cout << "-W- <SpdGeoLoader::LoadModule> Geometry is not initialized" << endl;
        return kFALSE;
    }
+   
+   if (fLockGeom) {
+       cout << "-W- <SpdGeoLoader::LoadModule> Geomery is locked, disable protection to add module " << endl;
+       return kFALSE; 
+   }
     
    std::map<TString,Int_t>::const_iterator it = fModulesId.find(name);
    if (it != fModulesId.end()) return LoadModule(it->second);
@@ -231,14 +297,14 @@ Bool_t SpdGeoLoader::LoadModule(TString name)
    if (mname == "all" || mname == "total" || mname == "passives" || mname == "passive") {
        Int_t nmod;
        SpdPassiveModule** mod = SpdCommonGeoMapper::Instance()->GetListOfPassives(nmod);
-       for (Int_t i(0); i<nmod; i++) load = LoadModule(mod[i]->GetId());
+       for (Int_t i(0); i<nmod; i++) load = LoadModule(mod[i]->GetId(),unsetmat);
        delete [] mod;
    }
    
    if (mname == "all" || mname == "total" || mname == "actives" || mname == "active") {
        Int_t ndet;
        SpdDetector** det = SpdCommonGeoMapper::Instance()->GetListOfDetectors(ndet);
-       for (Int_t i(0); i<ndet; i++) load = LoadModule(det[i]->GetDetId());
+       for (Int_t i(0); i<ndet; i++) load = LoadModule(det[i]->GetDetId(),unsetmat);
        delete [] det;
    }
      
@@ -276,26 +342,47 @@ Bool_t SpdGeoLoader::IsModuleActive(Int_t id) const
 }
 
 //_____________________________________________________________________________  
-SpdParSet* SpdGeoLoader::GetParameters(Int_t id)
+SpdPassiveGeoParSet* SpdGeoLoader::GetPassiveParameters()
+{
+   TFile* g = gFile;
+   
+   SpdPassiveGeoParSet* pars  = 0;
+   if (fParFile) {
+       pars = (SpdPassiveGeoParSet*)fParFile->Get("PassiveGeoParSet");
+   }
+   else {
+       FairRuntimeDb* rtdb = FairRun::Instance()->GetRuntimeDb();
+       pars = (SpdPassiveGeoParSet*)rtdb->getContainer("PassiveGeoParSet");
+       ((FairParSet*)pars)->init();
+   }
+
+   gFile = g;
+   if (g) g->cd();
+       
+   return pars; 
+}
+
+//_____________________________________________________________________________  
+SpdParSet* SpdGeoLoader::GetActiveParameters(Int_t id)
 {
    if (!fIsInit) {
-       cout << "-W- <SpdGeoLoader::GetParameters> Geometry is not initialized" << endl;
+       cout << "-W- <SpdGeoLoader::GetActiveParameters> Geometry is not initialized" << endl;
        return 0;
    }
    
    if (!IsGeometryModule(id)) {
-       cout << "-W- <SpdGeoLoader::GetParameters> Module of id = " << id << " is not actual " << endl;
+       cout << "-W- <SpdGeoLoader::GetActiveParameters> Module of id = " << id << " is not actual " << endl;
        return 0;
    }
    
    if (SpdCommonGeoMapper::IsPassive(id)) {
-       cout << "-W- <SpdGeoLoader::GetParameters> This module is \"passive\": " << id << endl;
+       cout << "-W- <SpdGeoLoader::GetActiveParameters> This module is \"passive\": " << id << endl;
        return 0;
    }
    
    SpdDetector* det = SpdCommonGeoMapper::Instance()->SearchForActive(id);
    if (!det) {
-       cout << "-W- <SpdGeoLoader::LoadModule> No module of id = " << id << endl;
+       cout << "-W- <SpdGeoLoader::GetActiveParameters> No module of id = " << id << endl;
        return 0;
    }
    
@@ -312,6 +399,7 @@ SpdParSet* SpdGeoLoader::GetParameters(Int_t id)
        ((FairParSet*)pars)->init();
    }
    
+   gFile = g;
    if (g) g->cd();  
    
    return pars;
@@ -327,6 +415,26 @@ FairModule* SpdGeoLoader::GetModule(Int_t id)
    return SpdCommonGeoMapper::Instance()->SearchForModule(id);
 }
 
+//_____________________________________________________________________________
+SpdDetector* SpdGeoLoader::GetActive(Int_t id)
+{
+   if (!IsModuleActual(id)) {
+       cout << "-W- <SpdGeoLoader::GetActive> Module of id = " << id << " is not actual " << endl;
+       return 0;
+   }
+   return SpdCommonGeoMapper::Instance()->SearchForActive(id);
+}
+
+//_____________________________________________________________________________
+SpdPassiveModule* SpdGeoLoader::GetPassive(Int_t id)
+{
+   if (!IsModuleActual(id)) {
+       cout << "-W- <SpdGeoLoader::GetPassive> Module of id = " << id << " is not actual " << endl;
+       return 0;
+   }
+   return SpdCommonGeoMapper::Instance()->SearchForPassive(id);
+}
+
 //_____________________________________________________________________________
 SpdGeoMapper* SpdGeoLoader::GetMapper(Int_t id)
 {
@@ -361,6 +469,13 @@ void SpdGeoLoader::PrintGeometry() const
    cout << "-I- <SpdGeoLoader::PrintGeometry> Modules [actual/total]: " 
         << GetNActualModules()  << "/" << GetNTotalModules() << endl; 
         
+   cout << endl;  
+   cout << "Cave geometry:    " <<  fTopGeoFile << endl;
+   cout << "Media file:        " << fMediaFile << endl; 
+   cout << "Unset materials:  " << ((fUnsetMaterials) ? "true" : "false") << endl;
+   cout << "Pars. materials:  " << ((fResetMediaFromPars) ? "true" : "false") << endl;
+   cout << endl;
+   
    if (GetNTotalModules() < 1) return;     
    
    printf("--------------------------------------------------\n");
@@ -381,13 +496,21 @@ void SpdGeoLoader::PrintActualGeometry() const
 {
    cout << "-I- <SpdGeoLoader::PrintActualGeometry> Modules [actual/total]: " 
         << GetNActualModules() << "/" << GetNTotalModules() << endl; 
-      
-   if (GetNActualModules() < 1) return;     
+
+   cout << endl;  
+   cout << "Cave geometry:      " << fTopGeoFile << endl;
+   cout << "Media file:         " << fMediaFile << endl; 
+   cout << "Is geometry locked: " << fLockGeom << endl;
+   cout << "Unset materials:    " << ((fUnsetMaterials) ? "true" : "false") << endl;
+   cout << "Reset materials:    " << ((fResetMediaFromPars) ? "true" : "false") << endl;
+   cout << endl;
    
    printf("--------------------------------------------------\n");
    printf("%5s | %5s | \"%s\"\n","N","Id","Name");
    printf("--------------------------------------------------\n");
   
+   if (GetNActualModules() < 1) return;     
+    
    Int_t n(0);
    std::map<TString,Int_t>::const_iterator it = fModulesId.begin();
    
diff --git a/spdgeometry/SpdGeoLoader.h b/spdgeometry/SpdGeoLoader.h
index 4499763ae4de23aa9f80ea4a313e9d3ec4d15bb6..936bea34fb4d403781fad2153849d6235fc235cd 100644
--- a/spdgeometry/SpdGeoLoader.h
+++ b/spdgeometry/SpdGeoLoader.h
@@ -13,8 +13,11 @@
 
 class TFile;
 class SpdParSet;
+class SpdPassiveGeoParSet;
 class FairBaseParSet;
 class FairModule;
+class SpdDetector;
+class SpdPassiveModule;
 class SpdGeoMapper;
 class SpdGeoBuilder;
 
@@ -33,12 +36,18 @@ public:
     SpdGeoLoader();
     virtual ~SpdGeoLoader();
     
-    Bool_t   LoadGeometry(TString parfile); // file name or "" (TOP level geometry only)
+    static   SpdGeoLoader* Instance() { return fInstance; }
+    
+    Bool_t   LoadGeometry(TString parfile); 
+    Bool_t   LoadGeometry(); // use this method if parameters already have been loaded via runtime database 
    
-    Bool_t   LoadModule(Int_t id);
-    Bool_t   LoadModule(TString name); // module name, "all", "passives", "actives"
+    Bool_t   LoadModule(Int_t id, Bool_t unsetmat = false);
+    Bool_t   LoadModule(TString name, Bool_t unsetmat = false); // name = module name, "all", "passives", "actives"
+    
+    void     LockGeometry(Bool_t lock = true) { fLockGeom = lock; }   // if true, prevent loading new modules via LoadModule
     
     /* Getters */
+    Bool_t   IsGeometryLocked()  const { return fLockGeom; } 
     
     Int_t    GetNTotalModules()  const { return fModulesId.size(); }
     Int_t    GetNActualModules() const { return fModules.size();   }
@@ -50,10 +59,21 @@ public:
     Bool_t   IsModuleActual(Int_t id) const;
     Bool_t   IsModuleActive(Int_t id) const;
     
-    SpdParSet*     GetParameters(Int_t id);
-    FairModule*    GetModule(Int_t id);
-    SpdGeoMapper*  GetMapper(Int_t id);
-    SpdGeoBuilder* GetBuilder(Int_t id);
+    SpdPassiveGeoParSet*  GetPassiveParameters();
+    SpdParSet*            GetActiveParameters(Int_t id);
+    FairModule*           GetModule(Int_t id);
+    SpdPassiveModule*     GetPassive(Int_t id);
+    SpdDetector*          GetActive(Int_t id); 
+    SpdGeoMapper*         GetMapper(Int_t id);
+    SpdGeoBuilder*        GetBuilder(Int_t id);
+    
+    /* Setters (static) */
+  
+    static void ForceTopGeoFile(TString fname);       // TOP (cave) geometry changing
+    static void ForceMediaFile(TString fname);        // Media file changing
+    static void UnsetMaterials(Bool_t m = false); 
+    static void ResetMediaFromParams(Bool_t r = true);
+    static void ResetPassivesMedia(Bool_t r = false);
     
     /* Draw/Print */
     
@@ -62,18 +82,23 @@ public:
     void  PrintGeometry() const;
     void  PrintActualGeometry() const;
     
-    /* specials */
-    
-    Bool_t   LoadGeometry();
-    
 protected:
     
     Bool_t   fIsInit;
+    Bool_t   fLockGeom;
     TFile*   fParFile;
     
     std::map<TString,Int_t> fModulesId; // module [name <-> id]
     std::set<Int_t>         fModules;   // list of modules were constructed
-
+    
+    static TString fTopGeoFile;         // default: "cave.geo"
+    static TString fMediaFile;          // default: "media.geo"
+    static Bool_t  fUnsetMaterials;     // default: false
+    static Bool_t  fResetMediaFromPars; // default: true
+    static Bool_t  fResetPassivesMedia; // default: false
+    
+    static SpdGeoLoader* fInstance;
+    
     ClassDef(SpdGeoLoader,1)
 };
 
diff --git a/spdgeometry/SpdGeometryLinkDef.h b/spdgeometry/SpdGeometryLinkDef.h
index 059629da03153c52cfa07ba512e8932de6f14927..455e3ec3f023f3298c2becb1f18149b9fcb20ffc 100644
--- a/spdgeometry/SpdGeometryLinkDef.h
+++ b/spdgeometry/SpdGeometryLinkDef.h
@@ -29,12 +29,16 @@
 #pragma link C++ class SpdItsGeoMapperX+;
 
 #pragma link C++ class SpdEcalTBGeoMapper+;
+#pragma link C++ class SpdEcalTB2GeoMapper+;
 #pragma link C++ class SpdEcalTECGeoMapper+;
+#pragma link C++ class SpdEcalTEC2GeoMapper+;
 #pragma link C++ class SpdEcalSBGeoMapper+;
 #pragma link C++ class SpdEcalSECGeoMapper+;
 
 #pragma link C++ class SpdRsTBGeoMapper+;
+#pragma link C++ class SpdRsTB2GeoMapper+;
 #pragma link C++ class SpdRsTECGeoMapper+;
+#pragma link C++ class SpdRsTEC2GeoMapper+;
 #pragma link C++ class SpdRsSBGeoMapper+;
 #pragma link C++ class SpdRsSECGeoMapper+;
 
diff --git a/spdgeometry/ecalt/SpdEcalTB2GeoMapper.cxx b/spdgeometry/ecalt/SpdEcalTB2GeoMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..88dfcd7f1238f0b3b7ed47d2b92482df39e2659a
--- /dev/null
+++ b/spdgeometry/ecalt/SpdEcalTB2GeoMapper.cxx
@@ -0,0 +1,737 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+//_____________________________________________________________________________
+//
+// SpdEcalTB2GeoMapper
+//_____________________________________________________________________________
+
+#include "SpdEcalTB2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+
+#include <TMath.h>
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+using namespace TMath;
+
+ClassImp(SpdEcalTB2GeoMapper)
+
+SpdEcalTB2GeoMapper* SpdEcalTB2GeoMapper::fInstance = 0;
+
+SpdEcalTB2GeoMapper* SpdEcalTB2GeoMapper::Instance() 
+{ return (fInstance) ? fInstance : new SpdEcalTB2GeoMapper(); }
+
+SpdEcalTB2GeoMapper* SpdEcalTB2GeoMapper::GetMapper() 
+{ return fInstance; }
+    
+//_____________________________________________________________________________
+SpdEcalTB2GeoMapper::SpdEcalTB2GeoMapper():SpdGeoMapper("EcalTB")
+{
+  if (fInstance) {
+      Fatal("SpdEcalTB2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  fGeoVolPars = new TObjArray();  
+  fGeoTable = new SpdGeoTable(); 
+   
+  fMasterVolName = SpdCommonGeoMapper::Instance()->GetMasterVolumeName();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetEcalTBDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdEcalTB2GeoMapper::SpdEcalTB2GeoMapper(TString prefix):SpdGeoMapper(prefix)
+{
+  if (fInstance) {
+      Fatal("SpdEcalTB2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  fGeoVolPars = new TObjArray();  
+  fGeoTable = new SpdGeoTable(); 
+   
+  fMasterVolName = SpdCommonGeoMapper::Instance()->GetMasterVolumeName();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetEcalTBDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdEcalTB2GeoMapper::~SpdEcalTB2GeoMapper() 
+{
+ 
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::AddParameterFromCommon(TString parname, Int_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit) 
+{
+    static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+    SpdParameter* par = GetParameter(parname);
+    if (par) { if (reinit) *par = accessFunc(mapper); }
+    else fParams->Add(new SpdParameter(parname, accessFunc(mapper)));
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::AddParameterFromCommon(TString parname, Double_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit) 
+{
+    static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+    SpdParameter* par = GetParameter(parname);
+    if (par) { if (reinit) *par = accessFunc(mapper); }
+    else fParams->Add(new SpdParameter(parname, accessFunc(mapper)));
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Values from CommonGeoMapper:
+//
+// EcalBarrelNSectors: number of sectors in barrel
+// EcalBarrelLength [cm]: length of barrel part
+// SectorClearance  [cm]: minimum distance between modules of different sectors
+// EcalBarrelRadius [cm]: shortest distance from Z axis to ECAL barrel basket
+// EcalTBWidth2     [cm]: (meaningful only for EcalBarrelForceCellSize == false) the radial size of barrel basket. 
+//                        All modules are contained within the basket. Size and shape of modules is varied accordingly
+//
+// Some default values:
+//
+// EcalTBNBasketsZ: number of baskets in barrel in Z direction [default: 2]
+//
+// EcalBarrelForceCellSize (bool): 
+//   - if TRUE, cell sizes are forced to be as defined with 
+//           EcalCellPhiInnerSize/EcalCellPhiOuterSize/EcalCellThetaInnerSize/EcalCellThetaOuterSize; 
+//   - if FALSE, cell sizes are calculated automatically to 
+//        1) minimize empty spaces between modules, and 
+//        2) to be as close to the defined variables 
+//           EcalCellPhiInnerSize/EcalCellPhiOuterSize/EcalCellThetaInnerSize/EcalCellThetaOuterSize as possible
+//
+// EcalBarrelTrimModuleLength (bool): 
+//   - if TRUE, the module length is calculated so that the module is fitted inside the basket;
+//   - if FALSE, the module size is fixed and defined by EcalModuleNLayers
+//
+// EcalCellPhiInnerSize [cm]: П†-size of inner size of barrel cell 
+//     (if EcalBarrelForceCellSize is false, this defines rough dimensions) [default: 5.5]
+//
+// EcalCellPhiOuterSize [cm]: П†-size of outer size of barrel cell 
+//     (if EcalBarrelForceCellSize is false, chosen automatically to minimize empty space) [default: 7.0]
+//
+// EcalCellThetaInnerSize [cm]: Оё(Z)-size of inner size of barrel cell 
+//     (if EcalBarrelForceCellSize is false, this defines rough dimensions) [default: 5.5]
+//
+// EcalCellThetaOuterSize [cm]: Оё(Z)-size of outer size of barrel cell 
+//     (if EcalBarrelForceCellSize is false, this defines rough dimensions) [default: 5.5]
+//
+// EcalBasketClearance [cm]: minimum distance between modules of different Z-baskets [default: 0.5]
+//
+// EcalModuleClearance [cm]: clearance between modules (2x2 cells) [default: 0.1]
+//
+// EcalCellClearance   [cm]: clerance between cells in a module [default: 0.05]
+//
+// EcalModuleNLayers: (meaningful only for EcalBarrelForceCellSize == true or EcalBarrelTrimModuleLength == FALSE) 
+//     number of layers in a module (same for barrel and endcap parts), [default: 200]. 
+//     In case of EcalBarrelForceCellSize == FALSE and EcalBarrelTrimModuleLength == TRUE, for each module, 
+//     maximum number of layers is calculated, for which the module stays within the basket.
+//
+// EcalAbsorberThickness [cm]: thickness of absorber layer (material hardcoded as lead) [default: 0.05]
+//
+// EcalScintThickness    [cm]: thickness of scintillator layer (material hardcoded as polystyrene(?)) [default: 0.15]
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTB2GeoMapper::InitGeometry(Int_t gtype, Bool_t reinit) 
+{ 
+   //cout << "-I- <SpdEcalTB2GeoMapper::InitGeometry>  " << endl;
+   
+   if (fLockGeometry) {
+       cout << "-E- <SpdEcalTB2GeoMapper::InitGeometry> Geometry is locked " << endl;
+       return kFALSE;
+   }
+  
+   if (!fParams) return kFALSE;
+   if (fGeoTable) fGeoTable->Clear();
+   if (fGeoVolPars) fGeoVolPars->Clear();
+ 
+   if (!CheckGeoType(gtype,"EcalTBGeoType")) return kFALSE;
+    
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+ 
+   AddParameterFromCommon("EcalBarrelNSectors", [](SpdCommonGeoMapper* m) {return m->GetNGeoSectors();}, reinit);
+   AddParameterFromCommon("EcalBarrelLength", [](SpdCommonGeoMapper* m) {return m->GetEcalTBLen2();}, reinit);
+   AddParameterFromCommon("EcalBarrelOuterSize", [](SpdCommonGeoMapper* m) {return m->GetEcalTBSize2();}, reinit);
+   AddParameterFromCommon("EcalBarrelWidth", [](SpdCommonGeoMapper* m) {return m->GetEcalTBWidth2();}, reinit);
+   AddParameterFromCommon("EcalTBWidth2", [](SpdCommonGeoMapper* m) {return m->GetEcalTBWidth2();}, reinit);
+   AddParameterFromCommon("SectorClearance", [](SpdCommonGeoMapper* m) {return m->GetSectorClearance();}, reinit);
+   
+   //sanity check of parameters
+   //barrelLength/2 should not be larger than distance to endcaps
+   
+   SpdParameter* par;
+   
+   Int_t nsectors(-1);
+   par = GetParameter("EcalBarrelNSectors"); 
+   if (par) par->Value(nsectors);
+   if (nsectors != -1 && nsectors < 3) {
+       cout << "-F- <SpdEcalTB2GeoMapper::InitGeometry> " 
+            << "Cannot map ECAL geometry: nsectors should be >=3 (recommended >= 6)" << endl;
+       exit(1);
+   }
+   
+   Double_t thetaInnerSize(-1.), thetaOuterSize(-1.);
+   Bool_t forceSize(false);
+   
+   par = GetParameter("EcalCellThetaInnerSize");  if (par) par->Value(thetaInnerSize);
+   par = GetParameter("EcalCellThetaOuterSize");  if (par) par->Value(thetaOuterSize);
+   par = GetParameter("EcalBarrelForceCellSize"); if (par) par->Value(forceSize);
+   
+   if (thetaInnerSize != -1. && thetaOuterSize != -1. && par && thetaInnerSize != thetaOuterSize && forceSize) {
+       cout << "-F- <SpdEcalTB2GeoMapper::InitGeometry> "
+            << "Cannot map ECAL geometry: theta(Z) inner size != theta(Z) outer size (while forced size): "
+            << "projective geometry support is not implemented yet!" << endl;
+       exit(1);
+   }
+   
+   if (thetaInnerSize != -1. && thetaOuterSize != -1. && thetaInnerSize != thetaOuterSize) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> "
+            << "theta(Z) inner size != theta(Z) outer size (size not forced): "
+            << "as a guideline for theta (Z) size is chosen as inner size = " << thetaInnerSize << " cm" << endl;
+   }
+   
+   Double_t phiInnerSize(-1.), phiOuterSize(-1.);
+   
+   par = GetParameter("EcalCellPhiInnerSize");    if (par) par->Value(phiInnerSize);
+   par = GetParameter("EcalCellPhiOuterSize");    if (par) par->Value(phiOuterSize);
+   par = GetParameter("EcalBarrelForceCellSize"); 
+   
+   if (phiInnerSize != -1. && phiOuterSize != -1. && par && phiInnerSize > phiOuterSize && forceSize) {
+       cout << "-F- <SpdEcalTB2GeoMapper::InitGeometry> "
+            << "Cannot map ECAL geometry: phi inner size > phi outer size (while forcing size): "
+            << "this gives undefined behaviour and is not recommended" << endl;
+       exit(1);
+   }
+   
+   SpdParameter* par2;
+   
+   Int_t nLayers(-1);
+   Bool_t trimModule(false);
+   
+   par  = GetParameter("EcalModuleNLayers");          if (par)  par->Value(nLayers);
+   par  = GetParameter("EcalBarrelForceCellSize");  
+   par2 = GetParameter("EcalBarrelTrimModuleLength"); if (par2) par2->Value(trimModule);
+   
+   if (nLayers != -1 && par && par2 && !forceSize && trimModule) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> Automatical selection of cell size is chosen "
+            << "(EcalBarrelForceCellSize = false && EcalBarrelTrimModuleLength == true): "
+            << "number of layers in each module will be calculated automatically! "
+            << "(setting EcalModuleNLayers is meaningless) " << endl;
+   }
+   
+   if (nLayers != -1 && par && !par2 && !forceSize) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> Automatical selection of cell size is chosen "
+            << "(EcalBarrelForceCellSize = false && EcalBarrelTrimModuleLength == true (by default)): "
+            << "number of layers in each module will be calculated automatically! "
+            << "(setting EcalModuleNLayers is meaningless) " << endl;
+   }
+   
+   if (nLayers != -1 && !par && !par2) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> Automatical selection of cell size is chosen "
+            << "(EcalBarrelForceCellSize = false (by default) && EcalBarrelTrimModuleLength == true (by default)): "
+            << "number of layers in each module will be calculated automatically! "
+            << "(setting EcalModuleNLayers is meaningless) " << endl;
+   }
+   
+   if (nLayers != -1 && !par && par2 && trimModule) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> Automatical selection of cell size is chosen "
+            << "(EcalBarrelForceCellSize = false (by default) && EcalBarrelTrimModuleLength == true): "
+            << "number of layers in each module will be calculated automatically! "
+            << "(setting EcalModuleNLayers is meaningless) " << endl;
+   }
+   
+   Double_t moduleLength(-1.);
+   
+   par = GetParameter("EcalTBWidth2");               if (par) par->Value(moduleLength);
+   par = GetParameter("EcalBarrelTrimModuleLength"); 
+   
+   if (par && moduleLength != -1. && moduleLength != mapper->GetEcalTBWidth2() && !trimModule) {
+       cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> : manual selection of cell length is chosen "    
+            << "(EcalBarrelTrimModuleLength = false): cell length is calculated using "
+            << "EcalModuleNLayers/EcalAbsorberThickness/EcalScintThickness "
+            << "(changing EcalTBWidth2 WILL NOT change simulation) " << endl;
+   }
+   if (!par && moduleLength != -1. && moduleLength != mapper->GetEcalTBWidth2()) {
+        cout << "-W- <SpdEcalTB2GeoMapper::InitGeometry> : manual selection of cell length is chosen "
+             << "(EcalBarrelTrimModuleLength = false): cell length is calculated using "
+             << "EcalModuleNLayers/EcalAbsorberThickness/EcalScintThickness "
+             << "(changing EcalTBWidth2 WILL NOT change simulation) " << endl;
+   }
+   
+   par = GetParameter("EcalTBNBasketsZ");
+   if (par) { if (reinit) *par = 2; }
+   else { fParams->Add(new SpdParameter("EcalTBNBasketsZ", 2)); }
+   
+   par = GetParameter("EcalCellPhiInnerSize");
+   if (par) { if (reinit) *par = 5.5; }
+   else { fParams->Add(new SpdParameter("EcalCellPhiInnerSize", 5.5)); }
+   
+   par = GetParameter("EcalCellPhiOuterSize");
+   if (par) { if (reinit) *par = 7.0; }
+   else { fParams->Add(new SpdParameter("EcalCellPhiOuterSize", 7.0)); }
+   
+   par = GetParameter("EcalCellThetaInnerSize");
+   if (par) { if (reinit) *par = 5.5; }
+   else { fParams->Add(new SpdParameter("EcalCellThetaInnerSize", 5.5)); }
+   
+   par = GetParameter("EcalCellThetaOuterSize");
+   if (par) { if (reinit) *par = 5.5; }
+   else { fParams->Add(new SpdParameter("EcalCellThetaOuterSize", 5.5)); }
+   
+   par = GetParameter("EcalBasketClearance");
+   if (par) { if (reinit) *par = 0.5; }
+   else { fParams->Add(new SpdParameter("EcalBasketClearance", 0.5)); }
+   
+   par = GetParameter("EcalModuleClearance");
+   if (par) { if (reinit) *par = 0.1; }
+   else { fParams->Add(new SpdParameter("EcalModuleClearance", 0.1)); }
+   
+   par = GetParameter("EcalCellClearance");
+   if (par) { if (reinit) *par = 0.05; }
+   else { fParams->Add(new SpdParameter("EcalCellClearance", 0.05)); }
+   
+   par = GetParameter("EcalBarrelMaxTheta");
+   if (par) { if (reinit) *par = 0.0; }
+   else { fParams->Add(new SpdParameter("EcalBarrelMaxTheta", 0.0)); }
+   
+   par = GetParameter("EcalModuleNLayers");
+   if (par) { if (reinit) *par = 200; }
+   else { fParams->Add(new SpdParameter("EcalModuleNLayers", 200)); }
+   
+   par = GetParameter("EcalAbsorberThickness");
+   if (par) { if (reinit) *par = 0.05; }
+   else { fParams->Add(new SpdParameter("EcalAbsorberThickness", 0.05)); }
+   
+   par = GetParameter("EcalScintThickness");
+   if (par) { if (reinit) *par = 0.15; }
+   else { fParams->Add(new SpdParameter("EcalScintThickness", 0.15)); }
+   
+   par = GetParameter("EcalBarrelForceCellSize");
+   if (par) { if (reinit) *par = false; }
+   else { fParams->Add(new SpdParameter("EcalBarrelForceCellSize", false)); }
+   
+   par = GetParameter("EcalBarrelTrimModuleLength");
+   if (par) { if (reinit) *par = false; }
+   else { fParams->Add(new SpdParameter("EcalBarrelTrimModuleLength", false)); }
+   
+   par = GetParameter("EcalBarrelBaseMedium");
+   if (par) { if (reinit) *par = "air"; }
+   else { fParams->Add(new SpdParameter("EcalBarrelBaseMedium", "air")); }
+   
+   par = GetParameter("EcalBarrelAbsorberMedium");
+   if (par) { if (reinit) *par = "lead"; }
+   else { fParams->Add(new SpdParameter("EcalBarrelAbsorberMedium", "lead")); }
+   
+   par = GetParameter("EcalBarrelScintMedium");
+   if (par) { if (reinit) *par = "FscScint"; }
+   else { fParams->Add(new SpdParameter("EcalBarrelScintMedium", "FscScint")); }
+   
+   return kTRUE;
+}
+
+/*
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ++++++++++++++++++++++++++++++++ GETTERS ++++++++++++++++++++++++++++++++++++++
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+*/ 
+
+//_____________________________________________________________________________
+TString SpdEcalTB2GeoMapper::GetBaseMedium() const 
+{
+   const SpdParameter* par = GetParameter("EcalBarrelBaseMedium");
+   const Char_t* value = par->Value();
+   return TString(value);
+}
+
+//_____________________________________________________________________________
+TString SpdEcalTB2GeoMapper::GetAbsorberMedium() const 
+{
+   const SpdParameter* par = GetParameter("EcalBarrelAbsorberMedium");
+   const Char_t* value = par->Value();
+   return TString(value);
+}
+
+//_____________________________________________________________________________
+TString SpdEcalTB2GeoMapper::GetScintMedium() const 
+{
+   const SpdParameter* par = GetParameter("EcalBarrelScintMedium");
+   const Char_t* value = par->Value();
+   return TString(value);
+}
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTB2GeoMapper::IsForceCellSize() const 
+{
+   const SpdParameter* par = GetParameter("EcalBarrelForceCellSize");
+   Bool_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTB2GeoMapper::IsTrimModuleLength() const 
+{
+   const SpdParameter* par = GetParameter("EcalBarrelTrimModuleLength");
+   Bool_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Int_t SpdEcalTB2GeoMapper::GetNLayers() const
+{
+   const SpdParameter* par = GetParameter("EcalModuleNLayers");
+   Int_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBarrelModuleRadialSize() const
+{
+   const SpdParameter* par = GetParameter("EcalTBWidth2");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBarrelWidth() const
+{
+   const SpdParameter* par = GetParameter("EcalBarrelWidth");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBarrelOuterSize() const
+{
+   const SpdParameter* par = GetParameter("EcalBarrelOuterSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayerInnerSizeTheta() const
+{
+   const SpdParameter* par = GetParameter("EcalCellThetaInnerSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayerInnerSizePhi() const
+{
+   const SpdParameter* par = GetParameter("EcalCellPhiInnerSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayerOuterSizeTheta() const
+{
+   const SpdParameter* par = GetParameter("EcalCellThetaOuterSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayerOuterSizePhi() const
+{
+   const SpdParameter* par = GetParameter("EcalCellPhiOuterSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayer1SizeZ() const
+{
+   const SpdParameter* par = GetParameter("EcalAbsorberThickness");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetLayer2SizeZ() const
+{
+   const SpdParameter* par = GetParameter("EcalScintThickness");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBarrelLength() const
+{
+   const SpdParameter* par = GetParameter("EcalBarrelLength");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBarrelMaxTheta() const
+{
+   const SpdParameter* par = GetParameter("EcalBarrelMaxTheta");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetBasketClearance() const
+{
+   const SpdParameter* par = GetParameter("EcalBasketClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetCellClearance() const
+{
+   const SpdParameter* par = GetParameter("EcalCellClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetModuleClearance() const
+{
+   const SpdParameter* par = GetParameter("EcalModuleClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTB2GeoMapper::GetSectorClearance() const
+{
+   const SpdParameter* par = GetParameter("SectorClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Int_t SpdEcalTB2GeoMapper::GetNSectors() const
+{
+   const SpdParameter* par = GetParameter("EcalBarrelNSectors");
+   Int_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+/*
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ++++++++++++++++++++++++++++++++ SETTERS ++++++++++++++++++++++++++++++++++++++
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+*/ 
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetForceInsideBasket(Bool_t value)
+{
+   SpdParameter* par = GetParameter("EcalBarrelTrimModuleLength");
+   if (!par) fParams->Add(new SpdParameter("EcalBarrelTrimModuleLength",value)); 
+   else {
+       *par = value; 
+       cout << "-W- <SpdEcalTB2GeoMapper::SetForceInsideBasket> Overwriting parameter \"EcalBarrelTrimModuleLength\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetForceCellSize(Bool_t value)
+{
+   SpdParameter* par = GetParameter("EcalBarrelForceCellSize");
+   if (!par) fParams->Add(new SpdParameter("EcalBarrelForceCellSize", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetForceCellSize> Overwriting parameter \"EcalBarrelForceCellSize\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetCellZSize(Double_t value)
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetCellZSize> Cell z size should be > 0" << endl;
+       exit(1);
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTBLen2()) {
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellSize> "
+            << "cell z size is more than barrel length, "
+            << "recommended decreasing cell z size " << endl;
+   }
+   
+   SpdParameter* par = GetParameter("EcalCellThetaInnerSize");
+   if (!par) fParams->Add(new SpdParameter("EcalCellThetaInnerSize", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellZSize> Overwriting parameter \"EcalCellThetaInnerSize\"" << endl; 
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetCellInnerPhiSize(Double_t value)
+{
+   if (value <= 0) {
+        cout << "-F- <SpdEcalTB2GeoMapper::SetCellInnerPhiSize> Cell phi size should be > 0" << endl;
+        exit(1);
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTBSize2()) {
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellInnerPhiSize> "
+            << "Cell phi inner size is more than barrel outer radius, "
+            << "recommended decreasing cell phi inner size " << endl;
+   }
+
+   SpdParameter* par = GetParameter("EcalCellPhiInnerSize");
+   if (!par) fParams->Add(new SpdParameter("EcalCellPhiInnerSize", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellInnerPhiSize> Overwriting parameter \"EcalCellPhiInnerSize\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetCellOuterPhiSize(Double_t value)
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetCellOuterPhiSize> Cell phi size should be > 0" << endl;
+       exit(1);
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTBSize2()) {
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellOuterPhiSize> " 
+            << "Cell phi inner size is more than barrel outer radius, "
+            << "recommended decreasing cell phi inner size " << endl;
+   }
+   
+   SpdParameter* par = GetParameter("EcalCellPhiOuterSize");
+   if (!par) fParams->Add(new SpdParameter("EcalCellPhiOuterSize",value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellOuterPhiSize> Overwriting parameter \"EcalCellPhiOuterSize\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetNLayers(Int_t value)
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetNLayers> Number of layers should be > 0" << endl;
+       exit(1);
+   }
+   
+   SpdParameter* par = GetParameter("EcalModuleNLayers");
+   if (!par) fParams->Add(new SpdParameter("EcalModuleNLayers", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetNLayers> Overwriting parameter \"EcalModuleNLayers\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetAbsorberLayerThickness(Double_t value)
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetAbsorberLayerThickness> Absorber layer thickness should be > 0" << endl;
+       exit(1);
+   }
+   
+   SpdParameter* par = GetParameter("EcalAbsorberThickness");
+   if (!par) fParams->Add(new SpdParameter("EcalAbsorberThickness", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetAbsorberLayerThickness> Overwriting parameter \"EcalAbsorberThickness\"" << endl;
+   }
+   
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetScintLayerThickness(Double_t value)
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetScintLayerThickness> Scintillator layer thickness should be > 0" << endl;
+       exit(1);
+   }
+   
+   SpdParameter* par = GetParameter("EcalScintThickness");
+   if (!par) fParams->Add(new SpdParameter("EcalScintThickness", value)); 
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetScintLayerThickness> Overwriting parameter \"EcalScintThickness\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetCellClearance(Double_t value) 
+{
+   if (value < 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetCellClearance> Cell clearance should be >= 0" << endl;
+       exit(1);
+   }
+
+   SpdParameter* par = GetParameter("EcalCellClearance");
+   if (!par) fParams->Add(new SpdParameter("EcalCellClearance",value));
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetCellClearance> Overwriting parameter \"EcalCellClearance\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::SetModuleClearance(Double_t value) 
+{
+   if (value < 0) {
+       cout << "-F- <SpdEcalTB2GeoMapper::SetModuleClearance> Module clearance should be >= 0" << endl;
+       exit(1);
+   }
+   
+   SpdParameter* par = GetParameter("EcalModuleClearance");
+   if (!par) fParams->Add(new SpdParameter("EcalModuleClearance",value));
+   else {
+       *par = value;
+       cout << "-W- <SpdEcalTB2GeoMapper::SetModuleClearance> Overwriting parameter \"EcalModuleClearance\"" << endl;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTB2GeoMapper::Print(Option_t*) const
+{
+   cout << "-I- <SpdEcalTB2GeoMapper::Print>" << "\n\n";
+   SpdGeoMapper::Print("");
+}
+
+
+
+
+
+
+
+
diff --git a/spdgeometry/ecalt/SpdEcalTB2GeoMapper.h b/spdgeometry/ecalt/SpdEcalTB2GeoMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea5c30d726a2fe369826c772a5e5711c25aab9de
--- /dev/null
+++ b/spdgeometry/ecalt/SpdEcalTB2GeoMapper.h
@@ -0,0 +1,100 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#ifndef __SPDECALTB2GEOMAPPER_H__
+#define __SPDECALTB2GEOMAPPER_H__
+
+#include <TObjArray.h>
+
+#include "SpdGeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+
+class TString;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTB2GeoMapper                                                        //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdEcalTB2GeoMapper: public SpdGeoMapper {
+
+public:
+  
+    SpdEcalTB2GeoMapper();
+    SpdEcalTB2GeoMapper(TString prefix);
+    
+    virtual ~SpdEcalTB2GeoMapper();
+    
+    static SpdEcalTB2GeoMapper* Instance();
+    static SpdEcalTB2GeoMapper* GetMapper();
+    
+    virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
+            
+    /* Getters */
+    
+    Int_t    GetNLayers() const;
+    Int_t    GetNSectors() const;
+    
+    Double_t GetBarrelLength() const;
+    Double_t GetBarrelMaxTheta() const;
+    Double_t GetBarrelWidth() const;
+    Double_t GetBarrelOuterSize() const;
+    
+    Double_t GetSectorClearance() const;
+    Double_t GetBasketClearance() const;
+    Double_t GetModuleClearance() const;
+    Double_t GetCellClearance()   const;
+
+    Double_t GetBarrelModuleRadialSize() const;
+      
+    Double_t GetLayerInnerSizeTheta() const;
+    Double_t GetLayerInnerSizePhi() const;
+    Double_t GetLayerOuterSizeTheta() const;
+    Double_t GetLayerOuterSizePhi() const;
+    Double_t GetLayer1SizeZ() const;
+    Double_t GetLayer2SizeZ() const;
+    
+    Bool_t   IsForceCellSize() const;
+    Bool_t   IsTrimModuleLength() const;
+    
+    TString  GetBaseMedium() const;
+    TString  GetAbsorberMedium() const;
+    TString  GetScintMedium() const;
+    
+    /* Setters */
+    void SetForceInsideBasket(Bool_t value);
+    void SetForceCellSize(Bool_t value);
+
+    void SetCellZSize(Double_t value);
+    void SetCellInnerPhiSize(Double_t value);
+    void SetCellOuterPhiSize(Double_t value);
+
+    void SetNLayers(Int_t value);
+
+    void SetAbsorberLayerThickness(Double_t value);
+    void SetScintLayerThickness(Double_t value);
+
+    void SetCellClearance(Double_t value);
+    void SetModuleClearance(Double_t value);
+    
+    virtual void Print(Option_t*) const;
+            
+protected:
+    
+    /* data members */
+    static SpdEcalTB2GeoMapper* fInstance;
+    
+    TString fMasterVolName;
+    
+    void AddParameterFromCommon(TString parname, Int_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit);
+    void AddParameterFromCommon(TString parname, Double_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit);
+
+    ClassDef(SpdEcalTB2GeoMapper,1) 
+};
+
+#endif  /* __SPDECALTB2GEOMAPPER_H__ */
+
+
diff --git a/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.cxx b/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..dc921483e6cbe896e9d6f9c648af91d43473cdeb
--- /dev/null
+++ b/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.cxx
@@ -0,0 +1,457 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+//_____________________________________________________________________________
+//
+// SpdEcalTEC2GeoMapper
+//_____________________________________________________________________________
+
+#include "SpdEcalTEC2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+#include <TString.h>
+#include <TMath.h>
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+using namespace TMath;
+
+ClassImp(SpdEcalTEC2GeoMapper)
+
+SpdEcalTEC2GeoMapper* SpdEcalTEC2GeoMapper::fInstance = 0;
+
+SpdEcalTEC2GeoMapper* SpdEcalTEC2GeoMapper::Instance() 
+{ return (fInstance) ? fInstance : new SpdEcalTEC2GeoMapper(); }
+
+SpdEcalTEC2GeoMapper* SpdEcalTEC2GeoMapper::GetMapper() 
+{ return fInstance; }
+
+//_____________________________________________________________________________
+SpdEcalTEC2GeoMapper::SpdEcalTEC2GeoMapper():SpdGeoMapper("EcalTEC")
+{
+  if (fInstance) {
+      Fatal("SpdEcalTEC2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  fGeoVolPars = new TObjArray();  
+  fGeoTable = new SpdGeoTable(); 
+   
+  fMasterVolName = SpdCommonGeoMapper::Instance()->GetMasterVolumeName();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetEcalTECDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdEcalTEC2GeoMapper::SpdEcalTEC2GeoMapper(TString prefix):SpdGeoMapper(prefix)
+{
+  if (fInstance) {
+      Fatal("SpdEcalTEC2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  fGeoVolPars = new TObjArray();  
+  fGeoTable = new SpdGeoTable(); 
+   
+  fMasterVolName = SpdCommonGeoMapper::Instance()->GetMasterVolumeName();
+   
+  fGeoType = SpdCommonGeoMapper::Instance()->GetEcalTECDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdEcalTEC2GeoMapper::~SpdEcalTEC2GeoMapper() 
+{
+ 
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::UnsetMaterials(Bool_t precise, TString option)
+{
+   if (fLockGeometry) {
+       cout << "-E- <SpdEcalTEC2GeoMapper::UnsetMaterials> Geometry is locked " << endl;
+       return;
+   }
+}
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTEC2GeoMapper::IsGeoTypeDefined(Int_t gtype) const
+{ 
+   return (gtype > 0 && gtype < 2); 
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::AddParameterFromCommon(TString parname, Int_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit) 
+{
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+   SpdParameter* par = GetParameter(parname);
+   if (par) { if (reinit) *par = accessFunc(mapper); }
+   else fParams->Add(new SpdParameter(parname, accessFunc(mapper))); 
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::AddParameterFromCommon(TString parname, Double_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit) 
+{
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+   SpdParameter* par = GetParameter(parname);
+   if (par) { if (reinit) *par = accessFunc(mapper); }
+   else fParams->Add(new SpdParameter(parname, accessFunc(mapper))); 
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// Values from CommonGeoMapper:
+//
+// EcalTECMinDist1 [cm]: fabs(Z) of the front face of endcap cell 
+//                      (distance bewteen Z = 0 plane and endcap front face plane)
+//
+// Endcap is made in octagonal shape with a hole. It has two parameters:
+//
+// EcalTECSize [cm]: distance between center of endcap and the middle of octagon edge
+// EcalTECWidth [cm]: distance between centers of edges of middle and outer octagon (for same П†)
+// EcalTECThickness [cm]: thickness of endcap cell (first-level geometry)
+//
+// Some default values
+//
+// EcalECModuleClearance [cm]: clearance between modules (2x2 cells) (default: 0.1)
+// EcalECCellClearance [cm]: clerance between cells in a module (default: 0.05)
+// EcalECCellSize [cm]: X/Y size of endcap cell (default: 5.5)
+// EcalECAbsorberThickness [cm]: thickness of absorber layer (material hardcoded as lead) (default: 0.05)
+// EcalECScintThickness [cm]: thickness of scintillator layer (material hardcoded as polystyrene(?)) (default: 0.15)
+//
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//_____________________________________________________________________________
+Bool_t SpdEcalTEC2GeoMapper::InitGeometry(Int_t gtype, Bool_t reinit) 
+{ 
+   //cout << "-I- <SpdEcalTEC2GeoMapper::InitGeometry>  " << endl;
+      
+   if (fLockGeometry) {
+       cout << "-E- <SpdEcalTEC2GeoMapper::InitGeometry> Geometry is locked " << endl;
+       return kFALSE;
+   }
+  
+   if (!fParams) return kFALSE;
+   
+   if (!CheckGeoType(gtype,"EcalTECGeoType")) return kFALSE;
+   
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+   
+   SpdParameter* par; 
+    
+   /* set BASE material */
+
+   par = GetParameter("EcalECBaseMedium");
+   if (par) { if (reinit) *par = mapper->GetEcalTECBaseMaterial(); }
+   else fParams->Add(new SpdParameter("EcalECBaseMedium",mapper->GetEcalTECBaseMaterial())); 
+   
+   /* set BASE dimensions */
+    
+   AddParameterFromCommon("EcalTECMinDist1",  [](SpdCommonGeoMapper* m) { return m->GetEcalTECMinDist1();  }, reinit);
+   AddParameterFromCommon("EcalTECSize",      [](SpdCommonGeoMapper* m) { return m->GetEcalTECSize();      }, reinit);
+   AddParameterFromCommon("EcalTECWidth",     [](SpdCommonGeoMapper* m) { return m->GetEcalTECWidth();     }, reinit);
+   AddParameterFromCommon("EcalTECThickness", [](SpdCommonGeoMapper* m) { return m->GetEcalTECThickness(); }, reinit); 
+   
+//    par = GetParameter("EcalTECMinDist1");
+//    if (par) { if (reinit) *par = mapper->GetEcalTECMinDist1();  }
+//    else { fParams->Add(new SpdParameter("EcalTECMinDist1",mapper->GetEcalTECMinDist1())); }
+//    
+//    par = GetParameter("EcalTECSize");
+//    if (par) { if (reinit) *par = mapper->GetEcalTECSize();  }
+//    else { fParams->Add(new SpdParameter("EcalTECSize",mapper->GetEcalTECSize())); }
+//    
+//    par = GetParameter("EcalTECWidth");
+//    if (par) { if (reinit) *par = mapper->GetEcalTECWidth();  }
+//    else { fParams->Add(new SpdParameter("EcalTECWidth",mapper->GetEcalTECWidth())); }
+//    
+//    par = GetParameter("EcalTECThickness");
+//    if (par) { if (reinit) *par = mapper->GetEcalTECThickness();  }
+//    else { fParams->Add(new SpdParameter("EcalTECThickness",mapper->GetEcalTECThickness())); }
+   
+   //sanity check of parameters
+   //barrelLength/2 should not be larger than distance to endcaps
+
+   Double_t endcapSize(-1), endcapWidth(-2); 
+   
+   par = GetParameter("EcalTECSize");  
+   if (par) par->Value(endcapSize);
+
+   par = GetParameter("EcalTECWidth"); 
+   if (par) par->Value(endcapWidth);
+  
+   if (endcapSize < 0 || endcapWidth < 0 || endcapSize < endcapWidth) {
+       cout << "-F- <SpdEcalTEC2GeoMapper::InitGeometry> "
+            << " Cannot map ECAL geometry! ECAL endcap size < ECAL endcap width: doesn't make sense! " <<endl;
+       exit(1);     
+   }   
+   
+   /* define materials */
+   TString material;
+   
+   material = "lead";
+   par = GetParameter("EcalECAbsorberMedium");    
+   if (par) { if (reinit) *par = material; }   
+   else fParams->Add(new SpdParameter("EcalECAbsorberMedium",material)); 
+            
+   material = "FscScint";
+   par = GetParameter("EcalECScintMedium");    
+   if (par) { if (reinit) *par = material; }    
+   else { fParams->Add(new SpdParameter("EcalECScintMedium",material)); }      
+    
+   /* define dimensions */
+
+   par = GetParameter("EcalECModuleClearance");
+   if (par) { if (reinit) *par = 0.1;}
+   else { fParams->Add(new SpdParameter("EcalECModuleClearance", 0.1)); }
+   
+   par = GetParameter("EcalECCellClearance");
+   if (par) { if (reinit) *par = 0.05; }
+   else { fParams->Add(new SpdParameter("EcalECCellClearance", 0.05)); }
+   
+   par = GetParameter("EcalECCellSize");
+   if (par) { if (reinit) *par = 5.5; }
+   else { fParams->Add(new SpdParameter("EcalECCellSize", 5.5)); }
+   
+   par = GetParameter("EcalECAbsorberThickness");
+   if (par) {  if (reinit) *par = 0.05; }
+   else { fParams->Add(new SpdParameter("EcalECAbsorberThickness", 0.05)); }
+   
+   par = GetParameter("EcalECScintThickness");
+   if (par) {  if (reinit) *par = 0.15; }
+   else { fParams->Add(new SpdParameter("EcalECScintThickness", 0.15)); }
+   
+   return kTRUE;
+}
+    
+//_____________________________________________________________________________
+TString SpdEcalTEC2GeoMapper::GetBaseMedium() const 
+{
+    const SpdParameter* par = GetParameter("EcalECBaseMedium");
+    const Char_t* value = par->Value();
+    return TString(value);
+}
+
+//_____________________________________________________________________________
+TString SpdEcalTEC2GeoMapper::GetAbsorberMedium() const 
+{
+    const SpdParameter* par = GetParameter("EcalECAbsorberMedium");
+    const Char_t* value = par->Value();
+    return TString(value);
+}
+
+//_____________________________________________________________________________
+TString SpdEcalTEC2GeoMapper::GetScintMedium() const 
+{
+    const SpdParameter* par = GetParameter("EcalECScintMedium");
+    const Char_t* value = par->Value();
+    return TString(value);
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetEndcapSize() const
+{
+   const SpdParameter* par = GetParameter("EcalTECSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetEndcapWidth() const
+{
+   const SpdParameter* par = GetParameter("EcalTECWidth");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetEndcapThickness() const
+{
+   const SpdParameter* par = GetParameter("EcalTECThickness");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetEndcapMinDist() const
+{
+   const SpdParameter* par = GetParameter("EcalTECMinDist1");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetLayer1SizeZ() const
+{
+   const SpdParameter* par = GetParameter("EcalECAbsorberThickness");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetLayer2SizeZ() const
+{
+   const SpdParameter* par = GetParameter("EcalECScintThickness");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetCellSize() const
+{
+   const SpdParameter* par = GetParameter("EcalECCellSize");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetCellClearance() const
+{
+   const SpdParameter* par = GetParameter("EcalECCellClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+Double_t SpdEcalTEC2GeoMapper::GetModuleClearance() const
+{
+   const SpdParameter* par = GetParameter("EcalECModuleClearance");
+   Double_t lmax = 0;
+   if (par) par->Value(lmax);
+   return lmax;
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::SetCellSize(Double_t value) 
+{
+   if (value <= 0) {
+      cout << "-F- <SpdEcalTEC2GeoMapper::SetCellSize> cell size should be > 0" << endl;
+      exit(1);  
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTECSize()) {
+       cout << "-W- <SpdEcalTEC2GeoMapper::SetCellSize> Cell size of " 
+            << value << " cm is more than the endcap size (" 
+            << SpdCommonGeoMapper::Instance()->GetEcalTECSize() 
+            << " cm), decreasing cell size is recommended " << endl;
+   }
+   
+   SpdParameter* par = GetParameter("EcalECCellSize");
+   if (!par) fParams->Add(new SpdParameter("EcalECCellSize", value));
+   else {
+      cout << "-I- <SpdEcalTEC2GeoMapper::SetCellSize> Overwriting parameter \"EcalECCellSize\" " << endl;  
+      *par = value;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::SetAbsorberLayerThickness(Double_t value) 
+{
+   if (value <= 0) {
+       cout << "-F- <SpdEcalTEC2GeoMapper::SetAbsorberLayerThickness> Absorber layer thickness should be > 0" << endl;
+       exit(1);    
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTECThickness()/2) {
+       cout << "-W- <SpdEcalTEC2GeoMapper::SetAbsorberLayerThickness> Absorber layer thickness of " 
+            << value << " cm is more than half of the endcap thickness (" 
+            << SpdCommonGeoMapper::Instance()->GetEcalTECThickness()/2 
+            << " cm), decreasing layer width is recommended " << endl;
+   }
+    
+   SpdParameter* par = GetParameter("EcalECAbsorberThickness");
+   if (!par) fParams->Add(new SpdParameter("EcalECAbsorberThickness", value));
+   else {
+      cout << "-I- <SpdEcalTEC2GeoMapper::SetAbsorberLayerThickness> Overwriting parameter \"EcalECAbsorberThickness\" " << endl;      
+      *par = value;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::SetScintLayerThickness(Double_t value) 
+{
+   if (value <= 0) {   
+       cout << "-F- <SpdEcalTEC2GeoMapper::SetScintLayerThickness> Scintillator layer thickness should be > 0" << endl;
+       exit(1);    
+   }
+   
+   if (value > SpdCommonGeoMapper::Instance()->GetEcalTECThickness()/2) {
+       cout << "-W- <SpdEcalTEC2GeoMapper::SetScintLayerThickness> Scintillator layer thickness of " 
+            << value << " cm is more than half of the endcap thickness (" 
+            << SpdCommonGeoMapper::Instance()->GetEcalTECThickness()/2 
+            << " cm), decreasing layer width is recommended " <<endl;
+   }
+   
+   SpdParameter* par = GetParameter("EcalECScintThickness");
+   if (!par) fParams->Add(new SpdParameter("EcalECScintThickness", value));
+   else {
+      cout << "-I- <SpdEcalTEC2GeoMapper::SetModuleClearance> Overwriting parameter \"EcalECScintThickness\" " << endl;    
+      *par = value;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::SetCellClearance(Double_t value) 
+{
+   if (value < 0) {
+       cout << "-F- <SpdEcalTEC2GeoMapper::SetModuleClearance> Cell clearance should be >= 0" << endl;
+       exit(1);    
+   }
+
+   SpdParameter* par = GetParameter("EcalECCellClearance");
+   if (!par) fParams->Add(new SpdParameter("EcalECCellClearance", value));
+   else {
+       cout << "-I- <SpdEcalTEC2GeoMapper::SetModuleClearance> Overwriting parameter \"EcalECCellClearance\" " << endl; 
+       *par = value;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::SetModuleClearance(Double_t value) 
+{
+   if (value < 0) {
+       cout << "-F- <SpdEcalTEC2GeoMapper::SetModuleClearance> Module clearance should be >= 0" << endl;
+       exit(1);    
+   }
+   
+   SpdParameter* par = GetParameter("EcalECModuleClearance");
+   if (!par) fParams->Add(new SpdParameter("EcalECModuleClearance", value));
+   else {
+       cout << "-I- <SpdEcalTEC2GeoMapper::SetModuleClearance> Overwriting parameter \"EcalECModuleClearance\" " << endl; 
+       *par = value;
+   }
+}
+
+//_____________________________________________________________________________
+void SpdEcalTEC2GeoMapper::Print(Option_t*) const
+{
+   cout << "-I- <SpdEcalTEC2GeoMapper::Print>" << "\n\n";
+   SpdGeoMapper::Print("");
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.h b/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..32d0fbeac708c4f4c208b26ec7e944b0fe6ee0b2
--- /dev/null
+++ b/spdgeometry/ecalt/SpdEcalTEC2GeoMapper.h
@@ -0,0 +1,80 @@
+// $Id$
+// Author: andre/artur   2020/07/31
+
+#ifndef __SPDECALTEC2ECGEOMAPPER_H__
+#define __SPDECALTEC2ECGEOMAPPER_H__
+
+#include <TObjArray.h>
+
+#include "SpdGeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+
+class TString;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdEcalTEC2GeoMapper                                                       //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+
+class SpdEcalTEC2GeoMapper: public SpdGeoMapper {
+
+public:
+  
+    SpdEcalTEC2GeoMapper();
+    SpdEcalTEC2GeoMapper(TString prefix);
+    
+    virtual ~SpdEcalTEC2GeoMapper();
+    
+    static SpdEcalTEC2GeoMapper* Instance();
+    static SpdEcalTEC2GeoMapper* GetMapper();
+    
+    virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
+    
+    /* getters */
+    virtual Bool_t IsGeoTypeDefined(Int_t gtype) const;
+
+    Double_t GetLayer1SizeZ() const;
+    Double_t GetLayer2SizeZ() const;
+    Double_t GetCellSize() const;
+    Double_t GetCellClearance() const;
+    Double_t GetModuleClearance() const;
+    Double_t GetEndcapMinDist() const;
+    Double_t GetEndcapThickness() const;
+    Double_t GetEndcapSize() const;
+    Double_t GetEndcapWidth() const;
+    
+    TString  GetBaseMedium() const;
+    TString  GetAbsorberMedium() const;
+    TString  GetScintMedium() const;
+    
+    /* getters */
+    virtual void UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
+    
+    void SetCellSize(Double_t value);
+    void SetAbsorberLayerThickness(Double_t value);
+    void SetScintLayerThickness(Double_t value);
+    void SetCellClearance(Double_t value);
+    void SetModuleClearance(Double_t value);
+    
+    virtual void Print(Option_t*) const;
+    
+protected:
+    
+    /* data members */
+    static SpdEcalTEC2GeoMapper* fInstance;
+    
+    TString fMasterVolName;
+     
+    void AddParameterFromCommon(TString parname, Int_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit);
+    void AddParameterFromCommon(TString parname, Double_t accessFunc(SpdCommonGeoMapper*), Bool_t reinit);
+    
+    ClassDef(SpdEcalTEC2GeoMapper,1) 
+};
+
+#endif  /* __SPDECALTEC2ECGEOMAPPER_H__ */
+
+
diff --git a/spdgeometry/its/SpdItsGeoBuilder.cxx b/spdgeometry/its/SpdItsGeoBuilder.cxx
index 3e28dacf7895cb9a04d3451ef0b2b3fe5ab1473f..b67e7cbad1b757289c9be934a7c8dc67cbaec764 100644
--- a/spdgeometry/its/SpdItsGeoBuilder.cxx
+++ b/spdgeometry/its/SpdItsGeoBuilder.cxx
@@ -163,12 +163,21 @@ TGeoVolume* SpdItsGeoBuilder::BuildVolume(const SpdGeoVolPars* vpars)
    
    TGeoMedium* med = GetMedia(vpars->GetMedia());  
    
-   if (vpars->GetMedia() != med->GetName()) {
+   if (vpars->GetMedia() != med->GetName()) 
+   {
+       static Bool_t media_is_changed = false;
+       if (!media_is_changed) {
+           cout << "-W- <SpdTsTBGeoBuilder::BuildVolume> +++++ ALL MATERIALS ARE SET AS -> "
+                << med->GetName() << " +++++ " << endl;
+       }
+       media_is_changed = true;
+       
        cout << "-W- <SpdItsGeoBuilder::BuildVolume> "
             << " Volume's \"" << vpars->GetName() << "\" "
-            << " media is changed : " << vpars->GetMedia() 
+            << " media has been changed : " << vpars->GetMedia() 
             <<" -> " << med->GetName() << endl;
-      //const_cast<SpdGeoVolPars*>(vpars)->SetActivity(0); // WARNING      
+       
+       //const_cast<SpdGeoVolPars*>(vpars)->SetActivity(0); // WARNING      
    }
    
    const_cast<SpdGeoVolPars*>(vpars)->SetMedia(med->GetName()); // WARNING
@@ -321,14 +330,14 @@ Bool_t SpdItsGeoBuilder::GlobalToLocalP(const Double_t* gpnt, Double_t* lpnt)
 Bool_t SpdItsGeoBuilder::LocalToGlobalP(const Double_t* lpnt, Double_t* gpnt) 
 { 
   if (fVid < 0) return SpdGeoBuilder::LocalToGlobalP(lpnt,gpnt);
-     
+  
   SpdGeoVVolume* vvol = GetNodeVVolume();
   if (!vvol) return kFALSE;
   
   TGeoNavigator* ntor = gGeoManager->GetCurrentNavigator();
   if (!ntor) return kFALSE;
   
-  Double_t ploc[3] = {ploc[0], ploc[1], ploc[2]};
+  Double_t ploc[3] = {lpnt[0], lpnt[1], lpnt[2]};
   
   vvol->LocalToMaster(fVid,ploc[0],ploc[1],ploc[2]);
   ntor->LocalToMaster(ploc,gpnt);
@@ -339,4 +348,4 @@ Bool_t SpdItsGeoBuilder::LocalToGlobalP(const Double_t* lpnt, Double_t* gpnt)
 
 
     
-    
\ No newline at end of file
+    
diff --git a/spdgeometry/its/SpdItsGeoMapperX.cxx b/spdgeometry/its/SpdItsGeoMapperX.cxx
index 9aa8629423cf75ec0cd7e075984218d9e6ea1889..a830aa34ae0580ce8b61043d7ee900891e1a2253 100644
--- a/spdgeometry/its/SpdItsGeoMapperX.cxx
+++ b/spdgeometry/its/SpdItsGeoMapperX.cxx
@@ -332,7 +332,14 @@ void SpdItsGeoMapperX::UnsetMaterials(Bool_t precise, TString option)
        cout << "-E- <SpdItsGeoMapperX::UnsetMaterials> Geometry is locked " << endl;
        return;
    }
-   fUnsetMedia = "vacuumX";
+
+        if (option.IsWhitespace()) { fUnsetMedia = "vacuumX"; }
+   else if (option == "base")      { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "vacuum")    { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "air")       { fUnsetMedia = "airX";    } 
+   else                            { fUnsetMedia = option;    }
+   
+   //cout << "-I- <SpdItsGeoMapperX::UnsetMaterials> Material: " << fUnsetMedia << endl;
 }
 
 //_____________________________________________________________________________
diff --git a/spdgeometry/its/SpdItsGeoMapperX.h b/spdgeometry/its/SpdItsGeoMapperX.h
index bf92bac10c44829115aea18a38b83f1df416bda1..d2f90cc3650e34cec0ce0dc9c6462619ad772e26 100644
--- a/spdgeometry/its/SpdItsGeoMapperX.h
+++ b/spdgeometry/its/SpdItsGeoMapperX.h
@@ -35,7 +35,7 @@ public:
     
     virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
     
-    virtual void UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
+    virtual void   UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
    
     virtual Bool_t IsGeoTypeDefined(Int_t gtype) const;
      
diff --git a/spdgeometry/rst/SpdRsTB2GeoMapper.cxx b/spdgeometry/rst/SpdRsTB2GeoMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..980208e67d851537e1f51d8e5c08e58bc8f4b494
--- /dev/null
+++ b/spdgeometry/rst/SpdRsTB2GeoMapper.cxx
@@ -0,0 +1,330 @@
+// $Id$
+// Author: artur   2018/02/01
+
+//_____________________________________________________________________________
+//
+// SpdRsTB2GeoMapper
+//_____________________________________________________________________________
+
+#include "SpdRsTB2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+#include <TMath.h>
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+using namespace TMath;
+
+ClassImp(SpdRsTB2GeoMapper)
+
+SpdRsTB2GeoMapper* SpdRsTB2GeoMapper::fInstance = 0;
+
+SpdRsTB2GeoMapper* SpdRsTB2GeoMapper::Instance() 
+{ return (fInstance) ? fInstance : new SpdRsTB2GeoMapper(); }
+
+SpdRsTB2GeoMapper* SpdRsTB2GeoMapper::GetMapper() 
+{ return fInstance; }   
+    
+//_____________________________________________________________________________
+SpdRsTB2GeoMapper::SpdRsTB2GeoMapper():SpdGeoMapper("RsTB")
+{
+  if (fInstance) {
+      Fatal("SpdRsTB2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+   
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetRsTBDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdRsTB2GeoMapper::SpdRsTB2GeoMapper(TString prefix):SpdGeoMapper(prefix)
+{
+  if (fInstance) {
+      Fatal("SpdRsTB2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+   
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetRsTBDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdRsTB2GeoMapper::~SpdRsTB2GeoMapper() 
+{
+ 
+}
+
+//_____________________________________________________________________________
+void SpdRsTB2GeoMapper::UnsetMaterials(Bool_t precise, TString option)
+{
+   if (fLockGeometry) {
+       cout << "-E- <SpdRsTB2GeoMapper::UnsetMaterials> Geometry is locked " << endl;
+       return;
+   }
+   
+        if (option.IsWhitespace()) { fUnsetMedia = "vacuumX"; }
+   else if (option == "base")      { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "vacuum")    { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "air")       { fUnsetMedia = "airX";    } 
+   else                            { fUnsetMedia = option;    }
+}
+
+// ****************************************************************************
+// ********************* GETTERS (BEGIN) **************************************
+// ****************************************************************************
+
+//_____________________________________________________________________________
+TString SpdRsTB2GeoMapper::GetBaseMaterial() const
+{
+   const SpdParameter* par = GetParameter("RsTBBaseMaterial");
+   return (par) ?  par->Value() : "";
+}
+
+//_____________________________________________________________________________
+TString SpdRsTB2GeoMapper::GetAbsorbMaterial() const
+{
+   const SpdParameter* par = GetParameter("RsTBAbsorbMaterial");
+   return (par) ?  par->Value() : "";
+}
+
+//_____________________________________________________________________________
+TString SpdRsTB2GeoMapper::GetPassiveMaterialMDT() const
+{
+   const SpdParameter* par = GetParameter("RsTBPassiveMaterialMDT");
+   return (par) ?  par->Value() : "";
+}
+
+//_____________________________________________________________________________
+TString SpdRsTB2GeoMapper::GetActiveMaterialMDT() const
+{
+   const SpdParameter* par = GetParameter("RsTBActiveMaterialMDT");
+   return (par) ?  par->Value() : "";
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleLength() const
+{
+   const SpdParameter* par = GetParameter("RsTBLen");
+   Double_t len = 0;
+   if (par) par->Value(len);
+   return len;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleSize() const
+{
+   const SpdParameter* par = GetParameter("RsTBSize");
+   Double_t size = 0;
+   if (par) par->Value(size);
+   return size;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleWidth() const
+{
+   const SpdParameter* par = GetParameter("RsTBWidth");
+   Double_t width = 0;
+   if (par) par->Value(width);
+   return width;
+}
+
+//_____________________________________________________________________________
+Int_t SpdRsTB2GeoMapper::GetNLayers() const
+{
+   const SpdParameter* par = GetParameter("RsTBNLayers");
+   Int_t nlayers = 0;
+   if (par) par->Value(nlayers);
+   return nlayers;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleHmin() const
+{
+   const SpdParameter* par = GetParameter("RsTBHmin");
+   Double_t h = 0;
+   if (par) par->Value(h);
+   return h;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleHmax() const
+{
+   const SpdParameter* par = GetParameter("RsTBHmax");
+   Double_t h = 0;
+   if (par) par->Value(h);
+   return h;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleLmin() const
+{
+   const SpdParameter* par = GetParameter("RsTBLmin");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetModuleLmax() const
+{
+   const SpdParameter* par = GetParameter("RsTBLmax");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________
+Int_t SpdRsTB2GeoMapper::GetNSectors() const
+{
+   Int_t nsec;
+   const SpdParameter* par = GetParameter("RsTBNSectors");
+   if (!par) return 0;
+   par->Value(nsec);
+   return nsec;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTB2GeoMapper::GetSecAngle() const
+{
+   Int_t nsec = GetNSectors();
+   return (nsec > 0) ? 360./nsec: 0;
+}
+
+//_____________________________________________________________________________
+Bool_t SpdRsTB2GeoMapper::IsGeoTypeDefined(Int_t gtype) const
+{ 
+   return (gtype > 0 && gtype < 3); 
+}
+
+// ****************************************************************************
+// ********************* GETTERS (END) ****************************************
+// ****************************************************************************
+
+//_____________________________________________________________________________
+Bool_t SpdRsTB2GeoMapper::InitGeometry(Int_t gtype, Bool_t reinit) 
+{ 
+   if (fLockGeometry) {
+       cout << "-E- <SpdRsTB2GeoMapper::InitGeometry> Geometry is locked " << endl;
+       return kFALSE;
+   }
+ 
+   if (!fParams) return kFALSE;
+
+   if (!CheckGeoType(gtype,"RsTBGeoType")) return kFALSE;
+
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+     
+   SpdParameter* par;
+   
+   // ATTENTION Number of sectors -> FIXED!
+   const Int_t NUMBER_OF_SECTORS = 8;
+   par = GetParameter("RsTBNSectors");
+   if (par) { if (reinit) *par = NUMBER_OF_SECTORS; }
+   else { fParams->Add(new SpdParameter("RsTBNSectors",NUMBER_OF_SECTORS)); } 
+  
+   par = GetParameter("RsTBBaseMaterial");
+   if (par) { if (reinit) *par = mapper->GetRsTBBaseMaterial(); }
+   else { fParams->Add(new SpdParameter("RsTBBaseMaterial",mapper->GetRsTBBaseMaterial())); } 
+          
+   //cout << "-I- <SpdRsTB2GeoMapper::InitGeometry> reinit: " << reinit << endl;
+      
+   SetParameters(reinit);
+  
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+void SpdRsTB2GeoMapper::SetParameters(Bool_t reinit) // private
+{
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+  
+   SpdParameter* par;
+   
+   /* define module size */
+
+   par = GetParameter("RsTBLen");  
+   if (par) { if (reinit) *par = mapper->GetRsTBLen2(); }
+   else { fParams->Add(new SpdParameter("RsTBLen",mapper->GetRsTBLen2())); }
+    
+   Double_t size = mapper->GetRsTBSize2();
+   par = GetParameter("RsTBSize");  
+   if (par) { if (reinit) *par = size; }
+   else { fParams->Add(new SpdParameter("RsTBSize",size)); }
+    
+   Double_t width = mapper->GetRsTBWidth2();
+   par = GetParameter("RsTBWidth");  
+   if (par) { if (reinit) *par = width; }
+   else { fParams->Add(new SpdParameter("RsTBWidth",width)); } 
+   
+   /* define materials */
+   
+   TString material;
+   
+   material = "iron";
+   par = GetParameter("RsTBAbsorbMaterial");
+   if (par) { if (reinit) *par = material; }
+   else { fParams->Add(new SpdParameter("RsTBAbsorbMaterial",material)); } 
+   
+   material = "aluminium";
+   par = GetParameter("RsTBPassiveMaterialMDT");
+   if (par) { if (reinit) *par = material; }
+   else { fParams->Add(new SpdParameter("RsTBPassiveMaterialMDT",material)); } 
+   
+   material = "MDTMixture";
+   par = GetParameter("RsTBActiveMaterialMDT");
+   if (par) { if (reinit) *par = material; }
+   else { fParams->Add(new SpdParameter("RsTBActiveMaterialMDT",material)); } 
+      
+   /* define secondary parameters */
+  
+   Double_t angle = 0.5*GetSecAngle()*DegToRad();
+  
+   Double_t hmin = size - width;
+   par = GetParameter("RsTBHmin");  
+   if (par) { *par = hmin; }
+   else { fParams->Add(new SpdParameter("RsTBHmin",hmin,1)); }
+   
+   Double_t hmax = size;
+   par = GetParameter("RsTBHmax");  
+   if (par) { *par = hmax; }
+   else { fParams->Add(new SpdParameter("RsTBHmax",hmax,1)); }
+   
+   Double_t lmin = 2.*hmin*Tan(angle); 
+   par = GetParameter("RsTBHLmin");  
+   if (par) { *par = lmin; }
+   else { fParams->Add(new SpdParameter("RsTBLmin",lmin,2)); }
+
+   Double_t lmax = 2.*hmax*Tan(angle);
+   par = GetParameter("RsTBLmax");  
+   if (par) { *par = lmax; }
+   else { fParams->Add(new SpdParameter("RsTBLmax",lmax,2)); }
+   
+   //----------------------------------------------------------------
+   // Number of layers calcluation within RS thickness:
+   // (Thickness - top absorber - bottom absorber/mdt)/LayerThickness + 1(bottom layer)
+   
+   Int_t nLayers = Int_t((width - 6. - 9.5)/6.5) + 1; 
+   par = GetParameter("RsTBNLayers");  
+   if (par) { *par = nLayers; }
+   else { fParams->Add(new SpdParameter("RsTBNLayers",nLayers,2)); }
+}
+
+//_____________________________________________________________________________
+void SpdRsTB2GeoMapper::Print(Option_t*) const
+{
+   cout << "-I- <SpdRsTB2GeoMapper::Print>" << "\n\n";
+   SpdGeoMapper::Print("");
+}
+
+
+
+
diff --git a/spdgeometry/rst/SpdRsTB2GeoMapper.h b/spdgeometry/rst/SpdRsTB2GeoMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba2b95670a86307f9799c2962cae14d6cc26f1a7
--- /dev/null
+++ b/spdgeometry/rst/SpdRsTB2GeoMapper.h
@@ -0,0 +1,71 @@
+// $Id$
+// Author: artur   2018/02/01
+
+#ifndef __SPDRSTB2GEOMAPPER_H__
+#define __SPDRSTB2GEOMAPPER_H__
+
+#include <TObjArray.h>
+
+#include "SpdGeoMapper.h"
+
+class TString;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTB2GeoMapper                                                           //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdRsTB2GeoMapper: public SpdGeoMapper {
+
+public:
+  
+    SpdRsTB2GeoMapper();
+    SpdRsTB2GeoMapper(TString prefix);
+    
+    virtual ~SpdRsTB2GeoMapper();
+    
+    static SpdRsTB2GeoMapper* Instance();
+    static SpdRsTB2GeoMapper* GetMapper();
+    
+    virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
+    
+    virtual void UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
+    
+    TString  GetBaseMaterial() const;
+    TString  GetAbsorbMaterial() const;
+    TString  GetPassiveMaterialMDT() const;
+    TString  GetActiveMaterialMDT() const;
+
+    Double_t GetModuleLength() const;
+    Double_t GetModuleSize() const;
+    Double_t GetModuleWidth() const;
+    Int_t    GetNLayers() const;
+    
+    Double_t GetModuleHmin() const;
+    Double_t GetModuleHmax() const;
+    Double_t GetModuleLmin() const;
+    Double_t GetModuleLmax() const;
+
+    virtual Bool_t IsGeoTypeDefined(Int_t gtype) const;
+     
+    virtual void Print(Option_t*) const;
+    
+    Int_t      GetNSectors() const; 
+    Double_t   GetSecAngle() const; // deg
+    
+private:
+  
+    /* data members */
+    static SpdRsTB2GeoMapper* fInstance;
+    
+    void SetParameters(Bool_t reinit);
+      
+    ClassDef(SpdRsTB2GeoMapper,1) 
+};
+
+#endif  /* __SPDRSTB2GEOMAPPER_H__ */
+
+
diff --git a/spdgeometry/rst/SpdRsTEC2GeoMapper.cxx b/spdgeometry/rst/SpdRsTEC2GeoMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..23ed1ddcd43c445ce51f4c1735163b25b6b795af
--- /dev/null
+++ b/spdgeometry/rst/SpdRsTEC2GeoMapper.cxx
@@ -0,0 +1,310 @@
+// $Id$
+// Author: alver   2020/07/17
+
+//_____________________________________________________________________________
+//
+// SpdRsTEC2GeoMapper
+//_____________________________________________________________________________
+
+#include "SpdRsTEC2GeoMapper.h"
+#include "SpdCommonGeoMapper.h"
+
+#include <TMath.h>
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+using namespace TMath;
+
+ClassImp(SpdRsTEC2GeoMapper)
+
+SpdRsTEC2GeoMapper* SpdRsTEC2GeoMapper::fInstance = 0;
+
+SpdRsTEC2GeoMapper* SpdRsTEC2GeoMapper::Instance() 
+{ return (fInstance) ? fInstance : new SpdRsTEC2GeoMapper(); }
+
+SpdRsTEC2GeoMapper* SpdRsTEC2GeoMapper::GetMapper() 
+{ return fInstance; } 
+    
+//_____________________________________________________________________________
+SpdRsTEC2GeoMapper::SpdRsTEC2GeoMapper():SpdGeoMapper("RsTEC")
+{
+  if (fInstance) {
+      Fatal("SpdRsTEC2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetRsTECDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdRsTEC2GeoMapper::SpdRsTEC2GeoMapper(TString prefix):SpdGeoMapper(prefix)
+{
+  if (fInstance) {
+      Fatal("SpdRsTEC2GeoMapper", "Singleton instance already exists.");
+      return;
+  }
+  
+  fInstance = this;
+  
+  fParams = new TObjArray();
+  
+  fGeoType = SpdCommonGeoMapper::Instance()->GetRsTECDefGeoType();
+}
+
+//_____________________________________________________________________________
+SpdRsTEC2GeoMapper::~SpdRsTEC2GeoMapper() 
+{
+ 
+}
+
+//_____________________________________________________________________________
+void SpdRsTEC2GeoMapper::UnsetMaterials(Bool_t precise, TString option)
+{
+   if (fLockGeometry) {
+       cout << "-E- <SpdRsTEC2GeoMapper::UnsetMaterials> Geometry is locked " << endl;
+       return;
+   }
+ 
+        if (option.IsWhitespace()) { fUnsetMedia = "vacuumX"; }
+   else if (option == "base")      { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "vacuum")    { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX"; }
+   else if (option == "air")       { fUnsetMedia = "airX";    } 
+   else                            { fUnsetMedia = option;    }
+ 
+   SpdParameter* par;
+   
+   par = GetParameter("RsTEC2BaseMaterial");
+   if (!par) { fParams->Add(new SpdParameter("RsTECBaseMaterial",fUnsetMedia)); }
+   else { *par = fUnsetMedia; } 
+   
+   par = GetParameter("RsTECAbsorbMaterial");
+   if (!par) { fParams->Add(new SpdParameter("RsTECAbsorbMaterial",fUnsetMedia)); }
+   else { *par = fUnsetMedia; }
+
+   par = GetParameter("RsTECPassiveMaterialMDT");
+   if (!par) { fParams->Add(new SpdParameter("RsTECPassiveMaterialMDT",fUnsetMedia)); }
+   else { *par = fUnsetMedia; }
+   
+   par = GetParameter("RsTECActiveMaterialMDT");
+   if (!par) { fParams->Add(new SpdParameter("RsTECActiveMaterialMDT",fUnsetMedia)); }
+   else { *par = fUnsetMedia; }
+}
+
+// **************************************************************************** 
+// ********************* GETTERS (BEGIN) ************************************** 
+// **************************************************************************** 
+
+//_____________________________________________________________________________
+TString SpdRsTEC2GeoMapper::GetBaseMaterial() const
+{
+   const SpdParameter* par = GetParameter("RsTECBaseMaterial");    
+   return (par) ?  par->Value() : ""; 
+} 
+
+//_____________________________________________________________________________
+TString SpdRsTEC2GeoMapper::GetAbsorbMaterial() const
+{
+   const SpdParameter* par = GetParameter("RsTECAbsorbMaterial");
+   return (par) ?  par->Value() : ""; 
+}
+
+//_____________________________________________________________________________
+TString SpdRsTEC2GeoMapper::GetPassiveMaterialMDT() const
+{    
+   const SpdParameter* par = GetParameter("RsTECPassiveMaterialMDT");    
+   return (par) ?  par->Value() : ""; 
+} 
+
+//_____________________________________________________________________________
+TString SpdRsTEC2GeoMapper::GetActiveMaterialMDT() const 
+{    
+   const SpdParameter* par = GetParameter("RsTECActiveMaterialMDT");    
+   return (par) ?  par->Value() : ""; 
+} 
+
+//_____________________________________________________________________________
+Int_t SpdRsTEC2GeoMapper::GetNSectors() const
+{
+   Int_t nsec;
+   const SpdParameter* par = GetParameter("RsTECNSectors");
+   if (!par) return 0;
+   par->Value(nsec);
+   return nsec;
+}
+
+
+//_____________________________________________________________________________
+Double_t SpdRsTEC2GeoMapper::GetSecAngleOver2() const
+{
+   Int_t nsec = GetNSectors();
+   return (nsec > 0) ? 180./nsec: 0;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTEC2GeoMapper::GetModuleInnerRadius() const
+{
+   const SpdParameter* par = GetParameter("RsTECHmin");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTEC2GeoMapper::GetModuleOuterRadius() const
+{
+   const SpdParameter* par = GetParameter("RsTECSize");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTEC2GeoMapper::GetModuleThickness() const
+{
+   const SpdParameter* par = GetParameter("RsTECThickness");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________
+Double_t SpdRsTEC2GeoMapper::GetDist() const
+{
+   const SpdParameter* par = GetParameter("RsTECMinDist1");
+   Double_t l = 0;
+   if (par) par->Value(l);
+   return l;
+}
+
+//_____________________________________________________________________________ 
+Int_t SpdRsTEC2GeoMapper::GetNLayers() const 
+{    
+   const SpdParameter* par = GetParameter("RsTECNLayers");    
+   Int_t nlayers = 0;    
+   if (par) par->Value(nlayers);    
+   return nlayers; 
+}
+
+//_____________________________________________________________________________
+Bool_t SpdRsTEC2GeoMapper::IsGeoTypeDefined(Int_t gtype) const
+{ 
+  return (gtype > 0 && gtype < 3); 
+}
+
+// **************************************************************************** 
+// ********************* GETTERS (END) **************************************** 
+// ****************************************************************************
+//
+//_____________________________________________________________________________
+Bool_t SpdRsTEC2GeoMapper::InitGeometry(Int_t gtype, Bool_t reinit) 
+{ 
+   if (fLockGeometry) {
+       cout << "-E- <SpdRsTEC2GeoMapper::InitGeometry> Geometry is locked " << endl;
+       return kFALSE;
+   }
+  
+   if (!fParams) return kFALSE;
+   
+   if (!CheckGeoType(gtype,"RsTECGeoType")) return kFALSE;
+     
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+  
+   SpdParameter* par;
+  
+   // ATTENTION Number of sectors -> FIXED!
+   const Int_t NUMBER_OF_SECTORS = 8;
+   par = GetParameter("RsTECNSectors");
+   if (par) { if (reinit) *par = NUMBER_OF_SECTORS; }
+   else { fParams->Add(new SpdParameter("RsTECNSectors", NUMBER_OF_SECTORS)); }
+   
+   par = GetParameter("RsTECBaseMaterial");
+   if (par) { if (reinit) *par = mapper->GetRsTECBaseMaterial(); }
+   else { fParams->Add(new SpdParameter("RsTECBaseMaterial",mapper->GetRsTECBaseMaterial())); } 
+   
+   //cout << "-I- <SpdRsTEC2GeoMapper::InitGeometry> reinit: " << reinit << endl;
+     
+   SetParameters(reinit);
+    
+   return kTRUE;
+}
+
+//_____________________________________________________________________________
+void SpdRsTEC2GeoMapper::SetParameters(Bool_t reinit) // private
+{ 
+   static SpdCommonGeoMapper* mapper = SpdCommonGeoMapper::Instance();
+   
+   SpdParameter* par;
+   
+   par = GetParameter("RsTECMinDist");  
+   if (par) { if (reinit) *par = mapper->GetRsTECMinDist1(); }
+   else { fParams->Add(new SpdParameter("RsTECMinDist1",mapper->GetRsTECMinDist1())); } 
+   
+   Double_t size = mapper->GetRsTECSize();
+   par = GetParameter("RsTECSize");  
+   if (par) { if (reinit) *par = size; }
+   else { fParams->Add(new SpdParameter("RsTECSize",size)); } 
+   
+   Double_t width = mapper->GetRsTECWidth();
+   par = GetParameter("RsTECWidth");  
+   if (par) { if (reinit) *par = width; }
+   else { fParams->Add(new SpdParameter("RsTECWidth",width)); } 
+   
+   Double_t thickness = mapper->GetRsTECThickness();
+   par = GetParameter("RsTECThickness");  
+   if (par) { if (reinit) *par = thickness; }
+   else { fParams->Add(new SpdParameter("RsTECThickness",thickness)); }  
+   
+   /* define secondary parameters */
+  
+   Double_t hmin = size - width;  
+   par = GetParameter("RsTECHmin");
+   if (par) { *par = hmin; }
+   else { fParams->Add(new SpdParameter("RsTECHmin",hmin,1)); } 
+
+
+   /* define materials */
+
+   TString material;
+   material = "iron";    
+   par = GetParameter("RsTECAbsorbMaterial");    
+   if (par) { if (reinit) *par = material; }   
+   else { fParams->Add(new SpdParameter("RsTECAbsorbMaterial",material)); }       
+   
+   material = "aluminium";    
+   par = GetParameter("RsTECPassiveMaterialMDT");    
+   if (par) { if (reinit) *par = material; }    
+   else { fParams->Add(new SpdParameter("RsTECPassiveMaterialMDT",material)); }       
+
+   material = "MDTMixture";    
+   par = GetParameter("RsTECActiveMaterialMDT");    
+   if (par) { if (reinit) *par = material; }    
+   else { fParams->Add(new SpdParameter("RsTECActiveMaterialMDT",material)); }    
+
+   //----------------------------------------------------------------    
+   // Number of layers calcluation within RS thickness:    
+   // (Thickness - top absorber - bottom absorber/mdt)/LayerThickness + 1(bottom layer)       
+
+   Int_t nLayers = Int_t((thickness - 6. - 9.5)/6.5) + 1;    
+   par = GetParameter("RsTECNLayers");     
+   if (par) { *par = nLayers; }    
+   else { fParams->Add(new SpdParameter("RsTECNLayers",nLayers,2)); } 
+
+}
+
+//_____________________________________________________________________________
+void SpdRsTEC2GeoMapper::Print(Option_t*) const
+{
+   cout << "-I- <SpdRsTEC2GeoMapper::Print>" << "\n\n";
+   SpdGeoMapper::Print("");
+}
+
+
+
+
diff --git a/spdgeometry/rst/SpdRsTEC2GeoMapper.h b/spdgeometry/rst/SpdRsTEC2GeoMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ecf99a322c7c2455b3979782df07e3a5fe8d866
--- /dev/null
+++ b/spdgeometry/rst/SpdRsTEC2GeoMapper.h
@@ -0,0 +1,66 @@
+// $Id$
+// Author: alver   2020/07/17
+
+#ifndef __SPDRSTEC2GEOMAPPER_H__
+#define __SPDRSTEC2GEOMAPPER_H__
+
+#include <TObjArray.h>
+
+#include "SpdGeoMapper.h"
+
+class TString;
+
+////////////////////////////////////////////////////////////////////////////////
+//                                                                            //
+// SpdRsTEC2GeoMapper                                                          //
+//                                                                            //
+// <brief class description>                                                  //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+class SpdRsTEC2GeoMapper: public SpdGeoMapper {
+
+public:
+  
+    SpdRsTEC2GeoMapper();
+    SpdRsTEC2GeoMapper(TString prefix);
+    
+    virtual ~SpdRsTEC2GeoMapper();
+    
+    static SpdRsTEC2GeoMapper* Instance();
+    static SpdRsTEC2GeoMapper* GetMapper();
+    
+    virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
+    
+    virtual void UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
+    
+    virtual Bool_t IsGeoTypeDefined(Int_t gtype) const;
+     
+    virtual void Print(Option_t*) const;
+    
+    Int_t      GetNSectors() const;
+    Double_t   GetSecAngleOver2() const; // deg
+    Double_t   GetModuleInnerRadius() const;
+    Double_t   GetModuleOuterRadius() const;
+    Double_t   GetModuleThickness() const;
+    Double_t   GetDist() const;
+    Int_t      GetNLayers() const;
+
+    TString  GetBaseMaterial() const;     
+    TString  GetAbsorbMaterial() const;     
+    TString  GetPassiveMaterialMDT() const;     
+    TString  GetActiveMaterialMDT() const;
+
+private:
+  
+    /* data members */
+    static SpdRsTEC2GeoMapper* fInstance;
+    
+    void SetParameters(Bool_t reinit);
+      
+    ClassDef(SpdRsTEC2GeoMapper,1) 
+};
+
+#endif  /* __SPDRSTEC2GEOMAPPER_H__ */
+
+
diff --git a/spdgeometry/tst/SpdTsBVolPars.cxx b/spdgeometry/tst/SpdTsBVolPars.cxx
index a720f50a73edb4e828afdcdf5fa5d6b1cb3ab1cb..6a33377c34111e8470bc33719762e9e72e8a1a8a 100644
--- a/spdgeometry/tst/SpdTsBVolPars.cxx
+++ b/spdgeometry/tst/SpdTsBVolPars.cxx
@@ -25,7 +25,7 @@ ClassImp(SpdTsBStraw)
 ClassImp(SpdTsBStrawLayer)
 ClassImp(SpdTsBStrawModule)
 
-Double_t SpdTsBStraw::fMinStrawSize = 40.; //cm
+Double_t SpdTsBStraw::fMinStrawSize = 10.; //cm
 Double_t SpdTsBStrawLayer::fMinLayerSize = 0.1; //cm
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -309,6 +309,7 @@ Bool_t SpdTsBStrawLayer::MakePacking()
           SpdTsBStraw::GetMinStrawSize(), fPackingStrawShift,
           fPackingStrawAngle, fPackingStrawWidth, fPackingStrawGap);
   
+  return kTRUE;
 }
 
 //_____________________________________________________________________________
diff --git a/spdgeometry/tst/SpdTsECVolPars.cxx b/spdgeometry/tst/SpdTsECVolPars.cxx
index 6942c252c1a0e57db696a1ac41fae33e0c33124c..18f46021484678fba0357fa86982b46aef6d3fd7 100644
--- a/spdgeometry/tst/SpdTsECVolPars.cxx
+++ b/spdgeometry/tst/SpdTsECVolPars.cxx
@@ -27,7 +27,7 @@ ClassImp(SpdTsECStrawModule)
 ClassImp(SpdTsECStrawModuleArb)
 ClassImp(SpdTsECStrawModulePgon)
 
-Double_t SpdTsECStraw::fMinStrawSize = 40.; //cm
+Double_t SpdTsECStraw::fMinStrawSize = 10.; //cm
 
 ////////////////////////////////////////////////////////////////////////////////
 //                                                                            //
diff --git a/spdgeometry/tst/SpdTsTBGeoBuilder.cxx b/spdgeometry/tst/SpdTsTBGeoBuilder.cxx
index 80cb947bf61c630e754062db06cb9ea950c0264c..8050a43642e83d1bbca2f33da3501fbe17d33b25 100644
--- a/spdgeometry/tst/SpdTsTBGeoBuilder.cxx
+++ b/spdgeometry/tst/SpdTsTBGeoBuilder.cxx
@@ -151,6 +151,7 @@ Bool_t SpdTsTBGeoBuilder::IsGeometryChanged() // public
    if (fCheckedVolumes.empty()) return kFALSE;  
    std::map< TString, Int_t >::const_iterator it = fCheckedVolumes.begin();
    for (; it != fCheckedVolumes.end(); it++) { if (it->second > 0) return kTRUE; }
+   return kTRUE;
 }
 
 //_____________________________________________________________________________
@@ -327,11 +328,20 @@ TGeoVolume* SpdTsTBGeoBuilder::BuildVolume(const SpdGeoVolPars* vpars)
    
    TGeoMedium* med = GetMedia(vpars->GetMedia());  
    
-   if (vpars->GetMedia() != med->GetName()) {
-       cout << "-W- <SpdTsTBGeoBuilder::BuildVolume> "
-            << " Volume's \"" << vpars->GetName() << "\" "
-            << " media is changed : " << vpars->GetMedia() 
-            <<" -> " << med->GetName() << endl;
+   if (vpars->GetMedia() != med->GetName()) 
+   {
+       static Bool_t media_is_changed = false;
+       if (!media_is_changed) {
+           cout << "-W- <SpdTsTBGeoBuilder::BuildVolume> +++++ ALL MATERIALS ARE SET AS -> "
+                << med->GetName() << " +++++ " << endl;
+       }
+       media_is_changed = true;
+       
+       //cout << "-W- <SpdTsTBGeoBuilder::BuildVolume> "
+       //     << " Volume's \"" << vpars->GetName() << "\" "
+       //     << " media has been changed : " << vpars->GetMedia() 
+       //     <<" -> " << med->GetName() << endl;
+       
        //const_cast<SpdGeoVolPars*>(vpars)->SetActivity(0); // WARNING      
    }
    
diff --git a/spdgeometry/tst/SpdTsTBGeoMapper.cxx b/spdgeometry/tst/SpdTsTBGeoMapper.cxx
index 3e11fe09afdbb92bae276e7d7db03e20e5ebe2ab..5d320dedb9000b2b7ce13574152548fe99bfa73e 100644
--- a/spdgeometry/tst/SpdTsTBGeoMapper.cxx
+++ b/spdgeometry/tst/SpdTsTBGeoMapper.cxx
@@ -96,7 +96,12 @@ void SpdTsTBGeoMapper::UnsetMaterials(Bool_t precise, TString option)
        cout << "-E- <SpdTsTBGeoMapper::UnsetMaterials> Geometry is locked " << endl;
        return;
    }
-   (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuum";
+   
+        if (option.IsWhitespace()) { fUnsetMedia = "vacuumX1"; }
+   else if (option == "base")      { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX1"; }
+   else if (option == "vacuum")    { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX1"; }
+   else if (option == "air")       { fUnsetMedia = "airX1";    } 
+   else                            { fUnsetMedia = option;     }
 }
 
 //_____________________________________________________________________________
@@ -710,8 +715,18 @@ void SpdTsTBGeoMapper::SetParameters_2(Bool_t reinit) // private
    if (par) { *par = hmin2; }
    else { fParams->Add(new SpdParameter("TsTBHmin2",hmin2,1)); }
    
+   Double_t rmin2 = hmin2;
+   par = GetParameter("TsTBRmin2");  
+   if (par) { *par = rmin2; }
+   else { fParams->Add(new SpdParameter("TsTBRmin2",rmin2,1)); }
+   
+   Double_t rmax2 = size2/Cos(angle);
+   par = GetParameter("TsTBRmax2");  
+   if (par) { *par = rmax2; }
+   else { fParams->Add(new SpdParameter("TsTBRmax2",rmax2,1)); }
+   
    Double_t lmin2 = 2*(hmin2*Tan(angle) - clearance21);  // < 0 ? 
-   par = GetParameter("TsTBHLmin2");  
+   par = GetParameter("TsTBLmin2");  
    if (par) { *par = lmin2; }
    else { fParams->Add(new SpdParameter("TsTBLmin2",lmin2,2)); }
 
diff --git a/spdgeometry/tst/SpdTsTECGeoBuilder.cxx b/spdgeometry/tst/SpdTsTECGeoBuilder.cxx
index 8a17e78e53212da8dad8c0ac3dd4b1c21df75035..908e53c5bb355331552b1d0edac5a40d1d61f843 100644
--- a/spdgeometry/tst/SpdTsTECGeoBuilder.cxx
+++ b/spdgeometry/tst/SpdTsTECGeoBuilder.cxx
@@ -154,11 +154,20 @@ TGeoVolume* SpdTsTECGeoBuilder::BuildVolume(const SpdGeoVolPars* vpars)
    
    TGeoMedium* med = GetMedia(vpars->GetMedia());  
    
-   if (vpars->GetMedia() != med->GetName()) {
-       cout << "-W- <SpdTsTECGeoBuilder::BuildVolume> "
-            << " Volume's \"" << vpars->GetName() << "\" "
-            << " media is changed : " << vpars->GetMedia() 
-            <<" -> " << med->GetName() << endl;
+   if (vpars->GetMedia() != med->GetName()) 
+   {
+       static Bool_t media_is_changed = false;
+       if (!media_is_changed) {
+           cout << "-W- <SpdTsTBGeoBuilder::BuildVolume> +++++ ALL MATERIALS ARE SET AS -> "
+                << med->GetName() << " +++++ " << endl;
+       }
+       media_is_changed = true;
+       
+       //cout << "-W- <SpdTsTECGeoBuilder::BuildVolume> "
+       //     << " Volume's \"" << vpars->GetName() << "\" "
+       //     << " media has been changed : " << vpars->GetMedia() 
+       //     <<" -> " << med->GetName() << endl;
+            
        //const_cast<SpdGeoVolPars*>(vpars)->SetActivity(0); // WARNING      
    }
    
diff --git a/spdgeometry/tst/SpdTsTECGeoMapper.cxx b/spdgeometry/tst/SpdTsTECGeoMapper.cxx
index fc5796e4210f7c2a734778d0457950f39ed5f912..b1e1866ae2467feafed76f1bf5b36e194e0b3215 100644
--- a/spdgeometry/tst/SpdTsTECGeoMapper.cxx
+++ b/spdgeometry/tst/SpdTsTECGeoMapper.cxx
@@ -192,8 +192,13 @@ void SpdTsTECGeoMapper::UnsetMaterials(Bool_t precise, TString option)
    if (fLockGeometry) {
        cout << "-E- <SpdTsTECGeoMapper::UnsetMaterials> Geometry is locked " << endl;
        return;
-   }
-   (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuum";
+   }      
+   
+        if (option.IsWhitespace()) { fUnsetMedia = "vacuumX2"; }
+   else if (option == "base")      { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX2"; }
+   else if (option == "vacuum")    { (precise) ? fUnsetMedia = "vacuum2" : fUnsetMedia = "vacuumX2"; }
+   else if (option == "air")       { fUnsetMedia = "airX2";    } 
+   else                            { fUnsetMedia = option;     }
 }
 
 //_____________________________________________________________________________
@@ -1698,9 +1703,22 @@ void SpdTsTECGeoMapper::SetGeometryPars(Int_t g)
      AddBackwardModule(8,0,0);
      AddBackwardModule(8,0,0);
 
+     RecalculateDistance();
+   }  
+   if (g == 2) 
+   {           
+     SetParameters(7,1,1);
+     SetParameters(8,2,1);
+     
+     AddForwardModule(7,0,0);
+     AddForwardModule(7,0,0);
+     
+     AddBackwardModule(8,0,0);
+     AddBackwardModule(8,0,0);
+
      RecalculateDistance();
    }
-   else if (g == 2) 
+   else if (g == 3) 
    {     
      SetDefaultModulePars(1,1,-1); // set module length < 0
      SetDefaultModulePars(2,1,-1); // set module length < 0
@@ -1711,7 +1729,7 @@ void SpdTsTECGeoMapper::SetGeometryPars(Int_t g)
      AddForwardModule(1,0,0);
      AddBackwardModule(2,0,0);
    }
-   else if (g == 3) 
+   else if (g == 4) 
    {      
      SetDefaultModulePars( 9, 1, 24); // set number of layers = 24
      SetDefaultModulePars(10, 1, 24); // set number of layers = 24
@@ -1722,7 +1740,7 @@ void SpdTsTECGeoMapper::SetGeometryPars(Int_t g)
      AddIdentModules( 1,  9, 3);
      AddIdentModules(-1, 10, 3);
    }
-   else if (g == 4) 
+   else if (g == 5) 
    {      
      SetParameters(5);
      SetParameters(6);
diff --git a/spdgeometry/tst/SpdTsTECGeoMapper.h b/spdgeometry/tst/SpdTsTECGeoMapper.h
index bb1ea3fd0ce832782a338665d2c065819e074dc3..c9206eedd53b3c44d00b4d585586b986190ab2ee 100644
--- a/spdgeometry/tst/SpdTsTECGeoMapper.h
+++ b/spdgeometry/tst/SpdTsTECGeoMapper.h
@@ -34,7 +34,7 @@ public:
     
     virtual Bool_t InitGeometry(Int_t gtype = -1, Bool_t reinit = kFALSE);
     
-    virtual void UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
+    virtual void   UnsetMaterials(Bool_t precise = kTRUE, TString option = "base");
    
     virtual Bool_t IsGeoTypeDefined(Int_t gtype) const;
      
diff --git a/spdroot.py b/spdroot.py
new file mode 100755
index 0000000000000000000000000000000000000000..66708e3f82b0e849c2ee643d4ee137948bbc6098
--- /dev/null
+++ b/spdroot.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+import sys
+import os
+
+var = os.environ['VMCWORKDIR']
+
+rootlogon = var+"/macro/rootlogon.C"
+rootlogoff = var+"/macro/rootlogoff.C"
+
+os.system("root -l -q -b " + " " + rootlogon + " " + sys.argv[1] + " " + rootlogoff)
diff --git a/tst/barrel/SpdTsTB.cxx b/tst/barrel/SpdTsTB.cxx
index 82a761b6ef4d1d05d25a8f006a8932cc74a32904..6ace7988f101addf738405f85d46647606f369c4 100644
--- a/tst/barrel/SpdTsTB.cxx
+++ b/tst/barrel/SpdTsTB.cxx
@@ -114,7 +114,9 @@ void SpdTsTB::Initialize()
 //_____________________________________________________________________________________
 void SpdTsTB::Reset()
 {
+  //Int_t nt = fPointCollection->GetEntriesFast();
   if (fPointCollection) fPointCollection->Clear();
+  //cout << "<SpdTsTB::Reset> " << nt << ", " << fPointCollection->GetEntriesFast() << endl;
 }
 
 //_____________________________________________________________________________________
@@ -326,11 +328,7 @@ Bool_t SpdTsTB::LoadParsFrom(SpdParSet* params)
 //_____________________________________________________________________________________
 TString SpdTsTB::GetDataOut(Int_t n) const 
 { 
-    cout << "<SpdTsTB::GetDataOut> " << n << endl;
-  if (n < 0 || n >= fNDataOut) {
-      return "unknown";
-  }
-   cout << "<SpdTsTB::GetDataOut> " << n << " object: " << fOutDataPointObject << endl;
+  if (n < 0 || n >= fNDataOut) return "unknown";
   return fOutDataPointObject;
 }
 
diff --git a/tst/ecps/SpdTsTEC.cxx b/tst/ecps/SpdTsTEC.cxx
index 0f409acaa0d2b8f892bc8ddd443ca8a6964f4adb..4b37a70272da6cef78ecec55eaf2949b1da5d761 100644
--- a/tst/ecps/SpdTsTEC.cxx
+++ b/tst/ecps/SpdTsTEC.cxx
@@ -102,7 +102,7 @@ void SpdTsTEC::Initialize()
   cout << "*******************************************************************************\n" << endl;
  
   // data collections
-  fPointCollection = new TClonesArray(fOutDataPointObject);
+  fPointCollection = new TClonesArray(fOutDataPointObject,10000);
   
   // Initialize module and fill parameters
   SpdDetector::Initialize(); 
@@ -114,7 +114,9 @@ void SpdTsTEC::Initialize()
 //_____________________________________________________________________________________
 void SpdTsTEC::Reset()
 {
+  //Int_t nt = fPointCollection->GetEntriesFast();
   if (fPointCollection) fPointCollection->Clear();
+  //cout << "<SpdTsTEC::Reset> " << nt << ", " << fPointCollection->GetEntriesFast() << endl;
 }
 
 //_____________________________________________________________________________________