From b2af0d92111f86adc47f37d06471e69253ad516a Mon Sep 17 00:00:00 2001 From: lgray Date: Tue, 1 May 2018 08:37:39 -0500 Subject: [PATCH] Part 1 of MTD Tracking Integration: Topologies and Geometries --- .../interface/MTDAlignmentErrorExtendedRcd.h | 8 + .../interface/MTDAlignmentErrorRcd.h | 9 + .../interface/MTDAlignmentRcd.h | 9 + .../interface/MTDSurfaceDeformationRcd.h | 8 + .../src/MTDAlignmentErrorExtendedRcd.cc | 3 + .../src/MTDAlignmentErrorRcd.cc | 12 + .../AlignmentRecord/src/MTDAlignmentRcd.cc | 12 + .../src/MTDSurfaceDeformationRcd.cc | 12 + .../interface/PGeometricTimingDet.h | 57 + .../interface/PGeometricTimingDetExtra.h | 35 + .../interface/PMTDParameters.h | 26 + .../src/T_EventSetup_PGeometricTimingDet.cc | 5 + .../T_EventSetup_PGeometricTimingDetExtra.cc | 5 + .../src/T_EventSetup_PMTDParameters.cc | 4 + CondFormats/GeometryObjects/src/classes.h | 3 + .../GeometryObjects/src/classes_def.xml | 20 + .../python/GeometryExtended2023D24Reco_cff.py | 8 +- .../python/GeometryExtended2023D24_cff.py | 2 +- .../python/GeometryExtended2023D25Reco_cff.py | 8 +- .../python/GeometryExtended2023D25_cff.py | 2 +- .../Geometry/python/dict2023Geometry.py | 16 + DataFormats/FTLRecHit/BuildFile.xml | 1 + .../FTLRecHit/interface/FTLTrackingRecHit.h | 50 + .../FTLRecHit/src/FTLTrackingRecHit.cc | 11 + DataFormats/FTLRecHit/src/classes.h | 7 + DataFormats/FTLRecHit/src/classes_def.xml | 7 + DataFormats/ForwardDetId/interface/BTLDetId.h | 6 +- DataFormats/ForwardDetId/interface/ETLDetId.h | 4 +- DataFormats/ForwardDetId/interface/MTDDetId.h | 4 +- .../CommonDetUnit/interface/GeomDetType.h | 1 + .../interface/GlobalTrackingGeometry.h | 2 +- Geometry/CommonDetUnit/interface/MTDGeomDet.h | 21 + Geometry/CommonDetUnit/src/GeomDetType.cc | 5 + .../src/GlobalTrackingGeometry.cc | 8 +- Geometry/CommonDetUnit/src/MTDGeomDet.cc | 21 + .../plugins/BuildFile.xml | 1 + .../plugins/GlobalTrackingGeometryBuilder.cc | 6 +- .../plugins/GlobalTrackingGeometryBuilder.h | 2 + .../GlobalTrackingGeometryESProducer.cc | 17 +- .../test/BuildFile.xml | 1 + .../test/GlobalTrackingGeometryTest.cc | 36 + .../test/testGlobalTrackingGeometry_cfg.py | 6 +- Geometry/MTDGeometryBuilder/BuildFile.xml | 14 + .../MTDGeomBuilderFromGeometricTimingDet.h | 37 + .../interface/MTDGeomDetType.h | 38 + .../interface/MTDGeomDetUnit.h | 59 + .../interface/MTDGeometry.h | 93 ++ .../interface/MTDParametersFromDD.h | 25 + .../interface/MTDTopologyBuilder.h | 26 + .../PlaneBuilderFromGeometricTimingDet.h | 19 + .../interface/ProxyMTDTopology.h | 124 ++ .../interface/RectangularMTDTopology.h | 213 +++ .../MTDGeometryBuilder/plugins/BuildFile.xml | 13 + .../plugins/MTDDigiGeometryESModule.cc | 129 ++ .../plugins/MTDDigiGeometryESModule.h | 38 + .../plugins/MTDParametersESModule.cc | 49 + .../plugins/MTDParametersESModule.h | 33 + .../python/idealForDigiMTDGeometryDB_cff.py | 16 + .../python/idealForDigiMTDGeometry_cff.py | 16 + .../python/mtdModuleInfo_cfg.py | 31 + .../python/mtdParameters_cfi.py | 20 + .../MTDGeometryBuilder/src/ES_MTDGeometry.cc | 7 + .../MTDGeomBuilderFromGeometricTimingDet.cc | 200 +++ .../MTDGeometryBuilder/src/MTDGeomDetUnit.cc | 23 + .../MTDGeometryBuilder/src/MTDGeometry.cc | 262 ++++ .../src/MTDParametersFromDD.cc | 57 + .../src/MTDTopologyBuilder.cc | 38 + .../src/PlaneBuilderFromGeometricTimingDet.cc | 29 + .../src/ProxyMTDTopology.cc | 190 +++ .../src/RectangularMTDTopology.cc | 348 +++++ .../MTDGeometryBuilder/test/BuildFile.xml | 12 + .../test/MTDDigiGeometryAnalyzer.cc | 221 +++ Geometry/MTDGeometryBuilder/test/mtd_cfg.py | 37 + Geometry/MTDNumberingBuilder/BuildFile.xml | 8 + .../MTDNumberingBuilder/bin/BuildFile.xml | 11 + .../bin/stubs/GeometricTimingDetLoader.cc | 217 +++ .../bin/stubs/GeometricTimingDetLoader.h | 30 + .../doc/GeometricDetBuilder.png | Bin 0 -> 153228 bytes .../interface/CmsMTDDebugNavigator.h | 24 + .../interface/CmsMTDStringToEnum.h | 32 + .../interface/GeometricTimingDet.h | 294 ++++ .../interface/GeometricTimingDetExtra.h | 95 ++ .../interface/MTDMapDDDtoID.h | 42 + .../interface/MTDTopology.h | 187 +++ .../MTDNumberingBuilder/plugins/BuildFile.xml | 10 + .../plugins/CmsMTDAbstractConstruction.h | 18 + .../plugins/CmsMTDBuilder.cc | 65 + .../plugins/CmsMTDBuilder.h | 22 + .../plugins/CmsMTDConstruction.cc | 90 ++ .../plugins/CmsMTDConstruction.h | 18 + .../plugins/CmsMTDDetIdBuilder.cc | 113 ++ .../plugins/CmsMTDDetIdBuilder.h | 33 + .../plugins/CmsMTDDiscBuilder.cc | 59 + .../plugins/CmsMTDDiscBuilder.h | 20 + .../plugins/CmsMTDETLRingBuilder.cc | 28 + .../plugins/CmsMTDETLRingBuilder.h | 18 + .../plugins/CmsMTDEndcapBuilder.cc | 49 + .../plugins/CmsMTDEndcapBuilder.h | 21 + .../plugins/CmsMTDLevelBuilder.cc | 31 + .../plugins/CmsMTDLevelBuilder.h | 207 +++ .../plugins/CmsMTDModuleBuilder.cc | 31 + .../plugins/CmsMTDModuleBuilder.h | 19 + .../plugins/CmsMTDSubStrctBuilder.cc | 58 + .../plugins/CmsMTDSubStrctBuilder.h | 21 + .../plugins/CmsMTDTrayBuilder.cc | 65 + .../plugins/CmsMTDTrayBuilder.h | 18 + .../plugins/CondDBCmsMTDConstruction.cc | 75 + .../plugins/CondDBCmsMTDConstruction.h | 26 + .../plugins/DDDCmsMTDConstruction.cc | 75 + .../plugins/DDDCmsMTDConstruction.h | 29 + .../plugins/ExtractStringFromDDD.cc | 27 + .../plugins/ExtractStringFromDDD.h | 19 + .../plugins/MTDGeometricTimingDetESModule.cc | 61 + .../plugins/MTDGeometricTimingDetESModule.h | 31 + .../MTDGeometricTimingDetExtraESModule.cc | 160 +++ .../MTDGeometricTimingDetExtraESModule.h | 31 + .../plugins/MTDStablePhiSort.h | 119 ++ .../plugins/MTDTopologyEP.cc | 64 + .../plugins/MTDTopologyEP.h | 33 + .../src/CmsMTDDebugNavigator.cc | 43 + .../src/CmsMTDStringToEnum.cc | 58 + .../MTDNumberingBuilder/src/ES_MTDTopology.cc | 5 + .../src/GeometricTimingDet.cc | 333 +++++ .../src/GeometricTimingDetExtra.cc | 14 + .../MTDNumberingBuilder/src/MTDMapDDDtoID.cc | 71 + .../MTDNumberingBuilder/src/MTDTopology.cc | 149 ++ Geometry/MTDNumberingBuilder/src/module.cc | 10 + .../MTDNumberingBuilder/test/BuildFile.xml | 14 + Geometry/MTDNumberingBuilder/test/FakeCPP.h | 33 + .../test/GeometricTimingDetAnalyzer.cc | 125 ++ .../test/MTDModuleNumbering.cc | 1251 +++++++++++++++++ Geometry/MTDNumberingBuilder/test/mtd_cfg.py | 20 + .../test/trackerTopology_cfg.py | 17 + Geometry/Records/interface/BTLGeometryRcd.h | 6 + Geometry/Records/interface/ETLGeometryRcd.h | 6 + .../interface/GlobalTrackingGeometryRecord.h | 3 +- .../Records/interface/IdealGeometryRecord.h | 3 +- .../Records/interface/MTDDigiGeometryRecord.h | 25 + .../Records/interface/MTDGeometryRecord.h | 24 + Geometry/Records/interface/MTDTopologyRcd.h | 14 + .../interface/PGeometricTimingDetExtraRcd.h | 6 + .../Records/interface/PMTDParametersRcd.h | 12 + Geometry/Records/src/BTLGeometryRcd.cc | 5 + Geometry/Records/src/ETLGeometryRcd.cc | 5 + Geometry/Records/src/MTDDigiGeometryRecord.cc | 15 + Geometry/Records/src/MTDGeometryRecord.cc | 4 + Geometry/Records/src/MTDTopologyRcd.cc | 4 + .../src/PGeometricTimingDetExtraRcd.cc | 4 + Geometry/Records/src/PMTDParametersRcd.cc | 4 + RecoMTD/DetLayers/BuildFile.xml | 12 + .../DetLayers/interface/MTDDetLayerGeometry.h | 82 ++ RecoMTD/DetLayers/interface/MTDDetRing.h | 56 + RecoMTD/DetLayers/interface/MTDDetTray.h | 58 + .../interface/MTDRingForwardDoubleLayer.h | 80 ++ .../DetLayers/interface/MTDRingForwardLayer.h | 65 + .../DetLayers/interface/MTDTrayBarrelLayer.h | 63 + RecoMTD/DetLayers/plugins/BuildFile.xml | 10 + .../plugins/MTDDetLayerGeometryESProducer.cc | 56 + .../plugins/MTDDetLayerGeometryESProducer.h | 33 + RecoMTD/DetLayers/plugins/SealModule.cc | 6 + .../python/mtdDetLayerGeometry_cfi.py | 9 + .../src/BTLDetLayerGeometryBuilder.cc | 69 + .../src/BTLDetLayerGeometryBuilder.h | 30 + .../DetLayers/src/ES_MTDDetLayerGeometry.cc | 5 + .../src/ETLDetLayerGeometryBuilder.cc | 122 ++ .../src/ETLDetLayerGeometryBuilder.h | 37 + RecoMTD/DetLayers/src/GeneralBinFinderInPhi.h | 1 + RecoMTD/DetLayers/src/GeneralBinFinderInR.h | 1 + RecoMTD/DetLayers/src/MTDDetLayerGeometry.cc | 180 +++ RecoMTD/DetLayers/src/MTDDetRing.cc | 189 +++ RecoMTD/DetLayers/src/MTDDetTray.cc | 158 +++ .../src/MTDRingForwardDoubleLayer.cc | 225 +++ RecoMTD/DetLayers/src/MTDRingForwardLayer.cc | 232 +++ RecoMTD/DetLayers/src/MTDTrayBarrelLayer.cc | 215 +++ RecoMTD/DetLayers/src/PhiBorderFinder.h | 2 + RecoMTD/DetLayers/src/RBorderFinder.h | 1 + RecoMTD/DetLayers/test/BuildFile.xml | 12 + .../DetLayers/test/MTDRecoGeometryAnalyzer.cc | 249 ++++ RecoMTD/DetLayers/test/mtd_cfg.py | 35 + RecoMTD/DetLayers/test/testRecoGeometry.cfg | 36 + RecoMTD/Navigation/BuildFile.xml | 12 + .../Navigation/interface/BTLNavigableLayer.h | 179 +++ .../interface/DirectMTDNavigation.h | 66 + .../Navigation/interface/ETLNavigableLayer.h | 133 ++ RecoMTD/Navigation/interface/MTDDetLayerMap.h | 41 + RecoMTD/Navigation/interface/MTDEtaRange.h | 44 + .../Navigation/interface/MTDNavigableLayer.h | 54 + .../interface/MTDNavigationPrinter.h | 40 + .../interface/MTDNavigationSchool.h | 80 ++ RecoMTD/Navigation/src/BTLNavigableLayer.cc | 176 +++ RecoMTD/Navigation/src/DirectMTDNavigation.cc | 255 ++++ RecoMTD/Navigation/src/ETLNavigableLayer.cc | 193 +++ RecoMTD/Navigation/src/MTDEtaRange.cc | 81 ++ RecoMTD/Navigation/src/MTDNavigableLayer.cc | 77 + .../Navigation/src/MTDNavigationPrinter.cc | 179 +++ RecoMTD/Navigation/src/MTDNavigationSchool.cc | 379 +++++ RecoMTD/Navigation/test/BuildFile.xml | 8 + RecoMTD/Navigation/test/MTDNavigationTest.cc | 88 ++ RecoMTD/Records/BuildFile.xml | 7 + .../Records/interface/MTDRecoGeometryRecord.h | 22 + RecoMTD/Records/src/MTDRecoGeometryRecord.cc | 4 + .../DetLayers/src/GeneralBinFinderInPhi.h | 104 +- RecoMuon/DetLayers/src/GeneralBinFinderInR.h | 75 +- RecoMuon/DetLayers/src/PhiBorderFinder.h | 170 +-- RecoMuon/DetLayers/src/RBorderFinder.h | 189 +-- .../interface/GeneralBinFinderInPhi.h | 103 ++ .../DetLayers/interface/GeneralBinFinderInR.h | 74 + .../DetLayers/interface/PhiBorderFinder.h | 77 + .../DetLayers/interface/RBorderFinder.h | 61 + .../DetLayers/src/PhiBorderFinder.cc | 96 ++ TrackingTools/DetLayers/src/RBorderFinder.cc | 68 + 211 files changed, 12790 insertions(+), 559 deletions(-) create mode 100644 CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h create mode 100644 CondFormats/AlignmentRecord/interface/MTDAlignmentErrorRcd.h create mode 100644 CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h create mode 100644 CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h create mode 100644 CondFormats/AlignmentRecord/src/MTDAlignmentErrorExtendedRcd.cc create mode 100644 CondFormats/AlignmentRecord/src/MTDAlignmentErrorRcd.cc create mode 100644 CondFormats/AlignmentRecord/src/MTDAlignmentRcd.cc create mode 100644 CondFormats/AlignmentRecord/src/MTDSurfaceDeformationRcd.cc create mode 100644 CondFormats/GeometryObjects/interface/PGeometricTimingDet.h create mode 100644 CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h create mode 100644 CondFormats/GeometryObjects/interface/PMTDParameters.h create mode 100644 CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDet.cc create mode 100644 CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDetExtra.cc create mode 100644 CondFormats/GeometryObjects/src/T_EventSetup_PMTDParameters.cc create mode 100644 DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h create mode 100644 DataFormats/FTLRecHit/src/FTLTrackingRecHit.cc create mode 100644 Geometry/CommonDetUnit/interface/MTDGeomDet.h create mode 100644 Geometry/CommonDetUnit/src/MTDGeomDet.cc create mode 100644 Geometry/MTDGeometryBuilder/BuildFile.xml create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDGeometry.h create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h create mode 100644 Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h create mode 100644 Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h create mode 100644 Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h create mode 100644 Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h create mode 100644 Geometry/MTDGeometryBuilder/plugins/BuildFile.xml create mode 100644 Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.cc create mode 100644 Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.h create mode 100644 Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.cc create mode 100644 Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.h create mode 100644 Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometryDB_cff.py create mode 100644 Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometry_cff.py create mode 100644 Geometry/MTDGeometryBuilder/python/mtdModuleInfo_cfg.py create mode 100644 Geometry/MTDGeometryBuilder/python/mtdParameters_cfi.py create mode 100644 Geometry/MTDGeometryBuilder/src/ES_MTDGeometry.cc create mode 100644 Geometry/MTDGeometryBuilder/src/MTDGeomBuilderFromGeometricTimingDet.cc create mode 100644 Geometry/MTDGeometryBuilder/src/MTDGeomDetUnit.cc create mode 100644 Geometry/MTDGeometryBuilder/src/MTDGeometry.cc create mode 100644 Geometry/MTDGeometryBuilder/src/MTDParametersFromDD.cc create mode 100644 Geometry/MTDGeometryBuilder/src/MTDTopologyBuilder.cc create mode 100644 Geometry/MTDGeometryBuilder/src/PlaneBuilderFromGeometricTimingDet.cc create mode 100644 Geometry/MTDGeometryBuilder/src/ProxyMTDTopology.cc create mode 100644 Geometry/MTDGeometryBuilder/src/RectangularMTDTopology.cc create mode 100644 Geometry/MTDGeometryBuilder/test/BuildFile.xml create mode 100644 Geometry/MTDGeometryBuilder/test/MTDDigiGeometryAnalyzer.cc create mode 100644 Geometry/MTDGeometryBuilder/test/mtd_cfg.py create mode 100644 Geometry/MTDNumberingBuilder/BuildFile.xml create mode 100644 Geometry/MTDNumberingBuilder/bin/BuildFile.xml create mode 100644 Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.cc create mode 100644 Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.h create mode 100644 Geometry/MTDNumberingBuilder/doc/GeometricDetBuilder.png create mode 100644 Geometry/MTDNumberingBuilder/interface/CmsMTDDebugNavigator.h create mode 100644 Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h create mode 100644 Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h create mode 100644 Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h create mode 100644 Geometry/MTDNumberingBuilder/interface/MTDMapDDDtoID.h create mode 100644 Geometry/MTDNumberingBuilder/interface/MTDTopology.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/BuildFile.xml create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDAbstractConstruction.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.cc create mode 100644 Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.h create mode 100644 Geometry/MTDNumberingBuilder/src/CmsMTDDebugNavigator.cc create mode 100644 Geometry/MTDNumberingBuilder/src/CmsMTDStringToEnum.cc create mode 100644 Geometry/MTDNumberingBuilder/src/ES_MTDTopology.cc create mode 100644 Geometry/MTDNumberingBuilder/src/GeometricTimingDet.cc create mode 100644 Geometry/MTDNumberingBuilder/src/GeometricTimingDetExtra.cc create mode 100644 Geometry/MTDNumberingBuilder/src/MTDMapDDDtoID.cc create mode 100644 Geometry/MTDNumberingBuilder/src/MTDTopology.cc create mode 100644 Geometry/MTDNumberingBuilder/src/module.cc create mode 100644 Geometry/MTDNumberingBuilder/test/BuildFile.xml create mode 100644 Geometry/MTDNumberingBuilder/test/FakeCPP.h create mode 100644 Geometry/MTDNumberingBuilder/test/GeometricTimingDetAnalyzer.cc create mode 100644 Geometry/MTDNumberingBuilder/test/MTDModuleNumbering.cc create mode 100644 Geometry/MTDNumberingBuilder/test/mtd_cfg.py create mode 100644 Geometry/MTDNumberingBuilder/test/trackerTopology_cfg.py create mode 100644 Geometry/Records/interface/BTLGeometryRcd.h create mode 100644 Geometry/Records/interface/ETLGeometryRcd.h create mode 100644 Geometry/Records/interface/MTDDigiGeometryRecord.h create mode 100644 Geometry/Records/interface/MTDGeometryRecord.h create mode 100644 Geometry/Records/interface/MTDTopologyRcd.h create mode 100644 Geometry/Records/interface/PGeometricTimingDetExtraRcd.h create mode 100644 Geometry/Records/interface/PMTDParametersRcd.h create mode 100644 Geometry/Records/src/BTLGeometryRcd.cc create mode 100644 Geometry/Records/src/ETLGeometryRcd.cc create mode 100644 Geometry/Records/src/MTDDigiGeometryRecord.cc create mode 100644 Geometry/Records/src/MTDGeometryRecord.cc create mode 100644 Geometry/Records/src/MTDTopologyRcd.cc create mode 100644 Geometry/Records/src/PGeometricTimingDetExtraRcd.cc create mode 100644 Geometry/Records/src/PMTDParametersRcd.cc create mode 100644 RecoMTD/DetLayers/BuildFile.xml create mode 100644 RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h create mode 100644 RecoMTD/DetLayers/interface/MTDDetRing.h create mode 100644 RecoMTD/DetLayers/interface/MTDDetTray.h create mode 100644 RecoMTD/DetLayers/interface/MTDRingForwardDoubleLayer.h create mode 100644 RecoMTD/DetLayers/interface/MTDRingForwardLayer.h create mode 100644 RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h create mode 100644 RecoMTD/DetLayers/plugins/BuildFile.xml create mode 100644 RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.cc create mode 100644 RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.h create mode 100644 RecoMTD/DetLayers/plugins/SealModule.cc create mode 100644 RecoMTD/DetLayers/python/mtdDetLayerGeometry_cfi.py create mode 100644 RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.cc create mode 100644 RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.h create mode 100644 RecoMTD/DetLayers/src/ES_MTDDetLayerGeometry.cc create mode 100644 RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.cc create mode 100644 RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.h create mode 100644 RecoMTD/DetLayers/src/GeneralBinFinderInPhi.h create mode 100644 RecoMTD/DetLayers/src/GeneralBinFinderInR.h create mode 100644 RecoMTD/DetLayers/src/MTDDetLayerGeometry.cc create mode 100644 RecoMTD/DetLayers/src/MTDDetRing.cc create mode 100644 RecoMTD/DetLayers/src/MTDDetTray.cc create mode 100644 RecoMTD/DetLayers/src/MTDRingForwardDoubleLayer.cc create mode 100644 RecoMTD/DetLayers/src/MTDRingForwardLayer.cc create mode 100644 RecoMTD/DetLayers/src/MTDTrayBarrelLayer.cc create mode 100644 RecoMTD/DetLayers/src/PhiBorderFinder.h create mode 100644 RecoMTD/DetLayers/src/RBorderFinder.h create mode 100644 RecoMTD/DetLayers/test/BuildFile.xml create mode 100644 RecoMTD/DetLayers/test/MTDRecoGeometryAnalyzer.cc create mode 100644 RecoMTD/DetLayers/test/mtd_cfg.py create mode 100644 RecoMTD/DetLayers/test/testRecoGeometry.cfg create mode 100644 RecoMTD/Navigation/BuildFile.xml create mode 100644 RecoMTD/Navigation/interface/BTLNavigableLayer.h create mode 100644 RecoMTD/Navigation/interface/DirectMTDNavigation.h create mode 100644 RecoMTD/Navigation/interface/ETLNavigableLayer.h create mode 100644 RecoMTD/Navigation/interface/MTDDetLayerMap.h create mode 100644 RecoMTD/Navigation/interface/MTDEtaRange.h create mode 100644 RecoMTD/Navigation/interface/MTDNavigableLayer.h create mode 100644 RecoMTD/Navigation/interface/MTDNavigationPrinter.h create mode 100644 RecoMTD/Navigation/interface/MTDNavigationSchool.h create mode 100644 RecoMTD/Navigation/src/BTLNavigableLayer.cc create mode 100644 RecoMTD/Navigation/src/DirectMTDNavigation.cc create mode 100644 RecoMTD/Navigation/src/ETLNavigableLayer.cc create mode 100644 RecoMTD/Navigation/src/MTDEtaRange.cc create mode 100644 RecoMTD/Navigation/src/MTDNavigableLayer.cc create mode 100644 RecoMTD/Navigation/src/MTDNavigationPrinter.cc create mode 100644 RecoMTD/Navigation/src/MTDNavigationSchool.cc create mode 100644 RecoMTD/Navigation/test/BuildFile.xml create mode 100644 RecoMTD/Navigation/test/MTDNavigationTest.cc create mode 100644 RecoMTD/Records/BuildFile.xml create mode 100644 RecoMTD/Records/interface/MTDRecoGeometryRecord.h create mode 100644 RecoMTD/Records/src/MTDRecoGeometryRecord.cc create mode 100644 TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h create mode 100644 TrackingTools/DetLayers/interface/GeneralBinFinderInR.h create mode 100644 TrackingTools/DetLayers/interface/PhiBorderFinder.h create mode 100644 TrackingTools/DetLayers/interface/RBorderFinder.h create mode 100644 TrackingTools/DetLayers/src/PhiBorderFinder.cc create mode 100644 TrackingTools/DetLayers/src/RBorderFinder.cc diff --git a/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h b/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h new file mode 100644 index 0000000000000..fae8ce7bef006 --- /dev/null +++ b/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h @@ -0,0 +1,8 @@ +#ifndef MTDALIGNMENTERROREXTENDEDRCD_H +#define MTDALIGNMENTERROREXTENDEDRCD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" + +class MTDAlignmentErrorExtendedRcd : public edm::eventsetup::EventSetupRecordImplementation {}; + +#endif diff --git a/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorRcd.h b/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorRcd.h new file mode 100644 index 0000000000000..eae34287648bb --- /dev/null +++ b/CondFormats/AlignmentRecord/interface/MTDAlignmentErrorRcd.h @@ -0,0 +1,9 @@ +#ifndef MTDALIGNMENTERRORRCD_H +#define MTDALIGNMENTERRORRCD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" + +class MTDAlignmentErrorRcd : public edm::eventsetup::EventSetupRecordImplementation {}; + +#endif + diff --git a/CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h b/CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h new file mode 100644 index 0000000000000..bbf3caa79e00b --- /dev/null +++ b/CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h @@ -0,0 +1,9 @@ +#ifndef MTDALIGNMENTRCD_H +#define MTDALIGNMENTRCD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" + +class MTDAlignmentRcd : public edm::eventsetup::EventSetupRecordImplementation {}; + +#endif + diff --git a/CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h b/CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h new file mode 100644 index 0000000000000..2b9db2b7c336e --- /dev/null +++ b/CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h @@ -0,0 +1,8 @@ +#ifndef MTDSURFACEDEFORMATIONRCD_H +#define MTDSURFACEDEFORMATIONRCD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" + +class MTDSurfaceDeformationRcd : public edm::eventsetup::EventSetupRecordImplementation {}; + +#endif diff --git a/CondFormats/AlignmentRecord/src/MTDAlignmentErrorExtendedRcd.cc b/CondFormats/AlignmentRecord/src/MTDAlignmentErrorExtendedRcd.cc new file mode 100644 index 0000000000000..3dd515c3c2951 --- /dev/null +++ b/CondFormats/AlignmentRecord/src/MTDAlignmentErrorExtendedRcd.cc @@ -0,0 +1,3 @@ +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" +EVENTSETUP_RECORD_REG(MTDAlignmentErrorExtendedRcd); diff --git a/CondFormats/AlignmentRecord/src/MTDAlignmentErrorRcd.cc b/CondFormats/AlignmentRecord/src/MTDAlignmentErrorRcd.cc new file mode 100644 index 0000000000000..74b41aeb9e68b --- /dev/null +++ b/CondFormats/AlignmentRecord/src/MTDAlignmentErrorRcd.cc @@ -0,0 +1,12 @@ +// -*- C++ -*- +// +// Package: MTDGeometry +// Class : MTDAlignmentErrorRecord +// +// Implementation: +// +// + +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentErrorRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" +EVENTSETUP_RECORD_REG(MTDAlignmentErrorRcd); diff --git a/CondFormats/AlignmentRecord/src/MTDAlignmentRcd.cc b/CondFormats/AlignmentRecord/src/MTDAlignmentRcd.cc new file mode 100644 index 0000000000000..baa7d3bf89833 --- /dev/null +++ b/CondFormats/AlignmentRecord/src/MTDAlignmentRcd.cc @@ -0,0 +1,12 @@ +// -*- C++ -*- +// +// Package: MTDGeometry +// Class : MTDAlignmentRecord +// +// Implementation: +// +// + +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" +EVENTSETUP_RECORD_REG(MTDAlignmentRcd); diff --git a/CondFormats/AlignmentRecord/src/MTDSurfaceDeformationRcd.cc b/CondFormats/AlignmentRecord/src/MTDSurfaceDeformationRcd.cc new file mode 100644 index 0000000000000..a05fffed2837e --- /dev/null +++ b/CondFormats/AlignmentRecord/src/MTDSurfaceDeformationRcd.cc @@ -0,0 +1,12 @@ +// -*- C++ -*- +// +// Package: MTDGeometry +// Class : MTDSurfaceDeformationRecord +// +// Implementation: +// +// + +#include "CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" +EVENTSETUP_RECORD_REG(MTDSurfaceDeformationRcd); diff --git a/CondFormats/GeometryObjects/interface/PGeometricTimingDet.h b/CondFormats/GeometryObjects/interface/PGeometricTimingDet.h new file mode 100644 index 0000000000000..e00e515ced3cd --- /dev/null +++ b/CondFormats/GeometryObjects/interface/PGeometricTimingDet.h @@ -0,0 +1,57 @@ +#ifndef CondFormats_PGeometricTimingDet_h +#define CondFormats_PGeometricTimingDet_h + +#include "CondFormats/Serialization/interface/Serializable.h" + +#include +#include + +class PGeometricTimingDet{ + + public: + PGeometricTimingDet() { }; + ~PGeometricTimingDet() { }; + + struct Item{ + std::string name_; // save only the name, not the namespace. + std::string ns_; // save only the name, not the namespace. + + double x_; + double y_; + double z_; + double phi_; + double rho_; + // fill as you will but intent is rotation matrix A where first number is row and second number is column + double a11_, a12_, a13_, a21_, a22_, a23_, a31_, a32_, a33_; + double params_0,params_1,params_2,params_3,params_4,params_5,params_6,params_7,params_8,params_9,params_10; + double radLength_; + double xi_; + double pixROCRows_; + double pixROCCols_; + double pixROCx_; + double pixROCy_; + double siliconAPVNum_; + + int level_; // goes like 1, 2, 3, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 1, 2, 3, etc. + int shape_; + // nav_type _ddd; DO NOT SAVE! + // DDName _ddname; DO NOT SAVE! + int type_; + + int numnt_; + int nt0_, nt1_, nt2_, nt3_, nt4_, nt5_, nt6_, nt7_, nt8_, nt9_, nt10_; + + int geographicalID_; // to be converted to DetId + bool stereo_; + + COND_SERIALIZABLE; +}; + + std::vector pgeomdets_; + + + COND_SERIALIZABLE; +}; + +#endif + diff --git a/CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h b/CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h new file mode 100644 index 0000000000000..b31327bce03fc --- /dev/null +++ b/CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h @@ -0,0 +1,35 @@ +#ifndef CondFormats_PGeometricTimingDetExtra_h +#define CondFormats_PGeometricTimingDetExtra_h + +#include "CondFormats/Serialization/interface/Serializable.h" + +#include +#include + +class PGeometricTimingDetExtra{ + + public: + PGeometricTimingDetExtra() { }; + ~PGeometricTimingDetExtra() { }; + + struct Item{ + int geographicalId_; // to be converted to DetId + // std::vector< DDExpandedNode > parents_; DO NOT SAVE! + //GeoHistory _parents; + double volume_; + double density_; + double weight_; + int copy_; + std::string material_; + + COND_SERIALIZABLE; +}; + + std::vector pgdes_; + + + COND_SERIALIZABLE; +}; + +#endif + diff --git a/CondFormats/GeometryObjects/interface/PMTDParameters.h b/CondFormats/GeometryObjects/interface/PMTDParameters.h new file mode 100644 index 0000000000000..c05c71692026d --- /dev/null +++ b/CondFormats/GeometryObjects/interface/PMTDParameters.h @@ -0,0 +1,26 @@ +#ifndef CondFormats_GeometryObjects_PMTDParameters_h +#define CondFormats_GeometryObjects_PMTDParameters_h + +#include "CondFormats/Serialization/interface/Serializable.h" + +class PMTDParameters +{ + public: + PMTDParameters( void ) { } + ~PMTDParameters( void ) { } + + struct Item + { + int id_; + std::vector vpars_; + + COND_SERIALIZABLE; + }; + + std::vector vitems_; + std::vector vpars_; + + COND_SERIALIZABLE; +}; + +#endif diff --git a/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDet.cc b/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDet.cc new file mode 100644 index 0000000000000..d3e654288817d --- /dev/null +++ b/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDet.cc @@ -0,0 +1,5 @@ +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(PGeometricTimingDet); + diff --git a/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDetExtra.cc b/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDetExtra.cc new file mode 100644 index 0000000000000..8ac892adbbc62 --- /dev/null +++ b/CondFormats/GeometryObjects/src/T_EventSetup_PGeometricTimingDetExtra.cc @@ -0,0 +1,5 @@ +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h" +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(PGeometricTimingDetExtra); + diff --git a/CondFormats/GeometryObjects/src/T_EventSetup_PMTDParameters.cc b/CondFormats/GeometryObjects/src/T_EventSetup_PMTDParameters.cc new file mode 100644 index 0000000000000..24a90d66b786e --- /dev/null +++ b/CondFormats/GeometryObjects/src/T_EventSetup_PMTDParameters.cc @@ -0,0 +1,4 @@ +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(PMTDParameters); diff --git a/CondFormats/GeometryObjects/src/classes.h b/CondFormats/GeometryObjects/src/classes.h index 4b78e48d9e9d4..9a179e1f11a27 100644 --- a/CondFormats/GeometryObjects/src/classes.h +++ b/CondFormats/GeometryObjects/src/classes.h @@ -1,9 +1,12 @@ #include "CondFormats/GeometryObjects/interface/PGeometricDet.h" #include "CondFormats/GeometryObjects/interface/PGeometricDetExtra.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h" #include "CondFormats/GeometryObjects/interface/PCaloGeometry.h" #include "CondFormats/GeometryObjects/interface/RecoIdealGeometry.h" #include "CondFormats/GeometryObjects/interface/CSCRecoDigiParameters.h" #include "CondFormats/GeometryObjects/interface/PTrackerParameters.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" #include "CondFormats/GeometryObjects/interface/HcalParameters.h" #include "CondFormats/GeometryObjects/interface/PHGCalParameters.h" diff --git a/CondFormats/GeometryObjects/src/classes_def.xml b/CondFormats/GeometryObjects/src/classes_def.xml index d19741ac7a632..db65da5d684d0 100644 --- a/CondFormats/GeometryObjects/src/classes_def.xml +++ b/CondFormats/GeometryObjects/src/classes_def.xml @@ -10,6 +10,19 @@ + + + + + + + + + + + + + @@ -42,6 +55,13 @@ + + + + + + + diff --git a/Configuration/Geometry/python/GeometryExtended2023D24Reco_cff.py b/Configuration/Geometry/python/GeometryExtended2023D24Reco_cff.py index f9c3fb4299894..7a2ede9f9da53 100644 --- a/Configuration/Geometry/python/GeometryExtended2023D24Reco_cff.py +++ b/Configuration/Geometry/python/GeometryExtended2023D24Reco_cff.py @@ -49,5 +49,11 @@ from Geometry.ForwardGeometry.ForwardGeometry_cfi import * # timing - +from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import * +from Geometry.MTDGeometryBuilder.mtdParameters_cfi import * +from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import * +from Geometry.MTDNumberingBuilder.mtdTopology_cfi import * +from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import * +from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import * +mtdGeometry.applyAlignment = cms.bool(False) diff --git a/Configuration/Geometry/python/GeometryExtended2023D24_cff.py b/Configuration/Geometry/python/GeometryExtended2023D24_cff.py index a4f0773f5af0c..5b9db74cf786f 100644 --- a/Configuration/Geometry/python/GeometryExtended2023D24_cff.py +++ b/Configuration/Geometry/python/GeometryExtended2023D24_cff.py @@ -10,4 +10,4 @@ from Geometry.HcalCommonData.hcalDDDSimConstants_cfi import * from Geometry.HGCalCommonData.hgcalV6ParametersInitialization_cfi import * from Geometry.HGCalCommonData.hgcalV6NumberingInitialization_cfi import * - +from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import * diff --git a/Configuration/Geometry/python/GeometryExtended2023D25Reco_cff.py b/Configuration/Geometry/python/GeometryExtended2023D25Reco_cff.py index ce4996e075f54..2117096f864f6 100644 --- a/Configuration/Geometry/python/GeometryExtended2023D25Reco_cff.py +++ b/Configuration/Geometry/python/GeometryExtended2023D25Reco_cff.py @@ -49,5 +49,11 @@ from Geometry.ForwardGeometry.ForwardGeometry_cfi import * # timing - +from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import * +from Geometry.MTDGeometryBuilder.mtdParameters_cfi import * +from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import * +from Geometry.MTDNumberingBuilder.mtdTopology_cfi import * +from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import * +from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import * +mtdGeometry.applyAlignment = cms.bool(False) diff --git a/Configuration/Geometry/python/GeometryExtended2023D25_cff.py b/Configuration/Geometry/python/GeometryExtended2023D25_cff.py index 5f50f927b91fa..398c700064922 100644 --- a/Configuration/Geometry/python/GeometryExtended2023D25_cff.py +++ b/Configuration/Geometry/python/GeometryExtended2023D25_cff.py @@ -10,4 +10,4 @@ from Geometry.HcalCommonData.hcalDDDSimConstants_cfi import * from Geometry.HGCalCommonData.hgcalV6ParametersInitialization_cfi import * from Geometry.HGCalCommonData.hgcalV6NumberingInitialization_cfi import * - +from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import * diff --git a/Configuration/Geometry/python/dict2023Geometry.py b/Configuration/Geometry/python/dict2023Geometry.py index f7858424ca29c..c8861561e55fa 100644 --- a/Configuration/Geometry/python/dict2023Geometry.py +++ b/Configuration/Geometry/python/dict2023Geometry.py @@ -814,8 +814,16 @@ 'Geometry/MTDSimData/data/CrystalTile/mtdProdCuts.xml' ], "sim" : [ + 'from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import *', ], "reco" :[ + 'from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import *', + 'from Geometry.MTDGeometryBuilder.mtdParameters_cfi import *', + 'from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import *', + 'from Geometry.MTDNumberingBuilder.mtdTopology_cfi import *', + 'from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import *', + 'from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import *', + 'mtdGeometry.applyAlignment = cms.bool(False)' ], "era" : "phase2_timing, phase2_timing_layer_new", }, @@ -832,8 +840,16 @@ 'Geometry/MTDSimData/data/CrystalBar/mtdProdCuts.xml' ], "sim" : [ + 'from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import *', ], "reco" :[ + 'from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import *', + 'from Geometry.MTDGeometryBuilder.mtdParameters_cfi import *', + 'from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi import *', + 'from Geometry.MTDNumberingBuilder.mtdTopology_cfi import *', + 'from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import *', + 'from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import *', + 'mtdGeometry.applyAlignment = cms.bool(False)' ], "era" : "phase2_timing, phase2_timing_layer_new", } diff --git a/DataFormats/FTLRecHit/BuildFile.xml b/DataFormats/FTLRecHit/BuildFile.xml index fd0895193582d..f2b5be9c1b3a6 100644 --- a/DataFormats/FTLRecHit/BuildFile.xml +++ b/DataFormats/FTLRecHit/BuildFile.xml @@ -1,6 +1,7 @@ + diff --git a/DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h b/DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h new file mode 100644 index 0000000000000..9709f5cab730d --- /dev/null +++ b/DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h @@ -0,0 +1,50 @@ +#ifndef DataFormats_FTLRecHit_FTLTrackingRecHit_h +#define DataFormats_FTLRecHit_FTLTrackingRecHit_h + +/// Basic template class for a RecHit wrapping a Ref to an object + +#include +#include "DataFormats/TrackingRecHit/interface/RecHit2DLocalPos.h" + +template +class FTLTrackingRecHit : public RecHit2DLocalPos { + public: + typedef ObjRef ref_type; + typedef typename ObjRef::value_type obj_type; + + FTLTrackingRecHit() {} + FTLTrackingRecHit(DetId id, const ObjRef &objref, const LocalPoint &pos, const LocalError &err): + RecHit2DLocalPos(id), + objref_(objref), + pos_(pos), err_(err) {} + + FTLTrackingRecHit * clone() const override { return new FTLTrackingRecHit(*this); } + + LocalPoint localPosition() const override { return pos_; } + LocalError localPositionError() const override { return err_; } + + const ObjRef & objRef() const { return objref_; } + + float energy() const { return objref_->energy(); } + + float time() const { return objref_->time(); } + float timeError() const { return objref_->timeError(); } + + bool sharesInput( const TrackingRecHit* other, SharedInputType what) const override { assert(false); } + protected: + ObjRef objref_; + LocalPoint pos_; + LocalError err_; +}; + + +// Instantiations and specializations for FTLRecHitRef and reco::CaloClusterPtr +#include "DataFormats/FTLRecHit/interface/FTLRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h" +typedef FTLTrackingRecHit FTLTrackingRecHitFromHit; +typedef std::vector FTLTrackingRecHitCollection; + +template<> +bool FTLTrackingRecHit::sharesInput( const TrackingRecHit* other, SharedInputType what) const ; + +#endif diff --git a/DataFormats/FTLRecHit/src/FTLTrackingRecHit.cc b/DataFormats/FTLRecHit/src/FTLTrackingRecHit.cc new file mode 100644 index 0000000000000..661780a017534 --- /dev/null +++ b/DataFormats/FTLRecHit/src/FTLTrackingRecHit.cc @@ -0,0 +1,11 @@ +#include "DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h" + +template<> +bool FTLTrackingRecHit::sharesInput( const TrackingRecHit* other, SharedInputType what) const +{ + if (typeid(*other) == typeid(FTLTrackingRecHit)) { + return objRef() == (static_cast *>(other))->objRef(); + } else { + return false; + } +} diff --git a/DataFormats/FTLRecHit/src/classes.h b/DataFormats/FTLRecHit/src/classes.h index cb0e11d3d136c..fda7aecfe7591 100644 --- a/DataFormats/FTLRecHit/src/classes.h +++ b/DataFormats/FTLRecHit/src/classes.h @@ -2,6 +2,7 @@ #include "DataFormats/FTLRecHit/interface/FTLRecHit.h" #include "DataFormats/FTLRecHit/interface/FTLRecHitCollections.h" #include "DataFormats/FTLRecHit/interface/FTLSeverityLevel.h" +#include "DataFormats/FTLRecHit/interface/FTLTrackingRecHit.h" #include "DataFormats/Common/interface/RefProd.h" #include "DataFormats/Common/interface/Wrapper.h" #include "DataFormats/Common/interface/RefToBase.h" @@ -29,6 +30,12 @@ namespace DataFormats_FTLRecHit { FTLRecHitRef _FTLRHitRef; FTLRecHitRefs _FTLRHitRefs; FTLRecHitsRef _FTLRHitsRef; + + FTLTrackingRecHitFromHit _FTLTTrackingRecHitFromRef; + FTLTrackingRecHitCollection _FTLTTrackingRecHitCollection; + edm::Wrapper _FTLTTrackingRecHitProd; + + }; } diff --git a/DataFormats/FTLRecHit/src/classes_def.xml b/DataFormats/FTLRecHit/src/classes_def.xml index 958b4f40e74ba..fd8e082d9f6bd 100644 --- a/DataFormats/FTLRecHit/src/classes_def.xml +++ b/DataFormats/FTLRecHit/src/classes_def.xml @@ -28,5 +28,12 @@ + + + + + + + diff --git a/DataFormats/ForwardDetId/interface/BTLDetId.h b/DataFormats/ForwardDetId/interface/BTLDetId.h index 63aa450761477..90221cb807a7d 100644 --- a/DataFormats/ForwardDetId/interface/BTLDetId.h +++ b/DataFormats/ForwardDetId/interface/BTLDetId.h @@ -16,7 +16,7 @@ class BTLDetId : public MTDDetId { - private: + public: static constexpr uint32_t kBTLmoduleOffset = 10; static constexpr uint32_t kBTLmoduleMask = 0x3F; @@ -25,8 +25,6 @@ class BTLDetId : public MTDDetId { static constexpr uint32_t kBTLCrystalOffset = 0; static constexpr uint32_t kBTLCrystalMask = 0x3F; - public: - /// range constants, need two sets for the time being (one for tiles and one for bars) static constexpr int kModulesPerROD = 54; static constexpr int kTypeBoundaries[4] = { 0, 18, 36, 54 }; @@ -49,8 +47,6 @@ class BTLDetId : public MTDDetId { static constexpr int kSizeForDenseIndexing = MAX_HASH + 1 ; enum class CrysLayout { tile = 1 , bar = 2 } ; - - public: // ---------- Constructors, enumerated types ---------- diff --git a/DataFormats/ForwardDetId/interface/ETLDetId.h b/DataFormats/ForwardDetId/interface/ETLDetId.h index 874fec477be0b..ad5c1e6f99302 100644 --- a/DataFormats/ForwardDetId/interface/ETLDetId.h +++ b/DataFormats/ForwardDetId/interface/ETLDetId.h @@ -14,15 +14,13 @@ class ETLDetId : public MTDDetId { - private: + public: static const uint32_t kETLmoduleOffset = 7; static const uint32_t kETLmoduleMask = 0xFF; static const uint32_t kETLmodTypeOffset = 5; static const uint32_t kETLmodTypeMask = 0x3; - public: - // ---------- Constructors, enumerated types ---------- /** Construct a null id */ diff --git a/DataFormats/ForwardDetId/interface/MTDDetId.h b/DataFormats/ForwardDetId/interface/MTDDetId.h index ae503519b7a21..faae9f719cb17 100644 --- a/DataFormats/ForwardDetId/interface/MTDDetId.h +++ b/DataFormats/ForwardDetId/interface/MTDDetId.h @@ -20,7 +20,7 @@ class MTDDetId : public DetId { - protected: + public: /** Enumerated type for Forward sub-deteector systems. */ enum SubDetector { subUNKNOWN=0, FastTime=1 }; @@ -34,8 +34,6 @@ class MTDDetId : public DetId { static const uint32_t kZsideMask = 0x1; static const uint32_t kRodRingOffset = 16; static const uint32_t kRodRingMask = 0x3F; - - public: // ---------- Constructors, enumerated types ---------- diff --git a/Geometry/CommonDetUnit/interface/GeomDetType.h b/Geometry/CommonDetUnit/interface/GeomDetType.h index 136267fdc5eac..daf28a475e4b5 100644 --- a/Geometry/CommonDetUnit/interface/GeomDetType.h +++ b/Geometry/CommonDetUnit/interface/GeomDetType.h @@ -33,6 +33,7 @@ class GeomDetType { bool isGEM() const; bool isME0() const; bool isMuon() const; + bool isTiming() const; private: diff --git a/Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h b/Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h index bd702e945b420..fa1ed84deca50 100644 --- a/Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h +++ b/Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h @@ -7,7 +7,7 @@ * The main purpose is to provide the methods idToDetUnit(DetId) and idToDet(DetId) * that allow to get an element of the geometry given its DetId, regardless of wich subdetector it belongs. * - * The slave geometries (TrackerGeometry, DTGeometry, CSCGeometry, RPCGeometry, GEMGeometry, ME0Geometry) + * The slave geometries (TrackerGeometry, MTDGeometry, DTGeometry, CSCGeometry, RPCGeometry, GEMGeometry, ME0Geometry) * are accessible with the method slaveGeometry(DetId). * * \author M. Sani diff --git a/Geometry/CommonDetUnit/interface/MTDGeomDet.h b/Geometry/CommonDetUnit/interface/MTDGeomDet.h new file mode 100644 index 0000000000000..ef807ec5943c8 --- /dev/null +++ b/Geometry/CommonDetUnit/interface/MTDGeomDet.h @@ -0,0 +1,21 @@ +#ifndef CommonDet_MTDGeomDet_H +#define CommonDet_MTDGeomDet_H + + +#include "Geometry/CommonDetUnit/interface/GeomDet.h" + +class MTDGeomDet : public GeomDet { +protected : + explicit MTDGeomDet(Plane * plane) : GeomDet(plane), theLocalAlignmentError(InvalidError()){} + explicit MTDGeomDet(const ReferenceCountingPointer& plane) : GeomDet(plane), theLocalAlignmentError(InvalidError()){} + +public: + /// Return local alligment error + LocalError const & localAlignmentError() const { return theLocalAlignmentError;} + +private: + LocalError theLocalAlignmentError; + bool setAlignmentPositionError (const AlignmentPositionError& ape) final; + +}; +#endif diff --git a/Geometry/CommonDetUnit/src/GeomDetType.cc b/Geometry/CommonDetUnit/src/GeomDetType.cc index dfe26cfb8b490..6f3fb38e7461b 100644 --- a/Geometry/CommonDetUnit/src/GeomDetType.cc +++ b/Geometry/CommonDetUnit/src/GeomDetType.cc @@ -69,3 +69,8 @@ bool GeomDetType::isMuon() const { return GeomDetEnumerators::isMuon(theSubDet); } + +bool GeomDetType::isTiming() const +{ + return GeomDetEnumerators::isTiming(theSubDet); +} diff --git a/Geometry/CommonDetUnit/src/GlobalTrackingGeometry.cc b/Geometry/CommonDetUnit/src/GlobalTrackingGeometry.cc index 8c5fba1f8e638..213e2913e2762 100644 --- a/Geometry/CommonDetUnit/src/GlobalTrackingGeometry.cc +++ b/Geometry/CommonDetUnit/src/GlobalTrackingGeometry.cc @@ -6,6 +6,8 @@ #include "Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h" #include "FWCore/Utilities/interface/Exception.h" +#include "DataFormats/ForwardDetId/interface/ForwardSubdetector.h" + #include GlobalTrackingGeometry::GlobalTrackingGeometry(std::vector& geos) @@ -55,7 +57,11 @@ const TrackingGeometry* GlobalTrackingGeometry::slaveGeometry(DetId id) const { int idx = id.det()-1; if (id.det() == DetId::Muon) { - idx+=id.subdetId()-1; + idx+=id.subdetId(); //-1; // remove the -1 from before since MTD is there + } + if( id.det() == DetId::Forward && + id.subdetId() == ForwardSubdetector::FastTime ) { + idx = 1; } if (theGeometries[idx]==nullptr) throw cms::Exception("NoGeometry") << "No Tracking Geometry is available for DetId " << id.rawId() << std::endl; diff --git a/Geometry/CommonDetUnit/src/MTDGeomDet.cc b/Geometry/CommonDetUnit/src/MTDGeomDet.cc new file mode 100644 index 0000000000000..48373af3680fe --- /dev/null +++ b/Geometry/CommonDetUnit/src/MTDGeomDet.cc @@ -0,0 +1,21 @@ +#include "Geometry/CommonDetUnit/interface/MTDGeomDet.h" +#include "DataFormats/TrackingRecHit/interface/AlignmentPositionError.h" +#include "DataFormats/GeometryCommonDetAlgo/interface/ErrorFrameTransformer.h" + +bool MTDGeomDet::setAlignmentPositionError (const AlignmentPositionError& ape) +{ + if (!theAlignmentPositionError) { + if (ape.valid()) theAlignmentPositionError = new AlignmentPositionError(ape); + } + else *theAlignmentPositionError = ape; + + const GlobalErrorExtended& apeError = ape.globalError(); + GlobalError translatApe(apeError.cxx(),apeError.cyx(),apeError.cyy(),apeError.czx(),apeError.czy(),apeError.czz()); + + //check only translat part is valid + theLocalAlignmentError = ape.valid() ? + ErrorFrameTransformer().transform( translatApe,surface()) : + InvalidError(); + return ape.valid(); +} + diff --git a/Geometry/GlobalTrackingGeometryBuilder/plugins/BuildFile.xml b/Geometry/GlobalTrackingGeometryBuilder/plugins/BuildFile.xml index 2c068874efd9a..6cc41dddf2f5d 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/plugins/BuildFile.xml +++ b/Geometry/GlobalTrackingGeometryBuilder/plugins/BuildFile.xml @@ -2,6 +2,7 @@ + diff --git a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.cc b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.cc index 6cfa0c4541030..66c24ca1efe2c 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.cc +++ b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.cc @@ -11,6 +11,7 @@ #include "Geometry/GEMGeometry/interface/GEMGeometry.h" #include "Geometry/GEMGeometry/interface/ME0Geometry.h" #include "Geometry/DTGeometry/interface/DTGeometry.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" #include #include @@ -21,7 +22,8 @@ GlobalTrackingGeometryBuilder::GlobalTrackingGeometryBuilder() : myName("GlobalT GlobalTrackingGeometryBuilder::~GlobalTrackingGeometryBuilder(){} -GlobalTrackingGeometry* GlobalTrackingGeometryBuilder::build(const TrackerGeometry* tk, +GlobalTrackingGeometry* GlobalTrackingGeometryBuilder::build(const TrackerGeometry* tk, + const MTDGeometry* mtd, const DTGeometry* dt, const CSCGeometry* csc, const RPCGeometry* rpc, @@ -33,13 +35,13 @@ GlobalTrackingGeometry* GlobalTrackingGeometryBuilder::build(const TrackerGeomet std::vector tkGeometries; tkGeometries.emplace_back(tk); + tkGeometries.emplace_back(mtd); tkGeometries.emplace_back(dt); tkGeometries.emplace_back(csc); tkGeometries.emplace_back(rpc); tkGeometries.emplace_back(gem); tkGeometries.emplace_back(me0); - return new GlobalTrackingGeometry(tkGeometries); } diff --git a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.h b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.h index 7b85f460c9185..d72b3801db2af 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.h +++ b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.h @@ -17,6 +17,7 @@ class CSCGeometry; class RPCGeometry; class GEMGeometry; class ME0Geometry; +class MTDGeometry; class GlobalTrackingGeometryBuilder { public: @@ -28,6 +29,7 @@ class GlobalTrackingGeometryBuilder { /// Build the geometry GlobalTrackingGeometry* build(const TrackerGeometry* tk, + const MTDGeometry* mtd, const DTGeometry* dt, const CSCGeometry* csc, const RPCGeometry* rpc, diff --git a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryESProducer.cc b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryESProducer.cc index 8788c52d5beb8..37c58b00b9aa4 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryESProducer.cc +++ b/Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryESProducer.cc @@ -7,6 +7,8 @@ #include "Geometry/GlobalTrackingGeometryBuilder/plugins/GlobalTrackingGeometryBuilder.h" #include "Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h" +#include "DataFormats/ForwardDetId/interface/ForwardSubdetector.h" + #include "FWCore/Framework/interface/ESHandle.h" #include "FWCore/Framework/interface/ModuleFactory.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" @@ -27,6 +29,7 @@ std::shared_ptr GlobalTrackingGeometryESProducer::produce(const GlobalTrackingGeometryRecord& record) { TrackerGeometry const* tk = nullptr; + MTDGeometry const* mtd = nullptr; DTGeometry const* dt = nullptr; CSCGeometry const* csc = nullptr; RPCGeometry const* rpc = nullptr; @@ -45,6 +48,18 @@ GlobalTrackingGeometryESProducer::produce(const GlobalTrackingGeometryRecord& re LogWarning("GeometryGlobalTrackingGeometryBuilder") << "No TrackerDigiGeometryRecord is available."; } + try { + edm::ESHandle mtdH; + record.getRecord().get(mtdH); + if(mtdH.isValid()) { + mtd = mtdH.product(); + } else { + LogWarning("GeometryGlobalTrackingGeometryBuilder") << "No MTD geometry is available."; + } + } catch (edm::eventsetup::NoRecordException& e){ + LogWarning("GeometryGlobalTrackingGeometryBuilder") << "No MTDDigiGeometryRecord is available."; + } + try { edm::ESHandle dtH; @@ -92,7 +107,7 @@ GlobalTrackingGeometryESProducer::produce(const GlobalTrackingGeometryRecord& re } GlobalTrackingGeometryBuilder builder; - return std::shared_ptr(builder.build(tk, dt, csc, rpc, gem, me0)); + return std::shared_ptr(builder.build(tk, mtd, dt, csc, rpc, gem, me0)); } DEFINE_FWK_EVENTSETUP_MODULE(GlobalTrackingGeometryESProducer); diff --git a/Geometry/GlobalTrackingGeometryBuilder/test/BuildFile.xml b/Geometry/GlobalTrackingGeometryBuilder/test/BuildFile.xml index 254eb302d50b7..c7b39178ef2d9 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/test/BuildFile.xml +++ b/Geometry/GlobalTrackingGeometryBuilder/test/BuildFile.xml @@ -1,5 +1,6 @@ + diff --git a/Geometry/GlobalTrackingGeometryBuilder/test/GlobalTrackingGeometryTest.cc b/Geometry/GlobalTrackingGeometryBuilder/test/GlobalTrackingGeometryTest.cc index 745507d93fdb2..84af4101f435b 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/test/GlobalTrackingGeometryTest.cc +++ b/Geometry/GlobalTrackingGeometryBuilder/test/GlobalTrackingGeometryTest.cc @@ -17,6 +17,7 @@ #include "Geometry/DTGeometry/interface/DTGeometry.h" #include "Geometry/RPCGeometry/interface/RPCGeometry.h" #include "Geometry/GEMGeometry/interface/GEMGeometry.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" #include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h" #include "DataFormats/DetId/interface/DetId.h" @@ -42,6 +43,7 @@ class GlobalTrackingGeometryTest : public edm::one::EDAnalyzer<> void analyzeDT(const GlobalTrackingGeometry* geo, const DTGeometry* dtGeometry); void analyzeRPC(const GlobalTrackingGeometry* geo, const RPCGeometry* rpcGeometry); void analyzeGEM(const GlobalTrackingGeometry* geo, const GEMGeometry* gemGeometry); + void analyzeMTD(const GlobalTrackingGeometry* geo, const MTDGeometry* mtdGeometry); void analyzeTracker(const GlobalTrackingGeometry* geo, const TrackerGeometry* tkGeometry); const std::string& myName() { return my_name; } std::string my_name; @@ -144,6 +146,29 @@ void GlobalTrackingGeometryTest::analyzeGEM(const GlobalTrackingGeometry* geo, c std::cout << "GEM det: GlobalTrackingGeometry succesfully tested." << std::endl; } +void GlobalTrackingGeometryTest::analyzeMTD(const GlobalTrackingGeometry* geo, const MTDGeometry* mtdGeometry) +{ + for(auto& detUnit : mtdGeometry->detUnits()) + { + const DetId detId(detUnit->geographicalId()); + + // Check idToDetUnit + const GeomDetUnit* gdu(geo->idToDetUnit(detId)); + assert(gdu == detUnit); + } + std::cout << "MTD detUnit: GlobalTrackingGeometry succesfully tested." << std::endl; + + for(auto& det : mtdGeometry->dets()) + { + const DetId detId(det->geographicalId()); + + // Check idToDet + const GeomDet* gd(geo->idToDet(detId)); + assert(gd == det); + } + std::cout << "MTD det: GlobalTrackingGeometry succesfully tested." << std::endl; +} + void GlobalTrackingGeometryTest::analyzeTracker(const GlobalTrackingGeometry* geo, const TrackerGeometry* tkGeometry) { for(auto& detUnit : tkGeometry->detUnits()) @@ -183,6 +208,16 @@ void GlobalTrackingGeometryTest::analyze( const edm::Event& /*iEvent*/, const ed } catch (...) { std::cout << "N/A" << std::endl; } + + DetId detId6(DetId::Forward, 1); + const MTDGeometry* mtdGeometry = nullptr; + std::cout << "Pointer to MTD Geometry: "; + try { + mtdGeometry = (const MTDGeometry*) geo->slaveGeometry(detId6); + std::cout << mtdGeometry << std::endl; + } catch (...) { + std::cout << "N/A" << std::endl; + } DetId detId2(DetId::Muon, 1); const DTGeometry* dtGeometry = nullptr; @@ -228,6 +263,7 @@ void GlobalTrackingGeometryTest::analyze( const edm::Event& /*iEvent*/, const ed if (dtGeometry) analyzeDT(geo.product(), dtGeometry); if (rpcGeometry) analyzeRPC(geo.product(), rpcGeometry); if (gemGeometry) analyzeGEM(geo.product(), gemGeometry); + if (mtdGeometry) analyzeMTD(geo.product(), mtdGeometry); if (trackerGeometry) analyzeTracker(geo.product(), trackerGeometry); } diff --git a/Geometry/GlobalTrackingGeometryBuilder/test/testGlobalTrackingGeometry_cfg.py b/Geometry/GlobalTrackingGeometryBuilder/test/testGlobalTrackingGeometry_cfg.py index 0ed897456864b..386b122f652da 100644 --- a/Geometry/GlobalTrackingGeometryBuilder/test/testGlobalTrackingGeometry_cfg.py +++ b/Geometry/GlobalTrackingGeometryBuilder/test/testGlobalTrackingGeometry_cfg.py @@ -1,14 +1,14 @@ import FWCore.ParameterSet.Config as cms process = cms.Process("Demo") -process.load('Configuration.Geometry.GeometryExtended2019_cff') -process.load('Configuration.Geometry.GeometryExtended2019Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2023D24_cff') +process.load('Configuration.Geometry.GeometryExtended2023D24Reco_cff') process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') process.load('FWCore.MessageLogger.MessageLogger_cfi') from Configuration.AlCa.GlobalTag import GlobalTag -process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:upgrade2019', '') +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase2_realistic', '') process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(1) diff --git a/Geometry/MTDGeometryBuilder/BuildFile.xml b/Geometry/MTDGeometryBuilder/BuildFile.xml new file mode 100644 index 0000000000000..1bdbcb85ce7df --- /dev/null +++ b/Geometry/MTDGeometryBuilder/BuildFile.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h b/Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h new file mode 100644 index 0000000000000..3b2ba67c30db1 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h @@ -0,0 +1,37 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDGeomBuilderFromGeometricTimingDet_H +#define Geometry_MTDGeometryBuilder_MTDGeomBuilderFromGeometricTimingDet_H + +#include +#include +#include +#include "Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/CommonDetUnit/interface/GeomDetType.h" + +class MTDGeometry; +class MTDTopology; +class MTDGeomDetType; +class PMTDParameters; + +class MTDGeomBuilderFromGeometricTimingDet { +public: + + MTDGeometry* build(const GeometricTimingDet* gd, + const PMTDParameters & ptp, + const MTDTopology* tTopo); + +private: + + void buildPixel(std::vector const &, + MTDGeometry*,GeomDetType::SubDetector det, + const PMTDParameters& ptp ); + void buildGeomDet(MTDGeometry* ); + + PlaneBuilderFromGeometricTimingDet::ResultType + buildPlaneWithMaterial(const GeometricTimingDet* gd,double scaleFactor=1.) const; + + std::map theMTDDetTypeMap; + const MTDTopology* theTopo; +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h b/Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h new file mode 100644 index 0000000000000..7702fda3aa35e --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h @@ -0,0 +1,38 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDGeomDetType_H +#define Geometry_MTDGeometryBuilder_MTDGeomDetType_H + +#include "Geometry/CommonDetUnit/interface/GeomDetType.h" +#include "Geometry/CommonTopologies/interface/PixelTopology.h" + +/** + * Generic DetType for the MTD. + */ + +class MTDGeomDetType final: public GeomDetType { + +public: + using TopologyType = PixelTopology; + + MTDGeomDetType(TopologyType* t,std::string const& name, SubDetector& det) : + GeomDetType(name,det), + theTopology(t){} + + ~MTDGeomDetType() override { + } + + // Access to topologies + const Topology& topology() const override { return *theTopology;} + + virtual const TopologyType& specificTopology() const { return *theTopology;} + + MTDGeomDetType& operator = ( const MTDGeomDetType& other ) = delete; + MTDGeomDetType( const MTDGeomDetType& other ) = delete; + + private: + // take ownership of the topology when passed through constructor + std::unique_ptr theTopology; +}; + + + +#endif // PixelGeomDetType_H diff --git a/Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h b/Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h new file mode 100644 index 0000000000000..c10cc8f4909e3 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h @@ -0,0 +1,59 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDGeomDetUnit_H +#define Geometry_MTDGeometryBuilder_MTDGeomDetUnit_H + +#include "Geometry/CommonDetUnit/interface/MTDGeomDet.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h" + +class MTDGeomDetType; +class PixelTopology; +class SurfaceDeformation; +/** + * The base PixelGeomDetUnit. Specialized in SiPixelGeomDetUnit. + */ + +class MTDGeomDetUnit final : public MTDGeomDet { +public: + + MTDGeomDetUnit(BoundPlane* sp, MTDGeomDetType const * type, DetId id); + + // DetUnit interface + + /// NOTE (A.M.): The actual pointer to PixelGeomDetType is now a member of the + /// proxy topology. As PixelGeomDetType has the actual topology as a pointer, + /// it is possible to access this topology in two different ways. Once via + /// the proxy topology (through topology() and specificTopology()) which includes + /// corrections for the surface deformations, and once via the GeomDetType + /// (through type().topology() and the like). + const GeomDetType& type() const override; + + /// Returns a reference to the pixel proxy topology + const Topology& topology() const override; + + /// NOTE (A.M.): The actual pointer to PixelGeomDetType is now a member of the + /// proxy topology. As PixelGeomDetType has the actual topology as a pointer, + /// it is possible to access this topology in two different ways. Once via + /// the proxy topology (through topology() and specificTopology()) which includes + /// corrections for the surface deformations, and once via the GeomDetType + /// (through type().topology() and the like). + virtual const MTDGeomDetType& specificType() const; + + /// Returns a reference to the pixel proxy topology + virtual const PixelTopology& specificTopology() const; + + /// Return pointer to surface deformation. + const SurfaceDeformation * surfaceDeformation() const override { + return theTopology->surfaceDeformation(); + } + + bool isLeaf() const override { return true;} + +private: + + /// set the SurfaceDeformation for this StripGeomDetUnit to proxy topology. + void setSurfaceDeformation(const SurfaceDeformation * deformation) override; + + std::unique_ptr theTopology; +}; + +#endif // MTD_MTDGeomDetUnit_H diff --git a/Geometry/MTDGeometryBuilder/interface/MTDGeometry.h b/Geometry/MTDGeometryBuilder/interface/MTDGeometry.h new file mode 100644 index 0000000000000..c384fc893b59f --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDGeometry.h @@ -0,0 +1,93 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDGeometry_H +#define Geometry_MTDGeometryBuilder_MTDGeometry_H + +#include "Geometry/CommonDetUnit/interface/TrackingGeometry.h" +#include "Geometry/CommonDetUnit/interface/GeomDetEnumerators.h" +#include "Geometry/CommonDetUnit/interface/MTDGeomDet.h" + +class GeometricTimingDet; + +/** + * A specific MTD Builder which builds MTD from a list of DetUnits. + * Pattern recognition is used to discover layers, rings etc. + */ +class MTDGeometry final : public TrackingGeometry { + +public: + using SubDetector = GeomDetEnumerators::SubDetector; + + enum class ModuleType { + UNKNOWN, + BTL, + ETL, + }; + + ~MTDGeometry() override ; + + const DetTypeContainer& detTypes() const override {return theDetTypes;} + const DetContainer& detUnits() const override {return theDetUnits;} + const DetContainer& dets() const override {return theDets;} + const DetIdContainer& detUnitIds() const override {return theDetUnitIds;} + const DetIdContainer& detIds() const override {return theDetIds;} + const MTDGeomDet* idToDetUnit(DetId) const override; + const MTDGeomDet* idToDet(DetId) const override; + + const GeomDetEnumerators::SubDetector geomDetSubDetector(int subdet) const; + unsigned int numberOfLayers(int subdet) const; + bool isThere(GeomDetEnumerators::SubDetector subdet) const; + + unsigned int offsetDU(unsigned sid) const { return theOffsetDU[sid];} + unsigned int endsetDU(unsigned sid) const { return theEndsetDU[sid];} + // Magic : better be called at the right moment... + void setOffsetDU(unsigned sid) { theOffsetDU[sid]=detUnits().size();} + void setEndsetDU(unsigned sid) { theEndsetDU[sid]=detUnits().size();} + void fillTestMap(const GeometricTimingDet* gd); + + ModuleType moduleType(const std::string& name) const; + + GeometricTimingDet const * trackerDet() const {return theTrackerDet;} + + const DetContainer& detsBTL() const; + const DetContainer& detsETL() const; + + ModuleType getDetectorType(DetId) const; + float getDetectorThickness(DetId) const; + + +private: + + explicit MTDGeometry(GeometricTimingDet const* gd=nullptr); + + friend class MTDGeomBuilderFromGeometricTimingDet; + + void addType(GeomDetType const * p); + void addDetUnit(GeomDet const * p); + void addDetUnitId(DetId p); + void addDet(GeomDet const * p); + void addDetId(DetId p); + void finalize(); + + GeometricTimingDet const * theTrackerDet; + + /// Aligner has access to map + friend class GeometryAligner; + + DetTypeContainer theDetTypes; // owns the DetTypes + DetContainer theDetUnits; // they're all also into 'theDets', so we assume 'theDets' owns them + unsigned int theOffsetDU[2]; // offsets in the above + unsigned int theEndsetDU[2]; // end offsets in the above + DetContainer theDets; // owns *ONLY* the GeomDet * corresponding to GluedDets. + DetIdContainer theDetUnitIds; + DetIdContainer theDetIds; + mapIdToDetUnit theMapUnit; // does not own GeomDetUnit * + mapIdToDet theMap; // does not own GeomDet * + + DetContainer theBTLDets; // not owned: they're also in 'theDets' + DetContainer theETLDets; // not owned: they're also in 'theDets' + + GeomDetEnumerators::SubDetector theSubDetTypeMap[2]; + unsigned int theNumberOfLayers[2]; + std::vector< std::tuple< DetId, MTDGeometry::ModuleType, float> > theDetTypetList; +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h b/Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h new file mode 100644 index 0000000000000..49fde80a92d86 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h @@ -0,0 +1,25 @@ +#ifndef MTDGeometryBuilder_MTDParametersFromDD_h +#define MTDGeometryBuilder_MTDParametersFromDD_h + +#include +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +class DDCompactView; +class PMTDParameters; + +class MTDParametersFromDD { + public: + MTDParametersFromDD() {} + MTDParametersFromDD(const edm::ParameterSet& ); + virtual ~MTDParametersFromDD() {} + + bool build( const DDCompactView*, + PMTDParameters& ); + private: + void putOne( int, std::vector &, PMTDParameters& ); + std::vector items_; + std::vector pars_; +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h b/Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h new file mode 100644 index 0000000000000..54ee32d0c9dbb --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h @@ -0,0 +1,26 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDTopologyBuilder_H +#define Geometry_MTDGeometryBuilder_MTDTopologyBuilder_H + +#include +class PixelTopology; +class Bounds; + +/** + * Called by GeomTopologyBuilder, chooses the right topology for Pixels. + */ + +class MTDTopologyBuilder { +public: + + MTDTopologyBuilder(); + + PixelTopology* build(const Bounds* bounds, + bool upgradeGeometry, + int ROWS_PER_ROC, // Num of Rows per ROC + int COLS_PER_ROC, // Num of Cols per ROC + int BIG_PIX_PER_ROC_X, // in x direction, rows. BIG_PIX_PER_ROC_X = 0 for SLHC + int BIG_PIX_PER_ROC_Y, // in y direction, cols. BIG_PIX_PER_ROC_Y = 0 for SLHC + int ROCS_X, int ROCS_Y); +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h b/Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h new file mode 100644 index 0000000000000..f090739691c10 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h @@ -0,0 +1,19 @@ +#ifndef Geometry_MTDGeometryBuilder_PlaneBuilderFromGeometricTimingDet_H +#define Geometry_MTDGeometryBuilder_PlaneBuilderFromGeometricTimingDet_H + +#include "DataFormats/GeometrySurface/interface/BoundPlane.h" +#include "DataFormats/GeometrySurface/interface/ReferenceCounted.h" + +class GeometricTimingDet; +/** + * Converts DDFilteredView volumes to Bounds + */ +class PlaneBuilderFromGeometricTimingDet { +public: + using ResultType = ReferenceCountingPointer; + + ResultType plane( const GeometricTimingDet* gd) const; + +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h b/Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h new file mode 100644 index 0000000000000..146a1b7744f75 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h @@ -0,0 +1,124 @@ +#ifndef Geometry_MTDGeometryBuilder_ProxyMTDTopology_H +#define Geometry_MTDGeometryBuilder_ProxyMTDTopology_H + +/// ProxyMTDTopology +/// +/// Class derived from PixelTopology that serves as a proxy to the +/// actual topology for a given PixelGeomDetType. In addition, the +/// class holds a pointer to the surface deformation parameters. +/// ProxyMTDTopology takes over ownership of the surface +/// deformation parameters. +/// +/// All inherited virtual methods that take the predicted track +/// state as a parameter are reimplemented in order to apply +/// corrections due to the surface deformations. +// +/// The 'old' methods without the track predictions simply call +/// the method of the actual topology. +/// +/// \author : Andreas Mussgiller +/// date : December 2010 + +#include "Geometry/CommonTopologies/interface/SurfaceDeformation.h" +#include "Geometry/CommonTopologies/interface/PixelTopology.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h" + +class Plane; + +class ProxyMTDTopology final : public PixelTopology { +public: + + ProxyMTDTopology( MTDGeomDetType const * type, Plane * bp ); + + LocalPoint localPosition( const MeasurementPoint& ) const override; + /// conversion taking also the predicted track state + LocalPoint localPosition( const MeasurementPoint& mp, + const Topology::LocalTrackPred &trkPred ) const override; + + LocalError localError( const MeasurementPoint&, + const MeasurementError& ) const override; + /// conversion taking also the predicted track state + LocalError localError( const MeasurementPoint& mp, + const MeasurementError& me, + const Topology::LocalTrackPred &trkPred ) const override; + + MeasurementPoint measurementPosition( const LocalPoint & ) const override; + MeasurementPoint measurementPosition( const LocalPoint &lp, + const Topology::LocalTrackAngles &dir ) const override; + + MeasurementError measurementError( const LocalPoint &lp, const LocalError &le ) const override; + MeasurementError measurementError( const LocalPoint &lp, const LocalError &le, + const Topology::LocalTrackAngles &dir ) const override; + + int channel( const LocalPoint& ) const override; + int channel( const LocalPoint &lp, const Topology::LocalTrackAngles &dir ) const override; + + std::pair pixel( const LocalPoint& p) const override; + /// conversion taking also the angle from the track state + std::pair pixel( const LocalPoint& p, + const Topology::LocalTrackAngles <p ) const override; + + std::pair pitch() const override { return specificTopology().pitch(); } + int nrows() const override { return specificTopology().nrows(); } + int ncolumns() const override { return specificTopology().ncolumns(); } + int rocsY() const override { return specificTopology().rocsY(); } + int rocsX() const override { return specificTopology().rocsX(); } + int rowsperroc() const override { return specificTopology().rowsperroc(); } + int colsperroc() const override { return specificTopology().colsperroc(); } + float localX( const float mpX ) const override; + float localX( const float mpX, const Topology::LocalTrackPred &trkPred ) const override; + float localY( const float mpY ) const override; + float localY( const float mpY, const Topology::LocalTrackPred &trkPred ) const override; + + bool isItBigPixelInX(const int ixbin) const override { + return specificTopology().isItBigPixelInX(ixbin); + } + bool isItBigPixelInY(const int iybin) const override { + return specificTopology().isItBigPixelInY(iybin); + } + bool containsBigPixelInX(int ixmin, int ixmax) const override { + return specificTopology().containsBigPixelInX(ixmin, ixmax); + } + bool containsBigPixelInY(int iymin, int iymax) const override { + return specificTopology().containsBigPixelInY(iymin, iymax); + } + + bool isItEdgePixelInX(int ixbin) const override { + return specificTopology().isItEdgePixelInX(ixbin); + } + bool isItEdgePixelInY(int iybin) const override { + return specificTopology().isItEdgePixelInY(iybin); + } + bool isItEdgePixel(int ixbin, int iybin) const override { + return specificTopology().isItEdgePixel(ixbin, iybin); + } + + virtual const GeomDetType& type() const { return *theType;} + + virtual MTDGeomDetType const & specificType() const { return *theType; } + + const SurfaceDeformation * surfaceDeformation() const { + return theSurfaceDeformation.operator->(); + } + virtual void setSurfaceDeformation(const SurfaceDeformation * deformation); + + + virtual const PixelTopology& specificTopology() const { return specificType().specificTopology(); } + +private: + + /// Internal method to get correction of the position from SurfaceDeformation, + /// must not be called if 'theSurfaceDeformation' is a null pointer. + SurfaceDeformation::Local2DVector + positionCorrection(const LocalPoint &pos, const Topology::LocalTrackAngles &dir) const; + /// Internal method to get correction of the position from SurfaceDeformation, + /// must not be called if 'theSurfaceDeformation' is a null pointer. + SurfaceDeformation::Local2DVector + positionCorrection(const Topology::LocalTrackPred &trk) const; + + MTDGeomDetType const * theType; + float theLength, theWidth; + std::unique_ptr theSurfaceDeformation; +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h b/Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h new file mode 100644 index 0000000000000..1a8bc8225fa2b --- /dev/null +++ b/Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h @@ -0,0 +1,213 @@ +#ifndef Geometry_MTDGeometryBuilder_RectangularMTDTopology_H +#define Geometry_MTDGeometryBuilder_RectangularMTDTopology_H + + /** + * Topology for rectangular pixel detector with BIG pixels. + */ +// Modified for the large pixels. Should work for barrel and forward. +// Danek Kotlinski & Michele Pioppi, 3/06. +// The bigger pixels are on the ROC boundries. +// For columns (Y direction, longer direction): +// the normal pixel are 150um long, big pixels are 300um long, +// the pixel index goes from 0 to 416 (or less for smaller modules) +// the big pixel are in 0, 52,104,156,208,260,312,363 +// 51,103,155,207,259,311,363,415 . +// For rows (X direction, shorter direction): +// the normal pixel are 100um wide, big pixels are 200um wide, +// the pixel index goes from 0 to 159 (or less for smaller modules) +// the big pixel are in 79,80. +// The ROC has rows=80, cols=52. +// There are a lot of hardwired constants, sorry but this is a very +// specific class. For any other sensor design it has to be rewritten. + +// G. Giurgiu 11/27/06 --------------------------------------------- +// Check whether the pixel is at the edge of the module by adding the +// following functions (ixbin and iybin are the pixel row and column +// inside the module): +// bool isItEdgePixelInX (int ixbin) +// bool isItEdgePixelInY (int iybin) +// bool isItEdgePixel (int ixbin, int iybin) +// ------------------------------------------------------------------ +// Add the individual measurement to local trasformations classes 01/07 d.k. +// ------------------------------------------------------------------ +// Add big pixel flags for cluster range 15/3/07 V.Chiochia + +# include "Geometry/CommonTopologies/interface/PixelTopology.h" +# include "DataFormats/SiPixelDetId/interface/PixelChannelIdentifier.h" +# include "FWCore/MessageLogger/interface/MessageLogger.h" + + +class RectangularMTDTopology final : public PixelTopology +{ +public: + + // Constructor, initilize + RectangularMTDTopology( int nrows, int ncols, float pitchx, float pitchy, + bool upgradeGeometry, + int ROWS_PER_ROC, // Num of Rows per ROC + int COLS_PER_ROC, // Num of Cols per ROC + int BIG_PIX_PER_ROC_X, // in x direction, rows. BIG_PIX_PER_ROC_X = 0 for SLHC + int BIG_PIX_PER_ROC_Y, // in y direction, cols. BIG_PIX_PER_ROC_Y = 0 for SLHC + int ROCS_X, int ROCS_Y ) + : m_pitchx( pitchx ), + m_pitchy( pitchy ), + m_nrows( nrows ), + m_ncols( ncols ), + m_ROWS_PER_ROC( ROWS_PER_ROC ), // Num of Rows per ROC + m_COLS_PER_ROC( COLS_PER_ROC ), // Num of Cols per ROC + m_ROCS_X( ROCS_X ), // 2 for SLHC + m_ROCS_Y( ROCS_Y ), // 8 for SLHC + m_upgradeGeometry( upgradeGeometry ) + { + // Calculate the edge of the active sensor with respect to the center, + // that is simply the half-size. + // Take into account large pixels + m_xoffset = -(m_nrows + BIG_PIX_PER_ROC_X*m_nrows/ROWS_PER_ROC)/2. * + m_pitchx; + m_yoffset = -(m_ncols + BIG_PIX_PER_ROC_Y*m_ncols/COLS_PER_ROC)/2. * + m_pitchy; + + LogDebug("RectangularMTDTopology") << "nrows " << m_nrows << ", ncols " << m_ncols << ", pitchx " + << m_pitchx << ", pitchy " << m_pitchy << ", xoffset " + << m_xoffset << ", yoffset " << m_yoffset << ", BIG_PIX_PER_ROC_X " + << BIG_PIX_PER_ROC_X << ", BIG_PIX_PER_ROC_Y " << BIG_PIX_PER_ROC_Y << ", ROWS_PER_ROC " + << ROWS_PER_ROC << ", COLS_PER_ROC " << COLS_PER_ROC << ", ROCS_X " << ROCS_X << ", ROCS_Y " << ROCS_Y + << "\nNROWS " << m_ROWS_PER_ROC * m_ROCS_X << ", NCOL " << m_COLS_PER_ROC * m_ROCS_Y; + } + + // Topology interface, go from Masurement to Local corrdinates + // pixel coordinates (mp) -> cm (LocalPoint) + LocalPoint localPosition( const MeasurementPoint& mp ) const override; + + // Transform LocalPoint to Measurement. Call pixel(). + MeasurementPoint measurementPosition( const LocalPoint& lp ) + const override { + std::pair p = pixel( lp ); + return MeasurementPoint( p.first, p.second ); + } + + // PixelTopology interface. + // Transform LocalPoint in cm to measurement in pitch units. + std::pair pixel( const LocalPoint& p ) const override; + + // Errors + // Error in local (cm) from the masurement errors + LocalError localError( const MeasurementPoint&, + const MeasurementError& ) const override; + // Errors in pitch units from localpoint error (in cm) + MeasurementError measurementError( const LocalPoint&, + const LocalError& ) const override; + + //------------------------------------------------------------- + // Transform LocalPoint to channel. Call pixel() + // + int channel( const LocalPoint& lp ) const override { + std::pair p = pixel( lp ); + return PixelChannelIdentifier::pixelToChannel( int( p.first ), + int( p.second )); + } + + //------------------------------------------------------------- + // Transform measurement to local coordinates individually in each dimension + // + float localX( const float mpX ) const override; + float localY( const float mpY ) const override; + + //------------------------------------------------------------- + // Return the BIG pixel information for a given pixel + // + bool isItBigPixelInX( const int ixbin ) const override { + return (( m_upgradeGeometry )?(false):(( ixbin == 79 ) | ( ixbin == 80 ))); + } + + bool isItBigPixelInY( const int iybin ) const override { + if UNLIKELY( m_upgradeGeometry ) return false; + else { + int iybin0 = iybin%52; + return(( iybin0 == 0 ) | ( iybin0 == 51 )); + // constexpr int bigYIndeces[]{0,51,52,103,104,155,156,207,208,259,260,311,312,363,364,415,416,511}; + // return *std::lower_bound(std::begin(bigYIndeces),std::end(bigYIndeces),iybin) == iybin; + } + } + + //------------------------------------------------------------- + // Return BIG pixel flag in a given pixel range + // + bool containsBigPixelInX(int ixmin, int ixmax ) const override { + return m_upgradeGeometry ? false :( (ixmin<=80) & (ixmax>=79) ); + } + bool containsBigPixelInY(int iymin, int iymax ) const override { + return m_upgradeGeometry ? false : + ( isItBigPixelInY( iymin ) || isItBigPixelInY( iymax ) || (iymin/52) != (iymax/52) ) + ; + } + + + //------------------------------------------------------------- + // Check whether the pixel is at the edge of the module + // + bool isItEdgePixelInX (int ixbin) const override { + return ( (ixbin == 0) | (ixbin == (m_nrows-1)) ); + } + bool isItEdgePixelInY (int iybin) const override { + return ( (iybin == 0) | (iybin == (m_ncols-1)) ); + } + bool isItEdgePixel (int ixbin, int iybin) const override { + return ( isItEdgePixelInX( ixbin ) | isItEdgePixelInY( iybin ) ); + } + + //------------------------------------------------------------------ + // Return pitch + std::pair pitch() const override { + return std::pair( float(m_pitchx), float(m_pitchy)); + } + // Return number of rows + int nrows() const override { + return ( m_nrows ); + } + // Return number of cols + int ncolumns() const override { + return ( m_ncols ); + } + // mlw Return number of ROCS Y + int rocsY() const override { + return m_ROCS_Y; + } + // mlw Return number of ROCS X + int rocsX() const override { + return m_ROCS_X; + } + // mlw Return number of rows per roc + int rowsperroc() const override { + return m_ROWS_PER_ROC; + } + // mlw Return number of cols per roc + int colsperroc() const override { + return m_COLS_PER_ROC; + } + float xoffset() const { + return m_xoffset; + } + float yoffset() const { + return m_yoffset; + } + + +private: + + float m_pitchx; + float m_pitchy; + float m_xoffset; + float m_yoffset; + int m_nrows; + int m_ncols; + int m_ROWS_PER_ROC; + int m_COLS_PER_ROC; + int m_ROCS_X; + int m_ROCS_Y; + bool m_upgradeGeometry; +}; + +#endif + + diff --git a/Geometry/MTDGeometryBuilder/plugins/BuildFile.xml b/Geometry/MTDGeometryBuilder/plugins/BuildFile.xml new file mode 100644 index 0000000000000..e94a56ddabb56 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/plugins/BuildFile.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.cc b/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.cc new file mode 100644 index 0000000000000..844d061db0b19 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.cc @@ -0,0 +1,129 @@ +#include "MTDDigiGeometryESModule.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/PMTDParametersRcd.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" +#include "Geometry/MTDNumberingBuilder/interface/MTDTopology.h" +#include "Geometry/Records/interface/MTDTopologyRcd.h" + +// Alignments +#include "CondFormats/Alignment/interface/Alignments.h" +#include "CondFormats/Alignment/interface/AlignmentErrorsExtended.h" +#include "CondFormats/Alignment/interface/AlignmentSurfaceDeformations.h" +#include "CondFormats/Alignment/interface/DetectorGlobalPosition.h" +#include "CondFormats/AlignmentRecord/interface/GlobalPositionRcd.h" +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h" +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h" +#include "CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h" +#include "Geometry/CommonTopologies/interface/GeometryAligner.h" + +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/Framework/interface/ESProducer.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include + +//__________________________________________________________________ +MTDDigiGeometryESModule::MTDDigiGeometryESModule(const edm::ParameterSet & p) + : alignmentsLabel_(p.getParameter("alignmentsLabel")), + myLabel_(p.getParameter("appendToDataLabel")) +{ + applyAlignment_ = p.getParameter("applyAlignment"); + fromDDD_ = p.getParameter("fromDDD"); + + setWhatProduced(this); + + edm::LogInfo("Geometry") << "@SUB=MTDDigiGeometryESModule" + << "Label '" << myLabel_ << "' " + << (applyAlignment_ ? "looking for" : "IGNORING") + << " alignment labels '" << alignmentsLabel_ << "'."; +} + +//__________________________________________________________________ +MTDDigiGeometryESModule::~MTDDigiGeometryESModule() {} + +void +MTDDigiGeometryESModule::fillDescriptions(edm::ConfigurationDescriptions & descriptions) +{ + edm::ParameterSetDescription descDB; + descDB.add( "appendToDataLabel", "" ); + descDB.add( "fromDDD", false ); + descDB.add( "applyAlignment", true ); + descDB.add( "alignmentsLabel", "" ); + descriptions.add( "mtdGeometryDB", descDB ); + + edm::ParameterSetDescription desc; + desc.add( "appendToDataLabel", "" ); + desc.add( "fromDDD", true ); + desc.add( "applyAlignment", true ); + desc.add( "alignmentsLabel", "" ); + descriptions.add( "mtdGeometry", desc ); +} + +//__________________________________________________________________ +std::shared_ptr +MTDDigiGeometryESModule::produce(const MTDDigiGeometryRecord & iRecord) +{ + // + // Called whenever the alignments, alignment errors or global positions change + // + edm::ESHandle gD; + iRecord.getRecord().get( gD ); + + edm::ESHandle tTopoHand; + iRecord.getRecord().get(tTopoHand); + const MTDTopology *tTopo=tTopoHand.product(); + + edm::ESHandle ptp; + iRecord.getRecord().get( ptp ); + + MTDGeomBuilderFromGeometricTimingDet builder; + mtd_ = std::shared_ptr(builder.build(&(*gD), *ptp, tTopo)); + + + if (applyAlignment_) { + // Since fake is fully working when checking for 'empty', we should get rid of applyAlignment_! + edm::ESHandle globalPosition; + iRecord.getRecord().get(alignmentsLabel_, globalPosition); + edm::ESHandle alignments; + iRecord.getRecord().get(alignmentsLabel_, alignments); + edm::ESHandle alignmentErrors; + iRecord.getRecord().get(alignmentsLabel_, alignmentErrors); + // apply if not empty: + if (alignments->empty() && alignmentErrors->empty() && globalPosition->empty()) { + edm::LogInfo("Config") << "@SUB=MTDDigiGeometryRecord::produce" + << "Alignment(Error)s and global position (label '" + << alignmentsLabel_ << "') empty: Geometry producer (label " + << "'" << myLabel_ << "') assumes fake and does not apply."; + } else { + GeometryAligner ali; + ali.applyAlignments(&(*mtd_), &(*alignments), &(*alignmentErrors), + align::DetectorGlobalPosition(*globalPosition, + DetId(DetId::Forward))); + } + + edm::ESHandle surfaceDeformations; + iRecord.getRecord().get(alignmentsLabel_, surfaceDeformations); + // apply if not empty: + if (surfaceDeformations->empty()) { + edm::LogInfo("Config") << "@SUB=MTDDigiGeometryRecord::produce" + << "AlignmentSurfaceDeformations (label '" + << alignmentsLabel_ << "') empty: Geometry producer (label " + << "'" << myLabel_ << "') assumes fake and does not apply."; + } else { + GeometryAligner ali; + ali.attachSurfaceDeformations(&(*mtd_), &(*surfaceDeformations)); + } + } + + + return mtd_; +} + +DEFINE_FWK_EVENTSETUP_MODULE(MTDDigiGeometryESModule); diff --git a/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.h b/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.h new file mode 100644 index 0000000000000..9d8aa61442712 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/plugins/MTDDigiGeometryESModule.h @@ -0,0 +1,38 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDDigiGeometryESModule_H +#define Geometry_MTDGeometryBuilder_MTDDigiGeometryESModule_H + +#include "FWCore/Framework/interface/ESProducer.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "Geometry/Records/interface/MTDDigiGeometryRecord.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" +#include + +#include + +namespace edm { + class ConfigurationDescriptions; +} + +class MTDDigiGeometryESModule: public edm::ESProducer{ + public: + MTDDigiGeometryESModule(const edm::ParameterSet & p); + ~MTDDigiGeometryESModule() override; + std::shared_ptr produce(const MTDDigiGeometryRecord &); + + static void fillDescriptions(edm::ConfigurationDescriptions & descriptions); + + private: + /// Called when geometry description changes + std::shared_ptr mtd_; + const std::string alignmentsLabel_; + const std::string myLabel_; + bool applyAlignment_; // Switch to apply alignment corrections + bool fromDDD_; +}; + + +#endif + + + + diff --git a/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.cc b/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.cc new file mode 100644 index 0000000000000..21c703273a4f1 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.cc @@ -0,0 +1,49 @@ +#include "MTDParametersESModule.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/ESTransientHandle.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/PMTDParametersRcd.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" + +MTDParametersESModule::MTDParametersESModule( const edm::ParameterSet& pset) : + builder(pset) +{ + edm::LogInfo("TRACKER") << "MTDParametersESModule::MTDParametersESModule"; + + setWhatProduced(this); +} + +MTDParametersESModule::~MTDParametersESModule() +{ +} + +void +MTDParametersESModule::fillDescriptions( edm::ConfigurationDescriptions & descriptions ) +{ + edm::ParameterSetDescription desc; + edm::ParameterSetDescription vpdesc; + vpdesc.add("subdetPars",std::vector()); + desc.addVPSet("vitems",vpdesc,edm::VParameterSet()); + desc.add("vpars",std::vector()); + descriptions.add( "mtdParametersBase", desc ); +} + +MTDParametersESModule::ReturnType +MTDParametersESModule::produce( const PMTDParametersRcd& iRecord ) +{ + edm::LogInfo("MTDParametersESModule") << "MTDParametersESModule::produce(const PMTDParametersRcd& iRecord)" << std::endl; + edm::ESTransientHandle cpv; + iRecord.getRecord().get( cpv ); + + PMTDParameters* ptp = new PMTDParameters(); + builder.build( &(*cpv), *ptp ); + + return ReturnType( ptp ) ; +} + +DEFINE_FWK_EVENTSETUP_MODULE( MTDParametersESModule); diff --git a/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.h b/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.h new file mode 100644 index 0000000000000..3fdcc4f4e0746 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/plugins/MTDParametersESModule.h @@ -0,0 +1,33 @@ +#ifndef Geometry_MTDGeometryBuilder_MTDParametersESModule_H +#define Geometry_MTDGeometryBuilder_MTDParametersESModule_H + +#include "FWCore/Framework/interface/ESProducer.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h" +#include + +namespace edm { + class ConfigurationDescriptions; +} +class PMTDParameters; +class PMTDParametersRcd; + + +class MTDParametersESModule: public edm::ESProducer +{ + public: + MTDParametersESModule( const edm::ParameterSet & ); + ~MTDParametersESModule( void ) override; + + typedef std::shared_ptr ReturnType; + + static void fillDescriptions( edm::ConfigurationDescriptions & ); + + ReturnType produce( const PMTDParametersRcd & ); + + private: + MTDParametersFromDD builder; +}; + +#endif diff --git a/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometryDB_cff.py b/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometryDB_cff.py new file mode 100644 index 0000000000000..2691e23dd174f --- /dev/null +++ b/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometryDB_cff.py @@ -0,0 +1,16 @@ +import FWCore.ParameterSet.Config as cms + +import Geometry.MTDGeometryBuilder.mtdGeometryDB_cfi +# +# This cff provides a TrackerGeometry with the label 'idealForDigi' that is for sure matching +# the ideal one and thus should be used in the digitisers. +# +idealForDigiMTDGeometry = Geometry.MTDGeometryBuilder.mtdGeometryDB_cfi.mtdGeometryDB.clone() +# The es_module providing fake (i.e. empty) alignment constants: +from Alignment.CommonAlignmentProducer.fakeForIdealAlignmentProducer_cfi import * +# need to set to False, see below: +idealForDigiMTDGeometry.applyAlignment = False +# Label of the produced TrackerGeometry: +idealForDigiMTDGeometry.appendToDataLabel = 'idealForDigi' +# Alignments are looked for with this label: +idealForDigiMTDGeometry.alignmentsLabel = 'fakeForIdeal' diff --git a/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometry_cff.py b/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometry_cff.py new file mode 100644 index 0000000000000..480a226ec7776 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/python/idealForDigiMTDGeometry_cff.py @@ -0,0 +1,16 @@ +import FWCore.ParameterSet.Config as cms + +import Geometry.MTDGeometryBuilder.mtdGeometry_cfi +# +# This cff provides a TrackerGeometry with the label 'idealForDigi' that is for sure matching +# the ideal one and thus should be used in the digitisers. +# +idealForDigiMTDGeometry = Geometry.MTDGeometryBuilder.mtdGeometry_cfi.mtdGeometry.clone() +# The es_module providing fake (i.e. empty) alignment constants: +from Alignment.CommonAlignmentProducer.fakeForIdealAlignmentProducer_cfi import * +# need to set to False, see below: +idealForDigiMTDGeometry.applyAlignment = False +# Label of the produced TrackerGeometry: +idealForDigiMTDGeometry.appendToDataLabel = 'idealForDigi' +# Alignments are looked for with this label: +idealForDigiMTDGeometry.alignmentsLabel = 'fakeForIdeal' diff --git a/Geometry/MTDGeometryBuilder/python/mtdModuleInfo_cfg.py b/Geometry/MTDGeometryBuilder/python/mtdModuleInfo_cfg.py new file mode 100644 index 0000000000000..6c4341e30fad9 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/python/mtdModuleInfo_cfg.py @@ -0,0 +1,31 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("GeometryTest") +process.load("FWCore.MessageLogger.MessageLogger_cfi") + +process.load("Geometry.CMSCommonData.cmsIdealGeometryXML_cfi") + +process.load("Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi") + +process.load("Geometry.MTDGeometryBuilder.mtdGeometry_cfi") +process.load("Alignment.CommonAlignmentProducer.FakeAlignmentSource_cfi") + +#this is always needed if users want access to the vector +process.TrackerGeometricDetExtraESModule = cms.ESProducer( "MTDGeometricDetExtraESModule", + fromDDD = cms.bool( True ) + ) + +process.source = cms.Source("EmptySource") + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(1) +) +#process.print = cms.OutputModule("AsciiOutputModule") + +process.prod = cms.EDAnalyzer("ModuleInfo", + fromDDD = cms.bool(True) +) + +process.p1 = cms.Path(process.prod) +#process.ep = cms.EndPath(process.print) + diff --git a/Geometry/MTDGeometryBuilder/python/mtdParameters_cfi.py b/Geometry/MTDGeometryBuilder/python/mtdParameters_cfi.py new file mode 100644 index 0000000000000..a6f698c18e652 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/python/mtdParameters_cfi.py @@ -0,0 +1,20 @@ +import FWCore.ParameterSet.Config as cms + +from Geometry.MTDGeometryBuilder.mtdParametersBase_cfi import mtdParametersBase + +mtdParameters = mtdParametersBase.clone() +del mtdParametersBase + +mtdParameters.vpars = cms.vint32(4,4,4,24) +mtdParameters.vitems = cms.VPSet( + cms.PSet( #BTL + subdetPars = cms.vint32(22,24,16,10, + 0x1,0x3,0x3F,0x3F, + 4,4,4,1) #rows / columns / nROCs x / nROCs y + ), + cms.PSet( #ETL + subdetPars = cms.vint32(22,24,16,7, + 0x1,0x3,0x3F,0xFF, + 24,4,2,8) #rows / columns / nROCs x / nROCs y + ) + ) diff --git a/Geometry/MTDGeometryBuilder/src/ES_MTDGeometry.cc b/Geometry/MTDGeometryBuilder/src/ES_MTDGeometry.cc new file mode 100644 index 0000000000000..5dd81857ca50d --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/ES_MTDGeometry.cc @@ -0,0 +1,7 @@ +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" + +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(MTDGeometry); + + diff --git a/Geometry/MTDGeometryBuilder/src/MTDGeomBuilderFromGeometricTimingDet.cc b/Geometry/MTDGeometryBuilder/src/MTDGeomBuilderFromGeometricTimingDet.cc new file mode 100644 index 0000000000000..9db02ecc3da55 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/MTDGeomBuilderFromGeometricTimingDet.cc @@ -0,0 +1,200 @@ +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomBuilderFromGeometricTimingDet.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" +#include "Geometry/MTDNumberingBuilder/interface/MTDTopology.h" +#include "DataFormats/GeometrySurface/interface/MediumProperties.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include +#include +using std::vector; +using std::string; + +namespace { + void verifyDUinTG(MTDGeometry const & tg) { + int off=0; int end=0; + for ( int i=1; i!=2; i++) { + auto det = i - 1; + off = tg.offsetDU(det); + end = tg.endsetDU(det); assert(end>=off); // allow empty subdetectors. Needed for upgrade + for (int j=off; j!=end; ++j) { + assert(tg.detUnits()[j]->geographicalId().subdetId()==i); + assert(tg.detUnits()[j]->index()==j); + } + } + } +} + +MTDGeometry* +MTDGeomBuilderFromGeometricTimingDet::build( const GeometricTimingDet* gd, const PMTDParameters& ptp, const MTDTopology* tTopo ) +{ + theMTDDetTypeMap.clear(); + + MTDGeometry* tracker = new MTDGeometry(gd); + std::vector comp; + gd->deepComponents(comp); + + if(tTopo) theTopo = tTopo; + + //define a vector which associate to the detid subdetector index -1 (from 0 to 5) the GeometridDet enumerator to be able to know which type of subdetector it is + + std::vector gdsubdetmap(2,GeometricTimingDet::unknown); // hardcoded "2" should not be a surprise... + GeometricTimingDet::ConstGeometricTimingDetContainer subdetgd = gd->components(); + + LogDebug("SubDetectorGeometricTimingDetType") + << "GeometricTimingDet enumerator values of the subdetectors" << std::endl; + for(unsigned int i=0;igeographicalId()); + assert(mtdid.mtdSubDetector()>0 && mtdid.mtdSubDetector()<3); + gdsubdetmap[mtdid.mtdSubDetector()-1]= subdetgd[i]->type(); + LogTrace("SubDetectorGeometricTimingDetType") + << "subdet " << i + << " type " << subdetgd[i]->type() + << " detid " << std::hex << subdetgd[i]->geographicalId().rawId() << std::dec + << " subdetid " << subdetgd[i]->geographicalId().subdetId() << std::endl; + } + + std::vector dets[2]; + std::vector & btl = dets[0]; btl.reserve(comp.size()); + std::vector & etl = dets[1]; etl.reserve(comp.size()); + + for(auto & i : comp) { + MTDDetId mtdid(i->geographicalId()); + dets[mtdid.mtdSubDetector()-1].emplace_back(i); + } + + //loop on all the six elements of dets and firstly check if they are from pixel-like detector and call buildPixel, then loop again and check if they are strip and call buildSilicon. "unknown" can be filled either way but the vector of GeometricTimingDet must be empty !! + // this order is VERY IMPORTANT!!!!! For the moment I (AndreaV) understand that some pieces of code rely on pixel-like being before strip-like + + // now building the Pixel-like subdetectors + for(unsigned int i=0;i<2;++i) { + if(gdsubdetmap[i] == GeometricTimingDet::BTL) + buildPixel(dets[i],tracker, + GeomDetEnumerators::SubDetector::TimingBarrel, + ptp); + if(gdsubdetmap[i] == GeometricTimingDet::ETL) + buildPixel(dets[i],tracker, + GeomDetEnumerators::SubDetector::TimingEndcap, + ptp); + } + + buildGeomDet(tracker);//"GeomDet" + + verifyDUinTG(*tracker); + + return tracker; +} + +void MTDGeomBuilderFromGeometricTimingDet::buildPixel(std::vector const & gdv, + MTDGeometry* tracker, + GeomDetType::SubDetector det, + const PMTDParameters& ptp) // in y direction, cols. BIG_PIX_PER_ROC_Y = 0 for SLHC +{ + LogDebug("BuildingGeomDetUnits") + << " Pixel type. Size of vector: " << gdv.size() + << " GeomDetType subdetector: " << det + << " logical subdetector: " << GeomDetEnumerators::subDetGeom[det] + << " big pix per ROC x: " << 0<< " y: " << 0 + << " is upgrade: " << true << std::endl; + + // this is a hack while we put things into the DDD + int ROCrows(0),ROCcols(0),ROCSx(0),ROCSy(0); + switch(det) { + case GeomDetType::SubDetector::TimingBarrel: + ROCrows = ptp.vitems_[0].vpars_[8]; + ROCcols = ptp.vitems_[0].vpars_[9]; + ROCSx = ptp.vitems_[0].vpars_[10]; + ROCSy = ptp.vitems_[0].vpars_[11]; + break; + case GeomDetType::SubDetector::TimingEndcap: + ROCrows = ptp.vitems_[1].vpars_[8]; + ROCcols = ptp.vitems_[1].vpars_[9]; + ROCSx = ptp.vitems_[1].vpars_[10]; + ROCSy = ptp.vitems_[1].vpars_[11]; + break; + break; + default: + throw cms::Exception("UnknownDet") + << "MTDGeomBuilderFromGeometricTimingDet got a weird detector: " << det; + } + + switch(det) { + case GeomDetEnumerators::TimingBarrel: + tracker->setOffsetDU(0); + break; + case GeomDetEnumerators::TimingEndcap: + tracker->setOffsetDU(1); + break; + default: + throw cms::Exception("MTDGeomBuilderFromGeometricTimingDet") << det << " is not a timing detector!"; + } + + for(auto i : gdv){ + + std::string const & detName = i->name().fullname(); + if (theMTDDetTypeMap.find(detName) == theMTDDetTypeMap.end()) { + std::unique_ptr bounds(i->bounds()); + + PixelTopology* t = + MTDTopologyBuilder().build(&*bounds, + true, + ROCrows, + ROCcols, + 0,0, // these are BIG_PIX_XXXXX + ROCSx, ROCSy); + + theMTDDetTypeMap[detName] = new MTDGeomDetType(t,detName,det); + tracker->addType(theMTDDetTypeMap[detName]); + } + + PlaneBuilderFromGeometricTimingDet::ResultType plane = buildPlaneWithMaterial(i); + GeomDetUnit* temp = new MTDGeomDetUnit(&(*plane),theMTDDetTypeMap[detName],i->geographicalID()); + + tracker->addDetUnit(temp); + tracker->addDetUnitId(i->geographicalID()); + } + switch(det) { + case GeomDetEnumerators::TimingBarrel: + tracker->setEndsetDU(0); + break; + case GeomDetEnumerators::TimingEndcap: + tracker->setEndsetDU(1); + break; + default: + throw cms::Exception("MTDGeomBuilderFromGeometricTimingDet") << det << " is not a timing detector!"; + } +} + +void MTDGeomBuilderFromGeometricTimingDet::buildGeomDet(MTDGeometry* tracker){ + + auto const & gdu = tracker->detUnits(); + auto const & gduId = tracker->detUnitIds(); + + for(u_int32_t i=0;iaddDet(gdu[i]); + tracker->addDetId(gduId[i]); + string gduTypeName = gdu[i]->type().name(); + + } +} + +PlaneBuilderFromGeometricTimingDet::ResultType +MTDGeomBuilderFromGeometricTimingDet::buildPlaneWithMaterial(const GeometricTimingDet* gd, + double scale) const +{ + PlaneBuilderFromGeometricTimingDet planeBuilder; + PlaneBuilderFromGeometricTimingDet::ResultType plane = planeBuilder.plane(gd); + // + // set medium properties (if defined) + // + plane->setMediumProperties(MediumProperties(gd->radLength()*scale,gd->xi()*scale)); + + return plane; +} diff --git a/Geometry/MTDGeometryBuilder/src/MTDGeomDetUnit.cc b/Geometry/MTDGeometryBuilder/src/MTDGeomDetUnit.cc new file mode 100644 index 0000000000000..e0f8b97538280 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/MTDGeomDetUnit.cc @@ -0,0 +1,23 @@ +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h" + +#include "Geometry/CommonTopologies/interface/SurfaceDeformation.h" + +MTDGeomDetUnit::MTDGeomDetUnit( BoundPlane* sp, MTDGeomDetType const * type, DetId id) : + MTDGeomDet(sp), theTopology(new ProxyMTDTopology(type, sp)) +{ + setDetId(id); +} + +const GeomDetType& MTDGeomDetUnit::type() const { return theTopology->type(); } + +const MTDGeomDetType& MTDGeomDetUnit::specificType() const { return theTopology->specificType(); } + +const Topology& MTDGeomDetUnit::topology() const { return *theTopology; } + +const PixelTopology& MTDGeomDetUnit::specificTopology() const { return *theTopology; } + +void MTDGeomDetUnit::setSurfaceDeformation(const SurfaceDeformation * deformation) +{ + theTopology->setSurfaceDeformation(deformation); +} diff --git a/Geometry/MTDGeometryBuilder/src/MTDGeometry.cc b/Geometry/MTDGeometryBuilder/src/MTDGeometry.cc new file mode 100644 index 0000000000000..c132cbcb4246e --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/MTDGeometry.cc @@ -0,0 +1,262 @@ +#include + +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "Geometry/CommonDetUnit/interface/GeomDetType.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "DataFormats/ForwardDetId/interface/MTDDetId.h" +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" + +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include +#include +#include + +namespace { + GeomDetEnumerators::SubDetector + geometricDetToGeomDet(GeometricTimingDet::GTDEnumType gdenum) { + // provide a map between the GeometricTimingDet enumerators and the GeomDet enumerators of the possible tracker subdetectors + if(gdenum == GeometricTimingDet::GTDEnumType::BTL ) return GeomDetEnumerators::SubDetector::TimingBarrel; + if(gdenum == GeometricTimingDet::GTDEnumType::ETL ) return GeomDetEnumerators::SubDetector::TimingEndcap; + return GeomDetEnumerators::SubDetector::invalidDet; + } + + class DetIdComparator { + public: + bool operator()(GeometricTimingDet const* gd1, GeometricTimingDet const * gd2) const { + uint32_t det1 = gd1->geographicalId(); + uint32_t det2 = gd2->geographicalId(); + return det1 < det2; + } + }; +} + +MTDGeometry::MTDGeometry(GeometricTimingDet const* gd) + : theTrackerDet(gd) +{ + for(unsigned int i=0;i<2;++i) { + theSubDetTypeMap[i] = GeomDetEnumerators::invalidDet; + theNumberOfLayers[i] = 0; + } + GeometricTimingDet::ConstGeometricTimingDetContainer subdetgd = gd->components(); + + LogDebug("BuildingSubDetTypeMap") + << "GeometricTimingDet and GeomDetEnumerators enumerator values of the subdetectors" << std::endl; + for(unsigned int i=0;igeographicalId()); + assert(mtdid.mtdSubDetector()>0 && mtdid.mtdSubDetector()<3); + theSubDetTypeMap[mtdid.mtdSubDetector()-1] = geometricDetToGeomDet(subdetgd[i]->type()); + theNumberOfLayers[mtdid.mtdSubDetector()-1]= subdetgd[i]->components().size(); + LogTrace("BuildingSubDetTypeMap").log( [&](auto & debugstr) { + debugstr << "subdet " << i + << " Geometric Det type " << subdetgd[i]->type() + << " Geom Det type " << theSubDetTypeMap[mtdid.mtdSubDetector()-1] + << " detid " << std::hex << subdetgd[i]->geographicalId().rawId() << std::dec + << " subdetid " << mtdid.mtdSubDetector() + << " number of layers " << subdetgd[i]->components().size() + << std::endl; + }); + } + LogDebug("SubDetTypeMapContent").log( [&](auto & debugstr) { + debugstr << "Content of theSubDetTypeMap" << std::endl; + for(unsigned int i=1;i<=2;++i) { + debugstr << " detid subdet "<< i + << " Geom Det type "<< geomDetSubDetector(i) << std::endl; + } + }); + LogDebug("NumberOfLayers").log( [&](auto & debugstr) { + debugstr << "Content of theNumberOfLayers" << std::endl; + for(unsigned int i=1;i<=2;++i) { + debugstr << " detid subdet "<< i + << " number of layers " << numberOfLayers(i) << std::endl; + } + }); + std::vector deepcomp; + gd->deepComponents(deepcomp); + + sort(deepcomp.begin(), deepcomp.end(), DetIdComparator()); + + LogDebug("ThicknessAndType") + << " Total Number of Detectors " << deepcomp.size() << std::endl; + LogDebug("ThicknessAndType") + << "Dump of sensors names and bounds" << std::endl; + LogDebug("ThicknessAndType").log( [&](auto & debugstr) { + for(auto det : deepcomp) { + fillTestMap(det); + debugstr << std::hex << det->geographicalId().rawId() << std::dec + << " " << det->name().fullname() << " " + << det->bounds()->thickness(); + } + }); + LogDebug("DetTypeList").log( [&](auto & debugstr) { + debugstr << " Content of DetTypetList : size " << theDetTypetList.size() << std::endl; + for (auto iVal : theDetTypetList) { + debugstr + << " DetId " << std::get<0>(iVal).rawId() + << " Type " << static_cast::type>(std::get<1>(iVal)) + << " Thickness " << std::get<2>(iVal) << std::endl; + } + }); +} + +MTDGeometry::~MTDGeometry() { + for (auto d : theDets) delete const_cast(d); + for (auto d : theDetTypes) delete const_cast(d); +} + +void MTDGeometry::finalize() { + theDetTypes.shrink_to_fit(); // owns the DetTypes + theDetUnits.shrink_to_fit(); // they're all also into 'theDets', so we assume 'theDets' owns them + theDets.shrink_to_fit(); // owns *ONLY* the GeomDet * corresponding to GluedDets. + theDetUnitIds.shrink_to_fit(); + theDetIds.shrink_to_fit(); + + theBTLDets.shrink_to_fit(); // not owned: they're also in 'theDets' + theETLDets.shrink_to_fit(); // not owned: they're also in 'theDets' +} + +void MTDGeometry::addType(GeomDetType const * p) { + theDetTypes.emplace_back(p); // add to vector +} + +void MTDGeometry::addDetUnit(GeomDet const * p) { + // set index + const_cast(p)->setIndex(theDetUnits.size()); + theDetUnits.emplace_back(p); // add to vector + theMapUnit.emplace(p->geographicalId().rawId(),p); +} + +void MTDGeometry::addDetUnitId(DetId p){ + theDetUnitIds.emplace_back(p); +} + +void MTDGeometry::addDet(GeomDet const * p) { + // set index + const_cast(p)->setGdetIndex(theDets.size()); + theDets.emplace_back(p); // add to vector + theMap.insert(std::make_pair(p->geographicalId().rawId(),p)); + MTDDetId id(p->geographicalId()); + switch(id.mtdSubDetector()){ + case MTDDetId::BTL: + theBTLDets.emplace_back(p); + break; + case MTDDetId::ETL: + theETLDets.emplace_back(p); + break; + default: + edm::LogError("MTDGeometry")<<"ERROR - I was expecting a MTD Subdetector, I got a "<(p->second); + } + return nullptr; +} + +const MTDGeomDet* +MTDGeometry::idToDet(DetId s)const +{ + mapIdToDet::const_iterator p=theMap.find(s.rawId()); + if (p != theMap.end()) { + return static_cast(p->second); + } + return nullptr; +} + +const GeomDetEnumerators::SubDetector +MTDGeometry::geomDetSubDetector(int subdet) const { + if(subdet>=1 && subdet<=2) { + return theSubDetTypeMap[subdet-1]; + } else { + throw cms::Exception("WrongTrackerSubDet") << "Subdetector " << subdet; + } +} + +unsigned int +MTDGeometry::numberOfLayers(int subdet) const { + if(subdet>=1 && subdet<=2) { + return theNumberOfLayers[subdet-1]; + } else { + throw cms::Exception("WrongTrackerSubDet") << "Subdetector " << subdet; + } +} + +bool +MTDGeometry::isThere(GeomDetEnumerators::SubDetector subdet) const { + for(unsigned int i=1;i<=2;++i) { + if(subdet == geomDetSubDetector(i)) return true; + } + return false; +} + +void MTDGeometry::fillTestMap(const GeometricTimingDet* gd) { + + std::string temp = gd->name().fullname(); + std::string name = temp.substr(temp.find(":")+1); + DetId detid = gd->geographicalId(); + float thickness = gd->bounds()->thickness(); + std::string nameTag; + MTDGeometry::ModuleType mtype = moduleType(name); + if (theDetTypetList.empty()) { + theDetTypetList.emplace_back(detid, mtype, thickness); + } else { + auto & t = (*(theDetTypetList.end()-1)); + if (std::get<1>(t) != mtype) theDetTypetList.emplace_back(detid, mtype, thickness); + else { + if ( detid > std::get<0>(t) ) std::get<0>(t) = detid; + } + } +} + +MTDGeometry::ModuleType MTDGeometry::getDetectorType(DetId detid) const { + for (auto iVal : theDetTypetList) { + DetId detid_max = std::get<0>(iVal); + MTDGeometry::ModuleType mtype = std::get<1>(iVal); + if (detid.rawId() <= detid_max.rawId()) return mtype; + } + return MTDGeometry::ModuleType::UNKNOWN; +} + +float MTDGeometry::getDetectorThickness(DetId detid) const { + for (auto iVal : theDetTypetList) { + DetId detid_max = std::get<0>(iVal); + if (detid.rawId() <= detid_max.rawId()) + return std::get<2>(iVal); + } + return -1.0; +} + +MTDGeometry::ModuleType MTDGeometry::moduleType(const std::string& name) const { + if ( name.find("Timing") != std::string::npos ){ + if ( name.find("BModule") != std::string::npos ) return ModuleType::BTL; + else if ( name.find("EModule") != std::string::npos ) return ModuleType::ETL; + } + return ModuleType::UNKNOWN; +} diff --git a/Geometry/MTDGeometryBuilder/src/MTDParametersFromDD.cc b/Geometry/MTDGeometryBuilder/src/MTDParametersFromDD.cc new file mode 100644 index 0000000000000..62385fca33fce --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/MTDParametersFromDD.cc @@ -0,0 +1,57 @@ +#include "Geometry/MTDGeometryBuilder/interface/MTDParametersFromDD.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "DetectorDescription/Core/interface/DDVectorGetter.h" +#include "DetectorDescription/Core/interface/DDutils.h" + +MTDParametersFromDD::MTDParametersFromDD(const edm::ParameterSet& pset) { + const edm::VParameterSet& items = + pset.getParameterSetVector("vitems"); + pars_ = pset.getParameter >("vpars"); + + items_.resize(items.size()); + for( unsigned i = 0; i < items.size(); ++i) { + auto& item = items_[i]; + item.id_ = i+1; + item.vpars_ = items[i].getParameter >("subdetPars"); + } +} + +bool +MTDParametersFromDD::build( const DDCompactView* cvp, + PMTDParameters& ptp) +{ + if( items_.empty() ) { + for( int subdet = 1; subdet <= 6; ++subdet ) + { + std::stringstream sstm; + sstm << "Subdetector" << subdet; + std::string name = sstm.str(); + + if( DDVectorGetter::check( name )) + { + std::vector subdetPars = dbl_to_int( DDVectorGetter::get( name )); + putOne( subdet, subdetPars, ptp ); + } + } + } else { + ptp.vitems_ = items_; + } + + if( pars_.empty() ) { + ptp.vpars_ = dbl_to_int( DDVectorGetter::get( "vPars" )); + } else { + ptp.vpars_ = pars_; + } + + return true; +} + +void +MTDParametersFromDD::putOne( int subdet, std::vector & vpars, PMTDParameters& ptp ) +{ + PMTDParameters::Item item; + item.id_ = subdet; + item.vpars_ = vpars; + ptp.vitems_.emplace_back( item ); +} diff --git a/Geometry/MTDGeometryBuilder/src/MTDTopologyBuilder.cc b/Geometry/MTDGeometryBuilder/src/MTDTopologyBuilder.cc new file mode 100644 index 0000000000000..2b36d97ef264b --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/MTDTopologyBuilder.cc @@ -0,0 +1,38 @@ +// Make the change for "big" pixels. 3/06 d.k. +#include "Geometry/MTDGeometryBuilder/interface/MTDTopologyBuilder.h" +#include "Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h" +#include "DataFormats/GeometrySurface/interface/Bounds.h" + +MTDTopologyBuilder::MTDTopologyBuilder( void ) +{} + +PixelTopology* +MTDTopologyBuilder::build( const Bounds* bs, + bool upgradeGeometry, + int pixelROCRows, // Num of Rows per ROC + int pixelROCCols, // Num of Cols per ROC + int BIG_PIX_PER_ROC_X, // in x direction, rows. BIG_PIX_PER_ROC_X = 0 for SLHC + int BIG_PIX_PER_ROC_Y, // in y direction, cols. BIG_PIX_PER_ROC_Y = 0 for SLHC + int pixelROCsInX, int pixelROCsInY ) +{ + float width = bs->width(); // module width = Xsize + float length = bs->length(); // module length = Ysize + + // Number of pixel rows (x) and columns (y) per module + int nrows = pixelROCRows * pixelROCsInX; + int ncols = pixelROCCols * pixelROCsInY; + + // Take into account the large edge pixles + // 1 big pixel per ROC + float pitchX = width /(nrows+pixelROCsInX*BIG_PIX_PER_ROC_X); + // 2 big pixels per ROC + float pitchY = length/(ncols+pixelROCsInY*BIG_PIX_PER_ROC_Y); + + return ( new RectangularMTDTopology( nrows, ncols, pitchX, pitchY, + upgradeGeometry, + pixelROCRows, // (int)rocRow + pixelROCCols, // (int)rocCol + BIG_PIX_PER_ROC_X, + BIG_PIX_PER_ROC_Y, + pixelROCsInX, pixelROCsInY )); // (int)rocInX, (int)rocInY +} diff --git a/Geometry/MTDGeometryBuilder/src/PlaneBuilderFromGeometricTimingDet.cc b/Geometry/MTDGeometryBuilder/src/PlaneBuilderFromGeometricTimingDet.cc new file mode 100644 index 0000000000000..28792d8dd76cc --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/PlaneBuilderFromGeometricTimingDet.cc @@ -0,0 +1,29 @@ + +#include "Geometry/MTDGeometryBuilder/interface/PlaneBuilderFromGeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" + +#include + +//#define DEBUG + +/** + given a current detector node in the DDFilteredView, + extract the global translation and rotation. + Further apply ORCA semantics for the local reference frame in which each + solid of a detector is defined, in order to get the 'correct' GlobalToLocal + transforms. + Further determine the boundaries of the current detector. + + TODO: + . The function currently only knows how to handle BarrelPixel detectors - + should also know about other det-types. Maybe several classes, one per + detector element? +*/ + +PlaneBuilderFromGeometricTimingDet::ResultType PlaneBuilderFromGeometricTimingDet::plane(const GeometricTimingDet* gd) const { + // gd->bounds() returns a pointer owned by the caller! + return ResultType( new Plane( gd->positionBounds(), gd->rotationBounds(), gd->bounds().release())); +} + + + diff --git a/Geometry/MTDGeometryBuilder/src/ProxyMTDTopology.cc b/Geometry/MTDGeometryBuilder/src/ProxyMTDTopology.cc new file mode 100644 index 0000000000000..0f7db840b3d71 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/ProxyMTDTopology.cc @@ -0,0 +1,190 @@ +#include "DataFormats/GeometrySurface/interface/BoundPlane.h" +#include "DataFormats/GeometrySurface/interface/Bounds.h" + +#include "Geometry/MTDGeometryBuilder/interface/ProxyMTDTopology.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h" + +//////////////////////////////////////////////////////////////////////////////// +ProxyMTDTopology::ProxyMTDTopology(MTDGeomDetType const * type, BoundPlane * bp) + :theType(type), theLength(bp->bounds().length()), theWidth(bp->bounds().width()) +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +LocalPoint ProxyMTDTopology::localPosition( const MeasurementPoint& mp ) const +{ + return specificTopology().localPosition(mp); +} + +//////////////////////////////////////////////////////////////////////////////// +LocalPoint ProxyMTDTopology::localPosition( const MeasurementPoint& mp, + const Topology::LocalTrackPred &trkPred ) const +{ + if (!this->surfaceDeformation()) return specificTopology().localPosition(mp); + + // add correction from SurfaceDeformation + const LocalPoint posOld(specificTopology().localPosition(mp)); // 'original position' + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(trkPred)); + + return LocalPoint(posOld.x()+corr.x(), posOld.y()+corr.y(), posOld.z()); +} + +//////////////////////////////////////////////////////////////////////////////// +LocalError ProxyMTDTopology::localError( const MeasurementPoint& mp, + const MeasurementError& me ) const +{ + return specificTopology().localError(mp, me); +} + +//////////////////////////////////////////////////////////////////////////////// +LocalError ProxyMTDTopology::localError( const MeasurementPoint& mp, + const MeasurementError& me, + const Topology::LocalTrackPred &trkPred ) const +{ + // The topology knows to calculate the cartesian error from measurement frame. + // But assuming no uncertainty on the SurfaceDeformation variables, + // the errors do not change from a simple shift to compensate + // that the track 'sees' the surface at another place than it thinks... + return specificTopology().localError(mp, me); +} + +//////////////////////////////////////////////////////////////////////////////// +MeasurementPoint ProxyMTDTopology::measurementPosition( const LocalPoint& lp ) const +{ + return specificTopology().measurementPosition(lp); +} + +//////////////////////////////////////////////////////////////////////////////// +MeasurementPoint ProxyMTDTopology::measurementPosition( const LocalPoint& lp, + const Topology::LocalTrackAngles &dir ) const +{ + if (!this->surfaceDeformation()) return specificTopology().measurementPosition(lp); + + // subtract correction from SurfaceDeformation + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(lp, dir)); + const LocalPoint posOrig(lp.x() - corr.x(), lp.y() - corr.y(), lp.z()); + + return specificTopology().measurementPosition(posOrig); +} + +//////////////////////////////////////////////////////////////////////////////// +MeasurementError ProxyMTDTopology::measurementError( const LocalPoint &lp, const LocalError &le ) const +{ + return specificTopology().measurementError(lp, le); +} + +//////////////////////////////////////////////////////////////////////////////// +MeasurementError ProxyMTDTopology::measurementError( const LocalPoint &lp, const LocalError &le, + const Topology::LocalTrackAngles &dir ) const +{ + if (!this->surfaceDeformation()) return specificTopology().measurementError(lp, le); + + // subtract correction from SurfaceDeformation + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(lp, dir)); + const LocalPoint posOrig(lp.x() - corr.x(), lp.y() - corr.y(), lp.z()); + + return specificTopology().measurementError(posOrig, le); +} + +//////////////////////////////////////////////////////////////////////////////// +int ProxyMTDTopology::channel( const LocalPoint& lp) const +{ + return specificTopology().channel(lp); +} + +//////////////////////////////////////////////////////////////////////////////// +int ProxyMTDTopology::channel( const LocalPoint &lp, const Topology::LocalTrackAngles &dir) const +{ + if (!this->surfaceDeformation()) return specificTopology().channel(lp); + + // subtract correction from SurfaceDeformation + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(lp, dir)); + const LocalPoint posOrig(lp.x() - corr.x(), lp.y() - corr.y(), lp.z()); + + return specificTopology().channel(posOrig); +} + +//////////////////////////////////////////////////////////////////////////////// +std::pair ProxyMTDTopology::pixel( const LocalPoint& lp ) const +{ + return specificTopology().pixel(lp); +} + +//////////////////////////////////////////////////////////////////////////////// +std::pair ProxyMTDTopology::pixel( const LocalPoint& lp, + const Topology::LocalTrackAngles &dir ) const +{ + if (!this->surfaceDeformation()) return specificTopology().pixel(lp); + + // subtract correction from SurfaceDeformation + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(lp, dir)); + const LocalPoint posOrig(lp.x() - corr.x(), lp.y() - corr.y(), lp.z()); + + return specificTopology().pixel(posOrig); +} + +//////////////////////////////////////////////////////////////////////////////// +float ProxyMTDTopology::localX(const float mpX) const +{ + return specificTopology().localX(mpX); +} + +//////////////////////////////////////////////////////////////////////////////// +float ProxyMTDTopology::localX(const float mpX, + const Topology::LocalTrackPred &trkPred) const +{ + if (!this->surfaceDeformation()) return specificTopology().localX(mpX); + + // add correction from SurfaceDeformation + float xOld = specificTopology().localX(mpX); // 'original position' + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(trkPred)); + + return xOld + corr.x(); +} + +//////////////////////////////////////////////////////////////////////////////// +float ProxyMTDTopology::localY(const float mpY) const +{ + return specificTopology().localY(mpY); +} + +//////////////////////////////////////////////////////////////////////////////// +float ProxyMTDTopology::localY(const float mpY, + const Topology::LocalTrackPred &trkPred) const +{ + if (!this->surfaceDeformation()) return specificTopology().localY(mpY); + + // add correction from SurfaceDeformation + float yOld = specificTopology().localY(mpY); // 'original position' + const SurfaceDeformation::Local2DVector corr(this->positionCorrection(trkPred)); + + return yOld + corr.y(); +} + + + +//////////////////////////////////////////////////////////////////////////////// +void ProxyMTDTopology::setSurfaceDeformation(const SurfaceDeformation * deformation) +{ + theSurfaceDeformation.reset(deformation); +} + +//////////////////////////////////////////////////////////////////////////////// +SurfaceDeformation::Local2DVector +ProxyMTDTopology::positionCorrection(const LocalPoint &pos, + const Topology::LocalTrackAngles &dir) const +{ + const SurfaceDeformation::Local2DPoint pos2D(pos.x(), pos.y());// change precision and dimension + + return this->surfaceDeformation()->positionCorrection(pos2D, dir, + theLength, theWidth); +} + +//////////////////////////////////////////////////////////////////////////////// +SurfaceDeformation::Local2DVector +ProxyMTDTopology::positionCorrection(const Topology::LocalTrackPred &trk) const +{ + return this->surfaceDeformation()->positionCorrection(trk.point(), trk.angles(), + theLength, theWidth); +} diff --git a/Geometry/MTDGeometryBuilder/src/RectangularMTDTopology.cc b/Geometry/MTDGeometryBuilder/src/RectangularMTDTopology.cc new file mode 100644 index 0000000000000..5e87e28b71065 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/src/RectangularMTDTopology.cc @@ -0,0 +1,348 @@ +#include "Geometry/MTDGeometryBuilder/interface/RectangularMTDTopology.h" + + /** + * Topology for rectangular pixel detector with BIG pixels. + */ +// Modified for the large pixles. +// Danek Kotlinski & Michele Pioppi, 3/06. +// See documentation in the include file. + +//-------------------------------------------------------------------- +// PixelTopology interface. +// Transform LocalPoint in cm to measurement in pitch units. +std::pair +RectangularMTDTopology::pixel( const LocalPoint& p ) const +{ + // check limits + float py = p.y(); + float px = p.x(); + + LogDebug("RectangularMTDTopology").log( [&](auto & debugstr) { +#define EPSCM 0 +#define EPS 0 + // This will catch points which are outside the active sensor area. + // In the digitizer during the early induce_signal phase non valid + // location are passed here. They are cleaned later. + debugstr << "py = " << py << ", m_yoffset = " << m_yoffset + << "px = " << px << ", m_xoffset = " << m_xoffset << "\n"; + + if( py < m_yoffset ) // m_yoffset is negative + { + debugstr << " wrong lp y " << py << " " << m_yoffset << "\n"; + py = m_yoffset + EPSCM; // make sure it is in, add an EPS in cm + } + if( py>-m_yoffset ) + { + debugstr << " wrong lp y " << py << " " << -m_yoffset << "\n"; + py = -m_yoffset - EPSCM; + } + if( px-m_xoffset ) + { + debugstr << " wrong lp x " << px << " " << -m_xoffset << "\n"; + px = -m_xoffset - EPSCM; + } + }); + + float newybin = ( py - m_yoffset ) / m_pitchy; + int iybin = int( newybin ); + float fractionY = newybin - iybin; + + // Normalize it all to 1 ROC + int iybin0 = 0; + int numROC = 0; + float mpY = 0.; + + if( m_upgradeGeometry ) + { + iybin0 = (iybin%m_COLS_PER_ROC); // 0-51 + numROC = iybin/m_COLS_PER_ROC; // 0-7 + mpY = float(numROC*m_COLS_PER_ROC + iybin0) + fractionY; + +#ifdef EDM_ML_DEBUG + + if( iybin0 > m_COLS_PER_ROC ) + { + LogDebug("RectangularMTDTopology") << " very bad, newbiny " << iybin0 << "\n" + << py << " " << m_yoffset << " " << m_pitchy << " " + << newybin << " " << iybin << " " << fractionY << " " << iybin0 << " " + << numROC; + } +#endif // EDM_ML_DEBUG + + } + else + { + iybin0 = (iybin%54); // 0-53 + numROC = iybin/54; // 0-7 + + if (iybin0==53) { // inside big pixel + iybin0=51; + fractionY = (fractionY+1.)/2.; + } else if (iybin0==52) { // inside big pixel + iybin0=51; + fractionY = fractionY/2.; + } else if (iybin0>1) { // inside normal pixel + iybin0=iybin0-1; + } else if (iybin0==1) { // inside big pixel + iybin0=0; + fractionY = (fractionY+1.)/2.; + } else if (iybin0==0) { // inside big pixel + iybin0=0; + fractionY = fractionY/2.; + } + + mpY = float(numROC*52. + iybin0) + fractionY; + } + +#ifdef EDM_ML_DEBUG + + if( mpY < 0. || mpY >= 416. ) + { + LogDebug("RectangularMTDTopology") << " bad pix y " << mpY << "\n" + << py << " " << m_yoffset << " " << m_pitchy << " " + << newybin << " " << iybin << " " << fractionY << " " + << iybin0 << " " << numROC; + } +#endif // EDM_ML_DEBUG + + // In X + float newxbin = ( px - m_xoffset ) / m_pitchx; + int ixbin = int( newxbin ); + float fractionX = newxbin - ixbin; + +#ifdef EDM_ML_DEBUG + + if( ixbin > 161 || ixbin < 0 ) // ixbin < 0 outside range + { + LogDebug("RectangularMTDTopology") << " very bad, newbinx " << ixbin << "\n" + << px << " " << m_xoffset << " " << m_pitchx << " " + << newxbin << " " << ixbin << " " << fractionX; + } +#endif // EDM_ML_DEBUG + + if( ! m_upgradeGeometry ) + { + if (ixbin>82) { // inside normal pixel, ROC 1 + ixbin=ixbin-2; + } else if (ixbin==82) { // inside bin pixel + ixbin=80; + fractionX = (fractionX+1.)/2.; + } else if (ixbin==81) { // inside big pixel + ixbin=80; + fractionX = fractionX/2.; + } else if (ixbin==80) { // inside bin pixel, ROC 0 + ixbin=79; + fractionX = (fractionX+1.)/2.; + } else if (ixbin==79) { // inside big pixel + ixbin=79; + fractionX = fractionX/2.; + } + } + + float mpX = float( ixbin ) + fractionX; + +#ifdef EDM_ML_DEBUG + + if( mpX < 0. || mpX >= 160. ) + { + LogDebug("RectangularMTDTopology") << " bad pix x " << mpX << "\n" + << px << " " << m_xoffset << " " << m_pitchx << " " + << newxbin << " " << ixbin << " " << fractionX; + } +#endif // EDM_ML_DEBUG + + return std::pair( mpX, mpY ); +} + +//---------------------------------------------------------------------- +// Topology interface, go from Masurement to Local corrdinates +// pixel coordinates (mp) -> cm (LocalPoint) +LocalPoint +RectangularMTDTopology::localPosition( const MeasurementPoint& mp ) const +{ + float mpy = mp.y(); // measurements + float mpx = mp.x(); + +#ifdef EDM_ML_DEBUG +#define EPS 0 + // check limits + std::ostringstream debugstr; + + if( mpy < 0.) + { + debugstr << " wrong mp y, fix " << mpy << " " << 0 << "\n"; + mpy = 0.; + } + if( mpy >= m_ncols) + { + debugstr << " wrong mp y, fix " << mpy << " " << m_ncols << "\n"; + mpy = float(m_ncols) - EPS; // EPS is a small number + } + if( mpx < 0.) + { + debugstr << " wrong mp x, fix " << mpx << " " << 0 << "\n"; + mpx = 0.; + } + if( mpx >= m_nrows ) + { + debugstr << " wrong mp x, fix " << mpx << " " << m_nrows << "\n"; + mpx = float(m_nrows) - EPS; // EPS is a small number + } + if(! debugstr.str().empty()) + LogDebug("RectangularMTDTopology") << debugstr.str(); +#endif // EDM_ML_DEBUG + + float lpY = localY( mpy ); + float lpX = localX( mpx ); + + // Return it as a LocalPoint + return LocalPoint( lpX, lpY ); +} + +//-------------------------------------------------------------------- +// +// measuremet to local transformation for X coordinate +// X coordinate is in the ROC row number direction +float +RectangularMTDTopology::localX( const float mpx ) const +{ + int binoffx = int( mpx ); // truncate to int + float fractionX = mpx - float(binoffx); // find the fraction + float local_pitchx = m_pitchx; // defaultpitch + + if UNLIKELY( m_upgradeGeometry ) { +#ifdef EDM_ML_DEBUG + if( binoffx > m_ROWS_PER_ROC * m_ROCS_X ) // too large + { + LogDebug("RectangularMTDTopology") << " very bad, binx " << binoffx << "\n" + << mpx << " " << binoffx << " " + << fractionX << " " << local_pitchx << " " << m_xoffset << "\n"; + } +#endif + } else { + if (binoffx>80) { // ROC 1 - handles x on edge cluster + binoffx=binoffx+2; + } else if (binoffx==80) { // ROC 1 + binoffx=binoffx+1; + local_pitchx *= 2; + } else if (binoffx==79) { // ROC 0 + binoffx=binoffx+0; + local_pitchx *= 2; + } + // else if (binoffx>=0) { // ROC 0 + // binoffx=binoffx+0; + // } + +#ifdef EDM_ML_DEBUG + if (binoffx<0) // too small + LogDebug("RectangularMTDTopology") << " very bad, binx " << binoffx << "\n" + << mpx << " " << binoffx << " " + << fractionX << " " << local_pitchx << " " << m_xoffset; +#endif + } + + // The final position in local coordinates + float lpX = float( binoffx * m_pitchx ) + fractionX * local_pitchx + m_xoffset; + +#ifdef EDM_ML_DEBUG + + if( lpX < m_xoffset || lpX > ( -m_xoffset )) + { + LogDebug("RectangularMTDTopology") << " bad lp x " << lpX << "\n" + << mpx << " " << binoffx << " " + << fractionX << " " << local_pitchx << " " << m_xoffset; + } +#endif // EDM_ML_DEBUG + + return lpX; +} + +// measuremet to local transformation for Y coordinate +// Y is in the ROC column number direction +float +RectangularMTDTopology::localY( const float mpy ) const +{ + int binoffy = int( mpy ); // truncate to int + float fractionY = mpy - float(binoffy); // find the fraction + float local_pitchy = m_pitchy; // defaultpitch + + if UNLIKELY( m_upgradeGeometry ){ + #ifdef EDM_ML_DEBUG + if( binoffy > m_ROCS_Y * m_COLS_PER_ROC ) // too large + { + LogDebug( "RectangularMTDTopology" ) << " very bad, biny " << binoffy << "\n" + << mpy << " " << binoffy << " " << fractionY + << " " << local_pitchy << " " << m_yoffset; + } +#endif + } else { // 415 is last big pixel, 416 and above do not exists! + constexpr int bigYIndeces[]{0,51,52,103,104,155,156,207,208,259,260,311,312,363,364,415,416,511}; + auto const j = std::lower_bound(std::begin(bigYIndeces),std::end(bigYIndeces),binoffy); + if (*j==binoffy) local_pitchy *= 2 ; + binoffy += (j-bigYIndeces); + } + + // The final position in local coordinates + float lpY = float(binoffy*m_pitchy) + fractionY*local_pitchy + m_yoffset; + +#ifdef EDM_ML_DEBUG + + if( lpY < m_yoffset || lpY > ( -m_yoffset )) + { + LogDebug( "RectangularMTDTopology" ) << " bad lp y " << lpY << "\n" + << mpy << " " << binoffy << " " + << fractionY << " " << local_pitchy << " " << m_yoffset; + } +#endif // EDM_ML_DEBUG + + return lpY; +} + +/////////////////////////////////////////////////////////////////// +// Get hit errors in LocalPoint coordinates (cm) +LocalError +RectangularMTDTopology::localError( const MeasurementPoint& mp, + const MeasurementError& me ) const +{ + float pitchy=m_pitchy; + int binoffy=int(mp.y()); + if( isItBigPixelInY(binoffy) )pitchy = 2.*m_pitchy; + + float pitchx=m_pitchx; + int binoffx=int(mp.x()); + if( isItBigPixelInX(binoffx) )pitchx = 2.*m_pitchx; + + return LocalError( me.uu()*float(pitchx*pitchx), 0, + me.vv()*float(pitchy*pitchy)); +} + +///////////////////////////////////////////////////////////////////// +// Get errors in pixel pitch units. +MeasurementError +RectangularMTDTopology::measurementError( const LocalPoint& lp, + const LocalError& le ) const +{ + float pitchy=m_pitchy; + float pitchx=m_pitchx; + + if LIKELY( !m_upgradeGeometry ) { + int iybin = int( (lp.y() - m_yoffset)/m_pitchy ); //get bin for equal picth + int iybin0 = iybin%54; //This is just to avoid many ifs by using the periodicy + //quasi bins 0,1,52,53 fall into larger pixels + if( (iybin0<=1) | (iybin0>=52) ) + pitchy = 2.f * m_pitchy; + + int ixbin = int( (lp.x() - m_xoffset)/m_pitchx ); //get bin for equal pitch + //quasi bins 79,80,81,82 fall into the 2 larger pixels + if( (ixbin>=79) & (ixbin<=82) ) pitchx = 2.f * m_pitchx; + } + + return MeasurementError( le.xx()/float(pitchx*pitchx), 0, + le.yy()/float(pitchy*pitchy)); +} + diff --git a/Geometry/MTDGeometryBuilder/test/BuildFile.xml b/Geometry/MTDGeometryBuilder/test/BuildFile.xml new file mode 100644 index 0000000000000..7dc24175279dd --- /dev/null +++ b/Geometry/MTDGeometryBuilder/test/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Geometry/MTDGeometryBuilder/test/MTDDigiGeometryAnalyzer.cc b/Geometry/MTDGeometryBuilder/test/MTDDigiGeometryAnalyzer.cc new file mode 100644 index 0000000000000..918c684abe38f --- /dev/null +++ b/Geometry/MTDGeometryBuilder/test/MTDDigiGeometryAnalyzer.cc @@ -0,0 +1,221 @@ +// -*- C++ -*- +// +// Package: MTDDigiGeometryAnalyzer +// Class: MTDDigiGeometryAnalyzer +// +/**\class MTDDigiGeometryAnalyzer MTDDigiGeometryAnalyzer.cc + + Description: + + Implementation: + +*/ +// +// Original Author: Filippo Ambroglini +// Created: Tue Jul 26 08:47:57 CEST 2005 +// +// + + +// system include files +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeometry.h" +#include "Geometry/Records/interface/MTDDigiGeometryRecord.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/CommonTopologies/interface/PixelTopology.h" +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetType.h" + +#include "Geometry/MTDGeometryBuilder/interface/MTDGeomDetUnit.h" +#include "DataFormats/GeometrySurface/interface/BoundSurface.h" +#include "DataFormats/GeometrySurface/interface/MediumProperties.h" +#include "DataFormats/GeometrySurface/interface/TrapezoidalPlaneBounds.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +// +// +// class decleration +// + + +// #define PRINT(X) edm::LogInfo(X) +#define PRINT(X) std::cout << X << ": " + +class MTDDigiGeometryAnalyzer : public edm::one::EDAnalyzer<> +{ +public: + explicit MTDDigiGeometryAnalyzer( const edm::ParameterSet& ); + ~MTDDigiGeometryAnalyzer() override; + + void beginJob() override {} + void analyze(edm::Event const& iEvent, edm::EventSetup const&) override; + void endJob() override {} + +private: + void analyseTrapezoidal( const GeomDetUnit& det); + void checkRotation( const GeomDetUnit& det); + std::ostream& cylindrical( std::ostream& os, const GlobalPoint& gp) const; +}; + +MTDDigiGeometryAnalyzer::MTDDigiGeometryAnalyzer( const edm::ParameterSet& iConfig ) +{} + +MTDDigiGeometryAnalyzer::~MTDDigiGeometryAnalyzer() +{} + +// ------------ method called to produce the data ------------ +void +MTDDigiGeometryAnalyzer::analyze( const edm::Event& iEvent, const edm::EventSetup& iSetup ) +{ + + PRINT("MTDDigiGeometryAnalyzer")<< "Here I am" << std::endl; + // + // get the TrackerGeom + // + edm::ESHandle pDD; + iSetup.get().get( pDD ); + PRINT("MTDDigiGeometryAnalyzer")<< " Geometry node for MTDGeom is "<<&(*pDD) << std::endl; + PRINT("MTDDigiGeometryAnalyzer")<<" I have "<detUnits().size() <<" detectors"<detTypes().size() <<" types"<detUnits()){ + if(dynamic_cast((it))!=nullptr){ + const BoundPlane& p = (dynamic_cast((it)))->specificSurface(); + PRINT("MTDDigiGeometryAnalyzer") << it->geographicalId() + <<" RadLeng Pixel "<detTypes() ){ + if (dynamic_cast((it))!=nullptr){ + const PixelTopology& p = (dynamic_cast((it)))->specificTopology(); + PRINT("MTDDigiGeometryAnalyzer")<<" PIXEL Det " // << it->geographicalId() + <<" Rows "<(&bounds); + if (tb == nullptr) return; // not trapezoidal + + const GlobalPoint& pos = det.position(); + double length = tb->length(); + double width = tb->width(); + + const std::array & par = tb->parameters(); + double top = std::max(par[1], par[0]); + double bot = std::min(par[1], par[0]); + + std::cout << std::endl; + std::cout << "Det at pos " << pos << " has length " << length + << " width " << width << " pars "; + for (int i = 0; i<4; i++) std::cout << par[i] << ", "; + std::cout << std::endl; + + std::cout << "det center inside bounds? " << tb->inside( det.surface().toLocal(pos)) << std::endl; + + // double outerScale = (pos.perp()+safety*length/2.) / pos.perp(); + // GlobalPoint outerMiddle = GlobalPoint( outerScale*pos.x(), outerScale*pos.y(), pos.z()); + + GlobalVector yShift = det.surface().toGlobal( LocalVector( 0, safety*length/2., 0)); + GlobalPoint outerMiddle = pos + yShift; + GlobalPoint innerMiddle = pos + (-1.*yShift); + if (outerMiddle.perp() < innerMiddle.perp()) std::swap( outerMiddle, innerMiddle); + + GlobalVector upperShift = det.surface().toGlobal( LocalVector( safety*top, 0, 0)); + + GlobalPoint ulc = outerMiddle+upperShift; + GlobalPoint urc = outerMiddle+(-1.*upperShift); + std::cout << "outerMiddle " << outerMiddle + << " upperShift " << upperShift + << " ulc " + << "(" << ulc.perp() + << "," << ulc.phi() + << "," << ulc.z() + << " urc " + << "(" << urc.perp() + << "," << urc.phi() + << "," << urc.z() + << std::endl; + + std::cout << "upper corners inside bounds? " + << tb->inside( det.surface().toLocal( ulc)) << " " + << tb->inside( det.surface().toLocal( urc)) << std::endl; + + // double innerScale = (pos.perp()-safety*length/2.) / pos.perp(); + // GlobalPoint innerMiddle = GlobalPoint( innerScale*pos.x(), innerScale*pos.y(), pos.z()); + + GlobalVector lowerShift = det.surface().toGlobal( LocalVector( safety*bot, 0, 0)); + + std::cout << "lower corners inside bounds? " + << tb->inside( det.surface().toLocal( innerMiddle+lowerShift)) << " " + << tb->inside( det.surface().toLocal( innerMiddle+(-1.*lowerShift))) << std::endl; + +} + + +void MTDDigiGeometryAnalyzer::checkRotation( const GeomDetUnit& det) +{ + + const double eps = std::numeric_limits::epsilon(); + static int first = 0; + if (first == 0) { + std::cout << "numeric_limits::epsilon() " << std::numeric_limits::epsilon() << std::endl; + first =1; + } + + const Surface::RotationType& rot( det.surface().rotation()); + GlobalVector a( rot.xx(), rot.xy(), rot.xz()); + GlobalVector b( rot.yx(), rot.yy(), rot.yz()); + GlobalVector c( rot.zx(), rot.zy(), rot.zz()); + GlobalVector cref = a.cross(b); + GlobalVector aref = b.cross(c); + GlobalVector bref = c.cross(a); + if ((a-aref).mag() > eps || (b-bref).mag() > eps || (c-cref).mag() > eps) { + std::cout << " Rotation not good by cross product: " + << (a-aref).mag() << ", " + << (b-bref).mag() << ", " + << (c-cref).mag() + << " for det at pos " << det.surface().position() << std::endl; + + } + if ( fabs(a.mag() - 1.) > eps || fabs(b.mag() - 1.) > eps || fabs(c.mag() - 1.) > eps ) { + std::cout << " Rotation not good by bector mag: " + << (a).mag() << ", " + << (b).mag() << ", " + << (c).mag() + << " for det at pos " << det.surface().position() << std::endl; + } + +} + +std::ostream& MTDDigiGeometryAnalyzer::cylindrical( std::ostream& os, + const GlobalPoint& gp) const +{ + os << "(" << gp.perp() + << "," << gp.phi() + << "," << gp.z(); + return os; +} + + + +//define this as a plug-in +DEFINE_FWK_MODULE(MTDDigiGeometryAnalyzer); diff --git a/Geometry/MTDGeometryBuilder/test/mtd_cfg.py b/Geometry/MTDGeometryBuilder/test/mtd_cfg.py new file mode 100644 index 0000000000000..2b806be23bf15 --- /dev/null +++ b/Geometry/MTDGeometryBuilder/test/mtd_cfg.py @@ -0,0 +1,37 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("GeometryTest") +# empty input service, fire 10 events +process.load("FWCore.MessageLogger.MessageLogger_cfi") + +# Choose Tracker Geometry +process.load("Configuration.Geometry.GeometryExtended2023D24_cff") + +process.load("Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi") + +process.load("Geometry.MTDNumberingBuilder.mtdTopology_cfi") +process.load("Geometry.MTDGeometryBuilder.mtdGeometry_cfi") +process.load("Geometry.MTDGeometryBuilder.mtdParameters_cfi") +process.mtdGeometry.applyAlignment = cms.bool(False) + +process.Timing = cms.Service("Timing") + +process.source = cms.Source("EmptyIOVSource", + lastValue = cms.uint64(1), + timetype = cms.string('runnumber'), + firstValue = cms.uint64(1), + interval = cms.uint64(1) + ) + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(1) +) + +process.myprint = cms.OutputModule("AsciiOutputModule") + +process.prod = cms.EDAnalyzer("MTDDigiGeometryAnalyzer") + +process.p1 = cms.Path(process.prod) + +process.e1 = cms.EndPath(process.myprint) + diff --git a/Geometry/MTDNumberingBuilder/BuildFile.xml b/Geometry/MTDNumberingBuilder/BuildFile.xml new file mode 100644 index 0000000000000..72a1276677a95 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/BuildFile.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Geometry/MTDNumberingBuilder/bin/BuildFile.xml b/Geometry/MTDNumberingBuilder/bin/BuildFile.xml new file mode 100644 index 0000000000000..02ddd70b993e6 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/bin/BuildFile.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.cc b/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.cc new file mode 100644 index 0000000000000..f9f45d6a24dc9 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.cc @@ -0,0 +1,217 @@ +#include "GeometricTimingDetLoader.h" + +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Framework/interface/Event.h" +#include "CondCore/DBOutputService/interface/PoolDBOutputService.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" + +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include +#include + +#include "Geometry/Records/interface/MTDGeometryRecord.h" + +#include +#include +#include + +// just a reminder to self... beware errors caused by levels. Look +// at how tracker is built and how GeometricSearchTracker.h is built +// up from the hierarchy. + +GeometricTimingDetLoader::GeometricTimingDetLoader(const edm::ParameterSet& iConfig) +{ + LogDebug("GeometricTimingDetLoader") + <<"GeometricTimingDetLoader::GeometricTimingDetLoader"< mydbservice; + if( !mydbservice.isAvailable() ){ + std::cout<<"PoolDBOutputService unavailable"< pDD; + edm::ESHandle rDD; + es.get().get( pDD ); + es.get().get( rDD ); + const GeometricTimingDet* tracker = &(*rDD); + + // so now I have the tracker itself. loop over all its components to store them. + putOne(tracker, pgd, 0); + std::vector tc = tracker->components(); + std::cout <<"Tracker has " << tc.size() << " components." << std::endl; //, lets go through them." << std::endl; + std::vector::const_iterator git = tc.begin(); + std::vector::const_iterator egit = tc.end(); + int count=0; + int lev = 1; + for (; git!= egit; ++git) { // one level below "tracker" + putOne(*git, pgd, lev); + std::vector inone = (*git)->components(); + // << ctste.name((*git)->type()) + // std::cout << lev << " type " << (*git)->type() << " " << int((*git)->geographicalId()) << std::endl; // << " has " << inone.size() << " components." << std::endl; + if ( inone.empty() ) ++count; + std::vector::const_iterator git2 = inone.begin(); + std::vector::const_iterator egit2 = inone.end(); + ++lev; + for (; git2 != egit2; ++git2) { // level 2 + putOne(*git2, pgd, lev); + std::vector intwo= (*git2)->components(); + // std::cout << lev << "\ttype " << (*git2)->type() << " " << int((*git2)->geographicalId()) << std::endl; // << " has " << intwo.size() << " components." << std::endl; + if ( intwo.empty() ) ++count; + std::vector::const_iterator git3 = intwo.begin(); + std::vector::const_iterator egit3 = intwo.end(); + ++lev; + for (; git3 != egit3; ++git3) { // level 3 + putOne(*git3, pgd, lev); + std::vector inthree= (*git3)->components(); + // std::cout << lev << "\t\ttype " << (*git3)->type() << " " << int((*git3)->geographicalId()) << std::endl; // << " has " << inthree.size() << " components." << std::endl; + if ( inthree.empty() ) ++count; + std::vector::const_iterator git4 = inthree.begin(); + std::vector::const_iterator egit4 = inthree.end(); + ++lev; + for (; git4 != egit4; ++git4) { //level 4 + putOne(*git4, pgd, lev); + std::vector infour= (*git4)->components(); + // std::cout << lev << "\t\t\ttype " << (*git4)->type() << " " << int((*git4)->geographicalId()) << std::endl; // << " has " << infour.size() << " components." << std::endl; + if ( infour.empty() ) ++count; + std::vector::const_iterator git5 = infour.begin(); + std::vector::const_iterator egit5 = infour.end(); + ++lev; + for (; git5 != egit5; ++git5) { // level 5 + putOne(*git5, pgd, lev); + std::vector infive= (*git5)->components(); + // std::cout << lev << "\t\t\t\ttype " << (*git5)->type() << " " << int((*git5)->geographicalId()) << std::endl; // << " has " << infive.size() << " components." << std::endl; + if ( infive.empty() ) ++count; + std::vector::const_iterator git6 = infive.begin(); + std::vector::const_iterator egit6 = infive.end(); + ++lev; + for (; git6 != egit6; ++git6) { //level 6 + putOne(*git6, pgd, lev); + std::vector insix= (*git6)->components(); + // std::cout << lev << "\t\t\t\t\ttype " << (*git6)->type() << " " << int((*git6)->geographicalId()) << std::endl; // << " has " << insix.size() << " components." << std::endl; + if ( insix.empty() ) ++count; + } // level 6 + --lev; + } // level 5 + --lev; + } // level 4 + --lev; + } //level 3 + --lev; + } // level 2 + --lev; + } + std::vector modules = tracker->deepComponents(); + std::cout << " No. of Tracker components \"deepComponents\" = " << modules.size() << std::endl; + std::cout << " Counted # of lowest \"leaves\" = " << count << std::endl; + if ( mydbservice->isNewTagRequest("PGeometricTimingDetRcd") ) { + mydbservice->createNewIOV( pgd + , mydbservice->beginOfTime() + , mydbservice->endOfTime() + , "PGeometricTimingDetRcd"); + } else { + std::cout << "PGeometricTimingDetRcd Tag is already present." << std::endl; + } +} + +void GeometricTimingDetLoader::putOne ( const GeometricTimingDet* gd, PGeometricTimingDet* pgd, int lev ) { + +// std::cout << "putting name: " << gd->name().name(); +// std::cout << " gid: " << gd->geographicalID(); +// std::cout << " type: " << gd->type() << std::endl; +// std::cout << "shape = " << gd->shape()<<"; name = "<name().name()<<"; parameter number = "<params().size()<translation(); + const DDRotationMatrix& rot = gd->rotation(); + DD3Vector x, y, z; + rot.GetComponents(x, y, z); + item.name_ = gd->name().name(); + item.level_ = lev; + item.x_ = tran.X(); + item.y_ = tran.Y(); + item.z_ = tran.Z(); + item.phi_ = gd->phi(); + item.rho_ = gd->rho(); + item.a11_ = x.X(); + item.a12_ = y.X(); + item.a13_ = z.X(); + item.a21_ = x.Y(); + item.a22_ = y.Y(); + item.a23_ = z.Y(); + item.a31_ = x.Z(); + item.a32_ = y.Z(); + item.a33_ = z.Z(); + item.shape_ = static_cast(gd->shape()); + item.type_ = gd->type(); + if(gd->shape()==DDSolidShape::ddbox){ + item.params_0=gd->params()[0]; + item.params_1=gd->params()[1]; + item.params_2=gd->params()[2]; + item.params_3=0; + item.params_4=0; + item.params_5=0; + item.params_6=0; + item.params_7=0; + item.params_8=0; + item.params_9=0; + item.params_10=0; + }else if(gd->shape()==DDSolidShape::ddtrap){ + item.params_0=gd->params()[0]; + item.params_1=gd->params()[1]; + item.params_2=gd->params()[2]; + item.params_3=gd->params()[3]; + item.params_4=gd->params()[4]; + item.params_5=gd->params()[5]; + item.params_6=gd->params()[6]; + item.params_7=gd->params()[7]; + item.params_8=gd->params()[8]; + item.params_9=gd->params()[9]; + item.params_10=gd->params()[10]; + }else{ + item.params_0=0; + item.params_1=0; + item.params_2=0; + item.params_3=0; + item.params_4=0; + item.params_5=0; + item.params_6=0; + item.params_7=0; + item.params_8=0; + item.params_9=0; + item.params_10=0; + } + item.geographicalID_ = gd->geographicalID(); + // FIXME: These are moved to PGeometricTimingDetExtra: + //item.volume_ = gd->volume(); + //item.density_ = gd->density(); + //item.weight_ = gd->weight(); + //item.copy_ = gd->copyno(); + //item.material_ = gd->material(); + item.radLength_ = gd->radLength(); + item.xi_ = gd->xi(); + item.pixROCRows_ = gd->pixROCRows(); + item.pixROCCols_ = gd->pixROCCols(); + item.pixROCx_ = gd->pixROCx(); + item.pixROCy_ = gd->pixROCy(); + item.stereo_ = gd->stereo(); + item.siliconAPVNum_ = gd->siliconAPVNum(); + pgd->pgeomdets_.push_back ( item ); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(GeometricTimingDetLoader); diff --git a/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.h b/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.h new file mode 100644 index 0000000000000..c6dc9c6a3713b --- /dev/null +++ b/Geometry/MTDNumberingBuilder/bin/stubs/GeometricTimingDetLoader.h @@ -0,0 +1,30 @@ +#ifndef MTDNumberingBuilder_GeometricTimingDetLoader_h +#define MTDNumberingBuilder_GeometricTimingDetLoader_h + +#include "FWCore/Framework/interface/one/EDAnalyzer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include + +class GeometricTimingDet; +class PGeometricTimingDet; + +class GeometricTimingDetLoader : public edm::one::EDAnalyzer { + + public: + explicit GeometricTimingDetLoader( const edm::ParameterSet& iConfig ); + ~GeometricTimingDetLoader() override; + + void beginJob() override {} + void beginRun(edm::Run const& iEvent, edm::EventSetup const&) override; + void analyze(edm::Event const& iEvent, edm::EventSetup const&) override {} + void endRun(edm::Run const& iEvent, edm::EventSetup const&) override {} + void endJob() override {} + + private: + void putOne ( const GeometricTimingDet* gd, PGeometricTimingDet* pgd, int lev ); +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/doc/GeometricDetBuilder.png b/Geometry/MTDNumberingBuilder/doc/GeometricDetBuilder.png new file mode 100644 index 0000000000000000000000000000000000000000..9a673f54261e0beb3c7e512310940576fd2528dd GIT binary patch literal 153228 zcmagG1z43^+cmoAl28#82@yq*ly0O^q(n(6QBt}aB^3dc66uhTl|5EC*BH=qkc8WTVC=|Id@(U|lGRp$K zN#JxxS&m@p4CR^g#EPOlI4IN=)E!x=2X3P)6RvJi4@dv}UXLoh({~N`1?9_&ijn6; zLi_^KN~!J7YCTf>Tt7A1^{LQ%xJ-?`=HvlY4NFMlt1Gf+Wk^zS6&VB6q_G)Ezm17C zNG5f2N5&C7zxF=h&{5y#so&Npqe}Ady$N8Ukm;SFW32$uY z=L#F53fpVGF(2W)XP>z8pPyRgz0HNXKc{bTzV|Nmf8Je|_Z{on|IY%=uWx_DgP)<9 zjZ~GG{@g|%8BQ^CwQhetzB^G=OXPnZ@`HlBJbsC3&&*o|`nSClX>Wh{99r}6@MJK- z0{*Tr&3*sya3EcQe36imbH?oJ6P`N?un=>~4ypgyu>b$PGatb6kjHmgFZfYVPvf!k z!gK9;b92{Z%&4w*`AW0(>+m22hQN34lyVDMtoz2?pA0($cq~IT?%Qv;Z-I#FQE!6)k z?cMVWz46^_!Ehlv;@^Wl`aHTK@vE%NZadqfAqDlroxr9N%fWGaXLvfd5R)@^xYyD` zo-0)lOMNd6o00L&yR@Ot*6}psJ{!+H95w6Hq)9skZ34`aAL7g|7Y1h~YchB)=aW=? zH}Y#&+xY)Nk*Bess*Dis$aw8%*yw>>bB2q|4PNLMCsQwe|l({a=6(w zwM=rJxzTeyr_cAaZgz9FttCZjiPUI>yS+E)M_peHpwVJ_A6bV%})6)4HpH3^*{?}T_=!}Lr+xqZu6B-O3ok>cv zG&-{swcfAhjO*2cuU&PH-W?Yk$N1P|VUCS$@a!|*F!{t8pIe`D2X9xq+WwiNZfnbd z9hjNHs5|jm*F6b*cWx{cpPt@QKm0(Ekg?#&;qIyl{6d|f7kj^4P*b3@H1XMlKv-Cq zEO{A|bKbvO%PT&mv@|N&_arVyBTFDBX>?R~C{M@nr0cms-$O0^R_9^;VEJ?lr^~NG zL-%)v4dZ@J5pQHF$A`RreN9M6TfzyVR@RfG|FTv875)W}wMYCR-oNGST!Z%}wfu(` zlC`p49q#8yRhDc%e;&R(yokx!q`q%Z5FSoWo2|m;>XOi|i0oYGOZBXuk|&iOpRWjL zCKB8Ftin#W2D@)z7PJb3PLAhrxB@7Kp3kj(FF{sO_515(EVrZIZB@s+WA3NNdt4Xa z8?;wU`g9dGoDesn(-qL>d``TFTffgNIO$d5^#_7G zgpL1pvV=aJ_1b^}9siK!;NlNFJZ^U$cEf`CCz8jdB0J+c`_)YsM6s|e8^xZ4eCV?| z{3u7d!cPOIx}yDOCNyYlZq-^Zxx~T8$I@rt56kk{pCET&H`!a$dv(2`rLf`C^IC(# z`TV|QE(SNo0B*e^BP<;q9a>=rTth=c6x6AU+(syWe9{>%-+iUXCEu+cL5{uC&De&N z;pP2b=@Gil$zH!(skavg2>gzYywcLsb;_Sz+7s0!D(mGRek9}UT;`SXpGR3ABq=VY zl@#=;_23;a$DlV~5jz_TY+-C9C7rR#YsH+Sowq0*%;uJdt&Zu~uFKIe7EXQ*k{?Q> z%kuFijXoT1z_eLf^{KiFHfUz~e^eS=$o+)bavoBUCba)3>^Og>D~4ls*wD8OcL9}} zn#!(M{<^X8c5z9G`^?K5Az@*2VS+yzCngdFf4KQGDTEiBJ6KN@yj0626z1jlJGvko2iVTVED+$@4M_q>z4et5mD= zWp&Nig1!|W1*MaOP=nfjkeeHyVGZrzLS90XQGBSuX&Ju1wH>re>~rVOLli^mj;vMP ziDbU@q@AL(v-8hA~fpTyw`-k6%MZs+D)*Y`3j>OS#3S_uh>dr4w(HS6{9`Fa(bdkv?F zX35?$b)I|oA3f^+g-%}_tKe!l-o0Eg?mz->6%`YsyL31!gkr8dv?)Obx4M);aQdq%cbl8~1?bvSuP{C*J zroU3CI?{@Ygs$WE1d#qBr$-BtM8w38*T$>ZA634Y znRyJgxa~O(!9`IQ_DQd;9=v7#+=2qr-!rXHBEr(rt_~F%_Jy2fLWP8cq{sx5(Tcjf zE-mG&t*diC*j(ywwhT=ZGE)f%~Q%LoXsIrTezg-;V_#py@!{Uq zh)IO~pAF+`=jE?ejtgp(fv~Ley0*Cy76X~cKPcT!h>VmmHfDrpeEs?i6r5ippVKF- zmKcUdXIeu!gnzwCL*9qmtd~~FZbDljg8n1?iaD*RtkfR$&9OcYU7-M1cM%(oP3yz^ z_ZN?jk9Eo{qbD3A#5O~Eu~6Q9c^d(Q0oV zt%64#$ZlV@t(9_d5vXxpFaOy_KtK?goNT)_3g`R*ejHU~Jti>U9oLc|?8qH=?_!ud z{+Wxn4GfazVm^H6Yz`z@4Ifh*3nIPzb-E=OZCMtB_9%J0Tqn9rbmq)8F0Q`$&&|!! zex?@j5LRe|vf{Jb+EcvlTB8BR03$;Lx>{QUsSVtoD=>IRO-&hn4ZEyhZOy^pwSmQ^ znP;>$-xF4_JR2cty7=wmvx(~HdhbIX_su6Y2`gU}RaLX}Dr_G49`Bg*(F_&ncfCA+ zBm2{*$J@WqVz713ChHTM{0Smql@qR$JxhbRSR228PnQiFF!Aub3nZcDab9{r@40fz z=VagPYdD<}9ELvu`8*_k`7_o9MIRrDER{rTjNA%>Tpyd55Rs9|t5XWt{^)Lh%Y>wT zM{lo-ZeJ9uhTC)?wc@>d8NR0{N81CcF|^yiXWI<#k0CgXsGqB*sQT~I7gMoo--f3{ zvgpEv3lAPXM3-4LX%^M0xT*o_OIXzJQo_599 zua*tZtgiM9Y8m!a+RrMgsLT)P**=AhK?)QEse_}VJH-00(X!mR9RmY{qr=Hl)6r6k zamYu=*VE~6(X~c%K8Ga?Yo=;)@A2NGs)tAQfWUj4Ct>n3w{N2&nU!adR$u<8Lr56>wf$}2w$;;hcSWZqZM(iZ!nV!|oxMQC& zPn_G%pw?V$2!IBXcXBhZf=B35-TW5R=3{t`@2g5apCQ_{^Z}__TmRY*&0l|f=?s1_ zHCX~6lg5?~iHx2Jr1GWddvU$}KQr5jTfQZ(w|LQmACUsnQbqwz{_tqtc59{%C} z&n60s37VU{1JEB~918en_A{68KG-%sKG+f4!DxKD%&WmT0i_r;Cv?b4%MXr?$^C9E2miZ|e8%qhdtSngU`be}V-N0yw`NcW8t%Dc`( zP0h_#YQqhPptlJLXZ%#MOaPo+yLL^@z#u#{l!Q6*CBW30;mc?60oov4%KLElqhW)O zti1fp{5*3a8?qPJJTH);v(y3LF1v1NNQC6c``TJD6qKSkNneS*NngpPrlu!PpWcF0 zgI;Uz=r|j#Wx&YC7X_L2?*04r-PN&pc{OByR4@gpW_k`D77II zaBSS`lu)IsOfWm6H}7j`xWle#*Lw*^M@OTOR6%M76j?|PYmNGhi~v9eTM*spXmd9J zKyL8U{g#9L#w8^sckbOQt(yD!Q%I~_*gPU62#7Of0&pfiTt3zCb`WJWvV0sN)H_vzWJ&-l&ij7iK{LkjpbglL?UG9^y1=T zk(aS?>eHwRFQq$on$W{IfF`dpFCAYWnT{LDPyTF7Q$L(UPyiGG7A~$EA|f9KbF~CL_glHr(GV*(a zujIpr4_%(t)z%V{kd(YG-dmqchQ*FgOw1`?fS82|8i`ZcF?9oj-e3lwb^s$?P^z)| zmv_cp#;nCQ+nE5xF1%a*QSU7}kf}V2$fG>%OP)qVbFC zvdYS&78VvU>bnqN#n8Dnx3=hF3L7p?K#Bd;pX%>*5dtG4+bwBhNChq<~1sW~}z!}>)g1W%qywS|*bsH%_AuU2;|L6I;ckiNpjaTtPCI~sscQ>`QWqps(0Z<4DuT$l49ksR4 zw*ZjX;`8|LgHZJ9Xjv#cg+8~rAeSQb*|Urclo0P)%pWi4ivt&S zS2el{^s-{;#C4}bxq64~4_AqEwb-1NGv7oG{1J$Wx%ubdCauIu?TPyqbbsO$)Ln>@XvhXuNKXzQugH#!qvLg7Ek2qsY!<*14|L>2spvJ+a=vc82bg+M_%*?d<-F!h`X{ z^<1g^j*KF&Di2B4JB;l2@=v=j?Kn3aJst}WCGEc;XFS3k7|oVAoE(?apB_xpEy`A6 z6)SC?ec8J1`o}GB!!FRI4I{9-oV77|nzWugn0sM&Jr<$wbcI*|Y?kpn z8{v*eIYBY)1jKRrCdF}obM94>ks9jy&6{^Sy1S2B4zjYd6~7lh4OQ+h7+9pmU;Xjp zM`w|7OB6sgR+z>flt25P_Ta&T_TYOk_}8S_mdKp$@7r~8So%~np=5#@9s8PMIF|U< z)zdK!{sb~ECbiJ=&WTEjZ1|>P?O;;laXMdf?;eGt=a6xv!Dc+u$;Iv+~ephaVwU zG?vY}{d|s%zFmuxxEesgkpUHRmx#Sf3rjErjtItHfianlRD?e)o1a;ve|mw11D zFS!wUL)G;3x<#?KVduyZsM5YfyL+N5)hH6kJmPoW6+`Wsr zJ<;7FlTVI88Nwcyu-&}*c)B^z3#PuGKYwDN<4z$^?Br-aKwxKGkryBg`B;Um*%BrP zdL+f=%Uum8J6wQ@w}LBr1_z@vum?Z|*~=Vy$fTwM44E zNM`6xA_dxTyvh=FG!t6>{IvBZmzF{s0a-w9VUUzR?J&cooN}Us*q1M#lS}xuF=#1t zo0v=wY7NGrh6?qo&dv8|bmbY4`c8#}L7O%MhT{n4_Meic`{WC~i8u(->z5(_J>^ec z-Z{m6?OMR3&taJ7T2(M)W&*U-V%K#8q_jDS=r11>rwxzctr|64)R&gVMn-#p!9bV< zlvxeyb`BXz)dTzu2nc8o)`CaF{pI_9abPfKx}!twK}Pr!Gt=fgoxcPnZ^z?;ctCp3?aoKO~*s@gO96zQ1L>Wx9`nR>v#swsGb3Pn#q%$iqZ{ zJvC}oIEPkXnA;t*wcXLkpO~1~2b})$_3NK;W=Y1-XlO;8LZIE#7#dD$PM$I{GQxv! zcign@5-}IFJ&t+zPFh8U%xbuxjA-=u_}E&0^l)!o6$+i+GiOhz*fY|j^8!}N>iVQ+ zeV?9}@Na3FpPVdYMd3VnkX^OJ!Ota?DQPG*mnpR1_ouJPX!t@9svzE`I!77bZPI&>&h>};4H)kMffak~SQgYD zEV=ylfjPo{su3$5y^Fy-xHnHJ#0H#$teo8UXU9|*E(GT0=6Y>FcLu^;_Xg5hwLZW! zUk_LuK*twApo5ZWG^BzPPUlr6_A`2<&8!Du#Ck90&eImb&<5eLS~1DfS^LXUR09YL z_$T)CmH9@PE1L`Q(p!HW>?{X2dE`^W79d&#Ry9Of9$?dx$FHS=zY;JBMObjykw0CvkU=rr`w-y{>yU?Fa+FU%> zpb5d8ARZHqUg(K$^IWeBHYjYEksyF+9yo|@(*FR$y`quS-dL$nGEGcZRt@%D-N zcRYDKUTN=jyfgfVf9nIY^~2)}KLM+8@Uqk5ti(}%<0A5IBH&I4!Le|cD= z#3`qi&DyWcpWIzSV_yAL|NQk}(Qqy?`hGe$2TCF_oCcqDOEG$@oPJ7bx zfj=NHu!Eo(L=Wlsx4S`9>03KH*LirpnU>Z8X_RjhDvBTqJHOs{*OxSn(smBFH7aGk z{)M^N+iX(z@1KJzJr8s&E-o&#{7D{$?X zr{PrTVQU+wT>VEhm!zm;p9AV2 z`gxaLN-#Gs?UH}=c6oUW#C^Q=WV!96jZR8YJ#vV<`Xd zSZw$3*`K4%A~_(kubOb^;xI4Mg}uB2FAb*wAF|7L4K>D{#-4t#ROBTbLS9B4TkPwv3c`b z)lpHD!BREJ$qZ-Do)t)61&%OAT@2|Ff3?BY)-Ny5@559R2e}zc&R_~)*6VP!0#+w4 zk`)L_+SpuKvZ!k~^kdkL-StUTn6!WY{{5w`O|R3#-Tf>Tm1)VU-o1Ng*4Ea(Rlyb@ z*-FSbnwFi-(luirFKBCe^yhc&&X8Vr?9LNTQDDPrQtCc^dbPdn1d)YwwEOoT?>9hT zP*YQT?5^s;~*q~K?##rr^cGy)3)TdE0@{ouP{ z3D4bUC`c(qC8d%}7LyPVFsHk)wfi4Gb^^XV4YK^dR;O!qAw7mWX4&P2EmByZnuRM(-~ShoSci+q$|))G8En^71m$ z(y-yF0q8)%4J+sx9K4XPsidqN_E9CWLl%+|>PgR#>6U%BH3{&T+1c4Ty)D%?%k>s( zTiL#3Y1S8kr-n@cst>5|FR_L`9X*1R?1=+pFLq1J`igx|eV~K`BN`lvcK7r=Pe*56 zvNPs~g=6RF7}E$;!y*1PN~%HEI(P z?*l$y7NN94xBnqOJO~s7fbjO-UQblmm_}pT+ZE59JNN#U34X)TCJBr;b3h@@!6`=dTFiQRd#_R< z3B$<2(POh*0n~9#$^`nc6JV|uBW}e7Vn*3`(tiC%7(Lm517ATww^e@aVqA$+T3v_V z?^0z3QO5_%sns+?`TkLqf7V17tTEjmmA$=vlQ~}+%d6|}U7VfevIeG?mtoQ;g5w8VdmkX5wY9Z> zTh-F1Tp|0JFL-?|Xkmm}1|I!puS_Y&eCsT|&mUtbX5vX6ORQuJ65U8of;R1>COR`W z_mrqSkwZQfn2{fKp0JiOz1J#P14!;(db&Q@API^IBR9922tX_>kN8v;wFgcor-oiw z>$T}W_I86@Cj+13463idNZWoIpFldvQ>hC_zW>cDwF&krS)e?xpQzg7eJT)HLVLPwy|xW!(-5%|M%@ zoDZ^^jEsQe`Ez&(k=+9w^d+cL{i!lgV(pIp*aKe#EKteiR2SIZzCLoGBlp%O06D|_ z91KchWL(@GBcm(E#>Pm4K`0+A9DHElZ-cA>)ZPU=JiLsotO3BJ_z?p+8aKXu`?gZQ zG9(!R^*Y{B@$TI;C}TwDnMW{&y1E`Zz3C_RvX_tEr4Dbc)vTX`75S4(v;&JI3*;Qo z&Tpa{3;p)$Z^3*%UKKe${z$3c;M6sCN6{0iC&&Vp7Z&DO^xKaPH}2mL${R@fpu5m| z#Id!zTmI<%;G&b8r|0nD&0M~N7daIbg3!f#zLf)G3c=OU*OygX{LMmG!CT|>m=&na z>gt2EaE6N)6@gGcxQfrh>hPbJMMYByhrBp$^YVy<}4%3l;X z1HpSykZju{B-9_Bo@%CARu4LRj2>oc_ju2ETAKehC#!l^v6)%2B!1&Vt(<|ywg}rt z@m-yO6P;=5o2DvHh7E%++XjF!BAcb{>8sFbhEuh!hnmep`9)?Ct5(5e54rg6y+=KK z2t%&4j|A8wwg>FStlz}3N@7X#L6lQK*OE?0PtDEA>FUy4zkWT&A`Wm=I&?*ZZ3aAr z&&9rq*N1~g*fDp@k=Xf+KD$0nqj0yK5iJ_Yc~)#Z+n3^%Wt?}=Ba zu$g!-?8w}3dLjx*V!X37DEr>5`6ZjYOek81OEESfVa4v22&|xsrDmTBw6m%yH(?UP z{DF_4p@xKqo5HTelyd)N1gX2sA1H)fkR$b~u!bj9crjnO}37Kfn0DR z1An8=BS)$jO_-Adu)4%-kad|{g3$NyG7Mr8e8{>L-Q}UY zx2g>k)Qpmn$(5Bt_n0H+?s^|v2YwqEK;Va{%L*b${`vDqTb>E<&`Rcxt}3aky}dE` z8uIii!a)dp%o7K@ReLN^ z0|li6a9_V=S@#Eign|2B+VsIaV{&4G4%z?+DI5`(!{mucNcsqnR4QQc6n>_K8|zArbC&88jcqz5x3&*#c<(~`Nl2noS_qm0#%*o@fX5y zT48ArSBQv+03_p+)87M58K;3BV^j*~45c+PCPp6CJ<-D(sFt-f*kJhJ0cOg++G$Z5 zkX$;{Q{khH7IKy4y^W1Z_J!#cp)~6y;D11#d;0bDB~Y$!fg40eOhpLJ#H`|?zPYZ_jvV;^W=R&^}Q$w{rPP2kk8?$1(X z08<2qRmipL*Uw(QtON!%G#ZV%cm^LyT2oVIIOr*ugg~$mR(5~&@+BiL?|G$Xk5)76+zSGm{vv{4~&wKuov*jTUc{bLH5?78!Tj;B)0o6gT zRaFUfoGEGpHJnr6de$4X{P#n3bVgca=;$V^G!k{|O@e0+$Z6HaaC^H}Mn9^woGwTX zp4}q7JoVk|Fa2|zeEOVR@`d!=px z=>!3(p|5YPL-NswCTf2@AUK!+tSw9sZDmJ27jHcd_^4b}Rkbo&M&bvjRc<{NWKg&e zqi2%}C;%$Sn-3peMMRK;Ab$fU0thltQvz~x*%+Nmv=cvy!D>c%#Jz#syT;6nFfATC zORc1W<9_fqqONP##Kk8TJ>N!0w}N&B<`EdpVV0$>;hB#+Gd(>`cE|)lla6jjluZz1 z{^q!clHO
    hW}G9RBM#oa-zT#~|k1Ja5gp9)Z?2g^$)EkQXpezoRjk0wv0 z?21G#{CI}G+NPK9yp$3CmF<-X@yS-7Wp8yAN4mn;u;HUT{OPgs9QU8$os<`Hs^*A@ zEGNb)a>u$CofZs5y@bZ?{As#}G1*niq0}wyZ#Q$OXRZQrdBxy+gkH0E z1LKk>7rxA*pIslSe91CfWve?2=qON&A>LADf=4sX(h1r5fsHO)JzYL^c==^$sN)Cx zhwAFjVJJcrKMr=`-w^VR9Steu-aOn=F!g-C|m81QFWfVOlzdkRqGNvw-VQmoc2aXw+i#~1BD$iJOu>{ zT9Jj5lF}hmgTTt0ab6d4c0ouj7km0N?+=2u^je1A{J^ub!6=Vd3_$}tf9VoyA`@pE zG#Z%O!0q4~Pfku;oV9K3Eqjc(5yk|}AfSPj4D8)bM~{5` z+vMid^sN~Z;&JAA%~lu+vx|BxY;Ag%Do*aN=DjX4oEa+QU~@E30b1#ge;A!;Oh5oG zv+@T7jsupP-s+Py>x^RkCY;t&jfqPA3iY^HiRmUMr|Hl3x0IBWQ>&}WUS49rv^c-V zAA~A@1|J84eEs+@kpS@m1)HP?rWkqGrDL{vMQE4}qBmArlr}F@H8-QB`=(wte<9>$VQf82t73Tv~EK2tWaY51`dImnz5cF z%Z_bES6A1X$x|B}n+IB2dJYqGW&D7(K`FnJQ*0BjlGW1F6NY#)cl5@`$5&3sfPe+` zr~f_Fog6R^(3W9It#+(y)ytetq&-C!Ua;BY>Jy?lg<-wm2B9vy!I3ce_e-sxNkv14 zP1rHw#=N||V^0}EhnfKNC;J?{MCAI`Q0lFjP%Z~(01_vEOmun-OWAs&J7-x&1Qv`d zFt_OJo$SkfP^)?QuhN9P3d+leEK*i}UEOIlaI?cO%#)1#VG zJFF*Mr(N7Z9i9{NaawMqL_|$S+n4L9h^}$9Ma(+T z#6n)aG#>o)5EM2;5rxuZu4#@pA0BFG3_Nod*tN~CsHm8m$xEMHoG&l^in$JjtHDp^ zET@-$Uc!h#>FJ&YPvrI6wk8Ryj8@ziY3goR-@pG(IT04h!OmVfMoxtQ`qNl0G<1Vix^ZKSyv0Fc?0f2V0^MI8g3=;Cl(wrA_5D zzQpmi2GkbjM5fWe7{wkD`=D+>w7bn_BvjG0mvV?&IBzx(CV==gUugiavh)7!VY6j)umv z;zk~XW&Uy%M%#g>QR2qVB8d=wVDxDTCLaL*QH{891f8fn%vDHKa@~b= zDK9OB+MozC_zG3BRfIQt0EKT&tvCz+ZcRH;SaD42zWL_R5(DQ)*Kswau4ojNGEWq z+pg~V_q4ZPVPa~rQPnnEP}k6yEg}b=o6L?SxGUPwKGmyb$QwCWy(~=)TFT=BHHMRp1x!ysFcg{f z(SxTNygH6oNOSqpk__v-);wT)Fjrs>T9wZ=9F9K!t)!?#c(I@Zx)1TPLtFdQI%vc zo!kcgl2*b?TSU5)nAfZqjxS67DP%rJ=$Dt8vv&=y*?^!#R`KE4@=_Kle;~AvI|SIy zOMr@MCfGmCi`jVZXvCswFdq-BNl8h8GA@t9e5_fkCP`Ge(GVruA{mL?4MJDLaGW|k zc2X@6caM^qdKUUKFm+%_jA>I+QbKS8E5dn!moIV|?&SP#v+6BnRFKLqq0E|B(JE%n zQTnI6TT6rN=i}o8jN0tX4B}RX{)^Z^!EF-P6EDbXiD7|Z9egJsUKK&J?|LErA6|NN zbd-4zxoT9(3|sQ|8j=0?xQYlOa&johZN+W5JDqhfB_NEj-#`4W2~l2Q_0mn11R*I+ zP0h%qe{KtL04U~gG?uG9(DARl9Di;ZS3r{g3P^{076;MDc6@;Uwg+P_s`wSbibTL zlrHCuebb)zj*CZZpP+Vw7RImLt3HWYSE8nl4VCaQGD`7+B%Qf?>N#nuSAcbtcj7C$ zFB=^Uh2eQ$M?bAe6HR&xr{xa@La#~VdGXdQ@bP<$#PNy2|I~L1Gd=U zZNEe!FT8uUvYxIu%YON{eW$M9Xv=r{CZ7;BN%{p#VR{1< zGM=}l2?quS0_RLVl&_}%yK|oTUeSKShkMKdHsfwh9-sihcZ|T)qkMQb6^)o=Kjr2E zm1_cyJs23@y?r}fRGVJ^*~b^!1PmFlGMG4~wkrWV$toz607mT6Jqro4X$(3fQU6%V zX!X?j6qFl5W$N0gs9ysX*AU*ciQnbtZc~?y#MS&oi0KJ3h6gK1{}ga)d!gJaIY+j! zGckC%f~e$SxFO=_Q_5*4MwpP7+f~T<#%busqp6*0zY|NNhRE4WA@f-R(x}30(bKTT z66a$(@eQX56I=eY2vTP(`*UhTw|%vT7xTn_G)6kljr*lGD(s9FmvK%R5L99dV##CN z>E|U5ayT0cC&{G=Nw(Vc!CnXMT}FQXvW}gQA>aom9kAqb2RE}Mk2}sG4BRYGb5EaM z2iZMFeG{CDsRN6k)TIFf1EZI~Cly`@Pf-0qi(z^70`f#Y{j8ii`|~=eXkdc^Ft4ro z*u|wA>Krn=ZB-T9`11o(0DB3tWo32syZCr3_i=N+``T_2TK5Wv2U2ASz$(De=7`aB zOiW5j0xvj>PlRM-aGy|T6d3AOu<5tAw>S3mkS3}q=;*|KlraPFJP(70|NuahywsQn_m@_Q&bprLmX~gH?k4zGle9ISok>Ko%e#VPV-5o zG?riVdSMbaVzCU3us7(JSllD3{U}n{iaM9B`Y~nsO+IJ8Qn==`P>rff-QC4u9vuAr zE^=1IzF*#NJu!-b{LH7CxIXdAzpMv?zWPXy(+KsF`qey4?Cr!u`O5d$XRTfRTIFG_ zgEy|fN8^VF_uF{$4%$haccqSfC}xO;*f+kFa zzxxS~{oq3_H0%(Nvm)gk}-ViT}CIoa7oqM7balGm>Xe)@DXh>Xrs zxIiVVB<_=ehK3BVi4Z8Ms>u>CFU|fVlHIv;2YLIqZ>5|{MFKlv#)RyFyDW?SsW`w8 zAYHB?AGr;Kgcvh3a%l|iDX~CqP1buug+~ZHL{or10H8qq^tJQqD*%(gT0%_&gFd)> zGhhe=3KOAwZ{92>DNtrU590xH2L)uD;A3R+Ycc}c)3<+AqM!Z~-7xyHC!3*n!H%zf z|Gu<^Mb4a|nOz*v9+;?2eI z5#rlH{iSL6L9Vxn@sM4nprrf)tT_ztZtm{LJPTqZ(3mKM$8=g9{o5&_(<3SyoLL)C z&~OS^MlepV{HQy8;fxR0JrWa<@fke5mv~K!K#BG_TonWu2^Vsn02~5R0I?4LFIZP& z!hHQYnD2qyEV~ql@BF|6&}Yo)!u))(RqTO6NlJ>J^;kI&I8^|)!GSdc++#*&=FIGD z3xpi-VzVIr0Si05v~(9d5Ptf4Jy4*n1zs_T4Cg`$FBg7)y(Rr7Y zw6-r4yWh-1ic)82$dJ1M!XdqLnE4L*Jw7xxlv{u9t4VuyJaO~nm9%*6ngOt?Gn zkJa29%(NLPEW3tI-rnBe{6a2k#OQ&A3(&*2x6;_#n$wptwet(hFPetcvceh+sn1A6 zh>(tvzYqIxC|1Gw-s`i$)Fg#3r#P3#o5)!aOOvNKbBX!9=`FvTU3Q|==f9K7CVEI_ zKR+od7|^M@h{^dCF|5xXB9};PsJA|@l~&MPh^3i6Kd0w7L~gU$!XD7VFt_OdYrOV9 zD$CQG?%sfak!waENuidUtf6yt5jv}=g!f>Zk`7uV4e4uW_-p3MrK1sk<{tBTkUn8I z$Y_Nc;TmZhlsXVTfNvKT%LGk%KmaQ87F?eZ@#+;DwYBlj%DVCW`x2%SDaffMfKkjXAwx{yM4HNc_R=m-N4ZZm)o%^Zt zG342~DL034|Mdd+axax0o8^ygnqj^Z+;VOs$C^(s@URv5aYquaYg}lA*73qL*cY?o z0cEWdE+t*M^%z(3Xv6<$fG8s)7B~oi&CL1q2`;#%t2^t4!cARq@kFq1Ko9x#qfQiV zVI~OKzW|Aof{IFBTl@Whi9j$ow6Jk-IyyVAUb%t-i5vVm07an40e}Y<`eSYFI2?g| zI{KR-zCRW@IXS%gcepVNBU)$YT_sDn7?nR4TGP2jBlW%vb`?MsCBY zB-Rtqgk|2bg3IcdP~#o{-Tz~!^W3umV>hSFRakl&HiDuoV#L{D{rz0vdf}*3?tAj$q1<8>DB5Z~Y zKO*whvQom|4BMK>FfD(;KaeqdXeKjv@^DX^V`YvG!WZ3ZN-3@gepXpqgP4~tUXYD zh}#qw@B?Vb?I2ZLg1d%rXA-8%H*s-`b~nut;pUc6BT8CYnq5N{fbS(?hii}^Fg}2i z&<7^O)$s3X^mcZ3+`y>j_L%g_W5AbpNzjHC^chGa$R`+&p-1t!tY|~)Vc(zG8M8bQ z{J(I5VL%$d*}Z)E5_-p5sG`6K#Bm#AgAf&C@e9VC*9?;M{!QSj5QPhX@VjnrIvCa< zr+~ap+yyLh2?796=x6Ukmwglo`t_qnkKlsjm8(}@z+!Qh?j=A-b+H_RfeN_}383je z&N-q{ED`6WC+ADaY53aT-M=QQgl36_s}XqY#zb3jTUy^&ES=uKi`7>HT0=kViTRk*}&NeSZ-^it@LBem|lpbOw)XltR` zcBR?(=lqUSnSkGOB5l>YfOS6ng|#ES zixSxY!B(~c0XDmZfo&Z4=ek0){D)OGoUfc?>iHU@(fuwfm{=7JH$ zdR+3cAWeeRMW@Ck|6?BD6j)>N#l*jUz5+@F;sD;64?O}aEHJxQxVb4n;Y5^cxK_XZ zW5QH!k;Hlu6IC5(Zq?0-f~op_%JJ9Bwxwb&yDK^X&1`u`lc3+LtG}Ii>;%{uh6_FU z@8C=B`)eDs8lAZV^mSBhETR|KzJrghD4f!M{y~qOvrm*E>;o@nfcZ}MA^)%z$R2=l zplX9`4_>d|dwWp)#r;H{YNez3guc1vI3t&^w9dg*rkd7YpZ?3VKf-Aa^H(bTxU%kR z8xRJ%lO>bkMsjkjfk%hU*j?}_mFV)A6N&qKjy^lRsw;1*%RDfoI(u5;I&Z9;_?_X@ z)Sp6;kb>eYg?i|HIXQLQXkEOfvV7;9vVm&nM9ndkF~hM-q5~?!aVmnboSI|y7S5Jv zOZ~HgR2O9Bo}N96`&~;1``Vks!&&}V+;>HUnj2n8HzKCz=WEx+_g?II_PO`jlQ=M$ zy>Ftf|A{+OkXl|&1sB=)-AmNKNDvjo`Bt&W9DNn)hSbOVWmQzwCFRN=kIsotN&5IV z`_i^S9mm?)*?FUQjpC)Osa|Sab7v>9bSgzySeU+P3Dd~;@2Q!Y_$bedA8k!CgJ*@( zV=QCdbj@WK6l9VFTnQmFhIsmXF|q!NKKN{*W$Il>KmStp*JMM3`d9_r(HDZ7@w8m5 ztVHmF$TfRJLGaq_xPjbTdp&yl+_nCiGuDYzH^`FwAiWafY?y_FE-GP^xG!jQT*5`; zfJyHwAoS^(nHQk7q5MGBgh>hBC=9p!gwf2z#H40a(0NDz&8wdCfRL0_4tfr1C<)?? z5ZF6A2Zv^GOOILS0v1xc84YNT-vS0S1{D<*FYCYppoa(`utwmH8A>xw{OZ-_U(ch! ziUW63;>%^Po`ow9$bzeH6TYbQetw;*;@s-(<;PBd$60RPoQeH$vB1h!N6H5jD#&i$ z&c|@eq8UCk<|W((LA>;VkQ2hmxFS*%xb`<7>cNdi0jf_xW+rn;>toE|;Pl3H3l!_y zz&~>Po_N{O5{Zz2^n!xkCl5xWl)atwavn&tQ-Mk2we4@_w~A9gf8vJEx*2oDb}`0wAy8Lg zLOJa6xpUZ_o`;&`ug)x_z|Dc!yB~{+i)R?57bP7X9Hc?{L5G#W{0jHZ_kZj5KC~Se z8lu8}j{5kqR3hR^NV$a$V%%e7V#0yeJZlJ`8|D~Zo!7l!DTUjT`72+)d@+Kard{iH z3*pU6(5^53ZUy=d7!&Uir+|x6TTf3WYd|V@5F3TDmnePh>8^SLO+LV5SXw#`++fom)2u)6xk8rNKnh2w{fY0;tf^)SUVDQAz%<5f;YA__9`eTDWih8t9rC zFugZ{UE2(f(}9P`>BSYow3@~CQCp4t!s<=|w4=R?%hx=ek}DL1MrLNg;916CFt?c_ zr(x=Wo3UTuLlI!QdjaDs47^M?ZV=?;cE!!xc33s)(}gEbi>Q3YUQzdXJLcCt3= zdmvxng36hCKZhIqI}bE9(+Ud6py9}XZ3Lks8cuy8XQ`;EWbLgP(&{Lh!Y;c7;C_4HAC~fz8`MJ2r zVR-jiI)N+o_E6zZny92GzO1G^xCuprjf0~VWHb1TpkvI8E96m;<={=Y2=W-{+6SwN ze*;H~!c`Q~0p@(LAkAuY)YaAP_wn-ZaD(9*vHGIezGkYi{Q2bs<8xkK-e{>XFp2dt zw@pl#CeLeMp}4}rLMW0*Ha9m%L5N%Fw0I8Y{O3TB$goo}iHMA@RL;NZ1zN`#W^ws3 z#Ks2{tEOX7S(zN%lt-m}`b13I2J!fN49Iq{*+6hiS{9&Qe>)nqf3!irgQV=O?Z8~*{`HRA|ldPC{n-_ z43!WGnABA~iKh1vrnH+TaQkn6~V8e+iWXXfT1E`AlEumF` zsNf$KMp|54oHDQ|A`WAVAUJVQ;G~pD)7RGzgO3ydI3U9r3!Wt^LE9fI{grUPyy<9v zE3EuuR#yDD;PvZxaQ(=?q=Xk28w;pTF#Lh{IHd)QZf-U(yvmYBLir7<^cnKp%AClzf6P8<8$VEwv zXBg7?z~i$q9w?w@>ClRx9s*EQu(9E^8LvcVawxfk{Ez~}LN1>js+L9Y8Y}Bd-v;0% zv~_f(vIc$+4nS1@=~Mm=MoL*zQ|8kxplY#D!-a+lP-6n5Q`KdU;L~sdAKc{slxSr6 z$nSzW4{b?C1}@a0XIpZ(3#K=2|Ms`r6}q^;s}Of2=XffYWbt($mQx17eesBI>lYIe)jBHbV09uLPv9u zzOaqby?irUb93%jAr%R1ZT}Bl?*WhX{{IhOHVs4>Wu-LDhREIxEjh9i8D*=;9t|W^ z4l1FPBw5MIPDq)R?3G#emU%zl=bYbv+>iVIK6-rDDP7m+^B%9)bG;n9q?mELZ?D07 z4-ma2I7ogNt0#-~{Ufx#iglMZJj+&LRo(yc?RrLXrtN*ohzn6wOcl2nN{f_~l;}G# z+3!?X@yBSD?kQ$}g56FWO%Akg6Rq&(Prz7`?Ph-meI!LsR4;8U_>GV$yu?z zoVgkD<>Zbi<)jAu`iYeSG4%)ZUXIHP*JMG{*@mF9@tf;#Pc6MNIy{G;Aq-6C4yp<> zm?zQ85UCCH8aT$z=;^t(I{*6@1&k(Cq$oB1x=K0=kZXYu^uRJj1B{n9Ya1&gemfO~ znVA`;*44FGzW~uqv0tSex+wCiOIOg9AmnIW5QhjgC4Z_$hUjx)^75Y+n0f_7&KNO+&3NzzY=n;PsCL&_c}>; zT<=+rcU#iZvKdV&Nz7W6qXYy6mEx2Ak=(c6qRJ;MjQytaR{5oI6_PeWelET%u(b&= zrY7)FU^h>*$c&F)~MZ-$VG%ae5_sWHy&eYUY{Q9`bQV;)XF@9oR`EFB*H_6Ex zxVf1?cEfB=yo4>9=p}lr&@+KnlnXr^t<>A_a@;$8<6>GO{c4J!#q58mg+a2x&QfP88RgktX{7 z&6_uW+At>tO7A+>qvOO+HQen`QS(3vn%gtQx+ZalI2JwAwA~Bv&`@gPr&O>gEKw-f zuH`94c>>|b?7w6|b%_rk0XU3D&TV5>Ru*f}qbNiL`JtW3S~!UyuF7TX6P&doD-3#P z&z1&VqmUv9B5g`>efSDK) zsqP>7emM{2K)p+usRR^%-LN=+PB|9;`o! z#g8q6&*lMcxmO&|!~F>#w^C=0Z(*C@L@kj-U;j zH{XGRl$z3C6CE@-XmyuInk^(Ggmuj=T@r)9(H?Ou9-b&!FzuS73EF$oalQlMS416x zPMAa|z#0&YYIhr?4zR_R!_FygQN@MlOm>4XBYxa9UyU2zm6-k^BU%S`JE)Am*g+t$n&J zfbT}K2qG(rw}nznB^+kk zFvy3;2n2Lgz;So|S<2~M4u~D1_@J`DZQuae7yF!A78nNAix;? zzE?4sp3jR5TGD01Gxe@{wX!rvw&Q&lcNDk7=zkHJ`kENgWtiWiKyZzUXow zsj>NyT-~odZ{ARX>A7S$SQ#IuhF=-*`Ib=aJ@!?|IVQiLdNCtupylMN%SUAH9gDY! zwPdY2oE6IDN`V-ok$^v|}oQfkzsYy%(VZh8G;C;`*}3}NZ`s>?^5s$h!M&y3)^ zPYS+A*ou1n#B7V*7aXFzmbe^{?pKB|C{)V9-YZkFsE3yZ&ci(k24ayk5@ZM85fr5${HusHE-u~<>sE(yx_ zAJpODiq{SXh3M$KJ?ANxu{hgWJXVy!IC@+x-JhC?sd#5>+F)u-?iJtX8ooUhdhfp9 zs|@qKHuSKL#%J8YV&KyT$#YLQs9+bw9+ zyzc%ur1Wxx#>cQ`>019fm~b^8Qor;xsmbo|Kl4}FTmILtecm75;WTqFXWhUH?_YUk z^NTb%LbvP{WxhTT-R~-5K>xA)?Ue1S@TzFevlZQAEK4(~#dDn*)&mep&NcpOGTgIA z_lLUMVfIEUs_FrXNu!m6xO=L?DG`Z7jkCs_MwCR9MWct&VHYlr${6N3ub&%=^s@?e^kKc{y1h4PulrKd3KrajGMp=XgCF}N~S z7fO}(4gxI8ManSMjSd$#NgI>nn+*+{JYJrp>+p`P9{R|XRr@)-7^I?7S!I~8NXK_q zX%}XPYX?1fOeGL9CH%pAW{*sEV=9fbw2jU30|tBh*{6fWRFY#7W{(FBU*5RLT;~z9 zF7kqAjE!3gZ?5Q(r|h)#VQ}9ogU=)(ZDFyI5fP-_)y=l!1(}fsZ?V&3Dm1)J3Fj@% z6(LMOr*HYL8ZZo+HY@m2_Pg2D%p&%us-?QJ@)^4_Ycz!IBwWcxsAdKrzbTse>qz{l z)ce>Ts#wP(eMrNQC+HZp@Ymc+>_K%qwx?-Nz1ZGm?@eRZadCHpSbkk$de{RWIrpZ; zk=92Jy!&p(2Mw)_s(Dz#$8pgzBNn)4VE!`|z1}M|Px@)q?`rLf3-{20@% zt8!a>v1sW-+~>;&S@~;!Tn^>0olQ)!U|ByqW@-Hb7>R6o^5cE7{lll8eEQ+XFZX#? z=Gq;(r>KFO)3c_P^dDd9d>rL({M6lj|7!jW$8mhV4H2pYg}?YljK{a`K`inYKIKVKyAiy(PD_4u3lb*x%T!QZ%1--H81+# zc3#qtIrwGTu+`n@o+5CWofE)t&5-R#GEiaQHu>%>E+@xJ4qWHqrV^K3IHTV3pd zAQS`ifC;V?@X^#J)@8VU(a{3w_|fNl^eMaQfGeq$s>F|(`$5RQ3D<9SyL^Pe`{>?_ z9PPH12KMQU7msg95OaI!EygOI&dpJNr)qgXLGjY=pr=`CuF{JxZBiV;otZ&QIm5&K z)0YEp2Aaz)2nh*p2%0aP9- zk?P=jr{oNw#oN~7Gqcryil5k5SJRmEj5d|j42`x|n>93~2johx%NU&=_)-2+dcE;# z*N3mJ=~qS9j~qIXHbtH0FSl@a{jzMVcj2{XIaw{bkE5(LQi4RgQuJ@w;d_Hb15{9# z6m=fu8AoG2yXv_~R4&~}y;f3Dp@9=MZSDtqCA5yj97j}HK$q(4>U_|4kiLvGuyCU* z*X(}^t;9nG@51^oH8sqegXu{C$Gc14#3AvniaNvs)ESM<4Xs2~toZ~R0|;3%QJW0F zsh|YUaZ<|x5m1XC5~6n>P-As@d^X|Xb-m2juC4PEHU+8jhg&#m6>5L1Em{-}vOD$o zyKrGksUMy2p4G`O#Wm4yPCqohE41V7#!CgCWUdCNJ)2ScuxC$`o2!qSH!rW=JNHuh zi2gRgus7{T;x!M*FYKzz7BdLzXfS(M!O-tvZO2DLpSGELEeBW7R1F(vBadsuk;h4s zQ8Ho?HGLlgt5PZAp6`FXp48D9mP$3e;OA9L$uinuR=-qJm6=!bhq9nU@cmVULfI!doQCF&4W{DVzjKUdqPsM-b6F!*$O(e&3^4h1SKrI|I9xQt#j zZEB1Rj(*%CT;)7QFDR&cSgsB@BAKS@}I{(>_%hHf(Npx3yqZV&H~ttLEa5HrbUGm#pF9w9F>X^J!B6|6SQ&ZbNI{`Kcc*ZNC{iDtlGr0!u#X0 zBFrTWbBa68=bASA_xHDiH>%07I%w~BBoJWtvuJf$4BC;)S<%lF1&WayF^*K63twLx zO_mQ02`O)gu#RT@$wFd~PVd^-%NX~CM8Lx1ln!N4;qtQ>ELI+ab!QJT{XFT|%ec3z zVZ+8X9Emm>Bkb&l=zNZq3ARMLatYt3%+4m$z2JLvSIu<&x7XEM!{09FZS~AGs1P5Z zIbK-6UaQJu$+Z#u`E-xx~dWubJR`ssd z0D;lVuU{YDSwpoW=GZavpB&N$$-f`9)eNsG{vRzss1!rf=CM(ZH|-L)rTKLyN1~;4 zikEJ1o*gLrnrn0U_q@m6JuPB2BGog@f9??Y=Bo5iV`>G0Q%%xCbMYtv?RG({<{XRa z`1wjP?SzKl{Ue{4KJxY1w!iW-pI6C+f8X4I222gycjX3J0`>WxWTp7PL_)H$VV8w1zXDgs z$&Nod zKN|CdU|+1X6cd0L9(m=6m~>*q-;^Um*8@@iZRrTN{cNf%X8(4=0viAPW-6bCMDaJj z!X7;ELwgP?CG3iufVS<;|BxHTIDeub2e734>@9;9e2%@5*pi6$hIr#lV)PIOR`5cZ6D1$x#_3P^D^1MW4*&Y5c$U5ON7JYBlcx@KG`74q%Q}9ni6%Nl z`8miCpZ%7U5bHu6^Tc6YzckG*eu=GB=Uj#AVC?ETT6)se zZ{N9JCM(NFi|JFJk79Ah-f+#QJB6smidd>1QX#4h#k~72{PFyi!%x3SY>{!H4%?djzg0&J0m z1$6ZC<*LvN0YZzE(?-=x2c3mUSMgte712LY>rK5n=k1f1_s8|u`RuRe_y49vX0Xkh zrvhF4t5z|MbDcCLCBq((k%wCMU$d)WbH8S0ey@1V%~v>3~yf1CP?Qma>XUF0jRGiPhNXqd;+f zLTe%ofv+7B6xx90*td=XSE-pn*h#}sMy-6FNS=g*L>n+N`!D4Ho~0q@sHv~NKQ%qw zE59(fEohM+QQ`*arfUAS2PGw)u-i&)7r)lk026dQkK7|im?Zm=KHh0p#EY;xgxd{h zj%I*9vjgt$vh>~ZInYGJ{edB5f3RgYCK=Bz9pQ&Xvn7ai_Z zO6AY-`9~d+MrKJ<{-e_O*LY$)BW|3mxKP17+ffHr(BErWvvqmokfi@p0p^AVo;`b{ z?rtvY9>2gG7|27<+#Rs?W3ABP$10b0`*)W%Ka`O8uZO-c*t4=My>VmOoSvRd+o29|FY}8BYQNNklqR07 zYLu6^2|-a3QdY)O6K%G*H0J%XwmMYdu{?c&=awxN&)+{T&2i*$9$zN$xfN&r34!klfuLDad33IE92s zJC3v*46BIaPl))sJ+Nb$wn*B^F65~I$0J(Z7gs9T6rY)#`5Gt4G2<~NSKPrD5J35n zV%yoYvQqp;Z+ICswUCTRaJ)!lIF+Mg^-vR4grsO#`hmgk+8lq{3iAF;eL7Oy8l|R5 zRs4;;DKkjz)QnktyhLlL{Aa<>`?!(HGoD?E*h+i<1v#;BarsV7T5*7jZ_yVqNQKHx=S~9p)V> zQhHEj)n+ z3~rp(_~Qqm%TbJw9{$*|HKOMW?;`bzn}Cdsss51rV^6X?I~_pU!vBkVVK6XgHJI~s z!acDo{Fql86r}J9@}s@tl5;zty$89rt^UXugi4m1-*bAyP30_o^Z%Rk*(O6It*a|@ z3Lcm)K(0Y>0poDUsw6d-B18_;EY2jQuS_Q>C~apeL6#SVNXu>7ayDosZiIYA3NZ<= z(yp*j#(yQmf<$JeIAGBd&Ix9zGTg7}NJoYw;Bh7$g}{$MzQ;)%dD)#!OR^wipg`0Q zX7@P0@ttfx>~&MlWPSnE4jn8YwU9!uRGIwqNPkEPIz6QB--e{K{vbAVrx{^sWUq^V zUjKD_YtI)K8GVO9ffcKzC7)V(>w@JQEV}7A5rQWLtc7Vk}^ z?AhcnZqjNdbNH<{a*#MgX<^7`k`fcMIG1FutQT5mQf7RX{dnn0YiHBE^48bfllX&>n-nP1CZ86`hu(6G7?X@8v%h-c4v0icoyQ`}I zSxlU?j+}%$9B$2Kq4q7l=$01)VYwg{)Ie?QPT!8wrw0dV>rW!%O&p^(jGqkYK_3Hw z#A!pryDpucoJeOXh6v*3roB1>`}ecMlc@%L4$(1zAiLud6Pcj9(8Vkla^UypfV`Xs zUo(MfIu6<8O$fLqk$|8Cxey!!r35|YiJUtJ=oxx)&l9I>YQgMgSQ4lxr2Qu8-ax*2 zVFv?0Cy1o}TO=eD9^MKF`$+Ed^Ys4O*ifY#^cP?wCU6O#+u&A@KYfvdjj8+)^PSe# zzNva+OEnQ(Ls~;2D7ftM^tX9T*qJ~A97s(X4qGb11Tx_kBut?C6!JDCWI__nVvwP3 zuQ68iSCS5K{*riEoRLrkQxy+OpbPE-e6K#x4FMP?-iW1HH;NKmoCr02oEIMmxbgV< zY8G?p=!Aw^4tdVh*JtTwha__v7d%!gIQ7Je9FWRq&$46JboKO@IV+FFa27#r0Yic*6iH15?uSv83&0kV&}Y#>|#wX{mkh2S|SW zE^+R!zqp(4gYdetSM4jNs+`9u3rX%>@Z-$Ut5At|0hPQ7ZUlgZ#FWnCiy9tBS>@I| zyBEJCKS8^<&D@?vTj#B*J|ACo!zYmqd^K88F2g39GBGa+n8ZMhxv7-UtzfyUyVxzD zr?C#-#9A!)-q%<7HUFlDrS{Y!3sc7*!WKIZKUTBnZX@wXR;j)pVBq)g3C#W~x1KIvQJ|}lj)|7qfyW=xBjOVIXQzDL zo2nSE)omj4RgTv_z6B92o1qx{sKO$56UWB~h#uOKciqxSy45C-d^&cvuzsX+Wz`WSj*KqaE(}@z4>#B$@04yq@q`ki5b%#JFcf{ z(DpOS40rcf=DRIC>kMndyPyvF*>pSQ4%~Xp9c{01Q5M%M17N zii#dgmg?JE1#L(rr|cC6hhlHLcy}lXi9SvD{ngzOV&_AE1N1&RGQz&**7fC?#{0Go`(41w zqd+Ofy{eZjD1g0hxn64>yu(j*lBg);wm5zIo|*yS*frN&Jl^y0a6b-$3}u7o^#Y=z z%yaE`vUK0JlXw~VV<`=nH(c4f=ZEomHq}t|XW|?Kyh;KlWx0pluk5=2kmDL9C~k9# zi{0A9cZ-c2E)`t;9wwF9EP~bhq(=i8= zu-4#0;h3A5oxN=+ssS-303zj@A*H(K8~vh3N%XPm7HPqamC3}RB8pXTIn*%$tKS@}Dv|DlYFDD)Y3k;Q<*#1!$c`NdE6TQWl_ z9*Ud=R8x2}rawOh<_{9tzXZ5+WS_0Y#iWM(ULY+@DDF_AyfMsWOVEGee*5OluD;0g zs7(|g_JWoE#)fU`CLoBR!tmGJK|;4otgXKU8B?HhyAIO(&#J(5S$|bCweCm5J>jOv zk_AEMa`$F>uA?UJ6eMcnaOj)i|0Y>oDaHkBpat|*q=24>5PE4ur{Uu9EQ7aDV?%tw ziW464$8DlF-M)A4S_T$AXnt+>7Z`bW{vH_c$3!bYGkmaq z_kQH_^XXal#fnXJY%4SqV)^5K&CVv-DzG_$;X8jne;bY#M1V+1NnPF3eguRN@c7e@ z0##o%Tt0B{Aa}f1)bqkZzRQ{KtF?iKsBh%pz;e#|OC}eH7V6QkUq4|0$iHVBD)RK& z9#?~&hcXsdoHZ|0W+i&|Ik_fXX*53HA-W)Z7X*2|m~{Q_mGxZ*ooJM<${eF?>ZOkh zx{lD^38ZNXAa@0`w=Orj7^D6srw17~Lc&m-Oj&$^GuAV0T%)$PyV)4G3GM|MIY_Q0 z_SR6n)B9AznyB59VmxG;&IQHP4u$=Vt47<|9!=jDGN4r5xqRHS{{-(9_cB+5tkyhx zchBZvvhM;hnytl@IHV~;w;>fE#;%ceWqa4OR(wJCwLurksU z!}d)upmpP-(B)=ZE~jW{^bERmcCTpgm5jSiecCEVYwbi;kLgGSTcD1D!h7hn#jC>8 zZP0#I2L2;+1U|N9B5wvXG=H@8jVXoIb&-=!`J`VMm7Xr^Mws^3XMOikANwEKt_)>5 z^7eM`4FdGFGyz;r|4r42t9)pU!@_Q023$8j|Etv03J`kYm%qPqPWIk;m`DbteFa7( z5N3W8mY%h^pr1wA_~ld(!!K?I>~lm{o^lz?la!Rqf$p4W#4%Z7+mjZC2Z}ob6o{$e zjZq#4 zDvU(XQ>DSZgI)9Bi8AXPBlJF$3P+;EOh~ZwFH%6b9x*;b)VsY7nC(aYF9WgOcHc9e z3_j#4a_FWezVsq!nJlyd+}+)`fo7xBAygSJ>|f0txwjz1K*ZAZE?)*#Ha0)ZsXKEM z5MJG@TImL{(YfNhaS%&og`%oy+X=3cwPdZo3PJpxCU<9ISKPXp? z?}c(ne7M*vvwwe>w>Rvp*s#VPG=%ttfyaD%Q>sxONqgY{oNBwbWChB0#MK3g9>Ged zLDvXz{5WXM9z6bXXr(H5)7F2f=kzzoveEOuQ_3A@pXuE9dDE+g-^`gkLMvRfJQa?; zw`URJ=Z9%JPO4&M5Ytb&>0N7ESa5^p^(R7n@&&|p?Xt>@h2|Cswh|c3XM8U&H#gJz zE|Pn?(d{b1xo|Hs(jOQ$AC~aJyrO3&p#XECIo3}$KeTZe$*8{2)fqkAA>};Gm8myW z25Gne<}mOmjf2EkPsYfA9rT0n)QM4P+Ns?UN;#G7Y?!FH1v@`Fs}EvJ1P&5?H$Zry zfsVe@w9x`?Ogt4^g@nqE+(n3+Vp7BAk)5oJ#4w8Y{Ft*BsRYqp`;tPRoQ+LJERFotfVT2XJgmKJI@`m6X2M6os&1(QQB5aV@&vkPgE+p7EtEYuR$cA*ne5;)$ z9oO(MGC!w4bpyu_?s9+qG(PdK=y9kH_g}_Y& zsYbq2|CXwfpzQb$Z?qk1Wn@j$ihZh$Re-dsMQ8EP!ouc2N3ab?wm*=OJmoo^kM5U< zCQDfq?uN=QFk(MOa}3%tIhP8$pc94~_UH06Zu=~@Vd%&qeYtw(8aWzq;eG0JIB?pFOvS6!U_#Jju+*4 zt&+-0CLnLWzVpDS#uBd;2zfi!fEk9OaL~QSkr^4R0romAO&lsrgoXAX^`1M;rtxzJuf7*eKMJNLz&J=hS>4c(r}O79_T-MWxzg}RWl9n8=aGA{U4Dt3v(s$HmRx6*=NH$0Ul`0Ex#g(OSRWWxWfcS zx3dM(lG7BTmUP=zNo=M1F9d^tZwCSkXfh{7)1@)46bgJKx%B{!;5uN%D*c!cM?Sw| zdNA8j$;|9|y;r|mNT+S$T@gArgqa}m6M?BW;5NR1;eze*{td}(FiwOS5# zpmf+8e$2r3P1@?6A+9d^80mz7x6bB9^tx@Jm4fRqp|k8#!rVDbJv1{nyyospZp>Q z&4H^1t=n-}Z^i99WDCuWQHdY}=z>-njgPKyIqKZ&C46jbUq`83ZeD_B*#y)Z1f|#) zsHq9Z3CIbfM^tducMT2(z+^Dqi4d{>?IrTZn}-`~JoyD2voz_tZI=z4oZi;24^R{! z<{LPqn32l&9f&Dj1-`Eepb#jWiX9E}%8$b$M08~%IB%~$aOXO4;so}(YU<&aoaa3@ zKLF!R;;-G@&T*A8ZSd36U>rk2NnD< zk?@{LQR!e%Db<^MCRiJ1VA6p#0$ zhb{0Xw#C(hkz(g1U%y5eLEGzroC_@W1p-CUF+H@cL;L?n3m~WT^wbln4H!b@@!HkO zYS8H50Cq@P8Y@Xf)z&8J`FZ2Xm$Z4t?_4Tc7CK-IDg|s?n|ieN%NNoTIiQAEp{m62 zgJMS>j6Bnmfn^F3S{2~qD7UC-XmH$8Ap`EY?QKbXL@1@oy*tq_19-+d;=-YYJ?gl! zRugAhLRQ;rLr zJaU9&@r%{rdpclF4n_Dub6p*J_7JqA2*DFXD~1XjR;qou)#7ZhKEVxAxoW7Z`)M_J zkFfB~f&w`VCTfw3Ihn9OH@Zh^AvBn9tO0gP#r4tZd072QnwpvkcE&Td0hEXpJsiUr zTLa9E24cSvl`cTYhA@;0+s?nEtWz)k$^p&? z!|VslPB*i+XTj+KpKJDGYY4pkN3Lyza+%1j$VT&C$-gfEV~71UGqLbv!TL|=7#QZ7 zv}bA@eti`}x;qa9?a3d1z(*qCxp0*n1#sxgy^q$w4MF!dLrsc9ghmVXc~uwdZ__e(ch>9Zs}VK63Nk(AIz2@R64U zuG+rLVV{H7fEHo95`VbW>c&__T3JPO(|kC8Lko@U_1YX`%U0oC>#oS7YtuskgL#3i$)` z?Y9%Bo#h~TyLICR4Olr=#5hB|z~}yic(3oI4Fv_k>PXzZWI^0XgCrXEbAAL8LD_ni zI4NJJd2D%j?8c$U&E9!G+aA~+|26-w#KDM;XUH|x1uU)$apHng7Bksq>vY^Q#Cylf;HwI;}(i(l_9#Kne|sltnNc2b=;xlMwe{d)4svNceP|0$dwtV#!-a zj(7l+K9h^BsA-U~LvXBHr@?Kal~2n3z5IQHJ1=rRc+iYdD8O6btDW$Z6%cs(Mc=4x zEwz#0eG^z`iBJtpsQWub`#_{2=#_XuFHe>>Y=kSi) zcF0%M-UgN~?d2(E>e3=?m>g5Lutg_e;xEacBBcJf_9Td`xHWrKTk38Xjw%vjZYSe(6n zTh;SZGm=7eR65n3fSQ_euk2izN%fv!dFi%gdlSKd@QZCw?k@O02r{Yb@N8>%L5jS1@dR$d&F<=& zd;irw&Gd6g4Lcf}H)oxrZaUmYu&&A8N?=ePS6flD0`oytj3lFdmqRbwrSPUVa!;3i z2$;RF+mD$7*q7K~F~7J56*z3I?d)Ecc9Vv*Jo~B)X3^n_>o}IiKu5O~g%w%mC`nev ze_UNCQV_{okMJs7{`$hFcXI^6ZHz zENai;OP@wK9@iIiWxNkKu?e>iO_A6IL0_60?7An?W#a2S~PR0a-IV-Tl?Lp4lk&$49 z!BHc#KBDHej@tE2S5j1hW1c6YYvA2OJ~cG(A)qwaMxf2=+PXb+>?J04)6ru4|m#! znwpT*su4^GIoI)HbqJ*&xB(cTw@OHCI2>JL<1SR7nEK|8DuO`}$NAcRI9d<3?;IlM z5c4n+L*%UtC>&Zgtg0><&+%HGId>#ptMG#pYKc`n9OV=)a}sYAMwVBcdu4Ss z;doG3mi=%-0=Km^SX?E+`{N?t(9E^I*0uPzc`*?G9dr^X-T!~% z^4>-^jO>uIZPEX#%vvyGuVqlQCHn?UmxiJPGAFoe)Z(=;k(dcN4jz>B zj4wTdW6ap@8s}bGM=h2eT#Db{Fc8@z<-pUJ$XCo$k=eZR={sWBTKL?J)Sy4d%KIf~ zL(&I`>k~C4cl_Zf(~f*s)XeKtq(o(LRk2DbY>q%3u>PNJP91}~JFC`sy5&np0Pe+I~pr{Y@Wb=5J|cr7v<-2TvO z`{2ju1F(~sY)%KD&_#<;)0kw8bQg!>!lBURd6 z0d!45JsS!*OZ#~65HRsh5dr$(mZ)zjmuQ5eoq|sOPs;X)2$hF#6TNd9oO0=k;|~2> z02WC^e(8hl3{PT!-y&-Bq3zpgK|Lk&r9|n!j0>GS9l(z$U6*b;#Jo# zMO$C4c)gpm4?uuEiY3-rHpmHFjV*8q4VsjlTJ5~@Q~X1fK&cX~L|j>b z-x&e=Q(L>ZWcztaaW*@Db6#9@j+$<@%UC@A_+9Gx)}^dGTbJyS9hbtUqk=Ep4U{NX zxvQmGLK8<#ulo0f-U9+OPJdHb6ne{6^%PeL>|*@1Tw`rqVrh{w3%pzF=%{^7zV_^CLbAEE_sY`E0L(GI1C`RWTfx%vT= zA3lsqA@1c%aA>sB#zAGuct_0sW}k$&o+{giiVmHgw>@Y5NoM1h zY#7)8K@&om)sUvz(LsV90cc{x1Gd5u{EY&esEpvbvdDOZ7zi@iwQ#%LUkcL&pXTL7A@K(71;fU|l+@G#0%!%Rj-}~P~R}@#jzW1~%YGL9d z*U*5tJOT_I&gS)m1pqG9kCco_7Bhs7$(oLkbhd2MM=>F}9AO8z);ZN59jLx>rCksH zRzzLmfIc&|Gv^9`j|&i8?b^5oMkYk`JTEBV#bifB*pi5Mv|a}!CCM0^2SUf~a(F(3 zRcB>M{`sU%f)`%afQGK6sjC7i_JpkQ|y59hqRhr@FdY zH(3YO$sL^c=@oo5CJ09WG8#c-LEnB6_LL07L%agyOjU2ZCJqMRw&by`bnUsoq?R27a_ZHSnIBx8DZ zmU+JWvc3I4@SzT_@r9B^JCHOyr@JPhqNI`K{4#y@4O*DuksT%1dfTpfc3AykZ_C9w zj+r>O+U+9G@(xrz+NN+GK}y)1QeI0^J{3Z2HzHN8zvX6U@5ySTe!=|~B@jNIPSPeE zO{m?E9yuZajw)0CgpN+cxuTBCx!3hy!gaaLKKA$KQgjZz$|1?g$x=Mb@AQ*Bsw^@b z(Sc*X8N4a>Ij~w&a}rW3+42|Pe$jtVAHNzSVEd<~zJBZ2=dSlJ)C3;h@q92e_hn{r zC~Y#sPYv<=rJn4oXEt2ZrZ@O*xlCSO=eU&DOCi{=ZieDZl!IVImYpDioU?wK?w#86w!Hs)`MOB z5h`qU463rR8BSa35XLgXp1>Y?B=30`XmLaY2gX!LL{%dX19i~g@83>A4X$QGHey)8 z*dI7pwsb-A$i~T8fh(rZG%lv*n`!zdJrVR)V7a}DA8`1Z?3p`S`b#0-Gh23MD+Ci^ zl_b)l&n6p$6&c_PpucbCC)&>G>FK+d&-5jBj4}GkQzI)o|I}D?6*Gi|7EeYI6IK^Fo#;^ea)1-{aiLtsjh>L0c(m}0-K9&8GN%TvU`;_s_fNus zrzeB(r45X<9gCnPeof@{C9+^u;^2J{5wWAS4KOPh3rjM9V`c{I&adCUp}8x}xgZl3D~CkCQBas&5_x`>87yR&#& z^M#;yWV{!?#oAe~ zXFs)EVKuWA=U&r@bM{f$`muGGvsrqmaAJLJ;|Y(ycCgg^WC7bWf1;q%F8iNUY#wRB zpb4zWY}2DSNT9tVvdd3?ZF&Jp2zkKqQFpiBiSg8-NM`@ip6YI0(bDmESL5^Y+&}5^ zGBYsy_q=3Smmi(5_jx*YVUAJTsOuT~&Vu?u6?*SgwW9rQSVv50tt0s>3q$!(Fv60{ zZ1D8ZfdeESK<^&srcJrYyytdpM2G5wb@bU!7WhY|zQ+OR>c}#Ztr4P7`*tnJ6=d9d zq&O|3{PdI-aP#X>`1g+JfZr&EX{K$>V|37!*5%QDZD(J4<$+4Nxx1T3Ip;-(gfOQr zN_DPF@q&Y=PeiQz0dm^j=nOs7Uc%?_lbM<8!m(~V67s$O2)Ppr3fil^EiDuBnP=1` z?q0h~U7{+qcW=;y@N&FPlEmgaaDM(eE&xP&Z@dv8iUY2m@#kD|a%@d)?cC*Tq^Lr*0G3AL_W&E(YN(6gHW;I< z;*bFu(QLB=12t|BAc$2BUk4pCJ3nj5-#;O`9avc$f0U%Ipv(t%yB7hsTQt(`&_GE9^sn5{{Ab}1?pXA#*Ju!iCeW5>o=s?5(ocQXsYmQLS zQAuvuy!m1j;()-KoZ%S6s2e;H9%crPAUd$t_`P`Kv$M`P^^gdS>I3ECJ+FL;CV%79 zgyiHCe9fqd-o1O5)9f5v_Df;kz6a1gx@V4ToH%6d{rYL+P~V8cjy)iI|K59lZgv)P zH$MTnA(s~_O~V`qgg%5$^+(x%jvc|FfLOH}Jfj>;Zd3IaWG!OgTex(}86ariidM4D zH^?zdyT_X<{Isi)>g%8=8Md$c!8P$PfIlMeZI%emDufjgkobhz@rd59x;w-HqHAS zsc2oQ#(WRuG5gi&`rY3fpZdTL~X%k)mI+nk~!|OXbM9*iS zrbA3s879_YgT6o?2LtZuzy4B#3WS14gNQi?TE;bN1VI{i}0L(IUp7;72Gv-MXqUrj^fVGT_Tmm)GI9s~M#uR=Q?iCic(OlrpYY&0^6N&V|5iexw zW26dV=^*AP2RH;)9SI3lC5q^Mdx9gImy5k16zIkV+?=WfBe3}5XDTb>Nv3PQ`E1#^0-(mZ1@#|!Ag8Oj+lg8pib}dd(*M0F<>bOh%}C|!GnCKI?H7-<9i@sqo zH=aoIzkQoI=Z_Qy01!=}!k@}h*MG%F+DVBEv1;~q-q_MyaAuX4oxK#UO=-`C186r; z4Z6*^Z$rUiX!1Q%^!84E+-w=mnrH$3>t2pEFmKS5GxlD-Mgea5%W=XRO(7Bvj^WA& zKklPFot}`ukksJz&9f1A!T;)Q7`~^W?Zeme#ipb&N!P_T{n+iWuG#*2&MT*Y|Iq?W z*0;6Y4GpagSUiNIh351wfj!6EUfg+cQ|1ozM|!$A%^!q?Nke&sVI&wPiJcSLY{MrY z3w={1QE!)aBNi9(KaKO}`H?S+mjI;ES1WOte|{oH`7dR_%{!u|gKekarm7v|Ej1t#s)@L@oQq1af@IvC?2 z6>D#6i@_K-@!+RWvz+i?rF8+Gaga>UMQ`p>IK_)5%-($+O5o+iIbxheNpU)<0cQoG zUC!Tq9BMFP36ce~v|q%>S4w8vcb@zgjfseqXc=)vCCv~p-`z2E@}>KcTV~%AV%~1p zJ?fXU;7@V{V zC3cxz_Lms}^{|OyOZBh*9n3|g7`HPXZ0}Ke#o$hAh@yCU&ZDbQQNJ##|F%pEMOBOp zX3di)YXWTC-yfaYxLV!9sc8h(1IH-Q5@s~xLfO1eE)|=t(bzp0`*Ixbk2p~31N@Gz zx{E*PL@&~veu}SJ{znvxZ`a9$)YMZjCydy8yDNYE-rg=}kyViq%YBspF!$)zTLj5D zbgS9srQ2u&1Sr5RLNUospbH?2o3Jdi)+Rd9t+ZJ8cQQ)5I@n;|Q zfGk8EaZ2cU*3$Z=mvuYbO}x%$z33+sH9TyST6^ihX6R-i1NnPZ0h3vP*Fl19iDN&G z3Mii}+E48%b&B#FkwH~^?aFazl$0AVX@>um_0Pii;@10`A*Kwvij(c^Jed@RIs zzbm=smg(ngoMOdx+0Re!>MgiaW~n5=W#l~8aRLP=1L%qB(wM_7Wu^1yJ0CV-Y5Ub< zBFgxj_v+l)LSDenx#%%K#RD&5=i?KV=K+Y>Bg{Mpl|Z`)Ml)CNS9CjQ<~(#6X(YH{Tr?Q1dNT)Xktb_S{5GjUm3@ru6jEJY|-;Sx#$F5B)I8 z=I2@0xxj%1Tq?8koI#50s_a9}d-u2gKa9P3IF@VMK5UGTR6+=;43#M|&!wbfDit!M zka-A^S!NBA$`B$+DoLiy3aMl$WX`Olgpl#u&$XU+d*AoBecSi@{#buJt7qNa_jR4; zG3>{_???I3O>5g(J#i9XW)ilZceZmaGN^fBSFX`h^yomh|6N_k!ozb6QU)~CAiC8{ z4&rrS>e<=Vb>0|38*Jh0@xBD5h+g-fz7_QtVTG2jF8_);xPks)3>g*y;YULE0{qdP z+&=zi)83ybW|7`xedfiz%S_M3M@tSS^vz7ZzIkKM?%-GQkeytbRI_m`-&X?TN$Zc8 zpEZ5jzKqT1P3rEl7u^GET&I8i`c}*XbD_!RL%OHeHY#pcs&L-6G#R#ix~~I`PfMRP z*ZjOm;c6|{WL`?u@4;S&R|^;OhqWxzrS9_IEyAy$$mzN%Vp4R2>=VPh5$-a>SmFBL zl|(8kX-r5k2L|x~eG~fBfaYGf;uiiHO}}79fF{d21D(Tv=n5Qrc5&|K<2X;Oq0s3f zprX37Zh5nniz^C{EL^Za{tIW6`xxEDvnZ-S*rdS_8(if-elRA*k4I`!EpY) zSjK6S5UQ2=Lw6+)EmY_WN4$>}+_rb4so$1?L5ohQdQnBMS$A6`*6OF{&s#o4Q==+JB*&*m0$aV8i!!HYK0i}gjGuSCx({vnP=sJ| zWxsQ(t`J(mbR-DnpF_YSNe_ro6gD#qxrb?G+{9DItsJht2>K7PtBtL{f{NZM@3iRD z$eYtYM0V^rpe&s*OM+oq%<#(wIhsXLP^i@L_U*A6wR+|mERdr4Jm`j}2w5Y=HJURjFr z@*6i@&vf(1)AX$>|LEKqF+Ffr*xj#B`S7G;@1BUC0D>2>hr02%O@7NB54{+vROf*! zJEFtn#ZInTH@-?qk-S=wrv75}Yp}k(ppL13&$mx3TSX%N`b|iwF0KCbyqTJl6&MGB zm33Ll=u3he2i2mblWW^cIWyDL&Iwc|6bRvNU+HHd7i&aiOKy`%Mq~%a$N(l z(ClpPDae1#0e!@ZuHaU@r&@+*+y?fGyBIEp?caEPf6Ps)_jiu?b1|XT2slP}_^|%t zxtlvDr&EGW#hzY=|8Cgm<@$|Ziu4v1>jg7dC*4LLu>N`|@NNEQPm6igkB*j#iY5Jo zt)e0!f5tOTTaUUacxdJ=EY2QYP2R_-{P)1d+Gph-?@deF?p#MD8?Vy0=(TQE@z!Utb4^tk(w!^J;%-L$2 z4Ofn568U1du0grOsH)C_kcS03C+IH*n%{C}3%fkqVXc=fXtwnyakK|IyIpidR?^X~ zX>c$jzaGSa~6=vQ&jABd`;T<#IT2|rmartMA)i5>H zj;e7JhOSSNO%;+8WjQ*#zR$KC(f_WXDf#!)!^7&vPj53+IrJ(v-I4M3-tpUiuBRRA zE=`k{O42?Zre@Sp5y_}u9TL=UF09JuS+n^o&yLE zste0K1T+45mEGLym1bBlaKyyU1seWlKB_7aSI~5k*Fd4+iF&QQ2I|W_Gz-Vs$KKyQ zeD+siMVa4^F}({8FWsyb4kA^wbbh~McH64Z%{8^;^1Ou4WT4dU)x^Ha^y^yVz4xm3 zN$6>LdNO##9_EyFW;?;i5ahq=`K|c!uei1gDvM8!?<;$F(7QYQndp4qD%Z_ex`!d_ z$#1&++A6kpH7-Y!n#C&bVria%R{z{Vt#^M;PbDXhZ~pBxt4RBLJNAtQSBZbcsBvf% z&;fD^(2%#S`&w=P1hhXkX^TeD{ZI}hT11pfBD-WZMjwRjvNFbGS0nyC$)c#_?0@KZ zCEC{vp#C45nAp7j_g&rVgw%!q7+@E=+1hnxeKMbqcF4xuxDlX!pR9z)wxirt_NBCYz25o_3oPJ)#(p0T9j}MEqLy$w)gMCe6<+9=@mJTW|Jd*lk zqR;;qaNjt;$Fx<}*lGQnQj4Yb@h{oBgzZ-sD|T+Ea7jNWxci8a0jw`CITPrxwt=i$t|zW*HK?LD{}5BKe)YSx#dWUdAQ;3r^6}I+8ZZ& z-+s8&HY~XFu!Q`+w8ClDXl7uE7~Ddk6b`kJZT{K34s6-EU06#dU-KYCz;^x2}*^U=*HO zrN55MO3r?Y--0lx`2jE4|6-!QOL#Ktp5!}-(K-u1OWh9*;T_G z&j9TJ!r{O0^$7~Ft#NO#YWs=dZj^sy8vz!xyr=Sg?yFN^Y-EH#lzFMrX4eXJRNvBw zjNrM^rG4eKC8Y|b?4A^>Og>CARBnNNlt&yT!ZQQ6^ITg^U3JMDqH?12FW+*4Qjt;C z^ZBK9m)M19k`@M(zxt+bytMw(AY0cq#xKlEltPqka{g+8=3k8~Jwv_9pB0#R@rYAy zv0Uv~*rqbnzGT!*sqKP+91iswFu^e$&`wDF4an^ju$%|h{0tWZ4)J(hfdqRpv2Q7q zcj+tLfcn)P9P@M=;NEe6%SP8}e#7+Nq94@~++WUnZy;Q;dRTPn355uz;g zU%l@a0d8;RFgQaxm|rk=XJQ$BQTy#XgsmG{Sq~t00Cg4v0PwJ^%vbX=5(&)q4NOcv zz?+f+RE*fU>U%OykYXo*x=Th!X!U=V{JK3S<797t4xB?mw9^&pZi`=Epz>uF;-S;e z&8yZ;tl!tf=e&(qh<0UN(<}N}|6lBnG6Pn5=jCtE*lQ%5F>UpK!Z@~Oh1Yz`B!}*2 zCu>gq0WI@Yih%p8dQ?mPmEK>6SK3z&t){AOoV2X`$)9Qv*s3X67yOrNa{Y3(r&-0- zmn*XOl3ag#(qA~(DQtT=uwvX_Y`HPfq_?Zh-?6?j3U+cI62+YA=vG}h1Na{73Hh>e zYAVpIxb$b=f@RszaQ7j`bngD{vAOoFpGuS;fXQ8!C1Xl?k zSjy9Vx}e(2K!$tqS;1E3y5~O_LnDI6B}aQT)e^Gqb&0W6P>$WODiNvlF}JR8UQg?% z!c=i2;Hu`guJ?gG%V+169!ULsxMHcZJtMJ^qMYXJLZ4Zr)TX7bl~GR$w}p^z9_DP5 z5p@1@Gj(SueoU~BnyDoOmPfv{Qtlb{-MtXvC9WT;I>A!z$Qry!g)etC_m$ake~Iex z0>(>g=)durcQpC?6iqzW^_ihfci!~qI0%Srst<_R4LSq?AtCz2hJ#pdY;(iqER$8! zro~@LG%^E=eXA#@rWpQqG?u@A<^EnHIJ&OReWQ6^2U+`uP?MIEvmU%0;1$HR2K*yJ zc@a#$M1^^|`h7kzF`eG>*ME~@$$$gq4W#q9-bo)b(zXTML(vPonm{- zj~U&fw)?Wzq_|dfE50Q4I2FIqqqMszUp&TnphBOSs2aX zZ!qc$SDA^bxf7$`vQBfnC9K3@m`*cqN{o79Ihfj4b1>hZ#_zKVhq=1Z{&nq)ndi4X zy;H$1d}g)7Z`<;BK9>nCqt#-O1G~PgX*s%(y&Oyb(G^I z(0jXBdwVdooa*b_wwXPO^WjyxMOxp370x~`Gy_R~8y2Kn_AFRd_AINrOSag1>#uGP z9M4-gw!$^v?w7kYN{ZTFrNwA!o#~PY)%Qh>;%pl+3-iFD`vZT5#+xl_ohgOi^F3Hy zl8@O-sej|e=8ZS3W-9g`V2U>}vwHq`)#)G$PC;b2lxLvo*Ee!@q6{@xc`cu>e`Q`o zR(*gI1EKl{j5-bkA62cjV41CfK87@*Fa#i-K

    L@P|~!kRB|xxh>%KGP7>Lj^QU6PaisqGD~c8C7$R9)|&96G@_tH#ds zFfA>J3}BD%0{={4$!e~=Y+bl-6RjuJCU@S80gzV_dKQQnHJ%PhERth*&TEwT_*A7r z%}rcnxh(}!>skuTSzaZwj?P5YvpD+o$JR#4(p@l=bH3}bROCDUr0nmjR*s-h;g9!n zPF#0Wpns?c1j+*Z7@*z+ULs8ns{nj)0ALvy#2QPO19|mS+`3hNcw5W>ay+;*=89h5 zvoa}SMt*|ZSZgkh!UcST`M+nx=nSk*NouxX<@K&?Z@+`gP95$(HrP5B zF2La*C~8G0xC9Opgn2Kj48= zpYnf$2Wp)f=TZ3tNR2NNnn>C!NCWO2JLKsp12x>#4@Wz@-MiuPoe?ijw*=G3~&e5$|b2i@ybN7Tjsb`iEjJPmf1D^%35tfNzBv1F|Yb3-z zS{eGuPaSP+Zd`{p@>6%WqORtnR{S!c_}fxOzh1g04JWiv_4_w8ATr4_W&%qFPXe=< z;R24*jO;>>ZtPA1lT}&8$zkXXgnsxwXa?Xxz<;lc?6Er4i|>D)(3-Y^hKC%!FHrRx7dmdH z>Y-)``CRz_pOx|UbnN~P8q#rru;uUXk7tH8LL+1|m%X&56el>jI|T*9fJMSz<^V8n zFgb>%8&wE7+0pNebqw`C429bvrFM_Kot(rlR7EwP3$h=8gXZx+FAEC|AXKeCHvob) zgc9$60q!MEKX}fVQ9>CE6uYDbRG;D315=u#-jwg5;K-h_2)qy}rcuv7U)_WyXa3?ss< zxeGs#xkX`1@jHuvj#7uIsuDccA$d0_*$CmGlim?}bqY zp+p@0EB*gMl)eW-I0Yd2_ZE3piDbfgf=0skilfwJYp%)7Yu zxiWjGU5DypDgGC$`ZZ|5&^Cb$0=nBEES6~az^+7HLS6#SF{ZB+j=$SJe@18+`n)V+ zT%fC`7g%M^CnBPKtsj(;!i!InPBR@-%-^8-o&g;5_b@ygvZo7C-^S4S%DGW#j=~xK zVvsr<%=j6gN(d@Sd*-ORA@9Duyg>;PJ_ah76oB0e zq9lH;SM4(76)@W%Mn*OmpTqa_kboE))c{6CVu6!{Pjid%w1d%HMNT4Sk#`O?4qE z4?hSI5p)r7)YhN6E_S2S2E#uv`{2iUR7)$;=2lnuqXFe(vI;CQy(A&X=-_5kpe-fd z4#8EGsDDls*vBhI?O>q~y`Gn_2n!w^jCO80t;d8A+{TkG&kVCcg6oG7Cb1qvY{1Nj zEh+@_N2p_-ci4ZiFRzs83Q$5XpaRID}jXaJJLi*X|Vmh)1PyB~^cu@2H52@ETosG&T!dey2 z9{2WJigVyXp<5+$s-feVzlpag<{Ks^NlVlUoZ-VeJ+G;*XJXm`st4F6@F@jp!0PYR zun$(nx@tYbVUj>9fx6xULkpr3_FdglQUL=c&tt*}lWdqF+;U)g2ofe} zxi@2Cs=!4vE2(v03{(*a9%! zEIbva%q+w$(`8BT7|~PWnP>5u5Gsam2?d(-|IW|xy-IjcWJJyj0B?}tDvE}iQ zzJALiN0se&mwcd`u+xoAAT6$Q_vZr)FnIVUpC$r=HsPHynib2vP4nY>eU( zR!wRN8gv+DGaX3{zSTJogHOy`SGRzX9>(j3&*TJpk=9QWbl;IVPOHGagQ^k>JT-#5 z`EhxJtH5hh&1rwH(L^D|*%090M{j*%w)v%;3D|uQ(ZSN;uiHR$)nDhH_HN@Jy&tRc zTb6Z4#SKRVoqy3Gm(zr+yA+l+vS^DdhqHQC9RNp^y5&RuvCKpk38jUxbj8)BX>ORs zqYeaJv?gRDlW@~LvegTYiBWYtm!qN8a_#e-BgQC@Hi&WR@=dA(!>NE+y(8a_O!niV z?A9K<_AhsOsdOhIw zf?N*y*3X}gUZKVL`J3akG@yA#F+@GPk@wxhO?X{KPamRC#eqDSP9*SQueUK?wqD%= zjJ?%%7}XSy@BdkTf)8us=y==GdGj=Ue|tam2)_&aBnoO^_1RpkfYw1jQa5k%dv5L! zSf&-ULCx%A0gs0K62UDRyn@09huf9MYiI+(KMsmEQDSOIEY^@|knBiqFZorzoBYTi zO*dYyq{VR1R>8oCxPDy_KncdAa4a~t*Fu~F;tNX*=?Ln9!D_Kh`&Ij(mwvLMqSr9A zBWdASrX|#`U|Hk>NP`3dJ3J_CymLmWStOvo)4A?P&p@b%@^)4E3jmyHyAg z*s6ga&DD*9Q_3BPLz)3ru(@wYjc;)8DRMq(+(D@9xgb035k`@^TQtVL2+?B7#S|PS5$cmROv4CbpygG z$MKv-T{QVYvT+ioN>lI6R`koOzzN!j&F!U2Q}1EDsk=wyl?GHuUr@6^V}z0v^`woH zlOX&m1O9Jx*}`31@BTk)z4X!wU(jfAI54Wm;_HuT8d2RoAgk6__x1IqKqD|UH8r#- z)2`IEo=5T0k%^%Xe9n7i%b}`M)%s?JT@8?tr|0LN@Tsf~hd&gYWN8Ln*_)gQWH`p7%O(R=^1r^E|- z&zhQzRK5qOwmvBH>GNOp#ocbq&MALKmdte6k6?Fel#t>MmLlSh_{F$hSA@myeIFAa}zVl@S81mFDM-f$G7Yor^P=2P>Lsg4QxOhafge zgaL;;OVxAgsgrLM3W)UfaWW#n%rG6!QBqG-n;Nm66;ws=8BBhJD276IW`GQZ9s|7= zN-2~jkba=jk#_9X1Vl*`OFsxF5jZB686XziIS`;v=&~rE1V90Us1|4G+sG%!!aQ_& zD1{(zB~=vpM<_1&`~gtTF56JRF*W}C-&IlZ zJVno%KmbfV%B22-9Xe{mk9ejcD zG?ARRG(Qwa-G?cW-l&aStS{-OMO<#|3Bm&>Uvb~F<5 zZSB6>#9R=e>S)&N98@Nbh3kbch6Te-FY7q--4HtAbm--rR2?2QPktknPHf4}+<|T7 z^~aE^9u)f%z#OX_1Q7{wdLx;COY;$6rivmd%ZXINS40wqlQh^b{0uU_r{)QHw>tFs z#BBzuPl)zbml{{Y*RatC5IEQ$HBZWM4s;v)1a*bk z?Og5OlgZL8f0mcv1A3`CZ)QAB2Cj^ottK=oFES-Ic+};nD4=yV%s$~GtJMAS{JC=! zFlx%Mm@Fwfq%V+ly@e!$R^!m?;XLt?89GVaFpQpoP zu7eZaDQHP-SOd)?SvG7?`ay?_6{DXqNbW;+#ZtXUa0TL~d$EjC}oA)pchvtGES_<7J#&jAyH zljT(~7@^N%IVypz-hiJd5Y#qMElcz1cjEy+*fa)626?TP3CbQ{=OcRpHR5VOwi89~lqIFR7aPesJc6s>(j0}R%@L+(a36w{HGl2|+TPHZ|1(7RykL_X+K+}NVp|1(ehrx1WD}`_>!*uaMOkqfw*-%(^M?1OOBI zfSoc`{=;%>uuS5!_A>xWu$L^c0US}1!2fg}($K(0>vw2p*Ki{%L($>%j;T9R>*qhj zS(oa5=eJp(H=RjE)>y{ZCx+f2^dW4pVW|HdTGZR4B)YFFv?l!X$cPoL(y)K#g9pSo z5$4TG1@|*KaESD>j=y*$^N+mjQnW*nw9=V$U>p{?rwF22=rMh9T@rfNbi-^oj&0w& zcPezTs_$^o$5aJwX1zP-qvJ0M|Fn!rklN4^RC=%7W+|1qV4tC|T(Zwv0d{l+K-KV{ zLSK~Jl>7MjF2rtnlG(lx>u^Zy-@&}s#XS!!#3<(ASrHv37{obOm||&VP(4UXd)C3=DGwCv z4qY~6o?}dPM!${~1k~~GLu@=Un9MdbQ3{0I=ZMF>(Yq-rVxHobaW^Hu+%cc(Kk5Xt zV$SEvc4<>kj7`J7eY*J&?{6?34n~hL)M9-FJx)OVhY#masSw*3vLElHsaMV5I0{s7 zf1_-Qx+=*{M|eE2zk3Z73EI%MK@0(S=nlGd8~x-%=oMfdNrXiZ?Lc=jF);zT=l=~> zM8m_?X>Vtjj=+Jig6KyCQ4sw6FI$E<0F3{qHcD|JziR^LFE%;(n5k(pH;B|6H+nub zHL1F}Ndh86Z%05%xbK~-a{pg=;*S3bCthDFEu~nS058KVD)XM`^!s0WBk2_f2i<+gD;yofq1DEfxGvO&gmh%*s&n$lh1x0!_M+ zHVz*CV^sN}5EO(n>(S2yM!VbIjP1I|HuS9&21=-)9WUtio-JwiI(YD43#48tDJgXv zr8NrrDna!kO@c@2?DobZvH@atn;JTdjXG~MSfjTfqGKQt4Dntv$-qOcC(SY-dxKY3 zkAo_VOl-9po<$4d#-n2wfGmYfSm5`)576bkmsDi{SzsIX!=ogr_QygAMw9>Xcqm%x zY5#W7we}oT?_JNBlkIEYym@<}v#hL4C{BOiF$TrBLx6HyZ8h%e5}#OLK$_ax8cz*l zpdi4}3F0s!J018Eqkc%s=^TB1S^m9TySShtAUn)Y(zA zbT0f)bW^8(MG1-^mP|iaPLL{p~ewIdq69eq8_^BbyIjBWo%#BZ99&){`d> zFaf9IxkQoI5e**^oG;jCLG}z!2k>PuF8*eCsrpYTAmko<*p0x}ZJ4bKO6gUx%cEP_ zTJ!((doqY0&thXe(qt|s6#0egY|ZWL+#Lnor#2dIjO`Xnu<>>^kg7c%d)MyyfhyDI zc29&nXc)gRO6yVzOHMDlScL}0SKZg@$XUOB@Yb0&xg7Q zVc!n2U^U#}-5%^`pc#$>e;@`cxhgOKxrX236GwBK4OWdB&3pfqRw6N{gGL9IaxF{G zHEazNy|amfL-XLl&{l_$hw!2z(FNN&N=r*0ohc!@aU{Mtc((Op0|X9#hhLo5PGl|n zzVaSjnKLYC9|N$;2chXT?3Uw?9t1+l!@~pY{Oi}Rs%S!S-~=pN6`p!uhGR656M}|x zZE+0T+`TqUe2zV@&U=Wi=T(;4LJj;vT6PI;&lFa5x9{GyaZfCU!(l3%{@`=R`O(6y z?kkp(;geyMzaL}#V)t=20E>`e7;4gOy`r1s+$5sQopm^4o5)*z@8dtEXNGu;ZEYXd zE2gKXyLF%XZs5A-YE}28r{4q%m1wKg#Dv$Z<9vf>dph5CGl+Ltvf)7+Exv!w0weQx zj{kBL_NIJ#c1A(k{)>5$*Jk>6y8+@$*?%F7Y{b}x_hJ<$&qmr`x!d8yp^d3)ZH)tb z<_7%9duB`x#Sg5V@O4w0Z5X=ifZoDBqY?!KOS9k1*oJ%Z?gOw3kyTL0!|V}|toDLK z+mkKugS$B1*3i_8S4t^dwq&-taPnF?aFq|&wxL5wR=PYeJREXV06yUu-WQ8NEpoM4s%#V&um?Pp|oNeP-NIeE|KE@;I^(Jti)~=;+hUb`3f&Jke z)3QrbLu+BKY9;}h>>NK?e-#wTXFbY{3{T`QKjd!+b9K}z>5>#cRb zKGylXzip$~f*}ev*2CtmYCbt$Xu^BrBMes9ibC zCzQj)B^`~3wTX?*aD;mXp)$Vv7v-AFZjM1dvQCJYL#8)#*j|T0yVIo}lSJ^0r1tnw zFTsz1g7BBnMs2_I-tE8uESga~p&=jc$SJ?pgVE&ANf1Vq+*iB<-@{20FA=Q%clQm; zF@c5=DQI9)vW3NU7}mZA7SA->e0?|Iy>(pDclXdh(0wW?s#pS6XICm#SGW`uO1Swi zjnrB>Bo;dMys+UNv`ks#=q~YWoJ>&WIG-e}8)MV?Qh0BCGY~xl^My z{wdtm$)Dn3)?v(sfr4RmW&@~-U(f-f>=wv6{8uf7jpptH+Q3`VpUN(K?q~P})Y8o) zwIPG{bOIjzhu<%~7Ut(UzPo<7TGd$|*_j+0- zkcCbgJknHi85|lqaGghq$?OT0!Q$PnjA}@po!5!`^&%861r-5XbqnlrZZ>=G~bUQBYyz8$A zt+sBmqczP=jvsoCWM*cL&i6Jd8Dj0EVK&@0cJ~eLm0@?YY`Q*p!ScORqR#6U3GtB& zId@LN6gdlV$mprzgJO2cVMpGXpoao+1uyxOMp{y5DjKfto>RP9BQdk63IDmfTZ4XdMl3n)OJ(Y+K#8}1|B*k6*h=*lXlMj<0bqU(RB|>yx7d%r z$Hl_~y7*AE1YAi&&!0c%R?vj~I2_AiamTl77Xv0QXm5#vo&r9f*v~}9N?~D#$~`|) zOe-8d{?sU6)gg`zMx3N+ClDb{ob~)aX&8=@AuHeOoH>-E`l&_C}KeSSlM_TlrPV=0tJ^_^~MWgIrT z5f&D9*hn`yTd25GXiO3191xWEZcKl_WeZJg;pX0BE0aR$eM0|8ov!E|H&`|VbDX^} zjDT}IOFsm~1v(_%hx#*52{aW_zNO`t^<}(Ldk2Rtd(Y8hYK3338THhD?}sL$nf|LQ zsC=h~>Nf#hb$zgB4J|EJc2whMVwe-!!hWRW%q4Gc*I&I#SX_yI9>N z9- z^KkCt2kN?&<3}_S?DaA&jI|i|3KR}nCb69pp*_sIH%xh_V2;F4rdUjy>8#7eix1GH z$$kG3y=9;6@hs1eYPn@hW110?rwyGL%cT>UHf#|XGZCm%&^S>x8tb6}H3ZV-R zXx*-p&psdx?)mA_oM){=T2^cW0J*~w+@RyxhF6h=Q5YpA<8Ea!T((`w8Df zuk${`aS_9VgZt4?AGx?KtCauBfYzE~akcu5AVH%558(|?odKcW=J)%{m~)-C;(_Rv zhL4|Lo%^#o-kPIk<1_sX2JDKW5-Xe8h@A$&pQWD> z*)InRTHIhao6AE#3o))o{(g>WIIg2rqrVc25q~7d5%)1HCfkM2-6c6qwobSfC&8{Fa_syzbfyvyq|-;#JmOIz&Q|%^Db}(ymd0G#p{27xOTl~FvA|SC5|{amx0LdydnTY; zxPSzNItz1D>~#SyR15c7%#%QQ$}%mJNAnVDGxVwRvu*z8r^a`%yr{X<%MHyuQ~P%; zCeY2$+Kfbf6eR^57NPiMCLskRm8j*~nwl+F%9E0kJ}|uaw$(^XOpHg#`&_|R#L9)a zUpjck-#%w;qCk`I02g4*sDiBQ7iSS(EcC=5Z5NuF7n=PqE`U%t+(L|c9?C^amSYi> z8bW!)M>Cxat+=t)>^rA@cLutDes+dSMn(oS<8@skjFCJU;(@BVxf1MZo>+zq7rosE z(W95(RNgY!`xARWz?&69`P78f${)|r`YpXa=)D0 zpC_~$W`fyHuRndtduto$RwyFG#l$HUjtK)yl#amV6lLUQ+ZEV&&y2UPhm$ibO7Th+ z{gyaTvSEeqQJ^Z{x(dZSe|Godh@*>kg8@~rNX-xXE7%QZH&_l4oe%VWtUjzG#@mbKOo)BX}Y-ReqW9HQ^QT0H`kyhe1vxI+MJT#(p><0O}UnbU_W`!IuW3I2Bcv# z6J2*;Z3xo}3&Dt`v(KJRh0E0}qi{pm*^iRebx$-Tv7iR5QAL%Fs{1SIB#`BBFo7aT zLPBRXej29Tb}fZ?0KkccVWh=YmzfiLH8OHtUF?lbMn2{Gco|NucwS75jxtWYQXLajCW%P&p$krfKlsrQp$CF( z6sii`HCecB;N_;Hs|GBHPqWB1!^K0PC=2;8pf8!|e)Kqy*HfZh!%tyqOtj0?&(I1L z@d0{d)c+L?sUW~$`38~>+uB-P&eef zrgk8T9e;d00*59KbNkne;1Su(C;h&yg!O(r&5WvBcK-}!)%(cIR<|{P%9>x zY49B$z#1Cs5+v(Jv8N1S1w|+^@y11jP5yS610kN^e_;6uOg?C_hXpAdei&=$`tFi= zk75JlJs91`AHDthG#u?hY|V5%IFx;4ffmc)i4TKRn4|mcHRsjZG-uFvcEB|X!^P(N z`{_^!TZTIVeujZK1_V+Yx*M_^x}_Yu@1ir=#LgZD^ISyxTF_*XT|qXLARzAav}9Kf zK1WveE?Pyd7btCWIIWMx+l|7WkQ794f`t`$O#M0F#ru~F!IrwOv}{-b?f|j`3)DGh z&!(MlNO&zfc*Ly2(QyT?9s+ayzXv0gf9K_lhd&%SVuM2sd&!_@tr@&kzP>`I$;LN6(X?1b^qC0 z26i!7FN0bbvvuUco!C}~@Q25NK1JtR0aRGnU;AEXZu>- zS5@ms^ZeCYR8r!GIExZ|{~ggYSM&nVc5$)sA}e3$d9@GC=0hwoLW;ur5FK^(APeK( zAZI*KRG^cyv(hv^NG%7jKB~xnRr%w`kJv?U9mB?0KR{5S2=Msbk}nGZ9mgt1OJ)MT zwrM$LZ@&k#(>K^-i=cZjy&qBGrG3Xu^1YhYMMOny$BV?LenmF~(;d>iJ=Rvby|;X3 zP6WeJf$8>&*~xy8NYC1|Kii6=!77;L+;l{w(VllEG8!l}dEV%R*7P$4em(sHaxuI` zZ6t84I8nqB6966XrQ1fNSXdN>X+?nvcS_n9y5-Z@N1&;rBX;xUOqxx$?3|j672cp> z>-WUhCNyQBxybQ<#!t(r z7dt0};@)w)KgEzZ6Tc99oM3yU4V;D`6?JuCcz2X71;#{s0ypiyjwjf zZX}ay?8$rw!Z#ELW|8?hEicx4Tm0K$vqpT)fQz^2ozZam_t=ZIE3Q7xM(>Z^v#oJj z=hL=fe}J{258lYN4<9~oUn|UaFdFVYb=Utw+LNEb%=$eQsL8>D0IJmbd@wR~jAh?g zBSjgf%W01wn&BwKBEH!Ac~s=@mb~Nu5Mc)^0ka80WUsURk~C|^*hvjG7T6H-0MC~4 zTETJyR8>lKZg|4z6>h}DSQI4Z1F#ahoKJ7~vC(HB{3~T~TX47~J~SI+En@)X=U?PUNv)L%!wD1^dHWdb_9F3NEa>Jt8K= z2`~V+p6tK?h^j6-Rudo;;J0S1X3xy`S5#GbwLLxekP;+e(7soN6i#{-e!iqWxv)s3 zhV>qCy9F*Y6xw&R@J&6+vEEnStc{g$xY9)bf|H5wuIBCis!Fe|Js%$-5hf78gRxa` zK&+pFT!#LIFU&d5Cm7%HplNuB4@VS?7=Na!OWEYKL8zrWif)6N|C(@m?|O0X85<&# zW{OE+40_>nW+QTTEyiMz853sy%lRgIZ0O&uIq~?o#OE{L32F8^uZk7YAuuDD!?I%M zUlDK`9A-(q{`O6qHd*RV#{;*6nLi2_t8t^NwAz1cmjLqN27kh($A2K}Iz-QT^YnygYAEXCAX$J~whk@C8%mM02WZM@uq|URzBU%=aV5F2 zY`}oryv#uOZ9PIBi~u)aAUgy|kaf+r)jtWv_bhRaSiZi0U*F#D@x9OKTN$l`nXdGO zju$(D8|?s;hbTFXwO@=-JPot@MlOQrgxxPEVY z8inzzc7l`zJoBq{pWlkB8ROA zm2&9(JoFdAd+p$V{+6f&yl6s{Kv&s;N@}b8MdEckaDe3&1M^mSLeIxf7{ORdKvMG4 zkP`pI2|gjZYw0E*=lcAeT&lDWG)1l1peCk<1rns>U$+Xz%6%lDYH=b3;-1Nzs%8|^ z1$F@>jd-%5w<3cEkUhgUsZSmyi5nHwdAvflK7-@T-e3|Uv9TXySBwLV3`+nHo1622 zE-rS$61y2h@;n?`A8#gTfdA6(uzEXmWg7*P@f6v}QyjdmBE96_^5C#g+yGHQRed5r zoSa;|R@|=FMj_VfgM2T;@;tLiyhloB?+s8T<<@&XmBlN-68f8I*h}u11Q*#sb<9ymU+;_M_6kK4EH58$%pD zhu+4ZKkgbD1+Xo0yae~zvb)HIcEtw^-XeT0YTmrz7&()9Y^zbeZ4G9+Hh;KLR9fg| zTYv!vTHWEK%FO}j>GK-e(kP`zcO}lVYBmzB=I0?vZfvU0dX(W15LC$ zYv9i*hs1}{7Qc!90D7+1>0Vw~bFb>{g zxD2+;Tl}Tk$WM4@KJfV?i-SQ0B@P4#jz}oyX2zN^r@$`hk6=e0#O1-akqD=RujK%C z5~Gyb8_xtT9ikv68U&+-H5cv|FUqC{V1ei~w(;==0A?KtzXE(Z63{?XmVqG3o_Nb8 zf_vb4fk#L2+-uqj1c+9#92c@0NNb-E|TL=&Cqm~My@$-2j zbi}}zHh&br-2`8b*p4H6!>1<|U0U}m_ao$4*TNOzXp5N!%^6+&CEUu;%W^SKjY<(U zn}Fo23Kg+`8#vS~<;F$7sqH0I2$kPT@xIBc;-RgXHop(n;O(OWDz5*&0^34LS@fmA z4G^+sHr1`6qpTuVCAP+p+PlLHbpq9_^PTv=#ajBcUhFiN_L6pek|Jh{P+YT4g}foTv6eFttOn%Z*fVm z9PJoBk3+%ZN$WJ*EeGInDV7p-cR`VRs@`RVz%f5RFK%8*L3EsG3Qkq{DS=qcE_m&0 zJZ#B$H^4R&W!%L%75*SmAwPmRo_gT_r}bornpObdXtJLD{#Vll?wR+MOcvU^vrZd) zsr3F4*`wBOn{PEf9F3fwhMt20jmTcB4;%zw0x*N~0(fh>Ka5vDOMfS%l;`u!V{yxn z#3j4UdF3yL1B^lo32cpr0_r#M&o8J6UjrtYZs0c{SdnkVl%sLrz+|^uV=j(yPqASv zYO75fH{MLoLA*%Zs)K|0<+(+0J=yYI4gQfAUN;D&1b#C%HqKs9!1@f_VpM~aEwe#@ zPAp-5`nT808843zwz1Kve|T5}F?@QTlUfH}q%`Iutvlq=#kk`$_4_9_!S4^HKY{Il z<*f;sgZX1r>>=F&jF1Rb0aq8vi9EXvxZdQoBH5)uwpY!!GXQy+C=lD*PjaMRlpCW` z>&QSY;xm2q!ok;|rm5q_QMk%Z;;!R>y+&n;dvXSTkp$|-M)0rSzSV<+o7`E52u*?i z^I7~_CJylcoHm0J4+n57DA01r&3d=>4FQUPxa>6u0Ano~i~yC*nJIn@=I&&fVQ4hXje-GUl2YdVXYU3lsB75j?qEL{ zpymEm?-Evz-k=w5ulo>(P#N4B{EPUF^+em5Xb7H+S10NGRh9Jppn3vdu^xC6Q7s#^ zk>Ff}!v{=ggBtrS`h_1F*`8W0HkFM!9M5i)t`+iIKEaXp{H6Wc_qW%g&V+068+=9V zEN{CJ>I?F8IRX%p64@@7+*u1##@xa}Yy3UrcH-EPALcxiQj1a%4~+?dcm!XJ2rSkd z%0H292tnrh(m!p+Sl5R+AFh0q+5rdDY(C3>+DreAB;wkI;z8A3+Ztse3a+ReAjNFE z=Tn?@xOaamRu@%3|6yvL44S!ve1yY5Jk2ScaovH01fXyQZ_bv*;Da{eAAzLE?q{Sl z|CPUC;7X`B8tZzzok-msrGP*AsQTqDHN6ALJw2lWSz|6fh*g- z)2BAkN0M2h3y4SP!4PU+y7RW!V!@L|sXG7dzR2)*aT%AnEY_-N91^{ghu26R4&+{k zfT9B`ChKC+US@M&EYqxo%3c$}4t0KhrySkk9)A=N7;O_A8Iu~OV|I8~sOI=#as^Bi zrgjEeR|?1E#5l3*>_JV<@=YzaMAjQM73p#T43A_BpN-+1JTd z*9=+(I^3!XSSxZ57Ccn(HN)Wsqz4WTbgs9nzIlN8aXQaRR$iWy+tUqeV3QDdK?exX z&q9f?(`=CCmM;<(mV1i}#i302GEn}0^A=nWa9>vS3LVdoLyins?6)kBCp>C!#Cz99 zxSyWWte*!M=!w04)iv+ z2PMV>sG}b|e8?tL*3}}5n~2zP9??Z$R`{sDH(}3UdD@A^IOR)|6hKZkDX`bbKIwm2 z*jwGvaa!oL%63%Rry>w`cJ}q7n(pdypmISR_oBrZwRIArBr6O zV!0)0L>;#4OA@c*B~@4wV=Qcmz(qq#dwNbSpYs;Ksj$#a8rrIIU$C_TD>>NN?@-B& z^0lU4_VU{NR*nusk9x_SU7+~v8s%2a(BJ&!@IIMqXdA#|WJl-Y)TSKrP3JnW%o87r zSIS0yn6Tnq_#qNgtK!6lxH-~do?wM}4X&Ikc8rkn9FyV@3v@!o7WFrG5+%fg!<)wM zxdo=);^#&mJ$XDq+Tqf%r++Q!YSBcq0hA=I+3`!X89`(;i1{Vj*=^A=>(M^{(;}ce##u?l z9Dy8L($%CMP4Dw=Lm0t8YHcw6JH@mybzMiyI{xYVUawbSt$j-r{a}ug-oLZckUnk{ z0vez?n0?c3{O}5V0MgO4NSu$UQ5=cb)S_jy$G%Ga@;15iB9>dCxEz5zJO{#nxIr2` zvJn=3w^HYr70@ZdV%Bf+$pSYIi0H2$bUP8P$fWmjjF?zKSb%EI5&_LR$@`lbP~$-X%Od;KR{xzkd&kTd4PUY99&iDr8*w`{Bcn-`omoN<4!P zQfr(UNlajfi0G)G+`G53&G5T|Jg48vmXVJk`@L8N_Bk>+mB!>XbaxkT7kNqljt5wI z8uA9}>nK#coUK9-GYu!t$=sN#>!Wz6v z{^(FpyzZJ^dCAQD!2dU`aBl7cye*@1I}%137<+!kn)&Y>{;&n?#rjyr)@SnKH)cXY zSPk5r`Ig^{9geszI6R=C@A>QCR_>+GE_UBPODw7U`LIQQJ~kVY)3Ea&2qIXiE#9(pJ;U>!_$L-m=Jg>D$&dZ!kGi)p6R0!r48}4}!Ly z>nfqjzUH&`cU8=cSn27}CG8A5-T3%KQwHP3?=-tlj&QGjyr+NQG_QSE>1o?cW0?z2 z%sbhKxOL)oiJzrOlHXZo<+!K0d9rU+Ynq86NX|`FY}oo)qvHDKCg0l|)-5epHR`xN zPfz=r*Z87uuJxq;%u>tFPhQk}jA$l057+gtEdLmNnjiSJ!)@TrS|C2P7$RN3^mO%a zqd&@fQVxNhdR&(7j6f`85e&p9hoTbmT|g`n@Cn8InzUC$kD`&bb2lIo4NVAtP}ou& zO_I$$u;BCJqOeWA?84&UsX|d{vR|Bai1(QN)T+mTy%XndHqpy2IZ$-J(Vy&=(_y=py=PxSi5JTu#`FtRW?b6|YZ zUgPqS<2yvB z-mzAcN0v|SrpglE^3d`jrWC(ja*HyKl_~yOzUR)XwLjC}53O1+0j2!jy)aULHL@LdUZXvRT71?jL1$CC5gEOvNog4Fu!_#RJ1y39W!M zCJ}(=*r*YtBtlCDbQgX$?<@IBU?1OH$KkWC0MQLbXpqKU{akCwvwrZUfo@H~Kjnaj z{0Dr}gL#GLbc&A~#GgveFy&D9-}cjcOU69kEQBLe=pbq9!kBhSQ+>#SrmVu?Oz7mQ zi?!Suh+{1g*Oy1>&GV}xBHyjq^v1nnm(eP;@E=%qu$EiB|Lwuv8k${aC#FLjXH2Yb zHEetI&#OkQqo!Vrza6c;*N>b#H6FrN!y>u6xUlb^hdX}AxQ89F*z@z}mHCkbzKgHK z#?(Go?0vRvr@eLaXR%vu&f>RcO3!`q+4T2nf6eq&xHN1dPKbYdYx$OX?aI9Q_z&z3 zb5|EWF1>3I>g4|G8I^T$dq(!|!`^htyOK zW@&Q#{u(-BE-;@OQ|&&+W5z6!*!tLuOuwUMDLJ&Z!2fmY&2#m_^bFiemI{tcUmub( zGxJw^t`#s)Zq6#c)ZOmB=r>bd_}b3LXS7|@UE29&)G*rt!BmI7;=?lKR~2sypQ?Cz z?2S)3!{ST}*2Xp7!dzs44jnZ}E!zTGvv@|@-{<_il(BJ8F-5t^pFGco_T5btpB7L> zLsGSQ%v;W`lGd=})b^GRuYIdixR{aB=@d4;iO|e!qj}fvwru|x(`}-nW9fE%>mBm5 z*2L}<7DebPTR=4aU#ugXB0;dg2(TAy6`HX`S3C)9$ARht^70w|kr63*m4cDIw6YkZ zCDCz!YX?;<|MC-N_$KJKL{Wj*wVQf_}soz_U$_3>l#_pC(w`rNbE zmF)-+K`lko<=ss_jrgOIncL1;b{w@h|L8#E%5?F|(~99dybj>#{-1;A3UU!JJVVyn)`4^bAjF0;jEmLw}p0^t1+fY?!PFjtL0l>(vKzh zgjiOPnDO&V8rKBZw7pR|PH!(4P`1<>JntJ%<4`ekp z=7#yTzY?=f-R5>`=AK+zQks}j$91|s|@UO zT>b;+1I(z1vXks#lntM^6fx?^l8++8Y|YFM_O8+Fq{C?%33c2voAVL;{{o!Znys7f$X$A!I4 zqic^s3$2+C_Uo8I%McH_8n!uLi`-GkHdY-`VXwwo%3(HfVd=M-b+nMe(kOk`bG&3Wi42Y{s4|i!^N3g!=Ca zdmJbfBbFl-YxXV9;wXoZJjtgO)Lu)@-;7x>Fdkc%V+wuolC<$JWzWBYhG<Gwl;j>LA89d+A2dN)sXtJA8nDE~M2L{7r+7juj0D{j&p zUfiww+g@HB=NqeX8E=goXDYOdNt$p!7+{euV{W~osl8e_ z>%A)eEKOZ~CcDpbuZvcgvt?T9jq=3So2U2;vz>d%f@D12(CrNTq1%jgk@#gcujf|e zXH`4L^|O_`$`f9N?MAhz7BP+PEO=Y<;cjB_aq}TZYe>Hz8ob*Pel9z5Z|)CW{=IyH zwBT0pov_A*=siI3j7d26Q1oh=QT}Q61A+Gu`AH;{{e^MC zj-lKeKffh}PPLmxuG9*49B*h+Vdr_cwA3tN*f%}+btPBlscYkqBR}OyuG2wzt7~fQ zYj4E(H#%8PpH8v5mSYkzxIA6lapAVrKIwf#?J}m@PqvfA>{RB97tN;?h5i08YogkCK&+ajiq zJd=nVpGolPbv*Ft-mRGZ&XasHBBOUGcof0f0Mtihy5LKE2dtgdrS>U-WrJ%(u-&nW z(7i)ditqgW`}YL1C*+Bm3q7@fB$$oESOyWG5?FHt!vOH3_S=VHG513X3mGKhPhIRh z=Q5@}_O~iH;=abUq~G#eOR&qSZ+y{4J9_>J$=2${0{ic^kF~Q=WVCe^L=)%NX0!#C zjqFssCYpjrzs2$QRGg3H?P(M;6=~f*UihP~C&5I1q?yNJ)18z}29@*#S?qC@Mfa{k zBlhIf4--|^-yYqn*)w4|gbJlxTN4>^$ZL7F#m2^ZuaS{X@kAZ%>fZ*YnGarFx+NpS z>SJ%q`nqXJ=7&{Il))>XKA~hdu4|L*9kD|I`ISVhrrV^VDu7D>mSc{5Sy@Jf(U!3; z7fh_GJ%<>7Y;OMaUfRE_r#RWRUBooxd|UrVzOBD>xS9QFL*w^JxWj02 z+3!F3HC;o+K;721W31JEyzTqShwiBYE2@!t1;^aq?}vxKa-=$Bw02~4_Y|v@dwDwE zJS%L>w>>E}?Pj|3$aBSw)wIE;$o5MQyOsgKu2Iw+X*>0GweNeZTCi;N&*F=nz4fiF z_M0P5avWmSqLpV{Zr58lSy^-P832#?RKB?=iU|qq=9@sl{$U&j36@Fd5=q6xS&t1p zGpZgilz`E{`_EQjN6-?PFJ~;eDT3S$)QE8ZBK#ZP+y5d%^CWw8P&DjM?YliqHNvCU zG~VCb^41|`qoT5?k}JGl-~GWYxMOs!PEG!t=Gv0>5B3!0#YYEbo7INDUMeqJ`Czo? zU5%RY*U6q&N7Ey(XUK_(3Yne1aR2Y!-Lw3>goY3K2GrP(fE~fp{`Rc@MzH9g-!Z1u zabgNZZmup$61RnNt=d!gVkJU0+p?t%-uk^#@NaZ?ySmnTaYdC<|FwbQYLb%qc>6h{ zj6HweON!@PUR|qVe(CS8(o=dM&yeB51-_-36Ow6}7A?v>@2IK}#oqo(p(kT+#@b)C z@GFnD#Rk$g<=NUe_UPKRY{D$IZTR@%?+VbJymB&+}fMpb2{P$Ze$i&XG1l-OS3z z4`ghFs+!V|tnkOaTj)(<4NbI%N8UU#p$YI4khGxwtBN+hlkklo7QkTe(;RyAdAmR^ zm}bw`;LLmp_SG;|QW@j0r*~KwA zN5!s@^OO^(s8Q@*rdlt5!%K7QyUAp$z?d1n6)$#G<-w<+S-ICHRkGX^+3$`?N^%|x z>f|r5Rl1rNHfXLZXk+DUda&Gi`@Q2fjqZ0i)l_TgRU*HB9a)b1aGQ~eZlJM5%8;4a z%>A*|Mrrqt3~luyV_W4G{mE|rM;o0ItO*_>Yo#se{;Gj(y}e41sPCzfWMC+|n`c>;_>ua{Mwclee;2w?p)7dL>Z0}nC6^m~*HB#EW ziyPxz3fX5Ryh|2(v7Tq$Yc-|&qq-`gSYAt(aP~OpC<`Lr-VxR-h-x4y`BN*nE!|jh zw6WOL4h##zhx67#l5(oMlETROFQg}Y_sdgj{fu~-aCcCiA}qthbDh6FQzC`5kalk6 zeE)WPmA_8n%M6+Np3K^Mhugr0Xj3ROgkPgN&rVH18AsUixNGMa}<2U(|U2qrWcS z>)M6`0);W&Fia5M=Fz@N7f%@$Bd%BS7(Czx2 zDQPTm9qE65KUmEFk&#ht+g)AGXMEKrB4OppDSZ`{w8c@k()R8nHKFlA)Tzr(%+$5A zXmoDkUcg%JYzS)&X8WtT>3_k|?SL_OK|ukpixFdwf~%t=(Hs%mF~mZH?X2rgbs*JA z>jWvyp?fk)Bh-gUy27|V-Et0jwPTs|j>g|EcI9@dr|0gnR9MUB_zb>UdpI}XocFq6 zLtZU@?!SX2izqSY}*inZWpvx}Sm#5s0`i$rlQkM@ zia6(up*9D@00x5`s(oV$Pvet$Vx#Fz+=duYVXJ6GODZrf?4X%x7~wJ3j>eVzkcG0( z>u{>ZVV)boqnF;jVcx^lDxP!cVCw>l1 zx^|LkZI&C84ecVk`G?%+*h^>iuUuK`eUJZn?rTYvhy1hoXyImu3j$6w%THq8X>1r>*ATx`k{*L>7_l0MSiWrB0J_Q)MqvQ65DXM^Hg zC1B@A^`mI%1i8=Xq<_6FxpVz`VbS0llfTbvDsdPD?PRGfzmT*WnUie40mE~1;`16BIVO3^1FnP z7R!G)Vc&o7-~|?uN-g1rm-9yM$!qQN^SjblmK2oOPIa3$+3;f&zdAG++~Bz*V^|hD zm(y>N7YtH`pMDmxTfl-vw0bCwRu24*>mVVNv6QPZIcJkgS?u(|(&KmQ={YPdGYnyFueS7%!(KJ>3 zPTSEh%XW#m)3=mgH@pnv8s}8{IYPQ3ENVnmvg6K}_p0oTka*#rc@K%58kVif<=z{T zAn;>>N5n|uz(w^1D_Jl$@vD%=`#n68^MU#69U3Use!Dh!VEW}G9GdW%_DkAx?&Upy z1s@!>2wXQ^=lT!wTB`JFXL+iz`n=ydwb2e8*wx(%FP?zKh@BUG>G4pk(WpD&&GBJ4>#S<}iMZJhY$82Le(WA8-~77s z|GGWyO&ya>KW9g-<|KZr<)|tca|BK2(>=OdAlyG>kq81EVcvIcNf30$FuLaEX0R7; zL5?Y8R6uN}Nw7fI%VVn>D6lM7QxhKJYRleFNEI>n5N|a%27^zk3Xlkv@yvuzj$jP>rzksv$#U%s#pP>QA*J>y(EX6|?2E{L z&~G4xs!!yoVB*2qDwh^$@y4)7EkmcrQutLl=9`8q~2tQHP`kvOI3e7dCyq% zRRQ@j%bmUa&1^d#wn|Mpg(Y=pc6B82YrAhK_rGMkJ{6?vFT0Juxtu;@R}brcW%{iV zm-;e|y+OK{P5p&EMW{0hyd!MG2RM4Vg}=Xz10zHkZtetCb#r|Ml$m>k*&L`)Pw(r| z5LC=+HZjQJDN=;5f!@`CJ-%IMo`ueGh}lt#5mE);4<#Na>e9~>FQcc3wE;J{a1>H- zh9m(sa4#6%Pr$4G1K^u{w%2234)mYll}*sV97pQeJUu=4N#A(`QP>rT@=BIEt>Bj! z2C{$u)YRqGZT#m{!`Uf4??oj&rwBNhddp}c@gB*BFQc-+@0sCGQs+iqhMd`xtVYH% z8rShRETDnRd6zqNZ+1@UoDvPE5t)~MQ>65e zNm=5LURc2Jf^nlTO|^3a6_?T~TX-)0voZD&y-FEYe)5Czf4`4kGdt|$By zOFsMPiL~2MFj%P&FLf3C$M?heZ1u-dcsm&B{RR~0e{Z))*LdN*zK?mMcg*iv@&&0U ziiU>Isz!X)rcQX{Kkz`R10Uxzsm~YbM*g_sU>maFUD=7B@z>@uHKNbd*{7(*+3US# zBdp#0dI`p%KI3Z=ERPDHQ#6!c8%s|x^u$AEFP z&&{%W{kF0b^ZUQe@ox>}Iqigh3}7$0 z8-QgmBp+nE$sGLFU$k02#WzkEwvrJ41qM=qUILM##A)+3x;?O^-rVO>_^>SX)AL{c zmyS-7w2r*tQ0h-t#Z3A>MU5s&g||{SzsKNc26aOxSo`)d|xFzow?X z1FRuPY;dZ5xbMj6m&F&gAokr+0TxT(5eiDj#w-ZDK!BTFSYX&D5V))8ej+p5Y3|nn zjp>CaESf1`aW0R0vc|DSG5kyx`NetkZ0wSn;MhP(LwG1WW)nzB}j{g zD|jXSbv=D<8IIld->134gJ7cfYKL3*Z@*MY+YUPM9$JHHz_Wd17$O($OgoPO> zCfAXUMieKA^8SD>&QhSUC&~wtJE0zzav6^j`=>wSx4r|~XTqrr((!Zq&Pk3EB8Z(_ zrI*7vFn1F}KEbvH6ArV&Q@m0J8!I4M5(dVXdJTn7K+_HW4h|93BZ4}=vqxcG2n z(Vq0`yjG`iJ1DY`21ZLS+Y8tMw)3z>Lj=$FP`ef?1W)9!6P!2j%?O7P2M`A~QT4R5 zW<~f6pNU&U40ZGU$NdWX8Nhq)j(>-05RBUI0PRYaA5aM`Qe0l$JxT8`Z;vy%wLa-qK zZ{0JH`M8i8VZH$J(y#vh3V^caePuG>TkQEKgJd*t;7m|4r`)ch^Spyd>3#vuY$abR z!v%j4)`g?NvQ?!Z@mKC63r5=JF>t+L4&eLf(M}MCVa+0BYJ-*+wxFj-cr~9tJbyEO zJO5d|OPTLC)Q0jX>uHr7HcD{$~zsEQO(6;ecsd2vH6%`F#n=TFoGT97r zKLIb1(@AUnx=rlkaFf9RjL}d|n4*XW9hBHgi@R`K;u2CQVDG?um+)7|kVlg)xf>cU zB2lf|;VT>bUd8@+{gK$T&dfT1*@xzX%vwU#zoE< zy`Cb3Z5z1p!~hAt@dHuIosF2l9Ji|Bm6`nS3yQ^I$?A9((gCz38-2~8Q$o8Yz0jyg z#7n>}9LwnX`vNnIPe9Lv1QL@9uei9bQv zG6ymvaGQ@nkA`D!2bQ`)p)HYV{n%3Q||ph zz9PY~pJ;tQe)Q3Svg^Ai{)Y>2LZnb0%OyOa6U1XA+|hCKIn9**r8#_Zx8sdrylTj& zBkP5+FzA>dslHJ9moEhNXFa&!fi0|0K(Pk_e(XKHv!-U_L=}|*c?k{D;VbDSKIY!A z-`aTWK7qdz5r2Ega2O6YQZC*Dc!yKAuSd2Fj`;vs9>ElIRKgJhRE zUs@Eo&eY?OuPn4^K1He_Hn(ZkyM3=iHbO`VpgFpR!{Z6VP=YUoeDDEKcOf^}f5Mg( zwF8^l``I0=`#xyB{zS9TZM<8FpK|e0Wu-yvVt(pLP?1rjnY=gjI@V+zhH}9&2V%Qu~o>1vO)UeR(e_cF1K$M*q_t?20H-ScwNyPY4 z#(Zp|E$2l?Idr>l(Yuzb#QBn{J(n|S#N})vL}v~MO*MX-hkU&9vQTz!Utmypbo5#9 z-(b}!ZqXb-cxzz<>#}s38>m8JNi)>Vs!G2C<(VY~AeRSg{Rq@rL}vt9APmTvLmcD@ zCK)OgVP{0da6m-Mq{Je(+)vK#F?qz{$Y>&(>ut#C0XYJucDP0qC6zesublCHKdzt) zvvSKP;6ELK6$TiE&=B)VORpDHxhW`+;#wj}$!-Ld8R zM6wSEImA&d?3sqrfDjQvjd=dKv;noVg8y$AU&C!F5Rc;>)?mMOQw>9ubV6@i!A)dO zA{Ry#KPJ4T8xl>CxP!YTC2{>Dx~Jj=Tz0O3v`^SI;HCopc~#(v4r3)nKa60roWpnF z)P@j*|2qg|Ah`n-FY;9PXgJ8DW`6{MezMHu(xqzf5CfB0jT3`QVJZCe989cXhbt)r z0y|+?0o4yG=Q0*@goowhJc43P$bf=_X(3PYOzom4yR5}Q{D9fNe-FbD3w^1nkmQ{^vPU2dc_qt^DypJ`dv;}d_`ca>$iHS5t@#FKLeqQ2K$i*-o{|c&EYR?L@^bx zG7Wi-Z`B|AHeKQwrGc86Hnk0_BejEMtUJJSKpO|1R@OeSxGnQH3=47qDhdadBu>-+ zOA!7Iv=7XD6nEm=5Bk^I`jZ3f$wA($#oIRa^X(y@jYVegsIqgHpl~HZ4oOhoN^Gtk zq9{s~-3^Hr{3{RwYX)BH>CaO8AV%#5XB);0zF;|`?Z5S|(-j*oOhwGQoWxLcEuabK zYoli*UH{PqFscTLymlLyE zE#WqaPz6ZoTb2Sz;JC#Unne?M+E+hIIRCZjzxv2voF$sT%7IFqf(vC9`G&MzXq+I( zQmuL@eLLUqQEaSHz7JDxZ?DVd@){s=dso+6Sho^P*MWfFiNwwgwxNN9gbGCg*1aJy zF)?F{g}v^<@b>)0N2U0>oQwDbi;9V8(D5!P#E(D%PWZ0jorkC0M|86gvt>8SA~a?h zPNk#}>3p#%yx2}zR9Fbx=Z6R3sX!>8QSm_qrI1JWsXoDy6@F8*nSZ93|P=$FL{hW$3U6~q;dY4_yeE|`VZm> z%YzOS(__;m^YxY+tkNR5vN{X;Jjm>yiDLuO zT#Tsc@Vf@tz4Z=azn!89@AK=2w7avY^6lXvlMf}|eNeCn%?#L)D1q;@^M5T}D)W>= zXGM^Zx9{cs;o-YWn=}J2E_tG^z*BLHJ%-tB3yAYogxe;x5KZQvYibBm&VSKMY31{? zvlX8{`GfKb^L+$GL2na=a8UFVB<5WOL@o~NsoOh%RfBX)G!^>*$UyPJdH66=KTSI;kyC97LPnndsr7?3J=>V|qw7N8`ExXE zh-cERZ8N&sa}Rcnz-i!89odHknf2<&?r4ICyS|Qt8llJ=KwQ2Hvmil=A{l_?w9^QGmV8?V(*2280H-C>nUA${$q-Ld#rrz`h+sTUh_-3zU z`ako(5`6l%Ht9gytYx^f)L|(rD()w2)c@k1{A-&lHWzR5PW~jFDWf$oC}c0pZojwF z|H0m0D+!SZ2^CF%2^-JOA&6|%y1d*bJdzL02 z6OuZdU{kyBgu!n&v=;q6FyQxZPD)paea_1U$|b@{oH)LR4*A1<7Wb9D@Vg+S<%tIS zJVb<>J`aCOuDom1j9;9gNbooC*$00A4#>(9gsX0v&_6K!BKX!QsPGVjAPE&s9(qt{ zFb1%Oya|{Hj#P~hzT;K=0s$g~@kbVirl&Q$y=A?$Le}cpV3VTgW%}0c6V=KKJ%{Got)|K0S-n$2z4}=^dz@cdu4`B{|ud!6mE9w zE?yZCCh^AuA4V!_ws+?HtH&mKxCZ&Ww`(xDc+tG=)t?zx#|Yb8nMW)tdl~vX52*|2 zDuz}1iCpgY+4A4q__*#~-7OMGR#N&4EH@6HfVG)>dk-hR+QDk%-DIx%WpHwby9@=T z%2ZuKUHBpU{<~Ahzpshg)vH;Ne!fo+!6l)z!{RX1@)QvX6%2fJV0yY9QA#>IHYZP0^nj3$$|`ny@)Dqx z&yY{3M_xe9f~-?!9aD8${wBI}BrbGw3k`9EqkMxlUx90hxP>5;Ald>L#56-a0pGl; zISDj95SRxS7Z(Rg#?*ZOUe(%~f4&Q#n)S(%e4DN|vqIqmq_0g%Yq6G4(a<>F1BW<= zrv;s#ibBx_v`D>xQY{Xa{HV|!Hb&E1Xcz&1!Niws_BqL9&2&czsHVp`}P)}An3ilJ2*T!^XCvU|5@IQ z+w;%%>T>44eRMvX+kLi#mF&OoKZzDK>hs}>>TvA?r(9JF{HDsjO{u5{ntJ;Vr0%$L zNBO$c9j!gpj#Eq?OC2o5GDaku8+K1lG4I){=EI(QxjjeGT1a|nUqFCz(_(>5>Ri`E zj!=2^z8ySM=adxAKjeP1w&;JNmv05;%;8BRjtOnjiwu(;hrFo1B{vN%`Uq>GyTS|+ zD4(;<(x$dqKXV+&mK2Nt(d8o+2+@`5lwnYKSRC7EHiHyMTrswGv8}-&u}kW zEK#N0R|CXRQ(u34@oGG~K;hW%F!CSYT zO~`~W8tmKgk9N4Xfh02%6CzR3-x3BqV*3DtpHS-7ggGS+;Qo`&d=Seb`Uu~@`hH0i z5y?}hB4c6@2zZE_I{@O0h^VLlD1-vd{># zk3U|nuCB203d}~sb7RS>jt*V}Fmdglo(_TA1#HBQToyB0`&i2{%bJw>asmQqt}dyN;lb#{bZ&-JFkCH4*!L1q>J}&Wquyd4fpq+`;Co-*2rq~ z-C~~cs`n4Y{K_d$`MR-&ye-v?A)ihD2j9DmyOsj)b+NBi1_Ftk5WVx8J|kg3_;?-n z;d4RPsJ5x@Wm8ZnT+07o`pPv5Rg){-YT!F6*tS!o%y^Tb{Wd4PQYFH!j6^IQ$&j+&MhNf9ii zCU!V`tnlm!AI2=8j6VivJ!TY{OE-bwu zG`N4DB@b3NlA0Q+E*U{*rJJ_B0 z0AXQCuJa=54`=W=cxgZL=->QgIbQ}}0R><#{6=*_ zyM?t)&Ri(^?;xVGgu)FK}?vm7zg_C5D`lNCd31Xz=7NI;H07~won?MIYR*e z3oXqt=TR*nJMguaU<_~{eQ{6HbNS78hgt)Y;j!f04Rq@jb#-+NjG}@rc_mZbnfspR z6DMtlJWgrGPKA|@GOtsZfes_D5e658*Ynxrj5b+j5###^lEd|^XQ*CWHs$~P$rECi zYTlF-$ggLVp-V(CLM4h)_!VtD*hVcNu%Ly3Y!nmhF8`16@aw~A$Kid_X$(toxFFvG zN`(6mxiGkMZ$L|2m`BLwq%qy5bqwQ%M&!9or+FxDS15ceuVyW>_c_WPB|bPOXQD0# zE>7$up4MM4=!|av8=G+b*wLe`f7WIv-!%|;cP=vGh*TPHi25AJ_EK9KBr3`XF)*_U zD}`peO$hTJrHLjp5y|B3i#e9DxxTluGUc>Wg3qq@*D6iJxuSnmr~l4~D*bNHj^tXM zo73*n(9r&U>8xx+macYyM?GtXoxg&rdP99Qg|Kq?%=}1dl>LOtnBYaBLtoms+Dhb7 zVcWa(g`Eu>-yp6W6*(_MRj2aDIoTW6zJHJ9>7eJlu}yl*bL_OkjqR5%UL5l}`e#Ik zeyg1T?T&qxXv6C-&gx(|IoOV<-&>8sC9T2KT`|bGjz^e((s~$ zE$*=gEpSo2CeG3XAZ%p8T?Vok3^|?WBPBH7Hq_L-Ev7>DD$JxOqBAlIRoR5?P9f+v z_2%2S_;_`zGuA7owWMI<+Tc$od*3AI7P0IH(v!MW_u7(>A_L;^&FnDz9!}wo#Hx%z zqhWNlaVOSZY{CJJ1aj%q8M=lH$|X40P~CilIboj9ADkY-HTsI!6W$sK%|EeARbF*@ zPUv-^?nk2VPoe%haDE8>3O|{&hVLv!$Df6MUH86v^@X~TU26j@K~)z?;Ynh-r+caM z_{TR z^E@Y&LrbkZ>ao)Bq|l8+aWaCbDTP*tWpbM26J+1G=TH5e>Y=5R=1iSCC8hFs6(-;& zTNg=@+v?8OSf{F|m(_}H0!csh07c+0;q`PZ=5hQYw57ZNkI?5L7PY#%8gFkfrl9|l zb$|?Zo~L{KS4Kap73&2Ap{S)wU@J)AtY}qXr*(sWZ64i}U-_#aO+k5tqacs~91(;c z0Chc|F+bdO!QjxjMT#N9mIk=n{!){FJ(b>GQ_9$$JWg0KVckZw%4fSRc}t&fU#Ptz zdZ@}={MqLZ=am``>kXyXG8kvQ%x?2SNBbNz9ULnKeiY<4us#B?AO@xcc%{T*ADH;- zB^3!+bHxH;hCd<-pmDi(>8A1T13R=?{xrya3KmthXgL|L+dt8q`iFMGrt8Y5ZFgoB zEaK;VHg&umc17$nE;!#wb3Q$i>kCAJRv*tjifA5tbk^cD24im0?P4yO+yf_UqdNB; zKObbDp00L%ZCvnWP>hh;dsSrq00oMiG_mqg=l<3gX)jb0M4X-+SmgJ}n%$?{Hnjogv&PaZ2a~KUC7B++n8oqRV zpRho1#NzoVrMrekh|&SFHE=Q>`fN;?qP}9g$>5C%gvG!EFo&7IuD^i4^j88@y%dR@x4aOgN1Q_1((qk?}}$x;48X#O4rx zQZH96RX`4LB)UiXJ$;tPG7;}J5I}sBoZD>0=pbLuS(1T zK%OV&3^<{~GHmMiOLew^17-AUiL{x4MQ`Yez5!!2fZYtd2_;~kbgjqr`MY-vJdD)i zdj<8C)piL~WBpWpYNq59=HpKYc@N~s+I`O`;8puXmiYMftZ_G_;RY%T3xWE#hO84L zgS9N3FT7q32=0oQuB6KklT%0k?C}elT(Ro;rvgTV(X+oJHMMnhKkwC)zK}e?s#>7$ zfr$Ie)ZLdA?-O7w;DNHWeN-Q$!pDVeti^7+wcJ zuh5K~%V~ES{fa1{*%@J*m&Y=oBtkrswV zN)fAYA}%W?e&e#u;^5er%FUZ;{Iq9ZTV3smfiD&k8VD@i?2KXxCQc$z7)SXDhVWy! z_rkL|cmEK>HkKkKo_EJK|DTu7a_$CXkL8Wl@jt69cMJQxV==70`C>z~nKlRXTaB_L z7<_v(^#q}@6uupTRMCT?qI58E0%+o1cl@`?eghIXs1ct6Yff}~L;njo|KETf)*QGN zkn}>VlL)#HAUc9`hS&#CEC@Gw@b+FRDX5{P20-vukLyfUYxFn)1mfSr_$%o;&5AoL z8Au%XEQPwJfN=?x9pJkV4mk~A^8PYq=pDaM4mWid6mPid9WQkG_Ag%5I=x0v!?5%De@-1qFo`iP^L&agGZA@W{k~L^FmnPp z29OPevF~thRPRzWd2jCvsy+=34S{6-2avJc1=oX~jm>7yCa^ogVFvwpXMSA~N7(IG zgn1uE#pM4Ddp#bXfKCi+rN>xXA78$XbjMlj%!yHN4*UVa#jZ&A&*@bCrzFng*GP80 zVcKV~zI^+2Y#BMtUCArr_S&)r-D#yCZE8fH$K82*>2BAcfY=BVnGDr? zZBJ7=NpdREQ*x+qP$IOd^{|2=K zfFvahEa5Wbp8XR!Uk2~BXg=z?1{z8E5tsmWwU3x8vTSh!1MYRp7=gz(_K3M_WqEnx zSlI=ByuzoarOmYdU(6x80L;f&ED+`>d<@`A`N5R_DCRW;$H9ZE5(!bLrFgSR{?C}v z85p#wb(m#w+{M}ulof2SzQS@F-z~vb(Dni}AoDu=#Q$&s9!m}X^9A;p#6kz9a-fRY z)C{E|MB=V;zxW$Qt*6_UCa)c2r3yHt6rjnaWY1W^mFP9MReSBK8}%&tO>*D6adR^l z*4g6?$}d!TO;fIt^j0u&?%YT7P1x2|LX1O~C9FmyzUWQVI~N+7J4^))koB zYjHT02>$_lb^wlnjGGQxCLU7~KzXSu;0jg=M?ih60u`eREy^a6SU^i(Kk{wS|l4Wyzs16$+) zfD_#1q2=Y}{F&_kzX*!nOOB^_qhOSU*pLcy@y@BNh+?ZYBjU0EqgVyxQD}3pw_$f= z9ZbG!a&y3VIDB9$IheASL;hIe;aT1{+wZ)*B!7!5_3n(KYMqI$r(m#Ph0k46-?|FT zDlZ1IPhr|62gq}nHFt}X`Gs>e9`zv?B|Q*awc?QSW5uTGnk#D~S@p3AL5^jr`=Yjo z*p|uO7cajpJ>Dx+FnBCQccIVvr~?;(t(v2gC0(_JQ{!86hXp>+e*2(ba<~W{w=Ze6zlP@|!1s68c4uE3tnz7y`99zn z>keGogn|J}Tm-rbU3!z)_KuTiCP~sX;$g|?^l1A6mTB%hjf?Iw|6dFsyV=|V9vxub zB?G=pJADo%oItBk!lk99iEsOaZ8xX5cof!;xJO`1`{{}p5yXOVh#-?3Cn6K@mblG+ zq*8B)2O^KFA=n$m0sS}eefasEZyf^X{>D2|Umn7vi?FXnl^wzqdlTy$Ow1>%A7ovU zj8+ok%n4~C)g&=Y4qOI+4wUZa|mfJ2#5~rX#qoEi?B1cy3q44pnjg9z*hVHK*wI|MPi&oC zp5a171;JpQhMTVP;I4p=SFWHthX=+!tVi+Ou^7B%)tUx7EW*YfR)UshNytE};a(UY zJh_0{gy?xSw6;iUWnf^qRO0>b49?Hb5At5sO(S5MBN*<}zBw z&r21SG&dNYv|oPk-HPgwSRO=%eOGpQ5Q%p zb&7p`UfO2PUvq}UUP)l}=4HOuFL!VZF_mk6NshaHJn?RnP~+g>;0K4ne+JKoY|o^W z@|zwS;)%O(FTACz)iS?o`nX@F!sM+Bf$)>3xQmWb-y=^)D}P`e!HW_P=E09>FOsBM z25FFl;57qZm1s_1FU`*Jcu{x#9n*-O5(r%UP1fQp!k<4pG|4%!eK>P89p6P7m%U!c zMMWYs!>(*)TiB9vOv8xFbJD8QGivWfmJX&m77E`wKpWns*Kjt-{TxH^z@I+{v~@RW z`@K`B-RQL!++v*3N2KX zjXjKtV86KTxy%0j!@ra|dw4_>Qv|&A9_BwMcB3%0MYsAJ9oT>wH^oUzvmsoKxVx-8 zC$54R!+2W5u6!`$6kg^4Y%vH+O++Tj;gZ6eHJFk9JkzBZDDY=oo4Cf%J7#@Z&2BKt zZgoYM3zaJ)8gi!km)ywjB#=A|pmRXSrM@_l@Mv2u7^YBL+odE~)P*7;6LscZjMv$Eh|AX;5Pg>6)U58EYl+)IwVcMlzY1}*| zTm?TZlecTvu2vkK%pYdeKJKeIC+Qf*wfRxmV7rX(ud1XTb~>HhxGVN^UYX{v7OBIB zMZ)O$r$c;yUdwjJ|In+(L_spz@h;u|A95`%t%^gT(v<+1La>Oz=X`f*!YCGO;V?V_ zSXiD0nKVG2xf=~TU(#>A3dCkt5k@l@(J}P>0>}LI+Sx)8raLEsl~QsZFSA=LNj6Px zdffaQO5PsE)!BA&8(Vhot)A)l3WNT$Zxi#G`lXcVEu~65?#w+JP@$L?ZfD|R46J*> z{k^LsN94Hmk#kqmcZRi<*71)lO+Hp~6ip#>Tw11jACi~WCw)h}`xV=V>>E`+6IX|f zJZ>BM+}wE=y+khjJ>d=cgaX4!PS<_mwoGOWz^8vlDPQ1xJ&hvL;PtoXD?X$K-hLS4 zsmIfg09YVsxFndklFzO&q3ARMfVi<_ZISQ_thRWx8Ye^M3TroUz4xs%C2KP0uOgP5ful@=xCG6;lf#P?|#8>I8CC82(^}|gShMrE*6Yu zBXIrOvx}ZOb3f8-aCWbyZ$H>biqAK3pTQM`Ne1n499a~+V@ zpo1k0$ULS$q}TtvCC;K=^~>bWFUpqVhX4MQd$3}Mjsq)O!XELh>x{`S2H!*$BCZTj z0VtZ73lFn4-=()|WFrSx;(PnSO3KHIIqgQemdtAj?Op^28C@3oYQoJ9(H6*wF;2JM zK}R$`XK8#z>lYxOBTR5138@{(MM_vt5{^0YkC+zrL?r+(b_6pt7eO@OK;oZ< zLAlCwx?S5e54t2P9bG7XWu{TgVUOK?u>Cx+5D1oX))OfwUgRYbA?5=W#gAsLT<#}K zfZ=Y4je8u-ZpAQhvrMdw4fyyO9kcww2a?AZ(eia{vE_tV2NEf^ZF@%Hu4mj&!)lax zN}Hmz2qcs`1peTrVwqgdS}W$HaOW9=*D}zr$?gwCropr4324OeE2d!u3L-%QzfM~J z@Gvi{{=aPNYoDnJcRm1V=-K5ko!G^{o5!*Q7aAq*L_(pMHSjW*-kEsNkB+uU!0-Ai z2u^h%!sD(YoFfNFoUdTOUdGh?^rVXbVSnmN#h!?DMCB2e*}r%2X)#q^q;{q{E5dNN zz;G{FPZKe$wSs{BI0ekfI!CIaT|J&*nOd=pP=wU#QZ=@CMI1 zjEB^8bmbLX%X#Ona_M1l?p5I<07 zd>_z8@$JP}p@W2}^!m3qd{iM12vB6b%Os#MIu^&tf#4rrFKPIyuXjuSDtUD^I=9l?DLBy8HdxAM;=&j1ZQVyE1vO zK|{b75h)8gU9QuJ27DMNUX@~FLfGBj&C55m;i6cbx&R&nq#szdz-Yee8f`iH1sW?_jKGGit>`{Zjw8~55nN!Q z+VBn%8~PAOd!k=Jno9Ne@7asi%)UH-PA&jBpt(g&u`39e88!Erpf#IDxTRtq#=j93 zv>neK*@Fk;bUqOi*PcCOK!S!Q(_h*PD(&&K|w*wIDq)Y{p}4I8{rOysY7666P(Gx$;tC@sKvLo z>xdNaZEIR*gbM)S(z3vmK~TH#O#h_{AL8RvmQ4GH2=0Ok5+Rd;#AcnHT?3>q*2>#b z?r^90+k#a#@#B#P>b)|=jM8!sga2X?7#{W!{?rSYW2071z?q(u^Tdh2(LREF9Jo~q zd5C-lf>Qv_A|ZPqZlYcH|L-Tnm7{0}w?hukSzmkQorJ4D?4Ztqxkd!`b$@8N`q>Tt z0MWFdRM0A>IkwdNM1lNNJ<^mL%?D4~BGJYJ zm5X`*M=I>yoE*Erf^D`fX*&t$K2YG%p26bCtO%>*9Ag_4BSKyJ-)~2TF|8T)Zk8+7 z-_|mOi38OPi5RB4CnsGp?a%IX1Q#1WUjMT z@C{Z(+A2OZ&~^Sy4;(>V0Y*#%SjjnJ%T{dj49D!@zjn<3!(4Lj#e0fRV?=W%A681S z5%KZg!Ec2Hb|pf$00kqBTPYTxAsUeuir`X*o)Wirx~G;VBM$GJeAEIaB7W75{1-wV z*=qt>95{1P7;mv%yQ|F~L2ns^vUvp8E!MR}x;8Wo8Co=&m-~U%67g^-knDH*Ne?zo z><7c1kh&mVBG!|?4d<>^4UdS(M8lMbxhDVu6LdfozUI|djYDKD+x$uKZ$CS3Lu7B@ z{Gn@mfC(Ha0!@MaD`%A=Rb(P1)ChUP%`rra*R#+JJ#J2%am3q|iIO_9X= z#<%v?p=1;6MfAZ0lN;$nk}0z*(7BW1ED3;kg(=j$XyK?wrao9GeIzwjXK2W2QS zEUW?u6zM*&dH^M+9d|hyucW#HW{{-w=x!3g`$%o0L);B!YCLBGFT{^dY_(Lco5yt| z1-cyCL2%1jP)xCOC6>cTpnRct?^&m&y7~~XP!d9+gdnUAwiqzwTQz`^^B2n-p0>7& z!v+8gE@IVw0OZ!GPOF}a_^?kmo#lN^D7cR=M?Tm+a+JNbR}oMZTDwDd@c;2aM#3iC z|1YxMJD%%*{T~-88AVx1GRw@!ER}2`BP4}T8dg>^N-7eWMT(Fa5-LQtP_oMinT3Y3 zN67d7=zTuFe}3nWb8el4*K=Ht>$vzHd|hP@%H zq5`OkE1LWh%t8>m&pmDyj&}uONBj`H%g}h&e~ylm!mGP_0fG5jao4aUgaTI@xT)RVK5z$O zl>3P~0yxIAutPza@6QiT8J3`Jd{_|DL39zooKV}zI@AAfSh0e;vIlEjU0kpTH*eo= zToFX3XIy$ZUfeE!<;oT467uYBKz)oP|L5m(+${^I(y3_i*+#ms7;KZ`1jXXw;+^gL zqWgVUKlAV0&fsa6kIwXC(Q#{@maKTR0e)yCgJ@6&RVcTsK7RF_7;B`ZKfc_3)M6SB zOBgmM0%;WUI03;v3^YtTb~J;H65aifVI38mF@^RjyN}Gm^K$I{D=YG z$NAZLcC7UV(6rcb)1w{oC$J(1D+PXbx8O|@{-%K$Cz0%kufz9k`7x^#BjLv)Vlsf; zaN#xp?C_}NqrM&e{vw%n#{BgqnYY1#^%7{?=6?74_An&{TvvX4YU;~7BtLXFK zq`8HW971l0xBEK!zRzwwp%#aQr;U*PiWtY#7wbNFPOJ1u_{bUa7~0$uM)k#l_ez~% z0C913%}P1-F`M>i)R`PU=CsW5-zi01n>7!AC2C;wx?nF!_keV3(1RQ3=&IY>qfmN| ze%VH{^$B*tI^GrhBw??65UgSY!^7mYJ|#iHxMhn9w14R8k$6MWiLrF?pAM=@Y_%UT z6J$vk_9uc{Nt3mY_)jM#+6_tkC5IPsNB%jm0=_wAI|$-G?O~;6R%d46t5G_2i!9;A z?s@PqG4js5Fwf*1wJQ**M*%+!h8gZv!fkC7YXPZZ4qfOgiru^L3Z8s*@sNBH=TFqY zDD4_7C*+Oec{1V53O(b0K{@5;_a|2zaQXNYm@0G|E^KMfLtpj?A8AM95=))<(##=a z$f(0V<3HhIQe%=~huUL%vGd_|U(pbpp-!$B*2%|`a~HPC=k0oGQf%M(7#vp6egv5h ziUzy5Hgu{veJ*Cf>vKM^ABbEt+ygD0LB-{^plXEMGWIRj}Y|&O5l6rz8pe!l1w{Dyrji zoZ7e^z_k7@+gy<#l%xy!Uz;;4PhoA+7O=%&2Sq#Hj(quog2cVTej+shq&O>d8VLR+%{8u%?kEz4+=% zaU-R^IR-)FxcXuVV<<=|>{+9p@1}JJD*Jl4zMhk4brR?aQo500G|VDEGjSzFUg%hKE3u3C(8&h z+Na4p$D(FvT0tL2L`1OuIGb(x;ufb^bntplFE1&`_~GFaX+MI$Mn$nfvT0f;mQi3d z8-W4w(yp}_oslk+mz!EZ{RhJ>N}W`$@tX{^Bx#-RkH*w{Wjx3pG6LeBdz_-)#98=9 zmC^qMYNEntvLvEPoj=)837bfKH}TH^4p48tHcRoZePF*990#E{vo(EHULGQDw^M^v z{s^7f{y&xh{jSaAjqicDBOf|05Z~RS?P0{4^)(_H>(<=Sqdi=kwCGvze%Euo(eIP)Auif5jeMgGhVm;-6D?KeLl{fnke@W#1Fa7i(EV76w`5 zI89X5^*KeB4jHis=@=ikXGwp)TZaY37O;4uwO#@3QSk7eIFISFq}4Yy5jV=$?^&5E z#}ob`V34QLeP<^!4jkjSsZutz^n@6>#WqSoe59D%(AQ2ud(m-xAGv84O!yzcseqXt zVqUxXd<6M)oy_@;I;5UliB=NBIN`NWe099XOwzV{cbVn92AG3Ehcr_#>#!Dl+=**m z0lx&sQJ0x91N6vm?q^fpE0lBjqCcp@fKiaOa5 z<@J=rz1K9+*;ng1R8*8;f&BL=xGjAqsbMRmg>eU^QWD`8UOY{YPuu11iocxn(ISrw zGYo7+hL?`#z|+?_;?+)ix{?x|2W}q_PNhO#*KNeTdStNKDckMWNjacsOp8E*hW31ZapCRuptTKaG?+EMRf0!$a zqYiG%RALkQMLMzTd#m8%jM?ukOF^I9Kr^9VZ@K!r-W_wggpVk>~WzYmNDD+*w@x{$gUdEpEnQ(0;zFAn54v)xV~C zd)vQO8L^CKJxT<`bm=g$TRd$%==y5aREOeB_VG-GHLFMHKdWo9nZW`^fCn`~K| zfD4F90*U~LQ)i`C5A51i_gGlb7bq;I6dXl(F*0Un^jsmrm%mZs2CcADEZRjKv zqKhw;g?B#w-BYON)B1gDl7#Wf8-q@=Pv=7@6@wp0WE^WZFooUV@Ccz>c{s+uZ(E-i zUB^?uD&?^*CSZ$R^JS%%niFmzfVfO~4Hp+92kr0jO*OCEyHcLeM2p?1+mU0jRR8@& zW_S0C_0gh!t1HcuHH#$LXLY52_4CwzJil&FXq+H;A*?zDajZUiKAu;{_2O0Hed^-Y zbE-L=v0Mmo&#dh1?0k8o@X3=vJdzN_z*U*Q)Qwrm{@Jlcn6mKjqk)d?sOvkj&xK_U zenV9K5PW0+E_l%U3=?B}tm9eDPmmo}P}o830eTD7JV-o2N&gnXac^J{qatj`AiW0L z*p{72g^r9{s5ls&n$z)VXooqCPKybKJMPlE-b&N?tTNU~yUKm`!qV^8UWm#RVtU_x z#`5?T6XO&6y(&a<MWzOK(3^ILFEn0&f^Y80jJOb%2uD(m#i`QwZ}`GAS2Z-M z*YBv<;frMhEiclUsrz4U;PTSk{3uM3H`SSq1@lWJxA{vN`}Ur;b16?;+@O=KXm}8* z>EUt9c{ovxE@Nflq882Svg@b0@y{Z+$FfggXU67s3yX`*`!9YC;=fc~Jvd${z_b6d z1agVGO{Nd<@ghz>Vkd8R{$16%$0`C>b|_FfbXN>kPyG4Ow!|S5`DS*zhiO5+hd8IA zslvWn8?zV1G8CV7xK{8FiPfsE-A($^O6kb~F7)eS@OspqL&yBF%6K4~+ACtXp z(c$6x7ZOf@Er85Jq}{^Sb|tndia_9S4zAaVDty%)A>o2!S$zkc;|9-2Ff~L6?P4W4A1oQc^NZcQrcKtTC6w5q4 zvEHeKN3Boh;fWrkWGJq@oUsVsNo|r7eN$X%^=}(PisZ>M`<@Q?YW}P}e`P5~vTbGI za?cf~K2crfmkuKPu|>nnS3Bs;iKzS+Y4EOpAzn;y(ui}r`sdp&q_T*HR_zTasnIp2 zogv$Y!P7`UoP(*R762DP7E*2N%U9-3;FFSy0>r=#@z22fUbua0)BZGvQkM(M0Td|5 z9?v_#3r~(ld8+|NQzs5l7>SaPlIA z_he;oV|hOm4;T+?0R5n6m_Wbx(Bge_^I0eraJs2;GE?3(QM45Irb7|RxtW~O&sS$kuh)_kLXnljIA zyT!7&AVkF5_wQzLiIt&)f>+rwRc|CRe7u_l=7`>2{>qJpe>`q&WO*Sj^1kiBv14x= zL_O^fwC?J$d*89c_oaQm;+{8q!v)W>urh1<|2|#c-JT|OspF-*?@X)4@jPp4G@ei; zHyFLq)SqALWny9ywP6MV1B)xO#@KkQ%hWyJ=Nl(-Xd4B z7pwfTy3m0G@j!r32K@je?zl1&q4fmZP!s=Cm_Ob&H;>{=krM>{sXPMJuq*@y;x@+aqyQX4dXFoAW_S)B z+yOWmHg|+>;5qU4qguZiqZvM&P60;qi^#{ob{ku-UnVQ-)~=Ozn^D(4NSH@_M|@-` z@N|D?K3x`m!UR!&C=zf1IKizJ+f;b{kH4w!FL@GxqmrL#DuoVo z+{X9oFDfXY6B9Z?*0Un^=D5#+?mE0%ub|%(8{Z4V9HI*G=Ky$+pF<1`Vz&XGOSd&0 zhx5_Or`WefbdIt1MM%OXfD4*4#o3QX)9BKtW<(f2%7EoKw3<-5XH#%-_v(V3EjxRG z)iI-sjVBFVsaikYGy2%u#_X!~e!1w2p^08}Vez+YyFwSOJuhmcT*dcv_R6rZ7`$O& zkvU@!u6Eke_Np(ZE&C}YC8g+TuXs<+@`m}i>6L~*2ND{4wuO6+8MB0_+w?Lkde1$T z4rCsSth>{2D2KiN^NnXlK@&gnY^>gGW}15x&P`k3=|$`0;fy=Fj^R4PHq}=P-oH2K zc^loE&=+B@Itm{#``+UW+jg#X>?x?S$uIr zpYJ%%geQ9vCWPl$iwfx$it4r%2Iu)m4xSbOdq9dsXMSUDIR%#>j7T>iz zexK4XxyORzgCHR&fbqzs+G`YT{!v@W)4$-)!a^)?Dho^ zem?v{AiZHjGE8IKQ%Re)Uw@-I$Rq2Z(OsDHYAemA=F-*QzN39kz3feowq$>d zi*u>&2o{#g(x-8{WcDzo)9uA57WN8{t7Yq@UXK!~nY=?E!DrdkjU4y+vZ8#Bk(UKc z-tlH)io=tW);=G?=fA$M>HYMnXz-V?abF(&x75_*XFV}W*MsKkDstV`(a}M?VpH$) z*U`>^rDCNShX7yBONHLz++i4}AIqX8F)?99qS0uuc-bl3QlR#^=#hCn92gWH;7X8@ zUPMF$%A_+-MYprC_(LMkP5Yf_{~*w0!iWt77S@@s02UEj5)!LW!$V9?H{yJlsuvL9 zfe_5xie;pI2sv9kDa!Zq^kf1PkN6P^WAE2Mo=p(AC~+jy z(#?RJg1oy(J1-vf%sA7Ly4?@R3lR(v^DD5tb|wQ>R+-)I>Rv5b5lV82?LjBL`N|&> zq7{P=`NY+y*}>%pw#D9Jdo9vrHr;$)+bY(;ztPU|Y2>pPC2-Y|;8T1wMr`gRDhdo3 zBK^)X`iamvCg6!nAlbeE4B(Sogz^D94!J<4icj?t|0SLk67vP;j|N$2y^Fsm?iD2w zt`WKeVi93{CTk!$6oit;kW7@wh<=KJyn|2u&M9!qIuE4$f#^?R_#GS>sU^F1(Nj8= z&a!UYxY4tAhtz2r9KcMw^x~xhT1Z|)*QZadILtPGO3%%Qupt`IL|eJ9FGx20T6j?! zN;e_XFf=q2NFG>#RUhkcJ)Vnzh4OaLvF)Xd?*;H_|Vnj6Oh%A z5YQCzHambFLwsE#2x-(5Qj&^IUH>dDO5!U>t}reP_oXpQ^fE+QWZ^TZhA@a4B18rQ zx#k?GT$~`Vk6gnuMV=2gH)#O6BKj-Gv)YMn>+f&my5MaAx0qp^#R|c;*H||^eD}}V zSi?*tYWDI;g<0L5t<@+pA=IO2R~zv91)aSAZ2?pcOnbmQzjfy9NVqb$6+f}ArY5yT zR+gNyc!U6R!(twSE0Q-F#hd_(4-t}taw=5eVi1E-szLn*pnt$9$wmiQjY$Myo1n2# zq9xn|c%*G6b#AK~=E2rjD}j9nx0+D1>%lMOv!8X4rnUiE3{W1D0FIw(cI+xFwUDsXbkCMSALeJhKlM?ebP2YNl8ul+=wEkV zwZ4jzWBG^WDv2z^$?$$i(-y)t@hy5^W1Y(05eXEmPnRJXuuBn>8L6VlVnlEjS%JyP zx!mW0N#Su8#(t-q^x;P#ChRQS15)cT>Ca)Bugfx*GaV5@OQu_Ut! z7f{4_j7Xl53;U+8j|-I+7%i;es2btOm_lUOSv1%G$syZo&HDB0fkv9~`Z;=CJ#N^+ z<#tqii$$hkhPG&vAFuyuXVnYN9=G1}ZW38Fle6!tK-*+WY^0r0JN%UmeuhiCS{wX| zzAr{rG7{keay5rwH-7uUK#3Q+QR4?RWF;tBemoo_6M@z145^04&vf>u>24$HE=|qA zr#;*einaZVH7g7Pp7xZVnYu*91lJ7wy|N$2!w?Q#gbtDR5xx0|jE-}Hifzx&90pU8 zHy)~%ZfEsSjnV}6N7N9tgNiq zV;T_|X-%KJE^qkz(2%w0%QXXogOxa4@?O4Fh4*Y=0QPy#y^o$%u#Yr}AEu9wo?;w} z93pEd*KOo9P12;&YOiW*i*zbm3?Mp9bjw605*8LFeMfbQ(QkKzCfBCtN++Wj$D%73 z&mY=A0{VV^jzv{AOh2+6Wk3V3W@f`5sB|}M+SEKeTjn~t5lpALUJ_E9T3boL2g(V? zOks)8{CpXR2vASgBb1xiq>0GD*?AC<8Io@}@SY>v0e#S(k@l^szE~5&z#;uVTQR74 z4Bh7OlBkNdbIZ?D6!+tEJT}Zok(=0B}w8|9S@&`J}j=Iaw4lT!St8Q#; z>saN-i0S>);1#FwR9BUoYO-V~5C1KbGvuPdD z_3o_f2;08TmR?Ja1m0olC!ROx3X&jdz>98m_N)d52nZ37LCOT#3zAV_WC1eIiCR&R zMb1Zz_3!r7qQ|0(TYa_m589O7{q!|NXfq6xl`6t85b%?bumh`gZcE>J6R4d!gm~kc zx;nz}PS=a%4E*>Z!oY`Hh|-2kqbj^3{~kyxsW;}dZdw9g@w*ab1xESU^mwlz97PDg zvPgY4h*O?Aw5GO}vnR~d1(yI2jfO*v#l0G@;)Fe&@OK+9mjEC z4}uod0mP_E@z$qcQNX;kCj7yJ^Ox={j~?9Zw_At{tm`@nR;pMevEp>NcThsW6SEcZ zR(*v4;Vd@OV*+9C58ixRm1YKAIU*yAGUsi2swmN&DyhCpO;6ueUJVctp^IJp-|&_~ z(~E~IuduLrTCUV0A>B^LpsS~68p0Hp*UvO+E*EWxWQOR~TOY*+uT7$1o{cn90A6^BYhYxgkt%boh8hF}P@A<6pbU{%_g=X{Wm zBGMhfs?`|3Jb@3iBI|YQo&fX-+EiLo6R>ZP9u_Y+3B8pLRE^Y2RB0Dw9{v8k9?sm5 z8r${s>>vR?QyAPzf@rgbD+?_su?d6M#=CP9a+JxDuV0OyN@7TeFIM>KY#tUgxcAV< zwHM&NDN>Y6o7N24^{@U#aJgyaK|lH!j}+dr;jdq7&<_dpC$=*SwY(37ypd7@l4Yd) z;BoP(L{1$PcJzc#gK}B?{$9$+OmZxfSZIg`Ps3Zdu(Z?}W9_+F%bEHQz{q##U^;GO z2tzN)5!@&or42n00+oA9z3&5=f|wiPA#l7l=g$)!NK%ps6*4w<8@$idCBtbp53MI? zkrE*)CKfX5j{k<}LlOfCdu}eN3qY5)jUspkd*{&W6?xA;bJjsE13l3iYu@FKE#Itr z)&IJ0m1UrPeFTgIsa0c$Z#a67A?Troq4fWrVTgJe@%j+)D72hJxYOEdz@d)En+dh> z7HGjW6ClIb9bR8u@gf052-7=Wayf6(Y4e5(XxB-cBRWVMcmt5Je4Im#cMVd}&oN(x z?gHYF%zBGpD;pCC8j(VnZI&Mx6qJOA(!QsF#7;0m`%1)re`bd+uqK+?IR%X9nH`vAE5(7*sU10Qwq7amc|vN&|# zn5oop1@F{hET{)NLNb2Q8xR8+LN_cpbgY;CUSlOZxr~sg5zRIhmLy8+NantHQC-FR zyZOKNdP>FB9YFvjlL!4?S67#EP1s`wTdnB;-FFFxmjrFvU(TyTs78in`00#~B)%>x zk_7t?6bnJ`HvsW z6Qd4BP0E{vdteKpqoX6k5u!DT29S97v)YkvY^mgyEooF&2zOe6ry`sVxEkbAW4$3R z^((aEm@?O@nnwi&1}f(q2CcuHZ?%{L^W*U`_e>*UJe_$GPJdllmX_{ETL6+9AB-Fk;u(h69Lx4O=LH%4)SLU7le*durXUm3t}6}9W- zK@2>=CS$h0AK2PdUoRElkKAX<@R*o$_TMf5V^fSrUK56LG&YI2XE@#;(`V1Jv&Eq7K+*UlxEpT-iFm_P!;K~e*?Sy2`XQIZ7*mfj92gQJCe_)AVH9Qa zX?Aujl?lQLb$ZFtT6QxSA${xlH@L7kx1M%L}(G+lX&TjVZNO|KlPtv zn{(N+$mc;5|EUhp4e=69HSB55MbtJC?PBdw>LmZQbAB^8rif;G5(=X*oL2Xrw7uXL z_y77Gfl&##w2JZN$o-+P8OvK^XJ?0o>6PnfsHBtp&YiXP&vMWR;c-t!!ABk5`ojRI z<}I9aBmx}Qm!viTKuqPx+G!XiQgo1>ghp7FH{qEeBP|95;3jRz62r@K1CtFZ?%UzS zCm3Ndo4?(2#ENScjmyyJ=q(&@h(369WW5qb8nkHS^u?!QVrNGK28DGnswhWkFVGU4 z=+MaI=H(6Icd3-`nIy>^=z8&D zc#Q*Tt)+ecF7Cq5CJFLT!y}2$3rA?GRYPD7I&I_k2WkTBA{WC`hXGP!0$zva2x^dg z-W@%8HX7s^27p5xMo6MY=Clrn0cGHFJy4}QfWAnbZo+&>!Bj&QZvsjUfM847NK#Pr zSZ95Geatb(P|!bnpq9kLN_;U0fhH{OE9YUwgC}*TPwv^XXT!#gBWNF?;zXYJ1?F7= zC%a=}ZmBaR{htpvN%A}yYbEAy-U-p((NlMp**l`5qKwDfN9G-4PuwW-#JSthohaz7O{>8g zc$dBf)N{&cWK=0LG0ZyJPSm{1kM15Xm)g`;Qp~QFZ}jk+Oc-ucX{-Y zM;9V45sYbtczYx?>o^8!O_jtWmc0UH_&9iDKzlZz)(QTI);NZ z+8l__a2gB)6u{o=?R0d(%1i1PH1qMW;JRJw8j}vB_;9kjN|rikpNVcwUtc`5j7+So zwPa-z^V+N?=A9Q0t60VUUM!!UF7Lqb=T%y!no}8BX3=PV_QHklDxLbQ=oHlpOtVby zwXNNJ4PDD1!Uxc<0D?G!gTpW`*6LlP00n$oB}xm)=n-&_Uz~Z*3M)2rOST7ZMroVm zSP)$`&ZZKurfuPy`S5MN!Xinj>Rfp?;Yu`0BvsMluE;jmA01-fJF;Wb_h|v=K~kIu zHwDS5FD#r_k?X_f)WF^aiilOmh266=GtxohLjmoqvL?D|dv6sToBLf@QBlEB9`G<| zCK1DQ#wlW8!lDRtpr-*#B3|Kni{j&lI;yH`@k_3M(ovd~swBQ2fE3@peX#(K+mQTa zop20&6k*vhuVOXNX&j|(F`Jc`qg^~aG%zkbeE3kKOUuu~hrXydO%87iX%8TRha5q1 zb$J>Wf)lb3%!ssitj3bj=FanuqI7NsqYMG&HT+I24-cQu{c5 zGI8kmrLZdj67qkiH#TmH{?(_!>UA;9cq9tdY(6`hvXlUmL}{^xxyRcv2sH~9A23v9 zB*X`~Y}=MvwJ+>MPlSlH2XI}y@V!s@SrJ6YO_cegokncl<`4;`9%`1Df zJ*1tND6sNT>AUz>@fa*}I3&pFQd#K-BM}AJJ~2G3+br35X!kEu!^Gfu4MW4t5dRFL zM&Jdm4cj5!PqF#-zXLXNH<1pKy>dC7d;ViP`D;9Rz@+8*EKV5)iwm`69R%yZi?ldG zbCamBkV*6nE@(&zn}qfOiqD)owi%Bxln{CVXg}>09rP0@s)>L!+D@IBQLrQva~oa< z*y-{xg%tSiX-vKHG4BE|coJL*SM*Uz_WBC)^6bG68{_w%C<_#bbg2rzvHKtNaE}k= zcm#3s5OYnB#5zrZDbsegSPO@w%v}D}L4P)!R9_%h_H)9yX zA<0mh(m2bIiu(#GAEC+OF${&WjLgjZ)LsI^pwX5=>Eikz24RPgXsKvjW<4l_CraPL z9-oTw!@n|qYX&x&|0qK}393g)C8;VXxW;;_$3Jpz71&QYmih!h__0C>LyzrI7Z z5dt|mi>j0ws(4q^&tiLo+Rz1dpq1o(R>s}-{p%yt6pZZATcl@3Bd!xCpVw`f!#pNX z*J3tKwn^01jzrXLLy8>9?u5-If=`1(Z`wLVhu@Yfpi7o6>Z7ni!t4rmp!|0}kTmJq4 zNGsKAV#v49?E4qaimXrNG7jAzf3AyG#bo%2yXUE~C{Ve8e^?OO4HyF}fv-6J%n}iL zh(Ok>ecET* z=j+h8OhPU+4b+ou;e?uh;o*9XM7DxS-V7f~bFUV(1^3o?mB!;D$KsiSNQ9W=|+(VXB zLD@yzX4v3E%V_nh-5{~&)2FB(3u0z3iBK5u|GVW*;VOW8fY_-?s+H?9q8TD12JMeaiRgG%;( z>_X$ji{l6fpBffGpnGdukU^|m zHD)RujO-6&>{xLyp=zJxNV^F@Jr}|WRG{4<25ML+-~+mbTGl8qjgNpOHmRhfAb2a;QZ19F#9m)<5bnQv{MU?B;X+| zlr1nbpsBm?ajB}lJ_s`m&UR?~@1o1+P;>KqtS?9a1+>9mfe&FP#=crl0hw5EMOe71 zfqJ^viAjbY1 zsow^)GgE)Y({l#f&!D00dU^h?kATq{vS$r%&IumZZ*F_ZAMi|>7T9k+nx>OsP=J>h zrsjCO_+*2};?SOIFqc~uT==ox4qAcjV5Oc-Z$~r$v_rTLP@nCAgEV8Z`Ow~Pch1;{ z6soAJ2Z)AKzZ$IV^fCWgch=SxsDTn@33%x4uYAd3#K1vNa?p+F6+K~c$#?QI`>cud z`m{X7%M*#cN6q*JhH)sU1v!B|AneMj{*kwwZnxji6FE8>O&~xdnwZ05<#~H|wWQHJ ziD@o^!vI~wG}%l^1T~1lh$6HNQcF2jI8R5uQV%rIxYzwILN~}f8im;D9RLJFnvY&ZZnj8`rvh)!Q!ReAz#J%i z?`c`u;oq}?oFwrQfZ}N#{N`Yfp2Wz4f7y(21ub#3UV!Qp4SQAZ87{AOQnqS7d^j3( zQ#eSJ@mLXPFts#~GHh9G)5HnD&!T~4Dkyz5=s)fEv7vRq?9am8t@QQxVe@!s>d2Fe zj&K10=mR;YcpoYLNR5gX3tifo%v%^U@k-rW95rS>&i!oa19nEdr~_tq{?lSoiSKW% zEt>qEk~8^Sgi!v`d7sie@)ovJL*$P9@ynw7-r_<$HO;$@?iTuaMWXJ?$;t7t#!p}z zLr@qb5=KFR8NSyZO=SqN{&}qOuH;JW*EZ&wDlT^OcWaAh5|26hIgWj|(e`AmjnV|s z!JJsKWX5(M5DIiITs_Mm7g4w(0M=viiH}vx1g-{wx52xe>&oTvD&+z#_t=hr{OGG~ zp@l5Lf?pi*?{_F{))K__>RqgN7x+(^`0a6FARF+OQz9BN*Mp(ATfCroK<`ILE+?cc5TVBZQ*{HaCok z8<7?qAx^)Afb$3)T7y&)22jYg9UTQ#op~1rmEos*d3HD#Xm?#~-*-EFG9)nB01fd~ZzEApNUj z9`ZzJY6svr)D-4=aKl1otiRkhzMrVlqSPZO&3QBAVeR%nO9z5rBaZqu?nrGyvmVbq zwT1!#g0f(4BGmCcgj%R5DN`i*H{%2EB+G9=l&m3XpO5{W$+@6_H(ee>Wf2@{K+(*y zSus;6)-}#fxFNv_Tu$wEbAKdYBf~Y-ES+AgzNW>@0m3*_v-;Yq$jnMqcy^Qp0J^|{ z0i9EwXTF`XmMo8eSOC9Y(UqkFpxK6gl;(doW`9vO$VhSOFS}-+Z4&X8bH*hJ0T%f2 z)=o}gX4yLtA^kbFXRXG)r!kI1?n=%$H&2gDg*y3Ib976ln%=!W;&T zQ=^JCm*8lz0!j-V6V9SG!OdC!aO51_s%uFQOBW5)^RKu^sAnD4epmdr@O z120>w!Tf}+#1!t|KR(951nr;x>q`#EPM>tbrJniu=`Oa>0fWfJVr+Q3fP8~N2Oa~g z+!}beVFrHosq^Qx+}vI|@5VJm!MPn0Qq$c{g0!GA~>O z1Oy^5u%6oJI($rk{z^7ZXQ65je&dZA8X5pW^l(ZoLY)hr0$BpnCb3ydl4v-AS(2C~ zvMQ8Al~?Gju;`opd{l0G&rfJ19xHS_C&Qt6_-^fGW@g&Unno{~$D$};(+5*Y>wg`? zKeqi*R{*XgQC~Q?2)qh_5i_?o205S?fC{Pc_5ZmxffYdkPaK>0QUNKcHo>$oP6h1k zCgNc<-_YgQ#bGljW?)=79-vJ?laNMFe7tCSNPAWVV)Exnkp3S*!8dba*s-n45hm}D zj9s*km3AgST4*1Ld5Ols8vQDPtI-5#RkLfZ>sxiKXUv8TC8jQ6F z+ZNb!MTSc3PsvC;i|ai0G46~^hrxixz^%-sDXitN!g{;s`f;j;m6WBu`^P>P`)RSb zXuWf$Tu#|qub#-}`a*Lg@n92M$=xmZ*-!x8#&zLX(#0;sDYS)2CRt=X779ihb_)<) z4(=h|DQbdBV*rw+^}dEnh8ofZuNw;PKdlqo?a2MCMmr6R0(}l%OQ=mqsf4Btr5fg% zeL(WmnxcIF-S22|%OjBYAYU>aAl8(>P{wmIbkBTm4+iEr{BL#-kPh-=b6M*q$VlBl z`G;~cOy1G9NsL{dVR_y1QFEfB17WltKZmsgQ1?N8o~4-B>)lYL^+K7rX~RVc%+5&Uo~)#P5X|m zAv~Y|^N^5`$;+Vl@M(xM72BdI2$crJ5$`!E3%1^SWB>Q5SipcRV)$7Tqu`q6W1yWm zx4zi$9m+6KhrpWe19xGYAcbFrz`)^(T2)4I3PabMv#Zx8ud(H>Go^EDR)~J+dStHz z!^9ekwaPA`A`}`oV;>9U(stdNct-WJo~ft#>m7y(gHXlnAo`Vu1ipdtcj1x{d+v$X7T zx#Rz#96&!H??D{y`G$ieT>~@92y}o%UJfjdzSP3`eS6FN;-GzM6df+wEzH!AdTGIfko z%)DpnITo~VDW6i7Dul_x?b@G;9ToOBM?a^r|5&2BEH--b+5-jNLf@vvlUOE@FR+0FLDy zBLBfOIQcrBGD(I)Gbw5${})FQ-hI4TfcsSLA2m7!^Z~|nEE=@3;=MYBcAWI#6_@EH znufoB*G8jA(iY_9$$DnAJEwh4qQ;c3{@n+_2YQxaXIEF4n^|J2u|ut5!5Hd^jU+$^ zWGpz`r(90wAUu8*W0A89xG`EZKpw(T^)b`Nob={v(68OG`3{)Xpz3**8y9AFn_^Y1 z+`>Zfmero#yd+?=GCeN2nPl$))Q}ArTed=dj5hsAQLMhhHGkVsUs|{KMNY!fEDA&2 z7yENZyS8+N2!4^JyQs$O@?Ot2G~8hgCxyLknL`5A!+RI6Xf1Y}Wr!(zIX;zbZu!>C zw@I$dwQO4Fooo@S_uXN&(wo{ZnzVPeJPz_~xqEkTWqxqJpGSl){xT)2c)(nksrkhQ zc6pbSfl0YO#=0aav&WwB~&)ft>&lF~=p# z%LVQ>-_WB*U@1^7Uh}^~plku7SkL!{Vff)blQ{CuvY3{bE;K2=BRwP?Lx%vz|9Jg}1WAYM6d?#?y$X6fV8A&I9rk;h$)d5LX=7oQm8q3nNsp(3 z*dq={?fLva%RsnErUH>MARRC7ROR)DOIF|S@}mKeM)>c>*P0HW*IaOeOr{FqdHOD(Yb+1*pcz2FXeXaybjU33ez_0@rWl} zr-9Le=BM0)*PA9h%4W9-HtrQ6+#zgAgop+inpvA=JXy~1dQ=q!F@pk6h59#+G=^iz#Xi4k1 zc#w}uRIH{XU9UQbMZ#k@2H6?YY_rM}PG7h0IVdS4QUeoocHDvXDqbB(PUxo8#-T&L$KROS~!& zL?I{#`ZV0mhq~t_n5EY~L5mHpk{`V%+8NX(Kq;>k4iw|KR7mpF)?C9_! zremsmIRiW~mIcZ!@?7{8Q)IWt+y?qPobR;{>Dyt2zkD4MSBb03mx%xx_M8hdn>z&W z1;PSRv01gtgOXRTd&}VX?u}Rc4ppop<_8)*Z{{kM?6-?1;|$9WU7K<_{d!mj^GtY^ z%g5I+v?yrYVaqR*4D=ZfRT%E1w!LSa?XEMjEZ9H%n!BW5Z`7Vu@qw$4MD7-*?>TQj z>5N75H8I$1%`Cca`zVSAlo*~J6^M$6t`?bPQQnn)eiy%O{@J@h*!bBgy(6s33$+Yg zui186+(ZIfy2;~fPGx?zAvNXNsf^+2NBnNB_gUb1d7di3I&W@nh*P7k*HbTn)s<`C zy6tJXK{=rrY?!wF?qoOmest@+%+}$E=xART@U{P1$ zCfjD#)zzuP6O(K9?dy7;dP)_B2%2WE4{3~S_q|KxWn=agcGI~1uXh<1(z@(=hO-=j z45v5jee};_L2TjO2Sx*webGTdz7&8wI$V@$aNc7GVMeP7uBZhQG@3Vm#C_oK<&&3x zbxre1L)umV`CjbSl3 zZr4Ho#>ed!P%bw?@`Ty2cA;yz4!-J7cw~mb*pNpLdXn}j82}yf#K(d2lf?93ygQWD z-chot;!gz+H`5@`rRH6>OAnV1_I~+WuKP<)o%zb^TTi+i7uJah53Bf1*rtDNu;Vbf zdiy_Lg}-1)H05b-moIcDmgaZPH)gj>q`Q|*f23)??9;T6#`F8V>qyg1xnA=qr>7PQ zb%#-GZz5+Js2QfE60AP?kp9@A=cKdasRs5*C(S@cSKk%te7ouodez>)D+?SXTv8aD zH*qOll3lwtknyKe8B<|WU}(VVU$%~C{%@DJusrM{DLzl;(+`IcE&3>=I zi&L{d=$;9P&>i?|`qZY0lc)E!2irEfkrC1F#SDWhojEr`LIO=Fm{?A6?7uuhFMW=C z?aI5mp45N*sCXHy`VRyKGV=V%DKnGWX5!!uN;e9-J=h= z>hOw#Ldi7pu85ohhr!6st_d=kh_LYM$jnnI#kz{jK4Tj&37VExC|owZf9i^?Vo8^| zbH@eqHws788gwP=gum?-d7!ik1UO5btJp$Z)!M-A8)d*p9u1AlUs+l%RK7nPh((fC zeTo+^GAguK`kI#%^%UOnQ(#%QvZD3`ZX4cv`|9@LORQfcTB%H~q9(8{vp6H_ zcG+RtcCfua>Zoqs)hi3bn|QA2ju!hIzq2|NTt($*L-lAM9L_X3t8?SjokIf@*k-?t z#v3an`+Z{*UL4C&?yKe)>oVw_pJC?pZjO%}4R!iVJ6!7*8~ciZT^~1zj{wJna@xFs z;^4~6mQ7rWiI_s5Mtl{DZ}-(4SC`ka1ng@ZPl}Iyxi< zV86-7xB&N}e^bn(3o8!`U%VK`feSQuH`y|ct`(%O{Gt_i#Fu0YIuzIi9t6t1{S%gLBAWV0m#{u{(1xDX!vHBywr(p0SlSfDDkf1}+YL>k>>BBdaHObY0!d!Bh zkU)AL6*3RtJ8}{M$_qeb2Ms?;2Q;4kp-u~x-2hcd{ljC6LsnY)vNE^ccFO9N$R;Wx z7=GdUhGI?A-~ZDB)YXyR78)dAg=l_X)CE2Kkh}Xooyp1Z{)3PTlW^CsIQU0EvZMna z6WGlu7-8h`Q2M+wI%dcNccXg4I&?d$cX5H{P~kZP$1!)MYj1tI_L*FMx})~_8D-I{ z3y*0uJlvSCw{U;iQTu1MN@R8LR`@-B+4b~8FKslKcCR+=Q?8i%#<#ZU@x^Ymi>KC< ztQ1T*CL9n`E{)RW8Ia+~v(i6_Ypy^W`$4+AR6XpzaNFT3$i63IVsSSK#sH?=Q%)egG4W1m=4I|rhh;x z31#@-dM=_f>G5D`ul)hFZcTh$1yPj)WARf!!cripW!#urlWYD6Y>9&x3Z9yefup|A zIg-WN&}2wK8wz9$(#?n+^qaNHn&097+|0GQ5(8|79Vi;+xXG*_m4c`ic4X#FPEn#Pinn@aPOOz|s;aja|J z-=||bcrlUv?CRCQ#Y>l1J7ryW-s5ji%*|)sNl6#`;iR|1HM`E6rY3?)*{q$@mFtU= zdTQ0bEcSGd(0aJu;Sfk-#`i1i)!&jLYOk;M_(fCI?Fs?2x^|^7CD>} z0yQ!(@2EjX$MaOd85(Qdyu68(`Jw3~`2u8BL{RQ=zff5xdQ!0C?5i^EJIaboBzPIL>Ze)~^zIfAXfA8yE!go*Ht8%*gV8i@xwqM_LwV2|64!zu?dw5HjxP#_=b%!CB z>%+}E#1$tNRr=_>pO#)Z6np=x*HkOTtK%E`vOvB;0RWsLM6uQ5t8)60Bz?=tt3J0G z;^+I>nk(tV1EX&=K8z}Jf1I7&)pGu$Ci6L;?-{+Liw40W^WO!M&eFTnYuATvA1XcQ zn)a$Jbh}#KTdliqb{bmQ%}+3@u`wjbUC1{Dvlnb5BxGHkYq8&|IkKf7yGvqbj`cTR zbuSXN+)k)e`-E((UYJx)iR}?x9Ny#{5~k)ZqN))*v^*DO`HiIx%wPjFy>MdL0yh*j zFP7HpdzRuu{57~m8rdd$;PX2lzHFVombXXgJZ)B#TYS=pM5jUprr!}CW@if)%-3W^ z9YNh-UJQavN(yd1VNbDWQ>lc-sYVf@qx2Tj;F=(&X@;bh=mZIc4HDVu>&cfUu|IB$ zHHN9n6}B~Jo3M!mI%w-l>L)W5PMIC{YlBxhv7WZ&G0e{P*ZPtNHAAlnNU*f zleW&e;w@>3V)Xn=^(HkBEZ$c8Qs+mNH0^g}7q4iV?v@Ca!_myl*vnHjF{qro^e4!- z{X%P-Q{%(yt`47tp8NT{mrP8oZwL#heY}R` zmOwj8%SoK|HK0<0CM~>mQ&M}&#P;rp+bf_rve*3A$;nAZj)zNIvEtzSo`&YdU%o%Y zn9fAr;~#myV_d@O`ovSq(uW=&vYh&F^^8^5jZ%bDmR?@~)%^egbm-mDIls6(X^ry8 zuJUUUPPmK{Mj|Y?QyzW*3ex8}x_zWMp&5~L$_N}KBv(MhM^i$a03dmTdk|tS48IxK zdNnB-lBpFea{G(3H4=cHKbK;?n9cmsX;Wn-^$*rBs;w<)A&mA{uO?B!3z4+)`P!OX z$487Ub8|`KR-;W-H};(gdc~riZN{7ZCH21Q-r7CQffrp59%MS6hv?11$w|ojt#5Ge zH~)C>?P46|z^Ai=Svji3nlEg5-O8LSdCUs!nFdEWbo+|pub6y%`qsB}Y3_FPRbk^+ z8P2EKR#T^)``e`CQU%gY#T^~1=&nxj`^-d`F6~MP)V)=GtEP6~<@uz)*JESPl`hQn zC?|GiMs54s|0<7hIpEj2e7n(0M=8#AZv4BbLF480yM(gztRB<$iC)*L*MH~xCx*ii zK0IkZ!w#sDlH`J8QdWXC2HN-BQ(MGSVMk^<$X6RM9 zymSnm8)D_cVEw_i`wF0XByUuw5LcR@*q~pHzu4%!w$kK}Y_k$%Joas>nT3{TZSYW+ zq`a3=ub$?$C=oR;ty77Nq3L?T#cSt()8(1PS-(lwqjM_o8%Oj=v4 zEl~Ao{3lj9`yX4qtJiRF?#=DqiJ4@L$ByRCAtEM$-E6I`o_v&TZ7%y{@Mx-D`rRkc zynTnf{>{&IZvru;4K2`#GdHV)>9ItB!y7mx5j^vcVfd%;4f7+3AXosi*Zuox`(!?$ z{lu--+KRow6}JwUq#Cy7Se7fs3%b_vrxMlPX|`Dbv$g2whgV^#h1hBYj-u0d&eQQ| zrQ)A4L3DdQ(8U&)j`Weh0u?X${aWjGPfsgPla4{{{=J*V!?jPeH(OY!WYFi`h$>j` zrAbq=Xj?h_yIfo`C;V8&kJ+kNhgUiJG`}w<97uZGd!3rMyr(&5%yW3i<+sOo{*p=G zWuB5n#ObpNNV}hl8IjB~s#4kS6d%*yXK^!aTN~B<_>Ei%rmK#7J0I+kxKhkGls4?? z9b7Wm(2&&m=pMiF;2M+c&C~XuBDb|AtmdU%Ix6_4SogywhJv+u->d>pQnWt2_}z%7 zW%~XRk@~z-4q{C*r*f^F9iWbChtZYQ+k1&}|D%J8U$*?6&GB6`K{#@!YP#cwk1=HD zLRd+hrbY#6g0o?y4EzjJ~%4Fb@Q+t!UOMA92wqxUxj8Yh$1x zmv~IUQ;OtWqZGF z-JNog`(B>D4{dL3{e(0^D<17jy0EhJJGibRN4!?}e0E4U<3j)H%_qNF1_y^MmM=3Y zjENiz(!^vj9WXxn_aZaX+JMFnDf~env8sY@$rOa`Sg)VuGOXANi1I;?6JP$ z@q2`JX;(a>wZcyIlZAi?7$pLK-D9@8QR?mL|5~Br={wy+@;;`$a$QC8vR-%I%G!m! z1;KV6MhQ@F#AQmtP~ojVu=H~e#Q`L4^<716$d00fd zjd2TqK`6rCa+~!&ll~J=+1Bsc#q?O8bL)>U{PxkSi-Na9>Q&v}%i6KjLhTgd@DO}q z9pEnFOaZqHO#n;rHt`I0h_Xmp3YtirhtgUcDGdkhm}|pZ0HN7Tsz40Q>niNIbLURP zOEmsJzTP{Y>%Z+AM`Tqa(lRP5St%uCm%S+&Nu`0zM1&-Jk5WohBzs4h z$;kdaUwyCZz908LzrW7M*;k*u-=Ehwj^nv_*Fd)dJ58?i!Xv7xAS@i)U4Qm2E*%C% z7#QFpgX?X?kW1m5<%9bSD%$>_rx-(JaU7Ltq1W<3)Di)qm>eA zNMvPoEX@#5&Ekmd{&M&6S(ntA>frB>Pv4av*|kf6yI9m^61I?=Lwaq>@bq9f*u+tB%i-Kl(hY(e-y z67XW$b$=HB$QdvWuB1j`zFiekW*hg81?n=}&jnE{t%B-WZtUWQ`W6;ffEXQovLX5O zxUZ}@G;)NC2q9_7@3-7v_y!fxb7QLClyR=*uYsO$B=lkbkJvP)mV(&vPIQ%$;U&Hx zG&a@N5rVf4^FJ4QAZ}EL6F7`U%$#YuPONcH$eH`cr@n*3qJU_Ou-5YD+QOF_V#UI= zS#O2klyiT|0|MP4URf8d3U`}2EWZG730|ie$;#;pZK&?)r-y=ZK4OXI7Vh%Wt(4u)n(iV>8wO=e&V;NT7SGYXeeu8c~ z+NS6hMha15`V6wV(X2?zE_4W7x<1yFXRTas(q2OyIYdrD7;gv|&&|&MK$@T#hU%}x zGHMT4W@ct+n)r1!G;YgvLJZD&@4fb=1tlFR&UHu#LF(_B9dnJi2SFBw9bO@N ziU_f}Y5M&B8jv)<%3t@4j`iReYqpe*mf{K{J}_3>^=1-S5eD++Ro<89Gz*`@w{MA1 zSa-SL%t@`yWxd>Q_mt_lD>~jF}j$q8LH+W>m!LEF8%!u939y@d{_Z`H*hf z?E@T%Wjq&NFZb<6n@Lg-U`1OaGeh0!zJg&v``kD7fEyavub^0FtF59kx%cSNJJ@`| zLUSpjP!8t2#FPosILXH+AtEJmAm~g9q6iWN9vyib z#}L$kSBXi&Zs3iGmVw(PSjUgRB5m90)|`OxDpX?|d3cO6!wj2g35UGJ&{6#fgOgGL z*ByTQaevrUBk-HJV`_CdvUrU9x-_cBw^-p#&SMF@2Ti>0PlG}O6i0)7ryIa9Hiw$= z(MiEw8+OvY0p;@&WG}PaW0;Zro}0@r-wH_-2=Ta_zFSK}HV?_r+eJ^OIw_LEv!Szxl^v{Vx8fd7!d1D1aGULCMB2W-zH){r5#dT? zYr;4DAEHVmG(M>6p|roa)g6ioI0}MposP3 zJWO4r^(}YIQJzCY=KY(m9P{N_tKrv6+w6TAJt{fO?mKYSTlmqXHOnh3O{!Q+b31p~ z-?VPuMmHEQA^vNB7n)Y$oQr862sGr&1%{7`m~cc%(S;fey5nGOn*v`ZzIzdWKr(t~-}qqI z0gI8B4vQ8T9l8& z=z1H+B_L*~&^G#4BDF;VBW(b@Um^3tCiwo!oDnc=2Xf}f3&hF>r;2bV!0MymgIW#J z7>yViB6%< zg58g;1MYh^3>|z<*V5S`g$jp}8vHs)<%oL!J1n zV^rrWsY)+4@Hi!)a?d^Cj zjp^L&k?ZNH;V3^Gz(*-GWvpuEZ*+9*^6 zW5k41<(6KA_Nf823#=`euzUKxowGGZ{2Y`=7xr?Ing(H9pnC(=C6q)QMHDfzu6Ma@ zOCq51a4)+Keg`6?z`K0&v%isM0-ff$Uz`b&I~snwg5-`3igRMPRHFWfd28Zc;a^E; zIJX?&Z~jWto5nKy^QWXuOw78S5$ZuA$2??TTk52!++lVm4<_(H^lTMORc&fHcEY3l=1kah~v?6$w z_;I8+8~oz@(1%kSK6g*w>GK47m|r~=DGy_PgwjQtNGcT=P#5tTzLDuFukkl_=X`md zbr0RXO8ME(k!|mdc!7>`OI!D3c`u7(mCil26K{9PKYShHXE%nlb0q3aOIrHItpm-&Es4($xl9^&32^lnxWIzPKezHQ@vS~*99 ziebv0x)&uBvObx8Kz7qz$4^yCjT2cwK_MC9Mma) z;dX~bn}8c|y+gYw%kUs5E}vlcM#Z<7DJ}W&QjVOuN~+-Iiam-V@tf`Tyey8oszFh8 z!nI_=@3##lZ$_W9CL6aVZ4bL?E@PYgXrs+Jq&}Y#xNR<{Wx(FD*EA5n7_+5rd7Jvwo>FO0GFX8C{({ zN8$GHH&5-#Zr`V;_`dw48DJeVg>m@@Utt!tAOdZOKh=!<>f}}x&-iEU| z^6(m|ij(RwBYvI_1OuGc*sft(6H%dT%2GG7^m6v`mY!Yl;et+cYvdLAdT2Rc5BWwZ zcCRnl&_VgJaUmv2jNveqH`tS{A&tk*YfP z!ciKHgVQK9k{n@ZVwdLk(TJ+Jy|&9?*jcd7-Ro6o z|AMyF>UqB8@9sJWH1?|o*U&51HzYe<6%r;TwI2=C$wN^07yp3D7 zd{kkQ+p+U??7sl4+0kR5C*g30R}Zl~gGZ=Qit;bj zS)>2FRy(_c($-SBJVQ{sym{f>nze~lrT#t&Ypi^aL>(RPZTxhk=ZYzPUAuw~YgSo> zMf`!fbK~DR+7kVE-E3&Q*50@hrw}^jGt%#&IIe$ugd` z>-w@U!v9(KK()Omufesc8mART!}Lz=_ITaO&w^YgO^W4r<9;mt?0gl7Q4ms^t3eSF z_kPdccp@H|gYUM7n`Y||1bn-ISxhUW=>$KQmF*a3Ykz%(75-wdJXkZ!!-bRjJIw3Q z6eeTPK|x#^U>FTI;qOR-g}cgwTLI}WPYoZC2=NlKwV_ql(x6^C)ir*2OnxCpu%p_C z>B;bZD$ZLBzsH$G*IcJCNm4Gom)kOZ;P4*pM;`8Di&8?izZcsU6{yDc_7-tktY6YT zZn7Y^B5SwqFRfj)^j4v;uC}Dd(x0d^Iu$Hy-FSp86>Cov=g&0-EK-`P3pBjn*t3mK z`<(3N-brKg+h=gX)3J3@?WifW$-JuJ{YucGG5*I?W7<9cwRS8nTXLzoRjsVVMVyBnc8?r@Gu-SDrsLNx_*rxo^LD{(!$pwlE z?njKWr(Sd}G5kOgu5hR=es}FIDkJ6qhC9r2MU{og%z6XyN}YoV2Y$r+I?kVco_eS3 zS=*wz&%98>?1zd2rl)sxA9_AxVr;{8)XQKWipn8avDcVN9<`TY8BQi1o}}3Ca@`3W z{lUGn4d{3BH1ovR88PrN1RG?FoZEdQ)FEW?w?lax3RYy$<7PEQ#jl^C`$9LJ^Bddr z=kc$%PhD+)?XFdD@9M|q@$-9pGAabG%J+zNCzec2P+m9{(lRe3G3|EK-D=azv+kJ^ z#JuYr1 zo{%?HXeUrg^Z*!#2hJBzR2H9BT-+VGu#DPy5B@&NK$46mE}nT*KUQmfXe#qhS|4vp z%2b-sz|{NsDjKh)HgVE;q;&QhKTXvus=;*C>kGAx^#<+l9zoK^npZ!1 ze`Qw^ZCiS;#yVzhA1BQe+;qu)<&AZ2S#a&o8wExY1zWuXs&6Ko+4=5cfYb%k!Q(T3 zl27Q^&i$^f{L0#v7nppaw`inkq_wq~J1c*`h3dg{7r!Qzt(r+kU~e^<P>T%5l11psqIn&@AvGa>FXPK10L@Q$vYdyFYm- z-j{*NTfMlFDapar;-DLE8wMH&7E3VDR{g4(8Q#t-2U|pj$h*~ybL&#hf)&My)K<8U3#rm_enE-`0vOz zYyl69WckYu$3J|Z66bXsN*4(IJDk3%JMeeI4^f*837-}bbaQZ`!TzK3yiD_$F zIWc|zcxexgmW|`TEDfxv=3ZUzzG`sNgX!Ae`OxY=<%eVye2()l3QPYP)*3yOoZGtf zFVE4hHDYh5T?8$En=sArzL1+8WH#v5N^$aA)nzmP}G@+64G@vgwTJUSXE8 z@1J}q?dCe`L~L`b8WVmMrld?AlrYqPl@-W%;`Y!;R&%z}&;H>qBiF3zY904<-RBpY z0?n>0KTuUtI^X?JT*>;yMoa-EEtpG^1D|QcZD`L|aXT2wo3Y?H@L8=lLak@`l*Q;B zk<;JwkLMIdC%QKZl$6RdIFX}pY$$=PL1|B)hu1fWHuYs=?ML4)R9ucSjWzki$+Jsr zzxvjP11UPUV5E5$q%nJl-wDBNo{`4FdO2hQeIb+Ht0~H*i*q-B_vvt`Y=>*g#`4>q zM(!Dw?!V0jDH}cpTy5{kZQ?4a8&d9`GUEf?hE=!_poEm^%B z>$^=w*tzS-?Er}~A4ZO*3qQY1)xJ8f@>AOR%rvv}W5*UX-|^rrdsCNX_m;j3j`f$` zIP@pSMs@IsszuxhwZJ^@FoWD#s)fX=E|Czj($Qc~LZZzIbsU)KqTZ#XWYnAUMl2q> zONWg#N~zp_KHJQ0v~3)==~Y7XwQG3DpD!osL>N_RO6s4YB94Ar^( z#iDC=O9c$&n!9u#%j|ldnqQP??=yAuP@9r>=?kw9b@b&Pg_6pY+QC3oCr@R|g?>o2 zrAnRlfAOL!?izRGz6W2d$KM9gmdZ0a*{N?ZIAp27v_2U14({TwKD$yq_HGTnaqo>5 z=kf8saLW7^vHmlJymvT~syUz+)LSFs_}CgQOHL28gOKm&ff zU?j)*P5=RhYy~FO(Iv9K;8&!5;mKB%Ph^q~PF{*uC^!u4=dXn$sisS{PH-Z=q|DXPhWYFKK6C5pF7uSETk$s_I`H^K0bC7VRBRQW$;~@Isr0QpabpND$lv+lUA2$7V07=%U3Jq=28uZ_IEoO z$M|nd#4#59nP#o>$m8L9|md1obfa{A|S5DK#{m%?eDNt@jsvm6TH6Q3;Kz6I`-{X^FPD%Lh3Nj z?+(WXDaRitpJ_a?%<|=L+6qf}Wh|O2@VI$DNMFqLq`^qoptXJT(sJa`?9#mOr>^zP z8xt2Y>-qvxc2ZN{AOD@Fe}8BDrM0a3S`#A|;L%ik+xFHWaiPjbE~GRs%oq>jkdWCYh7aF};! zese%b$+cIxxu$Tperux4p05Y&HwZs1K3Mg-#J=fb`N4GA? z9UTUpx!XA>F^p@&U;9Zk$o@I$e@K%|)6?Jo#4rg|=MnNQNm@YDy;L7Tx4}yZ8ZvO- zpmW-f6Pl$@oNheT`@i0Au~kCX&X1;BtcL)3n1X`}b!6S?>ZiI|lf>Q@4UAfis~DY= zmh140PP_zkmcSE{x_jtIIB#dqr!xg*8n3dz#K5Vn3T)N}Hfya4h`lG=HKxx5sDnFGGu~Id9l39jjz$)&riSHOAZVjR+Z*N#koI! z(w#57ZncJK2cr)LT&HdLY`18c8MV3_F-a#Q4c2hel{Po#&=9#41v;~<6N(FIa4tQ-Z zEqMc&07H2h@t#We3)Op>86Wo6Ga@74GnX4E8 z2_PC9mropQ2c&|vvhFN7&LNlO{P?&J?|cF9GN~KUe7qQ{&u}538H6`V8Q4~EKE1Ka zc*m!UyMMzBXg4T7Qn%@x7Q1_4_N{<#2^jtB7}5R2`WF`4j-Vo}J=>!Rqj+tmT8kt3 z=>uI9KihIe*82OBvixkfrXl`YkYd(`yEl#9W!xI!Vo7X!2qlH{2zAjDCWWOtNYuK) zv{eJ%0RtBcw*j5>K(GY}F9eAEd}(7*N(DK-DS7%v1!NRudk#6!`SDMYPLM91!~` zvpWY9%iJ0v2y(>4S{XhIo00SqBeZ`g`Ju5H>_)+UmhxJ1Ax*k!>KUisjX2qMF`SFr znSCV5NG3?pnF;zoVXDrs|Ne<^42kvP8(=_#j3|xJZB(Un=wArkkgA9HC*5<3Jo%~| zsjUAwwf(@i!=6NUEqEZVm}$l=eP87jC#D6WndY?d0aP?xBq(Ud+v#u2<{PVV@cGkV zmL~(B)W!!g>7DIw>@f=sKD;-KPT+MV-84o~_Ha%^mepfGl}l8H0+_<1Q)aiT<#8r1 zWP4z~Ls8JGy zizggH5TCRGN)dY7^5d>pNyLZ&;H50+_p|SP`I^{)@a_0C)Ilu3{6{j+{Wj@YK3Q5VN87bv@_Oi89||e=tx<86UDMjC-y;z3-R#u zMEU{8zl9SzkPxDXzg~R**FXXz-b|V!Mxos|2XXR^@Fe!Bl0mAYX!h;dNM^}`Pl3U4ok!M6E4N>^iI1r4#~gMwHgN^ zp&DOI)2BopQy$sC#8kn@rGa}RP?;pCOo%lK&a|&^IVPr@75L0IippUO(;zTtg!ZmI z8X+^MVzLw*7M7u>YC(e(#m3G}zvCJC8?EAiG~K&%M-fcd&DiBJkJkDDjNR%nNr^)N zgklVfM<)PPSTb~`@5EkKRPN{u2L#28EG1)OUdZaq?zn{p6oe=`Gh#{O2uCc+CVx77 zG^M9iE=KjOr2_7s+rdux z1mcCifVFh=fFc7v$`=(|&V||yqU?+?^ACu*zjpUF7c3TRVoAg?h|lanFduwsPlXB; z+=t!gowztnD3<^hu=y86C_damz(|5fuIFsERA=@zb|3Eg1Dq)wSnh{oS17<7aGakq zU#y82-SN@LZlBvqp-V%jCdSR3ax_KOxw_>M1opGp*(ktdgukAH0E{TSxeJntno@7qXF`gH@$_QNU!Xkw%Z0uHg0tQ3!8IEB*vo@=T5o zWv3TH{%xQ2xD4P{h;O<$@3)2e(@)f*8~%S$qM4CcCT6<7R~RXL+p14k&0Xu+V7gXP z?cAmy>J{qY+$b-KwG{bOAtyGkN(fEl=q$P>fBVFD^~L=!54Xow*o|?X=2_T6y^gv} zbar0Tccm>mWz%B)25LVay7+s7FOz)px5)2j9h6fz`}X(!X0I!?I-j#|DLQjS*I$y@ zupd|5*+Mo7%rY+#-};V%2#`uBh*=&|jB8|+a}U6Di2`Hjx82<)>-q$bZYWyhkL*y5 zXH4$jCYUNKb}sKJ$OQuf1H?ZA_B>-nZ=Kh4Ql80f*=eylq2}tZN2%^(QxQ^ey2n`k zqcP=_@71W`m=w9X?es2ZSQqIls4~K3)j6|TYR2Pya}~G8Z*8nj2n(zDTCwpy?IMMw z4r|VTc+Z8*xkx6_BuVN{hNX4uzRDNtuoj8DmY$&S+sCrXD9No)8>5;`CEI5w>!zN~ z+GbX(byc)@%i9uKi=-scMhLfg6+Pl?<1-#b zx@>t?DU+d_G+ylu#fiuY?-`=-d~RsY$p|FD=Q zyHLMb<-ypw!>)@=6js8n;&qngCH=x)*8Gj>0poIUP{RNn!DAf<1oa5Xo(P+YII{ z{|8oK^D8r8Eo`9LCS>cPI(+WrgraNzL{q?(f^RnB!m?dur+WdbxX}EK{#MR1_e+w3x!rQkibGqbJiprg_JuzwlD`yJy9|&2Xn*)H zK}&bhoJY_8kTFeDpkny{(!-vmm&+KQ-WbH0%3kVgOfgZi9muhB2W6b+H&Z4PazzKW zC8JW%7iC9`2h7%FKuZhbR0U#1RqDpUmP*OwwpD$pRP%h$th9FK^ctb8YpNfc0|wV= zA9aft4CX#?;D+rf%=)pAzR-*&8UJEb*ujJimkcwtF#@do_Sj*<%EaiIR5HzpRs?Dsx^PR%}g<7*6rCh zwX+e~=D8-{?2Q8PSgT<2Ww%=6psC`0?$CTUj)_D39Zhc3(VizE7CnVaI9<;DJ6)FoPFL@Zm7>^@nA0LmJhxzP5edc{QCRQkN4;7MHbn=WQxX)n7kUJv*j1Q*b!` zPy*9`#H>~Wb>@IJ0%M$McK8}9jP#&!rL2gIZw6M0 z6R!kCquE)zRd~GQ`zMzsHZ(9%aGVP442~Pz@TN?!q;sWWLXk_Lv~%l~3w0@y1MV+p z70(^E>u|U#o+e}{7?{v~+w+>@U>wJ4hEvDf@}99pUG2R-x9R^f#cP^& z_invF5xDQPkOo;kor6@RM?zTV&oqe`ZeAxeVXyQ1>8O^|34!*h#D#4=4;&WOrzyKD ziT`~eayy-paT;9%D1jDj+8K(2LqkLtKoJY4#lm;syjhWe#59f1p==?)X_WqTQRQ`nnHA4}8i~R+ zd^78QV}m=3fbTOFtI*n~R$%aZYAQ|2H#RCNxY=?L9?|h&KFLl6wbiU3%>EwpnSXQ< z{zh&JD5Hs8C_1l2-J8nGtSB`(fax_^@Vcq&WYlprPCa9Ju%?qmZlgK)tAs#}Ch`EK zA74`)wKm6Ew}Olwc~S$atrp)?wx3~=t0Aae$UwZFKb9}?>pwWCw7SN-$9SAA=|JUI zCWU%$j^&5p>|QlN+1qRQ*i7G!ewoE|=Qw;3C_tL>sbdO+wNfgZuXyj+_^tOB0lWyI*--7cAF&7#+%1eTs9PGU}`|7CD6&=xwj1~p8kJI_Zzs``Ox6{ zir;4@DPNVAxxq??7A;t7ckbP*2B-54-?fUZE0Z^OcNe3eHTt4o)3zsx#N#eoH=azS!RWr4`0GsIF1@;RDKfOakBo_^7raR!$vni<{2w_~=7vFD$dCL(96yEUV zeuSAP=KO`F`Z4{7Enu*@kH4|Bw3JvPj=Co@y!rcEO~!-s;5EOGCpq`5)y>pa&`a_8 z+#l|rvh(#-#uE?y##KLl%ItC}EloIf?^kZNix!J z36|TAr0#p6D?*&Q_|Cl`K3m3;vSuwx#^pKz~&$0 z)-MJ27YtroY+Gx8!PoeVY9F-{HD)yi<(aqW)5zG6s8R6_Ipvs)sNFiHV70$8-{8&u zT>n>apWQ*X4Mkv@6IWeuXg4K2R6R^R+Q~RSuWGXTOJv5oB~$Xk+77Q`2HNg?rY?^& zu3_c#M{W&emHDahQr@FqnAI_}|FUC7DCDK2%WqYI+5W!!-?u0j&-C|Fj=@BHPXN40ouYs+j(+48Q6 zxPBb@R+*^!OD4E{C@A0g{BU9Gx+FE2V5Mb=8{MZhRCxQ)ME8RC^0nM|FR$F&_)}9Z zxvEb^rMarwu|dh<)xxL6iS&tls}y#1tmN9JoXfqOZqq(zQkwoWYBdjycdBxT$GRS& zUu755ZmU|F|I~goRr;>C*9@7QG5U@C*O7`eV&;or7Z}_4 z$-jkLblXlPWWa@gXw!uIw#8mz{`N4i-XxcEU102=SKo_tT+Jfwdvh9krpyO_ep9Ir z-{M=oy#C9V`})@|6_<1tBSfMqZlYj~+nnzCA$CS;T9tCIzyrO<$5LAkI_q|IeNJNR z=H9bbBSx!_l}{d->u2ZZXKj|x_2xvXK|s*pQ);RC7Igg%INn~oUvu* zjC*Y}Z~yKO-?r;sFA?|ZhCRn zVN7JpaE~da9srMZe^74vt+M7Qmqw!y41YV5vXe?mG!l;3i?R>ZOBedk$uxsM)S51|(2j2etse1LYWNP*y_Eo2jQ+-qBxqJvM5YAf4 z$Tyw3IMdk|LOs|!w*I#JigDrT|NEdI27)e%o*(@!*#SGw|5Le z5O|LyH_19DY|69M^Q+H(<2<;qo(XPjsZ1_o@-SXNEXEdx(Ll zPAR(xkV@{3&dSj=*7uq}i!Xo9F2xa?g;lKfyI$1zE6_l6$53$H?OG;PnR6ZD%X8etr2&<>`A0ZWU5KF@~!Iq-J-uX zX9jKc(o$_Nn?DlhQClOVwD70FGJ)@)f!yranfa!JfYXADul;)3hO_Fx47YTup`+aE z;^7yHfp7C|vu@kZ*);#4-CE&C6Pe%ZKC#Po`cK25xp^31ZQwZ_y99=gP5F54M5B_< z!*V+%p8Pk7iPU*EIuX>1vz2YR$6r6JtqKghLI;w-P|=eo*%4Y|NLKo|E8~a{ozoo0 z@JzhT&UDd`$oINBELnE;I)y{aH+nUfulGEX9 zOOH7%99ch{;T)&C%3mt8y zw40sf0x+k$*)v3^Jf~&+R2K8dyaTDuwWqyc(~w-H$bfVH1*ce(GjyF$c=OgpFj-&3zf5Z z){mE$QFnlvL~<~Wd*ow0d_9_DtEM^T=~V0?$(2ip)+NvqZK=Z6IkbL$=2TyiBw3^j%Ghx2%E7VL!B5h4LaSH9Ztt(wF})avs- z7*JyDgW~YQ++Boj6Ll0Op{Utsc{Gn(ePzjM4gGBK+WqdmyLU&kkWJ?JzV~21x9|@s*rugDJv^W?Fl@?PeiLp5OKPOsAc)MwY!uoZsJZ|cBS2s+#!UmS z+2?hduh%8*1#d?X+Ld)$X0pnvXV(6!-=9Gu-6h_*IO5*LAkMNMhDT8Q&f|%U!{H&yS|MVWf>$McC+2W01M{f66la9gz5ih|U=wMEO!*6sZ(3 z5Ci}@k-7G36Do6(l!leTg2YJF-AHd>Mc`T@L~8g$qKX9{Zf8id9OOKFf`T`o_k);C z+iVmYJ>(6sJ;BR|GA9&M9zaHE9U9jUFg{FfMd#;>rHd{^!@|NM;x}{(|4vZ$T3M&c zT#SZq0xHV^7yQ}D$EU|;Ve3isBb>UaY;cy7kO|jA;;vL%H{Fz&i#ealm1K4oebIDfgjX{|$hX zD6|0G)#vU_|9^B{FZ1J|mc-XcSpZk;0}yZA>TlXk0ZQm;vr%Z4w#mqRA7|Uoxz0RR zL&fx=rpFw>8Yer{8zZVAih09J7sal6?=IvOgO+h_|FN zkHhQWjFy(EiRtH|(1YlbJc7Mo33BGs}-VkuiT^SP2IrUrx-zX1wz0k(O{2 zdk)YO{(*?|9_Yuqy6o^82Kr4h@0u;&v=>jExPvJMKaMQSJ{nPxLrzA*25D(oIXG^< zF-yQRLB(y4Y&00|(63)F0AhUCjk4x6++sK!59=4aG5d#?LkSAtF|p>mql3d}U*=DxKFmH)0BIk|SW{P)^jdYO|-C)a_5_=;1Nnd{5pZ((yv6V3kuJbExvz{N^Z zrml~7yhmgq;#)}=I1)$r+y6>m`4ZqhUYK(9khyCU6a0<=24fou0olSR1rLavbF+7M zwn5Yc)od8x(A~T5Lay5$_-MtO7!E)`ovkm5e47ybJVYjzTUETggs24RB04rH_(Do%+pO;Ti#KsWxGM@7@zS7#H_L@4 zK9W6#og#sw7`BCJ$72N(EFt5pG>$MxJ&P;wIO5rBnBO$!e}IO;C`{&fT2Z~hHL2)& ztlEN$y_MiY9A57ahD=0sv=xUb))1Bo0B{WK+Vgi}w~1eT!gJzxHut)+ z2x%~s0PO*s6Mk_KUgtC+Z zqLFA$44pPYwf+11g>Xtqf<6cF?PbpV#_X(=%Jd&bjIry!5CS=CvEZ;J{w&zNuYhUc zM=|iBPT)Ek0}IYxA@$K{5I6s}ijC&~;IGG^__pjn@R;9h}L$xMZw2 z&fLCN9vT|Du{aLr6|kbTZ{*Y{7Jzx&sB>9e$h`y)hU(#d=_0N8>d`PnE9A+1iim#hR}sa z^*`M9c3b6Bjz<8(`zFBx<*OW|uIk7ZXzA6Bs z46rRp9QVYNx_KP-Zhv7Bd7?xfk)jwL8Vp{~w{AuM`)7Xot7iK2KdQfZ-6kMKddU;u z7lh$rMp^lzX=E_$0vIl{(Mq^Z!{uf<2~>Qh)*CZfn2+_H&Zl}ls!u(45vL(>s~`sR zSbR^watc26i{7ZnY1@BM(@?SlZN#L_0l9kkv<=HWxV+_%w?>_Zb2S#FzaK(6D+a&PFQK?sQPDlM@GlLKe& zt@=wj?ay(O5@Xko6Gl+MoQ#tvdyAAe&!rgjIN;wgfXtRln3#Tia_Av6r7EGPHNO`+ zrWmCzE-tojPlVeJmM1Y65GaFOO9kf^@s1la9wItkR0QoiCl}`Ma-k$8v4p5YuxN4Y z;i`&w@ZboJbo?I#gx!gVP{QUo;JL6DRudZe3E}(q?tT5yD(rTvb>75RTtVX@3EnwMyB zxY&kq50L)@^@973nnzL>;ITney7+ntMhT37fV60Fs=;tVG81TswI!~9z@{T_2%7uP zupxkhmJ${g#Ceq3N+LKxOiklUyU7KDk3~dFUD*DvqtLx$n6VSwJIXa{C!v6D)syu8 z+e=H}P@IL2cAFoMxK1#748q-sRXNHlIFbz@ngEozhiY3r@1vv1I&9+Hc}?%}?4v!G zHJ@alqo%L)$*v@NlLmrysxFY(LJwM4U;61$LEQHUyDnlqjL7fanHoITPfE zOVIlZ@NY@m^MJUBtWDovtTM|c1QXnzuxjkb01@-!1D$U% z?nX_Ln}3Fv)Yj+{;d#mo#|K1pKp={r!A*AVqNwsd!B-ouuo4r9FGAFF?8C3zHJ6$H z15NUP=X?@xq+QRoW39au;(gDrEY0tWy;+otz+sTsOpu^>5JC3f3r6LjXH$-&gIwL@bOApD5s(#WI_cmZUO<2F z!lXPFHSr&)nSR4?<1tSBFR7=tgWY+V;{`ktNIdr?ph?(Un3+_-@`;=;c;lhGa#8qr zB=cOINXN9<{Ki_F)>nZDkjkr(!CnAW_Y#;n|yFk0rfH8+70hZ3&2=7FW^j)1KQs>jz>}wI}JDbVt$C$*JKhjJRFY) z@IxIqHB~cjf?SsfZh@*pi3tDBowPZvCs9(84&i?t7(lxPJ#8%3-oH}oS8i5`G(yld zVXsvB1oMddhhkw|fRR5UiD^+|ZO2g>f0WyAgc`k9EUw|B@oUh+fiMQxXLi_i_*Jt( zeLP2Sd!ggyupjfd{YBYN6vmODdn5_uYl@<5Chb2OdeWOBgBYFm5p-=>QvIM>Ii*bm z1<@V3y@kF4mK3eo7if{W1ZRw|#++Bc5Cw^?k~i5N2R+F{LJJKq4_dGUbCyeC!4`q{ zl#Q?!#ldTckxIWpa!qi&5cP8ith`sk0+|1wh4i2gU z6r&vUjRM4v)&&A#dA|7C_X=ej1yC7(wCXR>mi@=0%g-|Vl@M{; z>~NfD8GJ34#%#TFOti8L3;kdxjiM5BX-N=MK`u6Wnl&Y4wFM2fi@STfLW-v82e;DQ z{gZQZm$ByvpAZMkALMU-4=H0SR{~Y%;eqRVp{jN!f*LVLaj9d*Lzu|x`kvL))_#Tj z4^`P{R;NpUSTZ|9uD+-t4miT`gVzGl_5z@E!J8jl1@~_h(0noUrL+sgD^jx^3_nc zEq$=uyK(bo`liwARyaZ`Yin;}$kn~lhIRc2IY?h~X^_x;0?EBF=_IyS)@`qE!N(<~ zb`mWJi4i7(@3*&kPGDOYg(CL!9y-%@i71RGNZ!1$kQn9?KnE$)7CeDGhs#dUk%9)( zgbZz|f>&=pBjTW#_8|Dq#*fQhw4@&--8N3@pWm~$$LC!^#Oxa4hZGxPz?I1x(qjzj z1+Vv#J;h?Tzm_*FE9e0TXhz%w(+_iG_y;+FOXmmzDTHXw@YNt@8}YKe3qv>8b05J| zz@Y#X%txpsfnEMjj2s-!$PtaeW*iML!_qAZLz4u82mOW>@7YhX;&l$os}tw-X)i_y zXdS!%G3=f8CQ0?2la3$ap7A_nKXm{?$8yD zkp>VY9Wvdpaj>+`1;cY#87)@=lw9(*1jpGy!-><$buGC8eMMRm7(rm=R)hed|Rms3jX))}ZL19vAQ9e#<<*9>1J!dU9&&QP9Rg zHrBu`k2$aG%HRIJI|iGE9Wv8;|3sP5RX3l>G%2^azSZEWmX=lpoUy|ag^2a`5hYVw znL~#jGCS;hk5LLSr9*U}6#MvdQ50SuW98b@sJ!xRI&lZ39QV{>Q|-kyiW*S+xrO@q z^V^6yV@nIBgqzsdB2zsKdC@eJp8*nXFX%-SrQQa>(=O#ChVe#*@Q)#G~2S zy_BiZz{r^C5rS)ReGcL(X1Uo!g(&4AVjc^L!N*5ZDqBvgG%eD(Vbq3s!L_%%DlJdq#i$JUbZ39(Lry^|*`X_6`oO3Ybry+E)C9 zLqcaP*XI50DYvSJ&P&FlsUQF5oFMI zz>km4&op&FoW*Ie&zF{0G36_&HIbPomh{yc7OnoqIY+6DQk}6|ULl8En0^|Z_LnFn z>=R?+tpd=hU~g}`%}lNIa`4Ryc|UQg&NA%Ecqj!M3M0-hA%x%1+gphmnDE;$ zKgntufv2Y?`0a0ebsZ3)hpm2bbZ7+&;hnss5;FyEz48>ZNBiF3_$8pph7B8>M!u~_ zxcmGd*ag3CDbnuRq<8M<+GO$%Y=Yw}P5@HmL-`~u))<&(^7n;tX%s&8B}!NMrAd`5 zxnPczR^5?nhKC)?&~?$qzOU!WR+Ifo!`vPF8JxC z3YNe!<1_+-L9MbZ^?!qM7)cVgk}I~YuLJ-MP&XAFR6d55_bPv*xr(or?JA$5aAC_1 zQlUW?@eF4P+S5C+vEmvm)CtC>L6~;rYwmc{>4o_qQ7rZKnce1<6W+kWMGY>Yn^PZnU(5(eVG*+Ixp{ z+5hk3HYugDqG&0ED68y5Mv07Ul_)z&WR{X5G_0g-$q3miWQC0EkrCOWVej90b>HvL z=ll5_$L~14e|$Uoqq{p?uj_hV&*$TDp6BB{(RIkH2T}!DXm;lo6u^Lv70E$M#TzTq z#H4_o&t4h_f7}2cA0Lve&(CBd*=SWa&2u-JZp(Mu?=|p%%2Cxa!L|^uISQXAW#2M0ey0O^}IZ-71OGx)$& z852DjSmY!ycp+fVva%TELHtjEk)@Ee`vrJ;d!u16w4qf4Hi;$z8nq7(_~wFum%w=I z5lpAfM@ao?H@I&c2zbF1VX?#n6wxiBjPWrUua-}~eEGaO1NMpP+S;<}>P;!yDggfC zDv=~wiNsd?;2kDR%*;ev!l1CAd}oHs=MZc- z!V_xJGI=gZ%}oMD2vJtxr@`{=6W$%WTer%wxhKwtpIX~7x&tCNe(3Ec1mW#3O6!2? zc+hCLY5OR4Vz_@Y$)vQjqbmRhm1j5j@OLh5&wVPo{d|0WGb0V~=*5T^(f%STn9NcC zE1ny!^BkTX;a*EhN~*;=0*hTnqZZcv;}1vT|4BbMmfdoZ0B6##cumTsQljqs4CMI} z!W}=uUke%)Y25gM(3AcV5fOHF+u>080&q8B>NPhv1l?{BD-jNdr@Rv^+4QMlRNK>? zM$LE5TBm;TjOX>Kp{ZpGv)su`;13ui# zGT6Gq{0JdWrvbkVF&}&+WBVDmgFwJgYGFJNF@zqXD-vat*63!%Jk}*Zpi*DLtmHr3 z`0iGBXG&eUB0l)a(aPJIq`f}^ZvO8&f^BCq`h=KsAUZg%CB+k7K-H^?CkYG7KzL<6h*+}19f?M`Ht1` zU4^0JAHZ`jkVJ)q7Xmf`=74ZwY>)LgbiR(=s$9Xu3-QpHMg-%cDbJ;7AMuUe-&kvk z{f|-V4E=-rd&r&vKtgyh;`8{(Fi)~?I-z}c-?7X)GiJc1R8ae&mExX}z$<0qQ3==u zEZZrx@rVNAdm#c}&(A;_ztmssw8NHG6U%-=T%2veot2*qDoT@_XQp7DiI986f~>9q zXjKQ1adldq0g2sl&c&n6YE0UgX8DXHcOupXOXApcl9c20Za4{TVG+2CTEZTn%MM>J zAUJUZno-aF(CZ7JP;3KNcH83Wh;0FuE+B3xN&u3;4$@bUt@=h^Rn^;1ca%+RWSf8K zmASmDiB1?>MR`+c$9q|ap$BeFfQyd&)-kQ3Pb5%f7UoFhLC6lFL?~DCR0|N`O{kW- z6@?(STSq9PWM{)*K776JqojVeRTNGUsMJ7i2VfsTVTXs(KRj$!sDoEz7%z+|Pon)RAS$3_Huh#R1yxwoG%&%24_`Ox8gv7|1dEZNc4PLwj}=%d*~?#=i7Z)E3Z|n z@CB$i^t{M=TA1X1hcEkF=Ey(YX!-l#!02ZT6+8WSc80i5Kv@I{C5KqN{}r)-z=eV* z{{CiY$uPS68a?rgmoIgvuSA{L@+lW&F)?+8+dY7&WNdtq{Pba0a&4z182PRbkBrnt zUnhr;SK$+xZHP#P2h+fA*#vL0J>#}fxqtE#SU!p-H7UiVr8VXzSS`DmynpC>0=Kvv zwOZ1gn^s(z58gMdP%ZW<_JU*~r+e<$k#{U?rlr*Z21kOIV*s$7@Jc==Fkec#qoM;Y zeB<_Qe)a9bu=oQ|h}54a+<#DF<-N7TgFRtCyagF@Krz^wyP>u~Z0<3CQzvOO@k4+@ zNh$@$#c|k?5YvCyBDI{Ncsm|~jQE2c_&B1Q2y_?L^X98PG;`kA%UBu+o`$d?1Mn3> z>=z%fUobH+(1U%%&hlitsme=6tgxgT?3PSI85tR->Y4X;GBH(Rr%~ShO5E{%I%mjU znmKAYpB2D?FjC^maLatJVZ7=ngBH|Mr$wiCN#MWc}-?ya~UJvCwTb0m&Q-&Ub z2tXJ>xUm=NOSxv169*~e5rDKu@OCP+m!+JH@auQ2y(~I-q+71MaA>k?(g`Oo4uUAJ%FWP9NM&qJx1p zW4y;jpk2OVZ;LHv1LIVA;!VOX7&&f7Qw!{>`txTlZkj!Nz~%217w;DH&Qs+@;e|pW z=Iixb_qF`a1=DjA=5pRaF1v^|0ak8Y5;ZbBm zp3yq_?s`_&4)bZE`3AUS<@gL>E%+*6##HhX<1VVfWM8Ms*h-#+N zuGERmcbLlWANA~^nMHHQU8zYu3h)ZEw%>7>`~dB-_vA@E=N9mzGt6TC{=@_ns#F3t zwR^O;#U8om<4H22?ecL#ZMQEF1z=~2rCN5uqk;nQkfX*_{n!C3llfn(UXw6VQzOPV zP`MHUv9a*6CTcuBoWx>w}PA?tYaW@1LrZaO|P zRM~#!x94T#iym8+y#YS`0UpPMSw?GOkgIR&F=VRPeq4G;6mg5cF88`E7{Z_UsQ>l{ ztkF+TeWd}cGEEs%tuJa8y-XLv+rXV z-|3kER1Gb~7P{0Nv0ffx?9RP4eV=X798-krAB5AMy@VN7R-{i@7WzaJX6nRv zt?IjI4pea!+eL_;6Ep;NX_UjCkhHDZbpjZ*No=IVdPT95|HzLJ9uk3jn|MF{aU6v6 zHU|==habQ5lRzqk?0STT23h^wH^a+;$p+0wOphXKlj3Xg^L6= zHG#WINJu26xM|`H;mr;>wzz84eI^TN1MKEo^BQiVY(Ie#l;BlR5D80dz)9HVx8t=V zH4`^3FyevM@%N)AP}9-5&M=L&!Fe*BklumIXZR45RS`bL>PLkpE6L}5u&Dp#^is8y zp3GY1xbn1WmNuZ&y3zec4*Oght%(Ryna3^kr6Qrza?Imf3GxdrIIcL|3(@xzDjX0r zk4zH#&qSFC@XkvDtAq2p;qLu3K_yI6G0Fj!&d-cAreeMniK?VTDCbxm%X~^pL-TZA zy|r8pLq*`pmCl|`#vG^qHx=&}O@SeXKnslr+|5aCMis71?U%jNqnaDFSL{RzJ7q%?hzsLK<43?;AD|oOA%3cqdA_i zj>=trvTw~OP4dFQ`iCt0N0H>3;}-Qcml6D1j5 zXYQg$UMJ5H!c{mSkZfk+rT3;e#hE6*!o^kWrD=^zsZEL4^0S$K*U?ljO*tD5ht!sZ zQ+A$eyAFEV$boK00{|S7h;)y+#B3#}smZ|1Z?Ko2-ydw8kK8ytm~2;M_z=Y-!4rdO zVaeg7Ib~>qz&pYh7I`)^pdaB4%L}+kl&K)mEmPbWbZpkHS`^1IU7*Wz z({$K0i%nY5(y-L#8BIPNUQcMY$ey~53g46c^-@J;r$q#_k<&c_zD7L*6^ChI3Hk>G zlb#QRLgWzwq_tm}x5f$eBj9|R z3O=R@;a87uYTBScM|%q>mLn12Ok^mcPl7bipODB7Fhr>ygN_3fTLqZb3hV}P@4fbZ zBiAzLpd8j$d=0eX%VM?#2W4B9drf`4NVe4^k`LKAGxq2-6?LTHGvlbybDC0dYP zTLYNx=Ul$%eb5BTfOEzfi|s^5)hsTpHS1ocZiXOgM>FWK2!3{T?WYH`cgIt7s(>** zH#ER{y;>*se1bkV@gHg%IgHYO z#yeh*eT~QhD&Hsk;B=$)S-GSi>!2M%3PutSEw1!!;DC1|kU_i*HuO^4P-0&^T!+6r z4m}Z(nTN;|8T3jBm&gj|eQ?rCA?7=d%}b!tV4HmxJE7tNscahQT%KFti4{5%E$#4- z5pox64y`>b^HD0Cj@>3Y-^{s$x1Np^rDxSUdaH~*x$9F!1tr3}806n+iH}cIoICd$ za)Wf}O9?Fkrn5T0OFaH0=BdW)1auj=9Tf@>g4W(x*jSGclc%4g$FnIG$ZUF{Je^&Y zR&trt(U5FL;vI;LY@u)y% z_5#}sg78Gqn+DM+CuQ)y5?aHAghv45edYd+RV0@I2uABernnrqH!vE~jm0Vut)WZ_&tmCEI`p6Bd@+t9U?20p>N!i;2+(fB=cy!jf{pmo=lgq@I8%= z5&67sSVn$j7kMGC#~Dwx9vteV&xdU+4^|Z2ekwUCEQ8&bc+;`WI%v<*j~@drbx2aO zNMU#!P)_g$fB+$y$d^e)HU zkIO4k3j#J#>$e%y?oN~l^;2GY?bU8bZZ;8dO=X3*PS?=HYmAw5oD_wzD8E9hC|VYf zrJ|1>J-P(`_h!?3s&Qw-P-t9;oy}{&>dD_5&4-QoD$w!|+YA##p<#a!6r^P`gWQtO zi}vU0kLWB=_NYOBI|vM!AU6q|V?K*Rl3i?TIf>p**>JiaWYr}i{h>zJ&r=DN?1+q8 z_nYFpVWf5_gyxgm#n6wV6SBOWloKxJ zMha=awE9kbmkBfa!nSC5w8VqFx2>Uw)k)59vNRHeP1Lv_nDmV3FEP$&ytRwX3J^o z6+dJjTuJV5R7z&6g@w4xwU)KPhj}Zb%ygM%m5DyDJzL3oY?$gFDDPWov<`@c4Ni_e z0?nTw{KY34Qc2#ef<@E6|0N(YOMDTS1!x@M8f@pc5~bW5ND)*d`hJC?xDKN2g=Dm+ zSqz~0wrv4B2*kWL<`7x}7sbLa899^)Krw3!M$CcQfsj|z|oJ5SM`*824E>+*w{XB?5<_~?*>eyXm13=9_XG${QJWB)mfG#@&;fpHB$4v6cG(aRUoRMC=|#jr<9wP3Q}rqkkgM+Syscbq;lQ#!Nw89;oE{ zk8Ud@h?$56<^nwG;+@?k%o0Gy{#4-m2uX9!31~r%(5;G^(USbr_?zfKSTL zzg6u(Jwe3bLMyFF@fipR87$FF#Is~ub&|;-Xb*(}0Sl9$Pc2&v{r~4Z0F(s)k4C5( zcJXG|y+Uw()K>mqDo2hY{g(1sLu8zD7Eyaa%3f z`>dR)wC|Vo&A%n5oj+4iG0kI=`pT<)Q7813vcGA{YnUrVogyGJK>)^$7Fh=Qw;tp4 zCLF2k)P(nPW9n}ztVG74+5<=Nx57Iwph^P?<%9-ttgpCOEP(;Sb|fFAm%mv9eEu{f z#2auNKu_S8Kw~fzw@+BObyBRNqJl8H!f9`h`vJzk3QY&FC4&6Fo~3u|br=RJ=b;V7+?Tm!U1ki5D#(j^73Bx1$*}bc7DGAyv-mg;O0R2 zCJ-|RP+r62hz`kB6+j|EW*h>W1WPP`2K`M}0dz`W^T41GgQ z4cTAG51PA0iM+Jq0p8x;ou1CX#zt?QbaizlGOYkJ0gENjlMr!jj1<(@*AoB-iXWKA z+mTRhWB&sD;`iK~utJ3}>$yDRUqO2gL##C5qH_NHVPvx+qmoc257k_3jS&0Ok;2WKf~PZ728V_!02e98<`NLr%^#m{ZvJ)0*%@~Q{312@ zNFj?@8-}wW4%Aoqu>0ca1zKvDRtd)Hz9cXvP#8~s(zOJ+*NGmy@*gdLi}ABt&=oO# z(O~c*xS~IQa8#c{kj)nnt|@6OP5h1W6I~$9$VCDo-Fn6LzsW@pycGWjxi~n$o}e#{ zRvz7+zzVD78jt2{i0nRGE~6qchL8lPduT#|{y~_WPr2}JB52bX-V{3q3JHzyK!U}m z{%em3#+eQJ3_0+xHExBNml%k>srZlO6so`*SZgG3Q6hvTz}-2^3*wHNy;l7@wvMDK zAk&;!8rY(+Um>XVAbO-+9u}l`pk4UVWl|>wHA;DH?Ph!lkaNA1w$PKddQrXKlp1@r zxz72{?_xRutv-HUDe}G$)~szotnk69sdI<~!z*H(Cr|d1vH4D7O#dY`j1biYv6tNn z$AeGup<`vDi0!{r*N9gQn;?-|K)k#F4IOGel5W}i_~4TKrtu}3qbnangBTX510BAEe>yw*^*(xGNRO)P>P%7X z5j+|!|6l=W!;nSb6$>znq(w2dtQQjQ@i$Py6YnuSTfvfn0u4wYkzCM|ynx%59>UD5tpz-rY0e&<2NKr0APEC;WFt+<5 zMWp=szDU%KMB#|C>4`{N;7@wq<>?ctYXv1PR9H|*@9a&tRES;OJdfoVp| z+u?XIh|uJWfSx>iZ}2$buU~@?7jb`s$g}S)1f?Vz# z*M)!Y4$V5;fjJ;|B!a>;9;9Y|7P@$_5hysaD~J`c zy1IHD@q;*5u{u0)ByZ)AdZPOFc&{{6^6(o;6FWb4l-qLi);Ca~oj&L3Qwd+$y^x(& z+STAbl@eK*W_4jorKPM_0e}*6H0*VRE|hTO0ssS8-0BHPY(Te{p&d45-@Ii@Am5qR zN3pr>TL-M!W757u}Ck;<^=Gfwd`Msc9*`uKMG_odv&g!rJsEHzX-p= zSI#bge38s{_1jTH_3ct6R?kZQC%JdM=)cIlR`nZ=O)NMhDo2#kOP5QJq!xZcFG$Q* z;z9@UsxiE!IYnpUyk2BKqUtqrGin`&=3;l>I@FuD9?S3IroYC9tkY>>UxU_Gl5G;d zNE)O!Tpyd@4BK8sLpS{64HUB3A97Kif|4RM?HK169353OGdqNr3i9w55U&6dQL|~i z*}OReQ1y*}5$h{#vSZhMzJJV`VWFjbbHcuI(h@9tA$%KJO~9eDOz?y``|TThi=rzK z)uxtMLlM*NEnBu^T5Ku1@(}!fI&DE#1y!m0=B;g7NM8DaneOmBN_MGxgnX>p-U$+v01-|i=DL_>82^108l=jikEiPBQFI_XD9Paq zU@u={O zb1y=tZa%r`Xy^!xD@>teAaGeUrka4@gcUDejw!S3a&Hdz&n`cUyixz5 zBNQ=vvuVK}?;)xkr0@8nwlLnkpR8v+7rHNiioi$+FVCC8<9HQ7O15*qf;8kaIL&iV z%lCO~6!k291Nwuvu3+crsUBGh=L#snh`~t62{0i7R@g^_BI=CW_nINWmsS>@9T>w#?T_>C~IvrB`RYGOmTIf>P| zYIWNBrCm9GZ$E$GINxLFgop_r5Py|`CbT!P<&ipSWMH1(q%pPUj!5h=~=O!#5acU-)6Q<_amsp)w@ z#TUnuQZaYPShd;n(#}jhJ~)7%#N8rlbF>dcUN#^d78Gqn%p25FbF}6eZ6u)eTbQ6> zAR(|!bmJyJt)g5#bTu{=z5kU{yygc2ndkkX~9^8uDFL1RcGG74uu2 zNXRJWnx?^h|3c0d0mPzRAx2SFk9o0v2S7*odto-_vz4zTh8ZvEZ`u44@WF#|X2`u# zbs-(SFB9{X5bBU9+2@#`Twa8+1-KzsG;cu1^uqUdgoC*O+ILjiii@$wjoSQVUHe4ZZ{`h zc*>~WzkLd2R3!zJ3R4jg`*fphS6PuF~5O(j5C9f__01=H<@%r)+h?tn((uiEc*m1H!-i{P) z%XvE`duEF6&9M7DOw)Rwzz~=zUcq`*341#!toI|t%IjgtFzm6h;6X~5Mi#IB@fDL# zJ3+`YiBI7ocmNN?${YCVgK_zPq`ZFUE7_Q!5+YC zHzK*|M`%3#o-#PfroEO4p&_KKX?ZdsZliSGnEEHo|1pmB8DwbrzEgh0;92^mQqLV# zSMMnjL58Q?WdHqH^o)#@GOn(Lu8&3O(Sl*(rL?ZjkHdXY);VUgaAmC03ny46KUv_! zGy3l@4B=!8rJ*2~m2un~#aele?9^-ylZ==Eu}u@@7n9falB`KTR0Hsn)mTNf{Uqbz->_$*iXPuaFeuEu;}3d+*erL;T8 z7Z<-x9F-|@7>%SIkCKbJW3OW*8(ZDS(d*GS{|~%;;^t|?z_gv%2?Lllzmsn7eXkQ{#n=;`>IA*h#`jkE_KDjYdqQY;;mDQa4fv=d;sV zQ8A5st=5((_LCRUb8LH(QX<7s^vie)SBXjq%bI7&*1hr@GaAkXv^D9ix9aVdm*&Y{ z-@R9IyX2|liEWQ4^2bKj$+)PDsI$YK%>2b$lQWxDKj>paTv{55AjU|E2sEbaGQP*L zJ~=Vj2Tb7))(_U6@goxp&lXKZ#p{jyih|S$FkTdiHpS=h zqr2JGQO43-Jo!f+_4Jh1(dlL0J^bb_V#|xaQf}5vmvEN|mrPnWHc0kqtbhG|Kt5Dh z#Vqu1V5n%;P#3YjfZ>?d;yz9l2Kg9u z%!z7wP{~6nsm^c2D?XfB%v1AppUSQq)Xz$i{}jTZ<9Jc zj$W5P;jF1XU2LpQM$R~t)5kD0_ExLFwog0oy&)qfm*VTU7gPUO3%_pu^@e(@W?-6t z{4N0*^|tp#;v+tcKF6#=qi>DJLP?R3N=JJk@W)m8v7VJ_u}Cg>LvgW*=-6I!h%hN$ zjMkIV1_DAGiAw22X^VivabsE1TZ|Hi^*H$4WjOx9*Y65N`bk}opravS(%K(VLb)i* z;nlY#nR1$XojiB^f5GdKG?`vS7@U)Wjp7A2&HNUeScejY;e4dNOw7IT-L(y! z1sDC8B2L68lohWr+4OiWI_3V960HLB zJMQtJuf@{II#JW<@E$zA#h;z;gsRq5a)GRYOjEbz{rs`tH(DeI;$D(ZwryDPhzL8| zSug66I+N*Bdh;s_J z{Gp%n7pwcyvTk>6g3b*?@2v9b#OW7K$+{QA2M14{41=%)V}$3P?F&-HAV@+xnc;Z(iSJhBGiJkJlG%Xi`BQSQ0+`uT-C z!9!=&7CtnD#Z7lleqnE!b(DgS3TwI5s3%9jv+@SUyt>R%1FgQ$Xo zS@Zcm#;p5P?^Y^Pvar!NT{V5@@|*P5$LzF11V!XYB`dEU)ch9{sRk zK(TC?w0=L#hTSKuOOjUSaaUXNvDwzm!|n-VznXK|OwUuUl6bV-n%~kNv0U|#Eal!- zne+X{B_u7QSx4x#HmxX3MD*z%^~|^{nn-L}agP=J+@-fjkV+&-OX(CV(nl3bCQF;y z?6#cBl)J|t^o@-ltZzTYcBon&Ekhy!Kob&1hR2Z?mF?b*waYzBkjL}@;okV{Kx?*H z(B&C3ErF_XT#fxmuipo1%F?-s8&hFn_0xmoF$(WsO-FtB{HN0UY4(RD=2@&dA{A0+ z{_GXWzOtg7tQO(Xf0xHoQldYjAvuS*A(K5x3dP&@cp{Ljg?nysd2W2atZSjO_$@`r zzt@-?qv+!@6{Q{+c4W^YPwI!zingLrCW{ARX*?0U{Uxha(W2QM2zTE@ zXly-}YK>XjUTyS~3oBdEy?JBtV6i5MCxM!7ap|2_Yln+dS zPQKQQ>QNK?m`GeI0|$r0YSS^Lw;D0SIkp!ih|4`}?5b{OeODODD>-nIDgG+H0x>-XoICoAJ<;K4;0H0!Z+$71<>^^ z-(fQb5N-NC*1@&lJX#zA6=aK}yl{UInuxc6SP5krVR`svup)T=Y;`O;yricS%Mc8xTshN7nI%+Jau~Ih%+2!Wf-W@p0h`Z?L%eLH$WI`JVC#GLr45 zTNc9+?9NI|6D@(`0CUQTmRe$EG6Ts1>1PE40Xz`{$#&1dhT}D-ySZ(dnj=9}HbLQ_ zXRi!}bLM&k8cL8B1W69qA=Fh)pB`ZvZ-CuHK~aeUTd=+33KUzgkx}u2_11%v{KWJV zz`@i7XL*CYLPCJgt+Oe8b8>QM(x`}!1I_WZQcudjc83qpWq>B|$*>@EbX=U($QrS> z;F;{D+aun)k_+qIZQX$kimDIGPlt-0pE_^3DTT?%sr281c)X1c){jyqo`zRC?*Hve zsWBu&GypZwsM65U@!2J#_a6wQdIX6Hrtc2I(Q04@#ZS4eFky(9Vy&0+Fmi9GG>3?- zwo6lQcWZ(3M58QYi=6kVnc+0oyrK4`m9mwe-MvyO_S)?_XZ#a|dwm&{A~g?1AfAJ{WgVw~y$I>pWrjDRb3rF4cpqPgD96tAkaQpHN~ zJCM77IG%Q*c$Mpm0(RPjs)0i-0nyxuY4ltTGC%9s#P#Qt+n98 zS}!>~Df~Laj49ub=dx*3{mP!LVKgq_s#d%`xnKE%BE)8leS+J|}X2j3)Zz~`w| z;T-{_U?Vzm-0ohZ8WGC_v}TCSt>!Jwt-M?p6enYy8HbM|&-C#5H@v?W0o)VF@t!2{ z*SZ3R-1qKNN8NfA%Xp+^qpa+5=s9Wz@+edV zT(lkjT&*5c^Zk2dbLl6qM8$?0&$$Uy@D8ho->7;03Ka~V^7Yr2zg6t6rWWZl&L$d} ztHW4uUV@avJ;7(xu%Kn5%Ad~?5(Y`Sl!;Q1i#_)&b}KtM^JedD{GuB++G z`Kzv4mtc}oogN(%r4o|Z$xSl{`O{~ZIb9+rnyROq+oNO&8xy!yQ_CnSJ`y_}2{wqB zM}a|UN$4^2OVIBQ?A4F{`pxfbNL6o9+O=)r|5b!tI557@Lw#7aq`x##pvalg$gTB{ zljC%P=k3q*VlLW@qri-pX5eu9G~}&9ul-G)?4K{MT^hSEmv!-df=jFSRxOV1obyF- z@rm=I=F#l`Xfif!`qg}X{K~02vp-Y$8PL4iXWDL4QZlVdOeCHYILw0w4wN|^KV5$u z@d_^UyqGZHgl{0&cHaz&s2%A3**0zyfGL{#FYF=3+{E6e0b(E&{x5r78ode#jidC& zj5Oq)Mdc$`!21mB)_?v#3#(KADXi3EirkhH8eU0r@V0Kfar1)L^i%HG-8=c&RKX^(#V(7b7*(k)16I$8wLGCu&- zi$g3P_7adh?zs!LbtfyUG6Yiql?H&Q4)Dq*JmI=^Bhq7Iy|Oq$_C6IU{3{p-(_yeZ zti-pI_&k=FZz;pb5%yxPGLrzw$|yN+r=g&W*y&)%1Tbu$e>$U`U83R}p|R=o1TJAo zan87#CTBwmhtDGB}{wmiqV#q2gy7*&fN3rp_J+P8y6@6%0+cJ8yIet7PVe~!C z`_JI3`p4e>^y!kl-=EW$oYVgG_jGt%bq!fr^fT4B@!90N#Yh6A-5sa-^jqY~HCE^} zD^z6@OddRVKoE4k4dAMyAT=XC(ZK_Ba~FAkopNy4wY^4uK5}#N6-LMF9r9Z2`im?D zuci+LcTl;Xy76P%s_Z(~+3PI{+lg6Rpp2IR=~(sT2Vow}*ThQJELWYB4>G>35E=E*{vzv6Yn6VmxE5l1qBdYt|w&_aJm1_=y?h?F4yoU|G zzX7Hf1EukhnaC6j8ekRsIEJE>7XJV0P;i>erxOAv!ow>3Dr7JSkBnQy3^UQC;do}e zMnm{&fgjUUjlAfkpVOkRrN)qZJ0
    UfG!Tty1!%FUZR{I@UeaU(dl({`z)*wO;{guA+~ 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 SePK&nlajpZ>G!8DdH#Q + +class GeometricTimingDet; +/** + * This class travel recursively a GeometricTimingDet and dumps the information about type + */ +class CmsMTDDebugNavigator { + public: + CmsMTDDebugNavigator (const std::vector & ); + void dump(const GeometricTimingDet&, const std::vector & ); + private: + void iterate(const GeometricTimingDet&,int, const std::vector & ); + int numinstances[30]; + CmsMTDStringToEnum _CmsMTDStringToEnum; + std::map _helperMap; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h b/Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h new file mode 100644 index 0000000000000..7219d283c7fd7 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h @@ -0,0 +1,32 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDStringToEnum_H +#define Geometry_MTDNumberingBuilder_CmsMTDStringToEnum_H + +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include +#include +/** + * Builds map between Det type and an enum + */ +class CmsMTDStringToEnum { + public: + typedef std::map MapEnumType; + typedef std::map ReverseMapEnumType; + + GeometricTimingDet::GeometricTimingEnumType type(std::string const&) const; + std::string const & name(GeometricTimingDet::GeometricTimingEnumType) const; + + private: + static MapEnumType const & map() { return m_impl._map;} + static ReverseMapEnumType const & reverseMap() { return m_impl._reverseMap;} + + // a quick fix + struct Impl { + Impl(); + MapEnumType _map; + ReverseMapEnumType _reverseMap; + }; + + static const Impl m_impl; + +}; +#endif diff --git a/Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h b/Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h new file mode 100644 index 0000000000000..3abbd7b029e6a --- /dev/null +++ b/Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h @@ -0,0 +1,294 @@ +#ifndef Geometry_MTDNumberingBuilder_GeometricTimingDet_H +#define Geometry_MTDNumberingBuilder_GeometricTimingDet_H + +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" +#include "DetectorDescription/Core/interface/DDExpandedView.h" +#include "DetectorDescription/Core/interface/DDRotationMatrix.h" +#include "DetectorDescription/Core/interface/DDTranslation.h" +#include "DetectorDescription/Core/interface/DDSolidShapes.h" +#include "DataFormats/GeometrySurface/interface/Surface.h" +#include "DataFormats/GeometrySurface/interface/Bounds.h" +#include "DataFormats/DetId/interface/DetId.h" + +#include +#include +#include "FWCore/ParameterSet/interface/types.h" + +#include + +class DDFilteredView; + +/** + * Composite class GeometricTimingDet. A composite can contain other composites, and so on; + * You can understand what you are looking at via enum. + */ + +class GeometricTimingDet { + public: + + typedef DDExpandedView::nav_type DDnav_type; + typedef DDExpandedView::NavRange NavRange; + + typedef std::vector< GeometricTimingDet const *> ConstGeometricTimingDetContainer; + typedef std::vector< GeometricTimingDet *> GeometricTimingDetContainer; + +#ifdef PoolAlloc + typedef std::vector< DDExpandedNode, PoolAlloc > GeoHistory; + typedef std::vector > nav_type; +#else + typedef std::vector GeoHistory; + typedef DDExpandedView::nav_type nav_type; +#endif + typedef Surface::PositionType Position; + typedef Surface::RotationType Rotation; + + // + // more can be added; please add at the end! + // + typedef enum GTDEnumType {unknown=100, MTD=0, BTL=1, BTLLayer=2, BTLTray=3, + BTLModule=4, BTLSensor=5, BTLCrystal=6, + ETL=7, ETLDisc=8, ETLRing=9, ETLModule=10, + ETLSensor=11 } GeometricTimingEnumType; + + /** + * Constructors to be used when looping over DDD + */ +#ifdef GEOMETRICDETDEBUG + GeometricTimingDet(DDnav_type const & navtype, GeometricTimingEnumType dd); + GeometricTimingDet(DDExpandedView* ev, GeometricTimingEnumType dd); +#endif + GeometricTimingDet(DDFilteredView* fv, GeometricTimingEnumType dd); + GeometricTimingDet(const PGeometricTimingDet::Item& onePGD, GeometricTimingEnumType dd); + + + /** + * set or add or clear components + */ + void setGeographicalID(DetId id) { + geographicalID_ = id; + //std::cout <<"setGeographicalID " << int(id) << std::endl; + } +#ifdef GEOMETRICDETDEBUG + void setComponents(GeometricTimingDetContainer const & cont) { + container_ = cont; + //std::cout <<"setComponents" << std::endl; + } +#endif + void addComponents(GeometricTimingDetContainer const & cont); + void addComponents(ConstGeometricTimingDetContainer const & cont); + void addComponent(GeometricTimingDet*); + /** + * clearComponents() only empties the container, the components are not deleted! + */ + void clearComponents() { + container_.clear(); + } + + /** + * deleteComponents() explicitly deletes the daughters + * + */ + void deleteComponents(); + + bool isLeaf() const { + return container_.empty(); + } + + GeometricTimingDet* component(size_t index) { + return const_cast(container_[index]); + } + + /** + * Access methods + */ + DDRotationMatrix const & rotation() const { + return rot_; + } + DDTranslation const & translation() const { + return trans_; + } + double phi() const { + return phi_; + } + double rho() const { + return rho_; + } + + DDSolidShape const & shape() const { + return shape_; + } + GeometricTimingEnumType type() const { + return type_; + } + DDName const & name() const { + return ddname_; + } + // internal representaion + nav_type const & navType() const { + return ddd_; + } + // representation neutral interface + NavRange navRange() const { + return NavRange(&ddd_.front(),ddd_.size()); + } + // more meaningfull name (maybe) + NavRange navpos() const { + return NavRange(&ddd_.front(),ddd_.size()); + } + std::vector const & params() const { + //std::cout<<"params"< bounds() const; +#ifdef GEOMETRICDETDEBUG + int copyno() const { + return copy_; + } + double volume() const { + return volume_; + } + double density() const { + return density_; + } + double weight() const { + return weight_; + } + std::string const & material() const { + return material_; + } +#endif + double radLength() const { + return radLength_; + } + double xi() const { + return xi_; + } + /** + * The following four pix* methods only return meaningful results for pixels. + */ + double pixROCRows() const { + return pixROCRows_; + } + double pixROCCols() const { + return pixROCCols_; + } + double pixROCx() const { + return pixROCx_; + } + double pixROCy() const { + return pixROCy_; + } + + /** + * The following two are only meaningful for the silicon tracker. + */ + bool stereo() const { + return stereo_; + } + double siliconAPVNum() const { + return siliconAPVNum_; + } + + /** + * what it says... used the DD in memory model to build the geometry... or not. + */ +#ifdef GEOMETRICDETDEBUG + bool wasBuiltFromDD() const { + return fromDD_; + } +#endif + + private: + + ConstGeometricTimingDetContainer container_; + DDTranslation trans_; + double phi_; + double rho_; + DDRotationMatrix rot_; + DDSolidShape shape_; + nav_type ddd_; + DDName ddname_; + GeometricTimingEnumType type_; + std::vector params_; + + DetId geographicalID_; +#ifdef GEOMETRICDETDEBUG + GeoHistory parents_; + double volume_; + double density_; + double weight_; + int copy_; + std::string _material; +#endif + double radLength_; + double xi_; + double pixROCRows_; + double pixROCCols_; + double pixROCx_; + double pixROCy_; + bool stereo_; + double siliconAPVNum_; +#ifdef GEOMETRICDETDEBUG + bool fromDD_; +#endif + +}; + +#undef PoolAlloc +#endif + diff --git a/Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h b/Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h new file mode 100644 index 0000000000000..72032b8a299d8 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h @@ -0,0 +1,95 @@ +#ifndef Geometry_MTDNumberingBuilder_GeometricTimingDetExtra_H +#define Geometry_MTDNumberingBuilder_GeometricTimingDetExtra_H + +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "DetectorDescription/Core/interface/DDExpandedView.h" +#include "DataFormats/DetId/interface/DetId.h" + +#include +#include "FWCore/ParameterSet/interface/types.h" + +#include + +class GeometricTimingDetExtra { + public: + typedef DDExpandedView::NavRange NavRange; +#ifdef PoolAlloc + typedef std::vector< DDExpandedNode, PoolAlloc > GeoHistory; +#endif +#ifndef PoolAlloc + typedef std::vector GeoHistory; +#endif + /** + * Constructors to be used when looping over DDD + */ + GeometricTimingDetExtra( GeometricTimingDet const *gd ) : _mygd(gd) { }; // this better be "copied into" or it will never have any valid numbers/info. + + GeometricTimingDetExtra( GeometricTimingDet const *gd, DetId id, GeoHistory& gh, double vol, double dens, double wgt, double cpy, const std::string& mat, const std::string& name, bool dd=false ); + + /** + * + */ + ~GeometricTimingDetExtra(); + + /** + * get and set associated GeometricTimingDet + * DOES NO CHECKING! + */ + GeometricTimingDet const * geometricDet() const { return _mygd; } + + /** + * set or add or clear components + */ + void setGeographicalId(DetId id) { + _geographicalId = id; + } + DetId geographicalId() const { return _geographicalId; } + + GeoHistory const & parents() const { + + return _parents; + } + //rr + int copyno() const { + return _copy; + } + double volume() const { + return _volume; + } + double density() const { + return _density; + } + double weight() const { + return _weight; + } + std::string const & material() const { + return _material; + } + + /** + * what it says... used the DD in memory model to build the geometry... or not. + */ + bool wasBuiltFromDD() const { + return _fromDD; + } + + std::string const& name() const { return _name; } + + private: + + /** Data members **/ + + GeometricTimingDet const* _mygd; + DetId _geographicalId; + GeoHistory _parents; + double _volume; + double _density; + double _weight; + int _copy; + std::string _material; + std::string _name; + bool _fromDD; // may not need this, keep an eye on it. +}; + +#undef PoolAlloc +#endif diff --git a/Geometry/MTDNumberingBuilder/interface/MTDMapDDDtoID.h b/Geometry/MTDNumberingBuilder/interface/MTDMapDDDtoID.h new file mode 100644 index 0000000000000..0e63d31f49ce1 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/interface/MTDMapDDDtoID.h @@ -0,0 +1,42 @@ +#ifndef MTDMapDDDtoID_H +#define MTDMapDDDtoID_H + +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" + +#include +#include +#include + + +class DDExpandedView; +class DDFilteredView; + +class MTDMapDDDtoID { + public: + + typedef GeometricTimingDet::nav_type nav_type; + typedef std::map MapType; + typedef std::map RevMapType; + + MTDMapDDDtoID(const GeometricTimingDet* iDet); + ~MTDMapDDDtoID(){clear();} + + //! calculate the id of a given node + unsigned int id(const nav_type &) const; + + nav_type const & navType(uint32_t) const; + + std::vector const & allNavTypes() const; + void clear(); + private: + void buildAll(const GeometricTimingDet*); + void buildAllStep2(const GeometricTimingDet*); + + std::vector navVec; + MapType path2id_; + RevMapType revpath2id_; +}; + +//typedef Singleton TkMapDDDtoID; + +#endif diff --git a/Geometry/MTDNumberingBuilder/interface/MTDTopology.h b/Geometry/MTDNumberingBuilder/interface/MTDTopology.h new file mode 100644 index 0000000000000..286846db0019a --- /dev/null +++ b/Geometry/MTDNumberingBuilder/interface/MTDTopology.h @@ -0,0 +1,187 @@ +#ifndef MTDTOPOLOGY_H +#define MTDTOPOLOGY_H + +#include "DataFormats/DetId/interface/DetId.h" +#include "DataFormats/ForwardDetId/interface/ForwardSubdetector.h" +#include "DataFormats/ForwardDetId/interface/MTDDetId.h" + +#include +#include + +//knower of all things tracker geometry +//flexible replacement for PXBDetId and friends +//to implement +// endcap pixel + + +class MTDTopology { + + public: + + struct BTLValues { + unsigned int sideStartBit_; + unsigned int layerStartBit_; + unsigned int trayStartBit_; + unsigned int moduleStartBit_; + unsigned int sideMask_; + unsigned int layerMask_; + unsigned int trayMask_; + unsigned int moduleMask_; + }; + + struct ETLValues { + unsigned int sideStartBit_; + unsigned int layerStartBit_; + unsigned int ringStartBit_; + unsigned int moduleStartBit_; + unsigned int sideMask_; + unsigned int layerMask_; + unsigned int ringMask_; + unsigned int moduleMask_; + }; + + enum DetIdFields { + BTLModule, BTLTray, BTLLayer, BTLSide, + ETLModule, ETLRing, ETLLayer, ETLSide, + /* TODO: this can be extended for all subdetectors */ + DETID_FIELDS_MAX + }; + + class SameLayerComparator { + public: + explicit SameLayerComparator(const MTDTopology *topo): topo_(topo) {} + + bool operator()(DetId i1, DetId i2) const { + if(i1.det() == i2.det() && + i1.subdetId() == i2.subdetId() && + topo_->side(i1) == topo_->side(i2) && + topo_->layer(i1) == topo_->layer(i2)) { + return false; + } + return i1 < i2; + } + + bool operator()(uint32_t i1, uint32_t i2) const { + return operator()(DetId(i1), DetId(i2)); + } + private: + const MTDTopology *topo_; + }; + + + MTDTopology( const BTLValues& btl, const ETLValues& etl); + + unsigned int side(const DetId &id) const; + unsigned int layer(const DetId &id) const; + unsigned int module(const DetId &id) const; + unsigned int tray(const DetId& id) const; + unsigned int ring(const DetId& id) const; + + //module + unsigned int btlModule(const DetId &id) const { + return ((id.rawId()>>btlVals_.moduleStartBit_)& btlVals_.moduleMask_); + } + unsigned int etlModule(const DetId &id) const { + return int((id.rawId()>>btlVals_.moduleStartBit_) & btlVals_.moduleMask_); + } + + //tray + unsigned int btlTray(const DetId &id) const { + return ((id.rawId()>>btlVals_.trayStartBit_) & btlVals_.trayMask_) ; + } + + // ring id + unsigned int etlRing(const DetId &id) const { + return ((id.rawId()>>etlVals_.ringStartBit_) & etlVals_.ringMask_) ; + } + + // layer numbers + unsigned int btlLayer(const DetId &id) const { + return int((id.rawId()>>btlVals_.layerStartBit_) & btlVals_.layerMask_); + } + unsigned int etlLayer(const DetId &id) const { + return int((id.rawId()>>etlVals_.layerStartBit_) & etlVals_.layerMask_); + } + + //side + unsigned int btlSide(const DetId &id) const { + return ((id.rawId()>>btlVals_.sideStartBit_)&btlVals_.sideMask_); + } + + unsigned int etlSide(const DetId &id) const { + return ((id.rawId()>>etlVals_.sideStartBit_)&etlVals_.sideMask_); + } + + // which disc is this ring on the forward or backward one? + unsigned int etlDisc(const DetId &id) const { + return int((id.rawId()>>etlVals_.ringStartBit_) & etlVals_.ringMask_)%2; + } + + //old constructors, now return DetId + DetId btlDetId(uint32_t side, + uint32_t layer, + uint32_t tray, + uint32_t module) const { + //uply + DetId id(DetId::Forward,ForwardSubdetector::FastTime); + uint32_t rawid=id.rawId(); + rawid |= MTDDetId::BTL << MTDDetId::kMTDsubdOffset | + (side& btlVals_.sideMask_) << btlVals_.sideStartBit_ | + (layer& btlVals_.layerMask_) << btlVals_.layerStartBit_ | + (tray& btlVals_.trayMask_) << btlVals_.trayStartBit_ | + (module& btlVals_.moduleMask_) << btlVals_.moduleStartBit_; + return DetId(rawid); + } + + DetId etlDetId(uint32_t side, + uint32_t layer, + uint32_t ring, + uint32_t module) const { + DetId id(DetId::Forward,ForwardSubdetector::FastTime); + uint32_t rawid=id.rawId(); + rawid |= MTDDetId::ETL << MTDDetId::kMTDsubdOffset | + (side& etlVals_.sideMask_) << etlVals_.sideStartBit_ | + (layer& etlVals_.layerMask_) << etlVals_.layerStartBit_ | + (ring& etlVals_.ringMask_) << etlVals_.ringStartBit_ | + (module& etlVals_.moduleMask_) << etlVals_.moduleStartBit_; + return DetId(rawid); + } + + std::pair btlDetIdLayerComparator(uint32_t side, uint32_t layer) const { + return std::make_pair(btlDetId(side, layer, 1,1), SameLayerComparator(this)); + } + + std::pair etlDetIdDiskComparator(uint32_t side, uint32_t layer) const { + return std::make_pair(etlDetId(side, layer, 1,1), SameLayerComparator(this)); + } + + std::string print(DetId detid) const; + + int getMTDLayerNumber(const DetId &id)const; + + // Extract the raw bit value for a given field type. + // E.g. getField(id, PBLadder) == pxbLadder(id) + unsigned int getField(const DetId &id, DetIdFields idx) const { + return ((id.rawId()>>bits_per_field[idx].startBit)&bits_per_field[idx].mask); + } + // checks whether a given field can be extracted from a given DetId. + // This boils down to checking whether it is the correct subdetector. + bool hasField(const DetId &id, DetIdFields idx) const { + return id.subdetId() == bits_per_field[idx].subdet; + } + + private: + + const BTLValues btlVals_; + const ETLValues etlVals_; + + struct BitmaskAndSubdet { + unsigned int startBit; + unsigned int mask; + int subdet; + }; + const BitmaskAndSubdet bits_per_field[DETID_FIELDS_MAX]; +}; + +#endif + diff --git a/Geometry/MTDNumberingBuilder/plugins/BuildFile.xml b/Geometry/MTDNumberingBuilder/plugins/BuildFile.xml new file mode 100644 index 0000000000000..9602ec3833a3c --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/BuildFile.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDAbstractConstruction.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDAbstractConstruction.h new file mode 100644 index 0000000000000..d1db108d3ed9b --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDAbstractConstruction.h @@ -0,0 +1,18 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDAbstractConstruction_H +#define Geometry_MTDNumberingBuilder_CmsMTDAbstractConstruction_H + +#include + +class GeometricTimingDet; +class DDFilteredView; + +/** + * Abstract Class to construct a Tracker SubDet + */ +class CmsMTDAbstractConstruction{ + public: + virtual ~CmsMTDAbstractConstruction() = default; + virtual void build(DDFilteredView& , GeometricTimingDet*, std::string) = 0; + +}; +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.cc new file mode 100644 index 0000000000000..c34deb45b4069 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.cc @@ -0,0 +1,65 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h" + +#include + +CmsMTDBuilder::CmsMTDBuilder() +{} + +void +CmsMTDBuilder::buildComponent( DDFilteredView& fv, GeometricTimingDet* g, std::string s ) +{ + CmsMTDSubStrctBuilder theCmsMTDSubStrctBuilder; + CmsMTDEndcapBuilder theCmsMTDEndcapBuilder; + + GeometricTimingDet* subdet = new GeometricTimingDet( &fv, theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() ) ); + + switch( theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() ) ) + { + case GeometricTimingDet::ETL: + theCmsMTDEndcapBuilder.build( fv, subdet, s ); + break; + case GeometricTimingDet::BTL: + theCmsMTDSubStrctBuilder.build( fv, subdet, s ); + break; + default: + throw cms::Exception("CmsMTDBuilder") << " ERROR - I was expecting a SubDet, I got a " << fv.logicalPart().name().fullname(); + } + + g->addComponent( subdet ); +} + +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" +void +CmsMTDBuilder::sortNS( DDFilteredView& fv, GeometricTimingDet* det ) +{ + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + std::stable_sort( comp.begin(), comp.end(), subDetByType()); + + for( uint32_t i = 0; i < comp.size(); i++ ) + { + const uint32_t side = det->component(i)->translation().z() > 0 ? 1 : 0; + switch( comp[i]->type() ) { + case GeometricTimingDet::BTL: + det->component(i)->setGeographicalID(BTLDetId(0,0,0,0,0)); + break; + case GeometricTimingDet::ETL: + det->component(i)->setGeographicalID(ETLDetId(side,0,0,0)); + break; + default: + throw cms::Exception("CmsMTDBuilder") << " ERROR - I was expecting a SubDet, I got a " << comp[i]->name(); + } + } +} + + + + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h new file mode 100644 index 0000000000000..f63ef0b78ef42 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h @@ -0,0 +1,22 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDBuilder_H + +# include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +# include "FWCore/ParameterSet/interface/types.h" +# include + +/** + * Abstract Class to construct a Level in the hierarchy + */ +class CmsMTDBuilder : public CmsMTDLevelBuilder +{ +public: + CmsMTDBuilder(); + +private: + + void sortNS( DDFilteredView& , GeometricTimingDet* ) override; + void buildComponent( DDFilteredView& , GeometricTimingDet*, std::string ) override; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.cc new file mode 100644 index 0000000000000..6f3ee6638a440 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.cc @@ -0,0 +1,90 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DataFormats/DetId/interface/DetId.h" + +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" + +void CmsMTDConstruction::buildComponent(DDFilteredView& fv, + GeometricTimingDet *mother, + std::string attribute){ + + // + // at this level I check whether it is a merged detector or not + // + + GeometricTimingDet * det = new GeometricTimingDet(&fv,theCmsMTDStringToEnum.type(fv.logicalPart().name().fullname())); + + const std::string part_name = fv.logicalPart().name().fullname().substr(0,11); + + if ( theCmsMTDStringToEnum.type(part_name) == GeometricTimingDet::BTLModule ) { + bool dodets = fv.firstChild(); + while (dodets) { + buildBTLModule(fv,det,attribute); + dodets = fv.nextSibling(); + } + fv.parent(); + } else if ( theCmsMTDStringToEnum.type(part_name) == GeometricTimingDet::ETLModule ) { + bool dodets = fv.firstChild(); + while (dodets) { + buildETLModule(fv,det,attribute); + dodets = fv.nextSibling(); + } + fv.parent(); + } else { + throw cms::Exception("MTDConstruction") << "woops got: " << part_name << std::endl; + } + + mother->addComponent(det); +} + +void CmsMTDConstruction::buildBTLModule(DDFilteredView& fv, + GeometricTimingDet *mother, + const std::string& attribute){ + + GeometricTimingDet * det = new GeometricTimingDet(&fv, theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() )); + + const auto& copyNumbers = fv.copyNumbers(); + auto module_number = copyNumbers[copyNumbers.size()-2]; + + constexpr char positive[] = "PositiveZ"; + constexpr char negative[] = "NegativeZ"; + + const std::string modname = fv.logicalPart().name().fullname(); + size_t delim1 = modname.find("BModule"); + size_t delim2 = modname.find("Layer"); + module_number += atoi(modname.substr(delim1+7,delim2).c_str())-1; + + if( modname.find(positive) != std::string::npos ) { + det->setGeographicalID(BTLDetId(1,copyNumbers[copyNumbers.size()-3],module_number,0,1)); + } else if ( modname.find(negative) != std::string::npos ) { + det->setGeographicalID(BTLDetId(0,copyNumbers[copyNumbers.size()-3],module_number,0,1)); + } else { + throw cms::Exception("CmsMTDConstruction::buildBTLModule") + << "BTL Module " << module_number << " is neither positive nor negative in Z!"; + } + + mother->addComponent(det); +} + +void CmsMTDConstruction::buildETLModule(DDFilteredView& fv, + GeometricTimingDet *mother, + const std::string& attribute){ + + GeometricTimingDet * det = new GeometricTimingDet(&fv, theCmsMTDStringToEnum.type(ExtractStringFromDDD::getString(attribute,&fv))); + + const auto& copyNumbers = fv.copyNumbers(); + auto module_number = copyNumbers[copyNumbers.size()-2]; + + size_t delim_ring = det->name().fullname().find("EModule"); + size_t delim_disc = det->name().fullname().find("Disc"); + + std::string ringN = det->name().fullname().substr(delim_ring+7,delim_disc); + + const uint32_t side = det->translation().z() > 0 ? 1 : 0; + + // label geographic detid is front or back (even though it is one module per entry here) + det->setGeographicalID(ETLDetId(side,atoi(ringN.c_str()),module_number,0)); + + mother->addComponent(det); +} diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h new file mode 100644 index 0000000000000..d540158e0793e --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h @@ -0,0 +1,18 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDConstruction_H +#define Geometry_MTDNumberingBuilder_CmsMTDConstruction_H +#include +#include +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +/** + * Adds GeometricTimingDets representing final modules to the previous level + */ +class CmsMTDConstruction : public CmsMTDLevelBuilder { + public: + void buildComponent(DDFilteredView& , GeometricTimingDet*, std::string) override; + private: + + void buildBTLModule(DDFilteredView& , GeometricTimingDet* , const std::string&); + void buildETLModule(DDFilteredView& , GeometricTimingDet* , const std::string&); +}; + +#endif // Geometry_MTDNumberingBuilder_CmsMTDConstruction_H diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.cc new file mode 100644 index 0000000000000..e38107edd815e --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.cc @@ -0,0 +1,113 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include +#include +#include +#include +#include + +CmsMTDDetIdBuilder::CmsMTDDetIdBuilder( std::vector detidShifts ) + : m_detidshifts() +{ + if(detidShifts.size()!=nSubDet*maxLevels) + edm::LogError("WrongConfiguration") << "Wrong configuration of TrackerGeometricTimingDetESModule. Vector of " + << detidShifts.size() << " elements provided"; + else { + for(unsigned int i=0;isetGeographicalID( t ); + iterate( mtd, 0, mtd->geographicalID().rawId() ); + + return mtd; +} + +void +CmsMTDDetIdBuilder::iterate( GeometricTimingDet *in, int level, unsigned int ID ) +{ + std::bitset<32> binary_ID(ID); + + // SubDetector (useful to know fron now on, valid only after level 0, where SubDetector is assigned) + uint32_t mask = (7<<25); + uint32_t iSubDet = ID & mask; + iSubDet = iSubDet >> 25; + // + + LogTrace("BuildingTrackerDetId") << std::string(2*level,'-') + << "+" << ID << " " << iSubDet << " " << level; + + switch( level ) + { + // level 0: special case because it is used to assign the proper detid bits based on the endcap-like subdetector position: +z or -z + case 0: + { + for( uint32_t i = 0; i<(in)->components().size(); i++ ) + { + GeometricTimingDet* component = in->component(i); + uint32_t iSubDet = component->geographicalID().rawId(); + uint32_t temp = ID; + temp |= (iSubDet<<25); + component->setGeographicalID(temp); + + if(iSubDet>0 && iSubDet<=nSubDet && m_detidshifts[level*nSubDet+iSubDet-1]>=0) { + if(m_detidshifts[level*nSubDet+iSubDet-1]+2<25) temp|= (0<<(m_detidshifts[level*nSubDet+iSubDet-1]+2)); + bool negside = component->translation().z()<0.; + if(std::abs(component->translation().z())<1.) negside = component->components().front()->translation().z()<0.; // needed for subdet like TID which are NOT translated + LogTrace("BuildingTrackerDetId") << "Is negative endcap? " << negside + << ", because z translation is " << component->translation().z() + << " and component z translation is " << component->components().front()->translation().z(); + if(negside) + { + temp |= (1<setGeographicalID(DetId(temp)); + + // next level + iterate(component,level+1,((in)->components())[i]->geographicalID().rawId()); + } + break; + } + // level 1 to 5 + default: + { + for( uint32_t i = 0; i < (in)->components().size(); i++ ) + { + auto component = in->component(i); + uint32_t temp = ID; + + if(level0 && iSubDet <=nSubDet && m_detidshifts[level*nSubDet+iSubDet-1]>=0) { + temp |= (component->geographicalID().rawId()<setGeographicalID( temp ); + // next level + iterate(component,level+1,((in)->components())[i]->geographicalID().rawId()); + } + } + + break; + } + // level switch ends + } + + return; + +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h new file mode 100644 index 0000000000000..6c54a808e0d29 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h @@ -0,0 +1,33 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDDetIdBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDDetIdBuilder_H + +# include "FWCore/ParameterSet/interface/types.h" +# include +#include +#include + +class GeometricTimingDet; + +/** + * Class to build a geographicalId. + */ + +class CmsMTDDetIdBuilder +{ +public: + CmsMTDDetIdBuilder(std::vector detidShifts ); + GeometricTimingDet* buildId( GeometricTimingDet *det ); +protected: + void iterate( GeometricTimingDet *det, int level, unsigned int ID ); + +private: + + static const unsigned int nSubDet=6; + static const int maxLevels=6; + + // This is the map between detid and navtype to restore backward compatibility between 12* and 13* series + std::map< std::string , uint32_t > m_mapNavTypeToDetId; + std::array m_detidshifts; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.cc new file mode 100644 index 0000000000000..bf2ae64897dc2 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.cc @@ -0,0 +1,59 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h" +#include "Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include +#include + +using namespace std; + +void +CmsMTDDiscBuilder::buildComponent( DDFilteredView& fv, GeometricTimingDet* g, std::string s ) +{ + CmsMTDETLRingBuilder theCmsMTDETLRingBuilder; + const std::string ringname = fv.logicalPart().name().fullname().substr(0,8); + GeometricTimingDet * subdet = new GeometricTimingDet( &fv, theCmsMTDStringToEnum.type( ringname )); + + switch( theCmsMTDStringToEnum.type( ringname )) + { + case GeometricTimingDet::ETLRing: + theCmsMTDETLRingBuilder.build( fv, subdet, s ); + break; + default: + throw cms::Exception( "CmsMTDDiscBuilder" ) << " ERROR - I was expecting a Ring, I got a " << ringname; + } + + g->addComponent( subdet ); +} + +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" +void +CmsMTDDiscBuilder::sortNS( DDFilteredView& fv, GeometricTimingDet* det ) +{ + + + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + + switch(det->components().front()->type()){ + case GeometricTimingDet::ETLRing: + std::stable_sort(comp.begin(),comp.end(),LessR_module()); + break; + default: + edm::LogError("CmsMTDDiscBuilder")<<"ERROR - wrong SubDet to sort..... "<components().front()->type(); + } + + GeometricTimingDet::GeometricTimingDetContainer rings; + uint32_t totalrings = comp.size(); + + const uint32_t side = det->translation().z() > 0 ? 1 : 0; + + for ( uint32_t rn=0; rncomponent(rn)->setGeographicalID(ETLDetId(side,rn+1,0,0)); + } + +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h new file mode 100644 index 0000000000000..1d5dc6668ab1d --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h @@ -0,0 +1,20 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDDiscBuilder_H +# define Geometry_MTDNumberingBuilder_CmsMTDDiscBuilder_H + +# include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +# include "FWCore/ParameterSet/interface/types.h" +# include + +/** + * Class which contructs Phase2 Outer Tracker/Discs. + */ +class CmsMTDDiscBuilder : public CmsMTDLevelBuilder +{ + +private: + void sortNS( DDFilteredView& , GeometricTimingDet* ) override; + void buildComponent( DDFilteredView& , GeometricTimingDet*, std::string ) override; + +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.cc new file mode 100644 index 0000000000000..0476207154528 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.cc @@ -0,0 +1,28 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "DataFormats/DetId/interface/DetId.h" +#include + +#include "Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h" + +void CmsMTDETLRingBuilder::buildComponent(DDFilteredView& fv, GeometricTimingDet* g, std::string s){ + + CmsMTDConstruction theCmsMTDConstruction; + theCmsMTDConstruction.buildComponent(fv,g,s); + +} + +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" + +void CmsMTDETLRingBuilder::sortNS(DDFilteredView& fv, GeometricTimingDet* det){ + + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + + //increasing phi taking into account the sub-modules + MTDStablePhiSort(comp.begin(), comp.end(), ExtractPhiGluedModule()); + +} diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h new file mode 100644 index 0000000000000..ec287e411dee9 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDETLRingBuilder.h @@ -0,0 +1,18 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDETLRingBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDETLRingBuilder_H + +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +#include "FWCore/ParameterSet/interface/types.h" +#include +/** + * Class which contructs MTD ETL Rings. + */ +class CmsMTDETLRingBuilder : public CmsMTDLevelBuilder { + + private: + void sortNS(DDFilteredView& , GeometricTimingDet*) override; + void buildComponent(DDFilteredView& , GeometricTimingDet*, std::string) override; + +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.cc new file mode 100644 index 0000000000000..4d510954094af --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.cc @@ -0,0 +1,49 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDDiscBuilder.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + +#include + +CmsMTDEndcapBuilder::CmsMTDEndcapBuilder() +{} + +void +CmsMTDEndcapBuilder::buildComponent( DDFilteredView& fv, GeometricTimingDet* g, std::string s ) +{ + CmsMTDDiscBuilder theCmsMTDDiscBuilder; + + GeometricTimingDet * subdet = new GeometricTimingDet( &fv, theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() )); + std::string subdet_name = subdet->name().fullname(); + switch( theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() )) + { + case GeometricTimingDet::ETLDisc: + theCmsMTDDiscBuilder.build(fv,subdet,s); + break; + default: + throw cms::Exception("CmsMTDEndcapBuilder")<<" ERROR - I was expecting a Disk... I got a "<< fv.logicalPart().name().fullname(); + } + + g->addComponent(subdet); +} + + +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" +void +CmsMTDEndcapBuilder::sortNS( DDFilteredView& fv, GeometricTimingDet* det ) +{ + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + + std::stable_sort( comp.begin(), comp.end(), LessModZ()); + + for( uint32_t i = 0; i < comp.size(); i++ ) + { + const uint32_t side = det->component(i)->translation().z() > 0 ? 1 : 0; + det->component(i)->setGeographicalID(ETLDetId(side,0,0,0)); + } +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h new file mode 100644 index 0000000000000..6cfb5e7511014 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDEndcapBuilder.h @@ -0,0 +1,21 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDPixelPhase2EndcapBuilder_H +# define Geometry_MTDNumberingBuilder_CmsMTDPixelPhase2EndcapBuilder_H + +# include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +# include "FWCore/ParameterSet/interface/types.h" +# include + +/** + * Class which builds the ETL + */ +class CmsMTDEndcapBuilder : public CmsMTDLevelBuilder +{ +public: + CmsMTDEndcapBuilder(); + +private: + void sortNS( DDFilteredView& , GeometricTimingDet* ) override; + void buildComponent( DDFilteredView& , GeometricTimingDet*, std::string ) override; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.cc new file mode 100644 index 0000000000000..e867e93ba7dfb --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.cc @@ -0,0 +1,31 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + + +void CmsMTDLevelBuilder::build ( + DDFilteredView& fv, + GeometricTimingDet* tracker, + std::string attribute){ + + LogTrace("GeometricTimingDetBuilding") << std::string(3*fv.history().size(),'-') + << "+ " + << ExtractStringFromDDD::getString(attribute,&fv) << " " + << tracker->type() << " " + << tracker->name() + << std::endl; + + bool doLayers = fv.firstChild(); // descend to the next Layer + + while (doLayers) { + buildComponent(fv,tracker,attribute); + doLayers = fv.nextSibling(); // go to the next adjacent thingy + } + + fv.parent(); + + sortNS(fv,tracker); + +} diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h new file mode 100644 index 0000000000000..8440983e43b80 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h @@ -0,0 +1,207 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDLevelBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDLevelBuilder_H + +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDAbstractConstruction.h" +#include "Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "FWCore/ParameterSet/interface/types.h" +#include +/** + * Abstract Class to construct a Level in the hierarchy + */ + +typedef std::unary_function uFcn; + +class CmsMTDLevelBuilder : public CmsMTDAbstractConstruction { +public: + void build(DDFilteredView& , GeometricTimingDet*, std::string) override; + ~CmsMTDLevelBuilder() override{} + + + struct subDetByType{ + bool operator()(const GeometricTimingDet* a, const GeometricTimingDet* b) const { + return a->type() < b->type(); // it relies on the fact that the GeometricTimingDet::GDEnumType enumerators used to identify the subdetectors in the upgrade geometries are equal to the ones of the present detector + n*100 + } + }; + + // NP** Phase2 BarrelEndcap + struct PhiSortNP{ + bool operator()(const GeometricTimingDet* a,const GeometricTimingDet* b) const { + if ( fabs(a->translation().rho() - b->translation().rho()) < 0.01 && + (fabs(a->translation().phi() - b->translation().phi()) < 0.01 || + fabs(a->translation().phi() - b->translation().phi()) > 6.27 ) && + a->translation().z() * b->translation().z() > 0.0 ) { + return ( fabs(a->translation().z()) < fabs(b->translation().z()) ); + } + else + return false; + } + }; + + + struct LessZ{ + bool operator()(const GeometricTimingDet* a, const GeometricTimingDet* b) const + { + // NP** change for Phase 2 Tracker + if (a->translation().z() == b->translation().z()) + {return a->translation().rho() < b->translation().rho();} + else{ + // Original version + return a->translation().z() < b->translation().z();} + } + }; + + struct LessModZ{ + bool operator()(const GeometricTimingDet* a, const GeometricTimingDet* b) const + { + return fabs(a->translation().z()) < fabs(b->translation().z()); + } + }; + + + struct ExtractPhi:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + double phi = a->phi(); + return( phi>= 0 ? phi:phi+2*pi); + } + }; + + struct ExtractPhiModule:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + std::vector const & comp = a->components().back()->components(); + float phi = 0.; + bool sum = true; + + for(auto i : comp){ + if(fabs(i->phi())>pi/2.) { + sum = false; + break; + } + } + + if(sum){ + for(auto i : comp){ + phi+= i->phi(); + } + + double temp = phi/float(comp.size()) < 0. ? + 2*pi + phi/float(comp.size()): + phi/float(comp.size()); + return temp; + + }else{ + for(auto i : comp){ + double phi1 = i->phi() >= 0 ? i->phi(): + i->phi()+2*pi; + phi+= phi1; + } + + double com = comp.front()->phi() >= 0 ? comp.front()->phi(): + 2*pi + comp.front()->phi(); + double temp = fabs(phi/float(comp.size()) - com) > 2. ? + pi - phi/float(comp.size()): + phi/float(comp.size()); + temp = temp >= 0? temp:2*pi+temp; + return temp; + } + } + }; + + struct ExtractPhiGluedModule:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + std::vector comp; + a->deepComponents(comp); + float phi = 0.; + bool sum = true; + + for(auto & i : comp){ + if(fabs(i->phi())>pi/2.) { + sum = false; + break; + } + } + + if(sum){ + for(auto & i : comp){ + phi+= i->phi(); + } + + double temp = phi/float(comp.size()) < 0. ? + 2*pi + phi/float(comp.size()): + phi/float(comp.size()); + return temp; + + }else{ + for(auto & i : comp){ + double phi1 = i->phi() >= 0 ? i->phi(): + i->translation().phi()+2*pi; + phi+= phi1; + } + + double com = comp.front()->phi() >= 0 ? comp.front()->phi(): + 2*pi + comp.front()->phi(); + double temp = fabs(phi/float(comp.size()) - com) > 2. ? + pi - phi/float(comp.size()): + phi/float(comp.size()); + temp = temp >= 0? temp:2*pi+temp; + return temp; + } + } + }; + + struct ExtractPhiMirror:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + double phi = a->phi(); + phi = (phi>= 0 ? phi : phi+2*pi); // (-pi,pi] --> [0,2pi) + return ( (pi-phi) >= 0 ? (pi-phi) : (pi-phi)+2*pi ); // (-pi,pi] --> [0,2pi) + } + }; + + struct ExtractPhiModuleMirror:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + double phi = ExtractPhiModule()(a); // [0,2pi) + phi = ( phi <= pi ? phi : phi-2*pi ); // (-pi,pi] + return (pi-phi); + } + }; + + struct ExtractPhiGluedModuleMirror:public uFcn{ + double operator()(const GeometricTimingDet* a)const{ + const double pi = 3.141592653592; + double phi = ExtractPhiGluedModule()(a); // [0,2pi) + phi = ( phi <= pi ? phi : phi-2*pi ); // (-pi,pi] + return (pi-phi); + } + }; + + struct LessR_module{ + bool operator()(const GeometricTimingDet* a, const GeometricTimingDet* b) const + { + return a->deepComponents().front()->rho() < + b->deepComponents().front()->rho(); + } + }; + + struct LessR{ + bool operator()(const GeometricTimingDet* a, const GeometricTimingDet* b) const + { + return a->rho() < b->rho(); + } + }; + + + private: + virtual void buildComponent(DDFilteredView& , GeometricTimingDet*, std::string) = 0; +protected: + CmsMTDStringToEnum theCmsMTDStringToEnum; +private: + virtual void sortNS(DDFilteredView& , GeometricTimingDet*){} + CmsMTDStringToEnum _CmsMTDStringToEnum; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.cc new file mode 100644 index 0000000000000..06416e7faf7a6 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.cc @@ -0,0 +1,31 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDConstruction.h" +#include + +void CmsMTDModuleBuilder::buildComponent(DDFilteredView& fv, GeometricTimingDet* g, std::string side){ + + CmsMTDConstruction theCmsMTDConstruction; + theCmsMTDConstruction.buildComponent(fv,g,side); +} + + +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +void CmsMTDModuleBuilder::sortNS(DDFilteredView& fv, GeometricTimingDet* det){ + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + + std::stable_sort(comp.begin(),comp.end(),LessZ()); + + if (comp.empty() ){ + edm::LogError("CmsMTDModuleBuilder") << "Where are the ETL modules?"; + } + +} + + + + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h new file mode 100644 index 0000000000000..f9717bdd17af1 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h @@ -0,0 +1,19 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDModuleBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDModuleBuilder_H + +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +#include "FWCore/ParameterSet/interface/types.h" +#include + +/** + * Class which builds Pixel Ladders + */ +class CmsMTDModuleBuilder : public CmsMTDLevelBuilder { + + private: + void sortNS(DDFilteredView& , GeometricTimingDet*) override; + void buildComponent(DDFilteredView& , GeometricTimingDet*, std::string) override; + +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.cc new file mode 100644 index 0000000000000..8f7533e45dbb3 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.cc @@ -0,0 +1,58 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + +#include + +namespace { + constexpr std::array sides{ { "PositiveZ","NegativeZ" } }; +} + +CmsMTDSubStrctBuilder::CmsMTDSubStrctBuilder() +{} + +void +CmsMTDSubStrctBuilder::buildComponent( DDFilteredView& fv, GeometricTimingDet* g, std::string side ) +{ + CmsMTDTrayBuilder theCmsMTDTrayBuilder; + + GeometricTimingDet * subdet = new GeometricTimingDet( &fv, theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() )); + + switch( theCmsMTDStringToEnum.type( fv.logicalPart().name().fullname() ) ) { + case GeometricTimingDet::BTLLayer: + theCmsMTDTrayBuilder.build(fv,subdet,side); + break; + + default: + throw cms::Exception("CmsMTDSubStrctBuilder")<<" ERROR - I was expecting a BTLLayer... I got a "<< fv.logicalPart().name().fullname(); + } + + g->addComponent(subdet); +} + +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +void +CmsMTDSubStrctBuilder::sortNS( DDFilteredView& fv, GeometricTimingDet* det ) +{ + GeometricTimingDet::ConstGeometricTimingDetContainer & comp = det->components(); + + switch( comp.front()->type()) + { + case GeometricTimingDet::BTLLayer: + std::stable_sort( comp.begin(), comp.end(), LessR()); + break; + default: + edm::LogError( "CmsMTDSubStrctBuilder" ) << "ERROR - wrong SubDet to sort..... " << det->components().front()->type(); + } + + for( uint32_t i = 0; i < comp.size(); i++ ) + { + det->component(i)->setGeographicalID(i+1); // Every subdetector: Layer/Disk/Wheel Number + } +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h new file mode 100644 index 0000000000000..73098f4025f26 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDSubStrctBuilder.h @@ -0,0 +1,21 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDSubStrctBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDSubStrctBuilder_H + +# include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +# include "FWCore/ParameterSet/interface/types.h" +# include + +/** + * Classes which abuilds all the tracker substructures + */ +class CmsMTDSubStrctBuilder : public CmsMTDLevelBuilder +{ +public: + CmsMTDSubStrctBuilder(); + +private: + void sortNS( DDFilteredView& , GeometricTimingDet* ) override; + void buildComponent( DDFilteredView& , GeometricTimingDet*, std::string ) override; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.cc b/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.cc new file mode 100644 index 0000000000000..0644c8fbc6319 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.cc @@ -0,0 +1,65 @@ +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDModuleBuilder.h" +#include "Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + +#include + +void CmsMTDTrayBuilder::buildComponent(DDFilteredView& fv, GeometricTimingDet* g, std::string side){ + + CmsMTDModuleBuilder theCmsMTDModuleBuilder; + + GeometricTimingDet * subdet = new GeometricTimingDet(&fv,theCmsMTDStringToEnum.type(fv.logicalPart().name().fullname())); + switch (theCmsMTDStringToEnum.type(fv.logicalPart().name().fullname())){ + case GeometricTimingDet::BTLTray: + theCmsMTDModuleBuilder.build(fv,subdet,side); + break; + default: + throw cms::Exception("CmsMTDTrayBuilder")<<" ERROR - I was expecting a Tray, I got a "<< fv.logicalPart().name().fullname(); + } + + g->addComponent(subdet); +} + +void CmsMTDTrayBuilder::sortNS(DDFilteredView& fv, GeometricTimingDet* det){ + + GeometricTimingDet::ConstGeometricTimingDetContainer comp = det->components(); + + //order ladder and rings together + GeometricTimingDet::GeometricTimingDetContainer rods; + rods.clear(); + + + for(uint32_t i=0; icomponent(i); + if(component->type()== GeometricTimingDet::BTLTray){ + rods.emplace_back(component); + } else { + edm::LogError("CmsMTDOTLayerBuilder")<<"ERROR - wrong SubDet to sort..... "<components().front()->type(); + } + } + + // rods + if(!rods.empty()){ + MTDStablePhiSort(rods.begin(), rods.end(), ExtractPhi()); + uint32_t totalrods = rods.size(); + + LogTrace("DetConstruction") << " Rods ordered by phi: "; + for ( uint32_t rod = 0; rod < totalrods; rod++) { + uint32_t temp = rod+1; + temp|=(3<<8); + rods[rod]->setGeographicalID(DetId(temp)); + LogTrace("BuildingMTDDetId") << "\t\t\t DetId >> " << temp << "(r: " << sqrt(rods[rod]->translation().Perp2()) << ", phi: " << rods[rod]->phi() << ", z: " << rods[rod]->translation().z() << ")"; + } + } + + det->clearComponents(); + det->addComponents(rods); + +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h b/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h new file mode 100644 index 0000000000000..ac2a6f2ccce50 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CmsMTDTrayBuilder.h @@ -0,0 +1,18 @@ +#ifndef Geometry_MTDNumberingBuilder_CmsMTDTrayBuilder_H +#define Geometry_MTDNumberingBuilder_CmsMTDTrayBuilder_H + +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDLevelBuilder.h" +#include "FWCore/ParameterSet/interface/types.h" +#include +/** + * Class which contructs BTL trays + */ +class CmsMTDTrayBuilder : public CmsMTDLevelBuilder { + + private: + void sortNS(DDFilteredView& , GeometricTimingDet*) override; + void buildComponent(DDFilteredView& , GeometricTimingDet*, std::string) override; + +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.cc b/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.cc new file mode 100644 index 0000000000000..aa0420559f7a8 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.cc @@ -0,0 +1,75 @@ +#include "CondDBCmsMTDConstruction.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h" + +using namespace cms; + +CondDBCmsMTDConstruction::CondDBCmsMTDConstruction() { } + +const GeometricTimingDet* CondDBCmsMTDConstruction::construct(const PGeometricTimingDet& pgd) { + GeometricTimingDet* mtd = new GeometricTimingDet(pgd.pgeomdets_[0],GeometricTimingDet::MTD); + + size_t detMax = pgd.pgeomdets_.size(); + size_t tri = 1; + std::vector hier; + int lev=1; + GeometricTimingDet* subdet = mtd; + hier.emplace_back(subdet); + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 1 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + hier.emplace_back(subdet); + ++lev; + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 2 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + hier.emplace_back(subdet); + ++lev; + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 3 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + hier.emplace_back(subdet); + ++lev; + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 4 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + hier.emplace_back(subdet); + ++lev; + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 5 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + hier.emplace_back(subdet); + ++lev; + while ( tri < detMax && pgd.pgeomdets_[tri].level_ == 6 ) { + subdet = new GeometricTimingDet(pgd.pgeomdets_[tri], GeometricTimingDet::GTDEnumType(pgd.pgeomdets_[tri].type_)); + ++tri; + hier.back()->addComponent(subdet); + } + --lev; + hier.pop_back(); + } + --lev; + hier.pop_back(); + } + --lev; + hier.pop_back(); + } + --lev; + hier.pop_back(); + } + --lev; + hier.pop_back(); + } + return mtd; +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.h b/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.h new file mode 100644 index 0000000000000..1a0c24182ab18 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.h @@ -0,0 +1,26 @@ +#ifndef Geometry_MTDNumberingBuilder_CondDBCmsMTDConstruction_H +#define Geometry_MTDNumberingBuilder_CondDBCmsMTDConstruction_H + +#include "Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h" +#include "FWCore/ParameterSet/interface/types.h" +#include + +class GeometricTimingDet; +class DDCompactView; +class PGeometricTimingDet; + +/** + * High level class to build a tracker. It will only build subdets, + * then call subdet builders + */ + +class CondDBCmsMTDConstruction { + public: + CondDBCmsMTDConstruction(); + const GeometricTimingDet* construct( const PGeometricTimingDet& pgd ); + + protected: + +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.cc b/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.cc new file mode 100644 index 0000000000000..e7af181a9627b --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.cc @@ -0,0 +1,75 @@ +#include "Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h" + +#include +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDBuilder.h" +#include "Geometry/MTDNumberingBuilder/plugins/CmsMTDDetIdBuilder.h" + +class DDNameFilter : public DDFilter { +public: + void add(const std::string& add) { allowed_.emplace_back(add); } + void veto(const std::string& veto) { veto_.emplace_back(veto); } + + bool accept(const DDExpandedView & ev) const final { + for( const auto& test : veto_ ) { + if( ev.logicalPart().name().fullname().find(test) != std::string::npos ) + return false; + } + for( const auto& test : allowed_ ) { + if( ev.logicalPart().name().fullname().find(test) != std::string::npos ) + return true; + } + return false; + } +private: + std::vector allowed_; + std::vector veto_; +}; + +using namespace cms; + +DDDCmsMTDConstruction::DDDCmsMTDConstruction( void ) +{} + +const GeometricTimingDet* +DDDCmsMTDConstruction::construct( const DDCompactView* cpv, std::vector detidShifts) +{ + attribute = std::string("CMSCutsRegion"); + DDNameFilter filter; + filter.add("mtd:"); + filter.add("btl:"); + filter.add("etl:"); + filter.veto("service"); + filter.veto("support"); + filter.veto("FSide"); + filter.veto("BSide"); + filter.veto("LSide"); + filter.veto("RSide"); + filter.veto("Between"); + filter.veto("SupportPlate"); + filter.veto("Shield"); + + DDFilteredView fv( *cpv, filter ); + auto check_root = theCmsMTDStringToEnum.type( ExtractStringFromDDD::getString(attribute,&fv)); + if( check_root != GeometricTimingDet::MTD ) + { + fv.firstChild(); + auto check_child = theCmsMTDStringToEnum.type( ExtractStringFromDDD::getString(attribute,&fv)); + if( check_child != GeometricTimingDet::MTD ) + { + throw cms::Exception( "Configuration" ) << " The first child of the DDFilteredView is not what is expected \n" + << ExtractStringFromDDD::getString( attribute, &fv ) << "\n"; + } + fv.parent(); + } + + GeometricTimingDet* mtd = new GeometricTimingDet( &fv, GeometricTimingDet::MTD ); + CmsMTDBuilder theCmsMTDBuilder; + theCmsMTDBuilder.build( fv, mtd, attribute ); + + return mtd; +} + diff --git a/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h b/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h new file mode 100644 index 0000000000000..fcc5309d4a85f --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h @@ -0,0 +1,29 @@ +#ifndef Geometry_MTDNumberingBuilder_DDDCmsMTDConstruction_H +#define Geometry_MTDNumberingBuilder_DDDCmsMTDConstruction_H + +#include "Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h" +#include "FWCore/ParameterSet/interface/types.h" +#include +#include + +class GeometricTimingDet; +class DDCompactView; + +/** + * High level class to build a tracker. It will only build subdets, + * then call subdet builders + */ + +class DDDCmsMTDConstruction +{ +public: + DDDCmsMTDConstruction( void ); + const GeometricTimingDet* construct( const DDCompactView* cpv, std::vector detidShifts); + +protected: + + std::string attribute; + CmsMTDStringToEnum theCmsMTDStringToEnum; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.cc b/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.cc new file mode 100644 index 0000000000000..19fcfb1ffcf5b --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.cc @@ -0,0 +1,27 @@ +#include "Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include +#include + +using namespace cms; + +std::string ExtractStringFromDDD::getString(std::string const & s,DDFilteredView* fv){ + DDValue val(s); + std::vector result; + fv->specificsV(result); + std::vector::iterator it = result.begin(); + bool foundIt = false; + for (; it != result.end(); ++it) { + foundIt = DDfetch(*it,val); + if (foundIt) break; + } + if (foundIt) { + std::vector const & temp = val.strings(); + if (temp.size() != 1) { + throw cms::Exception("Configuration")<< " ERROR: I need 1 "<< s << " tags"; + } + return temp[0]; + } + return "NotFound"; +} diff --git a/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h b/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h new file mode 100644 index 0000000000000..6c88b0a2c7a56 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/ExtractStringFromDDD.h @@ -0,0 +1,19 @@ +#ifndef Geometry_MTDNumberingBuilder_ExtractStringFromDDD_H +#define Geometry_MTDNumberingBuilder_ExtractStringFromDDD_H + +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "FWCore/ParameterSet/interface/types.h" +#include + +class DDFilteredView; + +/** + * Helper function to extract a string from a SpecPar; only returns the + * first one and complains if more than 1 is found. + */ +class ExtractStringFromDDD{ + public: + static std::string getString(std::string const &,DDFilteredView*); +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.cc b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.cc new file mode 100644 index 0000000000000..71054d702af8e --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.cc @@ -0,0 +1,61 @@ +#include "Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.h" +#include "Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h" +#include "Geometry/MTDNumberingBuilder/plugins/CondDBCmsMTDConstruction.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "DetectorDescription/Core/interface/DDVectorGetter.h" +#include "DetectorDescription/Core/interface/DDutils.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/ESTransientHandle.h" +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include + +using namespace edm; + +MTDGeometricTimingDetESModule::MTDGeometricTimingDetESModule( const edm::ParameterSet & p ) + : fromDDD_( p.getParameter( "fromDDD" )) +{ + setWhatProduced( this ); +} + +MTDGeometricTimingDetESModule::~MTDGeometricTimingDetESModule( void ) {} + +void +MTDGeometricTimingDetESModule::fillDescriptions( edm::ConfigurationDescriptions & descriptions ) +{ + edm::ParameterSetDescription descDB; + descDB.add( "fromDDD", false ); + descriptions.add( "mtdNumberingGeometryDB", descDB ); + + edm::ParameterSetDescription desc; + desc.add( "fromDDD", true ); + descriptions.add( "mtdNumberingGeometry", desc ); +} + +std::unique_ptr +MTDGeometricTimingDetESModule::produce( const IdealGeometryRecord & iRecord ) +{ + if( fromDDD_ ) + { + edm::ESTransientHandle cpv; + iRecord.get( cpv ); + + DDDCmsMTDConstruction theDDDCmsMTDConstruction; + return std::unique_ptr (const_cast( theDDDCmsMTDConstruction.construct(&(*cpv), dbl_to_int( DDVectorGetter::get( "detIdShifts" ))))); + + } + else + { + edm::ESHandle pgd; + iRecord.get( pgd ); + + CondDBCmsMTDConstruction cdbtc; + return std::unique_ptr ( const_cast( cdbtc.construct( *pgd ))); + } +} + +DEFINE_FWK_EVENTSETUP_MODULE( MTDGeometricTimingDetESModule ); diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.h b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.h new file mode 100644 index 0000000000000..636d3a2e678a1 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetESModule.h @@ -0,0 +1,31 @@ +#ifndef Geometry_MTDNumberingBuilder_MTDGeometricTimingDetESModule_H +#define Geometry_MTDNumberingBuilder_MTDGeometricTimingDetESModule_H + +#include "FWCore/Framework/interface/ESProducer.h" + +namespace edm { + class ConfigurationDescriptions; + class ParameterSet; +} + +class GeometricTimingDet; +class IdealGeometryRecord; + +class MTDGeometricTimingDetESModule : public edm::ESProducer +{ +public: + MTDGeometricTimingDetESModule( const edm::ParameterSet & p ); + ~MTDGeometricTimingDetESModule( void ) override; + std::unique_ptr produce( const IdealGeometryRecord & ); + + static void fillDescriptions( edm::ConfigurationDescriptions & descriptions ); + +private: + bool fromDDD_; +}; + +#endif + + + + diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.cc b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.cc new file mode 100644 index 0000000000000..ef74ccd4f99a3 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.cc @@ -0,0 +1,160 @@ +#include "Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.h" +#include "Geometry/MTDNumberingBuilder/plugins/DDDCmsMTDConstruction.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDetExtra.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/PGeometricTimingDetExtraRcd.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "DetectorDescription/Core/interface/DDSolid.h" +#include "DetectorDescription/Core/interface/DDMaterial.h" +#include "ExtractStringFromDDD.h" +#include "CondDBCmsMTDConstruction.h" + +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/ESTransientHandle.h" +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/Framework/interface/ESProducer.h" + + +#include + +using namespace edm; + +MTDGeometricTimingDetExtraESModule::MTDGeometricTimingDetExtraESModule(const edm::ParameterSet & p) + : fromDDD_(p.getParameter("fromDDD")) +{ + setWhatProduced(this); +} + +MTDGeometricTimingDetExtraESModule::~MTDGeometricTimingDetExtraESModule() {} + +std::shared_ptr > +MTDGeometricTimingDetExtraESModule::produce(const IdealGeometryRecord & iRecord) { + auto gde = std::make_shared >(); + // get the GeometricTimingDet which has a nav_type + edm::ESHandle gd; + iRecord.get ( gd ); + if (fromDDD_) { + // traverse all components from the tracker down; + // read the DD if from DD + const GeometricTimingDet* tracker = &(*gd); + edm::ESTransientHandle cpv; + iRecord.get( cpv ); + DDExpandedView ev(*cpv); + ev.goTo(tracker->navType()); + putOne((*gde), tracker, ev, 0); + std::vector tc = tracker->components(); + int count=0; + int lev = 1; + // CmsMTDStringToEnum ctst + gde->reserve(tracker->deepComponents().size()); + for( const auto* git : tc ) { + ev.goTo(git->navType()); + putOne((*gde), git, ev, lev); + std::vector inone = git->components(); + if ( inone.empty() ) ++count; + ++lev; + for( const auto* git2 : inone ) { + ev.goTo(git2->navType()); + putOne((*gde), git2, ev, lev); + std::vector intwo= git2->components(); + if ( intwo.empty() ) ++count; + ++lev; + for( const auto* git3 : intwo ) { + ev.goTo(git3->navType()); + putOne((*gde), git3, ev, lev); + std::vector inthree= git3->components(); + if ( inthree.empty() ) ++count; + ++lev; + for( const auto* git4 : inthree ) { + ev.goTo(git4->navType()); + putOne((*gde), git4, ev, lev); + std::vector infour= git4->components(); + if ( infour.empty() ) ++count; + ++lev; + for( const auto* git5 : infour ) { + ev.goTo(git5->navType()); + putOne((*gde), git5, ev, lev); + std::vector infive= git5->components(); + if ( infive.empty() ) ++count; + ++lev; + for( const auto* git6 : infive ) { + ev.goTo(git6->navType()); + putOne((*gde), git6, ev, lev); + std::vector insix= git6->components(); + if ( insix.empty() ){ + ++count; + } else { + edm::LogError("GeometricTimingDetExtra") << "Hierarchy has exceeded hard-coded level 6 for Tracker " ; + } + } // level 6 + --lev; + } // level 5 + --lev; + } // level 4 + --lev; + } //level 3 + --lev; + } // level 2 + --lev; + } + }else{ + // if it is not from the DD, then just get the GDE from ES and match w/ GD. + edm::ESHandle pgde; + iRecord.getRecord().get(pgde); + std::map helperMap; + const GeometricTimingDet* tracker = &(*gd); + helperMap[gd->geographicalID()] = tracker; + std::vector tc = tracker->components(); + for( const auto* git : tc ) { // level 1 + helperMap[git->geographicalID()] = git; + std::vector inone = git->components(); + for( const auto* git2 : inone ) { // level 2 + helperMap[git2->geographicalID()] = git2; + std::vector intwo= git2->components(); + for( const auto* git3 : intwo ) { // level 3 + helperMap[git3->geographicalID()] = git3; + std::vector inthree= git3->components(); + for( const auto* git4 : inthree ) { // level 4 + helperMap[git4->geographicalID()] = git4; + std::vector infour= git4->components(); + for( const auto* git5 : infour ) { // level 5 + helperMap[git5->geographicalID()] = git5; + std::vector infive= git5->components(); + for( const auto* git6 : infive ) { // level 6 + helperMap[git6->geographicalID()] = git6; + if ( !git6->components().empty() ){ + edm::LogError("GeometricTimingDetExtra") << "Hierarchy has exceeded hard-coded level of 6 for Tracker " ; + } + } // level 6 + } // level 5 + } // level 4 + } //level 3 + } // level 2 + } + + const std::vector& pgdes = pgde->pgdes_; + gde->reserve(pgdes.size()); + std::vector evs; //EMPTY + std::string nm; //EMPTY + for (const auto & pgde : pgdes) { + gde->emplace_back( GeometricTimingDetExtra(helperMap[pgde.geographicalId_], pgde.geographicalId_, evs + , pgde.volume_, pgde.density_, pgde.weight_, pgde.copy_ + , pgde.material_, nm)); + } + } + return std::shared_ptr >(gde); +} + +void MTDGeometricTimingDetExtraESModule::putOne(std::vector & gde, const GeometricTimingDet* gd, const DDExpandedView& ev, int lev ) { + std::string matname = ((ev.logicalPart()).material()).name().fullname(); + std::string lpname = ((ev.logicalPart()).name().fullname()); + std::vector evs = GeometricTimingDetExtra::GeoHistory(ev.geoHistory().begin(),ev.geoHistory().end()); + gde.emplace_back(GeometricTimingDetExtra( gd, gd->geographicalId(), evs, + ((ev.logicalPart()).solid()).volume(), ((ev.logicalPart()).material()).density(), + ((ev.logicalPart()).material()).density() * ( ((ev.logicalPart()).solid()).volume() / 1000.), + ev.copyno(), matname, lpname, true )); +} + +DEFINE_FWK_EVENTSETUP_MODULE(MTDGeometricTimingDetExtraESModule); diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.h b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.h new file mode 100644 index 0000000000000..561153e5c7da9 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDGeometricTimingDetExtraESModule.h @@ -0,0 +1,31 @@ +#ifndef Geometry_MTDNumberingBuilder_MTDGeometricTimingDetExtraESModule_H +#define Geometry_MTDNumberingBuilder_MTDGeometricTimingDetExtraESModule_H + +#include "FWCore/Framework/interface/ESProducer.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h" + +class MTDGeometricTimingDetExtraESModule: public edm::ESProducer { + + public: + MTDGeometricTimingDetExtraESModule(const edm::ParameterSet & p); + ~MTDGeometricTimingDetExtraESModule() override; + std::shared_ptr > produce(const IdealGeometryRecord &); + + protected: + + private: + void putOne(std::vector & gde, const GeometricTimingDet* gd, const DDExpandedView& ev, int lev ); + + bool fromDDD_; + +}; + + +#endif + + + + diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h b/Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h new file mode 100644 index 0000000000000..9707b078dff0b --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDStablePhiSort.h @@ -0,0 +1,119 @@ +#ifndef MTDStablePhiSort_H +#define MTDStablePhiSort_H +// #include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include + +#include +#include +#include + +#include + +#include + +namespace details { + template + struct PhiSortElement { + typedef PhiSortElement self; + + template + static self + build(Object & o, Extractor const & extr) { + return self(&o, extr(o)); + } + + PhiSortElement() + : pointer(nullptr) {} + PhiSortElement(Object * p, Scalar v): + pointer(p), + value(v) {} + + Object * pointer; + Scalar value; + + bool operator<(self const & rh) const { + return value +void MTDStablePhiSort(RandomAccessIterator begin, + RandomAccessIterator end, + const Extractor& extr) { + + typedef typename Extractor::result_type Scalar; + typedef typename std::iterator_traits::value_type value_type; + + typedef details::PhiSortElement Element; + + + + std::vector tmpvec(end-begin); + std::transform(begin,end,tmpvec.begin(), + boost::bind(Element::template build,_1, boost::cref(extr)) + ); + + std::vector tmpcop(end-begin); + + std::sort(tmpvec.begin(), tmpvec.end()); + + const unsigned int vecSize = tmpvec.size(); + + + + // special tratment of the TEC modules of rings in petals near phi=0 + // there are at most 5 modules, no other structure has less than ~10 elements to order in phi + // hence the special case in phi~0 if the size of the elements to order is <=5 + const unsigned int nMaxModulesPerRing = 5; + bool phiZeroCase = true; + // + const double phiMin = M_PI_4; + const double phiMax = 2*M_PI-phiMin; + // + if( vecSize > nMaxModulesPerRing ) { + //stability check + // check if the last element is too near to zero --> probably it is zero + double tolerance = 0.000001; + if( fabs(tmpvec.back().value - 0) < tolerance // near 0 + || + fabs(tmpvec.back().value - 2*M_PI) < tolerance ) { // near 2pi + // move it to front + tmpvec.insert(tmpvec.begin(),tmpvec.back()); + tmpvec.pop_back(); + } + } + else { + // check if all the elements have phiphiMax to be sure we are near phi~0 (angles are in [0,2pi) range) + // if a phi goes out from [0,phiMin]U[phiMax,2pi) it is not the case + // sorted. if first > phiMax all other will also... + typename std::vector::iterator p = + std::find_if(tmpvec.begin(),tmpvec.end(), boost::bind(&Element::value,_1) > phiMin); + phiZeroCase = !(p!=tmpvec.end() && (*p).value) and then ('positive' values, >) in (-pi,pi] mapping + // already sorted, just swap ranges + if(p!=tmpvec.end()) { + tmpvec.insert(tmpvec.begin(),p,tmpvec.end()); + tmpvec.resize(vecSize); + } + } + } + + // overwrite the input range with the sorted values + // copy of input container not necessary, but tricky to avoid + std::vector tmpvecy(vecSize); + std::transform(tmpvec.begin(),tmpvec.end(),tmpvecy.begin(),boost::bind(&Element::obj,_1)); + std::copy(tmpvecy.begin(),tmpvecy.end(),begin); + +} + +#endif + diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.cc b/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.cc new file mode 100644 index 0000000000000..13d9b74cd3175 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.cc @@ -0,0 +1,64 @@ +#include "MTDTopologyEP.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "Geometry/Records/interface/PMTDParametersRcd.h" + +MTDTopologyEP::MTDTopologyEP( const edm::ParameterSet& conf ) +{ + edm::LogInfo("MTD") << "MTDTopologyEP::MTDTopologyEP"; + + setWhatProduced(this); +} + +MTDTopologyEP::~MTDTopologyEP() +{ +} + +void +MTDTopologyEP::fillDescriptions( edm::ConfigurationDescriptions & descriptions ) +{ + edm::ParameterSetDescription ttc; + descriptions.add( "mtdTopology", ttc ); +} + +MTDTopologyEP::ReturnType +MTDTopologyEP::produce( const MTDTopologyRcd& iRecord ) +{ + edm::LogInfo("MTDTopologyEP") << "MTDTopologyEP::produce(const MTDTopologyRcd& iRecord)"; + edm::ESHandle ptp; + iRecord.getRecord().get( ptp ); + fillParameters( *ptp ); + + ReturnType myTopo( new MTDTopology( btlVals_, etlVals_ )); + + return myTopo ; +} + +void +MTDTopologyEP::fillParameters( const PMTDParameters& ptp ) +{ + btlVals_.sideStartBit_ = ptp.vitems_[0].vpars_[0]; // 16 + btlVals_.layerStartBit_ = ptp.vitems_[0].vpars_[1]; // 16 + btlVals_.trayStartBit_ = ptp.vitems_[0].vpars_[2]; // 8 + btlVals_.moduleStartBit_ = ptp.vitems_[0].vpars_[3]; // 2 + btlVals_.sideMask_ = ptp.vitems_[0].vpars_[4]; // 0xF + btlVals_.layerMask_ = ptp.vitems_[0].vpars_[5]; // 0xF + btlVals_.trayMask_ = ptp.vitems_[0].vpars_[6]; // 0xFF + btlVals_.moduleMask_ = ptp.vitems_[0].vpars_[7]; // 0x3F + + etlVals_.sideStartBit_ = ptp.vitems_[1].vpars_[0]; + etlVals_.layerStartBit_ = ptp.vitems_[1].vpars_[1]; + etlVals_.ringStartBit_ = ptp.vitems_[1].vpars_[2]; + etlVals_.moduleStartBit_ = ptp.vitems_[1].vpars_[3]; + etlVals_.sideMask_ = ptp.vitems_[1].vpars_[4]; + etlVals_.layerMask_ = ptp.vitems_[1].vpars_[5]; + etlVals_.ringMask_ = ptp.vitems_[1].vpars_[6]; + etlVals_.moduleMask_ = ptp.vitems_[1].vpars_[7]; +} + +DEFINE_FWK_EVENTSETUP_MODULE( MTDTopologyEP); + diff --git a/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.h b/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.h new file mode 100644 index 0000000000000..224cbb2c6b1ca --- /dev/null +++ b/Geometry/MTDNumberingBuilder/plugins/MTDTopologyEP.h @@ -0,0 +1,33 @@ +#ifndef GEOMETRY_MTDNUMBERINGBUILDER_MTDTOPOLOGYEP_H +#define GEOMETRY_MTDNUMBERINGBUILDER_MTDTOPOLOGYEP_H 1 + +#include "memory" +#include "FWCore/Framework/interface/ESProducer.h" +#include "Geometry/MTDNumberingBuilder/interface/MTDTopology.h" +#include "Geometry/Records/interface/MTDTopologyRcd.h" +#include "CondFormats/GeometryObjects/interface/PMTDParameters.h" + +namespace edm { + class ConfigurationDescriptions; +} + +class MTDTopologyEP : public edm::ESProducer +{ +public: + MTDTopologyEP( const edm::ParameterSet & ); + ~MTDTopologyEP( void ) override; + + typedef std::shared_ptr ReturnType; + + static void fillDescriptions( edm::ConfigurationDescriptions & descriptions ); + + ReturnType produce( const MTDTopologyRcd & ); + +private: + void fillParameters( const PMTDParameters& ); + + MTDTopology::BTLValues btlVals_; + MTDTopology::ETLValues etlVals_; +}; + +#endif diff --git a/Geometry/MTDNumberingBuilder/src/CmsMTDDebugNavigator.cc b/Geometry/MTDNumberingBuilder/src/CmsMTDDebugNavigator.cc new file mode 100644 index 0000000000000..5eb881f7c7f06 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/CmsMTDDebugNavigator.cc @@ -0,0 +1,43 @@ +#include "Geometry/MTDNumberingBuilder/interface/CmsMTDDebugNavigator.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +CmsMTDDebugNavigator::CmsMTDDebugNavigator ( const std::vector& gdes ) { + for( const auto& gdei : gdes ) { + const GeometricTimingDetExtra* gdeaddr = &gdei; + _helperMap[gdei.geographicalId().rawId()] = gdeaddr; + } +} + +void CmsMTDDebugNavigator::dump(const GeometricTimingDet& in, const std::vector& gdes){ + edm::LogInfo("CmsMTDDebugNavigator")<<" CmsMTDDebugNavigator - Starting debug"; + for (int k=0; k<20; k++) numinstances[k]=0; + iterate(in,0, gdes); + + for (int k=0; k<20; k++){ + edm::LogInfo("CmsMTDDebugNavigator")<<" CmsMTDDebugNavigator has found "<& gdes){ + numinstances[level]++; + std::string spaces(' ',level*2); + for (unsigned int k=0; kgeographicalId().rawId()]; + edm::LogInfo("CmsMTDDebugNavigator") << level << spaces + << "### VOLUME " << in.components()[k]->name().name() + << " of type " << in.components()[k]->type() + << " copy number " << extra->copyno() + << " positioned in " << in.name().name() + << " global position of centre " << in.components()[k]->translation() + << " volume = " << extra->volume() << " cm3" + << " density = " << extra->density() << " g/cm3" + << " weight " << extra->weight() << " g" + << std::endl; + iterate(*((in.components())[k]),level+1, gdes); + } + return; +} diff --git a/Geometry/MTDNumberingBuilder/src/CmsMTDStringToEnum.cc b/Geometry/MTDNumberingBuilder/src/CmsMTDStringToEnum.cc new file mode 100644 index 0000000000000..fdd5a9ec3193f --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/CmsMTDStringToEnum.cc @@ -0,0 +1,58 @@ +#include "Geometry/MTDNumberingBuilder/interface/CmsMTDStringToEnum.h" + +const CmsMTDStringToEnum::Impl CmsMTDStringToEnum::m_impl; + +CmsMTDStringToEnum::Impl::Impl(){ + _map.insert(std::pair("FastTimerRegion",GeometricTimingDet::MTD)); + + _map.insert(std::pair("btl:BarrelTimingLayer",GeometricTimingDet::BTL)); + _map.insert(std::pair("mtd:Layer1",GeometricTimingDet::BTLLayer)); + _map.insert(std::pair("mtd:Rod1",GeometricTimingDet::BTLTray)); + _map.insert(std::pair("mtd:BModule",GeometricTimingDet::BTLModule)); + _map.insert(std::pair("SensorPackage",GeometricTimingDet::BTLSensor)); + _map.insert(std::pair("Crystal",GeometricTimingDet::BTLCrystal)); + + _map.insert(std::pair("etl:EndcapTimingLayer",GeometricTimingDet::ETL)); + _map.insert(std::pair("mtd:Disc1",GeometricTimingDet::ETLDisc)); + _map.insert(std::pair("mtd:Ring",GeometricTimingDet::ETLRing)); + _map.insert(std::pair("mtd:EModule",GeometricTimingDet::ETLModule)); + _map.insert(std::pair("Sensor",GeometricTimingDet::ETLSensor)); + + // + // build reverse map + // + + _reverseMap.insert(std::pair(GeometricTimingDet::MTD,"FastTimerRegion")); + + _reverseMap.insert(std::pair(GeometricTimingDet::BTL,"btl:BarrelTimingLayer")); + _reverseMap.insert(std::pair(GeometricTimingDet::BTLLayer,"mtd:Layer")); + _reverseMap.insert(std::pair(GeometricTimingDet::BTLTray,"mtd:Rod1")); + _reverseMap.insert(std::pair(GeometricTimingDet::BTLModule,"Module")); + _reverseMap.insert(std::pair(GeometricTimingDet::BTLSensor,"SensorPackage")); + _reverseMap.insert(std::pair(GeometricTimingDet::BTLCrystal,"Crystal")); + + _reverseMap.insert(std::pair(GeometricTimingDet::ETL,"etl:EndcapTimingLayer")); + _reverseMap.insert(std::pair(GeometricTimingDet::ETLDisc,"mtd:Disc1")); + _reverseMap.insert(std::pair(GeometricTimingDet::ETLRing,"mtd:Ring")); + _reverseMap.insert(std::pair(GeometricTimingDet::ETLModule,"Module")); + _reverseMap.insert(std::pair(GeometricTimingDet::ETLSensor,"Sensor")); + + // + // done + // +} + +GeometricTimingDet::GeometricTimingEnumType CmsMTDStringToEnum::type(std::string const & s) const{ + MapEnumType::const_iterator p=map().find(s); + if (p!= map().end()) return p->second; + return GeometricTimingDet::unknown; +} + +std::string const & CmsMTDStringToEnum::name(GeometricTimingDet::GeometricTimingEnumType t) const { + static std::string const u("Unknown"); + ReverseMapEnumType::const_iterator p=reverseMap().find(t); + if (p!= reverseMap().end()) + return p->second; + return u; +} + diff --git a/Geometry/MTDNumberingBuilder/src/ES_MTDTopology.cc b/Geometry/MTDNumberingBuilder/src/ES_MTDTopology.cc new file mode 100644 index 0000000000000..7fcaa3b6d4ec7 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/ES_MTDTopology.cc @@ -0,0 +1,5 @@ +#include "Geometry/MTDNumberingBuilder/interface/MTDTopology.h" + +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(MTDTopology); diff --git a/Geometry/MTDNumberingBuilder/src/GeometricTimingDet.cc b/Geometry/MTDNumberingBuilder/src/GeometricTimingDet.cc new file mode 100644 index 0000000000000..b2fdd7e56b262 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/GeometricTimingDet.cc @@ -0,0 +1,333 @@ +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/TrackerNumberingBuilder/interface/TrackerShapeToBounds.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "DetectorDescription/Core/interface/DDSolid.h" +#include "DetectorDescription/Core/interface/DDMaterial.h" +#include "DetectorDescription/Core/interface/DDExpandedNode.h" +#include "CondFormats/GeometryObjects/interface/PGeometricTimingDet.h" + +#include "CLHEP/Units/GlobalSystemOfUnits.h" + +#include + +#include +#include +#include + +namespace { + + const std::string strue("true"); + + template + double getDouble(const char * s, DDView const & ev) { + DDValue val(s); + std::vector result; + ev.specificsV(result); + std::vector::iterator it = result.begin(); + bool foundIt = false; + for (; it != result.end(); ++it) + { + foundIt = DDfetch(*it,val); + if (foundIt) break; + } + if (foundIt) + { + const std::vector & temp = val.strings(); + if (temp.size() != 1) + { + throw cms::Exception("Configuration") << "I need 1 "<< s << " tags"; + } + return double(::atof(temp[0].c_str())); + } + return 0; + } + + template + std::string getString(const char * s, DDView const & ev) { + DDValue val(s); + std::vector result; + ev.specificsV(result); + std::vector::iterator it = result.begin(); + bool foundIt = false; + for (; it != result.end(); ++it) + { + foundIt = DDfetch(*it,val); + if (foundIt) break; + + } + if (foundIt) + { + const std::vector & temp = val.strings(); + if (temp.size() != 1) + { + throw cms::Exception("Configuration") << "I need 1 "<< s << " tags"; + } + return temp[0]; + } + return "NotFound"; + } +} + + +/** + * What to do in the destructor? + * destroy all the daughters! + */ +GeometricTimingDet::~GeometricTimingDet(){ + deleteComponents(); +} +#ifdef GEOMETRICDETDEBUG +// for use outside CMSSW framework only since it asks for a default DDCompactView... +GeometricTimingDet::GeometricTimingDet(DDnav_type const & navtype, GeometricTimingEnumType type) : + ddd_(navtype.begin(),navtype.end()), type_(type){ + // + // I need to find the params by myself :( + // + //std::cout << "GeometricTimingDet1" << std::endl; + fromDD_ = true; + DDCompactView cpv; // bad, bad, bad! + DDExpandedView ev(cpv); + ev.goTo(navtype); + params_ = ((ev.logicalPart()).solid()).parameters(); + trans_ = ev.translation(); + phi_ = trans_.Phi(); + rho_ = trans_.Rho(); + rot_ = ev.rotation(); + shape_ = ((ev.logicalPart()).solid()).shape(); + ddname_ = ((ev.logicalPart()).ddname()).name(); + parents_ = GeoHistory(ev.geoHistory().begin(),ev.geoHistory().end()) ; + volume_ = ((ev.logicalPart()).solid()).volume(); + density_ = ((ev.logicalPart()).material()).density(); + // _weight = (ev.logicalPart()).weight(); + weight_ = density_ * ( volume_ / 1000.); // volume mm3->cm3 + copy_ = ev.copyno(); + material_ = ((ev.logicalPart()).material()).name().fullname(); + radLength_ = getDouble("TrackerRadLength",ev); + xi_ = getDouble("TrackerXi",ev); + pixROCRows_ = getDouble("PixelROCRows",ev); + pixROCCols_ = getDouble("PixelROCCols",ev); + pixROCx_ = getDouble("PixelROC_X",ev); + pixROCy_ = getDouble("PixelROC_Y",ev); + stereo_ = getString("TrackerStereoDetectors",ev)==strue; + siliconAPVNum_ = getDouble("SiliconAPVNumber",ev); + +} + +GeometricTimingDet::GeometricTimingDet(DDExpandedView* fv, GeometricTimingEnumType type) : type_(type) { + // + // Set by hand the ddd_ + // + //std::cout << "GeometricTimingDet2" << std::endl; + fromDD_ = true; + ddd_ = nav_type(fv->navPos().begin(),fv->navPos().end() ); + params_ = ((fv->logicalPart()).solid()).parameters(); + trans_ = fv->translation(); + phi_ = trans_.Phi(); + rho_ = trans_.Rho(); + rot_ = fv->rotation(); + shape_ = ((fv->logicalPart()).solid()).shape(); + ddname_ = ((fv->logicalPart()).ddname()).name(); + parents_ = GeoHistory(fv->geoHistory().begin(),fv->geoHistory().end()) ; + volume_ = ((fv->logicalPart()).solid()).volume(); + density_ = ((fv->logicalPart()).material()).density(); + // weight_ = (fv->logicalPart()).weight(); + weight_ = density_ * ( volume_ / 1000.); // volume mm3->cm3 + copy_ = fv->copyno(); + material_ = ((fv->logicalPart()).material()).name().fullname(); + radLength_ = getDouble("TrackerRadLength",*fv); + xi_ = getDouble("TrackerXi",*fv); + pixROCRows_ = getDouble("PixelROCRows",*fv); + pixROCCols_ = getDouble("PixelROCCols",*fv); + pixROCx_ = getDouble("PixelROC_X",*fv); + pixROCy_ = getDouble("PixelROC_Y",*fv); + stereo_ = getString("TrackerStereoDetectors",*fv)=="true"; + siliconAPVNum_ = getDouble("SiliconAPVNumber",*fv); + +} +#endif + +GeometricTimingDet::GeometricTimingDet(DDFilteredView* fv, GeometricTimingEnumType type) : + // + // Set by hand the ddd_ + // + trans_(fv->translation()), + phi_(trans_.Phi()), + rho_(trans_.Rho()), + rot_(fv->rotation()), + shape_(((fv->logicalPart()).solid()).shape()), + ddname_(((fv->logicalPart()).ddname()).name()), + type_(type), + params_(((fv->logicalPart()).solid()).parameters()), + // want this :) ddd_(fv->navPos().begin(),fv->navPos().end()), +#ifdef GEOMTRICDETDEBUG + parents_(fv->geoHistory().begin(),fv->geoHistory().end()), + volume_(((fv->logicalPart()).solid()).volume()), + density_(((fv->logicalPart()).material()).density()), + // _weight = (fv->logicalPart()).weight(); + weight_(density_ * ( volume_ / 1000.)), // volume mm3->cm3 + copy_(fv->copyno()), + material_(((fv->logicalPart()).material()).name().fullname()), +#endif + radLength_(getDouble("TrackerRadLength",*fv)), + xi_(getDouble("TrackerXi",*fv)), + pixROCRows_(getDouble("PixelROCRows",*fv)), + pixROCCols_(getDouble("PixelROCCols",*fv)), + pixROCx_(getDouble("PixelROC_X",*fv)), + pixROCy_(getDouble("PixelROC_Y",*fv)), + stereo_(getString("TrackerStereoDetectors",*fv)==strue), + siliconAPVNum_(getDouble("SiliconAPVNumber",*fv)) +#ifdef GEOMTRICDETDEBUG + , + fromDD_(true) +#endif +{ + const DDFilteredView::nav_type& nt = fv->navPos(); + ddd_ = nav_type(nt.begin(), nt.end()); +} + +// PGeometricTimingDet is persistent version... make it... then come back here and make the +// constructor. +GeometricTimingDet::GeometricTimingDet ( const PGeometricTimingDet::Item& onePGD, GeometricTimingEnumType type) : + trans_(onePGD.x_, onePGD.y_, onePGD.z_), + phi_(onePGD.phi_), //_trans.Phi()), + rho_(onePGD.rho_), //_trans.Rho()), + rot_(onePGD.a11_, onePGD.a12_, onePGD.a13_, + onePGD.a21_, onePGD.a22_, onePGD.a23_, + onePGD.a31_, onePGD.a32_, onePGD.a33_), + shape_(static_cast(onePGD.shape_)), + ddd_(), + ddname_(onePGD.name_, onePGD.ns_),//, "fromdb"); + type_(type), + params_(), + geographicalID_(onePGD.geographicalID_), +#ifdef GEOMTRICDETDEBUG + parents_(), // will remain empty... hate wasting the space but want all methods to work. + volume_(onePGD.volume_), + density_(onePGD.density_), + weight_(onePGD.weight_), + copy_(onePGD.copy_), + material_(onePGD.material_), +#endif + radLength_(onePGD.radLength_), + xi_(onePGD.xi_), + pixROCRows_(onePGD.pixROCRows_), + pixROCCols_(onePGD.pixROCCols_), + pixROCx_(onePGD.pixROCx_), + pixROCy_(onePGD.pixROCy_), + stereo_(onePGD.stereo_), + siliconAPVNum_(onePGD.siliconAPVNum_) +#ifdef GEOMTRICDETDEBUG + , // mind the tricky comma is needed. + fromDD_(false) +#endif +{ + //std::cout << "GeometricTimingDet4" << std::endl; + + if(onePGD.shape_==1||onePGD.shape_==3){ //The parms vector is neede only in the case of box or trap shape + params_.reserve(11); + params_.emplace_back(onePGD.params_0); + params_.emplace_back(onePGD.params_1); + params_.emplace_back(onePGD.params_2); + params_.emplace_back(onePGD.params_3); + params_.emplace_back(onePGD.params_4); + params_.emplace_back(onePGD.params_5); + params_.emplace_back(onePGD.params_6); + params_.emplace_back(onePGD.params_7); + params_.emplace_back(onePGD.params_8); + params_.emplace_back(onePGD.params_9); + params_.emplace_back(onePGD.params_10); + } + + ddd_.reserve(onePGD.numnt_); + ddd_.emplace_back(onePGD.nt0_); + ddd_.emplace_back(onePGD.nt1_); + ddd_.emplace_back(onePGD.nt2_); + ddd_.emplace_back(onePGD.nt3_); + if ( onePGD.numnt_ > 4 ) { + ddd_.emplace_back(onePGD.nt4_); + if ( onePGD.numnt_ > 5 ) { + ddd_.emplace_back(onePGD.nt5_); + if ( onePGD.numnt_ > 6 ) { + ddd_.emplace_back(onePGD.nt6_); + if ( onePGD.numnt_ > 7 ) { + ddd_.emplace_back(onePGD.nt7_); + if ( onePGD.numnt_ > 8 ) { + ddd_.emplace_back(onePGD.nt8_); + if ( onePGD.numnt_ > 9 ) { + ddd_.emplace_back(onePGD.nt9_); + if ( onePGD.numnt_ > 10 ) { + ddd_.emplace_back(onePGD.nt10_); + }}}}}} + } + +} + +GeometricTimingDet::ConstGeometricTimingDetContainer GeometricTimingDet::deepComponents() const { + // + // iterate on all the components ;) + // + ConstGeometricTimingDetContainer temp; + deepComponents(temp); + return temp; +} + +void GeometricTimingDet::deepComponents(ConstGeometricTimingDetContainer & cont) const { + if (isLeaf()) { + cont.emplace_back(this); + } + else + std::for_each(container_.begin(),container_.end(), + [&](const GeometricTimingDet* iDet) { + iDet->deepComponents(cont); + } + ); +} + +void GeometricTimingDet::addComponents(GeometricTimingDetContainer const & cont){ + container_.reserve(container_.size()+cont.size()); + std::copy(cont.begin(), cont.end(), back_inserter(container_)); +} + +void GeometricTimingDet::addComponents(ConstGeometricTimingDetContainer const & cont){ + container_.reserve(container_.size()+cont.size()); + std::copy(cont.begin(), cont.end(), back_inserter(container_)); +} + +void GeometricTimingDet::addComponent(GeometricTimingDet* det){ + container_.emplace_back(det); +} + +namespace { + struct Deleter { + void operator()(GeometricTimingDet const* det) const { delete const_cast(det);} + }; +} + +void GeometricTimingDet::deleteComponents(){ + std::for_each(container_.begin(),container_.end(),Deleter()); + container_.clear(); +} + + +GeometricTimingDet::Position GeometricTimingDet::positionBounds() const{ + Position pos(float(trans_.x()/cm), + float(trans_.y()/cm), + float(trans_.z()/cm)); + return pos; +} + +GeometricTimingDet::Rotation GeometricTimingDet::rotationBounds() const{ + DD3Vector x, y, z; + rot_.GetComponents(x, y, z); + Rotation rotation(float(x.X()),float(x.Y()),float(x.Z()), + float(y.X()),float(y.Y()),float(y.Z()), + float(z.X()),float(z.Y()),float(z.Z())); + return rotation; +} + +std::unique_ptr GeometricTimingDet::bounds() const{ + const std::vector& par = params_; + TrackerShapeToBounds shapeToBounds; + return std::unique_ptr(shapeToBounds.buildBounds(shape_,par)); +} + diff --git a/Geometry/MTDNumberingBuilder/src/GeometricTimingDetExtra.cc b/Geometry/MTDNumberingBuilder/src/GeometricTimingDetExtra.cc new file mode 100644 index 0000000000000..c3e7a74bda960 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/GeometricTimingDetExtra.cc @@ -0,0 +1,14 @@ +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h" + +/** + * Constructors to be used when looping over DDD + */ +GeometricTimingDetExtra::GeometricTimingDetExtra( GeometricTimingDet const * gd, DetId id, GeoHistory& gh, double vol, double dens, double wgt, double cpy, const std::string& mat, const std::string& name, bool dd ) + : _mygd(gd), _geographicalId(id), _parents(gh), _volume(vol), _density(dens), _weight(wgt), _copy((int)(cpy)), _material(mat), _name(name), _fromDD(dd) +{ + +} + +GeometricTimingDetExtra::~GeometricTimingDetExtra() +{ } + diff --git a/Geometry/MTDNumberingBuilder/src/MTDMapDDDtoID.cc b/Geometry/MTDNumberingBuilder/src/MTDMapDDDtoID.cc new file mode 100644 index 0000000000000..06cd087c109a3 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/MTDMapDDDtoID.cc @@ -0,0 +1,71 @@ +#include "Geometry/MTDNumberingBuilder/interface/MTDMapDDDtoID.h" +#include "DetectorDescription/Core/interface/DDExpandedView.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "CLHEP/Units/GlobalSystemOfUnits.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + +MTDMapDDDtoID::MTDMapDDDtoID(const GeometricTimingDet* iDet) +{ + buildAll(iDet); + // + // loop over all the volumes which hahe a SpecPar called specpar with value value, + // and save in the map the association nav_type<->id + // +} + +void MTDMapDDDtoID::buildAll(const GeometricTimingDet* iDet){ + edm::LogInfo("MTDMapDDDtoID")<<" Building the MTDMapDDDtoID map."; + MTDMapDDDtoID* me = const_cast(this); + me->buildAllStep2(iDet); +} + +void MTDMapDDDtoID::buildAllStep2(const GeometricTimingDet* theTracker){ + + std::vector allDetectors; + theTracker->deepComponents(allDetectors); + + // + // Also build a map! (for slower access) + // + + for (auto & allDetector : allDetectors){ + + path2id_.insert(std::pair(allDetector->navType(),(allDetector->geographicalID())())); + revpath2id_.insert(std::pair((allDetector->geographicalID())(),allDetector->navType())); + navVec.emplace_back(allDetector->navType()); + } + edm::LogInfo("MTDMapDDDtoID")<<"Created MTDMapDDDtoID; results in "<::const_iterator it = path2id_.find(n); + unsigned int result = 0; + if (it != path2id_.end()) + result = it->second; + return result; +} + + +std::vector const & MTDMapDDDtoID::allNavTypes() const{ + return navVec; +} + +namespace { + const MTDMapDDDtoID::nav_type nullresult; +} + +MTDMapDDDtoID::nav_type const & MTDMapDDDtoID::navType(uint32_t num) const +{ + std::map::const_iterator it = revpath2id_.find(num); + if (it != revpath2id_.end()) + return it->second; + return nullresult; +} + +void MTDMapDDDtoID::clear(){ + path2id_.clear(); + edm::LogInfo("MTDMapDDDtoID")<<" MTDMapDDDtoID maps deleted from memory."; +} diff --git a/Geometry/MTDNumberingBuilder/src/MTDTopology.cc b/Geometry/MTDNumberingBuilder/src/MTDTopology.cc new file mode 100644 index 0000000000000..dc74225570c84 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/MTDTopology.cc @@ -0,0 +1,149 @@ +#include "Geometry/MTDNumberingBuilder/interface/MTDTopology.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "DataFormats/ForwardDetId/interface/BTLDetId.h" +#include "DataFormats/ForwardDetId/interface/ETLDetId.h" +#include "DataFormats/SiPixelDetId/interface/PixelSubdetector.h" +#include "DataFormats/SiStripDetId/interface/StripSubdetector.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include +#include + +MTDTopology::MTDTopology( const BTLValues& btl, const ETLValues& etl ) + : btlVals_(btl), + etlVals_(etl), + bits_per_field{ + [BTLModule] = { btlVals_.moduleStartBit_, btlVals_.moduleMask_, MTDDetId::BTL}, + [BTLTray] = { btlVals_.trayStartBit_, btlVals_.trayMask_, MTDDetId::BTL}, + [BTLLayer] = { btlVals_.layerStartBit_, btlVals_.layerMask_, MTDDetId::BTL}, + [BTLSide] = { btlVals_.sideStartBit_, btlVals_.sideMask_, MTDDetId::BTL}, + [ETLModule] = { etlVals_.moduleStartBit_, etlVals_.moduleMask_, MTDDetId::ETL}, + [ETLRing] = { etlVals_.ringStartBit_, etlVals_.ringMask_, MTDDetId::ETL}, + [ETLLayer] = { etlVals_.layerStartBit_, etlVals_.layerMask_, MTDDetId::ETL}, + [ETLSide] = { etlVals_.sideStartBit_, etlVals_.sideMask_, MTDDetId::ETL} + } +{} + + + +unsigned int MTDTopology::side(const DetId &id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + switch( subdet ) { + case MTDDetId::BTL: + return btlSide(id); + case MTDDetId::ETL: + return etlSide(id); + default: + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::side"; + } + return std::numeric_limits::max(); +} + +unsigned int MTDTopology::layer(const DetId &id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + switch( subdet ) { + case MTDDetId::BTL: + return btlLayer(id); + case MTDDetId::ETL: + return etlLayer(id); + default: + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::layer"; + } + return std::numeric_limits::max(); +} + +unsigned int MTDTopology::module(const DetId &id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + switch( subdet ) { + case MTDDetId::BTL: + return btlModule(id); + case MTDDetId::ETL: + return etlModule(id); + default: + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::module"; + } + return std::numeric_limits::max(); +} + +unsigned int MTDTopology::tray(const DetId &id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + switch( subdet ) { + case MTDDetId::BTL: + return btlTray(id); + case MTDDetId::ETL: + return std::numeric_limits::max(); + default: + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::tray"; + } + return std::numeric_limits::max(); +} + +unsigned int MTDTopology::ring(const DetId &id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + switch( subdet ) { + case MTDDetId::BTL: + return std::numeric_limits::max(); + case MTDDetId::ETL: + return etlModule(id); + default: + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::ring"; + } + return std::numeric_limits::max(); +} + + + +std::string MTDTopology::print(DetId id) const { + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + std::stringstream strstr; + + if ( subdet == MTDDetId::BTL ) { + unsigned int theSide = btlSide(id); + unsigned int theLayer = btlLayer(id); + unsigned int theTray = btlTray(id); + unsigned int theModule = btlModule(id); + std::string side = (btlSide(id) == 1 ) ? "-" : "+"; + strstr << "BTL" + << " Side " << theSide << side + << " Layer " << theLayer + << " Tray " << theTray + << " Module " << theModule ; + strstr << " (" << id.rawId() << ")"; + return strstr.str(); + } + + if ( subdet == MTDDetId::ETL ) { + unsigned int theSide = etlSide(id); + unsigned int theLayer = etlLayer(id); + unsigned int theRing = etlRing(id); + unsigned int theModule = etlModule(id); + std::string side = (etlSide(id) == 1 ) ? "-" : "+"; + strstr << "ETL" + << " Side " << theSide << side + << " Layer " << theLayer + << " Ring " << theRing + << " Module " << theModule ; + strstr << " (" << id.rawId() << ")"; + return strstr.str(); + } + throw cms::Exception("Invalid DetId") << "Unsupported DetId in MTDTopology::print"; + return strstr.str(); +} + + + +int MTDTopology::getMTDLayerNumber(const DetId &id) const { + int layer = -1; + uint32_t subdet=MTDDetId(id).mtdSubDetector(); + + if (id.det() == DetId::Forward) { + if (subdet == MTDDetId::BTL) { + layer = btlLayer(id); + } else if (id.subdetId() == MTDDetId::ETL) { + layer = etlLayer(id); + } else { + edm::LogInfo("MTDTopology") << ">>> Invalid subdetId() " ; + } + } + return layer; +} + diff --git a/Geometry/MTDNumberingBuilder/src/module.cc b/Geometry/MTDNumberingBuilder/src/module.cc new file mode 100644 index 0000000000000..75a9bbd1a10ac --- /dev/null +++ b/Geometry/MTDNumberingBuilder/src/module.cc @@ -0,0 +1,10 @@ +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDetExtra.h" + +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(GeometricTimingDet); +TYPELOOKUP_DATA_REG(GeometricTimingDetExtra); +TYPELOOKUP_DATA_REG(std::vector); + + diff --git a/Geometry/MTDNumberingBuilder/test/BuildFile.xml b/Geometry/MTDNumberingBuilder/test/BuildFile.xml new file mode 100644 index 0000000000000..7b2fe8fb1b030 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/BuildFile.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Geometry/MTDNumberingBuilder/test/FakeCPP.h b/Geometry/MTDNumberingBuilder/test/FakeCPP.h new file mode 100644 index 0000000000000..8b4ca728ce6ec --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/FakeCPP.h @@ -0,0 +1,33 @@ +/* + * Fake cpp_unit to be used if cpp_unit is not avaliable + * + */ +#include +#include + +namespace cppUnit { + + std::pair & stats() { + static std::pair passedFailed(0,0); + return passedFailed; + } + + bool test(bool pf) { + if (pf) stats().first++; + else stats().second++; + return pf; + } + + struct Dump { + Dump(){} + ~Dump(){ + std::cerr << "Test passed: " << stats().first << std::endl; + std::cerr << "Test failed: " << stats().second << std::endl; + } + }; + + +} + +#define CPPUNIT_ASSERT(x) if (!cppUnit::test(x)) std::cerr<< "failed "<< #x << std::endl; + diff --git a/Geometry/MTDNumberingBuilder/test/GeometricTimingDetAnalyzer.cc b/Geometry/MTDNumberingBuilder/test/GeometricTimingDetAnalyzer.cc new file mode 100644 index 0000000000000..34b4c2167eeb2 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/GeometricTimingDetAnalyzer.cc @@ -0,0 +1,125 @@ +// -*- C++ -*- +// +// Package: GeometricDetAnalyzer +// Class: GeometricDetAnalyzer +// +/**\class GeometricDetAnalyzer GeometricDetAnalyzer.cc test/GeometricDetAnalyzer/src/GeometricDetAnalyzer.cc + + Description: + + Implementation: + +*/ +// +// Original Author: Tommaso Boccali +// Created: Tue Jul 26 08:47:57 CEST 2005 +// +// + + +// system include files +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/MTDNumberingBuilder/interface/GeometricTimingDet.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "Geometry/TrackerNumberingBuilder/interface/CmsTrackerDebugNavigator.h" + +// CLHEP Dependency +#include + +// +// +// class decleration +// + +class GeometricTimingDetAnalyzer : public edm::one::EDAnalyzer<> { + public: + explicit GeometricTimingDetAnalyzer( const edm::ParameterSet& ); + ~GeometricTimingDetAnalyzer() override; + + void beginJob() override {} + void analyze(edm::Event const& iEvent, edm::EventSetup const&) override; + void endJob() override {} +}; + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +GeometricTimingDetAnalyzer::GeometricTimingDetAnalyzer( const edm::ParameterSet& iConfig ) +{ + //now do what ever initialization is needed + +} + + +GeometricTimingDetAnalyzer::~GeometricTimingDetAnalyzer() +{ + + // do anything here that needs to be done at desctruction time + // (e.g. close files, deallocate resources etc.) + +} + + +// +// member functions +// + +// ------------ method called to produce the data ------------ +void +GeometricTimingDetAnalyzer::analyze( const edm::Event& iEvent, const edm::EventSetup& iSetup ) +{ + using namespace edm; + + edm::LogInfo("GeometricTimingDetAnalyzer")<< "Here I am "; + // + // get the GeometricTimingDet + // + edm::ESHandle pDD; + iSetup.get().get( pDD ); + edm::LogInfo("GeometricTimingDetAnalyzer")<< " Top node is "<< pDD.product(); + edm::LogInfo("GeometricTimingDetAnalyzer")<< " And Contains Daughters: "<< pDD->deepComponents().size(); + std::vector det = pDD->deepComponents(); + for(auto & it : det){ + const DDRotationMatrix& res = it->rotation(); + DD3Vector x, y, z; + res.GetComponents(x, y, z); + DD3Vector colx(x.X(),x.Y(),x.Z()); + DD3Vector coly(y.X(),y.Y(),y.Z()); + DD3Vector colz(z.X(),z.Y(),z.Z()); + + DDRotationMatrix result(colx,coly,colz); + + DD3Vector cx, cy, cz; + result.GetComponents(cx, cy, cz); + if (cx.Cross(cy).Dot(cz) < 0.5){ + edm::LogInfo("GeometricTimingDetAnalyzer") <<"Left Handed Rotation Matrix detected; making it right handed: "<name(); + } + } + + +} + +//define this as a plug-in +DEFINE_FWK_MODULE(GeometricTimingDetAnalyzer); diff --git a/Geometry/MTDNumberingBuilder/test/MTDModuleNumbering.cc b/Geometry/MTDNumberingBuilder/test/MTDModuleNumbering.cc new file mode 100644 index 0000000000000..d02acc7bcde71 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/MTDModuleNumbering.cc @@ -0,0 +1,1251 @@ +// -*- C++ -*- +// +/* + Description: + + Implementation: + +*/ + +// +// Original Author: Riccardo Ranieri +// Created: Tue Feb 27 22:22:22 CEST 2007 +// +// + +// system include files +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "Geometry/CommonDetUnit/interface/TrackingGeometry.h" +#include "Geometry/Records/interface/TrackerDigiGeometryRecord.h" +#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h" +#include "Geometry/CommonTopologies/interface/PixelTopology.h" +#include "Geometry/CommonTopologies/interface/StripTopology.h" +#include "Geometry/TrackerGeometryBuilder/interface/PixelGeomDetType.h" +#include "Geometry/TrackerGeometryBuilder/interface/StripGeomDetType.h" + +#include "Geometry/TrackerGeometryBuilder/interface/PixelGeomDetUnit.h" +#include "DataFormats/GeometrySurface/interface/BoundSurface.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "Geometry/TrackerNumberingBuilder/interface/CmsTrackerDebugNavigator.h" +#include "DataFormats/SiStripDetId/interface/StripSubdetector.h" +#include "DataFormats/TrackerCommon/interface/TrackerTopology.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/TrackerTopologyRcd.h" +#include "Geometry/TrackerNumberingBuilder/interface/CmsTrackerStringToEnum.h" +#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h" +#include "DetectorDescription/Core/interface/DDRoot.h" +#include "DetectorDescription/Core/interface/DDExpandedView.h" +#include "DetectorDescription/Core/interface/DDFilter.h" +#include "DetectorDescription/Core/interface/DDFilteredView.h" +#include "DetectorDescription/Core/interface/DDCompactView.h" +#include "DetectorDescription/Core/interface/DDMaterial.h" + +// output +#include +#include +#include +#include +#include +// + +// +// class decleration +// + +//double PI = 3.141592654; + +class ModuleNumbering : public edm::one::EDAnalyzer<> { +public: + explicit ModuleNumbering( const edm::ParameterSet& ); + ~ModuleNumbering() override; + + void beginJob() override {} + void analyze(edm::Event const& iEvent, edm::EventSetup const&) override; + void endJob() override {} + +private: + // ----------member data --------------------------- + void fillModuleVariables(const GeometricDet* module, double& polarRadius, double& phiRad, double& z); + double changePhiRange_From_ZeroTwoPi_To_MinusPiPlusPi(double phiRad); + double changePhiRange_From_MinusPiPlusPi_To_MinusTwoPiZero(double phiRad); + double changePhiRange_From_MinusPiPlusPi_To_ZeroTwoPi(double phiRad); + // + // counters + unsigned int iOK; + unsigned int iERROR; + // +}; + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// +static const double tolerance_space = 1.000; // 1.000 mm +static const double tolerance_angle = 0.001; // 0.001 rad + +// +// constructors and destructor +// +ModuleNumbering::ModuleNumbering( const edm::ParameterSet& iConfig ) +{ + //now do what ever initialization is needed + +} + + +ModuleNumbering::~ModuleNumbering() +{ + + // do anything here that needs to be done at desctruction time + // (e.g. close files, deallocate resources etc.) + +} + + +// +// member functions +// + +void ModuleNumbering::fillModuleVariables(const GeometricDet* module, double& polarRadius, double& phiRad, double& z) { + // module variables + polarRadius = std::sqrt(module->translation().X()*module->translation().X()+module->translation().Y()*module->translation().Y()); + phiRad = atan2(module->translation().Y(),module->translation().X()); + // tolerance near phi=0 + if(fabs(phiRad) < tolerance_angle) phiRad=0.0; + // negative phi: from [-PI,+PI) to [0,2PI) + if(phiRad < 0) phiRad+=2*M_PI; + // + z = module->translation().Z(); + // +} + +double ModuleNumbering::changePhiRange_From_ZeroTwoPi_To_MinusPiPlusPi(double phiRad) { + double new_phiRad = phiRad; + // tolerance near phi=PI + if(fabs(new_phiRad-M_PI) < tolerance_angle) new_phiRad=M_PI; + // phi greater than PI: from [0,2PI) to [-PI,+PI) + if(new_phiRad > M_PI) new_phiRad-=2*M_PI; + // + return new_phiRad; +} + +double ModuleNumbering::changePhiRange_From_MinusPiPlusPi_To_MinusTwoPiZero(double phiRad) { + double new_phiRad = phiRad; + // tolerance near phi=PI + if(fabs(fabs(new_phiRad)-M_PI) < tolerance_angle) new_phiRad=M_PI; + // phi greater than PI: from [-PI,+PI) to [0,2PI) + if(new_phiRad > 0) new_phiRad-=2*M_PI; + // + return new_phiRad; +} + +double ModuleNumbering::changePhiRange_From_MinusPiPlusPi_To_ZeroTwoPi(double phiRad) { + double new_phiRad = phiRad; + // tolerance near phi=PI + if(fabs(fabs(new_phiRad)-M_PI) < tolerance_angle) new_phiRad=M_PI; + // phi greater than PI: from [-PI,+PI) to [0,2PI) + if(new_phiRad < 0) new_phiRad+=2*M_PI; + // + return new_phiRad; +} + +// ------------ method called to produce the data ------------ +void +ModuleNumbering::analyze( const edm::Event& iEvent, const edm::EventSetup& iSetup ) +{ + //Retrieve tracker topology from geometry + edm::ESHandle tTopoHandle; + iSetup.get().get(tTopoHandle); + const TrackerTopology* const tTopo = tTopoHandle.product(); + + + + edm::LogInfo("ModuleNumbering") << "begins"; + + // output file + std::ofstream Output("ModuleNumbering.log",std::ios::out); + // + + // reset counters + iOK = 0; + iERROR = 0; + // + + // + // get the GeometricDet + // + edm::ESHandle rDD; + edm::ESHandle > rDDE; + iSetup.get().get( rDD ); + iSetup.get().get( rDDE ); + edm::LogInfo("ModuleNumbering") << " Top node is " << rDD.product() << " " << rDD.product()->name().name() << std::endl; + edm::LogInfo("ModuleNumbering") << " And Contains Daughters: " << rDD.product()->deepComponents().size() << std::endl; + CmsTrackerDebugNavigator nav(*rDDE.product()); + nav.dump(*rDD.product(), *rDDE.product()); + // + //first instance tracking geometry + edm::ESHandle pDD; + iSetup.get ().get (pDD); + // + + std::vector modules = (*rDD).deepComponents(); + std::map< uint32_t , const GeometricDet* > mapDetIdToGeometricDet; + + for(auto & module : modules){ + mapDetIdToGeometricDet[module->geographicalID().rawId()] = module; + } + + // Debug variables + // + uint32_t myDetId = 0; + unsigned int iDetector = 1; + unsigned int nSubDetectors = 6; + // + double polarRadius = 0.0; + double phiRad = 0.0; + double z = 0.0; + // + + Output << "************************ List of modules with positions ************************" << std::endl; + Output << std::fixed << std::setprecision(4); // set as default 4 decimal digits (0.1 um or 0.1 rad) + + for(unsigned int iSubDetector = 1; iSubDetector <= nSubDetectors; iSubDetector++) { + + // modules + switch (iSubDetector) { + + // PXB + case 1: + { + break; + } + + // PXF + case 2: + { + break; + } + + // TIB + case 3: + { + + // TIB loop + unsigned int string_int_ext_TIB[8] = { 26 , 30 , 34 , 38 , 44 , 46 , 52 , 56 }; // number of strings per layer 1/4 int/ext + unsigned int mod_type_TIB[8] = { 1 , 2 , 1 , 2 , 0 , 0 , 0 , 0 }; // first and last type for module type loop + unsigned int nLayers = 4; + unsigned int nModules = 3; + // debug variables + double layer_R = 0.0; + double layer_R_previous = 0.0; + double side_z = 0.0; + double side_z_previous = -10000.0; + double part_R = 0.0; + double part_R_previous = 0.0; + double string_phi = 0.0; + double string_phi_previous = 0.0; + double module_z = 0.0; + double module_z_previous = 0.0; + // + for(unsigned int iLayer = 1; iLayer <= nLayers; iLayer++) { // Layer: 1,...,nLayers + for(unsigned int iSide = 1; iSide <= 2; iSide++){ // Side: 1:- 2:+ + for(unsigned int iPart = 1; iPart <= 2; iPart++){ // Part: 1:int 2:ext + unsigned int jString = ( 2 * ( iLayer - 1 ) ) + ( iPart - 1 ); + for(unsigned int iString = 1; iString <= string_int_ext_TIB[jString] ; iString++) { // String: 1,...,nStrings + for(unsigned int iModule = 1; iModule <= nModules ; iModule++) { // Module: 1,...,nModules + for(unsigned int iType = mod_type_TIB[2*(iLayer-1)]; iType <= mod_type_TIB[2*(iLayer-1)+1] ; iType++) { // Module Type: 0 (ss) 1-2 (ds stereo and rphi) + + myDetId = 0; + // detector + myDetId <<= 4; + myDetId |= iDetector; + // subdetector + myDetId <<= 3; + myDetId |= iSubDetector; + // not used + myDetId <<= 8; + myDetId |= 0; + // layer + myDetId <<= 3; + myDetId |= iLayer; + // side + myDetId <<= 2; + myDetId |= iSide; + // part + myDetId <<= 2; + myDetId |= iPart; + // string number + myDetId <<= 6; + myDetId |= iString; + // module number + myDetId <<= 2; + myDetId |= iModule; + // module type + myDetId <<= 2; + myDetId |= iType; + // + std::bitset<32> binary_myDetId(myDetId); + Output << std::endl << std::endl; + Output << " ******** myDet Id = " << myDetId << " (" << binary_myDetId << ")" << std::endl; + // + unsigned int rawid = mapDetIdToGeometricDet[myDetId]->geographicalID().rawId(); + std::bitset<32> binary_detid(rawid); + GeometricDet::nav_type detNavType = mapDetIdToGeometricDet[myDetId]->navType(); + // + Output << " raw Id = " << rawid << " (" << binary_detid << ")" + << "\t nav type = " << printNavType(&detNavType.front(),detNavType.size()) << std::endl; + + // variables + fillModuleVariables(mapDetIdToGeometricDet[myDetId], polarRadius, phiRad, z); + layer_R = polarRadius; + side_z = z; + part_R = polarRadius; + string_phi = phiRad; + module_z = z; + // + + Output << "\t R = " << polarRadius << "\t phi = " << phiRad << "\t z = " << z << std::endl; + + // Module Info + + std::string name = mapDetIdToGeometricDet[myDetId]->name().name(); + unsigned int theLayer = tTopo->tibLayer(rawid); + std::vector theString = tTopo->tibStringInfo(rawid); + unsigned int theModule = tTopo->tibModule(rawid); + std::string side; + std::string part; + side = (theString[0] == 1 ) ? "-" : "+"; + part = (theString[1] == 1 ) ? "int" : "ext"; + Output << " TIB" << side << "\t" << "Layer " << theLayer << " " << part + << "\t" << "string " << theString[2] << "\t" << " module " << theModule << " " << name << std::endl; + // + + // module: |z| check + Output << "\t # "; + if( ( fabs(module_z) - fabs(module_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering not respected in module "; + iERROR++; + } else { + Output << "\t OK" << " |z| ordering in module "; + iOK++; + } + Output << iModule-1 << " to " << iModule << " (" << module_z_previous << " --> " << module_z << ")" << std::endl; + // + } // type loop + + // + module_z_previous = module_z; + // + } // module loop + + // string: phi check + Output << "\t ## "; + if( ( string_phi - string_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in string "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in string "; + iOK++; + } + Output << iString-1 << " to " << iString << " (" << string_phi_previous << " --> " << string_phi << ")" << std::endl; + // + string_phi_previous = string_phi; + module_z_previous = 0.0; + // + } // string loop + + // part: R check + Output << "\t ### "; + if( ( part_R - part_R_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR R ordering (part int/ext) not respected in layer "; + iERROR++; + } else { + Output << "\t OK" << " R ordering (part int/ext) in layer "; + iOK++; + } + Output << iLayer << " part " << iPart-1 << " to " << iPart << " (" << part_R_previous << " --> " << part_R << ")" << std::endl; + // + part_R_previous = part_R; + string_phi_previous = 0.0; + module_z_previous = 0.0; + // + } // part loop + + // side: z check + Output << "\t #### "; + if( ( side_z - side_z_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR z ordering (side -/+) not respected in layer "; + iERROR++; + } else { + Output << "\t OK" << " z ordering (side -/+) in layer "; + iOK++; + } + Output << iLayer << " side " << iSide-1 << " to " << iSide << " (" << side_z_previous << " --> " << side_z << ")" << std::endl; + // + side_z_previous = side_z; + part_R_previous = 0.0; + string_phi_previous = 0.0; + module_z_previous = 0.0; + // + } // side loop + + // layer: R check + Output << "\t ##### "; + if( ( layer_R - layer_R_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR R ordering not respected from layer "; + iERROR++; + } else { + Output << "\t OK" << " R ordering in layer "; + iOK++; + } + Output << iLayer-1 << " to " << iLayer << " (" << layer_R_previous << " --> " << layer_R << ")" << std::endl; + // + layer_R_previous = layer_R; + side_z_previous = -10000.0; + part_R_previous = 0.0; + string_phi_previous = 0.0; + module_z_previous = 0.0; + // + } // layer loop + + break; + } + + // TID + case 4: + { + + // TID loop + unsigned int modules_TID[3] = { 12 , 12 , 20 }; // number of modules per disk + unsigned int mod_type_TID[8] = { 1 , 2 , 1 , 2 , 0 , 0 , 0 , 0 }; // first and last type for module type loop + unsigned int nDisks = 3; + unsigned int nRings = 3; + // debug variables + double side_z = 0.0; + double side_z_previous = 10000.0; + double disk_z = 0.0; + double disk_z_previous = 0.0; + double ring_R = 0.0; + double ring_R_previous = 0.0; + double part_z = 0.0; + double part_z_previous = 0.0; + double module_phi = 0.0; + double module_phi_previous = -M_PI; + // + for(unsigned int iSide = 2; iSide >= 1; iSide--){ // Side: 1:- 2:+ + for(unsigned int iDisk = 1; iDisk <= nDisks; iDisk++) { // Disk: 1,...,nDisks + for(unsigned int iRing = 1; iRing <= nRings; iRing++){ // Ring: 1,...,nRings + for(int iPart = 2; iPart >= 1; iPart--){ // Part: 1:back 2:front + for(unsigned int iModule = 1; iModule <= modules_TID[iRing-1] ; iModule++) { // Module: 1,...,modules in ring + for(unsigned int iType = mod_type_TID[2*(iRing-1)]; iType <= mod_type_TID[2*(iRing-1)+1] ; iType++) { // Module Type: 0 (ss) 1-2 (ds stereo and rphi) + + myDetId = 0; + // detector + myDetId <<= 4; + myDetId |= iDetector; + // subdetector + myDetId <<= 3; + myDetId |= iSubDetector; + // not used + myDetId <<= 10; + myDetId |= 0; + // side + myDetId <<= 2; + myDetId |= iSide; + // disk number + myDetId <<= 2; + myDetId |= iDisk; + // ring number + myDetId <<= 2; + myDetId |= iRing; + // part + myDetId <<= 2; + myDetId |= iPart; + // module number + myDetId <<= 5; + myDetId |= iModule; + // module type + myDetId <<= 2; + myDetId |= iType; + // + std::bitset<32> binary_myDetId(myDetId); + Output << std::endl << std::endl; + Output << " ******** myDet Id = " << myDetId << " (" << binary_myDetId << ")" << std::endl; + // + unsigned int rawid = mapDetIdToGeometricDet[myDetId]->geographicalID().rawId(); + std::bitset<32> binary_detid(rawid); + GeometricDet::nav_type detNavType = mapDetIdToGeometricDet[myDetId]->navType(); + // + Output << " raw Id = " << rawid << " (" << binary_detid << ")" + << "\t nav type = " << printNavType(&detNavType.front(),detNavType.size()) << std::endl; + + // variables + fillModuleVariables(mapDetIdToGeometricDet[myDetId], polarRadius, phiRad, z); + side_z = z; + disk_z = z; + ring_R = polarRadius; + part_z = z; + module_phi = phiRad; + // + + Output << "\t R = " << polarRadius << "\t phi = " << phiRad << "\t z = " << z << std::endl; + + // Module Info + + std::string name = mapDetIdToGeometricDet[myDetId]->name().name(); + unsigned int theDisk = tTopo->tidWheel(rawid); + unsigned int theRing = tTopo->tidRing(rawid); + std::vector theModule = tTopo->tidModuleInfo(rawid); + std::string side; + std::string part; + side = (tTopo->tidSide(rawid) == 1 ) ? "-" : "+"; + part = (theModule[0] == 1 ) ? "back" : "front"; + Output << " TID" << side << "\t" << "Disk " << theDisk << " Ring " << theRing << " " << part + << "\t" << " module " << theModule[1] << "\t" << name << std::endl; + // + + // module: phi check + Output << "\t # "; + if( ( module_phi - module_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in module "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in module "; + iOK++; + } + Output << iModule-1 << " to " << iModule << " (" << module_phi_previous << " --> " << module_phi << ")" << std::endl; + // + } // type loop + + // + module_phi_previous = module_phi; + // + } // module loop + + // part: |z| check + Output << "\t ## "; + if( ( fabs(part_z) - fabs(part_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering (front/back) not respected in ring "; + iERROR++; + } else { + Output << "\t OK" << " |z| ordering (front/back) in ring "; + iOK++; + } + Output << iRing << " part " << iPart+1 << " to " << iPart << " (" << part_z_previous << " --> " << part_z << ")" << std::endl; + // + part_z_previous = part_z; + module_phi_previous = -M_PI; + // + } // part loop + + // ring: R check + Output << "\t ### "; + if( ( ring_R - ring_R_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR R ordering not respected in disk "; + iERROR++; + } else { + Output << "\t OK" << " R ordering in disk "; + iOK++; + } + Output << iDisk << " ring " << iRing-1 << " to " << iRing << " (" << ring_R_previous << " --> " << ring_R << ")" << std::endl; + // + ring_R_previous = ring_R; + part_z_previous = 0.0; + module_phi_previous = -M_PI; + // + } // ring loop + + // disk: |z| check + Output << "\t #### "; + if( ( fabs(disk_z) - fabs(disk_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering not respected in disk "; + iERROR++; + } else { + Output << "\t OK" << " |z| ordering in disk "; + iOK++; + } + Output << iDisk-1 << " to " << iDisk << " (" << disk_z_previous << " --> " << disk_z << ")" << std::endl; + // + disk_z_previous = disk_z; + ring_R_previous = 0.0; + part_z_previous = 0.0; + module_phi_previous = -M_PI; + // + } // disk loop + + // side: z check + Output << "\t ##### "; + if( ( side_z - side_z_previous ) > (0 + tolerance_space) ) { + Output << "\t ERROR z ordering (side -/+) not respected in TID side "; + iERROR++; + } else { + Output << "\t OK" << " z ordering (side -/+) in TID side "; + iOK++; + } + Output << iSide+1 << " to " << iSide << " (" << side_z_previous << " --> " << side_z << ")" << std::endl; + // + side_z_previous = side_z; + disk_z_previous = 0.0; + ring_R_previous = 0.0; + part_z_previous = 0.0; + module_phi_previous = -M_PI; + // + } // side loop + + break; + } + + // TOB + case 5: + { + // TOB loop + unsigned int rod_TOB[8] = { 42 , 48 , 54 , 60 , 66, 74 }; // number of rods per layer 1/6 + unsigned int mod_type_TOB[12] = { 1 , 2 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }; // first and last type for module type loop + unsigned int nLayers = 6; + unsigned int nModules = 6; + // debug variables + double layer_R = 0.0; + double layer_R_previous = 0.0; + double side_z = 0.0; + double side_z_previous = -10000.0; + double rod_phi = 0.0; + double rod_phi_previous = 0.0; + double module_z = 0.0; + double module_z_previous = 0.0; + // + for(unsigned int iLayer = 1; iLayer <= nLayers; iLayer++) { // Layer: 1,...,nLayers + for(unsigned int iSide = 1; iSide <= 2; iSide++){ // Side: 1:- 2:+ + for(unsigned int iRod = 1; iRod <= rod_TOB[iLayer-1] ; iRod++) { // Rod: 1,...,nRods + for(unsigned int iModule = 1; iModule <= nModules ; iModule++) { // Module: 1,...,nModules + for(unsigned int iType = mod_type_TOB[2*(iLayer-1)]; iType <= mod_type_TOB[2*(iLayer-1)+1] ; iType++) { // Module Type: 0 (ss) 1-2 (ds stereo and rphi) + + myDetId = 0; + // detector + myDetId <<= 4; + myDetId |= iDetector; + // subdetector + myDetId <<= 3; + myDetId |= iSubDetector; + // not used + myDetId <<= 8; + myDetId |= 0; + // layer + myDetId <<= 3; + myDetId |= iLayer; + // side + myDetId <<= 2; + myDetId |= iSide; + // rod number + myDetId <<= 7; + myDetId |= iRod; + // module number + myDetId <<= 3; + myDetId |= iModule; + // module type + myDetId <<= 2; + myDetId |= iType; + // + std::bitset<32> binary_myDetId(myDetId); + Output << std::endl << std::endl; + Output << " ******** myDet Id = " << myDetId << " (" << binary_myDetId << ")" << std::endl; + // + unsigned int rawid = mapDetIdToGeometricDet[myDetId]->geographicalID().rawId(); + std::bitset<32> binary_detid(rawid); + GeometricDet::nav_type detNavType = mapDetIdToGeometricDet[myDetId]->navType(); + // + Output << " raw Id = " << rawid << " (" << binary_detid << ")" + << "\t nav type = " << printNavType(&detNavType.front(),detNavType.size()) << std::endl; + + // variables + fillModuleVariables(mapDetIdToGeometricDet[myDetId], polarRadius, phiRad, z); + layer_R = polarRadius; + side_z = z; + rod_phi = phiRad; + module_z = z; + // + + Output << "\t R = " << polarRadius << "\t phi = " << phiRad << "\t z = " << z << std::endl; + + // Module Info + + std::string name = mapDetIdToGeometricDet[myDetId]->name().name(); + unsigned int theLayer = tTopo->tobLayer(rawid); + std::vector theRod = tTopo->tobRodInfo(rawid); + unsigned int theModule = tTopo->tobModule(rawid); + std::string side; + std::string part; + side = (theRod[0] == 1 ) ? "-" : "+"; + Output << " TOB" << side << "\t" << "Layer " << theLayer + << "\t" << "rod " << theRod[1] << " module " << theModule << "\t" << name << std::endl; + // + + // module: |z| check + Output << "\t # "; + if( ( fabs(module_z) - fabs(module_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering not respected in module "; + iERROR++; + } else { + Output << "\t OK" << " |z| ordering in module "; + iOK++; + } + Output << iModule-1 << " to " << iModule << " (" << module_z_previous << " --> " << module_z << ")" << std::endl; + // + } // type loop + + // + module_z_previous = module_z; + // + } // module loop + + // rod: phi check + Output << "\t ## "; + if( ( rod_phi - rod_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in rod "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in rod "; + iOK++; + } + Output << iRod-1 << " to " << iRod << " (" << rod_phi_previous << " --> " << rod_phi << ")" << std::endl; + // + rod_phi_previous = rod_phi; + module_z_previous = 0.0; + // + } // rod loop + + // side: z check + Output << "\t ### "; + if( ( side_z - side_z_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR z ordering (side -/+) not respected in layer "; + iERROR++; + } else { + Output << "\t OK" << " z ordering (side -/+) in layer "; + iOK++; + } + Output << iLayer << " side " << iSide-1 << " to " << iSide << " (" << side_z_previous << " --> " << side_z << ")" << std::endl; + // + side_z_previous = side_z; + rod_phi_previous = 0.0; + module_z_previous = 0.0; + // + } // side loop + + // layer: R check + Output << "\t #### "; + if( ( layer_R - layer_R_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR R ordering not respected from layer "; + iERROR++; + } else { + Output << "\t OK" << " R ordering in layer "; + iOK++; + } + Output << iLayer-1 << " to " << iLayer << " (" << layer_R_previous << " --> " << layer_R << ")" << std::endl; + // + layer_R_previous = layer_R; + side_z_previous = -10000.0; + rod_phi_previous = 0.0; + module_z_previous = 0.0; + // + } // layer loop + + break; + } + + // TEC + case 6: + { + + // TEC loop + unsigned int nWheels = 9; + unsigned int nPetals = 8; + unsigned int nRings = 7; + unsigned int first_ring_TEC[9] = { 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 4 }; // first ring of the wheel + unsigned int modules_ring_TEC[14] = { 1 , 2 , 1 , 2 , 2 , 3 , 3 , 4 , 3 , 2 , 3 , 4 , 5 , 5 }; // number of modules ring=1,...,nRings back/front + unsigned int mod_type_TEC[14] = { 1 , 2 , 1 , 2 , 0 , 0 , 0 , 0 , 1 , 2 , 0 , 0 , 0 , 0 }; // first and last type for module type loop (per ring) + // debug variables + double side_z = 0.0; + double side_z_previous = 10000.0; + double wheel_z = 0.0; + double wheel_z_previous = 0.0; + double part_z = 0.0; + double part_z_previous = 0.0; + double petal_phi = 0.0; + double petal_phi_previous = 0.0; + double ring_R = 0.0; + double ring_R_previous = 0.0; + double module_phi = 0.0; + double module_phi_previous = -M_PI; + // + for(unsigned int iSide = 2; iSide >= 1; iSide--){ // Side: 1:- 2:+ + switch (iSide) { + // TEC+ + case 2: + { + side_z = 0.0; + side_z_previous = 10000.0; + wheel_z = 0.0; + wheel_z_previous = 0.0; + part_z = 0.0; + part_z_previous = 0.0; + petal_phi = 0.0; + petal_phi_previous = 0.0; + ring_R = 0.0; + ring_R_previous = 0.0; + module_phi = 0.0; + module_phi_previous = -M_PI; + break; + } + // TEC- + case 1: + { + wheel_z = 0.0; + wheel_z_previous = 0.0; + part_z = 0.0; + part_z_previous = 0.0; + petal_phi = 0.0; + petal_phi_previous = 0.0; + ring_R = 0.0; + ring_R_previous = 0.0; + module_phi = 0.0; + module_phi_previous = 2*M_PI; + break; + } + default: + { + // do nothing + } + } + // + for(unsigned int iWheel = 1; iWheel <= nWheels; iWheel++) { // Wheel: 1,...,nWheels + for(int iPart = 2; iPart >= 1; iPart--){ // Part: 1:back 2:front + for(unsigned int iPetal = 1; iPetal <= nPetals; iPetal++) { // Petal: 1,...,nPetals + for(unsigned int iRing = first_ring_TEC[iWheel-1]; iRing <= nRings; iRing++){ // Ring: first,...,nRings + unsigned int nModules = modules_ring_TEC[2*(iRing-1)+(iPart-1)]; + for(unsigned int iModule = 1; iModule <= nModules; iModule++) { // Module: 1,...,modules in ring of petal + for(unsigned int iType = mod_type_TEC[2*(iRing-1)]; iType <= mod_type_TEC[2*(iRing-1)+1] ; iType++) { // Module Type: 0 (ss) 1-2 (ds stereo and rphi) + + myDetId = 0; + // detector + myDetId <<= 4; + myDetId |= iDetector; + // subdetector + myDetId <<= 3; + myDetId |= iSubDetector; + // not used + myDetId <<= 5; + myDetId |= 0; + // side + myDetId <<= 2; + myDetId |= iSide; + // wheel number + myDetId <<= 4; + myDetId |= iWheel; + // part + myDetId <<= 2; + myDetId |= iPart; + // petal number + myDetId <<= 4; + myDetId |= iPetal; + // ring number + myDetId <<= 3; + myDetId |= iRing; + // module number + myDetId <<= 3; + myDetId |= iModule; + // module type + myDetId <<= 2; + myDetId |= iType; + // + std::bitset<32> binary_myDetId(myDetId); + Output << std::endl << std::endl; + Output << " ******** myDet Id = " << myDetId << " (" << binary_myDetId << ")" << std::endl; + // + unsigned int rawid = mapDetIdToGeometricDet[myDetId]->geographicalID().rawId(); + std::bitset<32> binary_detid(rawid); + GeometricDet::nav_type detNavType = mapDetIdToGeometricDet[myDetId]->navType(); + // + Output << " raw Id = " << rawid << " (" << binary_detid << ")" + << "\t nav type = " << printNavType(&detNavType.front(),detNavType.size()) << std::endl; + + // variables + fillModuleVariables(mapDetIdToGeometricDet[myDetId], polarRadius, phiRad, z); + side_z = z; + wheel_z = z; + part_z = z; + switch (iSide) { + // TEC+ + case 2: + { + phiRad = phiRad; + break; + } + // TEC- + case 1: + { + phiRad = changePhiRange_From_ZeroTwoPi_To_MinusPiPlusPi(phiRad); + break; + } + default: + { + // do nothing + } + } + + // petal must be ordered inside [0,2PI) for TEC+, [PI,-PI) for TEC-, take the phi of the central module in a ring with (2n+1) modules + if( ( nModules%2 ) && ( iModule==(int)(nModules/2)+(nModules%2) ) ) { + switch (iSide) { + // TEC+ + case 2: + { + petal_phi = phiRad; + break; + } + // TEC- + case 1: + { + petal_phi = changePhiRange_From_MinusPiPlusPi_To_ZeroTwoPi(phiRad); + break; + } + default: + { + // do nothing + } + } + } + + ring_R = polarRadius; + // + // modules must be ordered inside petals [0,2PI)-->[-PI,PI) if the petal is near phi~0 TEC+ (petal number 1) + // modules must be ordered inside petals [PI,-PI)-->[2PI,0) if the petal is near phi~PI TEC- (petal number 5) + switch (iSide) { + // TEC+ + case 2: + { + if( iPetal == 1 ) { // it is the request of the petal at phi = 0, always the first + module_phi = changePhiRange_From_ZeroTwoPi_To_MinusPiPlusPi(phiRad); + } else { + module_phi = phiRad; + } + break; + } + // TEC- + case 1: + { + if( iPetal == 5 ) { // it is the request of the petal at phi = PI, always the fifth + module_phi = changePhiRange_From_MinusPiPlusPi_To_MinusTwoPiZero(phiRad); + } else { + module_phi = phiRad; + } + break; + } + default: + { + // do nothing + } + } + + // + + Output << "\t R = " << polarRadius << "\t phi = " << phiRad << "\t z = " << z << std::endl; + + // Module Info + + std::string name = mapDetIdToGeometricDet[myDetId]->name().name(); + unsigned int theWheel = tTopo->tecWheel(rawid); + unsigned int theModule = tTopo->tecModule(rawid); + std::vector thePetal = tTopo->tecPetalInfo(rawid); + unsigned int theRing = tTopo->tecRing(rawid); + std::string side; + std::string petal; + side = (tTopo->tecSide(rawid) == 1 ) ? "-" : "+"; + petal = (thePetal[0] == 1 ) ? "back" : "front"; + Output << " TEC" << side << "\t" << "Wheel " << theWheel << " Petal " << thePetal[1] << " " << petal << " Ring " << theRing << "\t" + << "\t" << " module " << theModule << "\t" << name << std::endl; + // + + // module: phi check + Output << "\t # "; + switch (iSide) { + // TEC+ + case 2: + { + if( ( module_phi - module_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in module "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in module "; + iOK++; + } + Output << iModule-1 << " to " << iModule << " (" << module_phi_previous << " --> " << module_phi << ")" << std::endl; + break; + } + // TEC- + case 1: + { + if( ( module_phi - module_phi_previous ) > (0 + tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in module "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in module "; + iOK++; + } + Output << iModule-1 << " to " << iModule << " (" << module_phi_previous << " --> " << module_phi << ")" << std::endl; + break; + } + default: + { + // do nothing + } + } + // + } // type loop + + // + module_phi_previous = module_phi; + // + } // module loop + + // ring: R check + Output << "\t ## "; + if( ( ring_R - ring_R_previous ) < (0 + tolerance_space) ) { + Output << "\t ERROR R ordering not respected in petal "; + iERROR++; + } else { + Output << "\t OK" << " R ordering in petal "; + iOK++; + } + Output << iPetal << " ring " << iRing-1 << " to " << iRing << " (" << ring_R_previous << " --> " << ring_R << ")" << std::endl; + // + switch (iSide) { + // TEC+ + case 2: + { + ring_R_previous = ring_R; + module_phi_previous = -M_PI; + break; + } + // TEC- + case 1: + { + ring_R_previous = ring_R; + module_phi_previous = 2*M_PI; + break; + } + default: + { + // do nothing + } + } + // + } // ring loop + + // petal: phi check + Output << "\t ### "; + switch (iSide) { + // TEC+ + case 2: + { + if( ( petal_phi - petal_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in petal "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in petal "; + iOK++; + } + Output << iPetal-1 << " to " << iPetal << " (" << petal_phi_previous << " --> " << petal_phi << ")" << std::endl; + // + petal_phi_previous = petal_phi; + ring_R_previous = 0.0; + module_phi_previous = -M_PI; + // + break; + } + // TEC- + case 1: + { + if( ( petal_phi - petal_phi_previous ) < (0 - tolerance_angle) ) { + Output << "\t ERROR phi ordering not respected in petal "; + iERROR++; + } else { + Output << "\t OK" << " phi ordering in petal "; + iOK++; + } + Output << iPetal-1 << " to " << iPetal << " (" << petal_phi_previous << " --> " << petal_phi << ")" << std::endl; + // + petal_phi_previous = petal_phi; + ring_R_previous = 0.0; + module_phi_previous = 2*M_PI; + // + break; + } + default: + { + // do nothing + } + } + // + } // petal loop + + // part: |z| check + Output << "\t #### "; + if( ( fabs(part_z) - fabs(part_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering (front/back) not respected in wheel "; + iERROR++; + } else { + Output << "\t OK" << " |z| (front/back) ordering in wheel "; + iOK++; + } + Output << iWheel << " part " << iPart+1 << " to " << iPart << " (" << part_z_previous << " --> " << part_z << ")" << std::endl; + // + switch (iSide) { + // TEC+ + case 2: + { + part_z_previous = part_z; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = -M_PI; + break; + } + // TEC- + case 1: + { + part_z_previous = part_z; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = 2*M_PI; + break; + } + default: + { + // do nothing + } + } + // + } // part loop + + // wheel: |z| check + Output << "\t ##### "; + if( ( fabs(wheel_z) - fabs(wheel_z_previous) ) < (0 + tolerance_space) ) { + Output << "\t ERROR |z| ordering not respected in wheel "; + iERROR++; + } else { + Output << "\t OK" << " |z| ordering in wheel "; + iOK++; + } + Output << iWheel-1 << " to " << iWheel << " (" << wheel_z_previous << " --> " << wheel_z << ")" << std::endl; + // + switch (iSide) { + // TEC+ + case 2: + { + wheel_z_previous = wheel_z; + part_z_previous = 0.0; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = -M_PI; + break; + } + // TEC- + case 1: + { + wheel_z_previous = wheel_z; + part_z_previous = 0.0; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = 2*M_PI; + break; + } + default: + { + // do nothing + } + } + // + } // wheel loop + + // side: z check + Output << "\t ###### "; + if( ( side_z - side_z_previous ) > (0 + tolerance_space) ) { + Output << "\t ERROR z ordering (side -/+) not respected in TEC side "; + iERROR++; + } else { + Output << "\t OK" << " z ordering (side -/+) in TEC side "; + iOK++; + } + Output << iSide+1 << " to " << iSide << " (" << side_z_previous << " --> " << side_z << ")" << std::endl; + // + switch (iSide) { + // TEC+ + case 2: + { + side_z_previous = side_z; + wheel_z_previous = 0.0; + part_z_previous = 0.0; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = -M_PI; + break; + } + // TEC- + case 1: + { + side_z_previous = side_z; + wheel_z_previous = 0.0; + part_z_previous = 0.0; + petal_phi_previous = 0.0; + ring_R_previous = 0.0; + module_phi_previous = 2*M_PI; + break; + } + default: + { + // do nothing + } + } + // + } // side loop + + break; + } + default: + Output << " WARNING no Silicon Strip subdetector, I got a " << iSubDetector << std::endl;; + } + + + } // subdetector loop + + // summary + unsigned int iChecks = iOK + iERROR; + Output << std::endl << std::endl; + Output << "-------------------------------------" << std::endl; + Output << " Module Numbering Check Summary " << std::endl; + Output << "-------------------------------------" << std::endl; + Output << " Number of checks: " << std::setw(6) << iChecks << std::endl; + Output << " OK: " << std::setw(6) << iOK + << " (" << std::fixed << std::setprecision(2) << ((double)iOK / (double)iChecks) * 100 << "%) " << std::endl; + Output << " ERRORS: " << std::setw(6) << iERROR + << " (" << std::fixed << std::setprecision(2) << ((double)iERROR / (double)iChecks) * 100 << "%) " << std::endl; + Output << "-------------------------------------" << std::endl; + +} + + +//define this as a plug-in +DEFINE_FWK_MODULE(ModuleNumbering); + diff --git a/Geometry/MTDNumberingBuilder/test/mtd_cfg.py b/Geometry/MTDNumberingBuilder/test/mtd_cfg.py new file mode 100644 index 0000000000000..c7f1c31c8b70d --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/mtd_cfg.py @@ -0,0 +1,20 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("GeometryTest") +# empty input service, fire 10 events +process.load("FWCore.MessageLogger.MessageLogger_cfi") + +process.load("Configuration.Geometry.GeometryExtended2023D24_cff") + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(1) +) +process.source = cms.Source("EmptySource") + +process.MTDGeometricTimingDetESModule = cms.ESProducer("MTDGeometricTimingDetESModule", + fromDDD = cms.bool(True)) + +process.prod = cms.EDAnalyzer("GeometricTimingDetAnalyzer") + +process.p1 = cms.Path(process.prod) + diff --git a/Geometry/MTDNumberingBuilder/test/trackerTopology_cfg.py b/Geometry/MTDNumberingBuilder/test/trackerTopology_cfg.py new file mode 100644 index 0000000000000..399e6ab85a6e8 --- /dev/null +++ b/Geometry/MTDNumberingBuilder/test/trackerTopology_cfg.py @@ -0,0 +1,17 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("NumberingTest") + +process.load("Configuration.Geometry.GeometryReco_cff") +process.load("Geometry.CMSCommonData.cmsExtendedGeometryXML_cfi") +process.trackerGeometry.applyAlignment = cms.bool(False) + +process.source = cms.Source("EmptySource") + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(1) +) + +process.prod = cms.EDAnalyzer("MTDTopologyAnalyzer"); + +process.p1 = cms.Path(process.prod) diff --git a/Geometry/Records/interface/BTLGeometryRcd.h b/Geometry/Records/interface/BTLGeometryRcd.h new file mode 100644 index 0000000000000..dce28de66d2cf --- /dev/null +++ b/Geometry/Records/interface/BTLGeometryRcd.h @@ -0,0 +1,6 @@ +#ifndef Geometry_BTLGeometryRcd_H +#define Geometry_BTLGeometryRcd_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +class BTLGeometryRcd : public edm::eventsetup::EventSetupRecordImplementation {}; +#endif diff --git a/Geometry/Records/interface/ETLGeometryRcd.h b/Geometry/Records/interface/ETLGeometryRcd.h new file mode 100644 index 0000000000000..a230ed63f759b --- /dev/null +++ b/Geometry/Records/interface/ETLGeometryRcd.h @@ -0,0 +1,6 @@ +#ifndef Geometry_ETLGeometryRcd_H +#define Geometry_ETLGeometryRcd_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +class ETLGeometryRcd : public edm::eventsetup::EventSetupRecordImplementation {}; +#endif diff --git a/Geometry/Records/interface/GlobalTrackingGeometryRecord.h b/Geometry/Records/interface/GlobalTrackingGeometryRecord.h index f0b908ab81506..1a1e4a317fab5 100644 --- a/Geometry/Records/interface/GlobalTrackingGeometryRecord.h +++ b/Geometry/Records/interface/GlobalTrackingGeometryRecord.h @@ -10,11 +10,12 @@ #include "FWCore/Framework/interface/EventSetupRecordImplementation.h" #include "FWCore/Framework/interface/DependentRecordImplementation.h" #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h" +#include "Geometry/Records/interface/MTDDigiGeometryRecord.h" #include "Geometry/Records/interface/MuonGeometryRecord.h" #include "boost/mpl/vector.hpp" -class GlobalTrackingGeometryRecord : public edm::eventsetup::DependentRecordImplementation > {}; +class GlobalTrackingGeometryRecord : public edm::eventsetup::DependentRecordImplementation > {}; #endif diff --git a/Geometry/Records/interface/IdealGeometryRecord.h b/Geometry/Records/interface/IdealGeometryRecord.h index 26e80a3ee7341..0334e13437f9b 100644 --- a/Geometry/Records/interface/IdealGeometryRecord.h +++ b/Geometry/Records/interface/IdealGeometryRecord.h @@ -21,10 +21,11 @@ #include "FWCore/Framework/interface/DependentRecordImplementation.h" #include "Geometry/Records/interface/GeometryFileRcd.h" #include "Geometry/Records/interface/PGeometricDetExtraRcd.h" +#include "Geometry/Records/interface/PGeometricTimingDetExtraRcd.h" #include "boost/mpl/vector.hpp" class IdealGeometryRecord : public edm::eventsetup::DependentRecordImplementation< - IdealGeometryRecord, boost::mpl::vector > { }; +IdealGeometryRecord, boost::mpl::vector > { }; #endif /* RECORDS_IDEALGEOMETRYRECORD_H */ diff --git a/Geometry/Records/interface/MTDDigiGeometryRecord.h b/Geometry/Records/interface/MTDDigiGeometryRecord.h new file mode 100644 index 0000000000000..8412529b6153f --- /dev/null +++ b/Geometry/Records/interface/MTDDigiGeometryRecord.h @@ -0,0 +1,25 @@ +#ifndef RECORDS_MTDDIGIGEOMETRYRECORD_H +#define RECORDS_MTDDIGIGEOMETRYRECORD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +#include "FWCore/Framework/interface/DependentRecordImplementation.h" +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentRcd.h" +#include "CondFormats/AlignmentRecord/interface/MTDAlignmentErrorExtendedRcd.h" +#include "CondFormats/AlignmentRecord/interface/MTDSurfaceDeformationRcd.h" +#include "CondFormats/AlignmentRecord/interface/GlobalPositionRcd.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/MTDTopologyRcd.h" +#include "Geometry/Records/interface/PMTDParametersRcd.h" +#include "boost/mpl/vector.hpp" + +class MTDDigiGeometryRecord : + public edm::eventsetup::DependentRecordImplementation > {}; + +#endif /* RECORDS_MTDDIGIGEOMETRYRECORD_H */ diff --git a/Geometry/Records/interface/MTDGeometryRecord.h b/Geometry/Records/interface/MTDGeometryRecord.h new file mode 100644 index 0000000000000..ecbd0b18b5e59 --- /dev/null +++ b/Geometry/Records/interface/MTDGeometryRecord.h @@ -0,0 +1,24 @@ +#ifndef RECORDS_MTDGEOMETRYRECORD_H +#define RECORDS_MTDGEOMETRYRECORD_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +#include "FWCore/Framework/interface/DependentRecordImplementation.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/PFastTimeRcd.h" +#include "Geometry/Records/interface/BTLGeometryRcd.h" +#include "Geometry/Records/interface/ETLGeometryRcd.h" +#include "CondFormats/AlignmentRecord/interface/GlobalPositionRcd.h" +#include "boost/mpl/vector.hpp" + +class MTDGeometryRecord : + public edm::eventsetup::DependentRecordImplementation< + MTDGeometryRecord, + boost::mpl::vector< + IdealGeometryRecord, + BTLGeometryRcd, + ETLGeometryRcd, + GlobalPositionRcd, + PFastTimeRcd > > {}; + +#endif /* RECORDS_MTDGEOMETRYRECORD_H */ + diff --git a/Geometry/Records/interface/MTDTopologyRcd.h b/Geometry/Records/interface/MTDTopologyRcd.h new file mode 100644 index 0000000000000..1fa74c29b54f3 --- /dev/null +++ b/Geometry/Records/interface/MTDTopologyRcd.h @@ -0,0 +1,14 @@ +#ifndef Geometry_Records_MTDTopologyRcd +#define Geometry_Records_MTDTopologyRcd + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +#include "FWCore/Framework/interface/DependentRecordImplementation.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "Geometry/Records/interface/PMTDParametersRcd.h" +#include "boost/mpl/vector.hpp" + +class MTDTopologyRcd : +public edm::eventsetup::DependentRecordImplementation > {}; + +#endif diff --git a/Geometry/Records/interface/PGeometricTimingDetExtraRcd.h b/Geometry/Records/interface/PGeometricTimingDetExtraRcd.h new file mode 100644 index 0000000000000..cae5f6651b0b6 --- /dev/null +++ b/Geometry/Records/interface/PGeometricTimingDetExtraRcd.h @@ -0,0 +1,6 @@ +#ifndef PGeometricTimingDetExtraRcd_H +#define PGeometricTimingDetExtraRcd_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +class PGeometricTimingDetExtraRcd : public edm::eventsetup::EventSetupRecordImplementation {}; +#endif diff --git a/Geometry/Records/interface/PMTDParametersRcd.h b/Geometry/Records/interface/PMTDParametersRcd.h new file mode 100644 index 0000000000000..1384f6da10bfe --- /dev/null +++ b/Geometry/Records/interface/PMTDParametersRcd.h @@ -0,0 +1,12 @@ +#ifndef PMTDParametersRcd_H +#define PMTDParametersRcd_H + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +#include "FWCore/Framework/interface/DependentRecordImplementation.h" +#include "Geometry/Records/interface/IdealGeometryRecord.h" +#include "boost/mpl/vector.hpp" + +class PMTDParametersRcd : public edm::eventsetup::DependentRecordImplementation > {}; + +#endif // PMTDParameters_H diff --git a/Geometry/Records/src/BTLGeometryRcd.cc b/Geometry/Records/src/BTLGeometryRcd.cc new file mode 100644 index 0000000000000..0ecac4ba5bfa4 --- /dev/null +++ b/Geometry/Records/src/BTLGeometryRcd.cc @@ -0,0 +1,5 @@ +//#include "CondFormats/DataRecord/interface/RecoIdealGeometryRcd.h" +#include "Geometry/Records/interface/BTLGeometryRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(BTLGeometryRcd); diff --git a/Geometry/Records/src/ETLGeometryRcd.cc b/Geometry/Records/src/ETLGeometryRcd.cc new file mode 100644 index 0000000000000..d2dfdd3f472e4 --- /dev/null +++ b/Geometry/Records/src/ETLGeometryRcd.cc @@ -0,0 +1,5 @@ +//#include "CondFormats/DataRecord/interface/RecoIdealGeometryRcd.h" +#include "Geometry/Records/interface/ETLGeometryRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(ETLGeometryRcd); diff --git a/Geometry/Records/src/MTDDigiGeometryRecord.cc b/Geometry/Records/src/MTDDigiGeometryRecord.cc new file mode 100644 index 0000000000000..f932e955b19b6 --- /dev/null +++ b/Geometry/Records/src/MTDDigiGeometryRecord.cc @@ -0,0 +1,15 @@ +// -*- C++ -*- +// +// Package: Records +// Class : IdealGeometryRecord +// +// Implementation: +// +// +// Author: +// Created: Mon Jul 25 11:05:09 EDT 2005 + +#include "Geometry/Records/interface/MTDDigiGeometryRecord.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(MTDDigiGeometryRecord); diff --git a/Geometry/Records/src/MTDGeometryRecord.cc b/Geometry/Records/src/MTDGeometryRecord.cc new file mode 100644 index 0000000000000..05aabdb062f74 --- /dev/null +++ b/Geometry/Records/src/MTDGeometryRecord.cc @@ -0,0 +1,4 @@ +#include "Geometry/Records/interface/MTDGeometryRecord.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(MTDGeometryRecord); diff --git a/Geometry/Records/src/MTDTopologyRcd.cc b/Geometry/Records/src/MTDTopologyRcd.cc new file mode 100644 index 0000000000000..c92073b3656c0 --- /dev/null +++ b/Geometry/Records/src/MTDTopologyRcd.cc @@ -0,0 +1,4 @@ +#include "Geometry/Records/interface/MTDTopologyRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(MTDTopologyRcd); diff --git a/Geometry/Records/src/PGeometricTimingDetExtraRcd.cc b/Geometry/Records/src/PGeometricTimingDetExtraRcd.cc new file mode 100644 index 0000000000000..0b092d4e6b001 --- /dev/null +++ b/Geometry/Records/src/PGeometricTimingDetExtraRcd.cc @@ -0,0 +1,4 @@ +#include "Geometry/Records/interface/PGeometricTimingDetExtraRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(PGeometricTimingDetExtraRcd); diff --git a/Geometry/Records/src/PMTDParametersRcd.cc b/Geometry/Records/src/PMTDParametersRcd.cc new file mode 100644 index 0000000000000..52e77e3cc9338 --- /dev/null +++ b/Geometry/Records/src/PMTDParametersRcd.cc @@ -0,0 +1,4 @@ +#include "Geometry/Records/interface/PMTDParametersRcd.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(PMTDParametersRcd); diff --git a/RecoMTD/DetLayers/BuildFile.xml b/RecoMTD/DetLayers/BuildFile.xml new file mode 100644 index 0000000000000..342425e4a6cbe --- /dev/null +++ b/RecoMTD/DetLayers/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h b/RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h new file mode 100644 index 0000000000000..58998115cadd9 --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h @@ -0,0 +1,82 @@ +#ifndef DetLayers_MTDDetLayerGeometry_h +#define DetLayers_MTDDetLayerGeometry_h + +/** \class MTDDetLayerGeometry + * + * Provide access to the DetLayers of mip timing detectors. + * + * \author L. Gray - FNAL + * + */ + +#include "DataFormats/DetId/interface/DetId.h" +#include "TrackingTools/DetLayers/interface/DetLayerGeometry.h" +#include +#include + +class DetLayer; + +class MTDDetLayerGeometry : public DetLayerGeometry{ + public: + + /// Constructor + MTDDetLayerGeometry(); + + friend class MTDDetLayerGeometryESProducer; + + /// Destructor + ~MTDDetLayerGeometry() override; + + /// return all barrel layers + const std::vector& allBarrelLayers() const; + + /// return all endcap layers + const std::vector& allEndcapLayers() const; + + /// return all endcap layers + const std::vector& allForwardLayers() const; + + /// return all endcap layers + const std::vector& allBackwardLayers() const; + + /// return the BTL DetLayers (barrel), inside-out + const std::vector& allBTLLayers() const; + + /// return the ETL DetLayers (endcap), -Z to +Z + const std::vector& allETLLayers() const; + + /// return all DetLayers (barrel + endcap), -Z to +Z + const std::vector& allLayers() const; + + /// return the DetLayer which correspond to a certain DetId + const DetLayer* idToLayer(const DetId& detId) const override; + + private: + /// Add ETL layers + /// etllayers.first=forward (+Z), etllayers.second=backward (-Z) + /// both vectors are ASSUMED to be sorted inside-out + void addETLLayers(const std::pair, std::vector >& etllayers); + + //. Add BTL layers; dtlayers is ASSUMED to be sorted inside-out + void addBTLLayers(const std::vector& btllayers); + + DetId makeDetLayerId(const DetLayer* detLayer) const; + + void sortLayers(); + + std::vector etlLayers_fw; + std::vector etlLayers_bk; + std::vector etlLayers_all; + + ////////////////////////////// + std::vector btlLayers; + std::vector allForward; + std::vector allBackward; + std::vector allEndcap; + std::vector allBarrel; + std::vector allDetLayers; + + std::map detLayersMap; +}; +#endif + diff --git a/RecoMTD/DetLayers/interface/MTDDetRing.h b/RecoMTD/DetLayers/interface/MTDDetRing.h new file mode 100644 index 0000000000000..55d36718836a5 --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDDetRing.h @@ -0,0 +1,56 @@ +#ifndef DetLayers_MTDDetRing_H +#define DetLayers_MTDDetRing_H + +/** \class MTDDetRing + * A ring of periodic, possibly overlapping vertical detectors. + * Designed for the endcap timing layer. + * + * \author L. Gray - FNAL + */ + +#include "TrackingTools/DetLayers/interface/ForwardDetRingOneZ.h" +#include "Utilities/BinningTools/interface/PeriodicBinFinderInPhi.h" + +class GeomDet; + +class MTDDetRing : public ForwardDetRingOneZ { + public: + + /// Construct from iterators on GeomDet* + MTDDetRing(std::vector::const_iterator first, + std::vector::const_iterator last); + + /// Construct from a vector of GeomDet* + MTDDetRing(const std::vector& dets); + + ~MTDDetRing() override; + + + // GeometricSearchDet interface + + const std::vector& components() const override; + + std::pair + compatible( const TrajectoryStateOnSurface& ts, const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + + private: + typedef PeriodicBinFinderInPhi BinFinderType; + BinFinderType theBinFinder; + + void init(); + +}; +#endif + diff --git a/RecoMTD/DetLayers/interface/MTDDetTray.h b/RecoMTD/DetLayers/interface/MTDDetTray.h new file mode 100644 index 0000000000000..bdb0e61c9a00e --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDDetTray.h @@ -0,0 +1,58 @@ +#ifndef DetLayers_MTDDetTray_H +#define DetLayers_MTDDetTray_H + +/** \class MTDDetTray + * A tray of aligned equal-sized non-overlapping detectors. + * Designed for barrel timing layer. + * + * \author L. Gray - FNAL + * + */ + +#include "TrackingTools/DetLayers/interface/DetRodOneR.h" +#include "TrackingTools/DetLayers/interface/PeriodicBinFinderInZ.h" +#include "Utilities/BinningTools/interface/GenericBinFinderInZ.h" +class GeomDet; + +class MTDDetTray : public DetRodOneR { + public: + + /// Construct from iterators on GeomDet* + MTDDetTray(std::vector::const_iterator first, + std::vector::const_iterator last); + + /// Construct from a std::vector of GeomDet* + MTDDetTray(const std::vector& dets); + + /// Destructor + ~MTDDetTray() override; + + + // GeometricSearchDet interface + + const std::vector& components() const override; + + std::pair + compatible( const TrajectoryStateOnSurface& ts, const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + + private: + typedef GenericBinFinderInZ BinFinderType; + BinFinderType theBinFinder; + + void init(); + +}; + +#endif diff --git a/RecoMTD/DetLayers/interface/MTDRingForwardDoubleLayer.h b/RecoMTD/DetLayers/interface/MTDRingForwardDoubleLayer.h new file mode 100644 index 0000000000000..3d30a01f4e881 --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDRingForwardDoubleLayer.h @@ -0,0 +1,80 @@ +#ifndef DetLayers_MTDRingForwardDoubleLayer_H +#define DetLayers_MTDRingForwardDoubleLayer_H + +/** \class MTDRingForwardDoubleLayer + * A plane composed two layers of disks. The Endcap Timing Layer. + * + * \author L. Gray + * + */ + +#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h" +#include "Utilities/BinningTools/interface/BaseBinFinder.h" +#include "RecoMTD/DetLayers/interface/MTDRingForwardLayer.h" + +class ForwardDetRing; +class ForwardDetRingBuilder; +class GeomDet; + +class MTDRingForwardDoubleLayer : public RingedForwardLayer { + + public: + + /// Constructor, takes ownership of pointers + MTDRingForwardDoubleLayer(const std::vector& frontRings, + const std::vector& backRings); + + ~MTDRingForwardDoubleLayer() override {} + + + // GeometricSearchDet interface + + const std::vector& basicComponents() const override {return theBasicComponents;} + + const std::vector& components() const override {return theComponents;} + + bool isInsideOut(const TrajectoryStateOnSurface&tsos) const; + + // tries closest layer first + std::pair + compatible( const TrajectoryStateOnSurface&, const Propagator&, + const MeasurementEstimator&) const override; + + std::vector + compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + + // DetLayer interface + SubDetector subDetector() const override {return theBackLayer.subDetector();} + + + // Extension of the interface + + /// Return the vector of rings. + virtual const std::vector& rings() const {return theRings;} + + bool isCrack(const GlobalPoint & gp) const; + + const MTDRingForwardLayer * frontLayer() const {return &theFrontLayer;} + const MTDRingForwardLayer * backLayer() const {return &theBackLayer;} + + void selfTest() const; + protected: + BoundDisk * computeSurface() override; + private: + MTDRingForwardLayer theFrontLayer; + MTDRingForwardLayer theBackLayer; + std::vector theRings; + std::vector theComponents; // duplication of the above + std::vector theBasicComponents; // All chambers + +}; +#endif + diff --git a/RecoMTD/DetLayers/interface/MTDRingForwardLayer.h b/RecoMTD/DetLayers/interface/MTDRingForwardLayer.h new file mode 100644 index 0000000000000..a03e4f09db9bf --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDRingForwardLayer.h @@ -0,0 +1,65 @@ +#ifndef DetLayers_MTDRingForwardLayer_H +#define DetLayers_MTDRingForwardLayer_H + +/** \class MTDRingForwardLayer + * A plane composed of disks (MTDRingForwardDisk). Represents ETL. + * + * \author L. Gray - FNAL + * + */ + +#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h" +#include "Utilities/BinningTools/interface/BaseBinFinder.h" + +class ForwardDetRing; +class ForwardDetRingBuilder; +class GeomDet; + +class MTDRingForwardLayer : public RingedForwardLayer { + + public: + + /// Constructor, takes ownership of pointers + MTDRingForwardLayer(const std::vector& rings); + + ~MTDRingForwardLayer() override; + + + // GeometricSearchDet interface + + const std::vector& basicComponents() const override {return theBasicComps;} + + const std::vector& components() const override; + + std::vector + compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + + + // DetLayer interface + SubDetector subDetector() const override; + + + // Extension of the interface + + /// Return the vector of rings. + virtual const std::vector& rings() const {return theRings;} + + + private: + std::vector theRings; + std::vector theComponents; // duplication of the above + std::vector theBasicComps; // All chambers + BaseBinFinder * theBinFinder; + bool isOverlapping; + +}; +#endif + diff --git a/RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h b/RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h new file mode 100644 index 0000000000000..1bc9dce8fe689 --- /dev/null +++ b/RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h @@ -0,0 +1,63 @@ +#ifndef DetLayers_MTDTrayBarrelLayer_H +#define DetLayers_MTDTrayBarrelLayer_H + +/** \class MTDTrayBarrelLayer + * A cylinder composed of half-trays. Represents Barrel Timing Layer. + * + * \author L. Gray - FNAL + * + */ +#include "TrackingTools/DetLayers/interface/RodBarrelLayer.h" +#include "Utilities/BinningTools/interface/BaseBinFinder.h" + +class DetRod; +class DetRodBuilder; +class GeomDet; + +class MTDTrayBarrelLayer : public RodBarrelLayer { +public: + + /// Constructor, takes ownership of pointers + MTDTrayBarrelLayer(std::vector& rods); + + ~MTDTrayBarrelLayer() override; + + // GeometricSearchDet interface + + const std::vector& basicComponents() const override {return theBasicComps;} + + const std::vector& components() const override; + + std::vector + compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + std::vector + groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const override; + + + // DetLayer interface + SubDetector subDetector() const override; + + // Extension of the interface + + /// Return the vector of rods. + virtual const std::vector& rods() const {return theRods;} + + +private: + + float xError(const TrajectoryStateOnSurface& tsos, + const MeasurementEstimator& est) const; + + std::vector theRods; + std::vector theComponents; // duplication of the above + std::vector theBasicComps; // All chambers + BaseBinFinder * theBinFinder; + bool isOverlapping; +}; + +#endif diff --git a/RecoMTD/DetLayers/plugins/BuildFile.xml b/RecoMTD/DetLayers/plugins/BuildFile.xml new file mode 100644 index 0000000000000..8b68508c8f419 --- /dev/null +++ b/RecoMTD/DetLayers/plugins/BuildFile.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.cc b/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.cc new file mode 100644 index 0000000000000..b673d5f4dbfb1 --- /dev/null +++ b/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.cc @@ -0,0 +1,56 @@ +/** \file + * + * \author L. Gray - FNAL + * + */ + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +using namespace edm; + +MTDDetLayerGeometryESProducer::MTDDetLayerGeometryESProducer(const edm::ParameterSet & p){ + setWhatProduced(this); +} + + +MTDDetLayerGeometryESProducer::~MTDDetLayerGeometryESProducer(){} + + +std::shared_ptr +MTDDetLayerGeometryESProducer::produce(const MTDRecoGeometryRecord & record) { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDDetLayerGeometryESProducer"; + auto mtdDetLayerGeometry = std::make_shared(); + + edm::ESHandle mtd; + record.getRecord().get(mtd); + if (mtd.isValid()) { + // Build BTL layers + mtdDetLayerGeometry->addBTLLayers(BTLDetLayerGeometryBuilder::buildLayers(*mtd)); + // Build ETL layers + mtdDetLayerGeometry->addETLLayers(ETLDetLayerGeometryBuilder::buildLayers(*mtd)); + } else { + LogInfo(metname) << "No MTD geometry is available."; + } + + // Sort layers properly + mtdDetLayerGeometry->sortLayers(); + + return mtdDetLayerGeometry; +} diff --git a/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.h b/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.h new file mode 100644 index 0000000000000..d93c5b01ce1e6 --- /dev/null +++ b/RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.h @@ -0,0 +1,33 @@ +#ifndef RecoMTD_DetLayers_MTDDetLayerGeometryESProducer_h +#define RecoMTD_DetLayers_MTDDetLayerGeometryESProducer_h + +/** \class MTDDetLayerGeometryESProducer + * + * ESProducer for MTDDetLayerGeometry in RecoMTD/DetLayers + * + * \author L. Gray - FNAL + */ + +#include +#include +#include +#include +#include + + +class MTDDetLayerGeometryESProducer: public edm::ESProducer{ + public: + /// Constructor + MTDDetLayerGeometryESProducer(const edm::ParameterSet & p); + + /// Destructor + ~MTDDetLayerGeometryESProducer() override; + + /// Produce MuonDeLayerGeometry. + std::shared_ptr produce(const MTDRecoGeometryRecord & record); + + private: +}; + + +#endif diff --git a/RecoMTD/DetLayers/plugins/SealModule.cc b/RecoMTD/DetLayers/plugins/SealModule.cc new file mode 100644 index 0000000000000..980c733d7f741 --- /dev/null +++ b/RecoMTD/DetLayers/plugins/SealModule.cc @@ -0,0 +1,6 @@ +#include "RecoMTD/DetLayers/plugins/MTDDetLayerGeometryESProducer.h" +#include "FWCore/Framework/interface/ModuleFactory.h" + +#include "FWCore/Utilities/interface/typelookup.h" + +DEFINE_FWK_EVENTSETUP_MODULE(MTDDetLayerGeometryESProducer); diff --git a/RecoMTD/DetLayers/python/mtdDetLayerGeometry_cfi.py b/RecoMTD/DetLayers/python/mtdDetLayerGeometry_cfi.py new file mode 100644 index 0000000000000..9bde6d9b7dfbb --- /dev/null +++ b/RecoMTD/DetLayers/python/mtdDetLayerGeometry_cfi.py @@ -0,0 +1,9 @@ +import FWCore.ParameterSet.Config as cms + +# +# This cfi should be included to build the muon DetLayers. +# +mtdDetLayerGeometry = cms.ESProducer("MTDDetLayerGeometryESProducer") + + + diff --git a/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.cc b/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.cc new file mode 100644 index 0000000000000..b268be3a09c2d --- /dev/null +++ b/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.cc @@ -0,0 +1,69 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +using namespace std; + +BTLDetLayerGeometryBuilder::BTLDetLayerGeometryBuilder() { +} + +BTLDetLayerGeometryBuilder::~BTLDetLayerGeometryBuilder() { +} + +vector +BTLDetLayerGeometryBuilder::buildLayers(const MTDGeometry& geo) { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|BTLDetLayerGeometryBuilder"; + + vector detlayers; + vector result; + + vector btlDetTrays; + + for(unsigned tray = BTLDetId::MIN_ROD; tray <= BTLDetId::HALF_ROD; ++tray) { + + vector geomDets; + for(unsigned module = 1; module <= BTLDetId::kModulesPerROD; ++module) { + for(unsigned side = 0; side <= 1; ++side) { + const GeomDet* geomDet = geo.idToDet(BTLDetId(side, tray, module, 0, 1)); + if (geomDet != nullptr) { + geomDets.push_back(geomDet); + LogTrace(metname) + << "get BTL module " + << std::hex << BTLDetId(side, tray, module, 0, 1).rawId() << std::dec + << " at R=" << geomDet->position().perp() + << ", phi=" << geomDet->position().phi(); + } + } + } + + if (!geomDets.empty()) { + precomputed_value_sort(geomDets.begin(), geomDets.end(), geomsort::DetZ()); + btlDetTrays.push_back(new MTDDetTray(geomDets)); + LogTrace(metname) << " New BTLDetTray with " << geomDets.size() + << " modules at R=" << btlDetTrays.back()->position().perp() + << ", phi=" << btlDetTrays.back()->position().phi() << std::endl; + } + } + + precomputed_value_sort(btlDetTrays.begin(), btlDetTrays.end(), geomsort::ExtractPhi()); + result.push_back(new MTDTrayBarrelLayer(btlDetTrays)); + LogDebug(metname) + << "BTLDetLayerGeometryBuilder: "<< " New MTDTrayBarrelLayer with " << btlDetTrays.size() + << " rods, at R " << result.back()->specificSurface().radius(); + + for(vector::const_iterator it = result.begin(); it != result.end(); it++) + detlayers.push_back((DetLayer*)(*it)); + + return detlayers; +} diff --git a/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.h b/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.h new file mode 100644 index 0000000000000..48aa3b0c26d1c --- /dev/null +++ b/RecoMTD/DetLayers/src/BTLDetLayerGeometryBuilder.h @@ -0,0 +1,30 @@ +#ifndef BTLDetLayerGeometryBuilder_h +#define BTLDetLayerGeometryBuilder_h + +/** \class BTLDetLayerGeometryBuilder + * + * Build the BTL DetLayers. + * + * \author L. Gray - FNAL + */ + +#include +#include + +class DetLayer; + +class BTLDetLayerGeometryBuilder { + public: + /// Constructor + BTLDetLayerGeometryBuilder(); + + /// Destructor + virtual ~BTLDetLayerGeometryBuilder(); + + /// Operations + static std::vector buildLayers(const MTDGeometry& geo); + private: + +}; +#endif + diff --git a/RecoMTD/DetLayers/src/ES_MTDDetLayerGeometry.cc b/RecoMTD/DetLayers/src/ES_MTDDetLayerGeometry.cc new file mode 100644 index 0000000000000..92a4ac8d1688d --- /dev/null +++ b/RecoMTD/DetLayers/src/ES_MTDDetLayerGeometry.cc @@ -0,0 +1,5 @@ +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" + +#include "FWCore/Utilities/interface/typelookup.h" + +TYPELOOKUP_DATA_REG(MTDDetLayerGeometry); diff --git a/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.cc b/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.cc new file mode 100644 index 0000000000000..e9b70b0aacf4d --- /dev/null +++ b/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.cc @@ -0,0 +1,122 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +using namespace std; + +pair, vector > +ETLDetLayerGeometryBuilder::buildLayers(const MTDGeometry& geo) { + + vector result[2]; // one for each endcap + + for(unsigned endcap=0; endcap<2; ++endcap) { + // there is only one layer for ETL right now, maybe more later + for(unsigned layer = 0; layer <= 0; ++layer) { + vector rings; + for(unsigned ring = 1; ring <= 12; ++ring) { + rings.push_back(ring); + } + MTDRingForwardDoubleLayer* thelayer = buildLayer(endcap, layer, rings, geo); + if (thelayer) result[endcap].push_back(thelayer); + } + } + pair, vector > res_pair(result[0], result[1]); + return res_pair; +} + +MTDRingForwardDoubleLayer* ETLDetLayerGeometryBuilder::buildLayer(int endcap, + int layer, + vector& rings, + const MTDGeometry& geo) { + const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|ETLDetLayerGeometryBuilder"; + MTDRingForwardDoubleLayer* result=nullptr; + + vector frontRings, backRings; + + for(unsigned ring : rings ) { + vector frontGeomDets, backGeomDets; + for(unsigned module = 1; module <= ETLDetId::kETLmoduleMask; ++module) { + ETLDetId detId(endcap, ring, module,0); + const GeomDet* geomDet = geo.idToDet(detId); + // we sometimes loop over more chambers than there are in ring + bool isInFront = isFront(layer, ring, module); + if(geomDet != nullptr) + { + if(isInFront) + { + frontGeomDets.push_back(geomDet); + } + else + { + backGeomDets.push_back(geomDet); + } + LogTrace(metname) + << "get ETL module " + << std::hex << ETLDetId(endcap, layer, ring, module).rawId() << std::dec + << " at R=" << geomDet->position().perp() + << ", phi=" << geomDet->position().phi() + << ", z= " << geomDet->position().z() + << " isFront? " << isInFront << std::endl; + } + } + + if(!backGeomDets.empty()) + { + backRings.push_back(makeDetRing(backGeomDets)); + } + + if(!frontGeomDets.empty()) + { + frontRings.push_back(makeDetRing(frontGeomDets)); + assert(!backGeomDets.empty()); + float frontz = frontRings[0]->position().z(); + float backz = backRings[0]->position().z(); + assert(fabs(frontz) < fabs(backz)); + } + } + + // How should they be sorted? + // precomputed_value_sort(muDetRods.begin(), muDetRods.end(), geomsort::ExtractZ()); + result = new MTDRingForwardDoubleLayer(frontRings, backRings); + LogTrace(metname) + << "New MTDRingForwardLayer with " << frontRings.size() + << " and " << backRings.size() + << " rings, at Z " << result->position().z() + << " R1: " << result->specificSurface().innerRadius() + << " R2: " << result->specificSurface().outerRadius() << std::endl; + return result; +} + + +bool ETLDetLayerGeometryBuilder::isFront(int layer, int ring, int module) +{ + return (module+1)%2; +} + + + +MTDDetRing * ETLDetLayerGeometryBuilder::makeDetRing(vector & geomDets) +{ + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|ETLDetLayerGeometryBuilder"; + + + precomputed_value_sort(geomDets.begin(), geomDets.end(), geomsort::DetPhi()); + MTDDetRing * result = new MTDDetRing(geomDets); + LogTrace(metname) + << "New MTDDetRing with " << geomDets.size() + << " chambers at z="<< result->position().z() + << " R1: " << result->specificSurface().innerRadius() + << " R2: " << result->specificSurface().outerRadius() << std::endl;; + return result; +} + diff --git a/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.h b/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.h new file mode 100644 index 0000000000000..0e51878328da5 --- /dev/null +++ b/RecoMTD/DetLayers/src/ETLDetLayerGeometryBuilder.h @@ -0,0 +1,37 @@ +#ifndef ETLDetLayerGeometryBuilder_h +#define ETLDetLayerGeometryBuilder_h + +/** \class ETLDetLayerGeometryBuilder + * + * Build the ETL DetLayers. + * + * \author L. Gray - FNAL + */ + +#include +#include + +class DetLayer; +class MTDRingForwardDoubleLayer; +class MTDDetRing; + +class ETLDetLayerGeometryBuilder { + public: + + /// return.first=forward (+Z), return.second=backward (-Z) + /// both vectors are sorted inside-out + static std::pair, std::vector > buildLayers(const MTDGeometry& geo); + private: + // Disable constructor - only static access is allowed. + ETLDetLayerGeometryBuilder(){} + + static MTDRingForwardDoubleLayer* buildLayer(int endcap, + int layer, + std::vector& rings, + const MTDGeometry& geo); + + static MTDDetRing * makeDetRing(std::vector & geomDets); + static bool isFront(int layer, int ring, int module); +}; +#endif + diff --git a/RecoMTD/DetLayers/src/GeneralBinFinderInPhi.h b/RecoMTD/DetLayers/src/GeneralBinFinderInPhi.h new file mode 100644 index 0000000000000..1573ce2fb9953 --- /dev/null +++ b/RecoMTD/DetLayers/src/GeneralBinFinderInPhi.h @@ -0,0 +1 @@ +#include "TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h" diff --git a/RecoMTD/DetLayers/src/GeneralBinFinderInR.h b/RecoMTD/DetLayers/src/GeneralBinFinderInR.h new file mode 100644 index 0000000000000..12ca216def555 --- /dev/null +++ b/RecoMTD/DetLayers/src/GeneralBinFinderInR.h @@ -0,0 +1 @@ +#include "TrackingTools/DetLayers/interface/GeneralBinFinderInR.h" diff --git a/RecoMTD/DetLayers/src/MTDDetLayerGeometry.cc b/RecoMTD/DetLayers/src/MTDDetLayerGeometry.cc new file mode 100644 index 0000000000000..5d94d78710009 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDDetLayerGeometry.cc @@ -0,0 +1,180 @@ +/** \file + * + * \author L. Gray - FNAL + * + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace geomsort; + +MTDDetLayerGeometry::MTDDetLayerGeometry() {} + +MTDDetLayerGeometry::~MTDDetLayerGeometry(){ +} + +void MTDDetLayerGeometry::addETLLayers(const pair, vector >& etllayers) { + + for(auto const it : etllayers.first) { + etlLayers_fw.push_back(it); + allForward.push_back(it); + + detLayersMap[ makeDetLayerId(it) ] = it; + } + + for(auto const it: etllayers.second) { + etlLayers_bk.push_back(it); + allBackward.push_back(it); + + detLayersMap[ makeDetLayerId(it) ] = it; + } +} + +void MTDDetLayerGeometry::addBTLLayers(const vector& dtlayers) { + + for(auto const it : dtlayers) { + btlLayers.push_back(it); + allBarrel.push_back(it); + + detLayersMap[ makeDetLayerId(it) ] = it; + } +} + +DetId MTDDetLayerGeometry::makeDetLayerId(const DetLayer* detLayer) const{ + + if(detLayer->subDetector() == GeomDetEnumerators::TimingEndcap) { + ETLDetId id( detLayer->basicComponents().front()->geographicalId().rawId() ) ; + return ETLDetId(id.mtdSide(),0,0,0); + } + else if(detLayer->subDetector() == GeomDetEnumerators::TimingBarrel) { + BTLDetId id( detLayer->basicComponents().front()->geographicalId().rawId() ) ; + return BTLDetId(id.mtdSide(),0,0,0,0); + } + else throw cms::Exception("InvalidModuleIdentification"); // << detLayer->module(); +} + +const vector& +MTDDetLayerGeometry::allBarrelLayers() const { + return allBarrel; +} + +const vector& +MTDDetLayerGeometry::allEndcapLayers() const { + return allEndcap; +} + +const vector& +MTDDetLayerGeometry::allForwardLayers() const { + return allForward; +} + +const vector& +MTDDetLayerGeometry::allBackwardLayers() const { + return allBackward; +} + +const vector& +MTDDetLayerGeometry::allBTLLayers() const { + return btlLayers; +} + +const vector& +MTDDetLayerGeometry::allETLLayers() const { + return etlLayers_all; +} + +const vector& +MTDDetLayerGeometry::allLayers() const { + return allDetLayers; +} + + +//////////////////////////////////////////////////// + +const DetLayer* MTDDetLayerGeometry::idToLayer(const DetId &id) const{ + + DetId idout; + MTDDetId detId; + + if(detId.mtdSubDetector() == 2){ // 2 is ETL + ETLDetId etlId( detId.rawId() ); + idout = ETLDetId(etlId.mtdSide(),0,0,0); + } + else if (detId.mtdSubDetector() == 1){ // 1 is BTL + BTLDetId btlId( detId.rawId() ); + idout = BTLDetId(btlId.mtdSide(),0,0,0,0); + } + else throw cms::Exception("InvalidSubdetId")<< detId.subdetId(); + + std::map::const_iterator layer = detLayersMap.find(idout); + if (layer == detLayersMap.end()) return nullptr; + return layer->second; +} + + +// Quick way to sort barrel det layers by increasing R, +// do not abuse! +#include +struct ExtractBarrelDetLayerR { + typedef Surface::Scalar result_type; + result_type operator()(const DetLayer* p) const { + const BarrelDetLayer * bdl = dynamic_cast(p); + if (bdl) return bdl->specificSurface().radius(); + else return -1.; + } +}; + +void MTDDetLayerGeometry::sortLayers() { + + // The following are filled inside-out, no need to re-sort + // precomputed_value_sort(dtLayers.begin(), dtLayers.end(),ExtractR()); + // precomputed_value_sort(cscLayers_fw.begin(), cscLayers_fw.end(),ExtractAbsZ()); + // precomputed_value_sort(cscLayers_bk.begin(), cscLayers_bk.end(),ExtractAbsZ()); + // precomputed_value_sort(rpcLayers_fw.begin(), rpcLayers_fw.end(),ExtractAbsZ()); + // precomputed_value_sort(rpcLayers_bk.begin(), rpcLayers_bk.end(),ExtractAbsZ()); + // precomputed_value_sort(rpcLayers_barrel.begin(), rpcLayers_barrel.end(), ExtractR()); + + // Sort these inside-out + precomputed_value_sort(allBarrel.begin(), allBarrel.end(), ExtractBarrelDetLayerR()); + precomputed_value_sort(allBackward.begin(), allBackward.end(), ExtractAbsZ()); + precomputed_value_sort(allForward.begin(), allForward.end(), ExtractAbsZ()); + + // Build more complicated vectors with correct sorting + + //etlLayers_all: from -Z to +Z + etlLayers_all.reserve(etlLayers_bk.size()+etlLayers_fw.size()); + std::copy(etlLayers_bk.begin(),etlLayers_bk.end(),back_inserter(etlLayers_all)); + std::reverse(etlLayers_all.begin(),etlLayers_all.end()); + std::copy(etlLayers_fw.begin(),etlLayers_fw.end(),back_inserter(etlLayers_all)); + + // allEndcap: order is all bw, all fw + allEndcap.reserve(allBackward.size()+allForward.size()); + std::copy(allBackward.begin(),allBackward.end(),back_inserter(allEndcap)); + std::reverse(allEndcap.begin(),allEndcap.end()); + std::copy(allForward.begin(),allForward.end(),back_inserter(allEndcap)); + + // allDetLayers: order is all bw, all barrel, all fw + allDetLayers.reserve(allBackward.size()+allBarrel.size()+allForward.size()); + std::copy(allBackward.begin(),allBackward.end(),back_inserter(allDetLayers)); + std::reverse(allDetLayers.begin(),allDetLayers.end()); + std::copy(allBarrel.begin(),allBarrel.end(),back_inserter(allDetLayers)); + std::copy(allForward.begin(),allForward.end(),back_inserter(allDetLayers)); + + // number layers + int sq=0; + for (auto l : allDetLayers) + (*const_cast(l)).setSeqNum(sq++); + + +} diff --git a/RecoMTD/DetLayers/src/MTDDetRing.cc b/RecoMTD/DetLayers/src/MTDDetRing.cc new file mode 100644 index 0000000000000..dbb27507c9851 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDDetRing.cc @@ -0,0 +1,189 @@ +/** \file + * + * \author L. Gray - FNAL + */ + +#include "RecoMTD/DetLayers/interface/MTDDetRing.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "TrackingTools/GeomPropagators/interface/Propagator.h" +#include "TrackingTools/DetLayers/interface/MeasurementEstimator.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include +#include + +using namespace std; + +MTDDetRing::MTDDetRing(vector::const_iterator first, + vector::const_iterator last) : + ForwardDetRingOneZ(first,last) +{ + init(); +} + + +MTDDetRing::MTDDetRing(const vector& vdets) : + ForwardDetRingOneZ(vdets) +{ + init(); +} + + +void MTDDetRing::init() +{ + theBinFinder = BinFinderType(basicComponents().front()->position().phi(), + basicComponents().size()); +} + +MTDDetRing::~MTDDetRing(){} + + +const vector& +MTDDetRing::components() const { + // FIXME dummy impl. + edm::LogError("MTDDetRing") << "temporary dummy implementation of MTDDetRing::components()!!" << endl; + static const vector result; + return result; +} + + +pair +MTDDetRing::compatible(const TrajectoryStateOnSurface& ts, const Propagator& prop, + const MeasurementEstimator& est) const { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDDetRing"; + TrajectoryStateOnSurface ms = prop.propagate(ts,specificSurface()); + + LogTrace(metname) << "MTDDetRing::compatible, Surface at Z: " + << specificSurface().position().z() + << " R1: " << specificSurface().innerRadius() + << " R2: " << specificSurface().outerRadius() + << " TS at Z,R: " << ts.globalPosition().z() << "," + << ts.globalPosition().perp(); + if (ms.isValid()) { + LogTrace(metname) << " DEST at Z,R: " << ms.globalPosition().z() << "," + << ms.globalPosition().perp() + << " local Z: " << ms.localPosition().z() << endl; + } + else + LogTrace(metname) << " DEST: not valid" < +MTDDetRing::compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDDetRing"; + + LogTrace(metname) << "MTDDetRing::compatibleDets, Surface at Z: " + << surface().position().z() + << " R1: " << specificSurface().innerRadius() + << " R2: " << specificSurface().outerRadius() + << " TS at Z,R: " << startingState.globalPosition().z() << "," + << startingState.globalPosition().perp() << " DetRing pos." << position(); + + vector result; + + // Propagate and check that the result is within bounds + pair compat = + compatible(startingState, prop, est); + if (!compat.first) { + LogTrace(metname) << " MTDDetRing::compatibleDets: not compatible" + << " (should not have been selected!)"; + return result; + } + + // Find the most probable destination component + TrajectoryStateOnSurface& tsos = compat.second; + GlobalPoint startPos = tsos.globalPosition(); + int closest = theBinFinder.binIndex(startPos.phi()); + const vector dets = basicComponents(); + LogTrace(metname) << " MTDDetRing::compatibleDets, closest det: " << closest + << " Phi: " << dets[closest]->surface().position().phi() + << " impactPhi " << startPos.phi(); + + // Add this detector, if it is compatible + // NOTE: add performs a null propagation + add(closest, result, tsos, prop, est); + +#ifdef EDM_ML_DEBUG + int nclosest = result.size(); int nnextdet=0; // MDEBUG counters +#endif + + // Try the neighbors on each side until no more compatible. + float dphi=0; + if (!result.empty()) { // If closest is not compatible the next cannot be either + float nSigmas = 3.; + if (result.back().second.hasError()) { + dphi = nSigmas* + atan(sqrt(result.back().second.localError().positionError().xx())/ + result.back().second.globalPosition().perp()); + } + } else { + LogTrace(metname) << " MTDDetRing::compatibleDets, closest not compatible!"; + //FIXME: if closest is not compatible the next cannot be either + } + + for (int idet=closest+1; idet < closest+int(dets.size())/4+1; idet++){ + // FIXME: should use dphi to decide if det must be queried. + // Right now query until not compatible. + int idetp = theBinFinder.binIndex(idet); + { + LogTrace(metname) << " next det:" << idetp + << " at Z: " << dets[idetp]->position().z() + << " phi: " << dets[idetp]->position().phi() + << " FTS phi " << startPos.phi() + << " max dphi " << dphi; +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + if ( !add(idetp, result, tsos, prop, est)) break; + } + } + + for (int idet=closest-1; idet > closest-int(dets.size())/4-1; idet--){ + // FIXME: should use dphi to decide if det must be queried. + // Right now query until not compatible. + int idetp = theBinFinder.binIndex(idet); + { + LogTrace(metname) << " previous det:" << idetp << " " << idet << " " << closest-dets.size()/4-1 + << " at Z: " << dets[idetp]->position().z() + << " phi: " << dets[idetp]->position().phi() + << " FTS phi " << startPos.phi() + << " max dphi" << dphi; +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + if ( !add(idetp, result, tsos, prop, est)) break; + } + } + +#ifdef EDM_ML_DEBUG + LogTrace(metname) << " MTDDetRing::compatibleDets, size: " << result.size() + << " on closest: " << nclosest << " # checked dets: " << nnextdet+1; +#endif + + if (result.empty()) { + LogTrace(metname) << " ***Ring not compatible,should have been discarded before!!!"; + } + + return result; +} + + +vector +MTDDetRing::groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + // FIXME should be implemented to allow returning overlapping chambers + // as separate groups! + cout << "dummy implementation of MTDDetRod::groupedCompatibleDets()" << endl; + vector result; + return result; +} diff --git a/RecoMTD/DetLayers/src/MTDDetTray.cc b/RecoMTD/DetLayers/src/MTDDetTray.cc new file mode 100644 index 0000000000000..c45600c7d1637 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDDetTray.cc @@ -0,0 +1,158 @@ +/** \file + * + * \author L. Gray - FNAL + */ + +#include "RecoMTD/DetLayers/interface/MTDDetTray.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "TrackingTools/GeomPropagators/interface/Propagator.h" +#include "TrackingTools/DetLayers/interface/MeasurementEstimator.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include + +using namespace std; + + +MTDDetTray::MTDDetTray(vector::const_iterator first, + vector::const_iterator last) + : DetRodOneR(first,last) { + init(); +} + +MTDDetTray::MTDDetTray(const vector& vdets) + : DetRodOneR(vdets) { + init(); +} + + +void MTDDetTray::init() { + theBinFinder = BinFinderType(basicComponents().begin(), basicComponents().end()); +} + + +MTDDetTray::~MTDDetTray(){} + +const vector& +MTDDetTray::components() const { + + // FIXME dummy impl. + edm::LogError("MTDDetTray") << "temporary dummy implementation of MTDDetTray::components()!!" << endl; + static const vector result; + return result; +} + +pair +MTDDetTray::compatible(const TrajectoryStateOnSurface& ts, const Propagator& prop, + const MeasurementEstimator& est) const { + + TrajectoryStateOnSurface ms = prop.propagate(ts,specificSurface()); + if (ms.isValid()) return make_pair(est.estimate(ms, specificSurface()) != 0, ms); + else return make_pair(false, ms); +} + + +vector +MTDDetTray::compatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDDetTray"; + + LogTrace(metname) << "MTDDetTray::compatibleDets, Surface at R,phi: " + << surface().position().perp() << "," + << surface().position().phi() << " DetRod pos."; + // FIXME << " TS at R,phi: " << startingState.position().perp() << "," + // << startingState.position().phi() + + + vector result; + + // Propagate and check that the result is within bounds + pair compat = + compatible(startingState, prop, est); + + if (!compat.first) { + LogTrace(metname) << " MTDDetTray::compatibleDets: not compatible" + << " (should not have been selected!)"; + return result; + } + + // Find the most probable destination component + TrajectoryStateOnSurface& tsos = compat.second; + GlobalPoint startPos = tsos.globalPosition(); + int closest = theBinFinder.binIndex(startPos.z()); + const vector dets = basicComponents(); + LogTrace(metname) << " MTDDetTray::compatibleDets, closest det: " << closest + << " pos: " << dets[closest]->surface().position() + << " impact " << startPos; + + // Add this detector, if it is compatible + // NOTE: add performs a null propagation + add(closest, result, tsos, prop, est); + +#ifdef EDM_ML_DEBUG + int nclosest = result.size(); int nnextdet=0; // just DEBUG counters +#endif + + // Try the neighbors on each side until no more compatible. + // If closest is not compatible the next cannot be either + if (!result.empty()) { + const BoundPlane& closestPlane(dets[closest]->surface()); + MeasurementEstimator::Local2DVector maxDistance = + est.maximalLocalDisplacement( result.front().second, closestPlane); + + // detHalfLen is assumed to be the same for all detectors. + float detHalfLen = closestPlane.bounds().length()/2.; + + for (unsigned int idet=closest+1; idet < dets.size(); idet++) { + LocalPoint nextPos(dets[idet]->toLocal(startPos)); + if (fabs(nextPos.y()) < detHalfLen + maxDistance.y()) { + LogTrace(metname) << " negativeZ: det:" << idet + << " pos " << nextPos.y() + << " maxDistance " << maxDistance.y(); +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + if ( !add(idet, result, tsos, prop, est)) break; + } else { + break; + } + } + + for (int idet=closest-1; idet >= 0; idet--) { + LocalPoint nextPos( dets[idet]->toLocal(startPos)); + if (fabs(nextPos.y()) < detHalfLen + maxDistance.y()) { + LogTrace(metname) << " positiveZ: det:" << idet + << " pos " << nextPos.y() + << " maxDistance " << maxDistance.y(); +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + if ( !add(idet, result, tsos, prop, est)) break; + } else { + break; + } + } + } + +#ifdef EDM_ML_DEBUG + LogTrace(metname) << " MTDDetTray::compatibleDets, size: " << result.size() + << " on closest: " << nclosest + << " # checked dets: " << nnextdet+1; +#endif + if (result.empty()) { + LogTrace(metname) << " ***Rod not compatible---should have been discarded before!!!"; + } + return result; +} + + +vector +MTDDetTray::groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + // FIXME should return only 1 group + cout << "dummy implementation of MTDDetTray::groupedCompatibleDets()" << endl; + vector result; + return result; +} diff --git a/RecoMTD/DetLayers/src/MTDRingForwardDoubleLayer.cc b/RecoMTD/DetLayers/src/MTDRingForwardDoubleLayer.cc new file mode 100644 index 0000000000000..2fcb513b0c404 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDRingForwardDoubleLayer.cc @@ -0,0 +1,225 @@ +/** \file + * + * \author L. Gray + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace std; + +MTDRingForwardDoubleLayer::MTDRingForwardDoubleLayer(const vector& frontRings, + const vector& backRings) : + RingedForwardLayer(true), + theFrontLayer(frontRings), + theBackLayer(backRings), + theRings(frontRings), // add back later + theComponents(), + theBasicComponents() +{ + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardDoubleLayer"; + + theRings.insert(theRings.end(), backRings.begin(), backRings.end()); + theComponents = std::vector (theRings.begin(), theRings.end()); + + // Cache chamber pointers (the basic components_) + // and find extension in R and Z + for (vector::const_iterator it=theRings.begin(); + it!=theRings.end(); it++) { + vector tmp2 = (*it)->basicComponents(); + theBasicComponents.insert(theBasicComponents.end(),tmp2.begin(),tmp2.end()); + } + + setSurface(computeSurface()); + + LogTrace(metname) << "Constructing MTDRingForwardDoubleLayer: " + << basicComponents().size() << " Dets " + << theRings.size() << " Rings " + << " Z: " << specificSurface().position().z() + << " R1: " << specificSurface().innerRadius() + << " R2: " << specificSurface().outerRadius(); + + selfTest(); +} + + +BoundDisk * MTDRingForwardDoubleLayer::computeSurface() +{ + const BoundDisk & frontDisk = theFrontLayer.specificSurface(); + const BoundDisk & backDisk = theBackLayer.specificSurface(); + + float rmin = min( frontDisk.innerRadius(), backDisk.innerRadius() ); + float rmax = max( frontDisk.outerRadius(), backDisk.outerRadius() ); + float zmin = frontDisk.position().z(); + float halfThickness = frontDisk.bounds().thickness()/2.; + zmin = (zmin > 0) ? zmin-halfThickness : zmin+halfThickness; + float zmax = backDisk.position().z(); + halfThickness = backDisk.bounds().thickness()/2.; + zmax = (zmax > 0) ? zmax+halfThickness : zmax-halfThickness; + float zPos = (zmax+zmin)/2.; + PositionType pos(0.,0.,zPos); + RotationType rot; + + return new BoundDisk( pos, rot, + new SimpleDiskBounds( rmin, rmax, + zmin-zPos, zmax-zPos)); +} + + +bool MTDRingForwardDoubleLayer::isInsideOut(const TrajectoryStateOnSurface& tsos) const +{ + return tsos.globalPosition().basicVector().dot(tsos.globalMomentum().basicVector()) > 0; +} + + + +std::pair +MTDRingForwardDoubleLayer::compatible(const TrajectoryStateOnSurface& startingState, const Propagator& prop, + const MeasurementEstimator& est) const +{ + // mostly copied from ForwardDetLayer, except propagates to closest surface, + // not to center + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardDoubleLayer"; + + bool insideOut = isInsideOut(startingState); + const MTDRingForwardLayer & closerLayer = (insideOut) ? theFrontLayer : theBackLayer; + LogTrace(metname) + << "MTDRingForwardDoubleLayer::compatible is assuming inside-out direction: "<< insideOut; + + TrajectoryStateOnSurface myState = prop.propagate( startingState, closerLayer.specificSurface()); + if ( !myState.isValid()) return make_pair( false, myState); + + // take into account the thickness of the layer + float deltaR = surface().bounds().thickness()/2. * + fabs( tan( myState.localDirection().theta())); + + // take into account the error on the predicted state + const float nSigma = 3.; + if (myState.hasError()) { + LocalError err = myState.localError().positionError(); + // ignore correlation for the moment... + deltaR += nSigma * sqrt(err.xx() + err.yy()); + } + + float zPos = (zmax()+zmin())/2.; + SimpleDiskBounds tmp( rmin()-deltaR, rmax()+deltaR, + zmin()-zPos, zmax()-zPos); + + return make_pair( tmp.inside(myState.localPosition()), myState); +} + + +vector +MTDRingForwardDoubleLayer::compatibleDets(const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + vector result; + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardDoubleLayer"; + pair compat = + compatible(startingState, prop, est); + + if (!compat.first) { + + LogTrace(metname) << " MTDRingForwardDoubleLayer::compatibleDets: not compatible" + << " (should not have been selected!)"; + return result; + } + + + TrajectoryStateOnSurface& tsos = compat.second; + + // standard implementation of compatibleDets() for class which have + // groupedCompatibleDets implemented. + // This code should be moved in a common place intead of being + // copied many times. + vector vectorGroups = groupedCompatibleDets(tsos,prop,est); + for(vector::const_iterator itDG=vectorGroups.begin(); + itDG!=vectorGroups.end();itDG++){ + for(vector::const_iterator itDGE=itDG->begin(); + itDGE!=itDG->end();itDGE++){ + result.push_back(DetWithState(itDGE->det(),itDGE->trajectoryState())); + } + } + return result; +} + + +vector +MTDRingForwardDoubleLayer::groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardDoubleLayer"; + vector detWithStates1, detWithStates2; + + LogTrace(metname) << "groupedCompatibleDets are currently given always in inside-out order"; + // this should be fixed either in RecoMTD/MeasurementDet/MTDDetLayerMeasurements or + // RecoMTD/DetLayers/MTDRingForwardDoubleLayer + + detWithStates1 = theFrontLayer.compatibleDets(startingState, prop, est); + detWithStates2 = theBackLayer.compatibleDets(startingState, prop, est); + + vector result; + if(!detWithStates1.empty()) result.push_back( DetGroup(detWithStates1) ); + if(!detWithStates2.empty()) result.push_back( DetGroup(detWithStates2) ); + LogTrace(metname) << "DoubleLayer Compatible dets: " << result.size(); + return result; +} + + +bool MTDRingForwardDoubleLayer::isCrack(const GlobalPoint & gp) const +{ + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardDoubleLayer"; + // approximate + bool result = false; + double r = gp.perp(); + const std::vector& backRings = theBackLayer.rings(); + if(backRings.size() > 1) + { + const MTDDetRing * innerRing = dynamic_cast(backRings[0]); + const MTDDetRing * outerRing = dynamic_cast(backRings[1]); + assert(innerRing && outerRing); + float crackInner = innerRing->specificSurface().outerRadius(); + float crackOuter = outerRing->specificSurface().innerRadius(); + LogTrace(metname) << "In a crack:" << crackInner << " " << r << " " << crackOuter; + if(r > crackInner && r < crackOuter) return true; + } + // non-overlapping rings + return result; +} + + +void MTDRingForwardDoubleLayer::selfTest() const +{ + const std::vector& frontDets = theFrontLayer.basicComponents(); + const std::vector& backDets = theBackLayer.basicComponents(); + + std::vector::const_iterator frontItr = frontDets.begin(), + lastFront = frontDets.end(), + backItr = backDets.begin(), + lastBack = backDets.end(); + + // test that each front z is less than each back z + for( ; frontItr != lastFront; ++frontItr) + { + float frontz = fabs( (**frontItr).surface().position().z() ); + for( ; backItr != lastBack; ++backItr) + { + float backz = fabs( (**backItr).surface().position().z() ); + assert(frontz < backz); + } + } +} + + diff --git a/RecoMTD/DetLayers/src/MTDRingForwardLayer.cc b/RecoMTD/DetLayers/src/MTDRingForwardLayer.cc new file mode 100644 index 0000000000000..4ff25c9449dc6 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDRingForwardLayer.cc @@ -0,0 +1,232 @@ +/** \file + * + * \author L. Gray - FNAL + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "RBorderFinder.h" +#include "GeneralBinFinderInR.h" + +#include +#include +#include + +using namespace std; + +MTDRingForwardLayer::MTDRingForwardLayer(const vector& rings) : + RingedForwardLayer(false), + theRings(rings), + theComponents(theRings.begin(),theRings.end()), + theBinFinder(nullptr), + isOverlapping(false) +{ + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardLayer"; + + // Initial values for R and Z bounds + float theRmin = rings.front()->basicComponents().front()->position().perp(); + float theRmax = theRmin; + float theZmin = rings.front()->position().z(); + float theZmax = theZmin; + + // Cache chamber pointers (the basic components_) + // and find extension in R and Z + for (vector::const_iterator it=rings.begin(); + it!=rings.end(); it++) { + vector tmp2 = (*it)->basicComponents(); + theBasicComps.insert(theBasicComps.end(),tmp2.begin(),tmp2.end()); + + theRmin = min( theRmin, (*it)->specificSurface().innerRadius()); + theRmax = max( theRmax, (*it)->specificSurface().outerRadius()); + float halfThick = (*it)->surface().bounds().thickness()/2.; + float zCenter = (*it)->surface().position().z(); + theZmin = min( theZmin, zCenter-halfThick); + theZmax = max( theZmax, zCenter+halfThick); + } + + RBorderFinder bf(theRings); + isOverlapping = bf.isROverlapping(); + theBinFinder = new GeneralBinFinderInR(bf); + + // Build surface + + float zPos = (theZmax+theZmin)/2.; + PositionType pos(0.,0.,zPos); + RotationType rot; + + setSurface(new BoundDisk( pos, rot, + new SimpleDiskBounds( theRmin, theRmax, + theZmin-zPos, theZmax-zPos))); + + + + LogTrace(metname) << "Constructing MTDRingForwardLayer: " + << basicComponents().size() << " Dets " + << theRings.size() << " Rings " + << " Z: " << specificSurface().position().z() + << " R1: " << specificSurface().innerRadius() + << " R2: " << specificSurface().outerRadius() + << " Per.: " << bf.isRPeriodic() + << " Overl.: " << bf.isROverlapping(); +} + + +MTDRingForwardLayer::~MTDRingForwardLayer(){ + delete theBinFinder; + for (vector ::iterator i = theRings.begin(); + i +MTDRingForwardLayer::compatibleDets(const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDRingForwardLayer"; + vector result; + + + LogTrace(metname) << "MTDRingForwardLayer::compatibleDets," + << " R1 " << specificSurface().innerRadius() + << " R2: " << specificSurface().outerRadius() + << " FTS at R: " << startingState.globalPosition().perp(); + + pair compat = + compatible(startingState, prop, est); + + if (!compat.first) { + + LogTrace(metname) << " MTDRingForwardLayer::compatibleDets: not compatible" + << " (should not have been selected!)"; + return result; + } + + + TrajectoryStateOnSurface& tsos = compat.second; + + int closest = theBinFinder->binIndex(tsos.globalPosition().perp()); + const ForwardDetRing* closestRing = theRings[closest]; + + // Check the closest ring + + LogTrace(metname) << " MTDRingForwardLayer::fastCompatibleDets, closestRing: " + << closest + << " R1 " << closestRing->specificSurface().innerRadius() + << " R2: " << closestRing->specificSurface().outerRadius() + << " FTS R: " << tsos.globalPosition().perp(); + if (tsos.hasError()) { + LogTrace(metname) << " sR: " << sqrt(tsos.localError().positionError().yy()) + << " sX: " << sqrt(tsos.localError().positionError().xx()); + } + LogTrace(metname) << endl; + + + result = closestRing->compatibleDets(tsos, prop, est); + +#ifdef EDM_ML_DEBUG + int nclosest = result.size(); int nnextdet=0; // MDEBUG counters +#endif + + //FIXME: if closest is not compatible next cannot be either? + + // Use state on layer surface. Note that local coordinates and errors + // are the same on the layer and on all rings surfaces, since + // all BoundDisks are centered in 0,0 and have the same rotation. + // CAVEAT: if the rings are not at the same Z, the local position and error + // will be "Z-projected" to the rings. This is a fairly good approximation. + // However in this case additional propagation will be done when calling + // compatibleDets. + GlobalPoint startPos = tsos.globalPosition(); + LocalPoint nextPos(surface().toLocal(startPos)); + + for (unsigned int idet=closest+1; idet < theRings.size(); idet++) { + bool inside = false; + if (tsos.hasError()) { + inside=theRings[idet]->specificSurface().bounds().inside(nextPos,tsos.localError().positionError()); + } else { + inside=theRings[idet]->specificSurface().bounds().inside(nextPos); + } + if (inside){ + LogTrace(metname) << " MTDRingForwardLayer::fastCompatibleDets:NextRing" << idet + << " R1 " << theRings[idet]->specificSurface().innerRadius() + << " R2: " << theRings[idet]->specificSurface().outerRadius() + << " FTS R " << nextPos.perp(); +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + vector nextRodDets = + theRings[idet]->compatibleDets(tsos, prop, est); + if (!nextRodDets.empty()) { + result.insert( result.end(), + nextRodDets.begin(), nextRodDets.end()); + } else { + break; + } + } + } + + for (int idet=closest-1; idet >= 0; idet--) { + bool inside = false; + if (tsos.hasError()) { + inside=theRings[idet]->specificSurface().bounds().inside(nextPos,tsos.localError().positionError()); + } else { + inside=theRings[idet]->specificSurface().bounds().inside(nextPos); + } + if (inside){ + LogTrace(metname) << " MTDRingForwardLayer::fastCompatibleDets:PreviousRing:" << idet + << " R1 " << theRings[idet]->specificSurface().innerRadius() + << " R2: " << theRings[idet]->specificSurface().outerRadius() + << " FTS R " << nextPos.perp(); +#ifdef EDM_ML_DEBUG + nnextdet++; +#endif + vector nextRodDets = + theRings[idet]->compatibleDets(tsos, prop, est); + if (!nextRodDets.empty()) { + result.insert( result.end(), + nextRodDets.begin(), nextRodDets.end()); + } else { + break; + } + } + } + +#ifdef EDM_ML_DEBUG + LogTrace(metname) << " MTDRingForwardLayer::fastCompatibleDets: found: " + << result.size() + << " on closest: " << nclosest + << " # checked rings: " << 1 + nnextdet; +#endif + + return result; +} + + +vector +MTDRingForwardLayer::groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + // FIXME should return only 1 group + cout << "dummy implementation of MTDRingForwardLayer::groupedCompatibleDets()" << endl; + return vector(); +} + + + +GeomDetEnumerators::SubDetector MTDRingForwardLayer::subDetector() const { + return theBasicComps.front()->subDetector(); +} + +const vector & +MTDRingForwardLayer::components() const { + return theComponents; +} diff --git a/RecoMTD/DetLayers/src/MTDTrayBarrelLayer.cc b/RecoMTD/DetLayers/src/MTDTrayBarrelLayer.cc new file mode 100644 index 0000000000000..2343c6974ece9 --- /dev/null +++ b/RecoMTD/DetLayers/src/MTDTrayBarrelLayer.cc @@ -0,0 +1,215 @@ +/** \file + * + * \author L. Gray - FNAL + */ + + +#include "RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h" +#include "RecoMTD/DetLayers/interface/MTDDetTray.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "TrackingTools/GeomPropagators/interface/Propagator.h" +#include "TrackingTools/DetLayers/interface/MeasurementEstimator.h" +#include "Utilities/BinningTools/interface/PeriodicBinFinderInPhi.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include +#include "DataFormats/GeometrySurface/interface/GeometricSorting.h" + +#include "GeneralBinFinderInPhi.h" +#include "PhiBorderFinder.h" + +#include +#include + +using namespace std; + +MTDTrayBarrelLayer::MTDTrayBarrelLayer(vector& rods) : + RodBarrelLayer(false), + theRods(rods), + theBinFinder(nullptr), + isOverlapping(false) +{ + // Sort rods in phi + precomputed_value_sort(theRods.begin(),theRods.end(), geomsort::ExtractPhi()); + + theComponents.reserve(theRods.size()); + std::copy(theRods.begin(),theRods.end(),back_inserter(theComponents)); + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDTrayBarrelLayer"; + + // Cache chamber pointers (the basic components_) + for (vector::const_iterator it=rods.begin(); + it!=rods.end(); it++) { + vector tmp2 = (*it)->basicComponents(); + theBasicComps.insert(theBasicComps.end(),tmp2.begin(),tmp2.end()); + } + + // Initialize the binfinder + PhiBorderFinder bf(theRods); + isOverlapping = bf.isPhiOverlapping(); + + if ( bf.isPhiPeriodic() ) { + theBinFinder = new PeriodicBinFinderInPhi + (theRods.front()->position().phi(),theRods.size()); + } else { + theBinFinder = new GeneralBinFinderInPhi(bf); + } + + // Compute the layer's surface and bounds (from the components()) + BarrelDetLayer::initialize(); + + LogTrace(metname) << "Constructing MTDTrayBarrelLayer: " + << basicComponents().size() << " Dets " + << theRods.size() << " Rods " + << " R: " << specificSurface().radius() + << " Per.: " << bf.isPhiPeriodic() + << " Overl.: " << isOverlapping; +} + + +MTDTrayBarrelLayer::~MTDTrayBarrelLayer() { + delete theBinFinder; + for (vector ::iterator i = theRods.begin(); + i +MTDTrayBarrelLayer::compatibleDets(const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + + const std::string metname = "MTD|RecoMTD|RecoMTDDetLayers|MTDTrayBarrelLayer"; + vector result; + + + LogTrace(metname) << "MTDTrayBarrelLayer::compatibleDets, Cyl R: " + << specificSurface().radius() + << " TSOS at R= " << startingState.globalPosition().perp() + << " phi= " << startingState.globalPosition().phi(); + + pair compat = + compatible(startingState, prop, est); + if (!compat.first) { + LogTrace(metname) << " MTDTrayBarrelLayer::compatibleDets: not compatible" + << " (should not have been selected!)"; + return vector(); + } + + TrajectoryStateOnSurface& tsos = compat.second; + + LogTrace(metname) << " MTDTrayBarrelLayer::compatibleDets, reached layer at: " + << tsos.globalPosition() + << " R = " << tsos.globalPosition().perp() + << " phi = " << tsos.globalPosition().phi(); + + int closest = theBinFinder->binIndex(tsos.globalPosition().phi()); + const DetRod* closestRod = theRods[closest]; + + // Check the closest rod + LogTrace(metname) << " MTDTrayBarrelLayer::compatibleDets, closestRod: " << closest + << " phi : " << closestRod->surface().position().phi() + << " FTS phi: " << tsos.globalPosition().phi(); + + result = closestRod->compatibleDets(tsos, prop, est); + +#ifdef EDM_ML_DEBUG + int nclosest = result.size(); // Debug counter +#endif + + bool checknext = false ; + double dist; + + if (!result.empty()) { + // Check if the track go outside closest rod, then look for closest. + TrajectoryStateOnSurface& predictedState = result.front().second; + float xErr = xError(predictedState, est); + float halfWid = closestRod->surface().bounds().width()/2.; + dist = predictedState.localPosition().x(); + + // If the layer is overlapping, additionally reduce halfWid by 10% + // to account for overlap. + // FIXME: should we account for the real amount of overlap? + if (isOverlapping) halfWid *= 0.9; + + if (fabs(dist) + xErr > halfWid) { + checknext = true; + } + } else { // Rod is not compatible + //FIXME: Usually next cannot be either. Implement proper logic. + // (in general at least one rod should be when this method is called by + // compatibleDets() which calls compatible()) + checknext = true; + + // Look for the next-to closest in phi. + // Note Geom::Phi, subtraction is pi-border-safe + if ( tsos.globalPosition().phi()-closestRod->surface().position().phi()>0.) + { + dist = -1.; + } else { + dist = +1.; + } + + + LogTrace(metname) << " MTDTrayBarrelLayer::fastCompatibleDets, none on closest rod!"; + } + + if (checknext) { + int next; + if (dist<0.) next = closest+1; + else next = closest-1; + + next = theBinFinder->binIndex(next); // Bin Periodicity + const DetRod* nextRod = theRods[next]; + + + LogTrace(metname) << " MTDTrayBarrelLayer::fastCompatibleDets, next-to closest" + << " rod: " << next << " dist " << dist + << " phi : " << nextRod->surface().position().phi() + << " FTS phi: " << tsos.globalPosition().phi(); + + vector nextRodDets = + nextRod->compatibleDets(tsos, prop, est); + result.insert(result.end(), + nextRodDets.begin(), nextRodDets.end()); + } + +#ifdef EDM_ML_DEBUG + LogTrace(metname) << " MTDTrayBarrelLayer::fastCompatibleDets: found: " + << result.size() + << " on closest: " << nclosest + << " # checked rods: " << 1 + int(checknext); +#endif + + return result; +} + + +vector +MTDTrayBarrelLayer::groupedCompatibleDets( const TrajectoryStateOnSurface& startingState, + const Propagator& prop, + const MeasurementEstimator& est) const { + // FIXME should return only 1 group + cout << "dummy implementation of MTDTrayBarrelLayer::groupedCompatibleDets()" << endl; + return vector(); +} + + + +GeomDetEnumerators::SubDetector MTDTrayBarrelLayer::subDetector() const { + return theBasicComps.front()->subDetector(); +} + +const vector& +MTDTrayBarrelLayer::components() const { + return theComponents; +} + +float MTDTrayBarrelLayer::xError(const TrajectoryStateOnSurface& tsos, + const MeasurementEstimator& est) const { + const float nSigmas = 3.f; + if (tsos.hasError()) { + return nSigmas * sqrt(tsos.localError().positionError().xx()); + } + else return nSigmas * 0.5; +} diff --git a/RecoMTD/DetLayers/src/PhiBorderFinder.h b/RecoMTD/DetLayers/src/PhiBorderFinder.h new file mode 100644 index 0000000000000..736512fcf46e1 --- /dev/null +++ b/RecoMTD/DetLayers/src/PhiBorderFinder.h @@ -0,0 +1,2 @@ +#include "TrackingTools/DetLayers/interface/PhiBorderFinder.h" + diff --git a/RecoMTD/DetLayers/src/RBorderFinder.h b/RecoMTD/DetLayers/src/RBorderFinder.h new file mode 100644 index 0000000000000..1a6fa2c81d6bc --- /dev/null +++ b/RecoMTD/DetLayers/src/RBorderFinder.h @@ -0,0 +1 @@ +#include "TrackingTools/DetLayers/interface/RBorderFinder.h" diff --git a/RecoMTD/DetLayers/test/BuildFile.xml b/RecoMTD/DetLayers/test/BuildFile.xml new file mode 100644 index 0000000000000..2391103d86b57 --- /dev/null +++ b/RecoMTD/DetLayers/test/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/RecoMTD/DetLayers/test/MTDRecoGeometryAnalyzer.cc b/RecoMTD/DetLayers/test/MTDRecoGeometryAnalyzer.cc new file mode 100644 index 0000000000000..a53e927274f2d --- /dev/null +++ b/RecoMTD/DetLayers/test/MTDRecoGeometryAnalyzer.cc @@ -0,0 +1,249 @@ +/** \file + * + */ + +#include +#include +#include +#include +#include +#include + +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "RecoMTD/Records/interface/MTDRecoGeometryRecord.h" + +#include "MagneticField/Engine/interface/MagneticField.h" +#include "MagneticField/Records/interface/IdealMagneticFieldRecord.h" + +#include "TrackPropagation/SteppingHelixPropagator/interface/SteppingHelixPropagator.h" +#include "TrackingTools/KalmanUpdators/interface/Chi2MeasurementEstimator.h" + + +#include "RecoMTD/DetLayers/interface/MTDTrayBarrelLayer.h" +#include "RecoMTD/DetLayers/interface/MTDDetTray.h" +#include "RecoMTD/DetLayers/interface/MTDRingForwardDoubleLayer.h" +#include "RecoMTD/DetLayers/interface/MTDDetRing.h" + +#include + +#include +#include + +#include + +#include "CLHEP/Random/RandFlat.h" + +using namespace std; +using namespace edm; + +class MTDRecoGeometryAnalyzer : public EDAnalyzer { + public: + + MTDRecoGeometryAnalyzer( const ParameterSet& pset); + + virtual void analyze( const Event& ev, const EventSetup& es); + + void testBTLLayers(const MTDDetLayerGeometry*, const MagneticField* field); + void testETLLayers(const MTDDetLayerGeometry*, const MagneticField* field); + + string dumpLayer(const DetLayer* layer) const; + + private: + MeasurementEstimator *theEstimator; +}; + + + +MTDRecoGeometryAnalyzer::MTDRecoGeometryAnalyzer(const ParameterSet& iConfig) +{ + float theMaxChi2=25.; + float theNSigma=3.; + theEstimator = new Chi2MeasurementEstimator(theMaxChi2,theNSigma); + +} + + +void MTDRecoGeometryAnalyzer::analyze( const Event& ev, + const EventSetup& es ) { + + ESHandle geo; + es.get().get(geo); + + ESHandle magfield; + es.get().get(magfield); + // Some printouts + + cout << "*** allBTLLayers(): " << geo->allBTLLayers().size() << endl; + for (auto dl = geo->allBTLLayers().begin(); + dl != geo->allBTLLayers().end(); ++dl) { + cout << " " << (int) (dl-geo->allBTLLayers().begin()) << " " << dumpLayer(*dl); + } + cout << endl << endl; + + cout << "*** allETLLayers(): " << geo->allETLLayers().size() << endl; + for (auto dl = geo->allETLLayers().begin(); + dl != geo->allETLLayers().end(); ++dl) { + cout << " " << (int) (dl-geo->allETLLayers().begin()) << " " << dumpLayer(*dl); + } + cout << endl << endl; + + cout << "*** allLayers(): " << geo->allLayers().size() << endl; + for (auto dl = geo->allLayers().begin(); + dl != geo->allLayers().end(); ++dl) { + cout << " " << (int) (dl-geo->allLayers().begin()) << " " << dumpLayer(*dl); + } + cout << endl << endl; + + + + + + testBTLLayers(geo.product(),magfield.product()); + testETLLayers(geo.product(),magfield.product()); +} + + +void MTDRecoGeometryAnalyzer::testBTLLayers(const MTDDetLayerGeometry* geo,const MagneticField* field) { + + const vector& layers = geo->allBTLLayers(); + + for (auto ilay = layers.begin(); ilay!=layers.end(); ++ilay) { + const MTDTrayBarrelLayer* layer = (const MTDTrayBarrelLayer*) (*ilay); + + const BoundCylinder& cyl = layer->specificSurface(); + + double halfZ = cyl.bounds().length()/2.; + + // Generate a random point on the cylinder + double aPhi = CLHEP::RandFlat::shoot(-Geom::pi(),Geom::pi()); + double aZ = CLHEP::RandFlat::shoot(-halfZ, halfZ); + GlobalPoint gp(GlobalPoint::Cylindrical(cyl.radius(), aPhi, aZ)); + + // Momentum: 10 GeV, straight from the origin + GlobalVector gv(GlobalVector::Spherical(gp.theta(), aPhi, 10.)); + + //FIXME: only negative charge + int charge = -1; + + GlobalTrajectoryParameters gtp(gp,gv,charge,field); + TrajectoryStateOnSurface tsos(gtp, cyl); + cout << "testBTLLayers: at " << tsos.globalPosition() + << " R=" << tsos.globalPosition().perp() + << " phi=" << tsos.globalPosition().phi() + << " Z=" << tsos.globalPosition().z() + << " p = " << tsos.globalMomentum() + << endl; + + + SteppingHelixPropagator prop(field,anyDirection); + + pair comp = layer->compatible(tsos,prop,*theEstimator); + cout << "is compatible: " << comp.first + << " at: R=" << comp.second.globalPosition().perp() + << " phi=" << comp.second.globalPosition().phi() + << " Z=" << comp.second.globalPosition().z() + << endl; + + vector compDets = layer->compatibleDets(tsos,prop,*theEstimator); + if (compDets.size()) { + cout << "compatibleDets: " << compDets.size() << endl + + << " final state pos: " << compDets.front().second.globalPosition() << endl + << " det pos: " << compDets.front().first->position() + << " id: " << std::hex << BTLDetId(compDets.front().first->geographicalId().rawId()).rawId() << std::dec<< endl + << " distance " << (tsos.globalPosition()-compDets.front().first->position()).mag() + + << endl + << endl; + } else { + cout << " ERROR : no compatible det found" << endl; + } + } +} + +void MTDRecoGeometryAnalyzer::testETLLayers(const MTDDetLayerGeometry* geo,const MagneticField* field) { + const vector& layers = geo->allETLLayers(); + + for (auto ilay = layers.begin(); ilay!=layers.end(); ++ilay) { + const MTDRingForwardDoubleLayer* layer = (const MTDRingForwardDoubleLayer*) (*ilay); + + const BoundDisk& disk = layer->specificSurface(); + + // Generate a random point on the disk + double aPhi = CLHEP::RandFlat::shoot(-Geom::pi(),Geom::pi()); + double aR = CLHEP::RandFlat::shoot(disk.innerRadius(), disk.outerRadius()); + GlobalPoint gp(GlobalPoint::Cylindrical(aR, aPhi, disk.position().z())); + + // Momentum: 10 GeV, straight from the origin + GlobalVector gv(GlobalVector::Spherical(gp.theta(), aPhi, 10.)); + + //FIXME: only negative charge + int charge = -1; + + GlobalTrajectoryParameters gtp(gp,gv,charge,field); + TrajectoryStateOnSurface tsos(gtp, disk); + cout << "testETLLayers: at " << tsos.globalPosition() + << " R=" << tsos.globalPosition().perp() + << " phi=" << tsos.globalPosition().phi() + << " Z=" << tsos.globalPosition().z() + << " p = " << tsos.globalMomentum() + << endl; + + + SteppingHelixPropagator prop(field,anyDirection); + + pair comp = layer->compatible(tsos,prop,*theEstimator); + cout << "is compatible: " << comp.first + << " at: R=" << comp.second.globalPosition().perp() + << " phi=" << comp.second.globalPosition().phi() + << " Z=" << comp.second.globalPosition().z() + << endl; + + vector compDets = layer->compatibleDets(tsos,prop,*theEstimator); + if (compDets.size()) { + cout << "compatibleDets: " << compDets.size() << endl + + << " final state pos: " << compDets.front().second.globalPosition() << endl + << " det pos: " << compDets.front().first->position() + << " id: " << std::hex << ETLDetId(compDets.front().first->geographicalId().rawId()).rawId() << std::dec << endl + << " distance " << (tsos.globalPosition()-compDets.front().first->position()).mag() + + << endl + << endl; + } else { + if(layer->isCrack(gp)) + { + cout << " CSC crack found "; + } + else + { + cout << " ERROR : no compatible det found in CSC" + << " at: R=" << gp.perp() + << " phi= " << gp.phi().degrees() + << " Z= " << gp.z(); + } + + } + } +} + +string MTDRecoGeometryAnalyzer::dumpLayer(const DetLayer* layer) const { + stringstream output; + + const BoundSurface* sur=0; + const BoundCylinder* bc=0; + const BoundDisk* bd=0; + + sur = &(layer->surface()); + if ( (bc = dynamic_cast(sur)) ) { + output << " Cylinder of radius: " << bc->radius() << endl; + } + else if ( (bd = dynamic_cast(sur)) ) { + output << " Disk at: " << bd->position().z() << endl; + } + return output.str(); +} + +//define this as a plug-in +#include +DEFINE_FWK_MODULE(MTDRecoGeometryAnalyzer); diff --git a/RecoMTD/DetLayers/test/mtd_cfg.py b/RecoMTD/DetLayers/test/mtd_cfg.py new file mode 100644 index 0000000000000..eac11e2a556fb --- /dev/null +++ b/RecoMTD/DetLayers/test/mtd_cfg.py @@ -0,0 +1,35 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("GeometryTest") +# empty input service, fire 10 events +process.load("FWCore.MessageLogger.MessageLogger_cfi") + +# Choose Tracker Geometry +process.load("Configuration.Geometry.GeometryExtended2023D24_cff") + +process.load("Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cfi") + +process.load("Geometry.MTDNumberingBuilder.mtdTopology_cfi") +process.load("Geometry.MTDGeometryBuilder.mtdGeometry_cfi") +process.load("Geometry.MTDGeometryBuilder.mtdParameters_cfi") +process.mtdGeometry.applyAlignment = cms.bool(False) + +process.load("MagneticField.Engine.volumeBasedMagneticField_160812_cfi") +process.load("RecoMTD.DetLayers.mtdDetLayerGeometry_cfi") + +process.Timing = cms.Service("Timing") + +process.source = cms.Source("EmptySource") + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(1) +) + +process.myprint = cms.OutputModule("AsciiOutputModule") + +process.prod = cms.EDAnalyzer("MTDRecoGeometryAnalyzer") + +process.p1 = cms.Path(process.prod) + +process.e1 = cms.EndPath(process.myprint) + diff --git a/RecoMTD/DetLayers/test/testRecoGeometry.cfg b/RecoMTD/DetLayers/test/testRecoGeometry.cfg new file mode 100644 index 0000000000000..cd8983e12f7b1 --- /dev/null +++ b/RecoMTD/DetLayers/test/testRecoGeometry.cfg @@ -0,0 +1,36 @@ +process test = { + + source = EmptySource { + } +untracked PSet maxEvents = {untracked int32 input = 10} + + service = MessageLogger { + untracked vstring destinations = { "cout" } + + untracked vstring debugModules = { "*" } + + untracked vstring categories = {"RecoMTDDetLayers"} + + untracked PSet cout = { + untracked string threshold = "DEBUG" + untracked bool noLineBreaks = true + untracked PSet DEBUG = {untracked int32 limit = 0 } + untracked PSet RecoMuonDetLayers = {untracked int32 limit = 10000000} + } + } + + include "MagneticField/Engine/data/volumeBasedMagneticField.cfi" + + include "Geometry/MuonCommonData/data/muonIdealGeometryXML.cfi" + include "Geometry/MTDGeometryBuilder/data/cscGeometry.cfi" + include "Geometry/DTGeometry/data/dtGeometry.cfi" + include "Geometry/RPCGeometry/data/rpcGeometry.cfi" + + include "RecoMuon/DetLayers/data/mtdDetLayerGeometry.cfi" + include "Geometry/MuonNumbering/data/muonNumberingInitialization.cfi" + + + module analyzer = MTDRecoGeometryAnalyzer { } + + path p = {analyzer} +} diff --git a/RecoMTD/Navigation/BuildFile.xml b/RecoMTD/Navigation/BuildFile.xml new file mode 100644 index 0000000000000..3a36668171285 --- /dev/null +++ b/RecoMTD/Navigation/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/RecoMTD/Navigation/interface/BTLNavigableLayer.h b/RecoMTD/Navigation/interface/BTLNavigableLayer.h new file mode 100644 index 0000000000000..5589197929c25 --- /dev/null +++ b/RecoMTD/Navigation/interface/BTLNavigableLayer.h @@ -0,0 +1,179 @@ +#ifndef Navigation_BTLNavigableLayer_H +#define Navigation_BTLNavigableLayer_H + +/** \class BTLNavigableLayer + * + * Navigable layer for Barrel Timing Layer. + * Taken from MuonBarrelNavigableLayer. + * + * + * \author : L. Gray - FNAL + * + */ + + +/* Collaborating Class Declarations */ +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" + +class DetLayer; +class BarrelDetLayer; + +/* Base Class Headers */ +#include "RecoMTD/Navigation/interface/MTDNavigableLayer.h" +/* C++ Headers */ + +/* ====================================================================== */ + +/* Class BTLNavigableLayer Interface */ + +class BTLNavigableLayer : public MTDNavigableLayer { + + public: + + /// Constructor + BTLNavigableLayer(BarrelDetLayer* bdl, + const MapB& outerBarrel, + const MapB& innerBarrel, + const MapE& outerBackward, + const MapE& outerForward, + const MapE& innerBackward, + const MapE& innerForward) : + theDetLayer(bdl), + theOuterBarrelLayers(outerBarrel), + theInnerBarrelLayers(innerBarrel), + theOuterBackwardLayers(outerBackward), + theInnerBackwardLayers(innerBackward), + theOuterForwardLayers(outerForward), + theInnerForwardLayers(innerForward) {} + + BTLNavigableLayer(BarrelDetLayer* bdl, + const MapB& outerBarrel, + const MapB& innerBarrel, + const MapE& outerBackward, + const MapE& outerForward, + const MapE& innerBackward, + const MapE& innerForward, + const MapB& allOuterBarrel, + const MapB& allInnerBarrel, + const MapE& allOuterBackward, + const MapE& allOuterForward, + const MapE& allInnerBackward, + const MapE& allInnerForward) : + theDetLayer(bdl), + theOuterBarrelLayers(outerBarrel), + theInnerBarrelLayers(innerBarrel), + theOuterBackwardLayers(outerBackward), + theInnerBackwardLayers(innerBackward), + theOuterForwardLayers(outerForward), + theInnerForwardLayers(innerForward), + theAllOuterBarrelLayers(allOuterBarrel), + theAllInnerBarrelLayers(allInnerBarrel), + theAllOuterBackwardLayers(allOuterBackward), + theAllInnerBackwardLayers(allInnerBackward), + theAllOuterForwardLayers(allOuterForward), + theAllInnerForwardLayers(allInnerForward) {} + + /// Constructor with outer layers only + BTLNavigableLayer(BarrelDetLayer* bdl, + const MapB& outerBarrel, + const MapE& outerBackward, + const MapE& outerForward) : + theDetLayer(bdl), + theOuterBarrelLayers(outerBarrel), + theOuterBackwardLayers(outerBackward), + theOuterForwardLayers(outerForward) { } + + BTLNavigableLayer(const BarrelDetLayer* bdl, + const MapB& outerBarrel, + const MapE& outerBackward, + const MapE& outerForward, + const MapB& allOuterBarrel, + const MapE& allOuterBackward, + const MapE& allOuterForward) : + theDetLayer(bdl), + theOuterBarrelLayers(outerBarrel), + theOuterBackwardLayers(outerBackward), + theOuterForwardLayers(outerForward), + theAllOuterBarrelLayers(allOuterBarrel), + theAllOuterBackwardLayers(allOuterBackward), + theAllOuterForwardLayers(allOuterForward) {} + + /// NavigableLayer interface + std::vector nextLayers(NavigationDirection dir) const override; + + /// NavigableLayer interface + std::vector nextLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override; + + std::vector compatibleLayers(NavigationDirection dir) const override; + + /// NavigableLayer interface + std::vector compatibleLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override; + + /// return DetLayer + const DetLayer* detLayer() const override; + + /// set DetLayer + void setDetLayer(const DetLayer*) override; + + MapB getOuterBarrelLayers() const { return theOuterBarrelLayers; } + MapB getInnerBarrelLayers() const { return theInnerBarrelLayers; } + MapE getOuterBackwardLayers() const { return theOuterBackwardLayers; } + MapE getInnerBackwardLayers() const { return theInnerBackwardLayers; } + MapE getOuterForwardLayers() const { return theOuterForwardLayers; } + MapE getInnerForwardLayers() const { return theInnerForwardLayers; } + + MapB getAllOuterBarrelLayers() const { return theAllOuterBarrelLayers; } + MapB getAllInnerBarrelLayers() const { return theAllInnerBarrelLayers; } + MapE getAllOuterBackwardLayers() const { return theAllOuterBackwardLayers; } + MapE getAllInnerBackwardLayers() const { return theAllInnerBackwardLayers; } + MapE getAllOuterForwardLayers() const { return theAllOuterForwardLayers; } + MapE getAllInnerForwardLayers() const { return theAllInnerForwardLayers; } + + /// set inward links + void setInwardLinks(const MapB&); + void setInwardCompatibleLinks(const MapB&); + + private: + + void pushResult(std::vector& result, + const MapB& map) const; + + void pushResult(std::vector& result, + const MapE& map) const; + + void pushResult(std::vector& result, + const MapB& map, const + FreeTrajectoryState& fts) const; + + void pushResult(std::vector& result, + const MapE& map, const + FreeTrajectoryState& fts) const; + void pushCompatibleResult(std::vector& result, + const MapB& map, const + FreeTrajectoryState& fts) const; + + void pushCompatibleResult(std::vector& result, + const MapE& map, const + FreeTrajectoryState& fts) const; + + private: + + const BarrelDetLayer* theDetLayer; + MapB theOuterBarrelLayers; + MapB theInnerBarrelLayers; + MapE theOuterBackwardLayers; + MapE theInnerBackwardLayers; + MapE theOuterForwardLayers; + MapE theInnerForwardLayers; + MapB theAllOuterBarrelLayers; + MapB theAllInnerBarrelLayers; + MapE theAllOuterBackwardLayers; + MapE theAllInnerBackwardLayers; + MapE theAllOuterForwardLayers; + MapE theAllInnerForwardLayers; + +}; +#endif diff --git a/RecoMTD/Navigation/interface/DirectMTDNavigation.h b/RecoMTD/Navigation/interface/DirectMTDNavigation.h new file mode 100644 index 0000000000000..184ee4f80277c --- /dev/null +++ b/RecoMTD/Navigation/interface/DirectMTDNavigation.h @@ -0,0 +1,66 @@ +#ifndef Navigation_DirectMTDNavigation_H +#define Navigation_DirectMTDNavigation_H +/** \file DirectMTDNavigation + * + * do a straight line extrapolation to + * find out compatible DetLayers with a given FTS + * + * \author Chang Liu - Purdue University + */ + +#include "FWCore/Framework/interface/ESHandle.h" +#include "DataFormats/GeometrySurface/interface/BoundCylinder.h" +#include "TrackingTools/DetLayers/interface/DetLayer.h" +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +class DirectMTDNavigation{ + + public: + + /* Constructor */ + DirectMTDNavigation(const edm::ESHandle&); + + DirectMTDNavigation(const edm::ESHandle&, const edm::ParameterSet&); + + DirectMTDNavigation* clone() const { + return new DirectMTDNavigation(*this); + } + + /* Destructor */ + ~DirectMTDNavigation() {} + + std::vector + compatibleLayers( const FreeTrajectoryState& fts, + PropagationDirection timeDirection) const; + + + std::vector + compatibleEndcapLayers( const FreeTrajectoryState& fts, + PropagationDirection timeDirection) const; + + private: + + void inOutBarrel(const FreeTrajectoryState&, std::vector&) const; + void outInBarrel(const FreeTrajectoryState&, std::vector&) const; + + void inOutForward(const FreeTrajectoryState&, std::vector&) const; + void outInForward(const FreeTrajectoryState&, std::vector&) const; + + void inOutBackward(const FreeTrajectoryState&, std::vector&) const; + void outInBackward(const FreeTrajectoryState&, std::vector&) const; + + bool checkCompatible(const FreeTrajectoryState& fts,const BarrelDetLayer*) const; + bool checkCompatible(const FreeTrajectoryState& fts,const ForwardDetLayer*) const; + bool outward(const FreeTrajectoryState& fts) const; + + edm::ESHandle theMTDDetLayerGeometry; + float epsilon_; + bool theEndcapFlag; + bool theBarrelFlag; + +}; +#endif diff --git a/RecoMTD/Navigation/interface/ETLNavigableLayer.h b/RecoMTD/Navigation/interface/ETLNavigableLayer.h new file mode 100644 index 0000000000000..5544821e78288 --- /dev/null +++ b/RecoMTD/Navigation/interface/ETLNavigableLayer.h @@ -0,0 +1,133 @@ +#ifndef Navigation_ETLNavigableLayer_H +#define Navigation_ETLNavigableLayer_H + +/** \class ETLNavigableLayer + * + * Navigable layer for Forward Muon + * + * + * \author : Stefano Lacaprara - INFN Padova + * + * Modification: + * Chang Liu: + * compatibleLayers(dir) and compatibleLayers(fts, dir) are added, + * which return ALL DetLayers that are compatible with a given DetLayer. + */ + +/* Collaborating Class Declarations */ +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" + +class DetLayer; +class ForwardDetLayer; + +/* Base Class Headers */ +#include "RecoMTD/Navigation/interface/MTDNavigableLayer.h" + +/* C++ Headers */ + +/* ====================================================================== */ + +/* Class ETLNavigableLayer Interface */ + +class ETLNavigableLayer : public MTDNavigableLayer { + + public: + + ETLNavigableLayer(const ForwardDetLayer* fdl, + const MapB& innerBarrel, + const MapE& outerEndcap, + const MapE& innerEndcap, + const MapB& allInnerBarrel, + const MapE& allOuterEndcap, + const MapE& allInnerEndcap) : + theDetLayer(fdl), + theInnerBarrelLayers(innerBarrel), + theOuterEndcapLayers(outerEndcap), + theInnerEndcapLayers(innerEndcap), + theAllInnerBarrelLayers(allInnerBarrel), + theAllOuterEndcapLayers(allOuterEndcap), + theAllInnerEndcapLayers(allInnerEndcap) {} + + /// Constructor with outer layers only + ETLNavigableLayer(const ForwardDetLayer* fdl, + const MapE& outerEndcap) : + theDetLayer(fdl), + theOuterEndcapLayers(outerEndcap) {} + /// Constructor with all outer layers only + ETLNavigableLayer(const ForwardDetLayer* fdl, + const MapE& outerEndcap, + const MapE& allOuterEndcap) : + theDetLayer(fdl), + theOuterEndcapLayers(outerEndcap), + theAllOuterEndcapLayers(allOuterEndcap) {} + + + /// NavigableLayer interface + std::vector nextLayers(NavigationDirection dir) const override; + + /// NavigableLayer interface + std::vector nextLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override; + + std::vector compatibleLayers(NavigationDirection dir) const override; + + /// NavigableLayer interface + std::vector compatibleLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override; + /// return DetLayer + const DetLayer* detLayer() const override; + + /// set DetLayer + void setDetLayer(const DetLayer*) override; + + /// Operations + MapE getOuterEndcapLayers() const { return theOuterEndcapLayers; } + MapE getInnerEndcapLayers() const { return theInnerEndcapLayers; } + MapB getInnerBarrelLayers() const { return theInnerBarrelLayers; } + + MapE getAllOuterEndcapLayers() const { return theAllOuterEndcapLayers; } + MapE getAllInnerEndcapLayers() const { return theAllInnerEndcapLayers; } + MapB getAllInnerBarrelLayers() const { return theAllInnerBarrelLayers; } + + /// set inward links + void setInwardLinks(const MapB&, const MapE&); + void setInwardCompatibleLinks(const MapB&, const MapE&); + + private: + + void pushResult(std::vector& result, + const MapB& map) const; + + void pushResult(std::vector& result, + const MapE& map) const; + + void pushResult(std::vector& result, + const MapB& map, + const FreeTrajectoryState& fts) const; + + void pushResult(std::vector& result, + const MapE& map, const + FreeTrajectoryState& fts) const; + + void pushCompatibleResult(std::vector& result, + const MapB& map, const + FreeTrajectoryState& fts) const; + + void pushCompatibleResult(std::vector& result, + const MapE& map, const + FreeTrajectoryState& fts) const; + + + private: + + const ForwardDetLayer* theDetLayer; + MapB theInnerBarrelLayers; + MapE theOuterEndcapLayers; + MapE theInnerEndcapLayers; + MapB theAllInnerBarrelLayers; + MapE theAllOuterEndcapLayers; + MapE theAllInnerEndcapLayers; + +}; +#endif diff --git a/RecoMTD/Navigation/interface/MTDDetLayerMap.h b/RecoMTD/Navigation/interface/MTDDetLayerMap.h new file mode 100644 index 0000000000000..54d2fe82f1870 --- /dev/null +++ b/RecoMTD/Navigation/interface/MTDDetLayerMap.h @@ -0,0 +1,41 @@ +#ifndef MTDDetLayerMap_h +#define MTDDetLayerMap_h + +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" + +#include +#include + +/** \class MTDDetLayerComp + * + * Sort the of BarrelDetLayers by radius, ForwardDetLayer by |Z|. + * + * \author : L. Gray + * + * Adapted from MuonDetLayerComp + * + */ + +struct MTDDetLayerComp { + bool operator()(const BarrelDetLayer* l1, const BarrelDetLayer* l2) const { + if ( l1->specificSurface().radius() < l2->specificSurface().radius() ) return true; + return false; + } + + bool operator()(const ForwardDetLayer* l1, const ForwardDetLayer* l2) const { + if ( fabs(l1->surface().position().z()) < fabs(l2->surface().position().z()) ) return true; + return false; + } +}; + + +// FIXME: these names are too generic... +typedef std::map MapB; +typedef std::map MapE; +typedef MapB::const_iterator MapBI; +typedef MapE::const_iterator MapEI; + +#endif + diff --git a/RecoMTD/Navigation/interface/MTDEtaRange.h b/RecoMTD/Navigation/interface/MTDEtaRange.h new file mode 100644 index 0000000000000..a237e9b03dfc6 --- /dev/null +++ b/RecoMTD/Navigation/interface/MTDEtaRange.h @@ -0,0 +1,44 @@ +#ifndef Navigation_MTDEtaRange_H +#define Navigation_MTDEtaRange_H + +/** \class MTDEtaRange + * + * a class to define eta range used in Muon Navigation + * + * + * \author : Stefano Lacaprara - INFN Padova + * + * Modification: + * + */ + +class MTDEtaRange { + + public: + + MTDEtaRange(); + MTDEtaRange(float max, float min); + MTDEtaRange(const MTDEtaRange&); + ~MTDEtaRange() {} + MTDEtaRange& operator=(const MTDEtaRange&); + inline float min() const { return theMin; } + inline float max() const { return theMax; } + bool isInside(float eta, float error=0.) const; + bool isInside(const MTDEtaRange& range) const; + bool isCompatible(const MTDEtaRange& range) const; + MTDEtaRange add(const MTDEtaRange&) const; + MTDEtaRange minRange(const MTDEtaRange&) const; + MTDEtaRange subtract(const MTDEtaRange&) const; + private: + + float theMin; + float theMax; +}; +#include +inline std::ostream& operator<<(std::ostream& os, const MTDEtaRange& range) +{ + os << "(" << range.min() << " : " << range.max() << ")" ; + return os; +} + +#endif diff --git a/RecoMTD/Navigation/interface/MTDNavigableLayer.h b/RecoMTD/Navigation/interface/MTDNavigableLayer.h new file mode 100644 index 0000000000000..5512bbb104610 --- /dev/null +++ b/RecoMTD/Navigation/interface/MTDNavigableLayer.h @@ -0,0 +1,54 @@ +#ifndef Navigation_MTDNavigableLayer_H +#define Navigation_MTDNavigableLayer_H + +/** \class MTDNavigableLayer + * + * base class for BTLNavigableLayer and ETLNavigableLayer. + * trackingRange defines an MTDEtaRange for an FTS, + * which is used for search compatible DetLayers. + * + * + * \author : L. Gray - FNAL + * + * Modification: + * + */ + +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" + +class DetLayer; +class BarrelDetLayer; + +#include "TrackingTools/DetLayers/interface/NavigableLayer.h" + + +class MTDNavigableLayer : public NavigableLayer { + + public: + + /// NavigableLayer interface + std::vector nextLayers(NavigationDirection dir) const override =0; + + /// NavigableLayer interface + std::vector nextLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override =0; + + std::vector compatibleLayers(NavigationDirection dir) const override =0; + + /// NavigableLayer interface + std::vector compatibleLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const override =0; + + /// return DetLayer + const DetLayer* detLayer() const override =0; + + /// set DetLayer + void setDetLayer(const DetLayer*) override =0; + + MTDEtaRange trackingRange(const FreeTrajectoryState& fts) const; + + bool isInsideOut(const FreeTrajectoryState& fts) const; + +}; +#endif diff --git a/RecoMTD/Navigation/interface/MTDNavigationPrinter.h b/RecoMTD/Navigation/interface/MTDNavigationPrinter.h new file mode 100644 index 0000000000000..2843c336a8e37 --- /dev/null +++ b/RecoMTD/Navigation/interface/MTDNavigationPrinter.h @@ -0,0 +1,40 @@ +#ifndef Navigation_MTDNavigationPrinter_H +#define Navigation_MTDNavigationPrinter_H + +/** \class MTDNavigationPrinter + * + * Description: + * class to print the MTDNavigationSchool + * + * + * \author : L. Gray - FNAL + * + */ + +class DetLayer; +class MTDDetLayerGeometry; +class GeometricSearchTracker; +class MTDNavigationSchool; + +#include +#include + +class MTDNavigationPrinter { + public: + + MTDNavigationPrinter(const MTDDetLayerGeometry *, MTDNavigationSchool const &, bool enableBTL = true, bool enableETL = true ); + MTDNavigationPrinter(const MTDDetLayerGeometry *,MTDNavigationSchool const &, const GeometricSearchTracker *); + + private: + void printLayer(const DetLayer*) const; + void printLayers(const std::vector&) const; + /// return detector part (barrel, forward, backward) +// std::string layerPart(const DetLayer*) const; + /// return detector module (pixel, silicon, msgc, dt, csc, rpc) +// std::string layerModule(const DetLayer*) const; + + + MTDNavigationSchool const * school=nullptr; + +}; +#endif diff --git a/RecoMTD/Navigation/interface/MTDNavigationSchool.h b/RecoMTD/Navigation/interface/MTDNavigationSchool.h new file mode 100644 index 0000000000000..b2f018e9ac9fc --- /dev/null +++ b/RecoMTD/Navigation/interface/MTDNavigationSchool.h @@ -0,0 +1,80 @@ +#ifndef Navigation_MTDNavigationSchool_H +#define Navigation_MTDNavigationSchool_H + +/** \class MTDNavigationSchool + * + * Description: + * Navigation school for the MTD system + * This class defines which DetLayers are reacheable from each MTD DetLayer + * ( BTL and ETL ). The reacheableness is based on an eta range criteria. + * + * + * \author : L. Gray + * + * Modification: + * + + */ + + +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "TrackingTools/DetLayers/interface/NavigationSchool.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include +#include + +class BTLNavigableLayer; +class ETLNavigableLayer; +class MTDEtaRange; +class BarrelDetLayer; +class ForwardDetLayer; + +class MTDNavigationSchool : public NavigationSchool { + + public: + ///Constructor + MTDNavigationSchool(const MTDDetLayerGeometry *, bool enableBTL = true, bool enableETL = true); + /// Destructor + ~MTDNavigationSchool() override; + /// return navigable layers, from base class + StateType navigableLayers() override; + private: + /// add barrel layer + void addBarrelLayer(const BarrelDetLayer*); + /// add endcap layer (backward and forward) + void addEndcapLayer(const ForwardDetLayer*); + /// link barrel layers + void linkBarrelLayers(); + /// link endcap layers + void linkEndcapLayers(const MapE&,std::vector&); + /// establish inward links + void createInverseLinks(); + float calculateEta(const float&, const float& ) const; + + private: + + struct delete_layer + { + template + void operator()(T*& p) + { + if( p) + { + delete p; + p = nullptr; + } + } + }; + + MapB theBarrelLayers; /// barrel + MapE theForwardLayers; /// +z endcap + MapE theBackwardLayers; /// -z endcap + + std::vector theBarrelNLC; + std::vector theForwardNLC; + std::vector theBackwardNLC; + + const MTDDetLayerGeometry * theMTDDetLayerGeometry; + +}; +#endif diff --git a/RecoMTD/Navigation/src/BTLNavigableLayer.cc b/RecoMTD/Navigation/src/BTLNavigableLayer.cc new file mode 100644 index 0000000000000..e662c0f822731 --- /dev/null +++ b/RecoMTD/Navigation/src/BTLNavigableLayer.cc @@ -0,0 +1,176 @@ +/** \class BTLNavigableLayer + * + * Navigable layer for Barrel Timing Layer + * Adapted from MuonBarrelNavigableLayer + * + * + * \author : L. Gray + * + */ + +#include "RecoMTD/Navigation/interface/BTLNavigableLayer.h" + +/* Collaborating Class Header */ +#include "TrackingTools/DetLayers/interface/DetLayer.h" +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "TrackingTools/TrajectoryState/interface/FreeTrajectoryState.h" +/* C++ Headers */ +#include + +using namespace std; +std::vector +BTLNavigableLayer::nextLayers(NavigationDirection dir) const { + + std::vector result; + + if ( dir == insideOut ) { + pushResult(result, theOuterBarrelLayers); + pushResult(result, theOuterBackwardLayers); + pushResult(result, theOuterForwardLayers); + } + else { + pushResult(result, theInnerBarrelLayers); + reverse(result.begin(),result.end()); + pushResult(result, theInnerBackwardLayers); + pushResult(result, theInnerForwardLayers); + } + + result.reserve(result.size()); + return result; + +} + + +std::vector +BTLNavigableLayer::nextLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const { + + std::vector result; + + if ( (isInsideOut(fts) && dir == alongMomentum) || ( !isInsideOut(fts) && dir == oppositeToMomentum)) { + pushResult(result, theOuterBarrelLayers, fts); + pushResult(result, theOuterBackwardLayers, fts); + pushResult(result, theOuterForwardLayers, fts); + } + else { + pushResult(result, theInnerBarrelLayers, fts); + reverse(result.begin(),result.end()); + pushResult(result, theInnerBackwardLayers, fts); + pushResult(result, theInnerForwardLayers, fts); + } + result.reserve(result.size()); + return result; +} + +std::vector +BTLNavigableLayer::compatibleLayers(NavigationDirection dir) const { + + std::vector result; + + if ( dir == insideOut ) { + pushResult(result, theAllOuterBarrelLayers); + pushResult(result, theAllOuterBackwardLayers); + pushResult(result, theAllOuterForwardLayers); + } + else { + pushResult(result, theAllInnerBarrelLayers); + reverse(result.begin(),result.end()); + pushResult(result, theAllInnerBackwardLayers); + pushResult(result, theAllInnerForwardLayers); + } + + result.reserve(result.size()); + return result; +} + +std::vector +BTLNavigableLayer::compatibleLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const { + std::vector result; + + if ( (isInsideOut(fts) && dir == alongMomentum) || ( !isInsideOut(fts) && dir == oppositeToMomentum)) { + pushCompatibleResult(result, theAllOuterBarrelLayers, fts); + pushCompatibleResult(result, theAllOuterBackwardLayers, fts); + pushCompatibleResult(result, theAllOuterForwardLayers, fts); + } + else { + pushCompatibleResult(result, theAllInnerBarrelLayers, fts); + reverse(result.begin(),result.end()); + pushCompatibleResult(result, theAllInnerBackwardLayers, fts); + pushCompatibleResult(result, theAllInnerForwardLayers, fts); + } + result.reserve(result.size()); + return result; + +} + + +void BTLNavigableLayer::pushResult(std::vector& result, + const MapB& map) const { + + for ( MapBI i = map.begin(); i != map.end(); i++ ) result.push_back((*i).first); + +} + +void BTLNavigableLayer::pushResult(std::vector& result, + const MapE& map) const { + + for ( MapEI i = map.begin(); i != map.end(); i++ ) result.push_back((*i).first); +} + + +void BTLNavigableLayer::pushResult(std::vector& result, + const MapB& map, + const FreeTrajectoryState& fts) const { + for ( MapBI i = map.begin(); i != map.end(); i++ ) + if ((*i).second.isInside(fts.position().eta())) result.push_back((*i).first); +} + +void BTLNavigableLayer::pushResult(std::vector& result, + const MapE& map, + const FreeTrajectoryState& fts) const { + + for (MapEI i = map.begin(); i != map.end(); i++) + if ((*i).second.isInside(fts.position().eta())) result.push_back((*i).first); + +} + +void BTLNavigableLayer::pushCompatibleResult(std::vector& result, + const MapB& map, + const FreeTrajectoryState& fts) const { + MTDEtaRange range= trackingRange(fts); + for ( MapBI i = map.begin(); i != map.end(); i++ ) + if ((*i).second.isCompatible(range)) result.push_back((*i).first); +} + +void BTLNavigableLayer::pushCompatibleResult(std::vector& result, + const MapE& map, + const FreeTrajectoryState& fts) const { + MTDEtaRange range= trackingRange(fts); + for (MapEI i = map.begin(); i != map.end(); i++) + if ((*i).second.isCompatible(range)) result.push_back((*i).first); + +} + +const DetLayer* BTLNavigableLayer::detLayer() const { + return theDetLayer; +} + + +void BTLNavigableLayer::setDetLayer(const DetLayer* dl) { + edm::LogError("BTLNavigableLayer") << "BTLNavigableLayer::setDetLayer called!! " << endl; +} + + +void BTLNavigableLayer::setInwardLinks(const MapB& innerBL) { + theInnerBarrelLayers = innerBL; +} +void BTLNavigableLayer::setInwardCompatibleLinks(const MapB& innerCBL) { + + theAllInnerBarrelLayers = innerCBL; + +} + diff --git a/RecoMTD/Navigation/src/DirectMTDNavigation.cc b/RecoMTD/Navigation/src/DirectMTDNavigation.cc new file mode 100644 index 0000000000000..d58936c279759 --- /dev/null +++ b/RecoMTD/Navigation/src/DirectMTDNavigation.cc @@ -0,0 +1,255 @@ +#include "RecoMTD/Navigation/interface/DirectMTDNavigation.h" + +/** \file DirectMTDNavigation + * + * \author L. Gray - FNAL + */ + +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "DataFormats/GeometrySurface/interface/BoundCylinder.h" +#include "DataFormats/GeometrySurface/interface/BoundDisk.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "FWCore/Framework/interface/ESHandle.h" + +#include + +using namespace std; + +DirectMTDNavigation::DirectMTDNavigation(const edm::ESHandle& mtdLayout) : theMTDDetLayerGeometry(mtdLayout), epsilon_(100.), theEndcapFlag(true), theBarrelFlag(true) { +} + +DirectMTDNavigation::DirectMTDNavigation(const edm::ESHandle& mtdLayout, const edm::ParameterSet& par) : theMTDDetLayerGeometry(mtdLayout), epsilon_(100.), theEndcapFlag(par.getParameter("Endcap")), theBarrelFlag(par.getParameter("Barrel")) { + +} + + +/* return compatible layers for given trajectory state */ +vector +DirectMTDNavigation::compatibleLayers( const FreeTrajectoryState& fts, + PropagationDirection dir ) const { + + float z0 = fts.position().z(); + float zm = fts.momentum().z(); + + bool inOut = outward(fts); + + vector output; + + // check direction and position of FTS to get a correct order of DetLayers + + if (inOut) { + if ((zm * z0) >= 0) { + if (theBarrelFlag) inOutBarrel(fts,output); + if (theEndcapFlag) { + if ( z0 >= 0 ) inOutForward(fts,output); + else inOutBackward(fts,output); + } + } else { + if (theEndcapFlag) { + if ( z0 >= 0 ) outInForward(fts,output); + else outInBackward(fts,output); + } + if (theBarrelFlag) inOutBarrel(fts,output); + } + } else { + if ((zm * z0) >= 0) { + if (theBarrelFlag) outInBarrel(fts,output); + if (theEndcapFlag) { + if ( z0 >= 0 ) inOutForward(fts,output); + else inOutBackward(fts,output); + } + } else { + if (theEndcapFlag) { + if ( z0 >= 0 ) outInForward(fts,output); + else outInBackward(fts,output); + } + if (theBarrelFlag) outInBarrel(fts,output); + } + } + + if ( dir == oppositeToMomentum ) std::reverse(output.begin(),output.end()); + + return output; +} + +/* +return compatible endcap layers on BOTH ends; +used for beam-halo muons +*/ +vector +DirectMTDNavigation::compatibleEndcapLayers( const FreeTrajectoryState& fts, + PropagationDirection dir ) const { + + float zm = fts.momentum().z(); + + vector output; + + // collect all endcap layers on 2 sides + outInBackward(fts,output); + inOutForward(fts,output); + + // check direction FTS to get a correct order of DetLayers + if ( ( zm > 0 && dir == oppositeToMomentum ) || + ( zm < 0 && dir == alongMomentum ) ) + std::reverse(output.begin(),output.end()); + + return output; +} + +void DirectMTDNavigation::inOutBarrel(const FreeTrajectoryState& fts, vector& output) const { + + bool cont = false; + const vector& barrel = theMTDDetLayerGeometry->allBarrelLayers(); + + for (vector::const_iterator iter_B = barrel.begin(); iter_B != barrel.end(); iter_B++){ + + if( cont ) output.push_back((*iter_B)); + else if ( checkCompatible(fts,dynamic_cast(*iter_B))) { + output.push_back((*iter_B)); + cont = true; + } + } +} + + +void DirectMTDNavigation::outInBarrel(const FreeTrajectoryState& fts, vector& output) const { + +// default barrel layers are in out, reverse order + const vector& barrel = theMTDDetLayerGeometry->allBarrelLayers(); + + bool cont = false; + vector::const_iterator rbegin = barrel.end(); + rbegin--; + vector::const_iterator rend = barrel.begin(); + rend--; + + for (vector::const_iterator iter_B = rbegin; iter_B != rend; iter_B--){ + if( cont ) output.push_back((*iter_B)); + else if ( checkCompatible(fts,dynamic_cast(*iter_B))) { + output.push_back((*iter_B)); + cont = true; + } + } +} + +void DirectMTDNavigation::inOutForward(const FreeTrajectoryState& fts, vector& output) const { + + const vector& forward = theMTDDetLayerGeometry->allForwardLayers(); + bool cont = false; + for (vector::const_iterator iter_E = forward.begin(); iter_E != forward.end(); + iter_E++){ + if( cont ) output.push_back((*iter_E)); + else if ( checkCompatible(fts,dynamic_cast(*iter_E))) { + output.push_back((*iter_E)); + cont = true; + } + } +} + +void DirectMTDNavigation::outInForward(const FreeTrajectoryState& fts, vector& output) const { +// default forward layers are in out, reverse order + + bool cont = false; + const vector& forward = theMTDDetLayerGeometry->allForwardLayers(); + vector::const_iterator rbegin = forward.end(); + rbegin--; + vector::const_iterator rend = forward.begin(); + rend--; + for (vector::const_iterator iter_E = rbegin; iter_E != rend; + iter_E--){ + if( cont ) output.push_back((*iter_E)); + else if ( checkCompatible(fts,dynamic_cast(*iter_E))) { + output.push_back((*iter_E)); + cont = true; + } + } +} + +void DirectMTDNavigation::inOutBackward(const FreeTrajectoryState& fts, vector& output) const { + bool cont = false; + const vector& backward = theMTDDetLayerGeometry->allBackwardLayers(); + + for (vector::const_iterator iter_E = backward.begin(); iter_E != backward.end(); + iter_E++){ + if( cont ) output.push_back((*iter_E)); + else if ( checkCompatible(fts,dynamic_cast(*iter_E))) { + output.push_back((*iter_E)); + cont = true; + } + } +} + +void DirectMTDNavigation::outInBackward(const FreeTrajectoryState& fts, vector& output) const { + + bool cont = false; + const vector& backward = theMTDDetLayerGeometry->allBackwardLayers(); + + vector::const_iterator rbegin = backward.end(); + rbegin--; + vector::const_iterator rend = backward.begin(); + rend--; + for (vector::const_iterator iter_E = rbegin; iter_E != rend; + iter_E--){ + if( cont ) output.push_back((*iter_E)); + else if ( checkCompatible(fts,dynamic_cast(*iter_E))) { + output.push_back((*iter_E)); + cont = true; + } + } + +} + + +bool DirectMTDNavigation::checkCompatible(const FreeTrajectoryState& fts,const BarrelDetLayer* dl) const { + + float z0 = fts.position().z(); + float r0 = fts.position().perp(); + float zm = fts.momentum().z(); + float rm = fts.momentum().perp(); + float slope = zm/rm; + if (!outward(fts) ) slope = -slope; + const BoundCylinder& bc = dl->specificSurface(); + float radius = bc.radius(); + float length = bc.bounds().length()/2.; + + float z1 = slope*(radius - r0) + z0; + return ( fabs(z1) <= fabs(length)+epsilon_ ); + +} + +bool DirectMTDNavigation::checkCompatible(const FreeTrajectoryState& fts,const ForwardDetLayer* dl) const { + + float z0 = fts.position().z(); + float r0 = fts.position().perp(); + float zm = fts.momentum().z(); + float rm = fts.momentum().perp(); + float slope = rm/zm; + + if (!outward(fts) ) slope = -slope; + + const BoundDisk& bd = dl->specificSurface(); + + float outRadius = bd.outerRadius(); + float inRadius = bd.innerRadius(); + float z = bd.position().z(); + + float r1 = slope*(z - z0) + r0; + return (r1 >= inRadius-epsilon_ && r1 <= outRadius+epsilon_); + +} + +bool DirectMTDNavigation::outward(const FreeTrajectoryState& fts) const { + +// return (fts.position().basicVector().dot(fts.momentum().basicVector())>0); + + float x0 = fts.position().x(); + float y0 = fts.position().y(); + + float xm = fts.momentum().x(); + float ym = fts.momentum().y(); + + return ((x0 * xm + y0 * ym ) > 0); + + +} diff --git a/RecoMTD/Navigation/src/ETLNavigableLayer.cc b/RecoMTD/Navigation/src/ETLNavigableLayer.cc new file mode 100644 index 0000000000000..a825724321a25 --- /dev/null +++ b/RecoMTD/Navigation/src/ETLNavigableLayer.cc @@ -0,0 +1,193 @@ +/** \class ETLNavigableLayer + * + * Navigable layer for ETL + * + * + * \author : L. Gray - FNAL + * + * + * Adapted from ETLNavigableLayer + */ + +#include "RecoMTD/Navigation/interface/ETLNavigableLayer.h" + +/* Collaborating Class Header */ +#include "TrackingTools/DetLayers/interface/DetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + +using namespace std; +using namespace edm; + +vector +ETLNavigableLayer::nextLayers(NavigationDirection dir) const { + + vector result; + vector barrel; + + if ( dir == insideOut ) { + pushResult(result, theOuterEndcapLayers); + } + else { + pushResult(result, theInnerEndcapLayers); + reverse(result.begin(),result.end()); + pushResult(barrel, theInnerBarrelLayers); + reverse(barrel.begin(),barrel.end()); + result.insert(result.end(),barrel.begin(),barrel.end()); + } + + result.reserve(result.size()); + return result; + +} + + +vector +ETLNavigableLayer::nextLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const { + + vector result; + vector barrel; + + if ( (isInsideOut(fts) && dir == alongMomentum) || ( !isInsideOut(fts) && dir == oppositeToMomentum)) { + pushResult(result, theOuterEndcapLayers, fts); + } + else { + pushResult(result, theInnerEndcapLayers, fts); + reverse(result.begin(),result.end()); + pushResult(barrel, theInnerBarrelLayers, fts); + reverse(barrel.begin(),barrel.end()); + result.insert(result.end(),barrel.begin(),barrel.end()); + } + + result.reserve(result.size()); + return result; + +} + +vector +ETLNavigableLayer::compatibleLayers(NavigationDirection dir) const { + + vector result; + vector barrel; + + if ( dir == insideOut ) { + pushResult(result, theAllOuterEndcapLayers); + } + else { + pushResult(result, theAllInnerEndcapLayers); + reverse(result.begin(),result.end()); + pushResult(barrel, theAllInnerBarrelLayers); + reverse(barrel.begin(),barrel.end()); + result.insert(result.end(),barrel.begin(),barrel.end()); + } + + result.reserve(result.size()); + return result; + +} +vector +ETLNavigableLayer::compatibleLayers(const FreeTrajectoryState& fts, + PropagationDirection dir) const { + vector result; + vector barrel; + + if ( (isInsideOut(fts) && dir == alongMomentum) || ( !isInsideOut(fts) && dir == oppositeToMomentum)) { + pushCompatibleResult(result, theAllOuterEndcapLayers, fts); + } + else { + pushCompatibleResult(result, theAllInnerEndcapLayers, fts); + reverse(result.begin(),result.end()); + pushCompatibleResult(barrel, theAllInnerBarrelLayers, fts); + reverse(barrel.begin(),barrel.end()); + result.insert(result.end(),barrel.begin(),barrel.end()); + } + result.reserve(result.size()); + return result; + +} + +void ETLNavigableLayer::pushResult(vector& result, + const MapB& map) const { + + for (MapBI i = map.begin(); i != map.end(); i++) result.push_back((*i).first); + +} + + +void ETLNavigableLayer::pushResult(vector& result, + const MapE& map) const { + + for (MapEI i = map.begin(); i != map.end(); i++) result.push_back((*i).first); + +} + + +void ETLNavigableLayer::pushResult(vector& result, + const MapE& map, + const FreeTrajectoryState& fts) const { + + for (MapEI i = map.begin(); i != map.end(); i++) + if ((*i).second.isInside(fts.position().eta())) result.push_back((*i).first); + +} + + +void ETLNavigableLayer::pushResult(vector& result, + const MapB& map, + const FreeTrajectoryState& fts) const { + + for (MapBI i = map.begin(); i != map.end(); i++) + if ((*i).second.isInside(fts.position().eta())) result.push_back((*i).first); + +} + + +void ETLNavigableLayer::pushCompatibleResult(vector& result, + const MapB& map, + const FreeTrajectoryState& fts) const { + MTDEtaRange range=trackingRange(fts); + for ( MapBI i = map.begin(); i != map.end(); i++ ) + if ((*i).second.isCompatible(range)) result.push_back((*i).first); +} + +void ETLNavigableLayer::pushCompatibleResult(vector& result, + const MapE& map, + const FreeTrajectoryState& fts) const { + MTDEtaRange range=trackingRange(fts); + for (MapEI i = map.begin(); i != map.end(); i++) + if ((*i).second.isCompatible(range)) result.push_back((*i).first); + +} + + +const DetLayer* ETLNavigableLayer::detLayer() const { + + return theDetLayer; + +} + + +void ETLNavigableLayer::setDetLayer(const DetLayer* dl) { + + edm::LogError ("ETLNavigablaLayer") << "ETLNavigableLayer::setDetLayer called!! " << endl; + +} + + +void ETLNavigableLayer::setInwardLinks(const MapB& innerBL, + const MapE& innerEL) { + + theInnerBarrelLayers = innerBL; + theInnerEndcapLayers = innerEL; + +} +void ETLNavigableLayer::setInwardCompatibleLinks(const MapB& innerCBL, + const MapE& innerCEL) { + + theAllInnerBarrelLayers = innerCBL; + theAllInnerEndcapLayers = innerCEL; + +} + diff --git a/RecoMTD/Navigation/src/MTDEtaRange.cc b/RecoMTD/Navigation/src/MTDEtaRange.cc new file mode 100644 index 0000000000000..c53ca551ec133 --- /dev/null +++ b/RecoMTD/Navigation/src/MTDEtaRange.cc @@ -0,0 +1,81 @@ +/** \class MTDEtaRange + * + * a class to define eta range used in MTD Navigation + * + * + * \author : L. Gray - FNAL + * + * Modification: + * + */ + +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include + + +MTDEtaRange::MTDEtaRange() : + theMin(0), theMax(0) {} + +MTDEtaRange::MTDEtaRange(float max, float min) { + if ( max < min ) { + edm::LogWarning ("MTDEtaRange") << "Warning MTDEtaRange:: max < min!! correcting" < max() || (eta-error) < min() ) return false; + return true; +} +/// true if this is completely inside range +bool MTDEtaRange::isInside(const MTDEtaRange& range) const { + if ( min() > range.min() && max() < range.max() ) return true; + return false; +} +/// true if this overlaps with range +bool MTDEtaRange::isCompatible(const MTDEtaRange& range) const { + if ( range.min() > max() || range.max() < min() ) return false; + return true; +} +/// create maximum of ranges +MTDEtaRange MTDEtaRange::add(const MTDEtaRange& range) const { + float max = ( theMax > range.theMax ) ? theMax : range.theMax; + float min = ( theMin < range.theMin ) ? theMin : range.theMin; + return MTDEtaRange(max,min); +} +/// create new range of size this minus range +MTDEtaRange MTDEtaRange::subtract(const MTDEtaRange& range) const { + + if ( range.isInside(*this) ) { + edm::LogInfo ("MTDEtaRange") << "MTDEtaRange: range is inside!" << std::endl; + return *this; + } + if ( !range.isCompatible(*this) ) { + edm::LogInfo ("MTDEtaRange") << "MTDEtaRange: no overlap between ranges" << std::endl; + return *this; + } + + float max = isInside(range.theMin) ? range.theMin : theMax; + float min = isInside(range.theMax) ? range.theMax : theMin; + return MTDEtaRange(max,min); +} + + diff --git a/RecoMTD/Navigation/src/MTDNavigableLayer.cc b/RecoMTD/Navigation/src/MTDNavigableLayer.cc new file mode 100644 index 0000000000000..c16e21111cb02 --- /dev/null +++ b/RecoMTD/Navigation/src/MTDNavigableLayer.cc @@ -0,0 +1,77 @@ +/** \class MTDNavigableLayer + * + * base class for MTDNavigableLayer and MuonForwardNavigableLayer. + * trackingRange defines an MTDEtaRange for an FTS, + * which is used for searching compatible DetLayers. + * + * + * \author : Chang Liu - Purdue University + * with contributions from: R. Bellan - INFN Torino + * + * code of trackingRange is from MuonGlobalNavigation in ORCA + * whose author is Stefano Lacaprara - INFN Padova + * Modification: + * + */ + +#include "RecoMTD/Navigation/interface/MTDNavigableLayer.h" + +/* Collaborating Class Header */ +#include "TrackingTools/DetLayers/interface/DetLayer.h" +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +/* C++ Headers */ +#include + + +using namespace std; + +extern float calculateEta(float r, float z) { + if ( z > 0 ) return -log((tan(atan(r/z)/2.))); + return log(-(tan(atan(r/z)/2.))); + +} + +MTDEtaRange MTDNavigableLayer::trackingRange(const FreeTrajectoryState& fts) const +{ + float z = fts.position().z(); + float r = fts.position().perp(); + float eta; + if ( z>0 ) eta = -log((tan(atan(r/z)/2.))); + else eta = log(-(tan(atan(r/z)/2.))); + + double theta = atan(r/z); + + double spread = 5.0*sqrt(fts.curvilinearError().matrix()(2,2))/fabs(sin(theta)); //5*sigma(eta) + + //C.L.: this spread could be too large to use. + // convert it to a smaller one by assuming a virtual radius + // that transforms the error on angle to error on z axis. + // not accurate, but works! + + double eta_max = 0; + + if ( z > 0 ) eta_max = calculateEta(r, z+spread); + else eta_max = calculateEta(r, z-spread); + + spread = std::min(0.07, fabs(eta_max-eta)); + + MTDEtaRange range(eta+spread,eta-spread); + + spread = 0.07; + // special treatment for special geometry in overlap region + + if ( eta > 1.0 && eta < 1.1 ) range = MTDEtaRange(eta+3.0*spread,eta-spread); + if ( eta < -1.0 && eta > -1.1 ) range = MTDEtaRange(eta+spread,eta-3.0*spread); + + return range; +} + +bool MTDNavigableLayer::isInsideOut(const FreeTrajectoryState& fts) const { + + return (fts.position().basicVector().dot(fts.momentum().basicVector())>0); + +} + diff --git a/RecoMTD/Navigation/src/MTDNavigationPrinter.cc b/RecoMTD/Navigation/src/MTDNavigationPrinter.cc new file mode 100644 index 0000000000000..85e7e8b70f9f0 --- /dev/null +++ b/RecoMTD/Navigation/src/MTDNavigationPrinter.cc @@ -0,0 +1,179 @@ +/** \class MTDNavigationPrinter + * + * Description: + * class to print the MTDNavigationSchool + * + * + * \author : L. Gray - FNAL + * + */ + +#include "RecoMTD/Navigation/interface/MTDNavigationPrinter.h" + +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "DataFormats/GeometrySurface/interface/BoundCylinder.h" +#include "DataFormats/GeometrySurface/interface/BoundDisk.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "RecoTracker/TkDetLayers/interface/GeometricSearchTracker.h" +#include "RecoMTD/Navigation/interface/MTDNavigationSchool.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include +#include +using namespace std; + +// #define VI_DEBUG + +#ifdef VI_DEBUG +#define PRINT(x) std::cout << x << ' ' +#else +#define PRINT(x) edm::LogInfo(x) +#endif + +MTDNavigationPrinter::MTDNavigationPrinter(const MTDDetLayerGeometry * mtdLayout, MTDNavigationSchool const & sh, bool enableBTL, bool enableETL) : + school(&sh) { + + PRINT("MTDNavigationPrinter")<< "MTDNavigationPrinter::MTDNavigationPrinter" << std::endl; + PRINT("MTDNavigationPrinter")<<"================================" << std::endl; + PRINT("MTDNavigationPrinter")<< "BARREL:" << std::endl; + vector barrel; + if ( enableBTL ) barrel = mtdLayout->allBarrelLayers(); + else barrel = mtdLayout->allBarrelLayers(); + + PRINT("MTDNavigationPrinter")<<"There are "< backward; + + if ( enableETL ) backward = mtdLayout->allBackwardLayers(); + else backward = mtdLayout->allBackwardLayers(); + + PRINT("MTDNavigationPrinter")<<"There are "< forward; + + if ( enableETL ) forward = mtdLayout->allForwardLayers(); + else forward = mtdLayout->allForwardLayers(); + + PRINT("MTDNavigationPrinter")<<"There are "<::const_iterator tkiter; +// vector::const_iterator tkfiter; + PRINT("MTDNavigationPrinter")<<"================================" << std::endl; + PRINT("MTDNavigationPrinter")<< "BARREL:" << std::endl; + const vector& tkbarrel = tracker->barrelLayers(); + PRINT("MTDNavigationPrinter")<<"There are "< barrel = mtdLayout->allBarrelLayers(); + PRINT("MTDNavigationPrinter")<<"There are "<& tkbackward = tracker->negForwardLayers(); + PRINT("MTDNavigationPrinter")<<"There are "< backward = mtdLayout->allBackwardLayers(); + PRINT("MTDNavigationPrinter")<<"There are "<& tkforward = tracker->posForwardLayers(); + PRINT("MTDNavigationPrinter")<<"There are "< forward = mtdLayout->allForwardLayers(); + PRINT("MTDNavigationPrinter")<<"There are "< nextLayers = school->nextLayers(*layer,insideOut); + vector compatibleLayers = school->compatibleLayers(*layer,insideOut); + if (const BarrelDetLayer* bdl = dynamic_cast(layer)) { + PRINT("MTDNavigationPrinter") + << layer->location() << " " << layer->subDetector() << " layer at R: " + << setiosflags(ios::showpoint | ios::fixed) + << setw(8) << setprecision(2) + << bdl->specificSurface().radius() << " length: " + << setw(6) << setprecision(2) + << layer->surface().bounds().length() << std::endl; + + } + else if (const ForwardDetLayer* fdl = dynamic_cast(layer)) { + PRINT("MTDNavigationPrinter") << endl + << layer->location() << " " << layer->subDetector() << "layer at z: " + << setiosflags(ios::showpoint | ios::fixed) + << setw(8) << setprecision(2) + << layer->surface().position().z() << " inner r: " + << setw(6) << setprecision(2) + << fdl->specificSurface().innerRadius() << " outer r: " + << setw(6) << setprecision(2) + << fdl->specificSurface().outerRadius() << std::endl; + } + PRINT("MTDNavigationPrinter") << " has " << nextLayers.size() << " next layers in the direction inside-out: " << std::endl; + printLayers(nextLayers); + + nextLayers.clear(); + nextLayers = school->nextLayers(*layer,outsideIn); + + PRINT("MTDNavigationPrinter") << " has " << nextLayers.size() << " next layers in the direction outside-in: " << std::endl; + printLayers(nextLayers); + + PRINT("MTDNavigationPrinter") << " has " << compatibleLayers.size() << " compatible layers in the direction inside-out:: " << std::endl; + printLayers(compatibleLayers); + compatibleLayers.clear(); + compatibleLayers = school->compatibleLayers(*layer,outsideIn); + + PRINT("MTDNavigationPrinter") << " has " << compatibleLayers.size() << " compatible layers in the direction outside-in: " << std::endl; + printLayers(compatibleLayers); + +} + +/// print next layers +void MTDNavigationPrinter::printLayers(const vector& nextLayers) const { + + for ( vector::const_iterator inext = nextLayers.begin(); + inext != nextLayers.end(); inext++ ) { + + PRINT("MTDNavigationPrinter") << " --> " << std::endl; + if ( (*inext)->location() == GeomDetEnumerators::barrel ) { + const BarrelDetLayer* l = dynamic_cast(&(**inext)); + PRINT("MTDNavigationPrinter") << (*inext)->location() << " " + << (*inext)->subDetector() + << " layer at R: " + << setiosflags(ios::showpoint | ios::fixed) + << setw(8) << setprecision(2) + << l->specificSurface().radius() << " " << std::endl; + } + else { + const ForwardDetLayer* l = dynamic_cast(&(**inext)); + PRINT("MTDNavigationPrinter") << (*inext)->location() << " " + << (*inext)->subDetector() + << " layer at z: " + << setiosflags(ios::showpoint | ios::fixed) + << setw(8) << setprecision(2) + << l->surface().position().z() << " " << std::endl; + } + PRINT("MTDNavigationPrinter") << setiosflags(ios::showpoint | ios::fixed) + << setprecision(1) + << setw(6) << (*inext)->surface().bounds().length() << ", " + << setw(6) << (*inext)->surface().bounds().width() << ", " + << setw(4) <<(*inext)->surface().bounds().thickness() << " : " + << (*inext)->surface().position() << std::endl; + } + +} diff --git a/RecoMTD/Navigation/src/MTDNavigationSchool.cc b/RecoMTD/Navigation/src/MTDNavigationSchool.cc new file mode 100644 index 0000000000000..b72640b853a33 --- /dev/null +++ b/RecoMTD/Navigation/src/MTDNavigationSchool.cc @@ -0,0 +1,379 @@ +/** \class MTDNavigationSchool + * + * Description: + * Navigation school for the MTD system + * This class defines which DetLayers are reacheable from each MTD DetLayer + * (BTL and ETL). The reacheableness is based on an eta range criteria. + * + * + * \author : L. Gray - FNAL + * + * Modification: + * + */ + +#include "RecoMTD/Navigation/interface/MTDNavigationSchool.h" + +/* Collaborating Class Header */ +#include "TrackingTools/DetLayers/interface/BarrelDetLayer.h" +#include "TrackingTools/DetLayers/interface/ForwardDetLayer.h" +#include "DataFormats/GeometrySurface/interface/BoundCylinder.h" +#include "DataFormats/GeometrySurface/interface/BoundDisk.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "RecoMTD/Navigation/interface/BTLNavigableLayer.h" +#include "RecoMTD/Navigation/interface/ETLNavigableLayer.h" +#include "RecoMTD/Navigation/interface/MTDEtaRange.h" +#include "RecoMTD/Navigation/interface/MTDDetLayerMap.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include +#include +using namespace std; + +/// Constructor +MTDNavigationSchool::MTDNavigationSchool(const MTDDetLayerGeometry * mtdLayout, bool enableBTL, bool enableETL ) : theMTDDetLayerGeometry(mtdLayout) { + + theAllDetLayersInSystem=&mtdLayout->allLayers(); + theAllNavigableLayer.resize(mtdLayout->allLayers().size(),nullptr); + + + + // get all barrel DetLayers (BTL) + vector barrel; + if ( enableBTL ) barrel = mtdLayout->allBarrelLayers(); + else barrel = mtdLayout->allBarrelLayers(); + + for ( auto i = barrel.begin(); i != barrel.end(); i++ ) { + const BarrelDetLayer* mbp = dynamic_cast(*i); + if ( mbp == nullptr ) throw cms::Exception("MTDNavigationSchool", "Bad BarrelDetLayer"); + addBarrelLayer(mbp); + } + + + // get all endcap DetLayers (ETL) + vector endcap; + if ( enableETL ) endcap = mtdLayout->allEndcapLayers(); + else endcap = mtdLayout->allEndcapLayers(); + + for ( auto i = endcap.begin(); i != endcap.end(); i++ ) { + const ForwardDetLayer* mep = dynamic_cast(*i); + if ( mep == nullptr ) throw cms::Exception("MTDNavigationSchool", "Bad ForwardDetLayer"); + addEndcapLayer(mep); + } + + // create outward links for all DetLayers + linkBarrelLayers(); + linkEndcapLayers(theForwardLayers,theForwardNLC); + linkEndcapLayers(theBackwardLayers,theBackwardNLC); + + // create inverse links + createInverseLinks(); + +} + + +/// Destructor +MTDNavigationSchool::~MTDNavigationSchool() { + + for_each(theBarrelNLC.begin(),theBarrelNLC.end(), delete_layer()); + for_each(theForwardNLC.begin(),theForwardNLC.end(), delete_layer()); + for_each(theBackwardNLC.begin(),theBackwardNLC.end(), delete_layer()); + +} + + +/// return all Navigable layers +MTDNavigationSchool::StateType +MTDNavigationSchool::navigableLayers() { + + StateType result; + + vector::const_iterator ib; + vector::const_iterator ie; + + for ( ib = theBarrelNLC.begin(); ib != theBarrelNLC.end(); ib++ ) { + result.push_back(*ib); + } + + for ( ie = theForwardNLC.begin(); ie != theForwardNLC.end(); ie++ ) { + result.push_back(*ie); + } + + for ( ie = theBackwardNLC.begin(); ie != theBackwardNLC.end(); ie++ ) { + result.push_back(*ie); + } + + return result; + +} + + +/// create barrel layer map +void MTDNavigationSchool::addBarrelLayer(const BarrelDetLayer* mbp) { + + const BoundCylinder& bc = mbp->specificSurface(); + float radius = bc.radius(); + float length = bc.bounds().length()/2.; + + float eta_max = calculateEta(radius, length); + float eta_min = -eta_max; + + theBarrelLayers[mbp] = MTDEtaRange(eta_max, eta_min); + +} + + +/// create forwrad/backward layer maps +void MTDNavigationSchool::addEndcapLayer(const ForwardDetLayer* mep) { + + const BoundDisk& bd = mep->specificSurface(); + float outRadius = bd.outerRadius(); + float inRadius = bd.innerRadius(); + float thick = bd.bounds().length()/2.; + float z = bd.position().z(); + + if ( z > 0. ) { + float eta_min = calculateEta(outRadius, z-thick); + float eta_max = calculateEta(inRadius, z+thick); + theForwardLayers[mep] = MTDEtaRange(eta_max, eta_min); + } else { + float eta_max = calculateEta(outRadius, z+thick); + float eta_min = calculateEta(inRadius, z-thick); + theBackwardLayers[mep] = MTDEtaRange(eta_max, eta_min); + } + +} + + +/// calculate pseudorapidity from r and z +float MTDNavigationSchool::calculateEta(const float& r, const float& z) const { + + if ( z > 0 ) return -log((tan(atan(r/z)/2.))); + return log(-(tan(atan(r/z)/2.))); + +} + +/// linking barrel layers outwards +void MTDNavigationSchool::linkBarrelLayers() { + + for (MapBI bl = theBarrelLayers.begin(); + bl != theBarrelLayers.end(); bl++) { + + MTDEtaRange range = (*bl).second; + + // first add next barrel layer + MapBI plusOne(bl); + plusOne++; + MapB outerBarrel; + MapB allOuterBarrel; + if ( plusOne != theBarrelLayers.end() ) { outerBarrel.insert(*plusOne);} + // add all outer barrel layers + for ( MapBI iMBI = plusOne; iMBI!= theBarrelLayers.end(); iMBI++){ + allOuterBarrel.insert(*iMBI); + } + // then add all compatible backward layers with an eta criteria + MapE allOuterBackward; + for (MapEI el = theBackwardLayers.begin(); + el != theBackwardLayers.end(); el++) { + if ( (*el).second.isCompatible(range) ) { + allOuterBackward.insert(*el); + } + } + //add the backward next layer with an eta criteria + MapE outerBackward; + for (MapEI el = theBackwardLayers.begin(); + el != theBackwardLayers.end(); el++) { + if ( (*el).second.isCompatible(range) ) { + outerBackward.insert(*el); + break; + } + } + + // then add all compatible forward layers with an eta criteria + MapE allOuterForward; + for (MapEI el = theForwardLayers.begin(); + el != theForwardLayers.end(); el++) { + if ( (*el).second.isCompatible(range) ) { + allOuterForward.insert(*el); + } + } + + // then add forward next layer with an eta criteria + MapE outerForward; + for (MapEI el = theForwardLayers.begin(); + el != theForwardLayers.end(); el++) { + if ( (*el).second.isCompatible(range) ) { + outerForward.insert(*el); + break; + } + } + + theBarrelNLC.push_back(new BTLNavigableLayer( + (*bl).first,outerBarrel, outerBackward, outerForward, + allOuterBarrel,allOuterBackward,allOuterForward)); + + } + +} +/// linking forward/backward layers outwards +void MTDNavigationSchool::linkEndcapLayers(const MapE& layers, + vector& result) { + + for (MapEI el = layers.begin(); el != layers.end(); el++) { + + MTDEtaRange range = (*el).second; + // first add next endcap layer (if compatible) + MapEI plusOne(el); + plusOne++; + MapE outerLayers; + if ( plusOne != layers.end() && (*plusOne).second.isCompatible(range) ) { + outerLayers.insert(*plusOne); + if ( !range.isInside((*plusOne).second) ) { + // then look if the next layer has a wider eta range, if so add it + MapEI tmpel(plusOne); + tmpel++; + MTDEtaRange max((*plusOne).second); + for ( MapEI l = tmpel; l != layers.end(); l++ ) { + MTDEtaRange next = (*l).second; + if ( next.isCompatible(max) && !range.isInside(next) && + !next.isInside(max) && next.subtract(max).isInside(range) ) { + max = max.add(next); + outerLayers.insert(*l); + } + } + } + } + + MapE allOuterLayers; + for (MapEI iMEI = plusOne; iMEI!=layers.end(); iMEI++){ + if ((*iMEI).second.isCompatible(range)) allOuterLayers.insert(*iMEI); + } + + result.push_back(new ETLNavigableLayer( + (*el).first,outerLayers, allOuterLayers)); + } + +} + + +/// create inverse links (i.e. inwards) +void MTDNavigationSchool::createInverseLinks() { + + // set outward link + // NavigationSetter setter(*this); + + setState(navigableLayers()); + + + // find for each layer which are the layers pointing to it + typedef map > BarrelMapType; + typedef map > ForwardMapType; + + // map of all DetLayers which can reach a specific DetLayer + BarrelMapType reachedBarrelLayersMap; + ForwardMapType reachedForwardLayersMap; + + // map of all DetLayers which is compatible with a specific DetLayer + BarrelMapType compatibleBarrelLayersMap; + ForwardMapType compatibleForwardLayersMap; + + // collect all reacheable layers starting from a barrel layer + for ( MapBI bli = theBarrelLayers.begin(); + bli != theBarrelLayers.end(); bli++ ) { + // barrel + BTLNavigableLayer* mbnl = + dynamic_cast(theAllNavigableLayer[((*bli).first)->seqNum()]); + MapB reacheableB = mbnl->getOuterBarrelLayers(); + for (MapBI i = reacheableB.begin(); i != reacheableB.end(); i++ ) { + reachedBarrelLayersMap[(*i).first].insert(*bli); + } + MapB compatibleB = mbnl->getAllOuterBarrelLayers(); + for (MapBI i = compatibleB.begin(); i != compatibleB.end(); i++ ) { + compatibleBarrelLayersMap[(*i).first].insert(*bli); + } + MapE reacheableE = mbnl->getOuterBackwardLayers(); + for (MapEI i = reacheableE.begin(); i != reacheableE.end(); i++ ) { + reachedBarrelLayersMap[(*i).first].insert(*bli); + } + reacheableE = mbnl->getOuterForwardLayers(); + for (MapEI i = reacheableE.begin(); i != reacheableE.end(); i++ ) { + reachedBarrelLayersMap[(*i).first].insert(*bli); + } + MapE compatibleE = mbnl->getAllOuterBackwardLayers(); + for (MapEI i = compatibleE.begin(); i != compatibleE.end(); i++ ) { + compatibleBarrelLayersMap[(*i).first].insert(*bli); + } + compatibleE = mbnl->getAllOuterForwardLayers(); + for (MapEI i = compatibleE.begin(); i != compatibleE.end(); i++ ) { + compatibleBarrelLayersMap[(*i).first].insert(*bli); + } + + } + + // collect all reacheable layer starting from a backward layer + for ( MapEI eli = theBackwardLayers.begin(); + eli != theBackwardLayers.end(); eli++ ) { + MapE reacheableE = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()])->getOuterEndcapLayers(); + for (MapEI i = reacheableE.begin(); i != reacheableE.end(); i++ ) { + reachedForwardLayersMap[(*i).first].insert(*eli); + } + // collect all compatible layer starting from a backward layer + MapE compatibleE = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()])->getAllOuterEndcapLayers(); + for (MapEI i = compatibleE.begin(); i != compatibleE.end(); i++ ) { + compatibleForwardLayersMap[(*i).first].insert(*eli); + } + } + + for ( MapEI eli = theForwardLayers.begin(); + eli != theForwardLayers.end(); eli++ ) { + // collect all reacheable layer starting from a forward layer + MapE reacheableE = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()])->getOuterEndcapLayers(); + for (MapEI i = reacheableE.begin(); i != reacheableE.end(); i++ ) { + reachedForwardLayersMap[(*i).first].insert(*eli); + } + // collect all compatible layer starting from a forward layer + MapE compatibleE = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()])->getAllOuterEndcapLayers(); + for (MapEI i = compatibleE.begin(); i != compatibleE.end(); i++ ) { + compatibleForwardLayersMap[(*i).first].insert(*eli); + } + } + + // now set inverse link for barrel layers + for ( MapBI bli = theBarrelLayers.begin(); + bli != theBarrelLayers.end(); bli++ ) { + BTLNavigableLayer* mbnl = + dynamic_cast(theAllNavigableLayer[((*bli).first)->seqNum()]); + mbnl->setInwardLinks(reachedBarrelLayersMap[(*bli).first]); + mbnl->setInwardCompatibleLinks(compatibleBarrelLayersMap[(*bli).first]); + + } + //BACKWARD + for ( MapEI eli = theBackwardLayers.begin(); + eli != theBackwardLayers.end(); eli++ ) { + ETLNavigableLayer* mfnl = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()]); + // for backward next layers + mfnl->setInwardLinks(reachedBarrelLayersMap[(*eli).first], + reachedForwardLayersMap[(*eli).first]); + // for backward compatible layers + mfnl->setInwardCompatibleLinks(compatibleBarrelLayersMap[(*eli).first], + compatibleForwardLayersMap[(*eli).first]); + } + //FORWARD + for ( MapEI eli = theForwardLayers.begin(); + eli != theForwardLayers.end(); eli++ ) { + ETLNavigableLayer* mfnl = + dynamic_cast(theAllNavigableLayer[((*eli).first)->seqNum()]); + // and for forward next layers + mfnl->setInwardLinks(reachedBarrelLayersMap[(*eli).first], + reachedForwardLayersMap[(*eli).first]); + // and for forward compatible layers + mfnl->setInwardCompatibleLinks(compatibleBarrelLayersMap[(*eli).first], + compatibleForwardLayersMap[(*eli).first]); + } + +} diff --git a/RecoMTD/Navigation/test/BuildFile.xml b/RecoMTD/Navigation/test/BuildFile.xml new file mode 100644 index 0000000000000..693b2ce1b1f3f --- /dev/null +++ b/RecoMTD/Navigation/test/BuildFile.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/RecoMTD/Navigation/test/MTDNavigationTest.cc b/RecoMTD/Navigation/test/MTDNavigationTest.cc new file mode 100644 index 0000000000000..79375fa24d900 --- /dev/null +++ b/RecoMTD/Navigation/test/MTDNavigationTest.cc @@ -0,0 +1,88 @@ +#include +/** \file MTDNavigationTest + * + * \author L. Gray + */ + + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "RecoMTD/Navigation/interface/MTDNavigationPrinter.h" +#include "RecoMTD/Navigation/interface/MTDNavigationSchool.h" +#include "RecoMTD/Records/interface/MTDRecoGeometryRecord.h" +#include "RecoMTD/Navigation/interface/MTDNavigationPrinter.h" +#include "RecoMTD/DetLayers/interface/MTDDetLayerGeometry.h" +#include "MagneticField/Records/interface/IdealMagneticFieldRecord.h" + +class MTDNavigationTest : public edm::EDAnalyzer { + public: + explicit MTDNavigationTest( const edm::ParameterSet& ); + ~MTDNavigationTest(); + + virtual void analyze( const edm::Event&, const edm::EventSetup& ); + private: +}; + +// constructor + +MTDNavigationTest::MTDNavigationTest( const edm::ParameterSet& iConfig ) +{ + std::cout<<"Muon Navigation Printer Begin:"< mtd; + iSetup.get().get(mtd); + const MTDDetLayerGeometry * mm(&(*mtd)); + + if ( testMuon ) { + MTDNavigationSchool school(mm); + MTDNavigationPrinter* printer = new MTDNavigationPrinter(mm, school ); + delete printer; + } +/* + if ( testMuonTk ) { + edm::ESHandle tracker; + iSetup.get().get(tracker); + + edm::ESHandle theMF; + iSetup.get().get(theMF); + + const GeometricSearchTracker * tt(&(*tracker)); + const MagneticField * field(&(*theMF)); + + MuonTkNavigationSchool school(mm,tt,field); + MTDNavigationPrinter* printer = new MTDNavigationPrinter(mm, tt); + delete printer; + } +*/ +} + +//define this as a plug-in +DEFINE_FWK_MODULE(MTDNavigationTest); + diff --git a/RecoMTD/Records/BuildFile.xml b/RecoMTD/Records/BuildFile.xml new file mode 100644 index 0000000000000..a3f7a5136c01c --- /dev/null +++ b/RecoMTD/Records/BuildFile.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/RecoMTD/Records/interface/MTDRecoGeometryRecord.h b/RecoMTD/Records/interface/MTDRecoGeometryRecord.h new file mode 100644 index 0000000000000..2dd10461d34ee --- /dev/null +++ b/RecoMTD/Records/interface/MTDRecoGeometryRecord.h @@ -0,0 +1,22 @@ +#ifndef RecoMTD_Record_MTDRecoGeometryRecord_h +#define RecoMTD_Record_MTDRecoGeometryRecord_h + +/** \class MTDRecoGeometryRecord + * + * Record to hold mtd reconstruction geometries. + * + * \author L. Gray - FNAL + */ + +#include "FWCore/Framework/interface/EventSetupRecordImplementation.h" +#include "FWCore/Framework/interface/DependentRecordImplementation.h" +#include "Geometry/Records/interface/MTDDigiGeometryRecord.h" + +#include "boost/mpl/vector.hpp" + + +class MTDRecoGeometryRecord : public edm::eventsetup::DependentRecordImplementation > {}; + +#endif + diff --git a/RecoMTD/Records/src/MTDRecoGeometryRecord.cc b/RecoMTD/Records/src/MTDRecoGeometryRecord.cc new file mode 100644 index 0000000000000..57cb3093772e8 --- /dev/null +++ b/RecoMTD/Records/src/MTDRecoGeometryRecord.cc @@ -0,0 +1,4 @@ +#include "RecoMTD/Records/interface/MTDRecoGeometryRecord.h" +#include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h" + +EVENTSETUP_RECORD_REG(MTDRecoGeometryRecord); diff --git a/RecoMuon/DetLayers/src/GeneralBinFinderInPhi.h b/RecoMuon/DetLayers/src/GeneralBinFinderInPhi.h index 3f5007928fb88..1573ce2fb9953 100644 --- a/RecoMuon/DetLayers/src/GeneralBinFinderInPhi.h +++ b/RecoMuon/DetLayers/src/GeneralBinFinderInPhi.h @@ -1,103 +1 @@ -#ifndef GeneralBinFinderInPhi_H -#define GeneralBinFinderInPhi_H - -/** \class GeneralBinFinderInPhi - * A phi bin finder for a non-periodic group of detectors. - * - * \author N. Amapane - INFN Torino - */ - -#include "Utilities/BinningTools/interface/BaseBinFinder.h" -#include "PhiBorderFinder.h" -#include "DataFormats/GeometryVector/interface/Pi.h" -#include "FWCore/MessageLogger/interface/MessageLogger.h" - -#include - -template -class GeneralBinFinderInPhi : public BaseBinFinder { -public: - - typedef PhiBorderFinder::Det Det; //FIXME!!! - - GeneralBinFinderInPhi() : theNbins(0) {} - - /// Construct from an already initialized PhiBorderFinder - GeneralBinFinderInPhi(const PhiBorderFinder& bf) { - theBorders=bf.phiBorders(); - theBins=bf.phiBins(); - theNbins=theBins.size(); - } - - /// Construct from the list of Det* - GeneralBinFinderInPhi(std::vector::const_iterator first, - std::vector::const_iterator last) - : theNbins( last-first) - { - std::vector dets(first,last); - PhiBorderFinder bf(dets); - theBorders=bf.phiBorders(); - theBins=bf.phiBins(); - theNbins=theBins.size(); - } - - ~GeneralBinFinderInPhi() override{}; - - /// Returns an index in the valid range for the bin that contains - /// AND is closest to phi - int binIndex( T phi) const override { - - const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|GeneralBinFinderInPhi"; - - static const T epsilon = 10*std::numeric_limits::epsilon(); - // Assume -pi, pi range in pi (which is the case for Geom::Phi - - LogTrace(metname) << "GeneralBinFinderInPhi::binIndex," - << " Nbins: "<< theNbins; - - for (int i = 0; i< theNbins; i++) { - - T cur = theBorders[i]; - T next = theBorders[binIndex(i+1)]; - T phi_ = phi; - - LogTrace(metname) << "bin: " << i - << " border min " << cur << " border max: " << next << " phi: "<< phi_; - - if ( cur > next ) // we are crossing the pi edge: so move the edge to 0! - { - cur = positiveRange(cur); - next = positiveRange(next); - phi_ = positiveRange(phi_); - } - if (phi_ > cur-epsilon && phi_ < next) return i; - } - throw cms::Exception("UnexpectedState") << "GeneralBinFinderInPhi::binIndex( T phi) bin not found!"; - } - - /// Returns an index in the valid range, modulo Nbins - int binIndex( int i) const override { - int ind = i % (int)theNbins; - return (ind < 0) ? ind+theNbins : ind; - } - - /// the middle of the bin in radians - T binPosition( int ind) const override { - return theBins[binIndex(ind)]; - } - - -private: - int theNbins; - std::vector theBorders; - std::vector theBins; - - // returns a positive angle; does NOT reduce the range to 2 pi - inline T positiveRange (T phi) const - { - return (phi > 0) ? phi : phi + Geom::twoPi(); - } - -}; -#endif - +#include "TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h" diff --git a/RecoMuon/DetLayers/src/GeneralBinFinderInR.h b/RecoMuon/DetLayers/src/GeneralBinFinderInR.h index 7f6d176729537..12ca216def555 100644 --- a/RecoMuon/DetLayers/src/GeneralBinFinderInR.h +++ b/RecoMuon/DetLayers/src/GeneralBinFinderInR.h @@ -1,74 +1 @@ -#ifndef GeneralBinFinderInR_H -#define GeneralBinFinderInR_H - -/** \class GeneralBinFinderInR - * A R binfinder for a non-periodic group of detectors. - * - * \author N. Amapane - INFN Torino - */ - -#include -#include "RBorderFinder.h" - -#include -#include - -template -class GeneralBinFinderInR : public BaseBinFinder{ -public: - - typedef RBorderFinder::Det Det; //FIXME!!! - - GeneralBinFinderInR() : theNbins(0) {} - - /// Construct from an already initialized RBorderFinder - GeneralBinFinderInR(const RBorderFinder& bf) { - theBorders=bf.RBorders(); - theBins=bf.RBins(); - theNbins=theBins.size(); - } - - /// Construct from the list of Det* - GeneralBinFinderInR(std::vector::const_iterator first, - std::vector::const_iterator last) - : theNbins( last-first) - { - std::vector dets(first,last); - RBorderFinder bf(dets); - theBorders=bf.RBorders(); - theBins=bf.RBins(); - theNbins=theBins.size(); - } - - - /// Returns an index in the valid range for the bin that contains - /// AND is closest to R - int binIndex( T R) const override { - int i; - for (i = 0; i theBorders; - std::vector theBins; - -}; -#endif - +#include "TrackingTools/DetLayers/interface/GeneralBinFinderInR.h" diff --git a/RecoMuon/DetLayers/src/PhiBorderFinder.h b/RecoMuon/DetLayers/src/PhiBorderFinder.h index fdde0a6ac3a7a..d8e47e0df84f9 100644 --- a/RecoMuon/DetLayers/src/PhiBorderFinder.h +++ b/RecoMuon/DetLayers/src/PhiBorderFinder.h @@ -1,169 +1 @@ -#ifndef PhiBorderFinder_H -#define PhiBorderFinder_H - -/** \class PhiBorderFinder - * Find the phi binning of a list of detector according to several - * definitions. - * - * \author N. Amapane - INFN Torino - */ - - -#include - -#include -#include - -#include -#include -#include -#include -#include - -// FIXME: remove this include -#include "FWCore/MessageLogger/interface/MessageLogger.h" - -#include - -class PhiBorderFinder { -public: - - typedef DetRod Det; //FIXME!!! - typedef geomsort::ExtractPhi DetPhi; - - - PhiBorderFinder(const std::vector& utheDets) - : theNbins(utheDets.size()), isPhiPeriodic_(false), isPhiOverlapping_(false) { - std::vector theDets = utheDets; - precomputed_value_sort(theDets.begin(), theDets.end(), DetPhi()); - - const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|PhiBorderFinder"; - - double step = 2.*Geom::pi()/theNbins; - - LogTrace(metname) << "RecoMuonDetLayers::PhiBorderFinder " - << "step w: " << step << " # of bins: " << theNbins; - - std::vector spread(theNbins); - std::vector > phiEdge; - phiEdge.reserve(theNbins); - thePhiBorders.reserve(theNbins); - thePhiBins.reserve(theNbins); - for ( unsigned int i = 0; i < theNbins; i++ ) { - thePhiBins.push_back(theDets[i]->position().phi()); - spread.push_back(theDets[i]->position().phi() - - (theDets[0]->position().phi() + i*step)); - - LogTrace(metname) << "bin: " << i << " phi bin: " << thePhiBins[i] - << " spread: " << spread[i]; - - - ConstReferenceCountingPointer plane = - dynamic_cast(&theDets[i]->surface()); - if (plane==nullptr) { - //FIXME - throw cms::Exception("UnexpectedState") << ("PhiBorderFinder: det surface is not a BoundPlane"); - } - - std::vector dc = - BoundingBox().corners(*plane); - - float phimin(999.), phimax(-999.); - for (std::vector::const_iterator pt=dc.begin(); - pt!=dc.end(); pt++) { - float phi = (*pt).phi(); -// float z = pt->z(); - if (phi < phimin) phimin = phi; - if (phi > phimax) phimax = phi; - } - if (phimin*phimax < 0. && //Handle pi border: - phimax - phimin > Geom::pi()) { //Assume that the Det is on - //the shortest side - std::swap(phimin,phimax); - } - phiEdge.push_back(std::pair(phimin,phimax)); - } - - for (unsigned int i = 0; i < theNbins; i++) { - - // Put the two phi values in the [0,2pi] range - double firstPhi = positiveRange(phiEdge[i].first); - double secondPhi = positiveRange(phiEdge[binIndex(i-1)].second); - - // Reformat them in the [-pi,pi] range - Geom::Phi firstEdge(firstPhi); - Geom::Phi secondEdge(secondPhi); - - // Calculate the mean and format the result in the [-pi,pi] range - // Get their value in order to perform the mean in the correct way - Geom::Phi mean((firstEdge.value() + secondEdge.value())/2.); - - // Special case: at +-pi there is a discontinuity - if ( phiEdge[i].first * phiEdge[binIndex(i-1)].second < 0 && - fabs(firstPhi-secondPhi) < Geom::pi() ) - mean = Geom::pi() - mean; - - thePhiBorders.push_back(mean); - } - - for (unsigned int i = 0; i < theNbins; i++) { - if (Geom::Phi(phiEdge[i].first) - - Geom::Phi(phiEdge[binIndex(i-1)].second) < 0) { - isPhiOverlapping_ = true; - break; - } - } - - double rms = stat_RMS(spread); - if ( rms < 0.01*step) { - isPhiPeriodic_ = true; - } - - //Check that everything is proper - if (thePhiBorders.size() != theNbins || thePhiBins.size() != theNbins) - //FIXME - throw cms::Exception("UnexpectedState") << "PhiBorderFinder: consistency error"; - } - - - virtual ~PhiBorderFinder(){}; - - inline unsigned int nBins() {return theNbins;} - - /// Returns true if the Dets are periodic in phi. - inline bool isPhiPeriodic() const { return isPhiPeriodic_; } - - /// Returns true if any 2 of the Det overlap in phi. - inline bool isPhiOverlapping() const { return isPhiOverlapping_; } - - /// The borders, defined for each det as the middle between its lower - /// edge and the previous Det's upper edge. - inline const std::vector& phiBorders() const { return thePhiBorders; } - - /// The centers of the Dets. - inline const std::vector& phiBins() const { return thePhiBins; } - - // inline std::vector etaBorders() {} - // inline std::vector zBorders() {} - -private: - unsigned int theNbins; - bool isPhiPeriodic_; - bool isPhiOverlapping_; - std::vector thePhiBorders; - std::vector thePhiBins; - - inline double positiveRange (double phi) const - { - return (phi > 0) ? phi : phi + Geom::twoPi(); - } - - int binIndex( int i) const { - int ind = i % (int)theNbins; - return (ind < 0) ? ind+theNbins : ind; - } - - -}; -#endif - +#include "TrackingTools/DetLayers/interface/PhiBorderFinder.h" diff --git a/RecoMuon/DetLayers/src/RBorderFinder.h b/RecoMuon/DetLayers/src/RBorderFinder.h index d7ef265e5d435..1a6fa2c81d6bc 100644 --- a/RecoMuon/DetLayers/src/RBorderFinder.h +++ b/RecoMuon/DetLayers/src/RBorderFinder.h @@ -1,188 +1 @@ -#ifndef RBorderFinder_H -#define RBorderFinder_H - -/** \class RBorderFinder - * Find the R binning of a list of detector according to several - * definitions. - * - * \author N. Amapane - INFN Torino - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include -//#include - -class RBorderFinder { -public: - - typedef ForwardDetRing Det; //FIXME!!! - typedef geomsort::ExtractR DetR; - - RBorderFinder(const std::vector& utheDets) - : theNbins(utheDets.size()), isRPeriodic_(false), isROverlapping_(false) - { - std::vector theDets = utheDets; - precomputed_value_sort(theDets.begin(), theDets.end(), DetR()); - - std::vector > disks(theNbins); - for ( int i = 0; i < theNbins; i++ ) { - disks[i] = - dynamic_cast (&(theDets[i]->surface())); - if (disks[i]==nullptr) { - throw cms::Exception("UnexpectedState") << "RBorderFinder: implemented for BoundDisks only"; - } - } - - - if (theNbins==1) { // Trivial case - isRPeriodic_ = true; // meaningless in this case - theRBorders.push_back(disks.front()->innerRadius()); - theRBins.push_back((disks.front()->outerRadius()+disks.front()->innerRadius())); -// std::cout << "RBorderFinder: theNbins " << theNbins << std::endl -// << " C: " << theRBins[0] -// << " Border: " << theRBorders[0] << std::endl; - } else { // More than 1 bin - double step = (disks.back()->innerRadius() - - disks.front()->innerRadius())/(theNbins-1); - std::vector spread; - std::vector > REdge; - REdge.reserve(theNbins); - theRBorders.reserve(theNbins); - theRBins.reserve(theNbins); - spread.reserve(theNbins); - - for ( int i = 0; i < theNbins; i++ ) { - theRBins.push_back((disks[i]->outerRadius()+disks[i]->innerRadius())/2.); - spread.push_back(theRBins.back() - (theRBins[0] + i*step)); - REdge.push_back(std::pair(disks[i]->innerRadius(), - disks[i]->outerRadius())); - } - - theRBorders.push_back(REdge[0].first); - for (int i = 1; i < theNbins; i++) { - // Average borders of previous and next bins - double br = (REdge[(i-1)].second + REdge[i].first)/2.; - theRBorders.push_back(br); - } - - for (int i = 1; i < theNbins; i++) { - if (REdge[i].first - REdge[i-1].second < 0) { - isROverlapping_ = true; - break; - } - } - - double rms = stat_RMS(spread); - if ( rms < 0.01*step) { - isRPeriodic_ = true; - } - -// std::cout << "RBorderFinder: theNbins " << theNbins -// << " step: " << step << " RMS " << rms << std::endl; -// for (int idbg = 0; idbg < theNbins; idbg++) { -// std::cout << "L: " << REdge[idbg].first -// << " C: " << theRBins[idbg] -// << " R: " << REdge[idbg].second -// << " Border: " << theRBorders[idbg] -// << " SP: " << spread[idbg] << std::endl; -// } - } - - //Check that everything is proper - if ((int)theRBorders.size() != theNbins || (int)theRBins.size() != theNbins) - throw cms::Exception("UnexpectedState") << "RBorderFinder consistency error"; -} - - // Construct from a std::vector of Det*. - // Not tested, and do not work if the Dets are rings since - // position().perp() gives 0... -// RBorderFinder(std::vector theDets) -// : theNbins(theDets.size()), isRPeriodic_(false), isROverlapping_(false) -// { -// sort(theDets.begin(), theDets.end(), DetLessR()); - -// double step = (theDets.back()->position().perp() - -// theDets.front()->position().perp())/(theNbins-1); -// std::vector spread(theNbins); -// std::vector > REdge; -// REdge.reserve(theNbins); -// theRBorders.reserve(theNbins); -// theRBins.reserve(theNbins); -// for ( int i = 0; i < theNbins; i++ ) { -// theRBins.push_back(theDets[i]->position().perp()); -// spread.push_back(theDets[i]->position().perp() -// - (theDets[0]->position().perp() + i*step)); - -// const BoundPlane * plane = -// dynamic_cast(&theDets[i]->surface()); -// if (plane==0) { -// throw DetLogicError("RBorderFinder: det surface is not a BoundPlane"); -// } - -// std::vector dc = -// BoundingBox().corners(*plane); - -// float rmin(dc.front().perp()); -// float rmax(rmin); -// for (std::vector::const_iterator pt=dc.begin(); -// pt!=dc.end(); pt++) { -// float r = (*pt).perp(); -// // float z = pt->z(); -// rmin = min( rmin, r); -// rmax = max( rmax, r); -// } - -// // in addition to the corners we have to check the middle of the -// // det +/- length/2 since the min (max) radius for typical fw dets -// // is reached there -// float rdet = theDets[i]->position().perp(); -// float len = theDets[i]->surface().bounds().length(); -// rmin = min( rmin, rdet-len/2.F); -// // theRmax = max( theRmax, rdet+len/2.F); - -// REdge.push_back(make_std::pair(rmin,rmax)); -// } -// // ... -// } - - - virtual ~RBorderFinder(){}; - - /// Returns true if the Dets are periodic in R. - inline bool isRPeriodic() const { return isRPeriodic_; } - - /// Returns true if any 2 of the Det overlap in R. - inline bool isROverlapping() const { return isROverlapping_; } - - /// The borders, defined for each det as the middle between its lower - /// edge and the previous Det's upper edge. - inline std::vector RBorders() const { return theRBorders; } - - /// The centers of the Dets. - inline std::vector RBins() const { return theRBins; } - - // inline std::vector etaBorders() {} - // inline std::vector zBorders() {} - - -private: - int theNbins; - bool isRPeriodic_; - bool isROverlapping_; - std::vector theRBorders; - std::vector theRBins; - - inline int binIndex( int i) const { - return std::min( std::max( i, 0), theNbins-1); - } -}; -#endif - +#include "TrackingTools/DetLayers/interface/RBorderFinder.h" diff --git a/TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h b/TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h new file mode 100644 index 0000000000000..e359f57b05f37 --- /dev/null +++ b/TrackingTools/DetLayers/interface/GeneralBinFinderInPhi.h @@ -0,0 +1,103 @@ +#ifndef TrackingTools_DetLayers_GeneralBinFinderInPhi_H +#define TrackingTools_DetLayers_GeneralBinFinderInPhi_H + +/** \class GeneralBinFinderInPhi + * A phi bin finder for a non-periodic group of detectors. + * + * \author N. Amapane - INFN Torino + */ + +#include "Utilities/BinningTools/interface/BaseBinFinder.h" +#include "TrackingTools/DetLayers/interface/PhiBorderFinder.h" +#include "DataFormats/GeometryVector/interface/Pi.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include + +template +class GeneralBinFinderInPhi : public BaseBinFinder { +public: + + typedef PhiBorderFinder::Det Det; //FIXME!!! + + GeneralBinFinderInPhi() : theNbins(0) {} + + /// Construct from an already initialized PhiBorderFinder + GeneralBinFinderInPhi(const PhiBorderFinder& bf) { + theBorders=bf.phiBorders(); + theBins=bf.phiBins(); + theNbins=theBins.size(); + } + + /// Construct from the list of Det* + GeneralBinFinderInPhi(std::vector::const_iterator first, + std::vector::const_iterator last) + : theNbins( last-first) + { + std::vector dets(first,last); + PhiBorderFinder bf(dets); + theBorders=bf.phiBorders(); + theBins=bf.phiBins(); + theNbins=theBins.size(); + } + + ~GeneralBinFinderInPhi() override{}; + + /// Returns an index in the valid range for the bin that contains + /// AND is closest to phi + int binIndex( T phi) const override { + + const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|GeneralBinFinderInPhi"; + + static const T epsilon = 10*std::numeric_limits::epsilon(); + // Assume -pi, pi range in pi (which is the case for Geom::Phi + + LogTrace(metname) << "GeneralBinFinderInPhi::binIndex," + << " Nbins: "<< theNbins; + + for (int i = 0; i< theNbins; i++) { + + T cur = theBorders[i]; + T next = theBorders[binIndex(i+1)]; + T phi_ = phi; + + LogTrace(metname) << "bin: " << i + << " border min " << cur << " border max: " << next << " phi: "<< phi_; + + if ( cur > next ) // we are crossing the pi edge: so move the edge to 0! + { + cur = positiveRange(cur); + next = positiveRange(next); + phi_ = positiveRange(phi_); + } + if (phi_ > cur-epsilon && phi_ < next) return i; + } + throw cms::Exception("UnexpectedState") << "GeneralBinFinderInPhi::binIndex( T phi) bin not found!"; + } + + /// Returns an index in the valid range, modulo Nbins + int binIndex( int i) const override { + int ind = i % (int)theNbins; + return (ind < 0) ? ind+theNbins : ind; + } + + /// the middle of the bin in radians + T binPosition( int ind) const override { + return theBins[binIndex(ind)]; + } + + +private: + int theNbins; + std::vector theBorders; + std::vector theBins; + + // returns a positive angle; does NOT reduce the range to 2 pi + inline T positiveRange (T phi) const + { + return (phi > 0) ? phi : phi + Geom::twoPi(); + } + +}; +#endif + diff --git a/TrackingTools/DetLayers/interface/GeneralBinFinderInR.h b/TrackingTools/DetLayers/interface/GeneralBinFinderInR.h new file mode 100644 index 0000000000000..53b8b8e7ac437 --- /dev/null +++ b/TrackingTools/DetLayers/interface/GeneralBinFinderInR.h @@ -0,0 +1,74 @@ +#ifndef TrackingTools_DetLayers_GeneralBinFinderInR_H +#define TrackingTools_DetLayers_GeneralBinFinderInR_H + +/** \class GeneralBinFinderInR + * A R binfinder for a non-periodic group of detectors. + * + * \author N. Amapane - INFN Torino + */ + +#include +#include "TrackingTools/DetLayers/interface/RBorderFinder.h" + +#include +#include + +template +class GeneralBinFinderInR : public BaseBinFinder{ +public: + + typedef RBorderFinder::Det Det; //FIXME!!! + + GeneralBinFinderInR() : theNbins(0) {} + + /// Construct from an already initialized RBorderFinder + GeneralBinFinderInR(const RBorderFinder& bf) { + theBorders=bf.RBorders(); + theBins=bf.RBins(); + theNbins=theBins.size(); + } + + /// Construct from the list of Det* + GeneralBinFinderInR(std::vector::const_iterator first, + std::vector::const_iterator last) + : theNbins( last-first) + { + std::vector dets(first,last); + RBorderFinder bf(dets); + theBorders=bf.RBorders(); + theBins=bf.RBins(); + theNbins=theBins.size(); + } + + + /// Returns an index in the valid range for the bin that contains + /// AND is closest to R + int binIndex( T R) const override { + int i; + for (i = 0; i theBorders; + std::vector theBins; + +}; +#endif + diff --git a/TrackingTools/DetLayers/interface/PhiBorderFinder.h b/TrackingTools/DetLayers/interface/PhiBorderFinder.h new file mode 100644 index 0000000000000..c0bf486908222 --- /dev/null +++ b/TrackingTools/DetLayers/interface/PhiBorderFinder.h @@ -0,0 +1,77 @@ +#ifndef TrackingTools_DetLayers_PhiBorderFinder_H +#define TrackingTools_DetLayers_PhiBorderFinder_H + +/** \class PhiBorderFinder + * Find the phi binning of a list of detector according to several + * definitions. + * + * \author N. Amapane - INFN Torino + */ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + +// FIXME: remove this include +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include + +class PhiBorderFinder { +public: + + typedef DetRod Det; //FIXME!!! + typedef geomsort::ExtractPhi DetPhi; + + + PhiBorderFinder(const std::vector& utheDets); + + virtual ~PhiBorderFinder(){}; + + inline unsigned int nBins() {return theNbins;} + + /// Returns true if the Dets are periodic in phi. + inline bool isPhiPeriodic() const { return isPhiPeriodic_; } + + /// Returns true if any 2 of the Det overlap in phi. + inline bool isPhiOverlapping() const { return isPhiOverlapping_; } + + /// The borders, defined for each det as the middle between its lower + /// edge and the previous Det's upper edge. + inline const std::vector& phiBorders() const { return thePhiBorders; } + + /// The centers of the Dets. + inline const std::vector& phiBins() const { return thePhiBins; } + + // inline std::vector etaBorders() {} + // inline std::vector zBorders() {} + +private: + unsigned int theNbins; + bool isPhiPeriodic_; + bool isPhiOverlapping_; + std::vector thePhiBorders; + std::vector thePhiBins; + + inline double positiveRange (double phi) const + { + return (phi > 0) ? phi : phi + Geom::twoPi(); + } + + int binIndex( int i) const { + int ind = i % (int)theNbins; + return (ind < 0) ? ind+theNbins : ind; + } + + +}; +#endif + diff --git a/TrackingTools/DetLayers/interface/RBorderFinder.h b/TrackingTools/DetLayers/interface/RBorderFinder.h new file mode 100644 index 0000000000000..2a380c975a89e --- /dev/null +++ b/TrackingTools/DetLayers/interface/RBorderFinder.h @@ -0,0 +1,61 @@ +#ifndef TrackingTools_DetLayers_RBorderFinder_H +#define TrackingTools_DetLayers_RBorderFinder_H + +/** \class RBorderFinder + * Find the R binning of a list of detector according to several + * definitions. + * + * \author N. Amapane - INFN Torino + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +class RBorderFinder { +public: + + typedef ForwardDetRing Det; //FIXME!!! + typedef geomsort::ExtractR DetR; + + RBorderFinder(const std::vector& utheDets); + + virtual ~RBorderFinder(){}; + + /// Returns true if the Dets are periodic in R. + inline bool isRPeriodic() const { return isRPeriodic_; } + + /// Returns true if any 2 of the Det overlap in R. + inline bool isROverlapping() const { return isROverlapping_; } + + /// The borders, defined for each det as the middle between its lower + /// edge and the previous Det's upper edge. + inline std::vector RBorders() const { return theRBorders; } + + /// The centers of the Dets. + inline std::vector RBins() const { return theRBins; } + + // inline std::vector etaBorders() {} + // inline std::vector zBorders() {} + + +private: + int theNbins; + bool isRPeriodic_; + bool isROverlapping_; + std::vector theRBorders; + std::vector theRBins; + + inline int binIndex( int i) const { + return std::min( std::max( i, 0), theNbins-1); + } +}; +#endif + diff --git a/TrackingTools/DetLayers/src/PhiBorderFinder.cc b/TrackingTools/DetLayers/src/PhiBorderFinder.cc new file mode 100644 index 0000000000000..49b0483d3981c --- /dev/null +++ b/TrackingTools/DetLayers/src/PhiBorderFinder.cc @@ -0,0 +1,96 @@ +#include "TrackingTools/DetLayers/interface/PhiBorderFinder.h" + +PhiBorderFinder::PhiBorderFinder(const std::vector& utheDets) + : theNbins(utheDets.size()), + isPhiPeriodic_(false), + isPhiOverlapping_(false) { + std::vector theDets = utheDets; + precomputed_value_sort(theDets.begin(), theDets.end(), DetPhi()); + + const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|PhiBorderFinder"; + + double step = 2.*Geom::pi()/theNbins; + + LogTrace(metname) << "RecoMuonDetLayers::PhiBorderFinder " + << "step w: " << step << " # of bins: " << theNbins; + + std::vector spread(theNbins); + std::vector > phiEdge; + phiEdge.reserve(theNbins); + thePhiBorders.reserve(theNbins); + thePhiBins.reserve(theNbins); + for ( unsigned int i = 0; i < theNbins; i++ ) { + thePhiBins.push_back(theDets[i]->position().phi()); + spread.push_back(theDets[i]->position().phi() + - (theDets[0]->position().phi() + i*step)); + + LogTrace(metname) << "bin: " << i << " phi bin: " << thePhiBins[i] + << " spread: " << spread[i]; + + + ConstReferenceCountingPointer plane = + dynamic_cast(&theDets[i]->surface()); + if (plane==nullptr) { + //FIXME + throw cms::Exception("UnexpectedState") << ("PhiBorderFinder: det surface is not a BoundPlane"); + } + + std::vector dc = + BoundingBox().corners(*plane); + + float phimin(999.), phimax(-999.); + for (std::vector::const_iterator pt=dc.begin(); + pt!=dc.end(); pt++) { + float phi = (*pt).phi(); + // float z = pt->z(); + if (phi < phimin) phimin = phi; + if (phi > phimax) phimax = phi; + } + if (phimin*phimax < 0. && //Handle pi border: + phimax - phimin > Geom::pi()) { //Assume that the Det is on + //the shortest side + std::swap(phimin,phimax); + } + phiEdge.push_back(std::pair(phimin,phimax)); + } + + for (unsigned int i = 0; i < theNbins; i++) { + + // Put the two phi values in the [0,2pi] range + double firstPhi = positiveRange(phiEdge[i].first); + double secondPhi = positiveRange(phiEdge[binIndex(i-1)].second); + + // Reformat them in the [-pi,pi] range + Geom::Phi firstEdge(firstPhi); + Geom::Phi secondEdge(secondPhi); + + // Calculate the mean and format the result in the [-pi,pi] range + // Get their value in order to perform the mean in the correct way + Geom::Phi mean((firstEdge.value() + secondEdge.value())/2.); + + // Special case: at +-pi there is a discontinuity + if ( phiEdge[i].first * phiEdge[binIndex(i-1)].second < 0 && + fabs(firstPhi-secondPhi) < Geom::pi() ) + mean = Geom::pi() - mean; + + thePhiBorders.push_back(mean); + } + + for (unsigned int i = 0; i < theNbins; i++) { + if (Geom::Phi(phiEdge[i].first) + - Geom::Phi(phiEdge[binIndex(i-1)].second) < 0) { + isPhiOverlapping_ = true; + break; + } + } + + double rms = stat_RMS(spread); + if ( rms < 0.01*step) { + isPhiPeriodic_ = true; + } + + //Check that everything is proper + if (thePhiBorders.size() != theNbins || thePhiBins.size() != theNbins) + //FIXME + throw cms::Exception("UnexpectedState") << "PhiBorderFinder: consistency error"; +} diff --git a/TrackingTools/DetLayers/src/RBorderFinder.cc b/TrackingTools/DetLayers/src/RBorderFinder.cc new file mode 100644 index 0000000000000..76901c81c6a22 --- /dev/null +++ b/TrackingTools/DetLayers/src/RBorderFinder.cc @@ -0,0 +1,68 @@ +#include "TrackingTools/DetLayers/interface/RBorderFinder.h" + +RBorderFinder::RBorderFinder(const std::vector& utheDets) + : theNbins(utheDets.size()), + isRPeriodic_(false), + isROverlapping_(false) +{ + std::vector theDets = utheDets; + precomputed_value_sort(theDets.begin(), theDets.end(), DetR()); + + std::vector > disks(theNbins); + for ( int i = 0; i < theNbins; i++ ) { + disks[i] = + dynamic_cast (&(theDets[i]->surface())); + if (disks[i]==nullptr) { + throw cms::Exception("UnexpectedState") << "RBorderFinder: implemented for BoundDisks only"; + } + } + + + if (theNbins==1) { // Trivial case + isRPeriodic_ = true; // meaningless in this case + theRBorders.push_back(disks.front()->innerRadius()); + theRBins.push_back((disks.front()->outerRadius()+disks.front()->innerRadius())); + // std::cout << "RBorderFinder: theNbins " << theNbins << std::endl + // << " C: " << theRBins[0] + // << " Border: " << theRBorders[0] << std::endl; + } else { // More than 1 bin + double step = (disks.back()->innerRadius() - + disks.front()->innerRadius())/(theNbins-1); + std::vector spread; + std::vector > REdge; + REdge.reserve(theNbins); + theRBorders.reserve(theNbins); + theRBins.reserve(theNbins); + spread.reserve(theNbins); + + for ( int i = 0; i < theNbins; i++ ) { + theRBins.push_back((disks[i]->outerRadius()+disks[i]->innerRadius())/2.); + spread.push_back(theRBins.back() - (theRBins[0] + i*step)); + REdge.push_back(std::pair(disks[i]->innerRadius(), + disks[i]->outerRadius())); + } + + theRBorders.push_back(REdge[0].first); + for (int i = 1; i < theNbins; i++) { + // Average borders of previous and next bins + double br = (REdge[(i-1)].second + REdge[i].first)/2.; + theRBorders.push_back(br); + } + + for (int i = 1; i < theNbins; i++) { + if (REdge[i].first - REdge[i-1].second < 0) { + isROverlapping_ = true; + break; + } + } + + double rms = stat_RMS(spread); + if ( rms < 0.01*step) { + isRPeriodic_ = true; + } + } + + //Check that everything is proper + if ((int)theRBorders.size() != theNbins || (int)theRBins.size() != theNbins) + throw cms::Exception("UnexpectedState") << "RBorderFinder consistency error"; +}