From 7969203b2b86147569e7c6b70e9ee55183c4d630 Mon Sep 17 00:00:00 2001 From: Chengdong Fu <fucd@ihep.ac.cn> Date: Tue, 18 Aug 2020 16:30:31 +0800 Subject: [PATCH] first import from ILCSoft & merge KiTrack and KiTrackMarlin --- Utilities/KiTrack/CMakeLists.txt | 21 + Utilities/KiTrack/Criteria/Criteria.h | 110 ++++ Utilities/KiTrack/Criteria/ICriterion.h | 68 ++ Utilities/KiTrack/ILDImpl/FTDHit01.h | 21 + Utilities/KiTrack/ILDImpl/FTDHitSimple.h | 45 ++ .../KiTrack/ILDImpl/FTDNeighborPetalSecCon.h | 46 ++ .../KiTrack/ILDImpl/FTDSectorConnector.h | 55 ++ Utilities/KiTrack/ILDImpl/FTDTrack.h | 71 +++ Utilities/KiTrack/ILDImpl/IFTDHit.h | 49 ++ Utilities/KiTrack/ILDImpl/SectorSystemFTD.h | 93 +++ Utilities/KiTrack/ILDImpl/SectorSystemVXD.h | 89 +++ Utilities/KiTrack/ILDImpl/VXDHitSimple.h | 44 ++ Utilities/KiTrack/KiTrack/Automaton.h | 215 +++++++ Utilities/KiTrack/KiTrack/HopfieldNeuralNet.h | 129 ++++ Utilities/KiTrack/KiTrack/IHit.h | 89 +++ Utilities/KiTrack/KiTrack/ISectorConnector.h | 40 ++ Utilities/KiTrack/KiTrack/ISectorSystem.h | 56 ++ Utilities/KiTrack/KiTrack/ITrack.h | 47 ++ Utilities/KiTrack/KiTrack/KiTrackExceptions.h | 105 +++ Utilities/KiTrack/KiTrack/Segment.h | 99 +++ Utilities/KiTrack/KiTrack/SegmentBuilder.h | 94 +++ Utilities/KiTrack/KiTrack/Subset.h | 58 ++ Utilities/KiTrack/KiTrack/SubsetHopfieldNN.h | 399 ++++++++++++ Utilities/KiTrack/KiTrack/SubsetSimple.h | 186 ++++++ Utilities/KiTrack/Tools/FTDHelixFitter.h | 65 ++ Utilities/KiTrack/Tools/Fitter.h | 129 ++++ Utilities/KiTrack/Tools/KiTrackMarlinTools.h | 97 +++ .../KiTrack/src/Criteria/Crit2_DeltaPhi.cc | 84 +++ .../KiTrack/src/Criteria/Crit2_DeltaPhi.h | 38 ++ .../KiTrack/src/Criteria/Crit2_DeltaPhi_MV.cc | 78 +++ .../KiTrack/src/Criteria/Crit2_DeltaPhi_MV.h | 38 ++ .../KiTrack/src/Criteria/Crit2_DeltaRho.cc | 81 +++ .../KiTrack/src/Criteria/Crit2_DeltaRho.h | 36 ++ .../src/Criteria/Crit2_DeltaTheta_MV.cc | 84 +++ .../src/Criteria/Crit2_DeltaTheta_MV.h | 38 ++ .../KiTrack/src/Criteria/Crit2_Distance_MV.cc | 74 +++ .../KiTrack/src/Criteria/Crit2_Distance_MV.h | 38 ++ .../KiTrack/src/Criteria/Crit2_HelixWithIP.cc | 125 ++++ .../KiTrack/src/Criteria/Crit2_HelixWithIP.h | 43 ++ .../KiTrack/src/Criteria/Crit2_RZRatio.cc | 82 +++ .../KiTrack/src/Criteria/Crit2_RZRatio.h | 35 + .../src/Criteria/Crit2_StraightTrackRatio.cc | 90 +++ .../src/Criteria/Crit2_StraightTrackRatio.h | 41 ++ .../KiTrack/src/Criteria/Crit3_2DAngle.cc | 121 ++++ .../KiTrack/src/Criteria/Crit3_2DAngle.h | 36 ++ .../src/Criteria/Crit3_2DAngleTimesR.cc | 134 ++++ .../src/Criteria/Crit3_2DAngleTimesR.h | 36 ++ .../KiTrack/src/Criteria/Crit3_3DAngle.cc | 124 ++++ .../KiTrack/src/Criteria/Crit3_3DAngle.h | 36 ++ .../src/Criteria/Crit3_3DAngleTimesR.cc | 136 ++++ .../src/Criteria/Crit3_3DAngleTimesR.h | 36 ++ .../src/Criteria/Crit3_ChangeRZRatio.cc | 91 +++ .../src/Criteria/Crit3_ChangeRZRatio.h | 48 ++ .../src/Criteria/Crit3_IPCircleDist.cc | 90 +++ .../KiTrack/src/Criteria/Crit3_IPCircleDist.h | 47 ++ .../src/Criteria/Crit3_IPCircleDistTimesR.cc | 90 +++ .../src/Criteria/Crit3_IPCircleDistTimesR.h | 40 ++ .../KiTrack/src/Criteria/Crit3_NoZigZag_MV.cc | 93 +++ .../KiTrack/src/Criteria/Crit3_NoZigZag_MV.h | 39 ++ Utilities/KiTrack/src/Criteria/Crit3_PT.cc | 99 +++ Utilities/KiTrack/src/Criteria/Crit3_PT.h | 48 ++ Utilities/KiTrack/src/Criteria/Crit3_PT_MV.cc | 99 +++ Utilities/KiTrack/src/Criteria/Crit3_PT_MV.h | 48 ++ .../src/Criteria/Crit4_2DAngleChange.cc | 101 +++ .../src/Criteria/Crit4_2DAngleChange.h | 35 + .../src/Criteria/Crit4_3DAngleChange.cc | 101 +++ .../src/Criteria/Crit4_3DAngleChange.h | 35 + .../src/Criteria/Crit4_3DAngleChangeNormed.cc | 124 ++++ .../src/Criteria/Crit4_3DAngleChangeNormed.h | 35 + .../src/Criteria/Crit4_DistOfCircleCenters.cc | 110 ++++ .../src/Criteria/Crit4_DistOfCircleCenters.h | 35 + .../src/Criteria/Crit4_DistToExtrapolation.cc | 119 ++++ .../src/Criteria/Crit4_DistToExtrapolation.h | 37 ++ .../KiTrack/src/Criteria/Crit4_NoZigZag.cc | 108 ++++ .../KiTrack/src/Criteria/Crit4_NoZigZag.h | 39 ++ .../src/Criteria/Crit4_PhiZRatioChange.cc | 120 ++++ .../src/Criteria/Crit4_PhiZRatioChange.h | 35 + .../KiTrack/src/Criteria/Crit4_RChange.cc | 97 +++ .../KiTrack/src/Criteria/Crit4_RChange.h | 35 + Utilities/KiTrack/src/Criteria/Criteria.cc | 278 ++++++++ .../KiTrack/src/Criteria/SimpleCircle.cc | 90 +++ Utilities/KiTrack/src/Criteria/SimpleCircle.h | 55 ++ Utilities/KiTrack/src/ILDImpl/#FTDTrack.cc# | 132 ++++ Utilities/KiTrack/src/ILDImpl/FTDHit01.cc | 44 ++ Utilities/KiTrack/src/ILDImpl/FTDHitSimple.cc | 30 + .../src/ILDImpl/FTDNeighborPetalSecCon.cc | 56 ++ .../KiTrack/src/ILDImpl/FTDSectorConnector.cc | 92 +++ Utilities/KiTrack/src/ILDImpl/FTDTrack.cc | 132 ++++ Utilities/KiTrack/src/ILDImpl/IMiniVector.h | 63 ++ Utilities/KiTrack/src/ILDImpl/IVXDHit.h | 53 ++ Utilities/KiTrack/src/ILDImpl/MiniVector.cc | 139 ++++ Utilities/KiTrack/src/ILDImpl/MiniVector.h | 67 ++ .../KiTrack/src/ILDImpl/MiniVectorHit01.cc | 59 ++ .../KiTrack/src/ILDImpl/MiniVectorHit01.h | 16 + .../KiTrack/src/ILDImpl/SectorSystemFTD.cc | 183 ++++++ .../KiTrack/src/ILDImpl/SectorSystemVXD.cc | 201 ++++++ Utilities/KiTrack/src/ILDImpl/VXDHit01.cc | 67 ++ Utilities/KiTrack/src/ILDImpl/VXDHit01.h | 23 + Utilities/KiTrack/src/ILDImpl/VXDHitSimple.cc | 29 + .../KiTrack/src/ILDImpl/VXDSectorConnector.cc | 100 +++ .../KiTrack/src/ILDImpl/VXDSectorConnector.h | 51 ++ Utilities/KiTrack/src/ILDImpl/VXDTrack.cc | 201 ++++++ Utilities/KiTrack/src/ILDImpl/VXDTrack.h | 89 +++ Utilities/KiTrack/src/KiTrack/Automaton.cc | 498 +++++++++++++++ .../KiTrack/src/KiTrack/HopfieldNeuralNet.cc | 217 +++++++ Utilities/KiTrack/src/KiTrack/IHit.cc | 28 + Utilities/KiTrack/src/KiTrack/Segment.cc | 67 ++ .../KiTrack/src/KiTrack/SegmentBuilder.cc | 117 ++++ Utilities/KiTrack/src/Tools/FTDHelixFitter.cc | 124 ++++ Utilities/KiTrack/src/Tools/Fitter.cc | 598 ++++++++++++++++++ .../src/Tools/KiTrackMarlinCEDTools.cc.bak | 122 ++++ .../KiTrack/src/Tools/KiTrackMarlinCEDTools.h | 31 + .../KiTrack/src/Tools/KiTrackMarlinTools.cc | 262 ++++++++ Utilities/KiTrack/src/Tools/Timer.cc | 127 ++++ Utilities/KiTrack/src/Tools/Timer.h | 22 + .../KiTrack/src/Tools/VXDHelixFitter.cc.bak | 190 ++++++ Utilities/KiTrack/src/Tools/VXDHelixFitter.h | 82 +++ 117 files changed, 10917 insertions(+) create mode 100644 Utilities/KiTrack/CMakeLists.txt create mode 100644 Utilities/KiTrack/Criteria/Criteria.h create mode 100644 Utilities/KiTrack/Criteria/ICriterion.h create mode 100644 Utilities/KiTrack/ILDImpl/FTDHit01.h create mode 100644 Utilities/KiTrack/ILDImpl/FTDHitSimple.h create mode 100644 Utilities/KiTrack/ILDImpl/FTDNeighborPetalSecCon.h create mode 100644 Utilities/KiTrack/ILDImpl/FTDSectorConnector.h create mode 100644 Utilities/KiTrack/ILDImpl/FTDTrack.h create mode 100644 Utilities/KiTrack/ILDImpl/IFTDHit.h create mode 100644 Utilities/KiTrack/ILDImpl/SectorSystemFTD.h create mode 100644 Utilities/KiTrack/ILDImpl/SectorSystemVXD.h create mode 100644 Utilities/KiTrack/ILDImpl/VXDHitSimple.h create mode 100644 Utilities/KiTrack/KiTrack/Automaton.h create mode 100644 Utilities/KiTrack/KiTrack/HopfieldNeuralNet.h create mode 100644 Utilities/KiTrack/KiTrack/IHit.h create mode 100644 Utilities/KiTrack/KiTrack/ISectorConnector.h create mode 100644 Utilities/KiTrack/KiTrack/ISectorSystem.h create mode 100644 Utilities/KiTrack/KiTrack/ITrack.h create mode 100644 Utilities/KiTrack/KiTrack/KiTrackExceptions.h create mode 100644 Utilities/KiTrack/KiTrack/Segment.h create mode 100644 Utilities/KiTrack/KiTrack/SegmentBuilder.h create mode 100644 Utilities/KiTrack/KiTrack/Subset.h create mode 100644 Utilities/KiTrack/KiTrack/SubsetHopfieldNN.h create mode 100644 Utilities/KiTrack/KiTrack/SubsetSimple.h create mode 100644 Utilities/KiTrack/Tools/FTDHelixFitter.h create mode 100644 Utilities/KiTrack/Tools/Fitter.h create mode 100644 Utilities/KiTrack/Tools/KiTrackMarlinTools.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_RZRatio.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_RZRatio.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_2DAngle.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_2DAngle.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_3DAngle.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_3DAngle.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_PT.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_PT.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_PT_MV.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit3_PT_MV.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.h create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_RChange.cc create mode 100644 Utilities/KiTrack/src/Criteria/Crit4_RChange.h create mode 100644 Utilities/KiTrack/src/Criteria/Criteria.cc create mode 100644 Utilities/KiTrack/src/Criteria/SimpleCircle.cc create mode 100644 Utilities/KiTrack/src/Criteria/SimpleCircle.h create mode 100644 Utilities/KiTrack/src/ILDImpl/#FTDTrack.cc# create mode 100644 Utilities/KiTrack/src/ILDImpl/FTDHit01.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/FTDHitSimple.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/FTDNeighborPetalSecCon.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/FTDSectorConnector.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/FTDTrack.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/IMiniVector.h create mode 100644 Utilities/KiTrack/src/ILDImpl/IVXDHit.h create mode 100644 Utilities/KiTrack/src/ILDImpl/MiniVector.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/MiniVector.h create mode 100644 Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.h create mode 100644 Utilities/KiTrack/src/ILDImpl/SectorSystemFTD.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/SectorSystemVXD.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDHit01.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDHit01.h create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDHitSimple.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.h create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDTrack.cc create mode 100644 Utilities/KiTrack/src/ILDImpl/VXDTrack.h create mode 100644 Utilities/KiTrack/src/KiTrack/Automaton.cc create mode 100644 Utilities/KiTrack/src/KiTrack/HopfieldNeuralNet.cc create mode 100644 Utilities/KiTrack/src/KiTrack/IHit.cc create mode 100644 Utilities/KiTrack/src/KiTrack/Segment.cc create mode 100644 Utilities/KiTrack/src/KiTrack/SegmentBuilder.cc create mode 100644 Utilities/KiTrack/src/Tools/FTDHelixFitter.cc create mode 100644 Utilities/KiTrack/src/Tools/Fitter.cc create mode 100644 Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.cc.bak create mode 100644 Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.h create mode 100644 Utilities/KiTrack/src/Tools/KiTrackMarlinTools.cc create mode 100644 Utilities/KiTrack/src/Tools/Timer.cc create mode 100644 Utilities/KiTrack/src/Tools/Timer.h create mode 100644 Utilities/KiTrack/src/Tools/VXDHelixFitter.cc.bak create mode 100644 Utilities/KiTrack/src/Tools/VXDHelixFitter.h diff --git a/Utilities/KiTrack/CMakeLists.txt b/Utilities/KiTrack/CMakeLists.txt new file mode 100644 index 00000000..ba301e6f --- /dev/null +++ b/Utilities/KiTrack/CMakeLists.txt @@ -0,0 +1,21 @@ +gaudi_subdir(KiTrack v0r0) + +find_package(ROOT REQUIRED) +find_package(CLHEP REQUIRED) +#find_package(DD4hep REQUIRED) +find_package(GSL REQUIRED) +find_package(EDM4HEP REQUIRED) +find_package(LCIO REQUIRED) + +gaudi_depends_on_subdirs(Service/TrackSystemSvc Utilities/DataHelper) + +set(KiTrackLib_srcs src/KiTrack/*.cc src/Criteria/*.cc src/ILDImpl/*.cc src/Tools/*.cc) + +#gaudi_install_headers(src) +include_directories(src) + +gaudi_add_library(KiTrackLib ${KiTrackLib_srcs} + PUBLIC_HEADERS KiTrack + LINK_LIBRARIES DataHelperLib TrackSystemSvcLib ROOT CLHEP GSL EDM4HEP::edm4hep LCIO + # DD4hep +) diff --git a/Utilities/KiTrack/Criteria/Criteria.h b/Utilities/KiTrack/Criteria/Criteria.h new file mode 100644 index 00000000..b0ec231b --- /dev/null +++ b/Utilities/KiTrack/Criteria/Criteria.h @@ -0,0 +1,110 @@ +#ifndef Criteria_h +#define Criteria_h +/* +#include "Criteria/Crit2_RZRatio.h" +#include "Criteria/Crit2_StraightTrackRatio.h" +#include "Criteria/Crit2_DeltaPhi.h" +#include "Criteria/Crit2_HelixWithIP.h" +#include "Criteria/Crit2_DeltaRho.h" + +#include "Criteria/Crit3_ChangeRZRatio.h" +#include "Criteria/Crit3_PT.h" +#include "Criteria/Crit3_2DAngle.h" +#include "Criteria/Crit3_2DAngleTimesR.h" +#include "Criteria/Crit3_3DAngle.h" +#include "Criteria/Crit3_3DAngleTimesR.h" +#include "Criteria/Crit3_IPCircleDist.h" +#include "Criteria/Crit3_IPCircleDistTimesR.h" + +#include "Criteria/Crit4_2DAngleChange.h" +#include "Criteria/Crit4_3DAngleChange.h" +#include "Criteria/Crit4_3DAngleChangeNormed.h" +#include "Criteria/Crit4_DistToExtrapolation.h" +#include "Criteria/Crit4_PhiZRatioChange.h" +#include "Criteria/Crit4_DistOfCircleCenters.h" +#include "Criteria/Crit4_NoZigZag.h" +#include "Criteria/Crit4_RChange.h" + +// Criteria for Mini - Vector based Cellular Automaton for VXD +#include "Criteria/Crit2_DeltaPhi_MV.h" +#include "Criteria/Crit2_Distance_MV.h" +#include "Criteria/Crit2_DeltaTheta_MV.h" +#include "Criteria/Crit3_NoZigZag_MV.h" +#include "Criteria/Crit3_PT_MV.h" +*/ + +#include <vector> +#include <set> +#include <string> + +namespace KiTrack{ + class ICriterion; + /* + * Information about all Criteria. + * + * For example bundles the includes. + * + * Author: Robin Glattauer, HEPHY + */ + class Criteria { + + + + public: + + /** @return a vector of strings that represent all types of criteria stored. + * For example: "2Hit" or "3Hit" or "4Hit" + */ + static std::set< std::string > getTypes(); + + + /** @return a vector of all Criteria of a certain type + * + * @param type the type of Criteria, that is wanted (e.g. "2Hit") + */ + static std::set< std::string > getCriteriaNames( std::string type ); + + /** @return the names of all Criteria in a set + */ + static std::set< std::string > getAllCriteriaNames(); + + /** A convenience method to get all the criteria in a vector (gives the same result as getAllCriteriaNames, but + * instead of a set, returns it as a vector) + * + * @return the names of all Criteria in a vector + */ + static std::vector< std::string > getAllCriteriaNamesVec(); + + + /** + * Creates a Criterion with the name and the min and max values + * + * @return a "new" Criterion (i.e. needs to be deleted later on) + */ + static ICriterion* createCriterion( std::string critName , float min=0. , float max=0. ) ; + + /** + * Sets values for the passed referneced floats left and right. They indicate how + * the specified criterion should be cut, if necessary. Say you want for example + * a 99% quantile, so that 99% of your true tracks are within it. + * A criterion like the angle between two segments then needs to define a boarder like: + * between an angle of 1° and of 9° there will be 99%. + * So 1% is outside. But should 1% be the ones with a bigger angle or with a smaller angle or should + * this be 50:50? + * + * This is defined by left and right. Left is the proportion, that is taken away on the left side and + * right is the one that is taken away on the right side. + * In the case of an angle we will most probably have lots around 0° and a long tail to the right, so + * left = 0 and right = 1 seems like a good idea. + * Standard is of course 0.5 and 0.5 + */ + static void getLeftRight( std::string critName, float & left, float & right ); + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/Criteria/ICriterion.h b/Utilities/KiTrack/Criteria/ICriterion.h new file mode 100644 index 00000000..1ff8f950 --- /dev/null +++ b/Utilities/KiTrack/Criteria/ICriterion.h @@ -0,0 +1,68 @@ +#ifndef ICriterion_h +#define ICriterion_h + +#include <vector> +#include <map> +#include <string> + +#include "KiTrack/Segment.h" +#include "KiTrack/KiTrackExceptions.h" + + + +namespace KiTrack{ + + + /** An Interface for Criteria. + * + * A Criterion is a class, that is able to take two Segments and check whether they are compatible or not. + */ + class ICriterion{ + + + public: + + /** @return If the two Segments are compatible with each other, i.e. could be combined to a longer Segment or a + * track. + */ + virtual bool areCompatible( Segment* parent , Segment* child ) = 0; + + + /** @return A map, where the calculated values are stored. The keys are the names of the values. + */ + std::map < std::string , float > getMapOfValues() {return _map_name_value; }; + + + virtual ~ICriterion(){}; + + /** Sets, whether the calculated values shall be saved in a map + */ + void setSaveValues( bool saveValues ){ _saveValues = saveValues;} + + + /** @return the name of the criterion */ + std::string getName(){return _name;} + + /** @return the type of the criterion */ + std::string getType(){return _type;} + + protected: + + + std::map < std::string , float > _map_name_value{}; + + bool _saveValues{}; + + std::string _name{}; + std::string _type{}; + + }; + +} + + +#endif + + + + diff --git a/Utilities/KiTrack/ILDImpl/FTDHit01.h b/Utilities/KiTrack/ILDImpl/FTDHit01.h new file mode 100644 index 00000000..6750231e --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/FTDHit01.h @@ -0,0 +1,21 @@ +#ifndef FTDHit01_h +#define FTDHit01_h + +#include "ILDImpl/IFTDHit.h" + +namespace KiTrackMarlin{ + /** A class for hits in the FTD (the 01 is just for historical reasons and may be renamed) + * + * - The side is according to CellID0. + * - Layer is set according to CellID0 +1 (so we can use layer 0 for the IP) + * - Module is set according to CellID0. + * - Sensor is set according to CellID0 -1. (because currently sensors of the FTD start with 1 in the CellID0, if this changes, this has to be modified) + */ + class FTDHit01 : public IFTDHit{ + public: + + FTDHit01( edm4hep::TrackerHit trackerHit , const SectorSystemFTD* const sectorSystemFTD ); + }; +} +#endif + diff --git a/Utilities/KiTrack/ILDImpl/FTDHitSimple.h b/Utilities/KiTrack/ILDImpl/FTDHitSimple.h new file mode 100644 index 00000000..36219730 --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/FTDHitSimple.h @@ -0,0 +1,45 @@ +#ifndef FTDHitSimple_h +#define FTDHitSimple_h + +#include "KiTrack/IHit.h" + +#include "ILDImpl/SectorSystemFTD.h" + + + +namespace KiTrackMarlin{ + + + /** A hit + */ + class FTDHitSimple : public IHit{ + + + public: + + FTDHitSimple( float x , float y , float z , int side, unsigned layer , unsigned module, unsigned sensor, const SectorSystemFTD* const sectorSystemFTD ); + + + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemFTD; }; + + virtual ~FTDHitSimple(){} + + private: + + int _side; + unsigned _layer; + unsigned _module; + unsigned _sensor; + + const SectorSystemFTD* _sectorSystemFTD; + + void calculateSector(){ _sector = _sectorSystemFTD->getSector( _side, _layer , _module , _sensor ); } + + }; + +} + + +#endif + diff --git a/Utilities/KiTrack/ILDImpl/FTDNeighborPetalSecCon.h b/Utilities/KiTrack/ILDImpl/FTDNeighborPetalSecCon.h new file mode 100644 index 00000000..07bfced5 --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/FTDNeighborPetalSecCon.h @@ -0,0 +1,46 @@ +#ifndef FTDNeighborPetalSecCon_h +#define FTDNeighborPetalSecCon_h + +#include "KiTrack/ISectorConnector.h" + +#include "ILDImpl/SectorSystemFTD.h" + + + +namespace KiTrackMarlin{ + + /** Used to connect two sectors. + * + * Allows: + * + * - Connections to the neighbouring petals (the one to the left and the one to the right on the same layer and side) + * + */ + class FTDNeighborPetalSecCon : public ISectorConnector{ + + + public: + + /** + * + */ + FTDNeighborPetalSecCon ( const SectorSystemFTD* sectorSystemFTD ); + + virtual std::set <int> getTargetSectors ( int sector ); + + virtual ~FTDNeighborPetalSecCon(){}; + + private: + + const SectorSystemFTD* _sectorSystemFTD; + + + + }; + + +} + + +#endif + diff --git a/Utilities/KiTrack/ILDImpl/FTDSectorConnector.h b/Utilities/KiTrack/ILDImpl/FTDSectorConnector.h new file mode 100644 index 00000000..8aaf4bfd --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/FTDSectorConnector.h @@ -0,0 +1,55 @@ +#ifndef FTDSectorConnector_h +#define FTDSectorConnector_h + +#include "KiTrack/ISectorConnector.h" + +#include "ILDImpl/SectorSystemFTD.h" + + + +namespace KiTrackMarlin{ + + /** Used to connect two sectors on the FTD. + * + * + * Allows: + * + * - going to layers on the inside (how far see constructor) + * - going to same petal or petals around (how far see constructor) + * - jumping to the IP (from where see constructor) + */ + class FTDSectorConnector : public ISectorConnector{ + + + public: + + /** @param layerStepMax the maximum distance of the next layer on the inside + * + * @param petalStepMax the maximum distance of the next petal (in + and - direction ) + * + * @param lastLayerToIP the highest layer from where a direct jump to the IP is allowed + */ + FTDSectorConnector ( const SectorSystemFTD* sectorSystemFTD , unsigned layerStepMax , unsigned petalStepMax , unsigned lastLayerToIP); + + /** @return a set of all sectors that are connected to the passed sector */ + virtual std::set <int> getTargetSectors ( int sector ); + + virtual ~FTDSectorConnector(){}; + + private: + + const SectorSystemFTD* _sectorSystemFTD; + + unsigned _layerStepMax; + unsigned _petalStepMax; + unsigned _lastLayerToIP; + + + }; + + +} + + +#endif + diff --git a/Utilities/KiTrack/ILDImpl/FTDTrack.h b/Utilities/KiTrack/ILDImpl/FTDTrack.h new file mode 100644 index 00000000..3db4c908 --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/FTDTrack.h @@ -0,0 +1,71 @@ +#ifndef FTDTrack_h +#define FTDTrack_h + +//#include "IMPL/TrackImpl.h" +//#include "MarlinTrk/IMarlinTrkSystem.h" +//#include "MarlinTrk/IMarlinTrack.h" +#include "edm4hep/Track.h" +#include "TrackSystemSvc/IMarlinTrkSystem.h" + +#include <vector> + +#include "ILDImpl/IFTDHit.h" +#include "KiTrack/ITrack.h" + +#include "Tools/Fitter.h" + + +namespace KiTrackMarlin{ + /** A class for ITracks containing an lcio::Track at core + */ + class FTDTrack : public ITrack { + public: + /** @param trkSystem An IMarlinTrkSystem, which is needed for fitting of the tracks + */ + FTDTrack( MarlinTrk::IMarlinTrkSystem* trkSystem ); + + /** @param hits The hits the track consists of + * @param trkSystem An IMarlinTrkSystem, which is needed for fitting of the tracks + */ + FTDTrack( std::vector< IFTDHit* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ); + FTDTrack( const FTDTrack& f ); + FTDTrack & operator= (const FTDTrack & f); + + /** @return a track in the lcio format + */ + edm4hep::Track* getLcioTrack(){ return ( _lcioTrack );} + + void addHit( IFTDHit* hit ); + + virtual double getNdf() const { return _lcioTrack->getNdf(); } + virtual double getChi2() const { return _lcioTrack->getChi2(); } + virtual double getChi2Prob() const { return _chi2Prob; } + + virtual std::vector< IHit* > getHits() const { std::vector<IHit*> hits; + for(unsigned i=0; i<_hits.size();i++) hits.push_back( _hits[i] ); + return hits; } + + virtual double getQI() const; + + /** Fits the track and sets chi2, Ndf etc. + */ + virtual void fit() ; + + virtual ~FTDTrack(){ delete _lcioTrack; } + + protected: + /** the hits the track consists of + */ + std::vector< IFTDHit* > _hits; + + edm4hep::Track* _lcioTrack; + + // for fitting + MarlinTrk::IMarlinTrkSystem* _trkSystem; + + double _chi2Prob; + }; +} +#endif + + diff --git a/Utilities/KiTrack/ILDImpl/IFTDHit.h b/Utilities/KiTrack/ILDImpl/IFTDHit.h new file mode 100644 index 00000000..33b817bf --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/IFTDHit.h @@ -0,0 +1,49 @@ +#ifndef IFTDHit_h +#define IFTDHit_h + + +#include "edm4hep/TrackerHit.h" + +#include "KiTrack/IHit.h" + +#include "ILDImpl/SectorSystemFTD.h" + +namespace KiTrackMarlin{ + /** An interface for a hit for the ILD using an lcio TrackerHit as basis. + * + * It comes along with a side, layer, module and a sensor. + */ + class IFTDHit : public IHit{ + public: + + edm4hep::TrackerHit* getTrackerHit() { return &_trackerHit; }; + + int getSide() { return _side; } + unsigned getModule() { return _module; } + unsigned getSensor() { return _sensor; } + + void setSide( int side ){ _side = side; calculateSector();} + void setLayer( unsigned layer ){ _layer = layer; calculateSector();} + void setModule( unsigned module ){ _module = module; calculateSector();} + void setSensor( unsigned sensor ){ _layer = sensor; calculateSector();} + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemFTD; }; + + protected: + + edm4hep::TrackerHit _trackerHit; + + int _side; + unsigned _layer; + unsigned _module; + unsigned _sensor; + + const SectorSystemFTD* _sectorSystemFTD; + + /** Calculates and sets the sector number + */ + void calculateSector(){ _sector = _sectorSystemFTD->getSector( _side, _layer , _module , _sensor ); } + }; +} +#endif + diff --git a/Utilities/KiTrack/ILDImpl/SectorSystemFTD.h b/Utilities/KiTrack/ILDImpl/SectorSystemFTD.h new file mode 100644 index 00000000..9f83b895 --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/SectorSystemFTD.h @@ -0,0 +1,93 @@ +#ifndef SectorSystemFTD_h +#define SectorSystemFTD_h + +#include "KiTrack/ISectorSystem.h" + +using namespace KiTrack; + +namespace KiTrackMarlin{ + + /** A Sector System class for the Forward Tracking Disks FTD in the ILD. + * + * It calculates sectors from the side, layer, sensor and module and vice versa. + * + * @param side: +1 for forward, -1 for backward + * + * @param layer: layer of FTD: 0 is the layer of the IP, 1 is the first FTD disk and so on. + * + * @param module: module + * + * @param sensor: the sensor on the module + * + * + */ + class SectorSystemFTD : public ISectorSystem{ + + + public: + + /**Constructor + * + * @param nLayers the number of possible layers. The layers from 0 to n-1 will be available. Keep in mind, + * that layer 0 is used for the IP. + * + * @param nModules the number of modules per disk. + * + * @param nSensors the number of sensors on one module. + */ + SectorSystemFTD( unsigned nLayers , unsigned nModules , unsigned nSensors ); + + + /** Calculates the sector number corresponding to the passed parameters + */ + int getSector( int side, unsigned layer , unsigned module , unsigned sensor ) const ; + + + /** Virtual, because this method is demanded by the Interface ISectorSystem + * + * @return the layer corresponding to the passed sector number + */ + virtual unsigned getLayer( int sector ) const ; + + + /** @return some information on the sector as string */ + virtual std::string getInfoOnSector( int sector ) const; + + /** @return the side the sector is on (+1 = forward, -1 = backward) + */ + int getSide( int sector ) const ; + + /** @return the module of the sector + */ + unsigned getModule( int sector ) const ; + + /** @return the sensor of the sector + */ + unsigned getSensor( int sector ) const ; + + + + unsigned getNumberOfModules() const { return _nModules; } + unsigned getNumberOfSensors() const { return _nSensors; } + + virtual ~SectorSystemFTD(){} + + private: + + unsigned _nModules; + unsigned _nSensors; + + int _sectorMax; + + void checkSectorIsInRange( int sector ) const ; + + }; + + + +} + + +#endif + + diff --git a/Utilities/KiTrack/ILDImpl/SectorSystemVXD.h b/Utilities/KiTrack/ILDImpl/SectorSystemVXD.h new file mode 100644 index 00000000..6852f63a --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/SectorSystemVXD.h @@ -0,0 +1,89 @@ +#ifndef SectorSystemVXD_h +#define SectorSystemVXD_h + +#include "KiTrack/ISectorSystem.h" + +#include <vector> + +using namespace KiTrack; + +namespace KiTrackMarlin{ + + /** A Sector System class for the Forward Tracking Disks FTD in the ILD. + * + * It calculates sectors from the side, layer, sensor and module and vice versa. + * + * @param side: +1 for forward, -1 for backward + * + * @param layer: layer of FTD: 0 is the layer of the IP, 1 is the first FTD disk and so on. + * + * @param module: module + * + * @param sensor: the sensor on the module + * + * + */ + class SectorSystemVXD : public ISectorSystem{ + + + public: + + /**Constructor + * + * @param nLayers the number of possible layers. The layers from 0 to n-1 will be available. Keep in mind, + * that layer 0 is used for the IP. + * + * @param nModules the number of modules per disk. + * + * @param nSensors the number of sensors on one module. + */ + SectorSystemVXD( unsigned nLayers , unsigned nDivisionsInPhi , unsigned nDivisionsInTheta ); + + + /** Virtual, because this method is demanded by the Interface ISectorSystem + * + * @return the layer corresponding to the passed sector number + */ + virtual unsigned getLayer( int sector ) const ; + + virtual unsigned getPhi( int sector ) const ; + + virtual unsigned getTheta( int sector ) const ; + + /** @return some information on the sector as string */ + virtual std::string getInfoOnSector( int sector) const; + + + /** Calculates the sector number corresponding to the passed parameters + */ + int getSector( int layer, int phi, int theta ) const ; + + int getSector( int layer, double phi, double cosTheta ) const ; + + unsigned getPhiSectors() const ; + + unsigned getThetaSectors() const ; + + unsigned getNLayers() const ; + + virtual ~SectorSystemVXD(){} + + private: + + int _sectorMax; + unsigned _nLayers; + unsigned _nDivisionsInPhi ; + unsigned _nDivisionsInTheta ; + + void checkSectorIsInRange( int sector ) const ; + + }; + + + +} + + +#endif + + diff --git a/Utilities/KiTrack/ILDImpl/VXDHitSimple.h b/Utilities/KiTrack/ILDImpl/VXDHitSimple.h new file mode 100644 index 00000000..fc464eef --- /dev/null +++ b/Utilities/KiTrack/ILDImpl/VXDHitSimple.h @@ -0,0 +1,44 @@ +#ifndef VXDHitSimple_h +#define VXDHitSimple_h + +#include "KiTrack/IHit.h" + +#include "ILDImpl/SectorSystemVXD.h" + + + +namespace KiTrackMarlin{ + + + /** A hit + */ + class VXDHitSimple : public IHit{ + + + public: + + VXDHitSimple( float x , float y , float z , int layer , int phi, int theta, const SectorSystemVXD* const sectorSystemVXD ); + + + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemVXD; }; + + virtual ~VXDHitSimple(){} + + private: + + int _layer; + int _phi; + int _theta; + + const SectorSystemVXD* _sectorSystemVXD; + + //void calculateSector(){ _sector = _sectorSystemVXD->getSector( _side, _layer , _module , _sensor ); } + + }; + +} + + +#endif + diff --git a/Utilities/KiTrack/KiTrack/Automaton.h b/Utilities/KiTrack/KiTrack/Automaton.h new file mode 100644 index 00000000..249aa354 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/Automaton.h @@ -0,0 +1,215 @@ +#ifndef Automaton_h +#define Automaton_h + +#include <vector> +#include "KiTrack/Segment.h" +#include "Criteria/ICriterion.h" + + + +namespace KiTrack{ + + + /** A class for the cellular automaton. + * + * For detailed info on the Cellular Automaton and its use for track reconstruction see + * <a href="../CellularAutomaton.pdf">Introduction to the Cellular Automaton</a> + * + * <h3>About the class </h3> + * + * This Cellular Automaton is specifically designed for track reconstruction, so it differs in the functionality + * from other Cellular Automata, like those used for simulation of biological cells. + * + * The basic information on how the CA works and what it needs is describet in the pdf above. Here I'll only sum up + * the basics of this class. + * + * The cells the Cellular Automaton deals with are here called segments as we deal with track reconstruction. + * These are the main information entities the CA deals with and therefore the most important member variable is + * a container of these segments. (For more details on the segments see the doxygen of the Segment class) + * To sum it up: Segments consist of hits. So they are a bit like tracks. Or if they only consist of one single hit + * (so called 1-hit-segments) then they are like hits. + * But there a few features that distinguish them from hits or tracks + * - They can have parents and children. These are simply segments on top or below them. The idea is, that all + * segments on the inside are stored as children if they could belong to the same track. And the same for all segments + * on the outside possible belonging to the same track (the parents). So if we start at a segment and go to a child + * and on to a grandchild and so on, we follow a possible track. If we erase those connections we decrease the number + * of possible tracks. + * - Segments must have a layer marking where it is. (layer 0: inside, higher layers further outside). This is a + * feature needed by the Automaton. Because it is an algorithm with discrete entities, we need some sort of discrete + * ordering. (If we for example had a Cellular Automaton for simulation of 2 dimensional cells and we arranged the + * cells for example on a chessboard, we always know the next cells. Here we have a 1 dimensional situation so we use + * layers) + * - Segments have states: this is simply an integer number (an unsigned to be more precise). It is needed by the + * Automaton to find connections that go all the way through (see pdf!) + * + * The Segments can be added via the addSegment() method and are stored layerwise. + * + * Once the Segments are all stored in the Cellular Automaton it can perform. + * Via the method doAutomaton() it raises the states of the Segments until no change happens anymore. + * When this is done Segments not connected all the way through can be discarded by the method + * cleanBadStates(). This reduces the number of possible tracks. + * + * To get an initial Cellular Automaton to start with, the class SegmentBuilder can be used. + * (It takes hits builds segments from them and establishes the first parent-child relations) + * + * In order to sort out even more it is possible to go to longer segments. So instead of checking 1-hit-segments, + * we can have a look at 2-hit-segments or 3-hit-segments. (And sort out much more along the way) + * For this the method lengthenSegments() is used. It combines connected segments and creates segments from them, + * that are exactly one hit longer. And then it is again time for connecting them. + * (I distinguish here between connecting: "storing the link" and combining: "making 1 new segment out of two others") + * + * When segments are connected only connections that make sense are made. This is really important! If we don't make + * assumptions here, what Segments could belong together (i.e. could form a sensible track) we get lost in combinatorics. + * For this the so called Criteria are used. Via the method addCriterion() (or addCriteria() ) they can be added + * to the Cellular Automaton. All a Criterion does (see the Criterion doxygen for more info) is to say whether two + * Segments would give a good match. These criteria can be anything that makes sense in distinguishing between + * real tracks and combinatorial background. For example if the segments are already long enough (already little tracks) + * one can compare the radius of their helices or the angle under which they meet and so on. + * + * Once we have longer segments we can again use the doAutomaton() method and then cleanBadStates(). Then we lenghten + * them once more and so on. + * + * Between two such runs, one should of course clear the old Criteria with clearCriteria and reset the states of the + * Segments with resetStates(). + * + * That's it. In the end, when nothing more is to be done in the Cellular Automaton, we need to extract the track + * candidates, it found. This is done via the getTracks() method. + * + */ + class Automaton{ + + + + public: + + Automaton(): _nConnections(0){} + + /** + * delete all the segments + */ + ~Automaton(); + + + /** Adds a segment to the automaton.\ + * Take care to set the layer of the segment before adding! + */ + void addSegment ( Segment* segment ); + + /**Lengthens the segments by one via adding the first hit of the next segment it is connected to + * to it. + * Also connects those longer segments with each other. ( one becomes a parent and one a child ) + * Segments that don't have connected segments to use to get longer, will die here. + */ + void lengthenSegments(); + + /**Adds a criteria to the automaton. So it will be used, when the methods doAutomaton() + * or cleanBadConnections() are called. + */ + void addCriterion ( ICriterion* criterion ){ _criteria.push_back( criterion ); } + void addCriteria ( std::vector< ICriterion* > criteria ){ _criteria.insert( _criteria.end() , criteria.begin() , criteria.end() ); } + void clearCriteria() { _criteria.clear(); }; + + /** Does iteration until the states of the segments don't change anymore. + * + * In one iteration all segments are checked, if they have a neighbor. + * A neighbor: + * - has the same state + * - fulfills all the criteria (this is automatically provided, because in lengthenSegments only connections that fullfill the Criteria are made) + * + * If it has a neighbor its state will be raised by one at the end of the iteration. + * (At the end only in theory: in the program it will be during the iteration, but + * in a way, that it doesn't affect other segments) + * + * When after an iteration the states didn't change, it stops. + */ + void doAutomaton(); + + /** + * Erases all segments that don't have a state corresponding to their layer. + * + * After the automaton is performed every segment, that has a neighbor, that has a neighbor, that... + * ...that reaches layer 0 should have a state equal to its layer. All the others are not connected + * to layer 0. All those get deleted by this method. + * (Of course all the connections to them are erased as well) + */ + void cleanBadStates(); + + /** + * Erase alls connections between segments, that don't satisfy the criteria. + */ + void cleanBadConnections(); + + /**Resets all the states of the segmens to 0 by calling the resetState() method of the segment + * Also sets all segments back to active. + */ + void resetStates(); + + + + /** Get all the possible tracks in the automaton. + * + * Tracks are built by starting from segments which don't have a parent (and are therefore the begin of a track). + * For all children they have a new own track is created. The children themselves have children again, so the + * tracks split up again. + * If we have for example a segment with 3 children, which each have 5 children, which each have 7 children, + * we will get 1*3*5*7=105 tracks. + * + * @return All tracks that are possible with the given segments and their connections. Tracks are returned + * as a vector of hits. So the output will be a vector of a vector of hits + * + * @param minHits the minimum number of hits that a track needs to have. All possible tracks, + * that have less won't be considered as tracks and won't be returned. + * + */ + //std::vector < std::vector< IHit* > > getTracks( unsigned minHits = 3 ); + std::vector < std::vector< IHit* > > getTracks( unsigned minHits = 2 ); // YV, 2 mini-vector hits can form a track + + /**Returns all the tracks starting from this segment. + * It is a recursive method and gets invoked by getTracks. + */ + //std::vector < std::vector< IHit* > > getTracksOfSegment ( Segment* segment, std::vector< IHit* > hits , unsigned minHits = 3 ); + std::vector < std::vector< IHit* > > getTracksOfSegment ( Segment* segment, std::vector< IHit* > hits , unsigned minHits = 2 ); // YV, 2 mini-vector hits can form a track + + /** + * @return All the segments currently saved in the automaton + */ + std::vector <const Segment*> getSegments() const; + + unsigned getNumberOfConnections(){ return _nConnections; } + + private: + + /** Here the segments are stored. + * The vector corresponds to the layer. + * The list corresponds to the segments on the layer. + * _segments[2] is a list with all segments on layer 2. + * + * The segments will be deleted by the Automaton in the destructor + * + */ + std::vector < std::list < Segment* > > _segments{}; + + /** A vector containing all the criteria, that are used in the Automaton + */ + std::vector < ICriterion* > _criteria{}; + + unsigned _nConnections{}; + + + + }; + + + + + +} + + + + + + +#endif + + diff --git a/Utilities/KiTrack/KiTrack/HopfieldNeuralNet.h b/Utilities/KiTrack/KiTrack/HopfieldNeuralNet.h new file mode 100644 index 00000000..f1b22e46 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/HopfieldNeuralNet.h @@ -0,0 +1,129 @@ +#ifndef HopfieldNeuralNet_h +#define HopfieldNeuralNet_h + + +#include <vector> + +#include "KiTrackExceptions.h" + +namespace KiTrack{ + + /** + * Represents a Hopfield Neural Network + * + * See <a href="../SubsetHopfieldNN.pdf">this</a> for detailed info. + * + * Author: Robin Glattauer, HEPHY + */ + class HopfieldNeuralNet { + + + public: + + /** + * @param G A matrix of the correlations between the neurons. + * True means two neurons are incompatible. False means, they are + * compatible. (the diagonal elements are 0 by definition and any entry there will be ignored and set to 0) + * + * @param QI A vector containing the qualtity indicators of the neurons (i.e. their power to amplify or + * weaken other neurons). Quality should be indicated by a value between 0 and 1. 1 being the highest quality. + * + * @param states The states of the neurons. Should be between 0 and 1. + * + * @param omega Controls the influence of the quality indicator on the activation of the neuron. Needs to be + * between 0 and 1. 0 means, no influence from the quality of the neurons -> system tends to biggest compatible + * set. 1 means highest influence from the quality of the neurons -> the highest quality neurons tend to win. + */ + HopfieldNeuralNet( std::vector < std::vector <bool> > G , std::vector < double > QI , std::vector < double > states , double omega) ; + + + /** Does one iteration of the neuronal network. + * + * \f$ \vec{y} = W \times \vec{state} + \vec{w_0} \f$ + * + * \f$ \vec{state}_{new} = activationFunction(\vec{y}) \f$ + * + * @return Whether the Neural Network is considered as stable + */ + bool doIteration(); + + /** + * Sets the temperature of the Neural Network (The HNN is cooled down in every iteration) + */ + void setT (double T) { _T = T;}; + + /** + * Sets the temperature at infinity. The temperature will converge to this + * value after infinite iterations. + */ + void setTInf (double TInf) {_TInf = TInf;}; + + /** + * Set the threshhold value below which the HNN is seen as "stable". As long as any Neuron changes its state + * by a value bigger than this, the HNN is not considered stable. When all Neurons change their states so little, + * that none of the changes exceeds this threshold, then the HNN is stable. + */ + void setLimitForStable (double limit) { _limitForStable = limit; }; + + + /** @return the vector of the states + */ + std::vector <double> getStates(){ return _States; }; + + + + protected: + + + + /** the matrix of the weights*/ + std::vector < std::vector <double> > _W{}; + + /** states describing how active a neuron is*/ + std::vector < double > _States{}; + + + std::vector < double > _w0{}; + + /** temperature */ + double _T{}; + + /** temperature after infinite iterations */ + double _TInf{}; + + /** indicates if the neuronal network is stable. + * this is true when the change after one iteration + * of any neuron is not bigger than the value _limitForStable. + */ + bool _isStable{}; + + /** The upper limit for change of a neuron, if it should be considered stabel.*/ + double _limitForStable{}; + + /** Omega controls the influence of the quality indicator on the activation of the neuron. + */ + double _omega{}; + + /** the order of the neurons to be updated. So it should of course reach from 0 to the number of neurons -1. + * (4 , 2, 0 1, 3) will for example mean: update first the neuron 4, then the neuron 2, then 0 and so on + */ + std::vector <unsigned> _order{}; + + + /** Calculates the activation function + * + * @param state the state + * @param T the temperature + * @return the activation function corresponding to the input values: g(x) = 1/2* (1 + tanh( x/T )) + */ + double activationFunction ( double state , double T ); + + + }; + + +} + + +#endif + diff --git a/Utilities/KiTrack/KiTrack/IHit.h b/Utilities/KiTrack/KiTrack/IHit.h new file mode 100644 index 00000000..736c6d21 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/IHit.h @@ -0,0 +1,89 @@ +#ifndef IHit_h +#define IHit_h + +#include "KiTrack/ISectorSystem.h" + +namespace KiTrack{ + + + /** An Interface for hits. + * + * They have of course a position, accessible with getX(), getY() and getZ(). + * + * Also a hit has a sector. A sector is just an integer, telling where the hit lies. For example + * a sector 141 could mean 1st layer, 4th module, 1st sensor. But how information is encoded is dealt + * with in the SectorSystem classes (see ISectorSystem for the Abstract Base Class ). + */ + class IHit{ + + + public: + + /** @return the x position */ + float getX() const { return _x; } + + /** @return the y position */ + float getY() const { return _y; } + + /** @return the z position */ + float getZ() const { return _z; } + + /** @return the sector, where the hit lies n */ + int getSector() const { return _sector; } + + /** @return the used SectorSystem that encodes the sector of the hit*/ + virtual const ISectorSystem* getSectorSystem() const =0; + + /** @return the layer of the hit */ + unsigned getLayer() const {return getSectorSystem()->getLayer( _sector ); } + + /** @return whether the hit is virtual (not a real hit). */ + bool isVirtual() const { return _isVirtual; }; + void setIsVirtual( bool isVirtual ){ _isVirtual = isVirtual; }; + + /** @return the distance to an other hit */ + float distTo( IHit* otherHit ); + + /** @return a string containing the position of the hit */ + std::string getPositionInfo(); + + /** to be used with mini-vectors: @return 3D angle */ //YV + double get3DAngle( IHit* /*otherHit*/) const { return _3DAngle ; } + + /** to be used with mini-vectors: @return azimuth angle */ //YV + double getPhi() const { return _phiMV ; } + + /** to be used with mini-vectors: @return polar angle */ //YV + double getTheta() const { return _thetaMV ; } + + virtual ~IHit(){} + + protected: + + + float _x{}; + float _y{}; + float _z{}; + + double _3DAngle{}; //YV + double _phiMV{}; //YV + double _thetaMV{}; //YV + + int _sector{}; + + + bool _isVirtual{}; + + + }; + + + +} + + +#endif + + + + diff --git a/Utilities/KiTrack/KiTrack/ISectorConnector.h b/Utilities/KiTrack/KiTrack/ISectorConnector.h new file mode 100644 index 00000000..558ea888 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/ISectorConnector.h @@ -0,0 +1,40 @@ +#ifndef ISectorConnector_h +#define ISectorConnector_h + +#include <set> + + +namespace KiTrack{ + + + /** Abstract Base Class for SectorConnectors. + * + * A SectorConnector is pretty simple: you put in a sector (int) and get back a bunch of other sectors in a set. + * What it can be used for: Suppose you want to search for the path of a particle through a detector + * and you know what possible ways it can go, than you can create a SectorConnector to emulate that. + * So if you have a hit in sector 43 (whatever 43 means) and you think, that from there the particle will + * only go to either sector 46, 47 or 48, then you would write a SectorConnector that will return + * a set of 46,47,48 when the method getTargetSectors( 43 ) is called. + */ + class ISectorConnector{ + + + public: + + /** @return a set of sectors somehow linked to the passed one */ + virtual std::set <int> getTargetSectors ( int ) = 0; + + virtual ~ISectorConnector(){}; + + }; + + + +} + + + +#endif + + + diff --git a/Utilities/KiTrack/KiTrack/ISectorSystem.h b/Utilities/KiTrack/KiTrack/ISectorSystem.h new file mode 100644 index 00000000..a9b3d992 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/ISectorSystem.h @@ -0,0 +1,56 @@ +#ifndef ISectorSystem_h +#define ISectorSystem_h + +#include <string> + +#include "KiTrack/KiTrackExceptions.h" + +namespace KiTrack{ + + + /** An interface for Sector Systems. + * + * A sector is a code for a place. So it can for example equal a sensor somewhere in a detector or be something + * abstract like the IP. + * + * A sector system is able to take a sector (integer number) and give back information + * about it. This can be things like the number of the sensor or the rough distance from the IP or such + * things. Or even neighbouring sectors. + * But this is all dependent on the circumstances of the detectors and their representation. + * + * What all SectorSystems have in common is the layer: SectorSystems must be able to + * return the layer of a sector and how many layers there are all in all. + */ + class ISectorSystem{ + + + public: + + /** @return the layer of the corresponding sector. */ + virtual unsigned getLayer( int sector ) const =0; + + /** @return the number of layers in the sector system. */ + unsigned getNumberOfLayers() const { return _nLayers; }; + + /** @return some information on the sector as string */ + virtual std::string getInfoOnSector( int sector ) const = 0; + + virtual ~ISectorSystem(){} + + + + protected: + + + unsigned _nLayers{}; + + + + }; + + +} + + +#endif + diff --git a/Utilities/KiTrack/KiTrack/ITrack.h b/Utilities/KiTrack/KiTrack/ITrack.h new file mode 100644 index 00000000..50d7e895 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/ITrack.h @@ -0,0 +1,47 @@ +#ifndef ITrack_h +#define ITrack_h + +#include <vector> +#include "KiTrack/IHit.h" + +namespace KiTrack{ + + + /** Abstract Base Class for tracks. + */ + class ITrack{ + + + public: + + /** @return a vector of the hits of the track + */ + virtual std::vector< IHit*> getHits() const = 0; + + /** @return an indicator for the quality of the track. Usually between 0 and 1 */ + virtual double getQI() const = 0; + + /** Fits the track. */ + virtual void fit() = 0; + + /** @return the degrees of freedom of the fit. This must only be called after fit() has been used */ + virtual double getNdf() const = 0; + + /** @return the chi squared value of the fit. This must only be called after fit() has been used */ + virtual double getChi2() const = 0; + + /** @return the chi squared probability of the fit. This must only be called after fit() has been used */ + virtual double getChi2Prob() const = 0; + + virtual ~ITrack(){} + + }; + + + + +} + +#endif + + diff --git a/Utilities/KiTrack/KiTrack/KiTrackExceptions.h b/Utilities/KiTrack/KiTrack/KiTrackExceptions.h new file mode 100644 index 00000000..6e2a4a39 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/KiTrackExceptions.h @@ -0,0 +1,105 @@ +#ifndef KiTrackExceptions_h +#define KiTrackExceptions_h + +#include <string> +#include <exception> + +//Exceptions for the KiTrack namespace + +namespace KiTrack { + + /**Base exception class for KiTrack - all other exceptions extend this. + * @author R. Glattauer, HEPHY + * + */ + + class KiTrackException : public std::exception { + + + protected: + std::string message{} ; + + KiTrackException(){ /*no_op*/ ; } + + public: + virtual ~KiTrackException() { /*no_op*/; } + + KiTrackException( const std::string& text ){ + message = "KiTrack::Exception: " + text ; + } + + virtual const char* what() const noexcept { return message.c_str() ; } + + }; + + + + /**Out of range exception, used when the user tries to access layers oder sensors, that are not implemented + * @author R. Glattauer, HEPHY + */ + class OutOfRange : public KiTrackException{ + + protected: + OutOfRange() { /*no_op*/ ; } + public: + virtual ~OutOfRange() { /*no_op*/; } + + OutOfRange( std::string text ){ + message = "KiTrack::OutOfRange: " + text ; + } + }; + + + /**Invalid Parameter exception. + * @author R. Glattauer, HEPHY + */ + class InvalidParameter : public KiTrackException{ + + protected: + InvalidParameter() { /*no_op*/ ; } + public: + virtual ~InvalidParameter() { /*no_op*/; } + + InvalidParameter( std::string text ){ + message = "KiTrack::InvalidParameter: " + text ; + } + }; + + + /**Wrong segment length exception. + * @author R. Glattauer, HEPHY + */ + class BadSegmentLength : public KiTrackException{ + + protected: + BadSegmentLength() { /*no_op*/ ; } + public: + virtual ~BadSegmentLength() { /*no_op*/; } + + BadSegmentLength( std::string text ){ + message = "KiTrack::BadSegmentLength: " + text ; + } + }; + + + + /**Unknown criterion exception. + * @author R. Glattauer, HEPHY + */ + class UnknownCriterion : public KiTrackException{ + + protected: + UnknownCriterion() { /*no_op*/ ; } + public: + virtual ~UnknownCriterion() { /*no_op*/; } + + UnknownCriterion( std::string text ){ + message = "KiTrack::UnknownCriterion: " + text ; + } + }; + +} + +#endif + + diff --git a/Utilities/KiTrack/KiTrack/Segment.h b/Utilities/KiTrack/KiTrack/Segment.h new file mode 100644 index 00000000..6a31c2f3 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/Segment.h @@ -0,0 +1,99 @@ +#ifndef Segment_h +#define Segment_h + +#include <vector> +#include <list> +#include <string> + +#include "KiTrack/IHit.h" + +namespace KiTrack{ + + + /** A Segment is something like a track or a part of a track: it consists of hits linked together. + * + * The simplest Segment consists of only one single hit (the truly smallest part of a track), + * a 1-hit-segment. + * A segment of two hits (a 2-hit-segment) is the next bigger version and so on. + * + * Segments are used by the Cellular Automaton (see class Automaton), which uses them to find tracks. + * + * The main difference to a hit (in case of 1-hit-segments) or a track (in case of segments with more hits) is, that + * the segments can have connection to other Segments. They can have children and parents. + * Children are connected Segments on the inside, Parents are connected Segments on the outside. + * + * Inside and outside are w.r.t. the layer a segment is on. Every Segment has a layer (getLayer(), setLayer() ). The + * layer indicates the place of the segment (whereever that place is. e.g. a detector ). Layer 0 usually means inside + * and higher layers are further outside. + * + * Also every Segment has a state. It is another feature requested by the Cellular Automaton. It gives the CA the possibility + * to check the quality of a Segment and manipulate it (the higher the state, usually the better; but for details on + * the states in the Cellular Autoamton see the <a href="../CellularAutomaton.pdf">Introduction to the Cellular Automaton</a> ) + * + * Segments can skip layers (a 1-hit-segment can't, since it is just a hit and can only be on one layer, but a + * 2-hit-segment could already be the connection between layer 2 and layer 4, thus skipping a layer). + * For this the state is not only an integer, but a vector of integers representing states for every layer. + * (the 2-hit-segment skipping layer number 3 can therefore be imagined as two 2-hit-segments, each of them having + * a seperate state ) + * + */ + class Segment { + + + public: + + Segment( std::vector <IHit*> hits); + Segment( IHit* hit); + + + void deleteParent ( Segment* delParent ){ _parents.remove( delParent );}; + void deleteChild ( Segment* delChild ){ _children.remove( delChild );}; + + + std::list <Segment*> getChildren() { return _children;}; + std::list <Segment*> getParents() { return _parents;}; + + std::vector <IHit*> getHits()const {return _hits;}; + + void addChild( Segment* child ){ _children.push_back(child); }; + void addParent( Segment* parent ){ _parents.push_back(parent); }; + + unsigned getLayer()const { return _layer; }; + void setLayer( unsigned layer ) { _layer = layer; }; + + std::vector<int>& getState() { return _state; }; + + void raiseState() { if (_state.size() > 0) _state[0]++; }; + int getInnerState()const { return _state[0];}; + int getOuterState()const { return _state.back();}; + void resetState(); + + void setSkippedLayers( unsigned skippedLayers ){ _state.resize( skippedLayers + 1 );} + + bool isActive() const { return _active;} + void setActive( bool active ){ _active = active; } + + /** @return infos about the segment */ + std::string getInfo(); + + private: + + std::list <Segment*> _children{}; + std::list <Segment*> _parents{}; + + + + std::vector <IHit*> _hits{}; + + std::vector<int> _state{}; + + unsigned _layer{}; + bool _active{}; + + }; + + +} //end of KiTrack Namespace + +#endif + diff --git a/Utilities/KiTrack/KiTrack/SegmentBuilder.h b/Utilities/KiTrack/KiTrack/SegmentBuilder.h new file mode 100644 index 00000000..a33a4f77 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/SegmentBuilder.h @@ -0,0 +1,94 @@ +#ifndef SegmentBuilder_h +#define SegmentBuilder_h + +#include "Criteria/ICriterion.h" +#include "KiTrack/ISectorConnector.h" +#include "KiTrack/Automaton.h" + +namespace KiTrack{ + + + /** This classe builds the Cellular Automaton from the hits + * + * It can be used to take all the autHits stored in a map< int , vector < IHits > > and makes + * 1-hit-segments out of them ( see the class Segment for more info on them ). + * + * The created 1-segments then are connected. + * + * For the rules of connecting criteria and hitConnectors can be added to the object: + * + * - a hitConnector takes the sector of the segment ( for example a cellID0 or a layer number or an own code ) and returns + * all the sectors we might connect to. So there we get the information like: "this segment can be connected + * to layer 3 and 4, module 7,8,9 in forward direction". + * + * - the criteria take two segments and return whether they are compatible or not. + * A criterion could check for anything, that is stored in the segments. + * For example: if the line formed from two 1-hit segments passes close by the IP might + * be a criterion for very stiff tracks. + * + * So the hitConnectors tell us were to look and the criteria whether to connect. If two 1-hit segments are found, + * that are compatible, they will be connected. Connected means: The inner 1-segment will save the outer one as a parent + * and the outer one will save the inner one as a child. + * + * All this (except adding hitConnectors and Criteria) is done in the method get1SegAutomaton. + * + * This method finally then returns an automaton (segments sorted by their layers), ready to be used. + * + */ + class SegmentBuilder{ + + + public: + + /** + * @param ftdRep the FTDRepresentation to take the autHits from + */ + SegmentBuilder( std::map< int , std::vector< IHit* > > map_sector_hits ); + + /** Adds a criterion. + */ + void addCriterion ( ICriterion* criterion ){ _criteria.push_back( criterion );}; + + /** Adds criteria + */ + void addCriteria ( std::vector< ICriterion* > criteria){ _criteria.insert( _criteria.end(), criteria.begin() , criteria.end() ); } + + /** Adds a hitConnector + */ + void addSectorConnector ( ISectorConnector* connector ){ _sectorConnectors.push_back( connector ); }; + + /** + * @return An automaton containing all the hits from the FTDRepresentation sorted now by layers. + * (attention: those are not necessarily the same layers as the FTD layers). + * Also they are connected. + */ + Automaton get1SegAutomaton(); + + + private: + + + std::vector <ICriterion* > _criteria{}; + std::vector <ISectorConnector* > _sectorConnectors{}; + + std::map< int , std::vector< IHit* > > _map_sector_hits{}; + + + + + + }; + + + + + +} + + +#endif + + + + + diff --git a/Utilities/KiTrack/KiTrack/Subset.h b/Utilities/KiTrack/KiTrack/Subset.h new file mode 100644 index 00000000..6b3e9fd5 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/Subset.h @@ -0,0 +1,58 @@ +#ifndef Subset_h +#define Subset_h + + +#include "KiTrack/ITrack.h" + + +namespace KiTrack { + + /** A base class for subsets. + * + * The idea behind the subset classes is, that one has a collection of elements, but not all elements are compatible + * with each other. One wants to find a subset of these elements, where all are compatible. Also the subset should have + * a high quality. + * Details about this can be found in the derived classes. For technical reasons (templates and virtual methods) + * this class only covers the basics. + */ + template <class T> + class Subset{ + + public: + + /** Adds an element + */ + void add( T newElement ){ _elements.push_back( newElement ); }; + + /** Adds a vector of elements + */ + void add( std::vector<T> newElements ){ _elements.insert( _elements.end() , newElements.begin() , newElements.end() ); }; + + + /** @return the subset of the best tracks, i.e. all the tracks that were accepted + */ + std::vector< T > getAccepted(){ return _acceptedElements;} ; + + /** @return the tracks that got rejected (and are therefore not in the best subset) + */ + std::vector< T > getRejected(){ return _rejectedElements;} ; + + + + protected: + + std::vector< T > _elements{}; + std::vector< T > _acceptedElements{}; + std::vector< T > _rejectedElements{}; + + + }; + + + + +} + + +#endif + diff --git a/Utilities/KiTrack/KiTrack/SubsetHopfieldNN.h b/Utilities/KiTrack/KiTrack/SubsetHopfieldNN.h new file mode 100644 index 00000000..5d92a2f0 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/SubsetHopfieldNN.h @@ -0,0 +1,399 @@ +#ifndef SubsetHopfieldNN_h +#define SubsetHopfieldNN_h + +#include <CLHEP/Random/RandFlat.h> + +#include "KiTrack/Subset.h" +#include "KiTrack/HopfieldNeuralNet.h" + + + +namespace KiTrack { + + /** A class to get the best subset with help of a Hopfield Neural Network + * + */ + template< class T > + class SubsetHopfieldNN : public Subset<T>{ + + public: + + /** Calculates the best set using a Hopfield Neural Network + * (see <a href="../SubsetHopfieldNN.pdf">this</a> for more info) . + * + * After this the results can be accessed with + * the getAccepted() and getRejected() methods (provided by the baseclass Subset). + * + * + * This is a templated class to allow the reuse with objects from different. + * The goal is this: if you have a set of things that are somehow compatible or incompatible + * with each other and you want a subset that only contains compatible ones and has a high quality, to find + * this subset. + * + * For example: you plan a concert where a lot of different artists shall perform together. You have 20 that + * you are interested in asking. BUT: not all of them get along together very well. So artist 1 might be incompatible + * with artist 2 and 7 for some arbitrary reasons. And artist 2 is incompatible with artist 1,3 and 13 and so on. + * In order not to completely mess up the concert you can only invite artists who are entirely compatible with each other. + * AND: not all artists are equal: some are really famous and some are pretty mediocre. + * So you want to find a set of artists with the highest possible quality which is completely compatible. + * + * This is done by this class. The algorithm used for it is a Hopfield Neural Network (HNN). + * + * In order to work it needs to know two things: how to calculate the quality of an element and how to determine + * if two elements are compatible. These are of course things the user has to provide. + * For both a functor object is needed. + * + * Here is how it could look like in the artist example: + * +\verbatim + +class AristQI{ + + public: + + // returns the quality of an artist (a value between 0 and 1, 0 being bad and 1 being fantastic) + inline double operator()( Artist artist ){ + + return artist.numberOfFans()/nPeopleOnEarth; // a number between 0 and 1 + + } + +}; + +class ArtistCompatibility{ + +public: + + // returns whether two artists are compatible + inline bool operator()( Artist artistA, Artist artistB ){ + + if( artistA.hates( artistB ) ) return false; + else return true; + + } + +}; + + +//Somewhere within the program: + +ArtistCompatibility comp; +ArtistQI qi; + +SubsetHopfieldNN< Artist > subset; +subset.add( vecOfArtists ); +subset.calculateBestSet( comp, qi ); + +std::vector< Artist > artistsToInvite = subset.getAccepted(); +std::vector< Artist > artistsToStayAtHome = subset.getRejected(); + + +\endverbatim + * + * + * @param areCompatible a functor of type bool( T, T ) that should tell whether two elements are compatible + * or not. + * + * @param getQI a functor of type double( T ) that returns the quality of an element and should range between 0 and 1. + */ + template< class GetQI, class AreCompatible > + void calculateBestSet( AreCompatible areCompatible, GetQI getQI ); + + + SubsetHopfieldNN(){ + + _TStart = 2.1; + _TInf = 0.1; + _omega = 0.75; + _limitForStable = 0.01; + _initStateMin = 0.; + _initStateMax = 0.1; + _activationThreshold = 0.5; + + } + + void setTStart( double tStart ){ _TStart = tStart; } + void setTInf( double tInf ){ _TInf = tInf; } + void setOmega( double omega ){ _omega = omega; } + void setLimitForStable( double limitForStable ){ _limitForStable = limitForStable; } + void setInitStateMin( double initStateMin ){ _initStateMin = initStateMin; } + void setInitStateMax( double initStateMax ){ _initStateMax = initStateMax; } + void setActivationThreshold( double activationThreshold ){ _activationThreshold = activationThreshold; } + + double getTStart(){ return _TStart; } + double getTInf(){ return _TInf; } + double getOmega(){ return _omega; } + double getLimitForStable(){ return _limitForStable; } + double getInitStateMin(){ return _initStateMin; } + double getInitStateMax(){ return _initStateMax; } + double getActivationThreshold(){ return _activationThreshold; } + + protected: + + + double _TStart{}; + double _TInf{}; + double _omega{}; + double _limitForStable{}; + double _initStateMin{}; + double _initStateMax{}; + double _activationThreshold{}; + + }; + + + template< class T > template< class GetQI, class AreCompatible > + void SubsetHopfieldNN<T>::calculateBestSet( AreCompatible areCompatible, GetQI getQI ){ + + + unsigned nAccepted=0; + unsigned nRejected=0; + unsigned nCompWithAll=0; + unsigned nIncompatible=0; + + + std::vector< T > elements = this->_elements; //this pointer is needed here, because of the template! + + unsigned nElements = elements.size(); + + // the information for the Hopfield Neural Network: + + std::vector < std::vector <bool> > G; // a matrix telling, if two neurons (elements) are compatible + G.resize( nElements ); + for (unsigned i=0; i<nElements; i++) G[i].resize( elements.size() ); + + std::vector < double > QI ; // the quality indicators of the neurons (elements) + QI.resize( nElements ); + + std::vector < double > states; // the initial state to start from. + states.resize( nElements ); + + + + + /**********************************************************************************************/ + /* 1. Find out which elements are compatible and get the QIs */ + /**********************************************************************************************/ + + + for ( unsigned i=0; i < nElements ; i++){ //over all elements + + + T elementA = elements[i]; //the track we want to look at. + + // Get the quality + QI[i] = getQI( elementA ); + + //streamlog_out(DEBUG3) << "QI of element " << i << " = " << QI[i] << "\n"; + + + // Set an initial state + states[i] = CLHEP::RandFlat::shoot ( _initStateMin , _initStateMax ); //random ( uniformly ) values from initStateMin to initStateMax + + + // Fill the states in the G matrix. (whether two elements are compatible or not + for ( unsigned j=i+1; j < nElements ; j++ ){ // over all elements that come after the current one (the elements before get filled automatically because of symmetry) + + T elementB = elements[j]; // the track we check if it is in conflict with trackA + + if ( areCompatible( elementA , elementB ) ){ + + G[i][j] = 0; + G[j][i] = 0; + + } + else{ + + G[i][j] = 1; + G[j][i] = 1; + + } + + } + + } + + // output of the G matrix: + if( !G.empty() ){ + + //streamlog_out(DEBUG2) << "G:\n"; + + + for ( unsigned i=0; i < G.size(); i++ ){ + + + for ( unsigned j=0; j < G[i].size(); j++ ){ + + //streamlog_out(DEBUG2) << G[i][j] << " "; + + } + + //streamlog_out(DEBUG2) << "\n"; + + } + + } + // output, where one sees, what elements are incompatible with what others: + if( !G.empty() ){ + + //streamlog_out(DEBUG2) << "Incompatible ones:\n"; + + + for ( unsigned i=0; i < G.size(); i++ ){ + + //streamlog_out(DEBUG2) << "Element " << i << ":\t"; + + for ( unsigned j=0; j < G[i].size(); j++ ){ + + //if( G[i][j] ) streamlog_out(DEBUG2) << j << ", "; + + } + + //streamlog_out(DEBUG2) << "\n"; + + } + + } + + + /**********************************************************************************************/ + /* 2. Save elements, that are compatible with all others */ + /**********************************************************************************************/ + + for( unsigned i=0; i < elements.size(); i++ ){ + + + bool isCompatibleWithAll = true; + + //check if this track is compatible with all others + for( unsigned j=0; j < elements.size(); j++){ + + //G[i][j] == 0 i and j are compatible, if G[i][j] == 1 i and j are incompatible + if( (i != j) && G[i][j] ){ + + isCompatibleWithAll = false; + break; + + } + + } + + + if ( isCompatibleWithAll ){ //if it is compatible with all others, we don't need the Hopfield Neural Net, we can just save it + + + //add the track to the good ones + this->_acceptedElements.push_back( elements[i] ); + nCompWithAll++; + + + //And now erase it from the ones we will still check: + elements.erase( elements.begin() + i ); + states.erase( states.begin() + i ); + QI.erase( QI.begin() + i ); + + for( unsigned j=0; j<G.size(); j++ ) G[j].erase( G[j].begin() + i ); + G.erase( G.begin() + i ); + + i--; + + } + else{ + + nIncompatible++; + + } + + } + + + //streamlog_out( DEBUG3 ) << nCompWithAll << " elements are compatible with all others, " << nIncompatible + //<< " elements are interfering and will be checked for the best subset\n"; + + + + /**********************************************************************************************/ + /* 3. Let the Neural Network perform to find the best subset */ + /**********************************************************************************************/ + + if( !elements.empty() ){ + + HopfieldNeuralNet net( G , QI , states , _omega); + + net.setT ( _TStart ); + net.setTInf( _TInf ); + net.setLimitForStable( _limitForStable ); + + unsigned nIterations=1; + + //streamlog_out(DEBUG1) << "states: ( "; + //for ( unsigned int i=0; i< states.size(); i++) streamlog_out(DEBUG1) << states[i] << " "; + //streamlog_out(DEBUG1) << ")\n"; + + while ( !net.doIteration() ){ // while the Neural Net is not (yet) stable + + nIterations++; + + std::vector <double> newStates = net.getStates(); + + //streamlog_out(DEBUG1) << "states: ( "; + + //for ( unsigned int i=0; i< newStates.size(); i++) streamlog_out(DEBUG1) << newStates[i] << " "; + + //streamlog_out(DEBUG1) << ")\n"; + + } + + + + //streamlog_out( DEBUG3 ) << "Hopfield Neural Network is stable after " << nIterations << " iterations.\n"; + + + + + /**********************************************************************************************/ + /* 4. Now just sort the elements into accepted and rejected ones */ + /**********************************************************************************************/ + + + states = net.getStates(); + + + + for ( unsigned i=0; i < states.size(); i++ ){ + + + if ( states[i] >= _activationThreshold ){ + + this->_acceptedElements.push_back( elements[i] ); + nAccepted++; + + } + else{ + + this->_rejectedElements.push_back( elements[i] ); + nRejected++; + + } + + } + + } + + + //streamlog_out( DEBUG3 ) << "Hopfield Neural Network accepted " << nAccepted + //<< " elements and rejected " << nRejected << " elements of all in all " + //<< nAccepted + nRejected << "incomaptible elements.\n"; + + //streamlog_out( DEBUG3 ) << "So in sum " << nAccepted + nCompWithAll + //<< " elements survived and " << nRejected << " elements got rejected.\n"; + + + } + + +} + + +#endif + diff --git a/Utilities/KiTrack/KiTrack/SubsetSimple.h b/Utilities/KiTrack/KiTrack/SubsetSimple.h new file mode 100644 index 00000000..a5521621 --- /dev/null +++ b/Utilities/KiTrack/KiTrack/SubsetSimple.h @@ -0,0 +1,186 @@ +#ifndef SubsetSimple_h +#define SubsetSimple_h + +#include <algorithm> + +//#include "marlin/VerbosityLevels.h" + +#include "KiTrack/Subset.h" + +namespace KiTrack { + + + template <class T, class QI > + struct SorterQI + { + SorterQI( QI getQI ): _getQI( getQI ){} + + bool operator()( T a, T b ){ return ( _getQI( a ) > _getQI( b ) ); } + + QI _getQI; + }; + + + /** A class to get the best subset by taking the element with the highest quality + * indicator and throwing away all incompatible ones. + * On the remaining elements repeat the procedure. + * + */ + template <class T > + class SubsetSimple : public Subset<T> { + + public: + + /** Calculates the best set using a very simple method. After this the results can be accessed with + * the getAccepted() and getRejected() methods (provided by the baseclass Subset). + * + * This is a templated class to allow the reuse with objects from different. + * The goal is this: if you have a set of things that are somehow compatible or incompatible + * with each other and you want a subset that only contains compatible ones and has a high quality, to find + * this subset. + * + * For example: you plan a concert where a lot of different artists shall perform together. You have 20 that + * you are interested in asking. BUT: not all of them get along together very well. So artist 1 might be incompatible + * with artist 2 and 7 for some arbitrary reasons. And artist 2 is incompatible with artist 1,3 and 13 and so on. + * In order not to completely mess up the concert you can only invite artists who are entirely compatible with each other. + * AND: not all artists are equal: some are really famous and some are pretty mediocre. + * So you want to find a set of artists with the highest possible quality which is completely compatible. + * + * This is done by this class. + * + * The algorithm used for it is this: take the element with the highest quality and accept it. Reject all + * other elements that are incompatible with it. From the remaining elements redo the same with the next best + * element. + * In our artist example: take the biggest star and throw out all he doesn't get allong with. From the remaining + * artists (those who do get along with the biggest star) pick next famous one. Once again kick out all that + * don't get along with him and so on. + * + * In order to work it needs to know two things: how to calculate the quality of an element and how to determine + * if two elements are compatible. These are of course things the user has to provide. + * For both a functor object is needed. + * + * Here is how it could look like in the artist example: + * +\verbatim + +class AristQI{ + +public: + + // returns the quality of an artist (a value between 0 and 1, 0 being bad and 1 being fantastic) + inline double operator()( Artist artist ){ + + return artist.numberOfFans()/nPeopleOnEarth; // a number between 0 and 1 + + } + +}; + +class ArtistCompatibility{ + +public: + + // returns whether two artists are compatible + inline bool operator()( Artist artistA, Artist artistB ){ + + if( artistA.hates( artistB ) ) return false; + else return true; + + } + +}; + + +//Somewhere within the program: + +ArtistCompatibility comp; +ArtistQI qi; + +SubsetHopfieldNN< Artist > subset; +subset.add( vecOfArtists ); +subset.calculateBestSet( comp, qi ); + +std::vector< Artist > artistsToInvite = subset.getAccepted(); +std::vector< Artist > artistsToStayAtHome = subset.getRejected(); + + +\endverbatim + * + * + * + * @param areCompatible a functor of type bool( T, T ) that should tell whether two elements are compatible + * or not. + * + * @param getQI a functor of type double( T ) that returns the quality of an element and should range between 0 and 1. + */ + template< class GetQI, class AreCompatible > + void calculateBestSet( AreCompatible areCompatible, GetQI getQI ); + }; + + template<class T> template<class GetQI, class AreCompatible> + void SubsetSimple<T>::calculateBestSet( AreCompatible areCompatible, GetQI getQI ){ + + + unsigned nAccepted=0; + unsigned nRejected=0; + + + + std::vector< T > elements = this->_elements; + + // sort the vector from big QI to small QI + SorterQI< T, GetQI > sorterQI( getQI ); + sort( elements.begin(), elements.end() , sorterQI ); + + //std::cout << "DEBUG: SubsetSimple::calculateBestSet The elements and their QIs sorted:" << std::endl; + for( unsigned i=0; i < elements.size(); i++ ){ + double qi = getQI( elements[i] ); + //std::cout << "DEBUG: SubsetSimple::calculateBestSet " << elements[i] << "\t" << qi << std::endl; + } + + /*The idea here is: the first track is (now that we sorted) the one with the highest + * QI. Check all other tracks if they are complatible with it. + * If one of them is incompatible throw it away. Once done with that, store the + * first track as accepted (and delete it from the vector) and do it once more for + * the new highest QI track. + * Repeat until all tracks are stored. + */ + while( elements.size() > 0 ){ + + + // check all elements with smaller QI if they are compatible + for( unsigned i=1; i < elements.size(); i++){ + + + if( areCompatible( elements[0] , elements[i] ) == false ){ // the track is incompatible + + // reject it + nRejected++; + this->_rejectedElements.push_back( elements[i] ); + + //std::cout << "DEBUG: SubsetSimple::calculateBestSet " << "reject " << elements[i] << std::endl; + // and delete it from the elements we are looking at + elements.erase( elements.begin() + i ); + i--; + + } + + } + + // store the first element + //std::cout << "DEBUG: SubsetSimple::calculateBestSet " << "accept " << elements[0] << std::endl; + nAccepted++; + this->_acceptedElements.push_back( elements[0] ); + + // delete it from the current tracks + elements.erase( elements.begin() ); + + } + + //std::cout << "DEBUG: SubsetSimple::calculateBestSet " << "SubsetSimple accepted " << nAccepted + // << " elements and rejected " << nRejected << " elements of all in all " + // << nAccepted + nRejected << " elements." << std::endl; + + } +} // end namespace +#endif diff --git a/Utilities/KiTrack/Tools/FTDHelixFitter.h b/Utilities/KiTrack/Tools/FTDHelixFitter.h new file mode 100644 index 00000000..6050ae01 --- /dev/null +++ b/Utilities/KiTrack/Tools/FTDHelixFitter.h @@ -0,0 +1,65 @@ +#ifndef FTDHelixFitter_h +#define FTDHelixFitter_h + +#include "edm4hep/Track.h" +#include "edm4hep/TrackerHitConst.h" + +class FTDHelixFitterException : public std::exception { + protected: + std::string message ; + + FTDHelixFitterException(){ /*no_op*/ ; } + + public: + virtual ~FTDHelixFitterException() { /*no_op*/; } + + FTDHelixFitterException( const std::string& text ){ + message = "FTDHelixFitterException: " + text ; + } + + virtual const char* what() const noexcept { return message.c_str() ; } + +}; + +/** A class to make it quick to fit a track or hits and get back the chi2 and Ndf values and + * also bundle the code used for that, so it doesn't have to be copied all over the places. + * Uses a helix fit from the MarlinTrk class HelixFit.cc + * It is named FTDHelixFitter, because it makes some assumptions about the hits, that come from them + * being on the FTD. Specifically the errors passed to the helix fit are calculated on the assumption, + * that du and dv are errors in the xy plane. + * If this class is intended to be used for hits on different detectors, a careful redesign is necessary! + */ +class FTDHelixFitter{ + public: + + FTDHelixFitter( edm4hep::Track* track ) ; + FTDHelixFitter( std::vector<edm4hep::ConstTrackerHit> trackerHits ) ; + + + double getChi2(){ return _chi2; } + int getNdf(){ return _Ndf; } + + float getOmega(){ return _omega; } + float getTanLambda(){ return _tanLambda; } + float getPhi0(){ return _phi0; } + float getD0(){ return _d0; } + float getZ0(){ return _z0; } + + private: + + void fit(); + + double _chi2; + int _Ndf; + + float _omega; + float _tanLambda; + float _phi0; + float _d0; + float _z0; + + std::vector< edm4hep::ConstTrackerHit > _trackerHits; + +}; + +#endif diff --git a/Utilities/KiTrack/Tools/Fitter.h b/Utilities/KiTrack/Tools/Fitter.h new file mode 100644 index 00000000..461d735d --- /dev/null +++ b/Utilities/KiTrack/Tools/Fitter.h @@ -0,0 +1,129 @@ +#ifndef Fitter_h +#define Fitter_h + +#include "TrackSystemSvc/IMarlinTrkSystem.h" +#include "TrackSystemSvc/IMarlinTrack.h" +#include "edm4hep/Track.h" +//#include "lcio.h" + +#include "Math/ProbFunc.h" + + +//using namespace lcio; + + + +class FitterException : public std::exception { + + +protected: + std::string message ; + + FitterException(){ /*no_op*/ ; } + +public: + virtual ~FitterException() { /*no_op*/; } + + FitterException( const std::string& text ){ + message = "FitterException: " + text ; + } + + virtual const char* what() const noexcept { return message.c_str() ; } + +}; + + + +/** A class to store additional information together with a TrackState, namely the chi2 value and Ndf + */ +class TrackStatePlus{ + + + +public: + + const edm4hep::TrackState* getTrackState() const {return _trackState; } + double getChi2() const {return _chi2;} + int getNdf() const {return _Ndf;} + + TrackStatePlus( const edm4hep::TrackState* trackState, double chi2, int Ndf ): + _trackState( trackState ), _chi2( chi2 ), _Ndf( Ndf ){} + + + +private: + + const edm4hep::TrackState* _trackState; + double _chi2; + int _Ndf; + + +}; + + +/** A class to make it quick to fit a track or hits and get back the chi2, Ndf and chi2prob values and + * also bundle the code used for that, so it doesn't have to be copied all over the places. + */ +class Fitter{ + + +public: + + Fitter( edm4hep::Track* track , MarlinTrk::IMarlinTrkSystem* trkSystem ); + Fitter( std::vector < edm4hep::ConstTrackerHit > trackerHits, MarlinTrk::IMarlinTrkSystem* trkSystem ); + Fitter( edm4hep::Track* track , MarlinTrk::IMarlinTrkSystem* trkSystem, int VXDFlag ); + + + double getChi2Prob( int trackStateLocation ) ; + double getChi2( int trackStateLocation ) ; + int getNdf( int trackStateLocation ) ; + + //TODO: maybe add methods for custom points (location: TrackState::AtOther) In that case, the point would have to + // be passed as well. (or only the point is passed) + + const edm4hep::TrackState* getTrackState( int trackStateLocation ) ; + + ~Fitter(){ + + for( unsigned i=0; i<_trackStatesPlus.size(); i++ ){ + + delete _trackStatesPlus[i]->getTrackState(); + delete _trackStatesPlus[i]; + + } + _trackStatesPlus.clear(); + + delete _marlinTrk; + + } + +private: + + void init_BField(); + + const TrackStatePlus* getTrackStatePlus( int trackStateLocation ) ; + + void fit(); + + void fitVXD(); + + static float _bField; + + + std::vector< edm4hep::ConstTrackerHit > _trackerHits; + + /** here the created TrackStates (plus) are stored */ + std::vector< const TrackStatePlus* > _trackStatesPlus; + + MarlinTrk::IMarlinTrkSystem* _trkSystem; + + MarlinTrk::IMarlinTrack* _marlinTrk; + + // No copy constructor or assignment needed so far. so private for safety + // If they are needed, they need to be implemented in a clean way first! + Fitter( const Fitter& f ){}; + Fitter& operator= ( Fitter const& f ){return *this;} + +}; + +#endif diff --git a/Utilities/KiTrack/Tools/KiTrackMarlinTools.h b/Utilities/KiTrack/Tools/KiTrackMarlinTools.h new file mode 100644 index 00000000..f4b58292 --- /dev/null +++ b/Utilities/KiTrack/Tools/KiTrackMarlinTools.h @@ -0,0 +1,97 @@ +#ifndef KiTrackMarlinTools_h +#define KiTrackMarlinTools_h + +#include <string> +#include <set> +#include <vector> +#include <map> +//#include <sstream> + +#include "edm4hep/TrackerHit.h" +#include "edm4hep/Track.h" + +#include "ILDImpl/FTDHitSimple.h" +#include "ILDImpl/VXDHitSimple.h" +#include "KiTrack/ITrack.h" + +using namespace KiTrack; + +namespace KiTrackMarlin{ + +/** @return information about the contents of the passed CellID0 */ +std::string getCellID0Info( int cellID0 ); + +/** @return the layer given by the cellID0 */ +int getCellID0Layer( int cellID0 ); + +/** Generates a root file with a specified name and with a single tree . + * If a rootfile with the same name already exists, a number will be appended + * to it, so the old one doesn't get lost. + * So if I create myRoot.root and it already exists, the old one will be renamed to + * "myRoot1.root". + * If "myRoot1.root" already exists, "myRoot2.root" will be created. + * + * So after we did this for some time, we end up with a lot of root files with numbers. + * The one without a number appended is the newest one. + * The one with the number 1 appended is the oldest, 2 is newer than 1, 3 is newer than 2 and so on. + * + * @param branchNames A set of all the branchnames that should be created in the tree + * + * @param createNew Whether to create a new root file or create the tree and branches in an existing one + */ +void setUpRootFile( std::string fileNamePath, std::string treeName , std::set<std::string> branchNames = std::set<std::string>() , bool createNew=true ); + + +/** Saves values to a tree in a rootfile. + * + * @param fileNamePath the name (path) of the rootfile + * + * @param treeName the name of the tree + * + * @param map_name_data a map of key = name of what we save , mapped value = value we want to save + * + */ +void saveToRoot( std::string fileNamePath, std::string treeName , std::map < std::string , float > map_name_data ); + +void saveToRoot( std::string rootFileName, std::string treeName , std::vector < std::map < std::string , float > > rootDataVec ); + + + + +/** method that compares two TrackerHits. + * + * @return true if |a.z| < |b.z| , i.e. true if a is nearer to z=0 than b is + */ +//bool compare_TrackerHit_z( edm4hep::ConstTrackerHit* a, edm4hep::ConstTrackerHit* b ); +bool compare_TrackerHit_z( edm4hep::ConstTrackerHit& a, edm4hep::ConstTrackerHit& b ); + +/** method that compares two TrackerHits. + * + * @return true if |a.R| < |b.R| , i.e. true if a has smaller radius than b + * + * to be used at the VXD-SIT system + */ +bool compare_TrackerHit_R( edm4hep::ConstTrackerHit& a, edm4hep::ConstTrackerHit& b ); + + +FTDHitSimple* createVirtualIPHit( int side , const SectorSystemFTD* sectorSystemFTD ); + +VXDHitSimple* createVirtualIPHit( const SectorSystemVXD* sectorSystemVXD ); + + +std::string getPositionInfo( edm4hep::ConstTrackerHit* hit ); + +std::string getPositionInfo( IHit* hit ); + +std::string getTrackHitInfo( ITrack* track ); + +std::string getTrackHitInfo( edm4hep::Track* track ); + +} // end of namespace KiTrackMarlin + + + + +#endif + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.cc b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.cc new file mode 100644 index 00000000..9bf3a11f --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.cc @@ -0,0 +1,84 @@ +#include "Criteria/Crit2_DeltaPhi.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit2_DeltaPhi::Crit2_DeltaPhi ( float deltaPhiMin , float deltaPhiMax ){ + + + _deltaPhiMax = deltaPhiMax; + _deltaPhiMin = deltaPhiMin; + _name = "Crit2_DeltaPhi"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_DeltaPhi::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + + IHit* a = parent->getHits()[0]; + IHit* b = child-> getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + + + float bx = b->getX(); + float by = b->getY(); + + + + float phia = atan2( ay, ax ); + float phib = atan2( by, bx ); + float deltaPhi = phia-phib; + if (deltaPhi > M_PI) deltaPhi -= 2*M_PI; //to the range from -pi to pi + if (deltaPhi < -M_PI) deltaPhi += 2*M_PI; //to the range from -pi to pi + + if (( by*by + bx*bx < 0.0001 )||( ay*ay + ax*ax < 0.0001 )) deltaPhi = 0.; // In case one of the hits is too close to the origin + + deltaPhi = 180.*fabs( deltaPhi ) / M_PI; + if (_saveValues) _map_name_value["Crit2_DeltaPhi"]= deltaPhi; + + + + + + if ( deltaPhi > _deltaPhiMax ) return false; + + if ( deltaPhi < _deltaPhiMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit2_DeltaPhi::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.h b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.h new file mode 100644 index 00000000..342e7750 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi.h @@ -0,0 +1,38 @@ +#ifndef Crit2_DeltaPhi_h +#define Crit2_DeltaPhi_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the difference between the \f$ \phi \f$ angles of two hits in degrees. + * The \f$ \phi \f$ is the angle in the xy plane w.r.t. the positive x axis. + * \f[ \phi = atan2(y,x) \f] + */ + class Crit2_DeltaPhi : public ICriterion{ + + + + public: + + Crit2_DeltaPhi ( float deltaPhiMin , float deltaPhiMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_DeltaPhi(){}; + + + private: + + float _deltaPhiMax{}; + float _deltaPhiMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.cc b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.cc new file mode 100644 index 00000000..a94b0ea9 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.cc @@ -0,0 +1,78 @@ +#include "Criteria/Crit2_DeltaPhi_MV.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit2_DeltaPhi_MV::Crit2_DeltaPhi_MV ( float deltaPhiMin , float deltaPhiMax ){ + + + _deltaPhiMax = deltaPhiMax; + _deltaPhiMin = deltaPhiMin; + _name = "Crit2_DeltaPhi_MV"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_DeltaPhi_MV::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + IHit* a = parent->getHits()[0]; + IHit* b = child->getHits()[0]; + + double phia = a->getPhi(); + double phib = b->getPhi(); + + double deltaPhi = phia-phib; + + if (deltaPhi > M_PI) deltaPhi -= 2*M_PI; //to the range from -pi to pi + if (deltaPhi < -M_PI) deltaPhi += 2*M_PI; //to the range from -pi to pi + + float ax = a->getX(); + float ay = a->getY(); + float bx = b->getX(); + float by = b->getY(); + + if (( by*by + bx*bx < 0.0001 )||( ay*ay + ax*ax < 0.0001 )) deltaPhi = 0.; // In case one of the hits is too close to the origin + + deltaPhi = 180.*fabs( deltaPhi ) / M_PI; + if (_saveValues) _map_name_value["Crit2_DeltaPhi_MV"]= deltaPhi; + + + if ( deltaPhi > _deltaPhiMax ) return false; + + if ( deltaPhi < _deltaPhiMin ) return false; + + + } + + + else{ + + std::stringstream s; + s << "Crit2_DeltaPhi_MV::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.h b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.h new file mode 100644 index 00000000..3dee9bad --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaPhi_MV.h @@ -0,0 +1,38 @@ +#ifndef Crit2_DeltaPhi_MV_h +#define Crit2_DeltaPhi_MV_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the difference between the \f$ \phi \f$ angles of two hits in degrees. + * The \f$ \phi \f$ is the angle in the xy plane w.r.t. the positive x axis. + * \f[ \phi = atan2(y,x) \f] + */ + class Crit2_DeltaPhi_MV : public ICriterion{ + + + + public: + + Crit2_DeltaPhi_MV ( float deltaPhiMin , float deltaPhiMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_DeltaPhi_MV(){}; + + + private: + + float _deltaPhiMax{}; + float _deltaPhiMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.cc b/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.cc new file mode 100644 index 00000000..64190dc6 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.cc @@ -0,0 +1,81 @@ +#include "Criteria/Crit2_DeltaRho.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit2_DeltaRho::Crit2_DeltaRho ( float deltaRhoMin , float deltaRhoMax ){ + + + _deltaRhoMax = deltaRhoMax; + _deltaRhoMin = deltaRhoMin; + + _name = "Crit2_DeltaRho"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_DeltaRho::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + + IHit* a = parent->getHits()[0]; + IHit* b = child-> getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + //the distance to (0,0) in the xy plane + float rhoA = sqrt( ax*ax + ay*ay ); + float rhoB = sqrt( bx*bx + by*by ); + + float deltaRho = rhoA - rhoB; + + //first check, if the distance to (0,0) rises --> such a combo could not reach the IP + if (_saveValues){ + _map_name_value["Crit2_DeltaRho_rhoParent"] = rhoA; + _map_name_value["Crit2_DeltaRho_rhoChild"] = rhoB; + _map_name_value["Crit2_DeltaRho"] = deltaRho; + } + + + + if ( deltaRho > _deltaRhoMax ) return false; + if ( deltaRho < _deltaRhoMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit2_DeltaRho::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.h b/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.h new file mode 100644 index 00000000..3b65daec --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaRho.h @@ -0,0 +1,36 @@ +#ifndef Crit2_DeltaRho_h +#define Crit2_DeltaRho_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the difference of the sqrt(x^2 + y^2) of two hits. + */ + class Crit2_DeltaRho : public ICriterion{ + + + + public: + + Crit2_DeltaRho ( float deltaRhoMin , float deltaRhoMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_DeltaRho(){}; + + + private: + + float _deltaRhoMax{}; + float _deltaRhoMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.cc b/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.cc new file mode 100644 index 00000000..5d0f0463 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.cc @@ -0,0 +1,84 @@ +#include "Criteria/Crit2_DeltaTheta_MV.h" + +#include <cmath> +#include <sstream> +//#include <iostream> // for debugging + +using namespace KiTrack; + +Crit2_DeltaTheta_MV::Crit2_DeltaTheta_MV ( float deltaThetaMin , float deltaThetaMax ){ + + + _deltaThetaMax = deltaThetaMax; + _deltaThetaMin = deltaThetaMin; + _name = "Crit2_DeltaTheta_MV"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_DeltaTheta_MV::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + IHit* a = parent->getHits()[0]; + IHit* b = child->getHits()[0]; + + + double thetaa = a->getTheta(); + double thetab = b->getTheta(); + + //streamlog_out(DEBUG4) << " theta a = " << (180*thetaa)/M_PI << " theta b = " << (180*thetab)/M_PI << std::endl ; + + double deltaTheta = thetaa-thetab; + + if (deltaTheta > M_PI) deltaTheta -= 2*M_PI; //to the range from -pi to pi + if (deltaTheta < -M_PI) deltaTheta += 2*M_PI; //to the range from -pi to pi + + float ax = a->getX(); + float ay = a->getY(); + float bx = b->getX(); + float by = b->getY(); + + if (( by*by + bx*bx < 0.0001 )||( ay*ay + ax*ax < 0.0001 )) deltaTheta = 0.; // In case one of the hits is too close to the origin + + deltaTheta = 180.*fabs( deltaTheta ) / M_PI; + if (_saveValues) _map_name_value["Crit2_DeltaTheta_MV"]= deltaTheta; + + + if ( deltaTheta > _deltaThetaMax ) return false; + + if ( deltaTheta < _deltaThetaMin ) return false; + + //streamlog_out(DEBUG4) << " delta theta " << deltaTheta << " max " << _deltaThetaMax << " min " << _deltaThetaMin << std::endl ; + + + } + + else{ + + std::stringstream s; + s << "Crit2_DeltaTheta_MV::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.h b/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.h new file mode 100644 index 00000000..3f9a0494 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_DeltaTheta_MV.h @@ -0,0 +1,38 @@ +#ifndef Crit2_DeltaTheta_MV_h +#define Crit2_DeltaTheta_MV_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the difference between the \f$ \theta \f$ angles of two hits in degrees. + * The \f$ \theta \f$ is the angle in the xy plane w.r.t. the positive x axis. + * \f[ \theta = atan2(y,x) \f] + */ + class Crit2_DeltaTheta_MV : public ICriterion{ + + + + public: + + Crit2_DeltaTheta_MV ( float deltaThetaMin , float deltaThetaMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_DeltaTheta_MV(){}; + + + private: + + float _deltaThetaMax{}; + float _deltaThetaMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.cc b/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.cc new file mode 100644 index 00000000..95f5e7d2 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.cc @@ -0,0 +1,74 @@ +#include "Criteria/Crit2_Distance_MV.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit2_Distance_MV::Crit2_Distance_MV ( float deltaPos2Min , float deltaPos2Max ){ + + + _deltaPos2Max = deltaPos2Max; + _deltaPos2Min = deltaPos2Min; + _name = "Crit2_Distance_MV"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_Distance_MV::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + IHit* a = parent->getHits()[0]; + IHit* b = child->getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + float bx = b->getX(); + float by = b->getY(); + + double posa = sqrt(ax*ax + ay*ay); + double posb = sqrt(bx*bx + by*by); + + double deltaPos2 = (posa-posb) * (posa-posb) ; + + if (( by*by + bx*bx < 0.0001 )||( ay*ay + ax*ax < 0.0001 )) deltaPos2 = 0.; // In case one of the hits is too close to the origin + + if (_saveValues) _map_name_value["Crit2_Distance_MV"]= deltaPos2; + + + if ( deltaPos2 > _deltaPos2Max ) return false; + + if ( deltaPos2 < _deltaPos2Min ) return false; + + + } + + + else{ + + std::stringstream s; + s << "Crit2_Distance_MV::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.h b/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.h new file mode 100644 index 00000000..6463acb2 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_Distance_MV.h @@ -0,0 +1,38 @@ +#ifndef Crit2_Distance_MV_h +#define Crit2_Distance_MV_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the difference between the \f$ \phi \f$ angles of two hits in degrees. + * The \f$ \phi \f$ is the angle in the xy plane w.r.t. the positive x axis. + * \f[ \phi = atan2(y,x) \f] + */ + class Crit2_Distance_MV : public ICriterion{ + + + + public: + + Crit2_Distance_MV ( float deltaPos2Min , float deltaPos2Max ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_Distance_MV(){}; + + + private: + + float _deltaPos2Max{}; + float _deltaPos2Min{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.cc b/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.cc new file mode 100644 index 00000000..0c8baf1c --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.cc @@ -0,0 +1,125 @@ +#include "Criteria/Crit2_HelixWithIP.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + +using namespace KiTrack; + +Crit2_HelixWithIP::Crit2_HelixWithIP ( float ratioMin , float ratioMax ){ + + + _ratioMax = ratioMax; + _ratioMin = ratioMin; + + _name = "Crit2_HelixWithIP"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_HelixWithIP::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + + IHit* a = parent->getHits()[0]; + IHit* b = child-> getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + + + float ratio = 1.; + + try{ + + SimpleCircle circle ( 0. , 0. , ax , ay , bx , by ); + + float x = circle.getCenterX(); + float y = circle.getCenterY(); + + + //calculate the angle in the circle from the IP to the child hit: + + //vector from the center of circle to the IP + float ux = 0. - x; + float uy = 0. - y; + + //vector from the center of circle to the child + float vx = bx - x; + float vy = by - y; + + //vector from the center of circle to the parent + float wx = ax - x; + float wy = ay - y; + + //the angle between u and v (angle between two vectors: cos(alpha) = u*v/|u||v| ) + float alpha1 = acos ( (ux*vx + uy*vy ) / sqrt(( ux*ux + uy*uy ) * ( vx*vx + vy*vy )) ); + + //the angle between v and w + float alpha2 = acos ( (vx*wx + vy*wy ) / sqrt(( vx*vx + vy*vy ) * ( wx*wx + wy*wy )) ); + + float deltaz1 = bz - 0.; + float deltaz2 = az - bz; + + + + if ( ( alpha2 != 0) && (deltaz1 != 0) ) ratio = ( alpha1 * deltaz2 ) / ( alpha2 * deltaz1 ); + + + + + } + catch ( InvalidParameter ){ + + + } + + + + + if (_saveValues) _map_name_value["Crit2_HelixWithIP"]= ratio; + + + if ( ratio > _ratioMax ) return false; + + if ( ratio < _ratioMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit2_HelixWithIP::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.h b/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.h new file mode 100644 index 00000000..2f888e15 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_HelixWithIP.h @@ -0,0 +1,43 @@ +#ifndef Crit2_HelixWithIP_h +#define Crit2_HelixWithIP_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: Check if two hits are compatible with a helix crossing the IP. + * The procedure is this: a circle is calculated from the two hits and the IP. + * The angle between the center of the circle and two hits is calles alpha here. + * alpha between IP and the first hit is proportional to the z-distance of the IP + * and the first hit in the same way alpha between the first and second hit should + * be proportional to the z-distance of those hits. The value calculated is + * \f[ \frac{ \frac{\alpha_1}{\Delta z_1} }{ \frac{\alpha_2}{\Delta z_2} } \simeq 1 \f] + * and is 1 for a perfect helix around the z - axis. + */ + class Crit2_HelixWithIP : public ICriterion{ + + + + public: + + Crit2_HelixWithIP ( float ratioMin , float ratioMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_HelixWithIP(){}; + + + private: + + float _ratioMax{}; + float _ratioMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.cc b/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.cc new file mode 100644 index 00000000..781e95b8 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.cc @@ -0,0 +1,82 @@ +#include "Criteria/Crit2_RZRatio.h" + +#include <cmath> +#include <sstream> + + +using namespace KiTrack; + +Crit2_RZRatio::Crit2_RZRatio ( float ratioMin, float ratioMax ){ + + + _ratioMax = ratioMax; + _ratioMin = ratioMin; + + _name = "Crit2_RZRatio"; + _type = "2Hit"; + + _saveValues = false; + + + +} + + +bool Crit2_RZRatio::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + IHit* a = parent->getHits()[0]; + IHit* b = child-> getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + // the square is used, because it is faster to calculate with the squares than with sqrt, which takes some time! + double ratioSquared = 0.; + if ( az-bz != 0. ) ratioSquared = ( (ax-bx)*(ax-bx) + (ay-by)*(ay-by) + (az-bz)*(az-bz) ) / ( (az-bz) * ( az-bz ) ); + + + if (_saveValues) _map_name_value[ "Crit2_RZRatio"] = sqrt( ratioSquared ); + + + + if ( ratioSquared > _ratioMax * _ratioMax ) return false; + if ( ratioSquared < _ratioMin * _ratioMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit2_RZRatio::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + + + + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.h b/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.h new file mode 100644 index 00000000..1d1ea36f --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_RZRatio.h @@ -0,0 +1,35 @@ +#ifndef Crit2_RZRatio_h +#define Crit2_RZRatio_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: distance of two hits divided by their z-distance. + * \f[ \frac{\sqrt{ \Delta x^2 + \Delta y^2 + \Delta z^2 }}{\left| \Delta z \right|}\f] + */ + class Crit2_RZRatio : public ICriterion{ + + + + public: + + Crit2_RZRatio ( float ratioMin, float ratioMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_RZRatio(){}; + + private: + + float _ratioMax{}; + float _ratioMin{}; + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.cc b/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.cc new file mode 100644 index 00000000..f52351ef --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.cc @@ -0,0 +1,90 @@ +#include "Criteria/Crit2_StraightTrackRatio.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit2_StraightTrackRatio::Crit2_StraightTrackRatio ( float ratioMin, float ratioMax ){ + + + _ratioMax = ratioMax; + _ratioMin = ratioMin; + + _name = "Crit2_StraightTrackRatio"; + _type = "2Hit"; + + _saveValues = false; + +} + + + +bool Crit2_StraightTrackRatio::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 1 )&&( child->getHits().size() == 1 )){ //a criterion for 1-segments + + + + IHit* a = parent->getHits()[0]; + IHit* b = child-> getHits()[0]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + //the distance to (0,0) in the xy plane + double rhoASquared = ax*ax + ay*ay; + double rhoBSquared = bx*bx + by*by; + + + + + if (_saveValues){ + _map_name_value["Crit2_StraightTrackRatio"]= 1.; + + } + + + if( (rhoBSquared >0.) && ( az != 0. ) ){ //prevent division by 0 + + // the square is used, because it is faster to calculate with the squares than with sqrt, which takes some time! + double ratioSquared = ( ( rhoASquared * ( bz*bz ) ) / ( rhoBSquared * ( az*az ) ) ); + + if (_saveValues) _map_name_value["Crit2_StraightTrackRatio"] = sqrt(ratioSquared); + + + if ( ratioSquared > _ratioMax * _ratioMax ) return false; + + if ( ratioSquared < _ratioMin * _ratioMin ) return false; + + } + + } + else{ + + std::stringstream s; + s << "Crit2_StraightTrackRatio::This criterion needs 2 segments with 1 hit each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.h b/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.h new file mode 100644 index 00000000..3d46c215 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit2_StraightTrackRatio.h @@ -0,0 +1,41 @@ +#ifndef Crit2_StraightTrackRatio_h +#define Crit2_StraightTrackRatio_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: for straight tracks: if the line between the two hits points towards IP. + * Calculated is + * + * \f[ \frac{ \frac{\rho_1}{z_1} }{ \frac{\rho_2}{z_2} } \simeq 1 \f] + * + * , where \f$ \rho = \sqrt{ x^2 + y^2 }\f$ + */ + class Crit2_StraightTrackRatio : public ICriterion{ + + + + public: + + Crit2_StraightTrackRatio ( float ratioMin, float ratioMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit2_StraightTrackRatio(){}; + + + private: + + float _ratioMax{}; + float _ratioMin{}; + + + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.cc b/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.cc new file mode 100644 index 00000000..2f3c4203 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.cc @@ -0,0 +1,121 @@ +#include "Criteria/Crit3_2DAngle.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit3_2DAngle::Crit3_2DAngle ( float angleMin, float angleMax ){ + + + _cosAngleMin = cos ( angleMax * M_PI / 180. ); + _cosAngleMax = cos ( angleMin * M_PI / 180. ); + + _name = "Crit3_2DAngle"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_2DAngle::areCompatible( Segment* parent , Segment* child ) { + + + //this is not written very beautiful, because this code gets called often and needs to be fast. + //But it's just a simple angle calculation of two vectors cos(alpha) = u*v/|u||v| + // + //Because of speed, I avoided using stuff like sqrt or cos or something in here. + //That's why it may look a bit odd. + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //this is a criterion for 2-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + float ux = bx - ax; + float uy = by - ay; + + + float vx = cx - bx; + float vy = cy - by; + + + //In the numerator there is the vector product of u and v + double numerator= ux*vx + uy*vy; + + //In the denominator there are the lengths of u and v (here squared) + double uSquared= ux*ux + uy*uy; + double vSquared= vx*vx + vy*vy; + + + + double denomSquared = uSquared * vSquared; + + if (_saveValues){ + + _map_name_value["Crit3_2DAngle_cos2DAngleSquared"] = 1.; + _map_name_value["Crit3_2DAngle"] = 0.; + + } + + if ( denomSquared > 0.){ //don't divide by 0 + + double cosThetaSquared = numerator * numerator / ( uSquared * vSquared ); + if( cosThetaSquared > 1. ) cosThetaSquared = 1; // prevent rounding errors: cosTheta can mathematically never be bigger than 1!!! + + if (_saveValues){ + + _map_name_value["Crit3_2DAngle_cos2DAngleSquared"] = cosThetaSquared; + _map_name_value["Crit3_2DAngle"] = acos( sqrt( cosThetaSquared ) ) * 180. / M_PI; + + } + + if (cosThetaSquared < _cosAngleMin*_cosAngleMin) return false; + if (cosThetaSquared > _cosAngleMax*_cosAngleMax) return false; + + } + + + + + + + } + else{ + + std::stringstream s; + s << "Crit3_2DAngle::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.h b/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.h new file mode 100644 index 00000000..666f5fed --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_2DAngle.h @@ -0,0 +1,36 @@ +#ifndef Crit3_2DAngle_h +#define Crit3_2DAngle_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the angle between two 2-segments in the xy - plane + */ + class Crit3_2DAngle : public ICriterion{ + + + + public: + + /** + * @param angleMax the maximum angle between 2 2-segments in grad + */ + Crit3_2DAngle ( float angleMin, float angleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_2DAngle(){}; + + private: + + float _cosAngleMin{}; + float _cosAngleMax{}; + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.cc b/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.cc new file mode 100644 index 00000000..a70c962d --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.cc @@ -0,0 +1,134 @@ +#include "Criteria/Crit3_2DAngleTimesR.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + + +using namespace KiTrack; + +Crit3_2DAngleTimesR::Crit3_2DAngleTimesR ( float angleMin, float angleMax ){ + + + _angleMin = angleMin; + _angleMax = angleMax; + + _name = "Crit3_2DAngleTimesR"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_2DAngleTimesR::areCompatible( Segment* parent , Segment* child ) { + + + //this is not written very beautiful, because this code gets called often and needs to be fast. + //But it's just a simple angle calculation of two vectors cos(alpha) = u*v/|u||v| + // + //Because of speed, I avoided using stuff like sqrt or cos or something in here. + //That's why it may look a bit odd. + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //this is a criterion for 2-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + float ux = bx - ax; + float uy = by - ay; + + + float vx = cx - bx; + float vy = cy - by; + + + //In the numerator there is the vector product of u and v + double numerator= ux*vx + uy*vy; + + //In the denominator there are the lengths of u and v (here squared) + double uSquared= ux*ux + uy*uy; + double vSquared= vx*vx + vy*vy; + + + + double denomSquared = uSquared * vSquared; + + if (_saveValues){ + + _map_name_value["Crit3_2DAngleTimesR"] = 0.; + + } + + if ( denomSquared > 0.){ //don't divide by 0 + + double cosThetaSquared = numerator * numerator / ( uSquared * vSquared ); + if( cosThetaSquared > 1. ) cosThetaSquared = 1; // prevent rounding errors: cosTheta can mathematically never be bigger than 1!!! + double angle = acos( sqrt( cosThetaSquared ) ) * 180. / M_PI; + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + double R = circle.getRadius(); + + double angleTimesR = R * angle; + + if (_saveValues){ + + _map_name_value["Crit3_2DAngleTimesR"] = angleTimesR; + + } + + if ( angleTimesR < _angleMin ) return false; + if ( angleTimesR > _angleMax ) return false; + + } + catch( InvalidParameter ){ + + + } + + + } + + + } + else{ + + std::stringstream s; + s << "Crit3_2DAngleTimesR::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.h b/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.h new file mode 100644 index 00000000..8025583f --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_2DAngleTimesR.h @@ -0,0 +1,36 @@ +#ifndef Crit3_2DAngleTimesR_h +#define Crit3_2DAngleTimesR_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the angle in the xy plane between two 2-segments multiplied by the radius of the circle they form + */ + class Crit3_2DAngleTimesR : public ICriterion{ + + + + public: + + /** + * @param angleMax the maximum angle between 2 2-segments in grad times radius + */ + Crit3_2DAngleTimesR ( float angleMin, float angleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_2DAngleTimesR(){}; + + private: + + float _angleMin{}; + float _angleMax{}; + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.cc b/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.cc new file mode 100644 index 00000000..bbe254fd --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.cc @@ -0,0 +1,124 @@ +#include "Criteria/Crit3_3DAngle.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +Crit3_3DAngle::Crit3_3DAngle ( float angleMin, float angleMax ){ + + + _cosAngleMin = cos ( angleMax * M_PI / 180. ); + _cosAngleMax = cos ( angleMin * M_PI / 180. ); + + _name = "Crit3_3DAngle"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_3DAngle::areCompatible( Segment* parent , Segment* child ) { + + + //this is not written very beautiful, because this code gets called often and needs to be fast. + //But it's just a simple angle calculation of two vectors cos(alpha) = u*v/|u||v| + // + //Because of speed, I avoided using stuff like sqrt or cos or something in here. + //That's why it may look a bit odd. + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //this is a criterion for 2-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + + float ux = bx - ax; + float uy = by - ay; + float uz = bz - az; + + float vx = cx - bx; + float vy = cy - by; + float vz = cz - bz; + + //In the numerator there is the vector product of u and v + double numerator= ux*vx + uy*vy + uz*vz; + + //In the denominator there are the lengths of u and v (here squared) + double uSquared= ux*ux + uy*uy + uz*uz; + double vSquared= vx*vx + vy*vy + vz*vz; + + + + double denomSquared = uSquared * vSquared; + + if (_saveValues){ + + _map_name_value["Crit3_3DAngle_cos3DAngleSquared"] = 1.; + _map_name_value["Crit3_3DAngle"] = 0.; + + } + + if ( denomSquared > 0.){ //don't divide by 0 + + double cosThetaSquared = numerator * numerator / ( uSquared * vSquared ); + if( cosThetaSquared > 1. ) cosThetaSquared = 1; // prevent rounding errors: cosTheta can mathematically never be bigger than 1!!! + + if (_saveValues){ + + _map_name_value["Crit3_3DAngle_cos3DAngleSquared"] = cosThetaSquared; + _map_name_value["Crit3_3DAngle"] = acos( sqrt( cosThetaSquared ) ) * 180. / M_PI; + + } + + if (cosThetaSquared < _cosAngleMin*_cosAngleMin) return false; + if (cosThetaSquared > _cosAngleMax*_cosAngleMax) return false; + + } + + + + + + + } + else{ + + std::stringstream s; + s << "Crit3_3DAngle::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.h b/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.h new file mode 100644 index 00000000..1c24922d --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_3DAngle.h @@ -0,0 +1,36 @@ +#ifndef Crit3_3DAngle_h +#define Crit3_3DAngle_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the angle between two 2-segments + */ + class Crit3_3DAngle : public ICriterion{ + + + + public: + + /** + * @param angleMax the maximum angle between 2 2-segments in grad + */ + Crit3_3DAngle ( float angleMin, float angleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_3DAngle(){}; + + private: + + float _cosAngleMin{}; + float _cosAngleMax{}; + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.cc b/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.cc new file mode 100644 index 00000000..ff52c6f5 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.cc @@ -0,0 +1,136 @@ +#include "Criteria/Crit3_3DAngleTimesR.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + + +using namespace KiTrack; + +Crit3_3DAngleTimesR::Crit3_3DAngleTimesR ( float angleMin, float angleMax ){ + + + _angleMin = angleMin; + _angleMax = angleMax; + + _name = "Crit3_3DAngleTimesR"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_3DAngleTimesR::areCompatible( Segment* parent , Segment* child ) { + + + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //this is a criterion for 2-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + + float ux = bx - ax; + float uy = by - ay; + float uz = bz - az; + + float vx = cx - bx; + float vy = cy - by; + float vz = cz - bz; + + //In the numerator there is the vector product of u and v + double numerator= ux*vx + uy*vy + uz*vz; + + //In the denominator there are the lengths of u and v (here squared) + double uSquared= ux*ux + uy*uy + uz*uz; + double vSquared= vx*vx + vy*vy + vz*vz; + + + + double denomSquared = uSquared * vSquared; + + if (_saveValues){ + + _map_name_value["Crit3_3DAngleTimesR"] = 0.; + + } + + if ( denomSquared > 0.){ //don't divide by 0 + + double cosThetaSquared = numerator * numerator / ( uSquared * vSquared ); + if( cosThetaSquared > 1. ) cosThetaSquared = 1; // prevent rounding errors: cosTheta can mathematically never be bigger than 1!!! + double angle = acos( sqrt( cosThetaSquared ) ) * 180. / M_PI; + + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + double R = circle.getRadius(); + + double angleTimesR = R * angle; + + if (_saveValues){ + + _map_name_value["Crit3_3DAngleTimesR"] = angleTimesR; + + } + + if ( angleTimesR < _angleMin ) return false; + if ( angleTimesR > _angleMax ) return false; + + } + catch( InvalidParameter ){ + + + } + + + } + + + + + + } + else{ + + std::stringstream s; + s << "Crit3_3DAngleTimesR::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.h b/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.h new file mode 100644 index 00000000..3a366a0d --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_3DAngleTimesR.h @@ -0,0 +1,36 @@ +#ifndef Crit3_3DAngleTimesR_h +#define Crit3_3DAngleTimesR_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: the angle between two 2-segments multiplied by the radius of the circle the segments form + */ + class Crit3_3DAngleTimesR : public ICriterion{ + + + + public: + + /** + * @param angleMax the maximum angle between 2 2-segments in grad times the radius of the circle the segments form + */ + Crit3_3DAngleTimesR ( float angleMin, float angleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_3DAngleTimesR(){}; + + private: + + float _angleMin{}; + float _angleMax{}; + + }; + +} + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.cc b/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.cc new file mode 100644 index 00000000..aec9768f --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.cc @@ -0,0 +1,91 @@ +#include "Criteria/Crit3_ChangeRZRatio.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + + +Crit3_ChangeRZRatio::Crit3_ChangeRZRatio( float minChange , float maxChange ){ + + + _ratioChangeMaxSquared = maxChange*maxChange; + _ratioChangeMinSquared = minChange*minChange; + + _name = "Crit3_ChangeRZRatio"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_ChangeRZRatio::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + + + // The rz ratios squared + + double ratioSquaredParent = 0.; + if ( az-bz != 0. ) ratioSquaredParent = ( (ax-bx)*(ax-bx) + (ay-by)*(ay-by) + (az-bz)*(az-bz) ) / ( (az-bz) * ( az-bz ) ); + + double ratioSquaredChild = 0.; + if ( cz-bz != 0. ) ratioSquaredChild = ( (cx-bx)*(cx-bx) + (cy-by)*(cy-by) + (cz-bz)*(cz-bz) ) / ( (cz-bz) * ( cz-bz ) ); + + double ratioOfRZRatioSquared = 0.; + + if (ratioSquaredChild != 0.) ratioOfRZRatioSquared = ratioSquaredParent / ratioSquaredChild; + + if (_saveValues) { + + _map_name_value["Crit3_ChangeRZRatio_ratioOfRZRatioSquared"] = ratioOfRZRatioSquared; + _map_name_value["Crit3_ChangeRZRatio"] = sqrt( ratioOfRZRatioSquared ); + + } + + if ( ratioOfRZRatioSquared > _ratioChangeMaxSquared ) return false; + if ( ratioOfRZRatioSquared < _ratioChangeMinSquared ) return false; + + + } + else{ + + std::stringstream s; + s << "Crit3_ChangeRZRatio::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + + return true; + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.h b/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.h new file mode 100644 index 00000000..a218523b --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_ChangeRZRatio.h @@ -0,0 +1,48 @@ +#ifndef Crit2_ChangeRZRatio_h +#define Crit2_ChangeRZRatio_h + +#include "Criteria/ICriterion.h" + + +namespace KiTrack{ + + /** Criterion: the change of the ratio of the distance of two hits over the z distance + */ + class Crit3_ChangeRZRatio : public ICriterion{ + + + + public: + + Crit3_ChangeRZRatio ( float minChange , float maxChange ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_ChangeRZRatio(){}; + + + private: + + float _ratioChangeMaxSquared{}; + float _ratioChangeMinSquared{}; + + + + }; + +} + + + + + + + + + + + + + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.cc b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.cc new file mode 100644 index 00000000..2e2486d3 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.cc @@ -0,0 +1,90 @@ +#include "Criteria/Crit3_IPCircleDist.h" + + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + +using namespace KiTrack; + + +Crit3_IPCircleDist::Crit3_IPCircleDist( float distToCircleMin , float distToCircleMax ){ + + _distToCircleMax = distToCircleMax; + _distToCircleMin = distToCircleMin; + + _name = "Crit3_IPCircleDist"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_IPCircleDist::areCompatible( Segment* parent , Segment* child ) { + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + double x = circle.getCenterX(); + double y = circle.getCenterY(); + double R = circle.getRadius(); + + double circleDistToIP = fabs( R - sqrt (x*x+y*y) ); + + if (_saveValues) _map_name_value["Crit3_IPCircleDist"] = circleDistToIP; + + if ( circleDistToIP > _distToCircleMax ) return false; + if ( circleDistToIP < _distToCircleMin ) return false; + + } + catch ( InvalidParameter ){ + + + if (_saveValues) _map_name_value["Crit3_IPCircleDist"] = 0.; + + } + + + + } + else{ + + std::stringstream s; + s << "Crit3_IPCircleDist::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + } + + + return true; + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.h b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.h new file mode 100644 index 00000000..08969069 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDist.h @@ -0,0 +1,47 @@ +#ifndef Crit2_IPCircleDist_h +#define Crit2_IPCircleDist_h + +#include "Criteria/ICriterion.h" + + +namespace KiTrack{ + + /** Criterion: the distance of the IP from the circle the 3 hits form (in the xy plane) + */ + class Crit3_IPCircleDist : public ICriterion{ + + + + public: + + Crit3_IPCircleDist ( float distToCircleMin , float distToCircleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_IPCircleDist(){}; + + + private: + + float _distToCircleMax{}; + float _distToCircleMin{}; + + + }; + +} + + + + + + + + + + + + + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.cc b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.cc new file mode 100644 index 00000000..cbda61ec --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.cc @@ -0,0 +1,90 @@ +#include "Criteria/Crit3_IPCircleDistTimesR.h" + + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + +using namespace KiTrack; + + +Crit3_IPCircleDistTimesR::Crit3_IPCircleDistTimesR( float distToCircleMin , float distToCircleMax ){ + + _distToCircleMax = distToCircleMax; + _distToCircleMin = distToCircleMin; + + _name = "Crit3_IPCircleDistTimesR"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_IPCircleDistTimesR::areCompatible( Segment* parent , Segment* child ) { + + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + double x = circle.getCenterX(); + double y = circle.getCenterY(); + double R = circle.getRadius(); + + double circleDistToIPTimesR = fabs( R - sqrt (x*x+y*y) ) * R; + + if (_saveValues) _map_name_value["Crit3_IPCircleDistTimesR"] = circleDistToIPTimesR; + + if ( circleDistToIPTimesR > _distToCircleMax ) return false; + if ( circleDistToIPTimesR < _distToCircleMin ) return false; + + } + catch ( InvalidParameter ){ + + + if (_saveValues) _map_name_value["Crit3_IPCircleDistTimesR"] = 0.; + + } + + + + } + else{ + + std::stringstream s; + s << "Crit3_IPCircleDistTimesR::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + } + + + return true; + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.h b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.h new file mode 100644 index 00000000..3800ed9c --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_IPCircleDistTimesR.h @@ -0,0 +1,40 @@ +#ifndef Crit3_IPCircleDistTimesR_h +#define Crit3_IPCircleDistTimesR_h + +#include "Criteria/ICriterion.h" + + +namespace KiTrack{ + + /** Criterion: the distance of the circle formed by the two segments from the IP multiplied by R + */ + class Crit3_IPCircleDistTimesR : public ICriterion{ + + + + public: + + Crit3_IPCircleDistTimesR ( float distToCircleMin , float distToCircleMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_IPCircleDistTimesR(){}; + + + private: + + float _distToCircleMax{}; + float _distToCircleMin{}; + + + }; + +} + + + + + + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.cc b/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.cc new file mode 100644 index 00000000..d2523735 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.cc @@ -0,0 +1,93 @@ +#include "Criteria/Crit3_NoZigZag_MV.h" + +#include <cmath> +#include <sstream> + +#include "TVector3.h" + + +using namespace KiTrack; + +Crit3_NoZigZag_MV::Crit3_NoZigZag_MV ( float prodMin , float prodMax ){ + + + _prodMin = prodMin; + _prodMax = prodMax; + + _name = "Crit3_NoZigZag_MV"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_NoZigZag_MV::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //this is a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + double thetaa = a->getTheta(); + double thetab = b->getTheta(); + double thetac = c->getTheta(); + + + double angleXY1 = thetac - thetab; //the angle between 2-segments in the xy plane + double angleXY2 = thetab - thetaa; + + + if ( a->isVirtual() ) { angleXY2 = 0 ; } + + angleXY1 -= 2*M_PI*floor( angleXY1 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY1 > M_PI) angleXY1 -= 2*M_PI; //to the range from -pi to pi + + angleXY2 -= 2*M_PI*floor( angleXY2 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY2 > M_PI) angleXY2 -= 2*M_PI; //to the range from -pi to pi + + + // to grad + angleXY1 *= 180./M_PI; + angleXY2 *= 180./M_PI; + + float prod = angleXY1 * angleXY2; // if the direction of curvature stays the same, both anlges have the same sign-> and therefore the product is positive + + + //streamlog_out(DEBUG4) << " parent layer " << Layerc << " theta " << (180*thetac)/M_PI << " child first hit layer " << Layera << " theta = " << (180*thetaa)/M_PI << " child second hit layer " << Layerb << " theta = " << (180*thetab)/M_PI << " angleXY1 " << angleXY1 << " angleXY2 " << angleXY2 << " prod " << prod << std::endl ; + + + + if (_saveValues) _map_name_value["Crit3_NoZigZag_MV_angle1"] = angleXY1; + if (_saveValues) _map_name_value["Crit3_NoZigZag_MV_angle2"] = angleXY2; + if (_saveValues) _map_name_value["Crit3_NoZigZag_MV"] = prod; + + if ( prod < _prodMin ) return false; + if ( prod > _prodMax ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit3_NoZigZag_MV::This criterion needs 2 segments with 2 mini-vectors each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.h b/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.h new file mode 100644 index 00000000..3dcf6f89 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_NoZigZag_MV.h @@ -0,0 +1,39 @@ +#ifndef Crit3_NoZigZag_MV_h +#define Crit3_NoZigZag_MV_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: forbids zig zagging: measure the angles in the xy plane, transpose them to the range from -pi to pi + * and multiply: if there is a zigzag, the sign of the angle switches and the product of both angles becomes + * negative. + */ + class Crit3_NoZigZag_MV : public ICriterion{ + + + + public: + + /** + * @param prodMin the minimum product of the two angles in degrees + * + * @param prodMax the maxinum product of the two angles in degrees + */ + Crit3_NoZigZag_MV ( float prodMin , float prodMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_NoZigZag_MV(){}; + + private: + + float _prodMin{}; + float _prodMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit3_PT.cc b/Utilities/KiTrack/src/Criteria/Crit3_PT.cc new file mode 100644 index 00000000..7b22dade --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_PT.cc @@ -0,0 +1,99 @@ +#include "Criteria/Crit3_PT.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + +using namespace KiTrack; + + +Crit3_PT::Crit3_PT( float ptMin , float ptMax , float Bz ){ + + _ptMin = ptMin; + _ptMax = ptMax; + _Bz = Bz; + + _name = "Crit3_PT"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_PT::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + + double R = circle.getRadius(); + + + // check if pt is bigger than _ptMin + // + // |omega| = K*Bz/pt + // R = pt / (K*Bz) + // pt = R * K *Bz + // + + const double K= 0.00029979; //K depends on the used units + + double pt = R * K * _Bz; + + if (_saveValues) _map_name_value["Crit3_PT"] = pt; + + if ( pt < _ptMin ) return false; + if ( pt > _ptMax ) return false; + + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit3_PT"] = 0.; + + } + + + + } + else{ + + std::stringstream s; + s << "Crit3_PT::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_PT.h b/Utilities/KiTrack/src/Criteria/Crit3_PT.h new file mode 100644 index 00000000..46e4f0f2 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_PT.h @@ -0,0 +1,48 @@ +#ifndef Crit2_PT_h +#define Crit2_PT_h + +#include "Criteria/ICriterion.h" + + +namespace KiTrack{ + + /** Criterion: the transversal momentum + */ + class Crit3_PT : public ICriterion{ + + + + public: + + Crit3_PT ( float ptMin , float ptMax , float Bz = 3.5 ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_PT(){}; + + + private: + + float _ptMin{}; + float _ptMax{}; + float _Bz{}; + + + }; + +} + + + + + + + + + + + + + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.cc b/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.cc new file mode 100644 index 00000000..da921091 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.cc @@ -0,0 +1,99 @@ +#include "Criteria/Crit3_PT_MV.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + +using namespace KiTrack; + + +Crit3_PT_MV::Crit3_PT_MV( float ptMin , float ptMax , float Bz ){ + + _ptMin = ptMin; + _ptMax = ptMax; + _Bz = Bz; + + _name = "Crit3_PT_MV"; + _type = "3Hit"; + + _saveValues = false; + +} + + + +bool Crit3_PT_MV::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 2 )&&( child->getHits().size() == 2 )){ //a criterion for 2-segments + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = parent-> getHits()[1]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + + double R = circle.getRadius(); + + + // check if pt is bigger than _ptMin + // + // |omega| = K*Bz/pt + // R = pt / (K*Bz) + // pt = R * K *Bz + // + + const double K= 0.00029979; //K depends on the used units + + double pt = R * K * _Bz; + + if (_saveValues) _map_name_value["Crit3_PT_MV"] = pt; + + if ( pt < _ptMin ) return false; + if ( pt > _ptMax ) return false; + + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit3_PT_MV"] = 0.; + + } + + + + } + else{ + + std::stringstream s; + s << "Crit3_PT_MV::This criterion needs 2 segments with 2 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + +} diff --git a/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.h b/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.h new file mode 100644 index 00000000..86ef0369 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit3_PT_MV.h @@ -0,0 +1,48 @@ +#ifndef Crit2_PT_MV_h +#define Crit2_PT_MV_h + +#include "Criteria/ICriterion.h" + + +namespace KiTrack{ + + /** Criterion: the transversal momentum + */ + class Crit3_PT_MV : public ICriterion{ + + + + public: + + Crit3_PT_MV ( float ptMin , float ptMax , float Bz = 3.5 ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit3_PT_MV(){}; + + + private: + + float _ptMin{}; + float _ptMax{}; + float _Bz{}; + + + }; + +} + + + + + + + + + + + + + +#endif + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.cc b/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.cc new file mode 100644 index 00000000..b406bf88 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.cc @@ -0,0 +1,101 @@ +#include "Criteria/Crit4_2DAngleChange.h" + +#include <cmath> +#include <sstream> + +#include "TVector3.h" + + +using namespace KiTrack; + +Crit4_2DAngleChange::Crit4_2DAngleChange ( float changeMin , float changeMax ){ + + + _changeMax = changeMax; + _changeMin = changeMin; + + _name = "Crit4_2DAngleChange"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_2DAngleChange::areCompatible( Segment* parent , Segment* child ) { + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + + + TVector3 outerVec (bx-ax , by-ay , bz-az ); + TVector3 middleVec (cx-bx , cy-by , cz-bz ); + TVector3 innerVec (dx-cx , dy-cy , dz-cz ); + + + + + double angleXY1 = outerVec.Phi()-middleVec.Phi(); //the angle between 2-segments in the xy plane + double angleXY2 = middleVec.Phi()-innerVec.Phi(); + + angleXY1 -= 2*M_PI*floor( angleXY1 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY1 > M_PI) angleXY1 -= 2*M_PI; //to the range from -pi to pi + + angleXY2 -= 2*M_PI*floor( angleXY2 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY2 > M_PI) angleXY2 -= 2*M_PI; //to the range from -pi to pi + + + float ratioOf2DAngles = angleXY1 / angleXY2 ; + + if (_saveValues) _map_name_value["Crit4_2DAngleChange"] = ratioOf2DAngles; + + if ( ratioOf2DAngles > _changeMax ) return false; + if ( ratioOf2DAngles < _changeMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit4_2DAngleChange::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.h b/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.h new file mode 100644 index 00000000..c3bcb65d --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_2DAngleChange.h @@ -0,0 +1,35 @@ +#ifndef Crit4_2DAngleChange_h +#define Crit4_2DAngleChange_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: change of the angle (in the xy plane) between segments in the xy plane + */ + class Crit4_2DAngleChange : public ICriterion{ + + + + public: + + /** + * @param changeMax + */ + Crit4_2DAngleChange ( float changeMin , float changeMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_2DAngleChange(){}; + + private: + + float _changeMin{}; + float _changeMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.cc b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.cc new file mode 100644 index 00000000..d6a8c5da --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.cc @@ -0,0 +1,101 @@ +#include "Criteria/Crit4_3DAngleChange.h" + +#include <cmath> +#include <sstream> + +#include "TVector3.h" + + +using namespace KiTrack; + +Crit4_3DAngleChange::Crit4_3DAngleChange ( float changeMin , float changeMax ){ + + + _changeMax = changeMax; + _changeMin = changeMin; + + _name = "Crit4_3DAngleChange"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_3DAngleChange::areCompatible( Segment* parent , Segment* child ) { + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + + + TVector3 outerVec (bx-ax , by-ay , bz-az ); + TVector3 middleVec (cx-bx , cy-by , cz-bz ); + TVector3 innerVec (dx-cx , dy-cy , dz-cz ); + + + + + double angleXY1 = outerVec.Angle( middleVec ); + double angleXY2 = middleVec.Angle( innerVec ); + + angleXY1 -= 2*M_PI*floor( angleXY1 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY1 > M_PI) angleXY1 -= 2*M_PI; //to the range from -pi to pi + + angleXY2 -= 2*M_PI*floor( angleXY2 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY2 > M_PI) angleXY2 -= 2*M_PI; //to the range from -pi to pi + + + float ratioOf3DAngles = angleXY1 / angleXY2 ; + + if (_saveValues) _map_name_value["Crit4_3DAngleChange"] = ratioOf3DAngles; + + if ( ratioOf3DAngles > _changeMax ) return false; + if ( ratioOf3DAngles < _changeMin ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit4_3DAngleChange::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.h b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.h new file mode 100644 index 00000000..84351869 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChange.h @@ -0,0 +1,35 @@ +#ifndef Crit4_3DAngleChange_h +#define Crit4_3DAngleChange_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: change of the angle between segments + */ + class Crit4_3DAngleChange : public ICriterion{ + + + + public: + + /** + * @param changeMax + */ + Crit4_3DAngleChange ( float changeMin , float changeMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_3DAngleChange(){}; + + private: + + float _changeMin{}; + float _changeMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.cc b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.cc new file mode 100644 index 00000000..ade7136d --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.cc @@ -0,0 +1,124 @@ +#include "Criteria/Crit4_3DAngleChangeNormed.h" + +#include <cmath> +#include <sstream> + +#include "TVector3.h" +#include "Criteria/SimpleCircle.h" + + +using namespace KiTrack; + +Crit4_3DAngleChangeNormed::Crit4_3DAngleChangeNormed ( float changeMin , float changeMax ){ + + + _changeMax = changeMax; + _changeMin = changeMin; + + _name = "Crit4_3DAngleChangeNormed"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_3DAngleChangeNormed::areCompatible( Segment* parent , Segment* child ) { + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + + + TVector3 outerVec (bx-ax , by-ay , bz-az ); + TVector3 middleVec (cx-bx , cy-by , cz-bz ); + TVector3 innerVec (dx-cx , dy-cy , dz-cz ); + + + + + double angleXY1 = outerVec.Angle( middleVec ); + double angleXY2 = middleVec.Angle( innerVec ); + + angleXY1 -= 2*M_PI*floor( angleXY1 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY1 > M_PI) angleXY1 -= 2*M_PI; //to the range from -pi to pi + + angleXY2 -= 2*M_PI*floor( angleXY2 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY2 > M_PI) angleXY2 -= 2*M_PI; //to the range from -pi to pi + + + try{ + + SimpleCircle circle1 ( ax , ay , bx , by , cx , cy ); + SimpleCircle circle2 ( bx , by , cx , cy , dx , dy ); + + + float R = ( circle1.getRadius() + circle2.getRadius() ) / 2.; + + + float ratioOf3DAngles = angleXY1 / angleXY2 ; + + float ratioNormed = ( (ratioOf3DAngles -1. ) * R ) + 1; + + if (_saveValues) _map_name_value["Crit4_3DAngleChangeNormed"] = ratioNormed; + + if ( ratioNormed > _changeMax ) return false; + if ( ratioNormed < _changeMin ) return false; + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit4_3DAngleChangeNormed"] = 0.; + + + } + + + + + + + } + else{ + + std::stringstream s; + s << "Crit4_3DAngleChangeNormed::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.h b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.h new file mode 100644 index 00000000..691d0060 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_3DAngleChangeNormed.h @@ -0,0 +1,35 @@ +#ifndef Crit4_3DAngleChangeNormed_h +#define Crit4_3DAngleChangeNormed_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: check for the change of the 3D angle and normalise it with R + */ + class Crit4_3DAngleChangeNormed : public ICriterion{ + + + + public: + + /** + * @param changeMax + */ + Crit4_3DAngleChangeNormed ( float changeMin , float changeMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_3DAngleChangeNormed(){}; + + private: + + float _changeMin{}; + float _changeMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.cc b/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.cc new file mode 100644 index 00000000..2f0ecbac --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.cc @@ -0,0 +1,110 @@ +#include "Criteria/Crit4_DistOfCircleCenters.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + + +using namespace KiTrack; + +Crit4_DistOfCircleCenters::Crit4_DistOfCircleCenters ( float distMin , float distMax ){ + + + _distMax = distMax; + _distMin = distMin; + + _name = "Crit4_DistOfCircleCenters"; + _type = "4Hit"; + + _saveValues = false; + + +} + + + +bool Crit4_DistOfCircleCenters::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + + + float ax = a->getX(); + float ay = a->getY(); +// float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); +// float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); +// float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); +// float dz = d->getZ(); + + + + try{ + + SimpleCircle circle1 ( ax , ay , bx , by , cx , cy ); + SimpleCircle circle2 ( bx , by , cx , cy , dx , dy ); + + + float X1 = circle1.getCenterX(); + float Y1 = circle1.getCenterY(); + + float X2 = circle2.getCenterX(); + float Y2 = circle2.getCenterY(); + + + float distOfCircleCenters = sqrt( (X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1) ); + + if (_saveValues) _map_name_value["Crit4_DistOfCircleCenters"] = distOfCircleCenters; + + + if ( distOfCircleCenters > _distMax ) return false; + if ( distOfCircleCenters < _distMin ) return false; + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit4_DistOfCircleCenters"] = 0.; + + + } + + + } + else{ + + std::stringstream s; + s << "Crit4_DistOfCircleCenters::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() <<" hit segment (child)."; + + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.h b/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.h new file mode 100644 index 00000000..c7d4a943 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_DistOfCircleCenters.h @@ -0,0 +1,35 @@ +#ifndef Crit4_DistOfCircleCenters_h +#define Crit4_DistOfCircleCenters_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: make circles from the semgments and measure the distances of their centers + */ + class Crit4_DistOfCircleCenters : public ICriterion{ + + + + public: + + /** + * @param distMax + */ + Crit4_DistOfCircleCenters ( float distMin , float distMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_DistOfCircleCenters(){}; + + private: + + float _distMax{}; + float _distMin{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.cc b/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.cc new file mode 100644 index 00000000..b993f45e --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.cc @@ -0,0 +1,119 @@ +#include "Criteria/Crit4_DistToExtrapolation.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" +#include "TVector3.h" + + + +using namespace KiTrack; + +Crit4_DistToExtrapolation::Crit4_DistToExtrapolation ( float distMin , float distMax ){ + + + _distMin = distMin; + _distMax = distMax; + + _name = "Crit4_DistToExtrapolation"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_DistToExtrapolation::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); +// float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + try{ + + SimpleCircle circle ( ax , ay , bx , by , cx , cy ); + + + double centerX = circle.getCenterX(); + double centerY = circle.getCenterY(); + double R = circle.getRadius(); + + TVector3 u ( bx - centerX , by - centerY , bz ); + TVector3 v ( cx - centerX , cy - centerY , cz ); + + + double deltaPhiParent = v.Phi() - u.Phi(); //angle in xy plane from center of circle, between point 2 and 3 + + // use this angle and the distance to the next layer to extrapolate + double zDistParent = fabs( cz - bz ); + double zDistChild = fabs( dz - cz ); + + double deltaPhiChild = deltaPhiParent * zDistChild / zDistParent ; + + double phiChild = v.Phi() + deltaPhiChild; + + double xChildPred = centerX + R* cos(phiChild); + double yChildPred = centerY + R* sin(phiChild); + + + double DistToPrediction = sqrt ( ( xChildPred- dx )*( xChildPred- dx ) + ( yChildPred- dy )*( yChildPred- dy ) ); + double distNormed = DistToPrediction / zDistChild; + + if (_saveValues) _map_name_value["Crit4_DistToExtrapolation"] = distNormed; + + if ( distNormed > _distMax ) return false; + if ( distNormed < _distMin ) return false; + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit4_DistToExtrapolation"] = -1.; + + } + + } + else{ + + std::stringstream s; + s << "Crit4_DistToExtrapolation::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.h b/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.h new file mode 100644 index 00000000..726e4434 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_DistToExtrapolation.h @@ -0,0 +1,37 @@ +#ifndef Crit4_DistToExtrapolation_h +#define Crit4_DistToExtrapolation_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: use the first 3 hits to extrapolate the location in xy for a given z of the last hit. + * Then measure the distance from the extrapolation to the hit. (Also divide by the z distance to the last hit, + * in order to take into account that with farther distances the accuracy drops) + */ + class Crit4_DistToExtrapolation : public ICriterion{ + + + + public: + + /** + * @param distMax + */ + Crit4_DistToExtrapolation ( float distMin , float distMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_DistToExtrapolation(){}; + + private: + + float _distMin{}; + float _distMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.cc b/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.cc new file mode 100644 index 00000000..3f00d4be --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.cc @@ -0,0 +1,108 @@ +#include "Criteria/Crit4_NoZigZag.h" + +#include <cmath> +#include <sstream> + +#include "TVector3.h" + + +using namespace KiTrack; + +Crit4_NoZigZag::Crit4_NoZigZag ( float prodMin , float prodMax ){ + + + _prodMin = prodMin; + _prodMax = prodMax; + + _name = "Crit4_NoZigZag"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_NoZigZag::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); + float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + + + TVector3 outerVec (bx-ax , by-ay , bz-az ); + TVector3 middleVec (cx-bx , cy-by , cz-bz ); + TVector3 innerVec (dx-cx , dy-cy , dz-cz ); + + + + + double angleXY1 = outerVec.Phi()-middleVec.Phi(); //the angle between 2-segments in the xy plane + double angleXY2 = middleVec.Phi()-innerVec.Phi(); + + angleXY1 -= 2*M_PI*floor( angleXY1 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY1 > M_PI) angleXY1 -= 2*M_PI; //to the range from -pi to pi + + angleXY2 -= 2*M_PI*floor( angleXY2 /2. /M_PI ); //to the range from 0 to 2pi + if (angleXY2 > M_PI) angleXY2 -= 2*M_PI; //to the range from -pi to pi + + + // to grad + angleXY1 *= 180./M_PI; + angleXY2 *= 180./M_PI; + + float prod = angleXY1 * angleXY2; // if the direction of curvature stays the same, both anlges have the same sign-> and therefore the product is positive + + if (_saveValues) _map_name_value["Crit4_NoZigZag_angle1"] = angleXY1; + if (_saveValues) _map_name_value["Crit4_NoZigZag_angle2"] = angleXY2; + if (_saveValues) _map_name_value["Crit4_NoZigZag"] = prod; + + if ( prod < _prodMin ) return false; + if ( prod > _prodMax ) return false; + + + + } + else{ + + std::stringstream s; + s << "Crit4_NoZigZag::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.h b/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.h new file mode 100644 index 00000000..5ca64cee --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_NoZigZag.h @@ -0,0 +1,39 @@ +#ifndef Crit4_NoZigZag_h +#define Crit4_NoZigZag_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: forbids zig zagging: measure the angles in the xy plane, transpose them to the range from -pi to pi + * and multiply: if there is a zigzag, the sign of the angle switches and the product of both angles becomes + * negative. + */ + class Crit4_NoZigZag : public ICriterion{ + + + + public: + + /** + * @param prodMin the minimum product of the two angles in degrees + * + * @param prodMax the maxinum product of the two angles in degrees + */ + Crit4_NoZigZag ( float prodMin , float prodMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_NoZigZag(){}; + + private: + + float _prodMin{}; + float _prodMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.cc b/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.cc new file mode 100644 index 00000000..e6c4db21 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.cc @@ -0,0 +1,120 @@ +#include "Criteria/Crit4_PhiZRatioChange.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" +#include "TVector3.h" + + + +using namespace KiTrack; + +Crit4_PhiZRatioChange::Crit4_PhiZRatioChange ( float changeMin , float changeMax ){ + + + _changeMin = changeMin; + _changeMax = changeMax; + + _name = "Crit4_PhiZRatioChange"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_PhiZRatioChange::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); +// float az = a->getZ(); + + float bx = b->getX(); + float by = b->getY(); + float bz = b->getZ(); + + float cx = c->getX(); + float cy = c->getY(); + float cz = c->getZ(); + + float dx = d->getX(); + float dy = d->getY(); + float dz = d->getZ(); + + try{ + + SimpleCircle circle1 ( ax , ay , bx , by , cx , cy ); + SimpleCircle circle2 ( bx , by , cx , cy , dx , dy ); + + + float X1 = circle1.getCenterX(); + float Y1 = circle1.getCenterY(); + float X2 = circle2.getCenterX(); + float Y2 = circle2.getCenterY(); + + + + TVector3 u ( bx - X1, by - Y1 , 0.); //vector from center of circle to point + TVector3 v ( cx - X1, cy - Y1 , 0.); + float zDist1 = fabs( cz - bz ); + float phi1 = u.Angle( v ); + float phiZRatio1 = phi1 / zDist1; + + TVector3 s ( cx - X2, cy - Y2 , 0.); //vector from center of circle to point + TVector3 t ( dx - X2, dy - Y2 , 0.); + float zDist2 = fabs( dz - cz ); + float phi2 = s.Angle( t ); + float phiZRatio2 = phi2 / zDist2; + + + float ratioOfPhiZRatio = phiZRatio1 / phiZRatio2; + + if (_saveValues) _map_name_value["Crit4_PhiZRatioChange"] = ratioOfPhiZRatio; + + + + if ( ratioOfPhiZRatio > _changeMax ) return false; + if ( ratioOfPhiZRatio < _changeMin ) return false; + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit4_PhiZRatioChange"] = 1.; + + } + + + + } + else{ + + std::stringstream s; + s << "Crit4_PhiZRatioChange::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.h b/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.h new file mode 100644 index 00000000..d8f41b1c --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_PhiZRatioChange.h @@ -0,0 +1,35 @@ +#ifndef Crit4_PhiZRatioChange_h +#define Crit4_PhiZRatioChange_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: check for the change of \f$ \frac{\phi}{Z} \f$. (\f$ \phi \f$ = angle in the circle formed by the hits) + */ + class Crit4_PhiZRatioChange : public ICriterion{ + + + + public: + + /** + * @param changeMax + */ + Crit4_PhiZRatioChange ( float changeMin , float changeMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_PhiZRatioChange(){}; + + private: + + float _changeMin{}; + float _changeMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Crit4_RChange.cc b/Utilities/KiTrack/src/Criteria/Crit4_RChange.cc new file mode 100644 index 00000000..ea7e4257 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_RChange.cc @@ -0,0 +1,97 @@ +#include "Criteria/Crit4_RChange.h" + +#include <cmath> +#include <sstream> + +#include "Criteria/SimpleCircle.h" + + + +using namespace KiTrack; + +Crit4_RChange::Crit4_RChange ( float changeMin , float changeMax ){ + + + _changeMin = changeMin; + _changeMax = changeMax; + + _name = "Crit4_RChange"; + _type = "4Hit"; + + _saveValues = false; + +} + + + +bool Crit4_RChange::areCompatible( Segment* parent , Segment* child ) { + + + + if (( parent->getHits().size() == 3 )&&( child->getHits().size() == 3 )){ //this is a criterion for 3-segments + + + + IHit* a = child->getHits()[0]; + IHit* b = child->getHits()[1]; + IHit* c = child->getHits()[2]; + IHit* d = parent-> getHits()[2]; + + float ax = a->getX(); + float ay = a->getY(); + + float bx = b->getX(); + float by = b->getY(); + + float cx = c->getX(); + float cy = c->getY(); + + float dx = d->getX(); + float dy = d->getY(); + + try{ + + SimpleCircle circle1 ( ax , ay , bx , by , cx , cy ); + SimpleCircle circle2 ( bx , by , cx , cy , dx , dy ); + + float R1 = circle1.getRadius(); + float R2 = circle2.getRadius(); + + float ratioOfR = 1.; + if (R2 > 0) ratioOfR = R1/R2; + + if (_saveValues) _map_name_value["Crit4_RChange"] = ratioOfR; + + + + if ( ratioOfR > _changeMax ) return false; + if ( ratioOfR < _changeMin ) return false; + + } + catch ( InvalidParameter ){ + + if (_saveValues) _map_name_value["Crit4_RChange"] = 1.; + + } + + } + else{ + + std::stringstream s; + s << "Crit4_RChange::This criterion needs 2 segments with 3 hits each, passed was a " + << parent->getHits().size() << " hit segment (parent) and a " + << child->getHits().size() << " hit segment (child)."; + + + throw BadSegmentLength( s.str() ); + + + } + + + return true; + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/Crit4_RChange.h b/Utilities/KiTrack/src/Criteria/Crit4_RChange.h new file mode 100644 index 00000000..3b4c1d8b --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Crit4_RChange.h @@ -0,0 +1,35 @@ +#ifndef Crit4_RChange_h +#define Crit4_RChange_h + + +#include "Criteria/ICriterion.h" + +namespace KiTrack{ + + /** Criterion: check for the change of the radii of the circles that can be made from the 3-hit segments + */ + class Crit4_RChange : public ICriterion{ + + + + public: + + /** + * @param changeMax + */ + Crit4_RChange ( float changeMin , float changeMax ); + + virtual bool areCompatible( Segment* parent , Segment* child ); + + virtual ~Crit4_RChange(){}; + + private: + + float _changeMin{}; + float _changeMax{}; + + }; + +} + +#endif diff --git a/Utilities/KiTrack/src/Criteria/Criteria.cc b/Utilities/KiTrack/src/Criteria/Criteria.cc new file mode 100644 index 00000000..f8ea29a2 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/Criteria.cc @@ -0,0 +1,278 @@ +#include "Criteria/Criteria.h" +#include "Criteria/ICriterion.h" + +#include "Criteria/Crit2_RZRatio.h" +#include "Criteria/Crit2_StraightTrackRatio.h" +#include "Criteria/Crit2_DeltaPhi.h" +#include "Criteria/Crit2_HelixWithIP.h" +#include "Criteria/Crit2_DeltaRho.h" +#include "Criteria/Crit3_ChangeRZRatio.h" +#include "Criteria/Crit3_PT.h" +#include "Criteria/Crit3_2DAngle.h" +#include "Criteria/Crit3_2DAngleTimesR.h" +#include "Criteria/Crit3_3DAngle.h" +#include "Criteria/Crit3_3DAngleTimesR.h" +#include "Criteria/Crit3_IPCircleDist.h" +#include "Criteria/Crit3_IPCircleDistTimesR.h" + +#include "Criteria/Crit4_2DAngleChange.h" +#include "Criteria/Crit4_3DAngleChange.h" +#include "Criteria/Crit4_3DAngleChangeNormed.h" +#include "Criteria/Crit4_DistToExtrapolation.h" +#include "Criteria/Crit4_PhiZRatioChange.h" +#include "Criteria/Crit4_DistOfCircleCenters.h" +#include "Criteria/Crit4_NoZigZag.h" +#include "Criteria/Crit4_RChange.h" +// Criteria for Mini - Vector based Cellular Automaton for VXD +#include "Criteria/Crit2_DeltaPhi_MV.h" +#include "Criteria/Crit2_Distance_MV.h" +#include "Criteria/Crit2_DeltaTheta_MV.h" +#include "Criteria/Crit3_NoZigZag_MV.h" +#include "Criteria/Crit3_PT_MV.h" + +using namespace KiTrack; + +std::set< std::string > Criteria::getAllCriteriaNames(){ + + + std::set< std::string > critNames; + + critNames.insert( "Crit2_RZRatio" ); + critNames.insert( "Crit2_StraightTrackRatio" ); + critNames.insert( "Crit2_DeltaPhi" ); + critNames.insert( "Crit2_HelixWithIP" ); + critNames.insert( "Crit2_DeltaRho" ); + + critNames.insert( "Crit3_ChangeRZRatio" ); + critNames.insert( "Crit3_PT" ); + critNames.insert( "Crit3_2DAngle" ); + critNames.insert( "Crit3_2DAngleTimesR" ); + critNames.insert( "Crit3_3DAngle" ); + critNames.insert( "Crit3_3DAngleTimesR" ); + critNames.insert( "Crit3_IPCircleDist" ); + critNames.insert( "Crit3_IPCircleDistTimesR" ); + + + critNames.insert( "Crit4_2DAngleChange" ); + critNames.insert( "Crit4_3DAngleChange" ); + critNames.insert( "Crit4_3DAngleChangeNormed" ); + critNames.insert( "Crit4_DistToExtrapolation" ); + critNames.insert( "Crit4_PhiZRatioChange" ); + critNames.insert( "Crit4_DistOfCircleCenters" ); + critNames.insert( "Crit4_NoZigZag" ); + critNames.insert( "Crit4_RChange" ); + + // MiniVector based Cellular Automaton for VXD + + critNames.insert( "Crit2_DeltaPhi_MV" ); + critNames.insert( "Crit2_Distance_MV" ); + critNames.insert( "Crit2_DeltaTheta_MV" ); + critNames.insert( "Crit3_NoZigZag_MV" ); + critNames.insert( "Crit3_PT_MV" ); + + return critNames; + +} + + +std::set < std::string > Criteria::getTypes(){ + + std::set< std::string > critNames = getAllCriteriaNames(); + std::set< std::string > types; + + std::set< std::string >::iterator it; + + + for( it = critNames.begin(); it != critNames.end(); it++ ){ + + + ICriterion* crit = Criteria::createCriterion( *it ); + + types.insert( crit->getType() ); + + delete crit; + + + } + + return types; + + +} + + +std::set< std::string > Criteria::getCriteriaNames( std::string type ){ + + + std::set< std::string > criteria; + std::set< std::string > critNames = getAllCriteriaNames(); + + + std::set< std::string >::iterator it; + + for( it = critNames.begin(); it != critNames.end(); it++ ){ + + + ICriterion* crit = Criteria::createCriterion( *it ); + + if ( crit->getType() == type ) criteria.insert( *it ); + + delete crit; + + } + + return criteria; + + + + +} + + +ICriterion* Criteria::createCriterion( std::string critName, float min , float max ) { + + + + if ( critName == "Crit2_RZRatio" ) return ( new Crit2_RZRatio( min , max ) ); + + else if ( critName == "Crit2_StraightTrackRatio" ) return ( new Crit2_StraightTrackRatio( min , max ) ); + + else if ( critName == "Crit2_DeltaPhi" ) return ( new Crit2_DeltaPhi( min , max ) ); + + else if ( critName == "Crit2_HelixWithIP" ) return ( new Crit2_HelixWithIP( min , max ) ); + + else if ( critName == "Crit2_DeltaRho" ) return ( new Crit2_DeltaRho( min , max ) ); + + else if ( critName == "Crit3_ChangeRZRatio" ) return ( new Crit3_ChangeRZRatio( min , max ) ); + + else if ( critName == "Crit3_PT" ) return ( new Crit3_PT( min , max ) ); + + else if ( critName == "Crit3_2DAngle" ) return ( new Crit3_2DAngle( min , max ) ); + + else if ( critName == "Crit3_2DAngleTimesR" ) return ( new Crit3_2DAngleTimesR( min , max ) ); + + else if ( critName == "Crit3_3DAngle" ) return ( new Crit3_3DAngle( min , max ) ); + + else if ( critName == "Crit3_3DAngleTimesR" ) return ( new Crit3_3DAngleTimesR( min , max ) ); + + else if ( critName == "Crit3_IPCircleDist" ) return ( new Crit3_IPCircleDist( min , max ) ); + + else if ( critName == "Crit3_IPCircleDistTimesR" ) return ( new Crit3_IPCircleDistTimesR( min , max ) ); + + else if ( critName == "Crit4_2DAngleChange" ) return ( new Crit4_2DAngleChange( min , max ) ); + + else if ( critName == "Crit4_3DAngleChange" ) return ( new Crit4_3DAngleChange( min , max ) ); + + else if ( critName == "Crit4_3DAngleChangeNormed" ) return ( new Crit4_3DAngleChangeNormed( min , max ) ); + + else if ( critName == "Crit4_DistToExtrapolation" ) return ( new Crit4_DistToExtrapolation( min , max ) ); + + else if ( critName == "Crit4_PhiZRatioChange" ) return ( new Crit4_PhiZRatioChange( min , max ) ); + + else if ( critName == "Crit4_DistOfCircleCenters" ) return ( new Crit4_DistOfCircleCenters( min , max ) ); + + else if ( critName == "Crit4_NoZigZag" ) return ( new Crit4_NoZigZag( min , max ) ); + + else if ( critName == "Crit4_RChange" ) return ( new Crit4_RChange( min , max ) ); + + // Mini-Vector based + + else if ( critName == "Crit2_DeltaPhi_MV" ) return ( new Crit2_DeltaPhi_MV( min , max ) ); + + else if ( critName == "Crit2_Distance_MV" ) return ( new Crit2_Distance_MV( min , max ) ); + + else if ( critName == "Crit2_DeltaTheta_MV" ) return ( new Crit2_DeltaTheta_MV( min , max ) ); + + else if ( critName == "Crit3_NoZigZag_MV" ) return ( new Crit3_NoZigZag_MV( min , max ) ); + + else if ( critName == "Crit3_PT_MV" ) return ( new Crit3_PT_MV( min , max ) ); + + else { + + std::string s = "Criteria::The criterion \"" + critName + + "\" is not known. Make sure the class Criteria has this criterion listed in the createCriterion method"; + + throw UnknownCriterion( s ); + + } + + + + +} + + + +std::vector< std::string > Criteria::getAllCriteriaNamesVec(){ + + std::vector < std::string > allCriteriaNamesVec; + std::set< std::string > critNames = getAllCriteriaNames(); + + + std::set< std::string >::iterator it; + + for( it = critNames.begin(); it != critNames.end(); it++ ){ + + + allCriteriaNamesVec.push_back( *it ); + + } + + return allCriteriaNamesVec; + +} + + +void Criteria::getLeftRight( std::string critName, float & left, float & right ){ + + + if ( critName == "Crit2_RZRatio" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit2_RZRatio" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit2_StraightTrackRatio" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit2_DeltaPhi" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit2_HelixWithIP" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit2_DeltaRho" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit3_ChangeRZRatio" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit3_PT" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit3_2DAngle" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit3_2DAngleTimesR" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit3_3DAngle" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit3_3DAngleTimesR" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit3_IPCircleDist" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit3_IPCircleDistTimesR" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit4_2DAngleChange" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit4_3DAngleChange" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit4_3DAngleChangeNormed" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit4_DistToExtrapolation" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit4_PhiZRatioChange" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit4_DistOfCircleCenters" ) { left = 0.; right = 1.; } + + else if ( critName == "Crit4_NoZigZag" ) { left = 0.5; right = 0.5; } + + else if ( critName == "Crit4_RChange" ) { left = 0.5; right = 0.5; } + + else { left = 0.5; right = 0.5; } + + +} + + diff --git a/Utilities/KiTrack/src/Criteria/SimpleCircle.cc b/Utilities/KiTrack/src/Criteria/SimpleCircle.cc new file mode 100644 index 00000000..77d1a8bd --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/SimpleCircle.cc @@ -0,0 +1,90 @@ +#include "Criteria/SimpleCircle.h" + +#include <cmath> +#include <sstream> + + + +using namespace KiTrack; + +SimpleCircle::SimpleCircle( double x1 , double y1 , double x2 , double y2 , double x3, double y3 ) { + + + + // 1. check if they are not in a line, i.e. the slopes are parallel (or two or more points are identical) + + if ( (x2 -x1)*(y3 - y2) == (x3 - x2)*(y2 - y1) ){ + + + std::stringstream s; + + s << "SimpleCircle::The 3 points are on one line in xy-space: x1 = " + << x1 + << ", y1 = " << y1 + << ", x2 = " << x2 + << ", y2 = " << y2 + << ", x3 = " << x3 + << ", y3 = " << y3; + + throw InvalidParameter( s.str() ); + + + } + + + _R = 0; + _centerX = 0.; + _centerY = 0.; + + + _x1 = x1; + _y1 = y1; + _x2 = x2; + _y2 = y2; + _x3 = x3; + _y3 = y3; + + + //check if x1 and x2 or x2 and x3 are equal. If they are, swap them around, so that those are not 0. (or else the slopes get infinite) + // note that x1==x2==x3 is not possible as they would need to be on a line for that (and parallel, which we checked) + + if ( x1 == x2 ) { // x1 and x2 have the same x --> we swap the points around (still it stays the same circle) so the + // that they are now x1 and x3. because the line x1->x3 (i.e. its slope) isn't used in the calculations --> we don't care if it's zero. + + + _x2 = x3; + _y2 = y3; + _x3 = x2; + _y3 = y2; + + } + else if ( x2 == x3 ) { // x1 and x2 have the same x --> we swap the points around (still it stays the same circle) so the + // that they are now x1 and x3. because the line x1->x3 (i.e. its slope) isn't used in the calculations --> we don't care if it's zero. + + + _x2 = x1; + _y2 = y1; + _x1 = x2; + _y1 = y2; + + } + + + + double ma = (_y2-_y1)/(_x2-_x1); //slope + double mb = (_y3-_y2)/(_x3-_x2); + + + _centerX = ( ma*mb*(_y1-_y3) + mb*(_x1+_x2) - ma*(_x2+_x3) )/( 2.*(mb-ma)); + _centerY = (-1./ma) * ( _centerX - (_x1+_x2)/2. ) + (_y1+_y2)/2; + + _R = sqrt (( _x1 - _centerX )*( _x1 - _centerX ) + ( _y1 - _centerY )*( _y1 - _centerY )); + + + + + + + +} + diff --git a/Utilities/KiTrack/src/Criteria/SimpleCircle.h b/Utilities/KiTrack/src/Criteria/SimpleCircle.h new file mode 100644 index 00000000..2c7d2da2 --- /dev/null +++ b/Utilities/KiTrack/src/Criteria/SimpleCircle.h @@ -0,0 +1,55 @@ +#ifndef SimpleCircle_h +#define SimpleCircle_h + +#include "KiTrack/KiTrackExceptions.h" + +namespace KiTrack{ + +/** A simple class representing a circle. + * + * In the constructor it builds a cricle from 3 2-dimensional points. + * After that, the parameters can be read out (radius and position of the center) + */ +class SimpleCircle { + + + + public: + + + SimpleCircle ( double x1 , double y1 , double x2 , double y2 , double x3, double y3 ) ; + + double getRadius() {return _R;}; + double getCenterX() {return _centerX;}; + double getCenterY() {return _centerY;}; + + private: + + + double _R{}; + double _centerX{}; + double _centerY{}; + + double _x1{}; + double _x2{}; + double _x3{}; + + double _y1{}; + double _y2{}; + double _y3{}; + + + +}; + + + + +} // end of namespace KiTrack + + + + +#endif + + diff --git a/Utilities/KiTrack/src/ILDImpl/#FTDTrack.cc# b/Utilities/KiTrack/src/ILDImpl/#FTDTrack.cc# new file mode 100644 index 00000000..6d928c37 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/#FTDTrack.cc# @@ -0,0 +1,132 @@ +#include "ILDImpl/FTDTrack.h" + + +#include <algorithm> +#include <math.h> + +//#include "UTIL/LCTrackerConf.h" + +// Root, for calculating the chi2 probability. +#include "Math/ProbFunc.h" + + + +using namespace KiTrackMarlin; + +/** @return if the absolute z value of hit a is bigger than that of hit b */ +bool compare_IHit_z( IHit* a, IHit* b ){ + + return ( fabs( a->getZ() ) < fabs( b->getZ() ) ); //compare their z values + +} + + + +FTDTrack::FTDTrack( MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + + +} + +FTDTrack::FTDTrack( std::vector< IFTDHit* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + + for( unsigned i=0; i < hits.size(); i++ ){ + + addHit( hits[i] ); + + + } + +} + + +FTDTrack::FTDTrack( const FTDTrack& f ){ + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + +} + +FTDTrack & FTDTrack::operator= (const FTDTrack & f){ + + if (this == &f) return *this; //protect against self assignment + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + + return *this; + +} + + + +void FTDTrack::addHit( IFTDHit* hit ){ + if ( hit != NULL ){ + _hits.push_back( hit ); + // and sort the track again + sort( _hits.begin(), _hits.end(), compare_IHit_z ); + _lcioTrack->addToTrackerHits( *hit->getTrackerHit() ); + } +} + + + + + +void FTDTrack::fit() { + + + Fitter fitter( _lcioTrack , _trkSystem ); + + + _lcioTrack->setChi2( fitter.getChi2( 1/*by fucd AtIP=1 in LCIO, changed to CepC rule in future: lcio::TrackState::AtIP*/ ) ); + _lcioTrack->setNdf( fitter.getNdf( 1/*lcio::TrackState::AtIP*/ ) ); + _chi2Prob = fitter.getChi2Prob( 1/*lcio::TrackState::AtIP*/ ); + + edm4hep::TrackState trkState( *fitter.getTrackState( 1/*lcio::TrackState::AtIP*/ ) ) ; + trkState.location = 1/*lcio::TrackState::AtIP*/ ; + _lcioTrack->addToTrackStates( trkState ); + + +} + + +double FTDTrack::getQI() const{ + + + double QI = _chi2Prob; + + // make sure QI is between 0 and 1 + if (QI > 1. ) QI = 1.; + if (QI < 0. ) QI = 0.; + + return QI; + +} + + + + + + + diff --git a/Utilities/KiTrack/src/ILDImpl/FTDHit01.cc b/Utilities/KiTrack/src/ILDImpl/FTDHit01.cc new file mode 100644 index 00000000..a5eaab1c --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/FTDHit01.cc @@ -0,0 +1,44 @@ +#include "ILDImpl/FTDHit01.h" + + +#include "UTIL/ILDConf.h" + +using namespace KiTrackMarlin; + + +FTDHit01::FTDHit01( edm4hep::TrackerHit trackerHit , const SectorSystemFTD* const sectorSystemFTD ){ + + + _sectorSystemFTD = sectorSystemFTD; + + _trackerHit = trackerHit; + + //Set the position of the FTDHit01 + const edm4hep::Vector3d& pos= trackerHit.getPosition(); + _x = pos[0]; + _y = pos[1]; + _z = pos[2]; + + + //find out layer, module, sensor + + UTIL::BitField64 cellID( UTIL::ILDCellID0::encoder_string ); + + cellID.setValue( trackerHit.getCellID() ); + + _side = cellID[ UTIL::ILDCellID0::side ]; + _module = cellID[ UTIL::ILDCellID0::module ]; + _sensor = cellID[ UTIL::ILDCellID0::sensor ] - 1; + _layer = cellID[ UTIL::ILDCellID0::layer ] + 1; + + + calculateSector(); + + + //We assume a real hit. If it is virtual, this has to be set. + _isVirtual = false; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/FTDHitSimple.cc b/Utilities/KiTrack/src/ILDImpl/FTDHitSimple.cc new file mode 100644 index 00000000..57824a74 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/FTDHitSimple.cc @@ -0,0 +1,30 @@ +#include "ILDImpl/FTDHitSimple.h" + + +using namespace KiTrackMarlin; + +FTDHitSimple::FTDHitSimple( float x , float y , float z , int side, unsigned layer , unsigned module, unsigned sensor, const SectorSystemFTD* const sectorSystemFTD ){ + + + _sectorSystemFTD = sectorSystemFTD; + + _x = x; + _y = y; + _z = z; + + + _side = side; + _layer = layer; + _module = module; + _sensor = sensor; + + + calculateSector(); + + + //We assume a real hit. If it is virtual, this has to be set. + _isVirtual = false; + + +} + diff --git a/Utilities/KiTrack/src/ILDImpl/FTDNeighborPetalSecCon.cc b/Utilities/KiTrack/src/ILDImpl/FTDNeighborPetalSecCon.cc new file mode 100644 index 00000000..30e80147 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/FTDNeighborPetalSecCon.cc @@ -0,0 +1,56 @@ +#include "ILDImpl/FTDNeighborPetalSecCon.h" + + +using namespace KiTrackMarlin; + + +FTDNeighborPetalSecCon::FTDNeighborPetalSecCon( const SectorSystemFTD* sectorSystemFTD ){ + + _sectorSystemFTD = sectorSystemFTD; + +} + + + +std::set< int > FTDNeighborPetalSecCon::getTargetSectors ( int sector ){ + + + + std::set <int> targetSectors; + + + int side = _sectorSystemFTD->getSide( sector ); + unsigned layer = _sectorSystemFTD->getLayer( sector ); + unsigned petal = _sectorSystemFTD->getModule( sector ); +// unsigned sensor = _sectorSystemFTD->getSensor( sector ); + +// unsigned nLayers = _sectorSystemFTD->getNumberOfLayers(); + unsigned nPetals = _sectorSystemFTD->getNumberOfModules(); + unsigned nSensors = _sectorSystemFTD->getNumberOfSensors(); + + + unsigned petalToTheLeft = petal - 1; //the names left and right are arbitrary, as it of course depends on from where one looks. + unsigned petalToTheRight = petal + 1; + + //Now we have to make sure that we didn't leave the petal range 0 to nPetals-1 + if (petal == 0) petalToTheLeft = nPetals - 1; + if (petal == nPetals - 1) petalToTheRight = 0; + + + + for ( unsigned iSensor=0; iSensor < nSensors ; iSensor++ ){ //over all sensors + + + targetSectors.insert( _sectorSystemFTD->getSector ( side , layer , petalToTheLeft , iSensor ) ); + targetSectors.insert( _sectorSystemFTD->getSector ( side , layer , petalToTheRight , iSensor ) ); + + } + + + + return targetSectors; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/FTDSectorConnector.cc b/Utilities/KiTrack/src/ILDImpl/FTDSectorConnector.cc new file mode 100644 index 00000000..4e887e00 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/FTDSectorConnector.cc @@ -0,0 +1,92 @@ +#include "ILDImpl/FTDSectorConnector.h" + + +using namespace KiTrackMarlin; + + + +FTDSectorConnector::FTDSectorConnector( const SectorSystemFTD* sectorSystemFTD , unsigned layerStepMax , unsigned petalStepMax, unsigned lastLayerToIP){ + + _sectorSystemFTD = sectorSystemFTD; + _layerStepMax = layerStepMax; + _lastLayerToIP = lastLayerToIP; + _petalStepMax = petalStepMax; + +} + + + +std::set< int > FTDSectorConnector::getTargetSectors ( int sector ){ + + + + std::set <int> targetSectors; + + + int side = _sectorSystemFTD->getSide( sector ); + unsigned layer = _sectorSystemFTD->getLayer( sector ); + unsigned module = _sectorSystemFTD->getModule( sector ); +// unsigned sensor = _sectorSystemFTD->getSensor( sector ); + +// unsigned nLayers = _sectorSystemFTD->getNumberOfLayers(); + unsigned nModules = _sectorSystemFTD->getNumberOfModules(); + unsigned nSensors = _sectorSystemFTD->getNumberOfSensors(); + + + for( unsigned layerStep = 1; layerStep <= _layerStepMax; layerStep++ ){ + + + + if ( layer >= layerStep +1 ){ //other wise the we could jump past layer 1, ( layer 0 is covered below) + + + unsigned layerTarget = layer - layerStep; + + + for ( unsigned iSensor=0; iSensor < nSensors ; iSensor++){ //over all sensors + + + for ( int iPetal= int(module) - _petalStepMax; iPetal <= int(module) + int(_petalStepMax) ; iPetal++ ){ + + //if iPetal is out of the range from 0 to nModules-1, move it back there. + //And of course use a different variable for that. + //(Or else we would create and endless loop: imagine we have iPetal = 16 and set it back to 0--> the loop will continue from there until it reaches 16 again and so on...) + int iModule = iPetal; + while( iModule < 0 ) iModule+= nModules; + while( iModule >= int(nModules) ) iModule -= nModules; + + targetSectors.insert( _sectorSystemFTD->getSector ( side , layerTarget , iModule , iSensor ) ); + + } + + } + + } + + } + + //Allow jumping to layer 0 from layer _lastLayerToIP or less + if ( ( layer >= 1 )&& ( layer <= _lastLayerToIP ) ){ + + + unsigned layerTarget = 0; + + for ( unsigned iModule=0; iModule < nModules ; iModule++){ //over all modules + + for ( unsigned iSensor=0; iSensor < nSensors ; iSensor++ ){ //over all sensors + + + targetSectors.insert( _sectorSystemFTD->getSector ( side , layerTarget , iModule , iSensor ) ); + + } + + } + + } + + return targetSectors; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/FTDTrack.cc b/Utilities/KiTrack/src/ILDImpl/FTDTrack.cc new file mode 100644 index 00000000..6d928c37 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/FTDTrack.cc @@ -0,0 +1,132 @@ +#include "ILDImpl/FTDTrack.h" + + +#include <algorithm> +#include <math.h> + +//#include "UTIL/LCTrackerConf.h" + +// Root, for calculating the chi2 probability. +#include "Math/ProbFunc.h" + + + +using namespace KiTrackMarlin; + +/** @return if the absolute z value of hit a is bigger than that of hit b */ +bool compare_IHit_z( IHit* a, IHit* b ){ + + return ( fabs( a->getZ() ) < fabs( b->getZ() ) ); //compare their z values + +} + + + +FTDTrack::FTDTrack( MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + + +} + +FTDTrack::FTDTrack( std::vector< IFTDHit* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + + for( unsigned i=0; i < hits.size(); i++ ){ + + addHit( hits[i] ); + + + } + +} + + +FTDTrack::FTDTrack( const FTDTrack& f ){ + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + +} + +FTDTrack & FTDTrack::operator= (const FTDTrack & f){ + + if (this == &f) return *this; //protect against self assignment + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + + return *this; + +} + + + +void FTDTrack::addHit( IFTDHit* hit ){ + if ( hit != NULL ){ + _hits.push_back( hit ); + // and sort the track again + sort( _hits.begin(), _hits.end(), compare_IHit_z ); + _lcioTrack->addToTrackerHits( *hit->getTrackerHit() ); + } +} + + + + + +void FTDTrack::fit() { + + + Fitter fitter( _lcioTrack , _trkSystem ); + + + _lcioTrack->setChi2( fitter.getChi2( 1/*by fucd AtIP=1 in LCIO, changed to CepC rule in future: lcio::TrackState::AtIP*/ ) ); + _lcioTrack->setNdf( fitter.getNdf( 1/*lcio::TrackState::AtIP*/ ) ); + _chi2Prob = fitter.getChi2Prob( 1/*lcio::TrackState::AtIP*/ ); + + edm4hep::TrackState trkState( *fitter.getTrackState( 1/*lcio::TrackState::AtIP*/ ) ) ; + trkState.location = 1/*lcio::TrackState::AtIP*/ ; + _lcioTrack->addToTrackStates( trkState ); + + +} + + +double FTDTrack::getQI() const{ + + + double QI = _chi2Prob; + + // make sure QI is between 0 and 1 + if (QI > 1. ) QI = 1.; + if (QI < 0. ) QI = 0.; + + return QI; + +} + + + + + + + diff --git a/Utilities/KiTrack/src/ILDImpl/IMiniVector.h b/Utilities/KiTrack/src/ILDImpl/IMiniVector.h new file mode 100644 index 00000000..af8142ba --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/IMiniVector.h @@ -0,0 +1,63 @@ +#ifndef IMiniVector_h +#define IMiniVector_h + +#include <iostream> + +#include "edm4hep/TrackerHit.h" + +#include "KiTrack/IHit.h" +#include "ILDImpl/MiniVector.h" + +#include "ILDImpl/SectorSystemVXD.h" + +namespace KiTrackMarlin{ + + + /** An interface for a mini-vector for the ILD + */ + class IMiniVector : public IHit{ + + + public: + + + MiniVector* getMiniVector() { return _miniVector; }; + + + int getTheta() { return _theta; } + unsigned getPhi() { return _phi; } + + + //void setLayer( unsigned layer ){ _layer = layer; calculateSector();} + //void setPhi( unsigned phi ){ _phi = phi; calculateSector();} + //void setTheta( unsigned theta ){ _theta = theta; calculateSector();} + void setLayer( unsigned layer ){ _layer = layer; } + void setPhi( unsigned phi ){ _phi = phi; } + void setTheta( unsigned theta ){ _theta = theta; } + + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemVXD; }; + + protected: + + MiniVector* _miniVector; + + + int _layer; + int _phi; + int _theta; + + const SectorSystemVXD* _sectorSystemVXD; + + /** Calculates and sets the sector number + */ + + //void calculateSector(){ _sector = _sectorSystemMV->getSector( _layer, _phi, _theta ); } + + }; + +} + + +#endif + diff --git a/Utilities/KiTrack/src/ILDImpl/IVXDHit.h b/Utilities/KiTrack/src/ILDImpl/IVXDHit.h new file mode 100644 index 00000000..dcbecd9e --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/IVXDHit.h @@ -0,0 +1,53 @@ +#ifndef IVXDHit_h +#define IVXDHit_h + +#include <iostream> + +#include "edm4hep/TrackerHit.h" +//#include "lcio.h" + +#include "KiTrack/IHit.h" + +#include "ILDImpl/SectorSystemVXD.h" + +namespace KiTrackMarlin{ + /** An interface for a hit for the ILD using an lcio TrackerHit as basis. + * + * It comes along with a layer, phi and theta. + */ + class IVXDHit : public IHit{ + public: + + edm4hep::TrackerHit* getTrackerHit() { return _trackerHit; }; + + int getTheta() { return _theta; } + unsigned getPhi() { return _phi; } + + //void setLayer( unsigned layer ){ _layer = layer; calculateSector();} + //void setPhi( unsigned phi ){ _phi = phi; calculateSector();} + //void setTheta( unsigned theta ){ _theta = theta; calculateSector();} + void setLayer( unsigned layer ){ _layer = layer; } + void setPhi( unsigned phi ){ _phi = phi; } + void setTheta( unsigned theta ){ _theta = theta; } + + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemVXD; }; + + protected: + + edm4hep::TrackerHit* _trackerHit; + + int _layer; + int _phi; + int _theta; + + const SectorSystemVXD* _sectorSystemVXD; + + /** Calculates and sets the sector number + */ + + //void calculateSector(){ _sector = _sectorSystemVXD->getSector( _layer, _phi, _theta ); } + }; +} +#endif + diff --git a/Utilities/KiTrack/src/ILDImpl/MiniVector.cc b/Utilities/KiTrack/src/ILDImpl/MiniVector.cc new file mode 100644 index 00000000..3d7840a2 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/MiniVector.cc @@ -0,0 +1,139 @@ +#include <ILDImpl/MiniVector.h> + +#include "TrackSystemSvc/IMarlinTrack.h" +#include "CLHEP/Vector/ThreeVector.h" + +using namespace KiTrack; +using namespace KiTrackMarlin; + +MiniVector::MiniVector(edm4hep::TrackerHit * outer, edm4hep::TrackerHit * inner) { + HitVec.push_back(outer); + HitVec.push_back(inner); +} + + +MiniVector::MiniVector( TrackerHitVec hitPair){ + + HitVec = hitPair ; + +} + +MiniVector::~MiniVector(){ + +} + + +double * MiniVector::getPosition(){ + + double x_outer = HitVec[0]->getPosition()[0]; + double y_outer = HitVec[0]->getPosition()[1]; + double z_outer = HitVec[0]->getPosition()[2]; + + double x_inner = HitVec[1]->getPosition()[0]; + double y_inner = HitVec[1]->getPosition()[1]; + double z_inner = HitVec[1]->getPosition()[2]; + + double *_pos = new double[3] ; + + //_pos[0] = (x_outer - x_inner)/2. ; + //_pos[1] = (y_outer - y_inner)/2. ; + //_pos[2] = (z_outer - z_inner)/2. ; + + _pos[0] = x_inner ; + _pos[1] = y_inner ; + _pos[2] = z_inner ; + + return _pos ; + +} + + +TrackerHitVec MiniVector::getTrackerHitVec(){ + + return HitVec ; + +} + + + +double MiniVector::getPhi(){ + + double x_outer = HitVec[0]->getPosition()[0]; + double y_outer = HitVec[0]->getPosition()[1]; + + double x_inner = HitVec[1]->getPosition()[0]; + double y_inner = HitVec[1]->getPosition()[1]; + + double phiMV = atan2((y_outer-y_inner),(x_outer-x_inner)) ; + + //std::cout << " outer x,y " << x_outer << " , " << y_outer << " inner x,y " << x_inner << " , " << y_inner << std::endl ; + + //std::cout << " Calling MiniVector::getPhi, returning " << phiMV << std::endl ; + + return phiMV ; + +} + +double MiniVector::getTheta(){ + + double x_outer = HitVec[0]->getPosition()[0]; + double y_outer = HitVec[0]->getPosition()[1]; + double z_outer = HitVec[0]->getPosition()[2]; + + double x_inner = HitVec[1]->getPosition()[0]; + double y_inner = HitVec[1]->getPosition()[1]; + double z_inner = HitVec[1]->getPosition()[2]; + + double thetaMV = atan2(sqrt((x_outer-x_inner)*(x_outer-x_inner) + (y_outer-y_inner)*(y_outer-y_inner)),(z_outer-z_inner)) ; + + return thetaMV ; + +} + + +double * MiniVector::getXYZ(){ + + double x_outer = HitVec[0]->getPosition()[0]; + double y_outer = HitVec[0]->getPosition()[1]; + double z_outer = HitVec[0]->getPosition()[2]; + + double x_inner = HitVec[1]->getPosition()[0]; + double y_inner = HitVec[1]->getPosition()[1]; + double z_inner = HitVec[1]->getPosition()[2]; + + double *xyz = new double[3] ; + + xyz[0] = x_outer - x_inner ; + xyz[1] = y_outer - y_inner ; + xyz[2] = z_outer - z_inner ; + + + return xyz ; + +} + + +double MiniVector::get3DAngleMV(MiniVector *MinVec2){ + + double *xyz1 = new double[3] ; + xyz1 = this->getXYZ() ; + CLHEP::Hep3Vector v1( xyz1[0], xyz1[1], xyz1[2] ) ; + + double *xyz2 = new double[3] ; + xyz2 = MinVec2->getXYZ() ; + + CLHEP::Hep3Vector v2( xyz2[0], xyz2[1], xyz2[2] ) ; + + double ScalarProd = v1.dot(v2); + double magV1 = v1.r(); + double magV2 = v2.r(); + + std::cout << "####### MINIVECTOR::get3DAngle, Scalar product " << ScalarProd << " mag. of the instantiate mv " << magV1 << " mag. of the second mv " << magV2 << std::endl ; + + double Angle3D = acos(ScalarProd / (magV1*magV2)) ; + + return Angle3D ; + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/MiniVector.h b/Utilities/KiTrack/src/ILDImpl/MiniVector.h new file mode 100644 index 00000000..40c2e369 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/MiniVector.h @@ -0,0 +1,67 @@ +#ifndef MINIVECTOR_H +#define MINIVECTOR_H 1 + +#include <iostream> +#include <sstream> +#include <string> +#include <edm4hep/TrackerHit.h> +//#include "UTIL/LCTrackerConf.h" +#include "KiTrack/IHit.h" + +#include "ILDImpl/SectorSystemVXD.h" + +#include <vector> +#include <math.h> + +typedef std::vector<edm4hep::TrackerHit*> TrackerHitVec; + +namespace KiTrackMarlin{ + class MiniVector : public IHit{ + public: + TrackerHitVec HitVec ; + + // Class constructor + MiniVector(edm4hep::TrackerHit * outer, edm4hep::TrackerHit * inner); + + MiniVector(TrackerHitVec hitPair); + + ~MiniVector(); + + // returns the TrackerHitVec + TrackerHitVec getTrackerHitVec() ; + + // Gives the layer of the inner hit + //int getLayer() ; + + // Gives the azimuth angle of the mini-vector + double getPhi() ; + + // Gives the polar angle of the mini-vector + double getTheta() ; + + // Gives the 2-D angle between two minivectors + //double get2DAngle(MiniVector MinVec1, MiniVector MinVec2) ; + + // Gives the 3-D angle between two minivectors + double get3DAngleMV(MiniVector *MinVec2) ; + + double * getXYZ() ; + + // Gives the position of the mini-vector + double * getPosition() ; + + virtual const ISectorSystem* getSectorSystem() const { return _sectorSystemVXD; }; + + + protected: + + const SectorSystemVXD* _sectorSystemVXD; + + }; + +} + + + + +#endif diff --git a/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.cc b/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.cc new file mode 100644 index 00000000..10d7ea3c --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.cc @@ -0,0 +1,59 @@ +#include "ILDImpl/MiniVectorHit01.h" +#include "ILDImpl/SectorSystemVXD.h" + +//#include "UTIL/LCTrackerConf.h" +#include <UTIL/ILDConf.h> + +#include <iostream> +#include <algorithm> +#include <cmath> +#include <climits> + +using namespace KiTrackMarlin; + +typedef std::vector<edm4hep::TrackerHit*> TrackerHitVec; + +MiniVectorHit01::MiniVectorHit01( MiniVector* miniVector , const SectorSystemVXD* const sectorSystemVXD ){ + + + _sectorSystemVXD = sectorSystemVXD; + + _miniVector = miniVector; + + _phiMV = miniVector->getPhi() ; + + _thetaMV = miniVector->getTheta() ; + + TrackerHitVec HitVec = miniVector->getTrackerHitVec(); + + UTIL::BitField64 cellID( UTIL::ILDCellID0::encoder_string ); + cellID.setValue( HitVec[1]->getCellID() ); + + int _layer = cellID[ UTIL::ILDCellID0::layer ] ; // +1 to take into account the IP (considered as layer 0 ) + int det_id = 0 ; + det_id = cellID[UTIL::ILDCellID0::subdet] ; + if ( det_id == UTIL::ILDDetID::SIT) { _layer = _layer + 6; } + + //Set the position of the VXDHit01 + const double* pos= miniVector->getPosition(); + _x = pos[0]; + _y = pos[1]; + _z = pos[2]; + + double _cosTheta = cos(miniVector->getTheta()); + double _phi = miniVector->getPhi(); + double _theta = miniVector->getTheta() ; + + if (_phi < 0.) _phi = _phi + 2*M_PI; + + // YV, for debugging. Calculate sector here and not through the IVXHit base class + //calculateSector(); + _sector = _sectorSystemVXD->getSector( _layer, _phi, _cosTheta ); + + //We assume a real hit. If it is virtual, this has to be set. + _isVirtual = false; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.h b/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.h new file mode 100644 index 00000000..e3e50afd --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/MiniVectorHit01.h @@ -0,0 +1,16 @@ +#ifndef MiniVectorHit01_h +#define MiniVectorHit01_h + +#include "ILDImpl/IMiniVector.h" + +namespace KiTrackMarlin{ + /** A class for mini-vectors in the VXD - SIT system (the 01 is just for historical reasons and may be renamed) + */ + class MiniVectorHit01 : public IMiniVector{ + public: + + MiniVectorHit01( MiniVector* miniVector , const SectorSystemVXD* const sectorSystemVXD ); + }; +} +#endif + diff --git a/Utilities/KiTrack/src/ILDImpl/SectorSystemFTD.cc b/Utilities/KiTrack/src/ILDImpl/SectorSystemFTD.cc new file mode 100644 index 00000000..ff064859 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/SectorSystemFTD.cc @@ -0,0 +1,183 @@ +#include "ILDImpl/SectorSystemFTD.h" + +#include <sstream> + +using namespace KiTrackMarlin; + + +SectorSystemFTD::SectorSystemFTD( unsigned nLayers , unsigned nModules , unsigned nSensors ): + + +_nModules( nModules ), +_nSensors( nSensors ){ + + _nLayers = nLayers; + _sectorMax = 2*nLayers*nModules*nSensors - 1; + +} + + + +int SectorSystemFTD::getSector( int side, unsigned layer , unsigned module , unsigned sensor )const { + + //check if the values passed are okay: + if ( ( side!= 1 )&&( side != -1 ) ){ + + + std::stringstream s; + s << "Side has to be either +1 or -1 and not " << side; + throw OutOfRange( s.str() ); + + } + + if ( layer >= _nLayers ){ + + std::stringstream s; + s << "Layer " << layer << " is too big, the outermost layer is layer " << _nLayers - 1; + throw OutOfRange( s.str() ); + + } + + if ( module >= _nModules ){ + + std::stringstream s; + s << "Module " << module << " is too big, the highest module is module " << _nModules - 1; + throw OutOfRange( s.str() ); + + } + + if ( sensor >= _nSensors ){ + + std::stringstream s; + s << "Sensor " << sensor << " is too big, the highest sensor is sensor " << _nSensors - 1; + throw OutOfRange( s.str() ); + + } + + unsigned multiplicator=1; + + + int sector = sensor; + multiplicator *= _nSensors; //there are nSensors possible values for sensor + + sector += module * multiplicator; + multiplicator *= _nModules; + + sector += layer * multiplicator; + multiplicator *= _nLayers; + + + sector += ( (side + 1 )/2 ) * multiplicator; // (side+1) /2 gives 0 for backward (-1) and 1 for forward (+1) + /* + streamlog_out( DEBUG0 ) << " Sector of side " << side + << ", layer " << layer + << ", module " << module + << ", sensor " << sensor + << " == " << sector << "\n"; + */ + + return sector; + +} + + + + + + +int SectorSystemFTD::getSide( int sector ) const { + + checkSectorIsInRange( sector ); + + + + int side = ( sector / ( _nSensors * _nModules * _nLayers ) ) % 2; //this is an integerdivision --> we will get the floor authomatically + + side = side*2 - 1 ; //from 0 and 1 to -1 and 1 + +// streamlog_out( DEBUG0 ) << "\n Sector " << sector << " == Side " << side; + + return side; + +} + +unsigned SectorSystemFTD::getLayer( int sector ) const { + + checkSectorIsInRange( sector ); + + unsigned layer = ( sector / ( _nSensors * _nModules ) ) % _nLayers; //this is an integerdivision --> we will get the floor authomatically + +// streamlog_out( DEBUG0 ) << "\n Sector " << sector << " == Layer " << layer; + + return layer; + + +} + +unsigned SectorSystemFTD::getModule( int sector ) const { + + + checkSectorIsInRange( sector ); + + unsigned module = ( sector / ( _nSensors ) ) % _nModules; //this is an integerdivision --> we will get the floor authomatically + +// streamlog_out( DEBUG0 ) << "\n Sector " << sector << " == Module " << module; + + return module; + + + +} +unsigned SectorSystemFTD::getSensor( int sector ) const { + + + checkSectorIsInRange( sector ); + + unsigned sensor = ( sector ) % _nSensors; + +// streamlog_out( DEBUG0 ) << "\n Sector " << sector << " == Sensor " << sensor; + + return sensor; + +} + + +void SectorSystemFTD::checkSectorIsInRange( int sector ) const { + + + if ( sector > _sectorMax ){ + + std::stringstream s; + s << "SectorSystemFTD:\n Sector " + << sector << " is too big, the highest possible number for a sector in this configuration of FTDSegRepresentation is" + << _sectorMax + << ".\nThe configuration is: nLayers = " << _nLayers + << ", nModules = " << _nModules + << ", nSensors = " << _nSensors + << "\n With 2 sides (forward and backward) this gives sectors from 0 to 2*" + << _nLayers << "*" + << _nModules << "*" + << _nSensors << " -1 = " << 2*_nLayers*_nModules*_nSensors -1 ; + throw OutOfRange( s.str() ); + + } + +} + +std::string SectorSystemFTD::getInfoOnSector( int sector ) const{ + + + std::stringstream s; + s << " (si" << getSide(sector) + << ",la" << getLayer(sector) + << ",mo" << getModule(sector) + << ",se" << getSensor(sector) + << ")"; + + + return s.str(); + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/SectorSystemVXD.cc b/Utilities/KiTrack/src/ILDImpl/SectorSystemVXD.cc new file mode 100644 index 00000000..305d37c3 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/SectorSystemVXD.cc @@ -0,0 +1,201 @@ +#include "ILDImpl/SectorSystemVXD.h" + +#include <sstream> +#include <cmath> + +using namespace KiTrackMarlin; + + +SectorSystemVXD::SectorSystemVXD( unsigned nLayers, unsigned nDivisionsInPhi, unsigned nDivisionsInTheta ){ + + _nLayers = nLayers; + _nDivisionsInPhi = nDivisionsInPhi ; + _nDivisionsInTheta = nDivisionsInTheta ; + _sectorMax = _nLayers + _nLayers*_nDivisionsInPhi + _nLayers*_nDivisionsInPhi*_nDivisionsInTheta ; + +} + +unsigned SectorSystemVXD::getNLayers() const { + + return _nLayers ; + +} + +unsigned SectorSystemVXD::getPhiSectors() const { + + return _nDivisionsInPhi ; + +} + + +unsigned SectorSystemVXD::getThetaSectors() const { + + return _nDivisionsInTheta ; + +} + + +unsigned SectorSystemVXD::getLayer( int sector ) const { + + //std::cout << " SectorSystemVXD::getLayer total no of layers = " << _nLayers << " n divisions in phi = " << _nDivisionsInPhi << " sector = " << sector << std::endl ; + + int theta = sector/(_nLayers*_nDivisionsInPhi) ; + + int phi = ((sector - (theta*_nLayers*_nDivisionsInPhi)) / _nLayers) ; + + int Layer = sector - (theta*_nLayers*_nDivisionsInPhi) - (phi*_nLayers) ; + + //std::cout << " SectorSystemVXD::getLayer " << Layer << " total no of layers = " << _nLayers << " iPhi = " << phi << " iTheta = " << theta << " n divisions in phi = " << _nDivisionsInPhi << " sector = " << sector << std::endl ; + + return Layer ; + +} + + +unsigned SectorSystemVXD::getPhi( int sector) const { + + int theta = sector/(_nLayers*_nDivisionsInPhi) ; + + int Phi = ((sector - (theta*_nLayers*_nDivisionsInPhi)) / _nLayers) ; + + //std::cout << " SectorSystemVXD::getPhi " << Phi << std::endl ; + + return Phi ; + +} + + +unsigned SectorSystemVXD::getTheta( int sector ) const { + + int Theta = sector/(_nLayers*_nDivisionsInPhi) ; + + //std::cout << " SectorSystemVXD::getTheta " << Theta << std::endl ; + + return Theta ; + +} + + +int SectorSystemVXD::getSector( int layer , int phi , int theta ) const { + + //std::cout << "getting sector : layer " << layer << " phi " << phi << " theta " << theta << std::endl ; + + if ( layer >= _nLayers ){ + + std::stringstream s; + s << "Layer " << layer << " is too big, the outermost layer is layer " << _nLayers - 1 ; + throw OutOfRange( s.str() ); + + } + + + if ( phi >= _nDivisionsInPhi ){ + + std::stringstream s; + s << "Phi " << phi << " is too big, the highest phi division is " << _nDivisionsInPhi ; + throw OutOfRange( s.str() ); + + } + + + + if ( theta >= _nDivisionsInTheta ){ + + std::stringstream s; + s << "Theta " << theta << " is too big, the highest theta division is " << _nDivisionsInTheta ; + + throw OutOfRange( s.str() ); + //std::cout << " ####3 calling getSector function $$$$$$$$$$" << std::endl ; + } + + int sector = layer + _nLayers*phi + _nLayers*_nDivisionsInPhi*theta ; + //std::cout << " did you call me? I am the Theta version, give you the sector " << sector << std::endl ; + + return sector ; + +} + + +int SectorSystemVXD::getSector( int layer , double phi , double cosTheta ) const { + + + double _dPhi = (2*M_PI)/_nDivisionsInPhi; + double _dTheta = 2.0/_nDivisionsInTheta; + int iPhi = int(phi / _dPhi); + int iTheta = int ((cosTheta + double(1.0))/_dTheta); + + //std::cout << "getting sector : layer " << layer << " phi " << iPhi << " theta " << iTheta << std::endl ; + + if ( layer >= _nLayers ){ + + std::stringstream s; + s << "Layer " << layer << " is too big, the outermost layer is layer " << _nLayers - 1 ; + throw OutOfRange( s.str() ); + + } + + + if ( iPhi >= _nDivisionsInPhi ){ + + std::stringstream s; + s << "Phi " << iPhi << " is too big, the highest phi division is " << _nDivisionsInPhi ; + throw OutOfRange( s.str() ); + + } + + + + if ( iTheta >= _nDivisionsInTheta ){ + + std::stringstream s; + s << "Theta " << iTheta << " is too big, the highest theta division is " << _nDivisionsInTheta ; + + throw OutOfRange( s.str() ); + //std::cout << " ####3 calling getSector function $$$$$$$$$$" << std::endl ; + } + + int sector = layer + _nLayers*iPhi + _nLayers*_nDivisionsInPhi*iTheta ; + //std::cout << " did you call me? I am the cosTheta version, give you the sector " << sector << std::endl ; + + return sector ; + +} + + + +void SectorSystemVXD::checkSectorIsInRange( int sector ) const { + + + if ( sector > _sectorMax ){ + + std::stringstream s; + s << "SectorSystemVXS:\n Sector " + << sector << " is too big, the highest possible number for a sector in this configuration of VXD - SIT is" + << _sectorMax + << ".\nThe configuration is: nLayers = " << _nLayers + << ", n divisions in phi = " << _nDivisionsInPhi + << ", n divisions in theta = " << _nDivisionsInTheta + << _nLayers + _nLayers*_nDivisionsInPhi + _nLayers*_nDivisionsInPhi*_nDivisionsInTheta ; + throw OutOfRange( s.str() ); + + } + +} + + +std::string SectorSystemVXD::getInfoOnSector( int sector ) const{ + + + std::stringstream s; + s << " (layer" << getLayer(sector ) + << ",theta" << getTheta(sector ) + << ",phi" << getPhi(sector ) + << ")"; + + + return s.str(); + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDHit01.cc b/Utilities/KiTrack/src/ILDImpl/VXDHit01.cc new file mode 100644 index 00000000..f6e67e95 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDHit01.cc @@ -0,0 +1,67 @@ +#include "ILDImpl/VXDHit01.h" +#include "ILDImpl/SectorSystemVXD.h" + +//#include "UTIL/LCTrackerConf.h" +#include <UTIL/ILDConf.h> + +#include <iostream> +#include <algorithm> +#include <cmath> +#include <climits> + +using namespace KiTrackMarlin; + + +VXDHit01::VXDHit01( edm4hep::TrackerHit* trackerHit , const SectorSystemVXD* const sectorSystemVXD ){ + + + _sectorSystemVXD = sectorSystemVXD; + + _trackerHit = trackerHit; + + //Set the position of the VXDHit01 + const edm4hep::Vector3d& pos= trackerHit->getPosition(); + _x = pos[0]; + _y = pos[1]; + _z = pos[2]; + + + //find out layer, module, sensor + + UTIL::BitField64 cellID( UTIL::ILDCellID0::encoder_string ); + + //cellID.setValue( trackerHit->getCellID0() ); + _layer = cellID[ UTIL::ILDCellID0::layer ] + 1 ; // + 1 to take into account the IP (considered as layer 0 ) + //_layer = cellID[ LCTrackerCellID::layer() ]; + int det_id = 0 ; + det_id = cellID[UTIL::ILDCellID0::subdet] ; + if ( det_id == UTIL::ILDDetID::SIT) { _layer = _layer + 6; } // need to find a more elegant way... + + + double radius = 0; + + for (int i=0; i<3; ++i) { + radius += pos[i]*pos[i]; + } + + radius = sqrt(radius); + + double _cosTheta = (pos[2]/radius); + double _phi = atan2(pos[1],pos[0]); + double _theta = acos( _cosTheta ) ; + + if (_phi < 0.) _phi = _phi + 2*M_PI; + + // YV, for debugging. Calculate sector here and not through the IVXHit base class + //calculateSector(); + + _sector = _sectorSystemVXD->getSector( _layer, _phi, _cosTheta ); + + + //We assume a real hit. If it is virtual, this has to be set. + _isVirtual = false; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDHit01.h b/Utilities/KiTrack/src/ILDImpl/VXDHit01.h new file mode 100644 index 00000000..dbcc828f --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDHit01.h @@ -0,0 +1,23 @@ +#ifndef VXDHit01_h +#define VXDHit01_h + +#include "ILDImpl/IVXDHit.h" + +namespace KiTrackMarlin{ + /** A class for hits in the VXD (the 01 is just for historical reasons and may be renamed) + * + * - The side is according to CellID0. + * - Layer is set according to CellID0 +1 (so we can use layer 0 for the IP) + * - Module is set according to CellID0. + * - Sensor is set according to CellID0 -1. (because currently sensors of the VXD start with 1 in the CellID0, if this changes, this has to be modified) + */ + class VXDHit01 : public IVXDHit{ + public: + + VXDHit01( edm4hep::TrackerHit* trackerHit , const SectorSystemVXD* const sectorSystemVXD ); + }; + //void setSectorisationInPhi(int PhiSectors); + //void setSectorisationInTheta(int ThetaSectors); +} +#endif + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDHitSimple.cc b/Utilities/KiTrack/src/ILDImpl/VXDHitSimple.cc new file mode 100644 index 00000000..857e6784 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDHitSimple.cc @@ -0,0 +1,29 @@ +#include "ILDImpl/VXDHitSimple.h" + + +using namespace KiTrackMarlin; + +VXDHitSimple::VXDHitSimple( float x , float y , float z , int layer , int phi, int theta, const SectorSystemVXD* const sectorSystemVXD ){ + + + _sectorSystemVXD = sectorSystemVXD; + + _x = x; + _y = y; + _z = z; + + + _layer = layer; + _phi = phi; + _theta = theta; + + _sector = _sectorSystemVXD->getSector( layer, phi, theta ); // maybe a good idea to calculate a sector for the IP hit as well + //calculateSector(); + + + //We assume a real hit. If it is virtual, this has to be set. + _isVirtual = false; + + +} + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.cc b/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.cc new file mode 100644 index 00000000..4237c06a --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.cc @@ -0,0 +1,100 @@ +#include "ILDImpl/VXDSectorConnector.h" + + +using namespace KiTrackMarlin; + + +// Constructor +VXDSectorConnector::VXDSectorConnector( const SectorSystemVXD* sectorSystemVXD , unsigned layerStepMax, unsigned lastLayerToIP, int neighPhi, int neighTheta, int layerMax ){ + + _sectorSystemVXD = sectorSystemVXD ; + _layerStepMax = layerStepMax ; + _lastLayerToIP = lastLayerToIP ; + + _nLayers = sectorSystemVXD->getNLayers(); + _nDivisionsInPhi = sectorSystemVXD->getPhiSectors(); + _nDivisionsInTheta = sectorSystemVXD->getThetaSectors(); + _neighPhi = neighPhi ; + _neighTheta = neighTheta ; + _layerMax = layerMax ; +} + + + +std::set< int > VXDSectorConnector::getTargetSectors ( int sector ){ + + + std::set <int> targetSectors; + + //std::cout << " check : n layers " << _nLayers << " n phi divisions " << _nDivisionsInPhi << " n theta divisions " << _nDivisionsInTheta << std::endl ; + + // Decode the sector integer, and take the layer, phi and theta bin + + int iTheta = sector/(_nLayers*_nDivisionsInPhi) ; + + int iPhi = ((sector - (iTheta*_nLayers*_nDivisionsInPhi)) / _nLayers) ; + + int layer = sector - (iTheta*_nLayers*_nDivisionsInPhi) - (iPhi*_nLayers) ; + + // search for sectors at the neighbouring theta nad phi bins + + int iPhi_Up = iPhi + _neighPhi; + int iPhi_Low = iPhi - _neighPhi; + int iTheta_Up = iTheta + _neighTheta; + int iTheta_Low = iTheta - _neighTheta; + if (iTheta_Low < 0) iTheta_Low = 0; + if (iTheta_Up >= _nDivisionsInTheta) iTheta_Up = _nDivisionsInTheta-1; + + //************************************************************************************* + + //streamlog_out(DEBUG2) << " checking sector " << sector << " layer " << layer << " phi " << iPhi << " theta " << iTheta <<std::endl ; + + for( unsigned layerStep = 1; layerStep <= _layerStepMax; layerStep++ ){ + + if ( layer >= layerStep ){ // +1 makes sense if I use IP as innermost layer + + unsigned layerTarget = layer - layerStep; + + if (layerTarget >= 0 && layerTarget < _layerMax ){ // just a test to run cellular automaton over the whole VXD - SIT + + for (int iPhi = iPhi_Low ; iPhi <= iPhi_Up ; iPhi++){ + + int ip = iPhi; + + // catch wrap-around + if (ip < 0) ip = _nDivisionsInPhi-1; + if (ip >= _nDivisionsInPhi) ip = ip - _nDivisionsInPhi; + + for (int iTheta = iTheta_Low ; iTheta <= iTheta_Up ; iTheta++){ + + targetSectors.insert( _sectorSystemVXD->getSector ( layerTarget , ip , iTheta ) ); + + } + } + } + } + } + + + if ( layer > 0 && ( layer <= _lastLayerToIP ) ){ + + unsigned layerTarget = 0; + + for (int ip = iPhi_Low ; ip <= iPhi_Up ; ip++){ + + for (int iTheta = iTheta_Low ; iTheta <= iTheta_Up ; iTheta++){ + + //streamlog_out(DEBUG1) << " VXDSectorConnector: from layer " << layer << " to layer " << layerTarget << std::endl ; + + targetSectors.insert( 0 ) ; + } + } + } + + + return targetSectors; + + +} + + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.h b/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.h new file mode 100644 index 00000000..27ef66f7 --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDSectorConnector.h @@ -0,0 +1,51 @@ +#ifndef VXDSectorConnector_h +#define VXDSectorConnector_h + +#include "KiTrack/ISectorConnector.h" + +#include "ILDImpl/SectorSystemVXD.h" + + + +namespace KiTrackMarlin{ + + /** Used to connect two sectors on the VXD. + * + * + * Allows: + * + * - going to layers on the inside (how far see constructor) + * - jumping to the IP (from where see constructor) + */ + class VXDSectorConnector : public ISectorConnector{ + + + public: + + VXDSectorConnector ( const SectorSystemVXD* sectorSystemVXD , unsigned layerStepMax, unsigned lastLayerToIP, int neighPhi = 8, int neighTheta = 1, int layerMax = 10 ) ; + + /** @return a set of all sectors that are connected to the passed sector */ + virtual std::set <int> getTargetSectors ( int sector ); + + virtual ~VXDSectorConnector(){}; + + private: + + const SectorSystemVXD* _sectorSystemVXD; + + unsigned _layerStepMax; + unsigned _nLayers; + unsigned _lastLayerToIP; + unsigned _nDivisionsInPhi ; + unsigned _nDivisionsInTheta ; + int _layerMax ; + int _neighTheta ; + int _neighPhi ; + }; + + +} + + +#endif + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDTrack.cc b/Utilities/KiTrack/src/ILDImpl/VXDTrack.cc new file mode 100644 index 00000000..b00b855e --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDTrack.cc @@ -0,0 +1,201 @@ +#include "ILDImpl/VXDTrack.h" + +#include <algorithm> + +//#include "UTIL/LCTrackerConf.h" + +// Root, for calculating the chi2 probability. +#include "Math/ProbFunc.h" + + + +using namespace KiTrackMarlin; + +// FIX ME +/** @return if the radius of hit a is bigger than that of hit b */ + +bool compare_IHit_R_3Dhits( IHit* a, IHit* b ){ + + double r2_a = fabs((a->getX()*a->getX()) + (a->getY()*a->getY())); + double r2_b = fabs((b->getX()*b->getX()) + (b->getY()*b->getY())); + + return ( r2_a < r2_b ); //compare their radii + +} + + + +VXDTrack::VXDTrack( MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + +} +/* +VXDTrack::VXDTrack( std::vector< IVXDHit* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new TrackImpl(); + + for( unsigned i=0; i < hits.size(); i++ ){ + + addHit( hits[i] ); + + + } + +} +*/ + +VXDTrack::VXDTrack( std::vector< IMiniVector* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ){ + + + _trkSystem = trkSystem; + _chi2Prob = 0.; + + _lcioTrack = new edm4hep::Track(); + + for( unsigned i=0; i < hits.size(); i++ ){ + + addHit( hits[i] ); + + + } + +} + + + + +VXDTrack::VXDTrack( const VXDTrack& f ){ + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + +} + +VXDTrack & VXDTrack::operator= (const VXDTrack & f){ + + if (this == &f) return *this; //protect against self assignment + + //make a new copied lcio track + _lcioTrack = new edm4hep::Track( *f._lcioTrack ); + + + _hits = f._hits; + _chi2Prob = f._chi2Prob; + _trkSystem = f._trkSystem; + + return *this; + +} + + +/* +void VXDTrack::addHit( IVXDHit* hit ){ + + + + if ( hit != NULL ){ + + _hits.push_back( hit ); + + // and sort the track again + sort( _hits.begin(), _hits.end(), compare_IHit_R_3Dhits ); + + + _lcioTrack->addHit( hit->getTrackerHit() ); + + } + +} +*/ + + + +void VXDTrack::addHit( IMiniVector* MV ){ + + + + if ( MV != NULL ){ + + _hits.push_back( MV ); // so to be able to check the tracks compatibilty + + MiniVector *MinVec = MV->getMiniVector(); + TrackerHitVec HitVec = MinVec->getTrackerHitVec() ; + + + for (TrackerHitVec::iterator it = HitVec.begin(); it != HitVec.end() ; ++it ){ + + edm4hep::TrackerHit *trkHit = *it ; + + //_trkhits.push_back( trkHit ); + + _lcioTrack->addToTrackerHits( *trkHit ); + + } + + // and sort the track again + //sort( _trkhits.begin(), _trkhits.end(), compare_IHit_R_3Dhits ); + + } + +} + + + + + +void VXDTrack::fit() { + + + Fitter fitter( _lcioTrack , _trkSystem , 1 ); + + + _lcioTrack->setChi2( fitter.getChi2( 1/*lcio::TrackState::AtIP*/ ) ); + _lcioTrack->setNdf( fitter.getNdf( 1/*lcio::TrackState::AtIP*/ ) ); + _chi2Prob = fitter.getChi2Prob( 1/*lcio::TrackState::AtIP*/ ); + + edm4hep::TrackState trkState( *fitter.getTrackState( 1/*lcio::TrackState::AtIP*/ ) ) ; + trkState.location = 1/*TrackState::AtIP*/; + _lcioTrack->addToTrackStates( trkState ); + +} + + +double VXDTrack::getQI() const{ + + + double QI = _chi2Prob; + + // make sure QI is between 0 and 1 + if (QI > 1. ) QI = 1.; + if (QI < 0. ) QI = 0.; + + return QI; + +} + +/* +double VXDTrack::getPT() const{ + + double Omega = _lcioTrack->getOmega(); + double PT = fabs((0.3*3.5)/(1000*Omega)); + + return PT ; + +} +*/ + + + diff --git a/Utilities/KiTrack/src/ILDImpl/VXDTrack.h b/Utilities/KiTrack/src/ILDImpl/VXDTrack.h new file mode 100644 index 00000000..ad57501f --- /dev/null +++ b/Utilities/KiTrack/src/ILDImpl/VXDTrack.h @@ -0,0 +1,89 @@ +#ifndef VXDTrack_h +#define VXDTrack_h + +#include "edm4hep/Track.h" +#include "edm4hep/TrackerHit.h" +#include "TrackSystemSvc/IMarlinTrkSystem.h" +#include "TrackSystemSvc/IMarlinTrack.h" + +#include <vector> + +#include "ILDImpl/IVXDHit.h" +#include "ILDImpl/IMiniVector.h" +#include "KiTrack/ITrack.h" + +#include "Tools/Fitter.h" + +//#include "SpacePointBuilder.h" +// CLHEP tools +#include "CLHEP/Vector/ThreeVector.h" +#include "CLHEP/Matrix/SymMatrix.h" +#include "CLHEP/Matrix/Matrix.h" + + +namespace KiTrackMarlin{ + /** A class for ITracks containing an lcio::Track at core + */ + class VXDTrack : public ITrack { + public: + + /** @param trkSystem An IMarlinTrkSystem, which is needed for fitting of the tracks + */ + VXDTrack( MarlinTrk::IMarlinTrkSystem* trkSystem ); + + /** @param hits The hits the track consists of + * @param trkSystem An IMarlinTrkSystem, which is needed for fitting of the tracks + */ + //VXDTrack( std::vector< IVXDHit* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ); + VXDTrack( std::vector< IMiniVector* > hits , MarlinTrk::IMarlinTrkSystem* trkSystem ); + VXDTrack( const VXDTrack& f ); + VXDTrack & operator= (const VXDTrack & f); + + /** @return a track in the lcio format + */ + edm4hep::Track* getLcioTrack(){ return ( _lcioTrack );} + + //void addHit( IVXDHit* hit ); + void addHit( IMiniVector* MV ); + + virtual double getNdf() const { return _lcioTrack->getNdf(); } + virtual double getChi2() const { return _lcioTrack->getChi2(); } + virtual double getChi2Prob() const { return _chi2Prob; } + + virtual std::vector< IHit* > getHits() const { + std::vector<IHit*> hits; + for(unsigned i=0; i<_hits.size();i++) hits.push_back( _hits[i] ); + return hits; + } + + virtual std::vector< IMiniVector* > getMVs() const { + std::vector<IMiniVector*> mvhits; + for(unsigned i=0; i<_hits.size();i++) mvhits.push_back( _hits[i] ); + return mvhits; + } + + virtual double getQI() const; + + /** Fits the track and sets chi2, Ndf etc. + */ + virtual void fit() ; + + virtual ~VXDTrack(){ delete _lcioTrack; } + + protected: + /** the hits the track consists of + */ + //std::vector< IVXDHit* > _hits; + std::vector< IMiniVector* > _hits; + + edm4hep::Track* _lcioTrack; + + // for fitting + MarlinTrk::IMarlinTrkSystem* _trkSystem; + + double _chi2Prob; + }; +} +#endif + + diff --git a/Utilities/KiTrack/src/KiTrack/Automaton.cc b/Utilities/KiTrack/src/KiTrack/Automaton.cc new file mode 100644 index 00000000..870f276a --- /dev/null +++ b/Utilities/KiTrack/src/KiTrack/Automaton.cc @@ -0,0 +1,498 @@ +#include "KiTrack/Automaton.h" + +#include <iostream> +//#include "marlin/VerbosityLevels.h" + +using namespace KiTrack; + +void Automaton::addSegment ( Segment* segment ){ + if ( segment->getLayer() >= _segments.size() ) { //in case this layer is not included so far + _segments.resize( segment->getLayer() + 1 ); //resize the vector, so that the layer of the segment is now included + } + + _segments[ segment->getLayer() ].push_back ( segment ); + + _nConnections += segment->getChildren().size(); +} + +void Automaton::lengthenSegments(){ + + // Info A: On skipped layers + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // + // (read this only if you are interested on how the number of skipped layers is determined) + // + // The skipped layers are always between the innermost two hits of a segment. + // Why? Because the connection between those two hits is the thing that differs + // from its parent. Let's assume two 5-segments like those: + // / // + // \\ // + // // // + // \\ _layer 2 // + // / _layer 1 // + // You see how they overlap with all of their hits except the inner one of the child + // and the outer one of the parent. As the layer they are on equals the layer of the + // innermost point, the child will have layer 1 and the parent layer 2. + // (The choice of assigning the layer number of the innermost point and not the outermost + // is arbitrary, it could be the other way as well.) + // + // Now suppose the child skips layer 1: ( in this example a kink in the segment means the layer is hit, + // no kink means it is left out.) + // + // / // + // \\ // + // // // + // \\ _layer 2 // + // / _layer 1 // + // / _layer 0 // + // + // That means the child has now layer 0 and the parent layer 2. + // This is no problem, the segment class has an outer and an inner state (simulating skipped layers) + // instead of just an int. (to be more precise it has a vector containing the inner state and every layer left out) + // Now when we want to make 6-segments (I know the numbers are high, but they help visualising), we would connect + // parent and child to a new segment. + // + // + // / // + // \ // + // / // + // \ _layer 2 // + // / _layer 1 // + // / _layer 0 // + // + // So how many layers does this track skip: again 1 layer, so we need a state vector with 2 elements. + // (one for layer 0, one for layer 1) + // + // So we don't care if there are any other skipped layers in the outer part of the segment, we only care about that + // bit that won't overlap with parents. + // So the easy recipe for the number of skipped layers after making a segment longer is: + // Compare the layer before ( 2 ) to the layer after ( 0 ). The skipped layers are the difference -1 + // ( 2 - 0 - 1 = 1 --> segment->setSkippedLayers( 1 ); + + //std::cout << "Combining the shorter segments to longer ones\n"; + + //----------------------------------------------------------------------------------------------// + // // + // first: we create a new vector of a list of segments // + // to have somewhere we can put the longer segments // + // // + //----------------------------------------------------------------------------------------------// + + std::vector < std::list < Segment* > > longerSegments; + + if( _segments.size() > 0 ) longerSegments.resize ( _segments.size() -1 ); //This will have one layer less + + //----------------------------------------------------------------------------------------------// + // // + // next: find all the longer segments and store them in the new vector[][] // + // // + //----------------------------------------------------------------------------------------------// + + unsigned nLongerSegments=0; + unsigned nShorterSegments= _segments[0].size(); + + for (unsigned layer = 1; layer < _segments.size(); layer++){ //over all layers where there still can be something below + std::list<Segment*> segments = _segments[layer]; + for ( std::list<Segment*>::iterator iSeg=segments.begin(); iSeg != segments.end(); iSeg++){ //over all segments in this layer + nShorterSegments++; + + Segment* parent = *iSeg; + + std::list <Segment*> children = parent->getChildren(); + + for ( std::list<Segment*>::iterator iChild=children.begin(); iChild !=children.end(); iChild++){ //over all children of this parent + Segment* child = *iChild; + + //Combine the parent and the child to form a new longer segment + + //take all the hits from the parent + std::vector < IHit* > hits = parent->getHits(); + + //and also add the inner hit from the child + hits.insert( hits.begin(), child->getHits().at(0) ); + + //make the new (longer) segment + Segment* newSegment = new Segment ( hits ); + nLongerSegments++; + + //set the layer to the layer of the childsegment + unsigned newLayer = child->getLayer(); + newSegment->setLayer ( newLayer ); + + // Set the skipped layers. For an explanation see Info A above + int skippedLayers = parent->getLayer() - child->getLayer() - 1; + if( skippedLayers < 0 ) throw InvalidParameter( "skippedLayers can't be < 0!" ); + newSegment->setSkippedLayers( unsigned(skippedLayers) ); // + /* + std::cout << "Created longer segment: " << parent->getHits().size() + << "hits -->" << newSegment->getHits().size() + << " hits, layer = " << newLayer + << ", skipped layers = " << skippedLayers <<"\n"; + std::cout << "Combined: " << child->getInfo() << "<--with-->" << parent->getInfo() << "\n"; + */ + // In a next step we want to again establish the conenctions between the longer segments (so we can do the + // Automaton and later combine them and then do it all again... ). + // If we just created the Segments and dumped the old ones, we would have no idea what of the new, longer + // Segments we can connect. + // We could add some other container to store the possible connections of the longer Segments, but maybe + // it's the easiest approach to use, what is already there: the shorter Segments. + // + // So when we combine two shorter segments, we store the new longer Segment as a parent or child. + // Child, when the longer Segment goes on towards the inside, Parent if it continues on to the outside. + // So the shorter Segments kind of act as joints, that hold the longer Segments together. + // + // Let's visulaize that, so that it makes more sense: + // Let's have a look at 3 2-hit segments: + // + // / 2-hit-Segment A + // \ 2-hit-Segment B + // / 2-hit-Segment C + // + // Obviously we can make 2 3-hit segments out of this: + // + // / --> / 3-hit-Segment D + // \ \ \ . + // / --> / 3-hit-Segment E + // + // In the 2-hit-Segment B we store the 3-hit-Segments D and E as parent and child (while deleting A and C + // as parent and child, because that is now not needed anymore ) + // + // So when we want to connect the 3-hit-Segments, all we have to do is iterate over all 2-hit-Segments which + // then only have 3-hit-Segments as parents and children. + // When we come to Segment B, we see that D is a parent and E is a child, thus we connect them. Or to be more + // precise, we connect them, if the criteria do say so. + // + // So, yes B acts like a joint connecting D and E + // + // Erase the connection from the child to the parent segment and replace it with a link to the new + // (longer) segment. ( and vice versa ) This way we can connect the longer segments easily after. + child->deleteParent( parent ); + child->addParent ( newSegment ); + parent->deleteChild ( child ); + parent->addChild ( newSegment ); + // So now the new longer segment is a child of the old parent and a parent of the childsegment. + + + // Save the new segment in the new vector[][] + longerSegments[newLayer].push_back( newSegment ); + } + } + } + + //std::cout << " Made " << nLongerSegments << " longer segments from " << nShorterSegments << " shorter segments.\n"; + + //----------------------------------------------------------------------------------------------// + // // + // Connect the new (longer) segments // + // // + //----------------------------------------------------------------------------------------------// + + //std::cout << "Next connecting the new longer segments\n"; + + unsigned nConnections=0; + unsigned nPossibleConnections=0; + + for ( unsigned layer = 1; layer + 1 < _segments.size(); layer++ ){ // over all layers (of course the first and the last ones are spared out because there is nothing more above or below + std::list<Segment*> segments = _segments[layer]; + for ( std::list<Segment*>::iterator iSeg=segments.begin(); iSeg != segments.end(); iSeg++ ){ //over all (short) segments in this layer + Segment* segment = *iSeg; + + std::list<Segment*> parents = segment->getParents(); + std::list<Segment*> children = segment->getChildren(); + + for ( std::list<Segment*>::iterator iParent = parents.begin(); iParent != parents.end(); iParent++ ){ // over all parents of the segment + Segment* parent = *iParent; + for ( std::list<Segment*>::iterator iChild = children.begin(); iChild != children.end(); iChild++ ){ // over all children of the segment + Segment* child = *iChild; + + // Check if they are compatible + bool areCompatible = true; + ICriterion* theFailedCrit = NULL; + + //check all criteria (or at least until one returns false) + for ( unsigned iCrit = 0; iCrit < _criteria.size(); iCrit++ ){ + if ( _criteria[iCrit]->areCompatible ( parent , child ) == false ){ + areCompatible = false; + theFailedCrit = _criteria[iCrit]; + break; + } + } + + if ( areCompatible ){ + //connect parent and child (i.e. connect the longer segments we previously created) + child->addParent( parent ); + parent->addChild( child ); + + nConnections++; + + //std::cout << "Connected: " << child->getInfo() << "<--with-->" << parent->getInfo() << "\n"; + } + else{ + //std::cout << "NOT Connected: " << child->getInfo() << "<--XXXX-->" << parent->getInfo() << "\n"; + //if( theFailedCrit != NULL ) std::cout << "Failed first at criterion: " << theFailedCrit->getName() << "\n"; + } + + nPossibleConnections++; + } + } + } + } + _nConnections = nConnections; + + //std::cout << "Made " << nConnections << " of " << nPossibleConnections << " possible connections \n"; + + //----------------------------------------------------------------------------------------------// + // // + // Finally: replace the vector<list<segment*>> of the old segments with the new one // + // // + //----------------------------------------------------------------------------------------------// + + //delete all old Segments: + for( unsigned i=0; i<_segments.size(); i++){ + std::list<Segment*>& segments = _segments[i]; + for ( std::list<Segment*>::iterator iSeg=segments.begin(); iSeg != segments.end(); iSeg++ ){ + Segment* segment = *iSeg; + delete segment; + } + segments.clear(); + } + + // And replace with the newer ones + _segments = longerSegments; +} + +void Automaton::doAutomaton(){ + + bool hasChanged = true; + int nIterations = -1; + + while ( hasChanged == true ){ //repeat this until no more changes happen (this should always be equal or smaller to the number of layers - 1 + hasChanged = false; + nIterations++; + + for ( int layer = _segments.size()-1; layer >= 0; layer--){ //for all layers from outside in + std::list <Segment*> segments = _segments[layer]; + for ( std::list<Segment*>::iterator iSeg=segments.begin(); iSeg!= segments.end(); iSeg++ ){ //for all segments in the layer + Segment* parent= *iSeg; + + //Simulate skipped layers + std::vector < int >& state = parent->getState(); + + for ( int j= state.size()-1; j>=1; j--){ + if ( state[j] == state[j-1] ){ + state[j]++; + hasChanged = true; //something changed + } + } + + if ( parent->isActive() ){ + bool isActive = false; //whether the segment is active (i.e. still changing). This will be changed in the for loop, if it is active + + //Check if there is a neighbor + std::list <Segment*> children = parent->getChildren(); + + for ( std::list<Segment*>::iterator iChild=children.begin(); iChild != children.end(); iChild++ ){// for all children + Segment* child = *iChild; + + if ( child->getOuterState() == parent->getInnerState() ){ //Only if they have the same state + parent->raiseState(); //So it has a neighbor --> raise the state + + hasChanged = true; //something changed + isActive = true; + + break; //It has a neighbor, we raised the state, so we need not check again in this iteration + } + } + + parent->setActive( isActive ); + } + } + } + } + + //std::cout << "Automaton performed using " << nIterations << " iterations.\n"; +} + +void Automaton::cleanBadStates(){ + + unsigned nErasedSegments = 0; + unsigned nKeptSegments = 0; + + for( unsigned layer=0; layer < _segments.size(); layer++ ){//for every layer + std::list <Segment*> & segments = _segments[layer]; // We want to change things in the original list! Therefore the reference operator + for( std::list<Segment*>::iterator iSeg= segments.begin(); iSeg != segments.end(); iSeg++ ){//over every segment + Segment* segment = *iSeg; + + if( segment->getInnerState() == (int) layer ){ //the state is alright (equals the layer), this segment is good + nKeptSegments++; + } + else { //state is wrong, delete the segment + nErasedSegments++; + + //erase it from all its children + std::list <Segment*> children = segment->getChildren(); + + for (std::list<Segment*>::iterator iChild = children.begin(); iChild != children.end(); iChild++ ){ + (*iChild)->deleteParent ( segment ); + _nConnections--; + } + + //erase it from all its parents + std::list <Segment*> parents = segment->getParents(); + + for (std::list<Segment*>::iterator iParent = parents.begin(); iParent!= parents.end(); iParent++){ + (*iParent)->deleteChild ( segment ); + _nConnections--; + } + + //erase from the automaton + delete *iSeg; + iSeg = segments.erase( iSeg ); // erase the segment and update the iterator (updating is important!!!) + } + } + } + + //std::cout << "Erased segments because of bad states= " << nErasedSegments << "\n"; + //std::cout << "Kept segments because of good states= " << nKeptSegments << "\n"; +} + +void Automaton::resetStates(){ + for ( unsigned layer = 0; layer < _segments.size(); layer++ ){ //over all layers + std::list<Segment*> segments = _segments[layer]; + + for ( std::list<Segment*>::iterator iSeg = segments.begin(); iSeg != segments.end(); iSeg++ ){ //over all segments in the layer + (*iSeg)->resetState(); + (*iSeg)->setActive( true ); + } + } +} + +void Automaton::cleanBadConnections(){ + + unsigned nConnectionsKept = 0; + unsigned nConnectionsErased = 0; + + for ( int layer = _segments.size()-1 ; layer >= 1 ; layer-- ){ //over all layers from outside in. And there's no need to check layer 0, as it has no children. + std::list<Segment*> segments = _segments[layer]; + for ( std::list<Segment*>::iterator iSeg = segments.begin(); iSeg!=segments.end(); iSeg++ ){ // over all segments in the layer + Segment* parent = *iSeg; + std::list < Segment* > children = parent->getChildren(); + + for ( std::list<Segment*>::iterator iChild = children.begin(); iChild != children.end(); iChild++ ){ //over all children the segment has got + Segment* child = *iChild; + + bool areCompatible = true; //whether segment and child are compatible + + //check all criteria (or at least until the first false pops up) + for ( unsigned iCrit=0; iCrit < _criteria.size() ; iCrit++ ){ + if ( _criteria[iCrit]->areCompatible( parent , child ) == false ){ + areCompatible = false; + break; //no need to continue, now that we know, they're not compatible + } + } + + if ( areCompatible == false ){ // they are not compatible --> erase the connection + nConnectionsErased++; + _nConnections--; + + //erase the connection: + parent->deleteChild ( child ); + child->deleteParent ( parent ); + + //A small note here: although we deleted a child from the vector, this doesn't mean we have to do iSeg--! + //Because we copied the value of segment->getChildren to the vector children. And this one doesn't change! + } + else{ + nConnectionsKept++; + } + } + } + } + + //std::cout << "Erased bad connections= " << nConnectionsErased << "\n"; + //std::cout << "Kept good connections= " << nConnectionsKept << "\n"; +} + +std::vector < std::vector< IHit* > > Automaton::getTracksOfSegment ( Segment* segment, std::vector< IHit*> hits , unsigned minHits ){ + + std::vector < std::vector< IHit* > > tracks; //the vector of the tracks to be returned + + std::vector <IHit*> segHits = segment->getHits(); // the hits of the segment + + //add the outer hit + if ( segHits.back()->isVirtual() == false ) hits.push_back ( segHits.back() ); //Of course add only real hits to the track + + std::list <Segment*> children = segment->getChildren(); + + if ( children.empty() ){ //No more children --> we are at the bottom --> start a new Track here + //add the rest of the hits to the vector + for ( int i = segHits.size()-2 ; i >= 0; i--){ + if ( segHits[i]->isVirtual() == false ) hits.push_back ( segHits[i] ); + } + + if ( hits.size() >= minHits ){ + //add this to the tracks + tracks.push_back ( hits ); + } + } + else{// there are still children below --> so just take all their tracks and do it again + for ( std::list<Segment*>::iterator iChild=children.begin(); iChild!= children.end(); iChild++){ //for all children + std::vector < std::vector< IHit* > > newTracks = getTracksOfSegment( *iChild , hits ); + for (unsigned int j=0; j < newTracks.size(); j++){//for all the tracks of the child + tracks.push_back ( newTracks[j] ); + } + } + } + + return tracks; +} + +std::vector < std::vector< IHit* > > Automaton::getTracks( unsigned minHits ){ + + std::vector < std::vector< IHit* > > tracks; + std::vector <IHit*> emptyHitVec; + + for ( unsigned layer = 0 ; layer < _segments.size() ; layer++ ){ //over all layers + std::list<Segment*> segments = _segments[layer]; + for ( std::list<Segment*>::iterator iSeg = segments.begin(); iSeg != segments.end(); iSeg++ ){ //over all segments + Segment* segment = *iSeg; + // by fucd: comment "if" in new ILC version of Automaton, why? + if ( segment->getParents().empty() ){ // if it has no parents it is the end of a possible track + // get the tracks from the segment + std::vector < std::vector< IHit* > > newTracks = getTracksOfSegment( segment , emptyHitVec , minHits ); + + // and add them to the vector of all tracks + tracks.insert( tracks.end() , newTracks.begin() , newTracks.end() ); + } + } + } + return tracks; +} + +std::vector <const Segment*> Automaton::getSegments() const{ + + std::vector <const Segment*> segments; + + for( unsigned layer=0; layer < _segments.size(); layer++ ){ + segments.insert( segments.end() , _segments[layer].begin() , _segments[layer].end() ); + } + + return segments; +} + +Automaton::~Automaton(){ + //delete the segments + for( unsigned layer=0; layer < _segments.size(); layer++){ //over all layers + std::list<Segment*> segments = _segments[layer]; + for( std::list<Segment*>::iterator iSeg = segments.begin(); iSeg!=segments.end(); iSeg++ ){ //over all segments + delete *iSeg; + } + } +} + + + + + + + diff --git a/Utilities/KiTrack/src/KiTrack/HopfieldNeuralNet.cc b/Utilities/KiTrack/src/KiTrack/HopfieldNeuralNet.cc new file mode 100644 index 00000000..6597b191 --- /dev/null +++ b/Utilities/KiTrack/src/KiTrack/HopfieldNeuralNet.cc @@ -0,0 +1,217 @@ +#include "KiTrack/HopfieldNeuralNet.h" + +#include <cmath> +#include <iostream> +#include <algorithm> +#include <sstream> +#include <random> + + +using namespace KiTrack; + +HopfieldNeuralNet::HopfieldNeuralNet( std::vector < std::vector <bool> > G , std::vector < double > QI , std::vector < double > states , double omega) { + + unsigned int nNeurons = G.size(); + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check the validity of the input parameters + + + std::stringstream s; + s << "HopfieldNeuralNet: "; + + // Is G a square matrix? + for( unsigned i=0; i< nNeurons; i++ ){ + + if( G[i].size() != nNeurons ){ + + s << "G must be a square matrix!!! G[" << i << "].size() == " << G[i].size() << " != G.size() (" << nNeurons << ")\n"; + throw InvalidParameter( s.str() ); + + } + + } + + // Does the QI vector have the right size? + if( QI.size() != nNeurons ){ + + s << "The QI vector must have the same size as G! QI.size() == " << QI.size() << " != G.size() (" << nNeurons << ")\n"; + throw InvalidParameter( s.str() ); + + } + + // Are all the Quality Indicators in the range 0 - 1 + for( unsigned i=0; i< nNeurons; i++ ){ + + if( ( QI[i] < 0. ) || ( QI[i] > 1. ) ){ + + s << "The QI must be between 0 and 1, QI[" << i << "] == " << QI[i] << " is not a valid value!\n"; + + } + + } + + // Does the states vector have the right size? + if( states.size() != nNeurons ){ + + s << "The vector of the states must have the same size as G! states.size() == " << states.size() << " != G.size() (" << nNeurons << ")\n"; + throw InvalidParameter( s.str() ); + + } + + // Are all the states in the range 0 - 1 + for( unsigned i=0; i< nNeurons; i++ ){ + + if( ( states[i] < 0. ) || ( states[i] > 1. ) ){ + + s << "The states must be between 0 and 1, states[" << i << "] == " << states[i] << " is not a valid value!\n"; + + } + + } + + // Is omega in the range from 0 to 1 + if( ( omega < 0. ) || ( omega > 1. ) ){ + + s << "Omega must be in the range from 0 to 1, omega == " << omega << " is not a valid value!\n"; + + } + // End of checking the parameters + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + _omega = omega; + _States = states; + + // resize the vectors. + _States.resize( nNeurons ); + _w0.resize( nNeurons ); + _W.resize( nNeurons ); + _order.resize( nNeurons); + + for ( unsigned int i =0; i < nNeurons; i++){ + + // resize the vectors of the matrix W + _W[i].resize( nNeurons ); + + + // initialise the order vector + _order[i]=i; //the order now is 0,1,2,3... (will be changed to a random sequence in the iteration) + + } + + + //calculate _w0 + for (unsigned int i=0; i < QI.size(); i++) _w0[i] = omega * QI[i]; + + + + // Build the W matrix. (the matrix of the influences including their force) + + double comp = 1; + if (nNeurons > 0 ) comp = (1. - omega) / double (nNeurons); + + + for (unsigned int i=0; i< nNeurons ; i++){ + + for (unsigned int j=0; j< nNeurons ; j++){ + + if (i == j) _W[i][j] = 0.; //diagonal elements are 0 --> whatever the matrix G says here is ignored. + + else{ + + if ( G[i][j] == 1 ) _W[i][j] = -1; //Neurons are incompatible + + else _W[i][j] = comp; //Neurons are compatible + + } + + } + + } + + + + + + _T = 0; + _TInf = 0; + + _isStable = false; + _limitForStable = 0.01; + + + +} + + + +double HopfieldNeuralNet::activationFunction ( double state , double T ){ + + + double y = 1; + + if (T > 0) y = 0.5 * ( 1 + tanh( state / T ) ); //if T==0 tanh( infinity ) gives 1. + + + return y; + + +} + + + + +bool HopfieldNeuralNet::doIteration(){ + + _isStable = true; + + // initialize the random generator + std::random_device rng; + std::mt19937 urng(rng()); + + shuffle ( _order.begin() , _order.end() , urng ); //shuffle the order + + for (unsigned int i=0; i<_States.size() ; i++){ //for all entries of the vector + + unsigned iNeuron = _order[i]; + + + double y; + + y = _w0[iNeuron]; + + //matrix vector multiplication (or one line of it to be precise) + for (unsigned int j=0; j< _W[iNeuron].size(); j++){ + + y += _W[iNeuron][j] * _States[j]; + + } + + y = activationFunction ( y , _T ); + + // check if the change was big enough that the Network is not stable + if ( fabs( _States[iNeuron] - y ) > _limitForStable ) _isStable = false; + + // update the state + _States[iNeuron] = y; + + } + + + + // after the iteration, we need to calculate a new tempereatur _T + + _T = 0.5* ( _T + _TInf); + + + return _isStable; + +} + + + + + + diff --git a/Utilities/KiTrack/src/KiTrack/IHit.cc b/Utilities/KiTrack/src/KiTrack/IHit.cc new file mode 100644 index 00000000..e4381d84 --- /dev/null +++ b/Utilities/KiTrack/src/KiTrack/IHit.cc @@ -0,0 +1,28 @@ +#include "KiTrack/IHit.h" + +#include <cmath> +#include <sstream> + +using namespace KiTrack; + +float IHit::distTo( IHit* otherHit ){ + + + + float dx = otherHit->getX() - _x; + float dy = otherHit->getY() - _y; + float dz = otherHit->getZ() - _z; + + return sqrt( dx*dx + dy*dy + dz*dz ); + +} + +std::string IHit::getPositionInfo(){ + + std::stringstream info; + + info << "(" << _x << "," << _y << "," << _z << ")"; + + return info.str(); + +} \ No newline at end of file diff --git a/Utilities/KiTrack/src/KiTrack/Segment.cc b/Utilities/KiTrack/src/KiTrack/Segment.cc new file mode 100644 index 00000000..0fd8916f --- /dev/null +++ b/Utilities/KiTrack/src/KiTrack/Segment.cc @@ -0,0 +1,67 @@ +#include "KiTrack/Segment.h" + +#include <sstream> + +using namespace KiTrack; + +Segment::Segment( std::vector <IHit*> hits){ + + _hits = hits; + + _state.push_back(0); + + _children.clear(); + _parents.clear(); + + _active = true; + + _layer=0; +} + + + +Segment::Segment( IHit* hit){ + + _hits.push_back( hit) ; + _state.push_back(0); + _children.clear(); + _parents.clear(); + + _active = true; + + _layer=0; +} + + + +void Segment::resetState(){ + + + for ( unsigned i = 0; i <_state.size(); i++){ + + _state[i] = 0; + + } + +} + +std::string Segment::getInfo(){ + + + std::stringstream info; + + for( unsigned i=0; i<_hits.size(); i++ ) info << _hits[i]->getPositionInfo(); + + info << "["; + for( unsigned i=0; i+1<_state.size(); i++ ) info << _state[i] << ","; + info << _state.back() << "]"; + + return info.str(); + + +} + + + + + diff --git a/Utilities/KiTrack/src/KiTrack/SegmentBuilder.cc b/Utilities/KiTrack/src/KiTrack/SegmentBuilder.cc new file mode 100644 index 00000000..7a19c4df --- /dev/null +++ b/Utilities/KiTrack/src/KiTrack/SegmentBuilder.cc @@ -0,0 +1,117 @@ +#include "KiTrack/SegmentBuilder.h" + +// ----- include for verbosity dependend logging --------- +//#include "marlin/VerbosityLevels.h" +#include <iostream> + +using namespace KiTrack; + +SegmentBuilder::SegmentBuilder( std::map< int , std::vector< IHit* > > map_sector_hits ): + _map_sector_hits( map_sector_hits){} + +Automaton SegmentBuilder::get1SegAutomaton(){ + /**********************************************************************************************/ + /* Create and fill a map for the segments */ + /**********************************************************************************************/ + std::map< int , std::vector< IHit* > >::iterator itSecHit; // Sec = sector , Hit = hits + std::map< int , std::vector< Segment* > > map_sector_segments; + std::map< int , std::vector< Segment* > > ::iterator itSecSeg; // Sec = sector , Seg = segments + + unsigned nCreatedSegments=0; + + for ( itSecHit = _map_sector_hits.begin(); itSecHit!=_map_sector_hits.end(); itSecHit++ ){ //over all sectors + // All the hits in the sector + int sector = itSecHit->first; + std::vector <IHit*> hits = itSecHit->second; + for ( unsigned int i=0; i < hits.size(); i++ ){ //over every hit in the sector + // create a Segment + Segment* segment = new Segment( hits[i] ); + segment->setLayer( hits[i]->getLayer() ); + + // Store the segment in its map + map_sector_segments[sector].push_back( segment ); + + nCreatedSegments++; + } + } + + //std::cout << " Number of created 1-segments: " << nCreatedSegments <<"\n"; + + /**********************************************************************************************/ + /* Now check all 1-Segments and connect them to others */ + /* Afterwards store them in an Automaton */ + /**********************************************************************************************/ + + unsigned nConnections=0; + unsigned nStoredSegments = 0; + + Automaton automaton; + + for ( itSecSeg = map_sector_segments.begin(); itSecSeg != map_sector_segments.end(); itSecSeg++ ){ // over all sectors + // All the segments with one certain code + int sector = itSecSeg->first; + std::vector <Segment*> segments = itSecSeg->second; + + // Now find out, what the allowed codes to connect to are: + std::set <int> targetSectors; + + for ( unsigned i=0; i < _sectorConnectors.size(); i++ ){ // over all IHitConnectors + // get the allowed targets + std::set <int> newTargetSectors = _sectorConnectors[i]->getTargetSectors( sector ); + + //insert them into our set + targetSectors.insert( newTargetSectors.begin() , newTargetSectors.end() ); + } + + for ( unsigned int i=0; i< segments.size(); i++ ){ //over all segments within the sector + Segment* parent = segments[i]; + + for ( std::set<int>::iterator itTarg = targetSectors.begin(); itTarg!=targetSectors.end(); itTarg++ ){ // over all target codes + int targetSector = *itTarg; + std::vector <Segment*> targetSegments = map_sector_segments[ targetSector ]; + + for ( unsigned int j=0; j < targetSegments.size(); j++ ){ // over all segments in the target sector + Segment* child = targetSegments[j]; + bool areCompatible = true; + ICriterion* theFailedCrit = NULL; + + for (unsigned int iCrit = 0; iCrit < _criteria.size(); iCrit++){ + if ( _criteria[iCrit]->areCompatible( parent , child ) == false ){ + areCompatible = false; + theFailedCrit = _criteria[iCrit]; + break; + } + } + + if ( areCompatible ){ //the connection was successful + parent->addChild( child ); + child->addParent( parent ); + + nConnections++; + //std::cout << "Connected: " << child->getInfo() << "<--with-->" << parent->getInfo() << "\n"; + } + else{ + //std::cout << "NOT Connected: " << child->getInfo() << "<--XXXX-->" << parent->getInfo() << "\n"; + //if( theFailedCrit != NULL ) std::cout << "Failed first at criterion: " << theFailedCrit->getName() << "\n"; + } + } + } + + // Store the segment in the automaton + automaton.addSegment( parent ); + nStoredSegments++; + } + } + + //std::cout << "Number of connections made " << nConnections <<"\n"; + //std::cout << "Number of 1-segments, that got stored in the automaton: " << nStoredSegments <<"\n"; + + return automaton; +} + + + + + + + diff --git a/Utilities/KiTrack/src/Tools/FTDHelixFitter.cc b/Utilities/KiTrack/src/Tools/FTDHelixFitter.cc new file mode 100644 index 00000000..2f0492a0 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/FTDHelixFitter.cc @@ -0,0 +1,124 @@ +#include "Tools/FTDHelixFitter.h" + +#include <sstream> +#include <algorithm> +#include <cmath> + +#include "edm4hep/TrackerHit.h" +#include "UTIL/BitSet32.h" +#include "UTIL/ILDConf.h" +#include "UTIL/LCTrackerConf.h" +//#include "marlin/VerbosityLevels.h" +#include "TrackSystemSvc/HelixFit.h" + +#include "Tools/KiTrackMarlinTools.h" + + +FTDHelixFitter::FTDHelixFitter( std::vector<edm4hep::ConstTrackerHit> trackerHits ){ + _trackerHits = trackerHits; + fit(); +} + +FTDHelixFitter::FTDHelixFitter( edm4hep::Track* track ){ + _trackerHits.clear(); + //int nHits = track->trackerHits_size(); + std::copy(track->trackerHits_begin(), track->trackerHits_end(), std::back_inserter(_trackerHits)); + //for(int i=0;i<nHits;i++){ + // edm4hep::ConstTrackerHit* hit = &track->getTrackerHits(i); + // _trackerHits.push_back(hit); + //} + fit(); +} + +void FTDHelixFitter::fit(){ + std::sort( _trackerHits.begin(), _trackerHits.end(), KiTrackMarlin::compare_TrackerHit_z ); + + int nHits = _trackerHits.size(); + int iopt = 2; + float chi2RPhi; + float chi2Z; + + if( nHits < 3 ){ + std::stringstream s; + s << "FTDHelixFitter::fit(): Cannot fit less with less than 3 hits. Number of hits = " << nHits << "\n"; + + throw FTDHelixFitterException( s.str() ); + } + + double* xh = new double[nHits]; + double* yh = new double[nHits]; + float* zh = new float[nHits]; + double* wrh = new double[nHits]; + float* wzh = new float[nHits]; + float* rh = new float[nHits]; + float* ph = new float[nHits]; + + float par[5]; + float epar[15]; + + for( int i=0; i<nHits; i++ ){ + edm4hep::ConstTrackerHit hit = _trackerHits[i]; + + xh[i] = hit.getPosition()[0]; + yh[i] = hit.getPosition()[1]; + zh[i] = hit.getPosition()[2]; + + float resZ = 0.1; + wzh[i] = 1.0/( resZ * resZ ); + + rh[i] = float(sqrt(xh[i]*xh[i]+yh[i]*yh[i])); + ph[i] = atan2(yh[i],xh[i]); + if (ph[i] < 0.) ph[i] = 2.*M_PI + ph[i]; + + if( UTIL::BitSet32( hit.getType() )[ UTIL::ILDTrkHitTypeBit::COMPOSITE_SPACEPOINT ] ){ + float sigX = hit.getCovMatrix()[0]; + float sigY = hit.getCovMatrix()[2]; + wrh[i] = 1/sqrt( sigX*sigX + sigY*sigY ); + } + else { + //TrackerHitPlane* hitPlane = dynamic_cast<TrackerHitPlane*>( hit ); + //wrh[i] = double(1.0/( hitPlane->getdU()*hitPlane->getdU() + hitPlane->getdV()*hitPlane->getdV() ) ); + wrh[i] = double(1.0/( hit.getCovMatrix(2)*hit.getCovMatrix(2) + hit.getCovMatrix(5)*hit.getCovMatrix(5) )); + } + } + + MarlinTrk::HelixFit helixFitter; + + helixFitter.fastHelixFit(nHits, xh, yh, rh, ph, wrh, zh, wzh,iopt, par, epar, chi2RPhi, chi2Z); + par[3] = par[3]*par[0]/fabs(par[0]); + + _omega = par[0]; + _tanLambda = par[1]; + _phi0 = par[2]; + _d0 = par[3]; + _z0 = par[4]; + + float chi2 = chi2RPhi+chi2Z; + int Ndf = 2*nHits-5; + + delete[] xh; + delete[] yh; + delete[] zh; + delete[] wrh; + delete[] wzh; + delete[] rh; + delete[] ph; + xh = NULL; + yh = NULL; + zh = NULL; + wrh = NULL; + wzh = NULL; + rh = NULL; + ph = NULL; + + //streamlog_out(DEBUG1) << "chi2 = " << chi2 << ", Ndf = " << Ndf << "\n"; + + _chi2 = chi2; + _Ndf = Ndf; + + return; +} + + + + diff --git a/Utilities/KiTrack/src/Tools/Fitter.cc b/Utilities/KiTrack/src/Tools/Fitter.cc new file mode 100644 index 00000000..13ae3aab --- /dev/null +++ b/Utilities/KiTrack/src/Tools/Fitter.cc @@ -0,0 +1,598 @@ +#include "Tools/Fitter.h" + +#include <algorithm> + +//#include "marlin/Global.h" +//#include "UTIL/LCTrackerConf.h" +#include <UTIL/ILDConf.h> + +#include <DD4hep/DD4hepUnits.h> +#include <DD4hep/Detector.h> + +#include "TrackSystemSvc/HelixTrack.h" +#include "DataHelper/Navigation.h" +#include "Tools/KiTrackMarlinTools.h" + +typedef std::vector<edm4hep::ConstTrackerHit> TrackerHitVec; +using namespace MarlinTrk; + +// by fucd: 3.5->3.0 default, will be read from GeoSvc +// if compare to Marlin, should change to 3.5 +float Fitter::_bField = 3.5;//later on overwritten with the value read by geo file + +void Fitter::init_BField(){ + + // B field from DD4hep + /* + dd4hep::Detector & lcdd = dd4hep::Detector::getInstance(); + const double pos[3]={0,0,0}; + double bFieldVec[3]={0,0,0}; + lcdd.field().magneticField(pos,bFieldVec); // get the magnetic field vector from DD4hep + _bField = bFieldVec[2]/dd4hep::tesla; // z component at (0,0,0) + */ + +} + +bool compare_TrackerHit_z( edm4hep::TrackerHit* a, edm4hep::TrackerHit* b ){ + return ( fabs(a->getPosition()[2]) < fabs( b->getPosition()[2]) ); //compare their z values +} + +bool compare_TrackerHit_R( edm4hep::TrackerHit* a, edm4hep::TrackerHit* b ){ + double Rad_a2 = (a->getPosition()[0]*a->getPosition()[0]) + (a->getPosition()[1]*a->getPosition()[1]) ; + double Rad_b2 = (b->getPosition()[0]*b->getPosition()[0]) + (b->getPosition()[1]*b->getPosition()[1]) ; + + return ( Rad_a2 < Rad_b2 ); //compare their radii +} + +Fitter::Fitter( edm4hep::Track* track , MarlinTrk::IMarlinTrkSystem* trkSystem ): _trkSystem( trkSystem ){ + _trackerHits.clear(); + + std::copy(track->trackerHits_begin(), track->trackerHits_end(), std::back_inserter(_trackerHits)); + //_trackerHits = track->getTrackerHits(); + + fit(); +} + +Fitter::Fitter( edm4hep::Track* track , MarlinTrk::IMarlinTrkSystem* trkSystem, int VXDFlag ): _trkSystem( trkSystem ){ + _trackerHits.clear(); + std::copy(track->trackerHits_begin(), track->trackerHits_end(), std::back_inserter(_trackerHits)); + //_trackerHits = track->getTrackerHits(); + fitVXD(); +} + +Fitter::Fitter( std::vector<edm4hep::ConstTrackerHit> trackerHits , MarlinTrk::IMarlinTrkSystem* trkSystem ): _trkSystem( trkSystem ){ + _trackerHits = trackerHits; + fit(); +} + +void Fitter::fitVXD(){ + //create the MarlinTrk + _marlinTrk = _trkSystem->createTrack(); + + /**********************************************************************************************/ + /* Add the hits to the MarlinTrack */ + /**********************************************************************************************/ + + // hits are in reverse order + std::sort( _trackerHits.begin(), _trackerHits.end(), KiTrackMarlin::compare_TrackerHit_R ); + // now at [0] is the hit with the smallest |z| and at [1] is the one with a bigger |z| and so on + // So the direction of the hits when following the index from 0 on is: + // from inside out: from the IP into the distance. + // (It is important to keep in mind, in which direction we fit, when using MarlinTrk) + + TrackerHitVec::iterator it; + + unsigned number_of_added_hits = 0; + unsigned ndof_added = 0; + std::vector< edm4hep::TrackerHit* > added_hits; + std::vector< edm4hep::TrackerHit* > added_hits_2D; + + for( it = _trackerHits.begin() ; it != _trackerHits.end() ; ++it ) { + edm4hep::TrackerHit* trkHit = Navigation::Instance()->GetTrackerHit((*it).getObjectID()); + bool isSuccessful = false; + + if( UTIL::BitSet32( trkHit->getType() )[ UTIL::ILDTrkHitTypeBit::COMPOSITE_SPACEPOINT ] ){ //it is a composite spacepoint + //Split it up and hits to the MarlinTrk + std::vector< edm4hep::TrackerHit* > rawHits; + //const LCObjectVec rawObjects = trkHit->getRawHits(); + //for( unsigned k=0; k<rawObjects.size(); k++ ) rawHits.push_back( dynamic_cast< TrackerHit* >( rawObjects[k] ) ); + int nRawHit = trkHit->rawHits_size(); + for( unsigned k=0; k< nRawHit; k++ ){ + edm4hep::TrackerHit* rawHit = Navigation::Instance()->GetTrackerHit(trkHit->getRawHits(k)); + rawHits.push_back(rawHit); + } + std::sort( rawHits.begin(), rawHits.end(), compare_TrackerHit_R ); + + for( unsigned k=0; k< rawHits.size(); k++ ){ + if( _marlinTrk->addHit( rawHits[k] ) == IMarlinTrack::success ){ + isSuccessful = true; //if at least one hit from the spacepoint gets added + ++ndof_added; // 1 degree of freedom for each strip hit + } + else{ + //std::cout << "Cannot addHit " << rawHits[k]->id() << " to MarlinTrk" << std::endl; + } + } + } + else { // normal non composite hit + if (_marlinTrk->addHit( trkHit ) == 0) { + isSuccessful = true; + ndof_added += 2; + } + } + + if (isSuccessful) { + added_hits.push_back(trkHit); + ++number_of_added_hits; + } + else{ + //std::cout << "DEBUG Fitter::fit(): Hit " << it - _trackerHits.begin() << " Dropped " << std::endl; + } + } + + if( ndof_added < 6 ) { + std::stringstream s; + s << "Fitter::fit(): Cannot fit less with less than 6 degrees of freedom. Number of hits = " << number_of_added_hits << " ndof = " << ndof_added << "\n"; + + throw FitterException( s.str() ); + } + + /**********************************************************************************************/ + /* Create a helix from the first, last and middle hit */ + /**********************************************************************************************/ + + for (unsigned ihit=0; ihit <added_hits.size(); ++ihit) { + // check if this a space point or 2D hit + if(UTIL::BitSet32( added_hits[ihit]->getType() )[ UTIL::ILDTrkHitTypeBit::ONE_DIMENSIONAL ] == false ){ + // then add to the list + added_hits_2D.push_back(added_hits[ihit]); + + } + } + + // initialise with space-points not strips + // make a helix from 3 hits to get a trackstate + const edm4hep::Vector3d x1 = added_hits_2D[0]->getPosition(); + const edm4hep::Vector3d x2 = added_hits_2D[ added_hits_2D.size()/2 ]->getPosition(); + const edm4hep::Vector3d x3 = added_hits_2D.back()->getPosition(); + + init_BField(); + HelixTrack helixTrack( x1, x2, x3, _bField, HelixTrack::forwards ); + + helixTrack.moveRefPoint(0.0, 0.0, 0.0); + + //const float referencePoint[3] = { float(helixTrack.getRefPointX()) , float(helixTrack.getRefPointY() ), float(helixTrack.getRefPointZ() )}; + edm4hep::Vector3f referencePoint = { float(helixTrack.getRefPointX()) , float(helixTrack.getRefPointY() ), float(helixTrack.getRefPointZ() )}; + + /**********************************************************************************************/ + /* Create a TrackStateImpl from the helix values and use it to initalise the fit */ + /**********************************************************************************************/ + std::array<float,15> covMatrix; + + for (unsigned icov = 0; icov<covMatrix.size(); ++icov) { + covMatrix[icov] = 0; + } + + covMatrix[0] = ( 1.e6 ); //sigma_d0^2 + covMatrix[2] = ( 1.e2 ); //sigma_phi0^2 + covMatrix[5] = ( 1.e-4 ); //sigma_omega^2 + covMatrix[9] = ( 1.e6 ); //sigma_z0^2 + covMatrix[14] = ( 1.e2 ); //sigma_tanl^2 + + + edm4hep::TrackState trackState = {0/*TrackState::AtOther*/, + helixTrack.getD0(), + helixTrack.getPhi0(), + helixTrack.getOmega(), + helixTrack.getZ0(), + helixTrack.getTanLambda(), + referencePoint, + covMatrix}; + + //init_BField(); + _marlinTrk->initialise( trackState, _bField, IMarlinTrack::backward ) ; + + // _marlinTrk->initialise( IMarlinTrack::backward ) ; + + /**********************************************************************************************/ + /* Do the fit */ + /**********************************************************************************************/ + + int fit_status = 0; + + try{ + + fit_status = _marlinTrk->fit() ; + + } + catch( MarlinTrk::Exception& e ){ + + std::stringstream s; + s << "Fitter::fit(): Couldn't fit, MarlinTrk->fit() gave: " << e.what() << "\n"; + throw FitterException( s.str() ); + + } + + if( fit_status != IMarlinTrack::success ){ + + std::stringstream s; + s << "Fitter::fit(): MarlinTrk->fit() wasn't successful, fit_status = " << fit_status << "\n"; + throw FitterException( s.str() ); + + } + + + // fitting finished get hits in the fit for safety checks: + + std::vector<std::pair<edm4hep::TrackerHit*, double> > hits_in_fit; + + // remember the hits are ordered in the order in which they were fitted + // here we are fitting inwards so the first is the last and vice verse + + _marlinTrk->getHitsInFit(hits_in_fit); + + if( hits_in_fit.size() < 3 ) { + + + std::stringstream s; + s << "Fitter::fit() Less than 3 hits in fit: Only " << hits_in_fit.size() << + " of " << _trackerHits.size() << " hits\n"; + + throw FitterException( s.str() ); + + } + edm4hep::TrackerHit* first_hit_in_fit = hits_in_fit.back().first; + if (!first_hit_in_fit) { + throw FitterException( std::string("Fitter::fit(): TrackerHit pointer to first hit == NULL ") ) ; + } + + + edm4hep::TrackerHit* last_hit_in_fit = hits_in_fit.front().first; + if (!last_hit_in_fit) { + throw FitterException( std::string("Fitter::fit(): TrackerHit pointer to last hit == NULL ") ) ; + } + + return; +} + + + +void Fitter::fit(){ + //create the MarlinTrk + _marlinTrk = _trkSystem->createTrack(); + + /**********************************************************************************************/ + /* Add the hits to the MarlinTrack */ + /**********************************************************************************************/ + + // hits are in reverse order + std::sort( _trackerHits.begin(), _trackerHits.end(), KiTrackMarlin::compare_TrackerHit_z ); + // now at [0] is the hit with the smallest |z| and at [1] is the one with a bigger |z| and so on + // So the direction of the hits when following the index from 0 on is: + // from inside out: from the IP into the distance. + // (It is important to keep in mind, in which direction we fit, when using MarlinTrk) + + TrackerHitVec::iterator it; + + unsigned number_of_added_hits = 0; + unsigned ndof_added = 0; + std::vector<edm4hep::TrackerHit*> added_hits; + + for( it = _trackerHits.begin() ; it != _trackerHits.end() ; ++it ) { + edm4hep::TrackerHit* trkHit = Navigation::Instance()->GetTrackerHit((*it).getObjectID()); + bool isSuccessful = false; + //std::cout << "Hit " << trkHit->id() << " " << trkHit->getPosition() << std::endl; + if( UTIL::BitSet32( trkHit->getType() )[ UTIL::ILDTrkHitTypeBit::COMPOSITE_SPACEPOINT ] ){ //it is a composite spacepoint + //Split it up and hits to the MarlinTrk + std::vector<edm4hep::TrackerHit*> rawHits; + //const LCObjectVec rawObjects = trkHit->getRawHits(); + //for( unsigned k=0; k<rawObjects.size(); k++ ) rawHits.push_back( dynamic_cast< TrackerHit* >( rawObjects[k] ) ); + int nRawHit = trkHit->rawHits_size(); + for( unsigned k=0; k< nRawHit; k++ ){ + edm4hep::TrackerHit* rawHit = Navigation::Instance()->GetTrackerHit(trkHit->getRawHits(k)); + //std::cout << "Raw Hit " << rawHit->id() << " " << rawHit->getPosition() << std::endl; + rawHits.push_back(rawHit); + } + std::sort( rawHits.begin(), rawHits.end(), compare_TrackerHit_z ); + + for( unsigned k=0; k< rawHits.size(); k++ ){ + if( _marlinTrk->addHit( rawHits[k] ) == IMarlinTrack::success ){ + isSuccessful = true; //if at least one hit from the spacepoint gets added + ++ndof_added; // 1 degree of freedom for each strip hit + } + else{ + //std::cout << "Cannot addHit " << rawHits[k]->id() << " to MarlinTrk" << std::endl; + } + } + } + else { // normal non composite hit + + if (_marlinTrk->addHit( trkHit ) == 0) { + isSuccessful = true; + ndof_added += 2; + } + } + + if (isSuccessful) { + added_hits.push_back(trkHit); + ++number_of_added_hits; + } + else{ + //std::cout << "DEBUG: Fitter::fit(): Hit " << it - _trackerHits.begin() << " Dropped " << std::endl; + } + } + + if( ndof_added < 6 ) { + std::stringstream s; + s << "Fitter::fit(): Cannot fit less with less than 6 degrees of freedom. Number of hits = " << number_of_added_hits << " ndof = " << ndof_added << "\n"; + + throw FitterException( s.str() ); + } + + /**********************************************************************************************/ + /* Create a helix from the first, last and middle hit */ + /**********************************************************************************************/ + + // initialise with space-points not strips + // make a helix from 3 hits to get a trackstate + const edm4hep::Vector3d x1 = added_hits[0]->getPosition(); + const edm4hep::Vector3d x2 = added_hits[ added_hits.size()/2 ]->getPosition(); + const edm4hep::Vector3d x3 = added_hits.back()->getPosition(); + + init_BField(); + HelixTrack helixTrack( x1, x2, x3, _bField, HelixTrack::forwards ); + + helixTrack.moveRefPoint(0.0, 0.0, 0.0); + + //const float referencePoint[3] = { float(helixTrack.getRefPointX()) , float(helixTrack.getRefPointY()) , float(helixTrack.getRefPointZ()) }; + edm4hep::Vector3f referencePoint = { float(helixTrack.getRefPointX()) , float(helixTrack.getRefPointY()) , float(helixTrack.getRefPointZ()) }; + + /**********************************************************************************************/ + /* Create a TrackStateImpl from the helix values and use it to initalise the fit */ + /**********************************************************************************************/ + std::array<float,15> covMatrix; + for (unsigned icov = 0; icov<covMatrix.size(); ++icov) { + covMatrix[icov] = 0; + } + + covMatrix[0] = ( 1.e6 ); //sigma_d0^2 + covMatrix[2] = ( 1.e2 ); //sigma_phi0^2 + covMatrix[5] = ( 1.e-4 ); //sigma_omega^2 + covMatrix[9] = ( 1.e6 ); //sigma_z0^2 + covMatrix[14] = ( 1.e2 ); //sigma_tanl^2 + + edm4hep::TrackState trackState = {0/*TrackState::AtOther*/, + helixTrack.getD0(), + helixTrack.getPhi0(), + helixTrack.getOmega(), + helixTrack.getZ0(), + helixTrack.getTanLambda(), + referencePoint, + covMatrix}; + + //init_BField(); + _marlinTrk->initialise( trackState, _bField, IMarlinTrack::backward ) ; + + // _marlinTrk->initialise( IMarlinTrack::backward ) ; + + /**********************************************************************************************/ + /* Do the fit */ + /**********************************************************************************************/ + int fit_status = 0; + + try{ + fit_status = _marlinTrk->fit() ; + } + catch( MarlinTrk::Exception& e ){ + std::stringstream s; + s << "Fitter::fit(): Couldn't fit, MarlinTrk->fit() gave: " << e.what() << "\n"; + throw FitterException( s.str() ); + } + + if( fit_status != IMarlinTrack::success ){ + std::stringstream s; + s << "Fitter::fit(): MarlinTrk->fit() wasn't successful, fit_status = " << fit_status << "\n"; + throw FitterException( s.str() ); + } + + // fitting finished get hits in the fit for safety checks: + + std::vector<std::pair<edm4hep::TrackerHit*, double> > hits_in_fit; + + // remember the hits are ordered in the order in which they were fitted + // here we are fitting inwards so the first is the last and vice verse + + _marlinTrk->getHitsInFit(hits_in_fit); + + if( hits_in_fit.size() < 3 ) { + std::stringstream s; + s << "Fitter::fit() Less than 3 hits in fit: Only " << hits_in_fit.size() + << " of " << _trackerHits.size() << " hits\n"; + + throw FitterException( s.str() ); + } + edm4hep::TrackerHit* first_hit_in_fit = hits_in_fit.back().first; + if (!first_hit_in_fit) { + throw FitterException( std::string("Fitter::fit(): TrackerHit pointer to first hit == NULL ") ) ; + } + + edm4hep::TrackerHit* last_hit_in_fit = hits_in_fit.front().first; + if (!last_hit_in_fit) { + throw FitterException( std::string("Fitter::fit(): TrackerHit pointer to last hit == NULL ") ) ; + } + + return; +} + + +const edm4hep::TrackState* Fitter::getTrackState( int trackStateLocation ){ + return getTrackStatePlus( trackStateLocation )->getTrackState(); +} + +double Fitter::getChi2Prob( int trackStateLocation ){ + return ROOT::Math::chisquared_cdf_c( getChi2( trackStateLocation ) , getNdf( trackStateLocation ) ); +} + +double Fitter::getChi2( int trackStateLocation ){ + return getTrackStatePlus( trackStateLocation )->getChi2(); +} + +int Fitter::getNdf( int trackStateLocation ){ + return getTrackStatePlus( trackStateLocation )->getNdf(); +} + + +const TrackStatePlus* Fitter::getTrackStatePlus( int trackStateLocation ){ + // check if there is already an entry with this trackState location + for( unsigned i=0; i<_trackStatesPlus.size(); i++ ){ + if( _trackStatesPlus[i]->getTrackState()->location == trackStateLocation ){ + return _trackStatesPlus[i]; + } + } + + // If we reach this point, obviously no trackState with the given location has been created so far + // Thus we create it now + edm4hep::TrackState* trackState = new edm4hep::TrackState; + int return_code = 0; + double chi2; + int ndf; + switch( trackStateLocation ){ + case 1/*lcio::TrackState::AtIP*/:{ + const edm4hep::Vector3d point(0.,0.,0.); // nominal IP + + return_code = _marlinTrk->propagate(point, *trackState, chi2, ndf ) ; + + if (return_code != MarlinTrk::IMarlinTrack::success ) { + delete trackState; + + std::stringstream s; + s << "Fitter::getTrackStatePlus(): Couldn't create TrackState at IP, return code from propagation = " << return_code << "\n"; + throw FitterException( s.str() ); + + break; + } + else{ + trackState->location = trackStateLocation; + TrackStatePlus* trackStatePlus = new TrackStatePlus( trackState, chi2, ndf ); + _trackStatesPlus.push_back( trackStatePlus ); + return trackStatePlus; + } + } + case 2/*lcio::TrackState::AtFirstHit*/:{ + std::vector<std::pair<edm4hep::TrackerHit*, double> > hits_in_fit; + + // remember the hits are ordered in the order in which they were fitted + // here we are fitting inwards so the first is the last and vice verse + _marlinTrk->getHitsInFit(hits_in_fit); + + edm4hep::TrackerHit* first_hit_in_fit = hits_in_fit.back().first; + + return_code = _marlinTrk->getTrackState(first_hit_in_fit, *trackState, chi2, ndf ) ; + + if(return_code !=MarlinTrk::IMarlinTrack::success){ + + delete trackState; + + std::stringstream s; + s << "Fitter::getTrackStatePlus(): Couldn't create TrackState at first hit, return code from propagation = " << return_code << "\n"; + throw FitterException( s.str() ); + + break; + } + else{ + trackState->location = trackStateLocation; + TrackStatePlus* trackStatePlus = new TrackStatePlus( trackState, chi2, ndf ); + _trackStatesPlus.push_back( trackStatePlus ); + return trackStatePlus; + } + } + case 3/*lcio::TrackState::AtLastHit*/:{ + std::vector<std::pair<edm4hep::TrackerHit*, double> > hits_in_fit; + _marlinTrk->getHitsInFit(hits_in_fit); + + edm4hep::TrackerHit* last_hit_in_fit = hits_in_fit.front().first; + + return_code = _marlinTrk->getTrackState(last_hit_in_fit, *trackState, chi2, ndf ) ; + + if(return_code !=MarlinTrk::IMarlinTrack::success){ + delete trackState; + + std::stringstream s; + s << "Fitter::getTrackStatePlus(): Couldn't create TrackState at last hit, return code from propagation = " << return_code << "\n"; + throw FitterException( s.str() ); + + break; + } + else{ + trackState->location = trackStateLocation; + TrackStatePlus* trackStatePlus = new TrackStatePlus( trackState, chi2, ndf ); + _trackStatesPlus.push_back( trackStatePlus ); + return trackStatePlus; + } + break; + } + case 4/*lcio::TrackState::AtCalorimeter*/:{ + std::vector<std::pair<edm4hep::TrackerHit*, double> > hits_in_fit; + _marlinTrk->getHitsInFit(hits_in_fit); + + edm4hep::TrackerHit* last_hit_in_fit = hits_in_fit.front().first; + + UTIL::BitField64 encoder( UTIL::ILDCellID0::encoder_string ) ; + encoder.reset() ; // reset to 0 + + // ================== need to get the correct ID(s) for the calorimeter face ============================ + unsigned ecal_barrel_face_ID = UTIL::ILDDetID::ECAL ; + //unsigned ecal_endcap_face_ID = UTIL::ILDDetID::ECAL_ENDCAP ; + //========================================================================================================= + + encoder[UTIL::ILDCellID0::subdet] = ecal_barrel_face_ID ; + encoder[UTIL::ILDCellID0::side] = UTIL::ILDDetID::barrel; + encoder[UTIL::ILDCellID0::layer] = 0 ; + + int detElementID = 0; + return_code = _marlinTrk->propagateToLayer(encoder.lowWord(), last_hit_in_fit, *trackState, chi2, ndf, detElementID, IMarlinTrack::modeForward ) ; + + if (return_code == MarlinTrk::IMarlinTrack::no_intersection ) { // try forward or backward + //encoder[UTIL::ILDCellID0::subdet] = ecal_endcap_face_ID ; + + const edm4hep::TrackState* trkStateLastHit = getTrackStatePlus( 3/*lcio::TrackState::AtLastHit*/ )->getTrackState(); + + if (trkStateLastHit->tanLambda>0) { + encoder[UTIL::ILDCellID0::side] = UTIL::ILDDetID::fwd; + } + else{ + encoder[UTIL::ILDCellID0::side] = UTIL::ILDDetID::bwd; + } + return_code = _marlinTrk->propagateToLayer(encoder.lowWord(), last_hit_in_fit, *trackState, chi2, ndf, detElementID, IMarlinTrack::modeForward ) ; + } + + if(return_code !=MarlinTrk::IMarlinTrack::success){ + delete trackState; + + std::stringstream s; + s << "Fitter::getTrackStatePlus(): Couldn't create TrackState at Calorimeter, return code from propagation = " << return_code << "\n"; + throw FitterException( s.str() ); + break; + } + else{ + trackState->location = trackStateLocation; + TrackStatePlus* trackStatePlus = new TrackStatePlus( trackState, chi2, ndf ); + _trackStatesPlus.push_back( trackStatePlus ); + return trackStatePlus; + } + } + default:{ + std::stringstream s; + s << "Creation of a trackState for the given location " << trackStateLocation + << " is not yet implemented for the class Fitter. \nImplemented are: AtIP, AtFirstHit, AtLastHit, AtCalorimeter.\n" + << "If another location is desired, it must be implemented in the method Fitter::getTrackStatePlus.\n"; + + throw FitterException( s.str() ); + return NULL; + } + } + + return NULL; // if we haven't returned so far, there was no success, so we return NULL +} + + + diff --git a/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.cc.bak b/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.cc.bak new file mode 100644 index 00000000..9ff3a242 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.cc.bak @@ -0,0 +1,122 @@ +#include "Tools/KiTrackMarlinCEDTools.h" + +#include <cmath> + +#include <CLHEP/Random/RandFlat.h> + +#include "MarlinCED.h" + + +void KiTrackMarlin::drawAutomatonSegments( const Automaton& automaton ){ + + + std::vector< const Segment* > segments = automaton.getSegments(); + + + for( unsigned i=0 ; i < segments.size(); i++ ){ + + + const Segment* segment = segments[i]; + std::vector < IHit* > hits = segment->getHits(); + + + if ( hits.size() == 1){ //exactly one hit, so draw a point + + + IHit* a = hits[0]; + ced_hit( a->getX() ,a->getY() , a->getZ() , 0 , 3 ,0xff0000 ); + + + } + else{ //more than one point or no points + + for( unsigned j=1 ; j< hits.size() ; j++ ){ // over all hits in the segment (as we connect it with the previous we start with hit 1) + + IHit* a = hits[j]; + IHit* b = hits[j-1]; + + + unsigned int color=0; + unsigned int red=0; + unsigned int blue=0; + unsigned int green=0; + + float p = sqrt ((float) segment->getInnerState() / (float) ( 7 )); + + green = unsigned( ceil ( (1.-p) * 255 ) ); + red = unsigned( floor( 255*p ) ); + blue = unsigned( ceil ( (1.-p) * 255 ) ); + + color = red * 256*256 + green * 256 + blue; + + + ced_line_ID( a->getX() ,a->getY() , a->getZ() , b->getX() ,b->getY() , b->getZ() , 2 , segment->getInnerState()+2 , color, 0); + + } + + } + + } + + +} + + + +void KiTrackMarlin::drawTrack( ITrack* track, int color ){ + + + std::vector < IHit* > hits = track->getHits(); + + for( unsigned j=1 ; j< hits.size() ; j++ ){ // over all hits in the segment (as we connect it with the previous we start with hit 1) + + IHit* a = hits[j]; + IHit* b = hits[j-1]; + + ced_line_ID( a->getX() ,a->getY() , a->getZ() , b->getX() ,b->getY() , b->getZ() , 2 , 5 , color, 0); + + } + + + + +} + + +void KiTrackMarlin::drawTrackRandColor( ITrack* track ){ + + + int red = 0; + int green = 0; + int blue = 0; + + int dist = 0; + int distmin = 60; + + while( dist < distmin ){ + + red = CLHEP::RandFlat::shootInt(256); + green = CLHEP::RandFlat::shootInt(256); + blue = CLHEP::RandFlat::shootInt(256); + + + dist = std::abs( red - green ); + if( std::abs( green - blue ) > dist ) dist = std::abs( green - blue ); + if( std::abs( red - blue ) > dist ) dist = std::abs( red - blue ); + + } + + int color = red * 256*256 + green * 256 + blue; + drawTrack( track, color ); + + + +} + + + + + + + + diff --git a/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.h b/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.h new file mode 100644 index 00000000..e2f3ad29 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/KiTrackMarlinCEDTools.h @@ -0,0 +1,31 @@ +#ifndef KiTrackMarlinCEDTools_h +#define KiTrackMarlinCEDTools_h + +#include "KiTrack/Automaton.h" +#include "KiTrack/ITrack.h" + +using namespace KiTrack; + +namespace KiTrackMarlin{ + + + + /** + * Draws the segments of an automaton. + * Segments will be colored according to their state. + * Also the higher the state, the thicker the line. + */ + void drawAutomatonSegments( const Automaton& automaton ); + + /** + * Draws a track by making straight lines between the hits + */ + void drawTrack( ITrack* track, int color = 0x00ff00 ); + + /** Draw a track in a random color, but not too bright */ + void drawTrackRandColor( ITrack* track ); + +} + +#endif + diff --git a/Utilities/KiTrack/src/Tools/KiTrackMarlinTools.cc b/Utilities/KiTrack/src/Tools/KiTrackMarlinTools.cc new file mode 100644 index 00000000..7bb007c9 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/KiTrackMarlinTools.cc @@ -0,0 +1,262 @@ +#include "Tools/KiTrackMarlinTools.h" + +#include <sstream> +#include <fstream> +#include <cmath> + +#include "TROOT.h" +#include "TTree.h" +#include "TFile.h" + +#include "UTIL/LCTrackerConf.h" + +using namespace KiTrackMarlin; + + +std::string KiTrackMarlin::getCellID0Info( int cellID0 ){ + + std::stringstream s; + + //find out layer, module, sensor + UTIL::BitField64 cellID( UTIL::LCTrackerCellID::encoding_string() ); + cellID.setValue( cellID0 ); + + int subdet = cellID[ UTIL::LCTrackerCellID::subdet() ] ; + int side = cellID[ UTIL::LCTrackerCellID::side() ]; + int module = cellID[ UTIL::LCTrackerCellID::module() ]; + int sensor = cellID[ UTIL::LCTrackerCellID::sensor() ]; + int layer = cellID[ UTIL::LCTrackerCellID::layer() ]; + + s << "(su" << subdet << ",si" << side << ",la" << layer << ",mo" << module << ",se" << sensor << ")"; + + return s.str(); + +} + +int KiTrackMarlin::getCellID0Layer( int cellID0 ){ + + + UTIL::BitField64 cellID( UTIL::LCTrackerCellID::encoding_string() ); + cellID.setValue( cellID0 ); + + return cellID[ UTIL::LCTrackerCellID::layer() ]; + + +} + + + + +void KiTrackMarlin::setUpRootFile( std::string rootNamePath, std::string treeName , std::set<std::string> branchNames , bool createNew ){ + + + std::string fileNamePath = rootNamePath.substr( 0 , rootNamePath.find_last_of(".") ); + + + + std::ifstream rf ((fileNamePath + ".root").c_str()); //rf for RootFile + if ((rf) && (createNew)) { // The file already exists and we don't want to append + + int i=0; + std::stringstream newname; + while (rf){ //Try adding a number starting from 1 to the filename until no file with this name exists and use this. + + rf.close(); + i++; + newname.str(""); + newname << fileNamePath << i << ".root"; + + rf.open( newname.str().c_str() ); + + } + rename ( (fileNamePath + ".root").c_str() , newname.str().c_str()); //renames the file in the way,so that our new file can have it's name + //and not ovrewrite it. + + } + + float x = 0; + + std::string modus = "RECREATE"; + if ( !createNew ) modus = "UPDATE"; + + TFile* myRootFile = new TFile((fileNamePath + ".root").c_str(), modus.c_str() ); //Make new file or update it + TTree* myTree; + + myTree = new TTree(treeName.c_str(),"My tree"); //make a new tree + + //create the branches: + + std::set < std::string >::iterator it; + + + for ( it = branchNames.begin() ; it != branchNames.end() ; it++ ){ + + + myTree->Branch( (*it).c_str() , &x ); + + } + + + myTree->Write("",TObject::kOverwrite); + myRootFile->Close(); + +} + + + + + +void KiTrackMarlin::saveToRoot( std::string rootFileName, std::string treeName , std::map < std::string , float > map_name_data ){ + std::map < std::string , float >::iterator it; + + TFile* myRootFile = new TFile( rootFileName.c_str(), "UPDATE"); //add values to the root file + TTree* myTree = dynamic_cast <TTree*>( myRootFile->Get( treeName.c_str()) ); + + if( myTree == NULL ){ + std::cout << "ERROR: KiTrackMarlin::saveToRoot could not get tree " << treeName << std::endl; + return; + } + + for( it = map_name_data.begin() ; it != map_name_data.end() ; it++){ + myTree->SetBranchAddress( it->first.c_str(), & it->second ); + } + + myTree->Fill(); + myTree->Write("",TObject::kOverwrite); + + myRootFile->Close(); +} + +void KiTrackMarlin::saveToRoot( std::string rootFileName, std::string treeName , std::vector < std::map < std::string , float > > rootDataVec ){ + std::map < std::string , float >::iterator it; + + TFile* myRootFile = new TFile( rootFileName.c_str(), "UPDATE"); //add values to the root file + TTree* myTree = dynamic_cast <TTree*>( myRootFile->Get( treeName.c_str()) ); + + if( myTree == NULL ){ + std::cout << "ERROR: KiTrackMarlin::saveToRoot could not get tree " << treeName << std::endl; + return; + } + + for( unsigned i=0; i<rootDataVec.size(); i++ ){ //for all entries + std::map < std::string , float > map_name_data = rootDataVec[i]; + for( it = map_name_data.begin() ; it != map_name_data.end() ; it++){ // for all data in the entrie + myTree->SetBranchAddress( it->first.c_str(), & it->second ); + } + myTree->Fill(); + } + myTree->Write("",TObject::kOverwrite); + myRootFile->Close(); +} + + +//bool KiTrackMarlin::compare_TrackerHit_z( edm4hep::ConstTrackerHit* a, edm4hep::ConstTrackerHit* b ){ +// return ( fabs(a->getPosition()[2]) < fabs( b->getPosition()[2]) ); //compare their z values +//} + +bool KiTrackMarlin::compare_TrackerHit_z( edm4hep::ConstTrackerHit& a, edm4hep::ConstTrackerHit& b ){ + return ( fabs(a.getPosition()[2]) < fabs( b.getPosition()[2]) ); +} + +bool KiTrackMarlin::compare_TrackerHit_R( edm4hep::ConstTrackerHit& a, edm4hep::ConstTrackerHit& b ){ + double Rad_a2 = (a.getPosition()[0]*a.getPosition()[0]) + (a.getPosition()[1]*a.getPosition()[1]) ; + double Rad_b2 = (b.getPosition()[0]*b.getPosition()[0]) + (b.getPosition()[1]*b.getPosition()[1]) ; + + return ( Rad_a2 < Rad_b2 ); //compare their radii +} + + + +FTDHitSimple* KiTrackMarlin::createVirtualIPHit( int side , const SectorSystemFTD* sectorSystemFTD ){ + + unsigned layer = 0; + unsigned module = 0; + unsigned sensor = 0; + FTDHitSimple* virtualIPHit = new FTDHitSimple( 0.,0.,0., side , layer , module , sensor , sectorSystemFTD ); + + + virtualIPHit->setIsVirtual ( true ); + + return virtualIPHit; + +} + + +VXDHitSimple* KiTrackMarlin::createVirtualIPHit( const SectorSystemVXD* sectorSystemVXD ){ + + int layer = 0 ; + int phi = 0 ; + int theta = 0 ; + + VXDHitSimple* virtualIPHit = new VXDHitSimple( 0.,0.,0., layer, phi, theta, sectorSystemVXD ); + + virtualIPHit->setIsVirtual ( true ); + + return virtualIPHit; + +} + + +std::string KiTrackMarlin::getPositionInfo( edm4hep::ConstTrackerHit* hit ){ + + std::stringstream info; + + double x = hit->getPosition()[0]; + double y = hit->getPosition()[1]; + double z = hit->getPosition()[2]; + + info << "(" << x << "," << y << "," << z << ")"; + + return info.str(); + +} + +std::string KiTrackMarlin::getPositionInfo( IHit* hit ){ + + std::stringstream info; + + double x = hit->getX(); + double y = hit->getY(); + double z = hit->getZ(); + + info << "(" << x << "," << y << "," << z << ")"; + + return info.str(); + +} + + +std::string KiTrackMarlin::getTrackHitInfo( ITrack* track){ + + std::stringstream info; + + std::vector< IHit* > hits = track->getHits(); + + for( unsigned i=0; i < hits.size(); i++ ){ + + info << getPositionInfo( hits[i] ); + + }; + + return info.str(); + + +} + +std::string KiTrackMarlin::getTrackHitInfo( edm4hep::Track* track){ + std::stringstream info; + //std::vector< edm4hep::TrackerHit* > hits; + unsigned int nHits = track->trackerHits_size(); + for(unsigned i=0; i<nHits; i++){ + edm4hep::ConstTrackerHit hit = track->getTrackerHits(i); + info << getPositionInfo(&hit); + } + + //for( unsigned i=0; i < hits.size(); i++ ){ + // info << getPositionInfo( hits[i] ); + //}; + + return info.str(); +} + + diff --git a/Utilities/KiTrack/src/Tools/Timer.cc b/Utilities/KiTrack/src/Tools/Timer.cc new file mode 100644 index 00000000..2597141d --- /dev/null +++ b/Utilities/KiTrack/src/Tools/Timer.cc @@ -0,0 +1,127 @@ +#include "Tools/Timer.h" + +#include <string> +#include <fstream> +#include <iterator> +#include <cstdlib> +#include <iostream> + +#define FINE_GRAINED_LINUX_TIMING + +#include <ctime> +#include <sys/times.h> +#include <unistd.h> + +using namespace std; +using namespace KiTrackMarlin; + +namespace { + #ifdef FINE_GRAINED_LINUX_TIMING + static unsigned cyc_hi = 0; + static unsigned cyc_lo = 0; + + void access_counter(unsigned *hi, unsigned *lo) + { + asm("rdtsc; movl %%edx,%0; movl %%eax,%1" + : "=r" (*hi), "=r" (*lo) + : + : "%edx", "%eax"); + } + + double get_counter() + { + unsigned ncyc_hi, ncyc_lo; + unsigned hi, lo, borrow; + access_counter(&ncyc_hi, &ncyc_lo); + lo = ncyc_lo - cyc_lo; + borrow = lo > ncyc_lo; + hi = ncyc_hi - cyc_hi - borrow; + return (double) hi * (1 << 30) * 4 + lo; + } + #else + clock_t before; + #endif +} + +double Timer::cpuMHz() +{ + static double ret=-1.; + if ( ret > -.5 ) return ret; + string input="Unknow CPU"; + { + ifstream cpuinfo("/proc/cpuinfo"); + if ( cpuinfo.is_open() ) + { + cpuinfo.unsetf( ios::skipws ); + istream_iterator<char> sbegin(cpuinfo),send; + copy(sbegin,send,inserter(input,input.end())); + cpuinfo.close(); + }; + } + + size_t i = input.find("model name"); + if (i!=string::npos ) + { + i = input.find("@ ",i); + if ( i != string::npos ) + { + size_t j = input.find("GHz",i); + //cout << "[debug] i=" << i << " j=" << j << " string=" << input.substr(i+1,j-i-1) << "X" << endl; + return 1000.*atof(input.substr(i+1,j-i-1).c_str() ); + }; + + } + + i = input.find("cpu MHz"); + if (i==string::npos) + { + cout << "[Timer] /proc/cpuinfo does not contain cpu speed..." << endl; + ret=0.; + }; + i = input.find(":",i); + ret=atof(input.substr(i+1,input.find("/n",i)-i).c_str()); + return ret; +} + +void Timer::start_counter() +{ + #ifdef FINE_GRAINED_LINUX_TIMING + access_counter(&cyc_hi, &cyc_lo); + #else + tms buf; + times( &buf ); + before = buf.tms_utime; + #endif +} + +double Timer::lap() +{ + #ifdef FINE_GRAINED_LINUX_TIMING + return get_counter() / cpuMHz() / 1.e6; + #else + tms buf; + times ( &buf ); + clock_t after = buf.tms_utime; + static float cps=sysconf(_SC_CLK_TCK); + double t = ( after - before ) / cps; + return t; + #endif +} + +double Timer::ticks() +{ + #ifdef FINE_GRAINED_LINUX_TIMING + return get_counter(); + #else + tms buf; + times ( &buf ); + clock_t after = buf.tms_utime; + // static float cps=sysconf(_SC_CLK_TCK); + double t = ( after - before ); + return t; + #endif +} + +#ifdef FINE_GRAINED_LINUX_TIMING +#undef FINE_GRAINED_LINUX_TIMING +#endif diff --git a/Utilities/KiTrack/src/Tools/Timer.h b/Utilities/KiTrack/src/Tools/Timer.h new file mode 100644 index 00000000..7c3cd3bd --- /dev/null +++ b/Utilities/KiTrack/src/Tools/Timer.h @@ -0,0 +1,22 @@ +#ifndef dataharvester_Timer_H_ +#define dataharvester_Timer_H_ + +namespace KiTrackMarlin { +class Timer { +public: + /** + * A fast, precise timer + * Works on linux only + * + * Author: Wolfgang Waltenberger + */ + static void start_counter(); + + /// Return what the harvester thinks is the CPU frequency. + static double cpuMHz(); + static double lap(); //< lapsed time, in seconds. + static double ticks(); //< lapsed time, in clock ticks. +}; +} + +#endif // dataharvester_Timer_H_ diff --git a/Utilities/KiTrack/src/Tools/VXDHelixFitter.cc.bak b/Utilities/KiTrack/src/Tools/VXDHelixFitter.cc.bak new file mode 100644 index 00000000..515a8029 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/VXDHelixFitter.cc.bak @@ -0,0 +1,190 @@ +#include "Tools/VXDHelixFitter.h" + +#include <sstream> +#include <algorithm> +#include <cmath> + +#include "edm4hep/TrackerHit.h" +#include "UTIL/ILDConf.h" +#include "UTIL/LCTrackerConf.h" +//#include "marlin/VerbosityLevels.h" +#include "TrackSystemSvc/HelixFit.h" + +#include "Tools/KiTrackMarlinTools.h" + + +VXDHelixFitter::VXDHelixFitter( std::vector< TrackerHit* > trackerHits ){ + + _trackerHits = trackerHits; + + fit(); + +} + +VXDHelixFitter::VXDHelixFitter( Track* track ){ + + _trackerHits = track->getTrackerHits(); + + fit(); + +} + +void VXDHelixFitter::fit(){ + + std::vector< TrackerHit* > trackerHits2D ; + + for (unsigned ihit=0; ihit <_trackerHits.size(); ++ihit) { + + // check if this a space point or 2D hit + if(UTIL::BitSet32( _trackerHits[ihit]->getType() )[ UTIL::ILDTrkHitTypeBit::ONE_DIMENSIONAL ] == false ){ + // then add to the list + trackerHits2D.push_back(_trackerHits[ihit]); + + } + } + + std::sort( trackerHits2D.begin(), trackerHits2D.end(), KiTrackMarlin::compare_TrackerHit_R ); + + int nHits = trackerHits2D.size(); + + int iopt = 2; + float chi2RPhi; + float chi2Z; + + // DEBUG + //streamlog_out(DEBUG4) << " no of hits fitted " << nHits << std::endl ; + + if( nHits < 3 ){ + + std::stringstream s; + s << "VXDHelixFitter::fit(): Cannot fit less with less than 3 hits. Number of hits = " << nHits << "\n"; + + throw VXDHelixFitterException( s.str() ); + + } + + double* xh = new double[nHits]; + double* yh = new double[nHits]; + float* zh = new float[nHits]; + double* wrh = new double[nHits]; + float* wzh = new float[nHits]; + float* rh = new float[nHits]; + float* ph = new float[nHits]; + + float par[5]; + float epar[15]; + + for( int i=0; i<nHits; i++ ){ + + TrackerHit* hit = trackerHits2D[i]; + + xh[i] = hit->getPosition()[0]; + yh[i] = hit->getPosition()[1]; + zh[i] = float(hit->getPosition()[2]); + + //wrh[i] = double(1.0/(hit->getResolutionRPhi()*hit->getResolutionRPhi())); + //wzh[i] = 1.0/(hit->getResolutionZ()*hit->getResolutionZ()); + //wrh[i] = double(1.0/(sqrt((hit->getCovMatrix()[0]*hit->getCovMatrix()[0]) + (hit->getCovMatrix()[2]*hit->getCovMatrix()[2])))); + //wzh[i] = 1.0/(hit->getCovMatrix()[5]); + + rh[i] = float(sqrt(xh[i]*xh[i]+yh[i]*yh[i])); + ph[i] = atan2(yh[i],xh[i]); + if (ph[i] < 0.) + ph[i] = 2.*M_PI + ph[i]; + + // Just to debug the resolutions + //streamlog_out(DEBUG4) << " hit's radius " << rh[i] << " R-phi uncertainty " << wrh[i] << " Z uncertainty " << wzh[i] << " Cov[0] " << hit->getCovMatrix()[0] << " Cov[2] " << hit->getCovMatrix()[2] << " Cov[5] " << hit->getCovMatrix()[5] << std::endl ; + + // check for composite spacepoints + if( BitSet32( hit->getType() )[ UTIL::ILDTrkHitTypeBit::COMPOSITE_SPACEPOINT ] ){ + + //streamlog_out(DEBUG4) << " COMPOSITE SPACEPOINT radius: " << rh[i] << std::endl ; + + float sigX = hit->getCovMatrix()[0]; + float sigY = hit->getCovMatrix()[2]; + wrh[i] = 1/sqrt( sigX*sigX + sigY*sigY ); + wzh[i] = 1.0/(hit->getCovMatrix()[5]); + + //streamlog_out(DEBUG4) << " SPACEPOINT:: hit's radius " << rh[i] << " R-phi uncertainty " << wrh[i] << " Z uncertainty " << wzh[i] << " res RPhi " << sqrt( sigX*sigX + sigY*sigY ) << " res Z " << (hit->getCovMatrix()[5]) << std::endl ; + + } + else if ( BitSet32( hit->getType() )[ UTIL::ILDTrkHitTypeBit::ONE_DIMENSIONAL ] ) { + + // YV: FIXME: very crude hack, hard coded the SIT strip digital resolution in V + //streamlog_out(DEBUG4) << " 1D hit radius: " << rh[i] << std::endl ; + + //TrackerHitPlane* hitPlane = dynamic_cast<TrackerHitPlane*>( hit ); + //wrh[i] = double(1.0/( hitPlane->getdU()*hitPlane->getdU() )); + wrh[i] = double(1.0/( hit->getCovMatrix(2)*hit->getCovMatrix(2) )); + double resZ = 92.0 / std::sqrt( 12. ) ; + //double resZ = 0.003 ; + wzh[i] = 1.0/( resZ * resZ ); + + //streamlog_out(DEBUG4) << " 1Dimensional TRACKERHITPLANE:: hit's radius " << rh[i] << " R-phi uncertainty " << wrh[i] << " Z uncertainty " << wzh[i] << " dU " << hitPlane->getdU() << " dV " << resZ << " 1/du^2 "<< (1/(hitPlane->getdU()*hitPlane->getdU())) << " 1/dv^2 "<< wzh[i] << std::endl ; + + } + + else { + + //streamlog_out(DEBUG4) << " 2D hit radius: " << rh[i] << std::endl ; + //TrackerHitPlane* hitPlane = dynamic_cast<TrackerHitPlane*>( hit ); + //wrh[i] = double(1.0/( hitPlane->getdU()*hitPlane->getdU() )); + //wzh[i] = wrh[i]; // pixel VXD + wrh[i] = double(1.0/( hit->getCovMatrix(2)*hit->getCovMatrix(2) )); + wzh[i] = double(1.0/( hit->getCovMatrix(5)*hit->getCovMatrix(5) )); + + //streamlog_out(DEBUG4) << "2D pixel TRACKERHITPLANE:: hit's radius " << rh[i] << " R-phi uncertainty " << wrh[i] << " Z uncertainty " << wzh[i] << " dU " << hitPlane->getdU() << " dV " << hitPlane->getdV() << " 1/du^2 "<< (1/(hitPlane->getdU()*hitPlane->getdU())) << " 1/dv^2 "<< (1/(hitPlane->getdV()*hitPlane->getdV())) << std::endl ; + + } + } + + + + + MarlinTrk::HelixFit helixFitter; + + helixFitter.fastHelixFit(nHits, xh, yh, rh, ph, wrh, zh, wzh,iopt, par, epar, chi2RPhi, chi2Z); + par[3] = par[3]*par[0]/fabs(par[0]); + + _omega = par[0]; + _tanLambda = par[1]; + _phi0 = par[2]; + _d0 = par[3]; + _z0 = par[4]; + + float chi2 = chi2RPhi+chi2Z; + int Ndf = 2*nHits-5; + + + + + delete[] xh; + delete[] yh; + delete[] zh; + delete[] wrh; + delete[] wzh; + delete[] rh; + delete[] ph; + xh = NULL; + yh = NULL; + zh = NULL; + wrh = NULL; + wzh = NULL; + rh = NULL; + ph = NULL; + + + //streamlog_out(DEBUG4) << "chi2 rphi = " << chi2RPhi << ", chi2 Z = " << chi2Z << ", Ndf = " << Ndf << "\n"; + + _chi2 = chi2; + _Ndf = Ndf; + + return; + + + +} + + + + diff --git a/Utilities/KiTrack/src/Tools/VXDHelixFitter.h b/Utilities/KiTrack/src/Tools/VXDHelixFitter.h new file mode 100644 index 00000000..cf066262 --- /dev/null +++ b/Utilities/KiTrack/src/Tools/VXDHelixFitter.h @@ -0,0 +1,82 @@ +#ifndef VXDHelixFitter_h +#define VXDHelixFitter_h + +#include "edm4hep/Track.h" +#include "edm4hep/TrackerHit.h" + +//#include "lcio.h" + + + +//using namespace lcio; + + + +class VXDHelixFitterException : public std::exception { + + +protected: + std::string message ; + + VXDHelixFitterException(){ /*no_op*/ ; } + +public: + virtual ~VXDHelixFitterException() { /*no_op*/; } + + VXDHelixFitterException( const std::string& text ){ + message = "VXDHelixFitterException: " + text ; + } + + virtual const char* what() const noexcept { return message.c_str() ; } + +}; + + + +/** A class to make it quick to fit a track or hits and get back the chi2 and Ndf values and + * also bundle the code used for that, so it doesn't have to be copied all over the places. + * Uses a helix fit from the MarlinTrk class HelixFit.cc + * It is named VXDHelixFitter, because it makes some assumptions about the hits, that come from them + * being on the VXD. Specifically the errors passed to the helix fit are calculated on the assumption, + * that du and dv are errors in the xy plane. + * If this class is intended to be used for hits on different detectors, a careful redesign is necessary! + */ +class VXDHelixFitter{ + + +public: + + VXDHelixFitter( edm4hep::Track* track ) ; + VXDHelixFitter( std::vector < edm4hep::TrackerHit* > trackerHits ) ; + + + double getChi2(){ return _chi2; } + int getNdf(){ return _Ndf; } + + float getOmega(){ return _omega; } + float getTanLambda(){ return _tanLambda; } + float getPhi0(){ return _phi0; } + float getD0(){ return _d0; } + float getZ0(){ return _z0; } + +private: + + + + void fit(); + + double _chi2; + int _Ndf; + + float _omega; + float _tanLambda; + float _phi0; + float _d0; + float _z0; + + std::vector< edm4hep::TrackerHit* > _trackerHits; + + +}; + +#endif -- GitLab