diff --git a/RecoTracker/LST/plugins/alpaka/LSTModulesDevESProducer.cc b/RecoTracker/LST/plugins/alpaka/LSTModulesDevESProducer.cc index 7152da9ed13c7..618b10b6ec09d 100644 --- a/RecoTracker/LST/plugins/alpaka/LSTModulesDevESProducer.cc +++ b/RecoTracker/LST/plugins/alpaka/LSTModulesDevESProducer.cc @@ -1,5 +1,6 @@ // LST includes #include "RecoTracker/LSTCore/interface/alpaka/LST.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" @@ -14,22 +15,25 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { class LSTModulesDevESProducer : public ESProducer { private: - std::string ptCutLabel_; + double ptCut_; + edm::ESGetToken lstGeoToken_; public: LSTModulesDevESProducer(edm::ParameterSet const& iConfig) - : ESProducer(iConfig), ptCutLabel_(iConfig.getParameter("ptCutLabel")) { - setWhatProduced(this, ptCutLabel_); + : ESProducer(iConfig), ptCut_(iConfig.getParameter("ptCut")) { + auto cc = setWhatProduced(this, "LSTModuleMaps"); + lstGeoToken_ = cc.consumes(edm::ESInputTag("", "LSTGeometry")); } static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) { edm::ParameterSetDescription desc; - desc.add("ptCutLabel", "0.8"); + desc.add("ptCut", 0.8); descriptions.addWithDefaultLabel(desc); } std::unique_ptr> produce(TrackerRecoGeometryRecord const& iRecord) { - return lst::loadAndFillESHost(ptCutLabel_); + const auto& lstg = iRecord.get(lstGeoToken_); + return lst::loadAndFillESHost(lstg); } }; diff --git a/RecoTracker/LST/plugins/alpaka/LSTProducer.cc b/RecoTracker/LST/plugins/alpaka/LSTProducer.cc index 496c1ae1182b0..eed5fb75c9427 100644 --- a/RecoTracker/LST/plugins/alpaka/LSTProducer.cc +++ b/RecoTracker/LST/plugins/alpaka/LSTProducer.cc @@ -26,7 +26,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { LSTProducer(edm::ParameterSet const& config) : EDProducer(config), lstInputToken_{consumes(config.getParameter("lstInput"))}, - lstESToken_{esConsumes(edm::ESInputTag("", config.getParameter("ptCutLabel")))}, + lstESToken_{esConsumes(edm::ESInputTag("", "LSTModuleMaps"))}, verbose_(config.getParameter("verbose")), ptCut_(config.getParameter("ptCut")), clustSizeCut_(static_cast(config.getParameter("clustSizeCut"))), @@ -42,7 +42,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { lst.run(iEvent.queue(), verbose_, - static_cast(ptCut_), + ptCut_, clustSizeCut_, &lstESDeviceData, &lstInputDC, @@ -60,7 +60,6 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE { desc.add("verbose", false); desc.add("ptCut", 0.8); desc.add("clustSizeCut", 16); - desc.add("ptCutLabel", "0.8"); desc.add("nopLSDupClean", false); desc.add("tcpLSTriplets", false); descriptions.addWithDefaultLabel(desc); diff --git a/RecoTracker/LST/python/lstProducerTask_cff.py b/RecoTracker/LST/python/lstProducerTask_cff.py index 588b354788635..2847f06178ba9 100644 --- a/RecoTracker/LST/python/lstProducerTask_cff.py +++ b/RecoTracker/LST/python/lstProducerTask_cff.py @@ -4,4 +4,8 @@ from RecoTracker.LST.lstModulesDevESProducer_cfi import lstModulesDevESProducer -lstProducerTask = cms.Task(lstModulesDevESProducer, lstProducer) +from RecoTracker.LST.lstInputProducer_cfi import lstInputProducer + +from RecoTracker.LSTCore.lstGeometryESProducer_cfi import lstGeometryESProducer + +lstProducerTask = cms.Task(lstGeometryESProducer, lstModulesDevESProducer, lstInputProducer, lstProducer) diff --git a/RecoTracker/LSTCore/BuildFile.xml b/RecoTracker/LSTCore/BuildFile.xml index e9cbb2cccf046..dbfe1a9fcda87 100644 --- a/RecoTracker/LSTCore/BuildFile.xml +++ b/RecoTracker/LSTCore/BuildFile.xml @@ -5,6 +5,7 @@ + diff --git a/RecoTracker/LSTCore/interface/EndcapGeometry.h b/RecoTracker/LSTCore/interface/EndcapGeometry.h index b8c44c14fb143..91891e1292e2e 100644 --- a/RecoTracker/LSTCore/interface/EndcapGeometry.h +++ b/RecoTracker/LSTCore/interface/EndcapGeometry.h @@ -1,6 +1,8 @@ #ifndef RecoTracker_LSTCore_interface_EndcapGeometry_h #define RecoTracker_LSTCore_interface_EndcapGeometry_h +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" + #include #include #include @@ -21,6 +23,8 @@ namespace lst { EndcapGeometry(std::string const& filename); void load(std::string const&); + void load(std::unordered_map const&, + std::unordered_map const&); void fillGeoMapArraysExplicit(); float getdxdy_slope(unsigned int detid) const; }; diff --git a/RecoTracker/LSTCore/interface/LSTESData.h b/RecoTracker/LSTCore/interface/LSTESData.h index bfa10186f8f2e..eb3f3c7906ba1 100644 --- a/RecoTracker/LSTCore/interface/LSTESData.h +++ b/RecoTracker/LSTCore/interface/LSTESData.h @@ -5,6 +5,7 @@ #include "RecoTracker/LSTCore/interface/EndcapGeometryDevHostCollection.h" #include "RecoTracker/LSTCore/interface/ModulesHostCollection.h" #include "RecoTracker/LSTCore/interface/PixelMap.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" #include "HeterogeneousCore/AlpakaInterface/interface/CopyToDevice.h" @@ -41,6 +42,7 @@ namespace lst { }; std::unique_ptr> loadAndFillESHost(std::string& ptCutLabel); + std::unique_ptr> loadAndFillESHost(lstgeometry::LSTGeometry const& lstg); } // namespace lst diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h b/RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h new file mode 100644 index 0000000000000..0fc9bb661896f --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h @@ -0,0 +1,15 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_Centroid_h +#define RecoTracker_LSTCore_interface_LSTGeometry_Centroid_h + +namespace lstgeometry { + + struct Centroid { + unsigned int moduleType; + double x; + double y; + double z; + }; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/CentroidMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/CentroidMethods.h new file mode 100644 index 0000000000000..bb66bc15a79ff --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/CentroidMethods.h @@ -0,0 +1,80 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_CentroidMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_CentroidMethods_h + +#include +#include + +#include "Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Module.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h" + +namespace lstgeometry { + + unsigned int extractBits(unsigned int value, unsigned int start, unsigned int end) { + unsigned int mask = (1 << (end - start + 1)) - 1; + return (value >> start) & mask; + } + + unsigned int firstDigit(unsigned int n) { + while (n >= 10) { + n /= 10; + } + return n; + } + + // TODO: refactor to use Module class better + int parseModuleType(unsigned int detId) { + // Check if the first digit of detId is '3' for inner tracker + if (firstDigit(detId) == 3) + return -1; + + unsigned int subdet = extractBits(detId, 25, 27); + unsigned int layer = subdet == Module::SubDet::Barrel ? extractBits(detId, 20, 22) : extractBits(detId, 18, 20); + unsigned int ring = subdet == Module::SubDet::Endcap ? extractBits(detId, 12, 15) : 0; + + bool is_even_det_id = detId % 2 == 0; + if (subdet == Module::SubDet::Barrel) { + if (layer <= 3) + return is_even_det_id ? Module::ModuleType::PSS : Module::ModuleType::PSP; + else + return Module::ModuleType::TwoS; + } else if (subdet == Module::SubDet::Endcap) { + if (layer <= 2) + return is_even_det_id && ring <= 10 ? Module::ModuleType::PSS + : (ring <= 10 ? Module::ModuleType::PSP : Module::ModuleType::TwoS); + else + return is_even_det_id && ring <= 7 ? Module::ModuleType::PSS + : (ring <= 7 ? Module::ModuleType::PSP : Module::ModuleType::TwoS); + } else { + throw std::runtime_error("Invalid subdetector type"); + } + } + + std::unordered_map computeCentroids( + std::unordered_map const& sensors) { + std::unordered_map centroids; + for (auto const& [detId, sensor] : sensors) { + int moduleType = parseModuleType(detId); + + // Remove sensors from inner tracker + if (moduleType == -1) { + continue; + } + + // Convert from mm to cm + double z = sensor.sensorCenterZ_cm; + double rho = sensor.sensorCenterRho_cm; + double phi = sensor.phi_rad; + double x = rho * cos(phi); + double y = rho * sin(phi); + + Centroid centroid{static_cast(moduleType), x, y, z}; + centroids[detId] = centroid; + } + return centroids; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/Common.h b/RecoTracker/LSTCore/interface/LSTGeometry/Common.h new file mode 100644 index 0000000000000..3535b98bde387 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/Common.h @@ -0,0 +1,65 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_Common_h +#define RecoTracker_LSTCore_interface_LSTGeometry_Common_h + +#include +#include + +namespace lstgeometry { + + using MatrixD3x3 = Eigen::Matrix; + using MatrixD4x2 = Eigen::Matrix; + using MatrixD4x3 = Eigen::Matrix; + using MatrixD8x3 = Eigen::Matrix; + using MatrixDNx2 = Eigen::Matrix; + using MatrixDNx3 = Eigen::Matrix; + using RowVectorD2 = Eigen::Matrix; + using ColVectorD3 = Eigen::Matrix; + using RowVectorD3 = Eigen::Matrix; + + // TODO: These should be moved to ../Common.h + constexpr double k2Rinv1GeVf = 0.00299792458; + constexpr double kB = 3.8112; + + // For pixel maps + constexpr unsigned int kNEta = 25; + constexpr unsigned int kNPhi = 72; + constexpr unsigned int kNZ = 25; + constexpr std::array kPtBounds = {{2.0, 10'000.0}}; + + // This is defined as a constant in case the legacy value (123456789) needs to be used + double kDefaultSlope = std::numeric_limits::infinity(); + + double degToRad(double degrees) { return degrees * (std::numbers::pi_v / 180); } + + double phi_mpi_pi(double phi) { + while (phi >= std::numbers::pi_v) + phi -= 2 * std::numbers::pi_v; + while (phi < -std::numbers::pi_v) + phi += 2 * std::numbers::pi_v; + return phi; + } + + double roundAngle(double angle, double tol = 1e-3) { + const double pi = std::numbers::pi_v; + if (std::fabs(angle) < tol) { + return 0.0; + } else if (std::fabs(angle - pi / 2) < tol) { + return pi / 2; + } else if (std::fabs(angle + pi / 2) < tol) { + return -pi / 2; + } else if (std::fabs(angle - pi) < tol || std::fabs(angle + pi) < tol) { + return -pi; + } + return angle; + } + + double roundCoordinate(double coord, double tol = 1e-3) { + if (std::fabs(coord) < tol) { + return 0.0; + } + return coord; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/CornerMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/CornerMethods.h new file mode 100644 index 0000000000000..242e09c765e5e --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/CornerMethods.h @@ -0,0 +1,150 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_CornerMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_CornerMethods_h + +#include +#include +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h" + +namespace lstgeometry { + + //Calculates the Rodrigues' rotation matrix for rotating a vector around an arbitrary axis. + MatrixD3x3 rodriguesRotationMatrix(ColVectorD3 axis, double theta) { + axis.normalize(); + + MatrixD3x3 k{{0, -axis(2), axis(1)}, {axis(2), 0, -axis(0)}, {-axis(1), axis(0), 0}}; + + MatrixD3x3 rotationMatrix = MatrixD3x3::Identity() + sin(theta) * k + (1 - cos(theta)) * (k * k); + + return rotationMatrix; + } + + // Generates a rotation matrix for rotating around the tangential direction in cylindrical coordinates. + MatrixD3x3 tangentialRotationMatrix(double phi, double theta) { + ColVectorD3 axis; + axis << -sin(phi), cos(phi), 0; + + return rodriguesRotationMatrix(axis, theta); + } + + // Computes the final rotation matrix based on tilt and phi angles. + // Note: + // Only the tilt angles are non-zero for the current geometry. If the other + // angles get used, implement their rotations using the tangentialRotationMatrix + // function above as an example. + MatrixD3x3 rotationMatrix(double tilt_rad, double skew_rad, double yaw_rad, double phi_rad) { + if (skew_rad != 0 || yaw_rad != 0) + throw std::invalid_argument("Skew and yaw angles are not currently supported."); + + // Rotation around Z-axis that makes the sensor "face towards" the beamline (i.e. towards z-axis) + // So for example if phi=0 then R is the identity (i.e. already facing), or if phi=90deg + // then R becomes (x,y,z)->(-y,x,z) so the sensor is rotated 90 degrees to face the beamline + MatrixD3x3 initialR{{cos(phi_rad), -sin(phi_rad), 0}, {sin(phi_rad), cos(phi_rad), 0}, {0, 0, 1}}; + + // The tilt angle given in the CSV files is with respect to a module that is facing + // the beamline, meaning after R_initial is applied. From there we tilt the module according + // to the rotation below. Note that because this tilt angle is not with respect to the X,Y,Z + // axes and is instead around an arbitrary axis (defined from the rotation above) we have to apply + // the Rodrigues' rotation formula + MatrixD3x3 rTilt = tangentialRotationMatrix(phi_rad, -tilt_rad); + + MatrixD3x3 finalR = rTilt * initialR; + + return finalR; + } + + // Calculates the transformed corners of each sensor + void transformSensorCorners(ModuleInfo& moduleInfo) { + auto module_z = moduleInfo.sensorCenterZ_cm; + auto module_rho = moduleInfo.sensorCenterRho_cm; + auto module_phi = moduleInfo.phi_rad; + auto sensor_spacing = moduleInfo.sensorSpacing_cm; + auto sensor_width = moduleInfo.meanWidth_cm; + auto sensor_length = moduleInfo.length_cm; + + auto module_x = module_rho * cos(module_phi); + auto module_y = module_rho * sin(module_phi); + + auto half_width = sensor_width / 2; + auto half_length = sensor_length / 2; + auto half_spacing = sensor_spacing / 2; + + // Make the module sizes consistent with hit-based method. + // FIXME: Using the real (smaller) sizes specified by CSV file increases + // fake rate significantly and lowers efficiency between abs(eta) 1 to 2. + auto width_extension = 5.0 - half_width; + auto length_extension = (half_length > 4 ? 5.0 : 2.5) - half_length; + + half_width += width_extension; + half_length += length_extension; + + MatrixD8x3 corners{{-half_spacing, -half_width, -half_length}, + {-half_spacing, -half_width, half_length}, + {-half_spacing, half_width, half_length}, + {-half_spacing, half_width, -half_length}, + {half_spacing, -half_width, -half_length}, + {half_spacing, -half_width, half_length}, + {half_spacing, half_width, half_length}, + {half_spacing, half_width, -half_length}}; + + MatrixD3x3 rotation_matrix = + rotationMatrix(moduleInfo.tiltAngle_rad, moduleInfo.skewAngle_rad, moduleInfo.yawAngle_rad, moduleInfo.phi_rad); + MatrixD8x3 rotated_corners = (rotation_matrix * corners.transpose()).transpose(); + + rotated_corners.rowwise() += RowVectorD3{module_x, module_y, module_z}; + + // Coordinate reorder before saving (x,y,z)->(z,x,y) + moduleInfo.transformedCorners.col(0) = rotated_corners.col(2); + moduleInfo.transformedCorners.col(1) = rotated_corners.col(0); + moduleInfo.transformedCorners.col(2) = rotated_corners.col(1); + } + + // Assigns each set of four corners to the correct sensor DetID based on the closest centroid. + std::unordered_map assignCornersToSensors( + std::vector const& modules, std::unordered_map const& sensors) { + std::unordered_map transformed_corners_dict; + + for (auto const& moduleInfo : modules) { + unsigned int module_det_id = moduleInfo.detId; + unsigned int sensor_det_id_1 = module_det_id + 1; + unsigned int sensor_det_id_2 = module_det_id + 2; + + auto& transformed_corners = moduleInfo.transformedCorners; + RowVectorD3 centroid_sensor_1 = transformed_corners.topRows(4).colwise().mean(); + RowVectorD3 centroid_sensor_2 = transformed_corners.bottomRows(4).colwise().mean(); + + double sensor1_center_z = sensors.at(sensor_det_id_1).sensorCenterZ_cm; + double sensor1_center_x = + sensors.at(sensor_det_id_1).sensorCenterRho_cm * cos(sensors.at(sensor_det_id_1).phi_rad); + double sensor1_center_y = + sensors.at(sensor_det_id_1).sensorCenterRho_cm * sin(sensors.at(sensor_det_id_1).phi_rad); + double sensor2_center_z = sensors.at(sensor_det_id_2).sensorCenterZ_cm; + double sensor2_center_x = + sensors.at(sensor_det_id_2).sensorCenterRho_cm * cos(sensors.at(sensor_det_id_2).phi_rad); + double sensor2_center_y = + sensors.at(sensor_det_id_2).sensorCenterRho_cm * sin(sensors.at(sensor_det_id_2).phi_rad); + + RowVectorD3 sensor_centroid_1{sensor1_center_z, sensor1_center_x, sensor1_center_y}; + RowVectorD3 sensor_centroid_2{sensor2_center_z, sensor2_center_x, sensor2_center_y}; + + double distance_to_sensor_1 = (centroid_sensor_1 - sensor_centroid_1).norm(); + double distance_to_sensor_2 = (centroid_sensor_2 - sensor_centroid_2).norm(); + + if (distance_to_sensor_1 < distance_to_sensor_2) { + transformed_corners_dict[sensor_det_id_1] = transformed_corners.topRows(4); + transformed_corners_dict[sensor_det_id_2] = transformed_corners.bottomRows(4); + } else { + transformed_corners_dict[sensor_det_id_2] = transformed_corners.topRows(4); + transformed_corners_dict[sensor_det_id_1] = transformed_corners.bottomRows(4); + } + } + + return transformed_corners_dict; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h b/RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h new file mode 100644 index 0000000000000..ff8370e5cbc39 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h @@ -0,0 +1,312 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_DetectorGeometry_h +#define RecoTracker_LSTCore_interface_LSTGeometry_DetectorGeometry_h + +#include +#include +#include +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Module.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTMath.h" + +namespace lstgeometry { + + using LayerEtaBinPhiBinKey = std::tuple; + + // We split modules into overlapping eta-phi bins so that it's easier to construct module maps + // These values are just guesses and can be optimized later + constexpr unsigned int kNEtaBins = 4; + constexpr double kEtaBinRad = std::numbers::pi_v / kNEtaBins; + constexpr unsigned int kNPhiBins = 6; + constexpr double kPhiBinWidth = 2 * std::numbers::pi_v / kNPhiBins; + + bool isInEtaPhiBin(double eta, double phi, unsigned int eta_bin, unsigned int phi_bin) { + double theta = 2. * std::atan(std::exp(-eta)); + + if (eta_bin == 0) { + if (theta > 3. * kEtaBinRad / 2.) + return false; + } else if (eta_bin == kNEtaBins - 1) { + if (theta < (2 * (kNEtaBins - 1) - 1) * kEtaBinRad / 2.) + return false; + } else if (theta < (2 * eta_bin - 1) * kEtaBinRad / 2. || theta > (2 * (eta_bin + 1) + 1) * kEtaBinRad / 2.) { + return false; + } + + double pi = std::numbers::pi_v; + if (phi_bin == 0) { + if (phi > -pi + kPhiBinWidth && phi < pi - kPhiBinWidth) + return false; + } else { + if (phi < -pi + (phi_bin - 1) * kPhiBinWidth || phi > -pi + (phi_bin + 1) * kPhiBinWidth) + return false; + } + + return true; + } + + std::pair getEtaPhiBins(double eta, double phi) { + double theta = 2. * std::atan(std::exp(-eta)); + + unsigned int eta_bin = 0; + if (theta <= kEtaBinRad) { + eta_bin = 0; + } else if (theta >= (kNEtaBins - 1) * kEtaBinRad) { + eta_bin = kNEtaBins - 1; + } else { + for (unsigned int i = 1; i < kNEtaBins - 1; i++) { + if (theta >= i * kEtaBinRad && theta <= (i + 1) * kEtaBinRad) { + eta_bin = i; + break; + } + } + } + + unsigned int phi_bin = 0; + double pi = std::numbers::pi_v; + + if (phi <= -pi + kPhiBinWidth / 2. || phi >= pi - kPhiBinWidth / 2.) { + phi_bin = 0; + } else { + for (unsigned int i = 1; i < kNPhiBins; i++) { + if (phi >= -pi + ((2 * i - 1) * kPhiBinWidth) / 2. && phi <= -pi + ((2 * i + 1) * kPhiBinWidth) / 2.) { + phi_bin = i; + break; + } + } + } + + return std::make_pair(eta_bin, phi_bin); + } + + class DetectorGeometry { + private: + std::unordered_map corners_; + std::vector avg_radii_; + std::vector avg_z_; + std::unordered_map, boost::hash> + barrel_lower_det_ids_; + std::unordered_map, boost::hash> + endcap_lower_det_ids_; + + public: + DetectorGeometry(std::unordered_map corners, + std::vector avg_radii, + std::vector avg_z) + : corners_(corners), avg_radii_(avg_radii), avg_z_(avg_z) {} + + MatrixD4x3 const& getCorners(unsigned int detId) const { return corners_.at(detId); } + + std::vector getDetIds(std::function&)> filter = + [](const auto&) { return true; }) const { + std::vector detIds; + for (const auto& entry : corners_) { + if (filter(entry)) { + detIds.push_back(entry.first); + } + } + return detIds; + } + + void buildByLayer() { + // Clear just in case they were already built + barrel_lower_det_ids_.clear(); + endcap_lower_det_ids_.clear(); + + // Initialize all vectors + for (unsigned int etabin = 0; etabin < kNEtaBins; etabin++) { + for (unsigned int phibin = 0; phibin < kNPhiBins; phibin++) { + for (unsigned int layer = 1; layer < 7; layer++) { + barrel_lower_det_ids_[{layer, etabin, phibin}] = {}; + } + for (unsigned int layer = 1; layer < 6; layer++) { + endcap_lower_det_ids_[{layer, etabin, phibin}] = {}; + } + } + } + + for (unsigned int layer = 1; layer < 7; layer++) { + auto detids = getDetIds([&layer](const auto& x) { + Module m(x.first); + return m.subdet() == 5 && m.layer() == layer && m.isLower() == 1; + }); + for (auto detid : detids) { + auto corners = getCorners(detid); + RowVectorD3 center = corners.colwise().mean(); + center /= 4.; + auto etaphi = getEtaPhi(center(1), center(2), center(0)); + for (unsigned int etabin = 0; etabin < kNEtaBins; etabin++) { + for (unsigned int phibin = 0; phibin < kNPhiBins; phibin++) { + if (isInEtaPhiBin(etaphi.first, etaphi.second, etabin, phibin)) { + barrel_lower_det_ids_[{layer, etabin, phibin}].push_back(detid); + } + } + } + } + } + for (unsigned int layer = 1; layer < 6; layer++) { + auto detids = getDetIds([&layer](const auto& x) { + Module m(x.first); + return m.subdet() == 4 && m.layer() == layer && m.isLower() == 1; + }); + for (auto detid : detids) { + auto corners = getCorners(detid); + RowVectorD3 center = corners.colwise().mean(); + center /= 4.; + auto etaphi = getEtaPhi(center(1), center(2), center(0)); + for (unsigned int etabin = 0; etabin < kNEtaBins; etabin++) { + for (unsigned int phibin = 0; phibin < kNPhiBins; phibin++) { + if (isInEtaPhiBin(etaphi.first, etaphi.second, etabin, phibin)) { + endcap_lower_det_ids_[{layer, etabin, phibin}].push_back(detid); + } + } + } + } + } + } + + std::vector const& getBarrelLayerDetIds(unsigned int layer, + unsigned int etabin, + unsigned int phibin) const { + return barrel_lower_det_ids_.at({layer, etabin, phibin}); + } + + std::vector const& getEndcapLayerDetIds(unsigned int layer, + unsigned int etabin, + unsigned int phibin) const { + return endcap_lower_det_ids_.at({layer, etabin, phibin}); + } + + double getBarrelLayerAverageRadius(unsigned int layer) const { return avg_radii_[layer - 1]; } + + double getEndcapLayerAverageAbsZ(unsigned int layer) const { return avg_z_[layer - 1]; } + + double getMinR(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double minR = std::numeric_limits::max(); + for (int i = 0; i < corners.rows(); i++) { + double x = corners(i, 1); + double y = corners(i, 2); + minR = std::min(minR, std::sqrt(x * x + y * y)); + } + return minR; + } + + double getMaxR(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double maxR = std::numeric_limits::min(); + for (int i = 0; i < corners.rows(); i++) { + double x = corners(i, 1); + double y = corners(i, 2); + maxR = std::max(maxR, std::sqrt(x * x + y * y)); + } + return maxR; + } + + double getMinZ(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double minZ = std::numeric_limits::max(); + for (int i = 0; i < corners.rows(); i++) { + double z = corners(i, 0); + minZ = std::min(minZ, z); + } + return minZ; + } + + double getMaxZ(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double maxZ = std::numeric_limits::lowest(); + for (int i = 0; i < corners.rows(); i++) { + double z = corners(i, 0); + maxZ = std::max(maxZ, z); + } + return maxZ; + } + + double getMinPhi(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double minPhi = std::numeric_limits::max(); + double minPosPhi = std::numeric_limits::max(); + double minNegPhi = std::numeric_limits::max(); + unsigned int nPos = 0; + unsigned int nOverPi2 = 0; + for (int i = 0; i < corners.rows(); i++) { + double phi = phi_mpi_pi(std::numbers::pi_v + std::atan2(-corners(i, 2), -corners(i, 1))); + minPhi = std::min(minPhi, phi); + if (phi > 0) { + minPosPhi = std::min(minPosPhi, phi); + nPos++; + } else { + minNegPhi = std::min(minNegPhi, phi); + } + if (std::fabs(phi) > std::numbers::pi_v / 2.) { + nOverPi2++; + } + } + if (nPos == 4 || nPos == 0) + return minPhi; + if (nOverPi2 == 4) + return minPosPhi; + return minPhi; + } + + double getMaxPhi(unsigned int detId) const { + auto const& corners = corners_.at(detId); + double maxPhi = std::numeric_limits::lowest(); + double maxPosPhi = std::numeric_limits::lowest(); + double maxNegPhi = std::numeric_limits::lowest(); + unsigned int nPos = 0; + unsigned int nOverPi2 = 0; + for (int i = 0; i < corners.rows(); i++) { + double phi = phi_mpi_pi(std::numbers::pi_v + std::atan2(-corners(i, 2), -corners(i, 1))); + maxPhi = std::max(maxPhi, phi); + if (phi > 0) { + maxPosPhi = std::max(maxPosPhi, phi); + nPos++; + } else { + maxNegPhi = std::max(maxNegPhi, phi); + } + if (std::fabs(phi) > std::numbers::pi_v / 2.) { + nOverPi2++; + } + } + if (nPos == 4 || nPos == 0) + return maxPhi; + if (nOverPi2 == 4) + return maxNegPhi; + return maxPhi; + } + + std::pair getCompatibleEtaRange(unsigned int detId, double zmin_bound, double zmax_bound) const { + double minr = getMinR(detId); + double maxr = getMaxR(detId); + double minz = getMinZ(detId); + double maxz = getMaxZ(detId); + double mineta = -std::log(std::tan(std::atan2(minz > 0 ? maxr : minr, minz - zmin_bound) / 2.)); + double maxeta = -std::log(std::tan(std::atan2(maxz > 0 ? minr : maxr, maxz - zmax_bound) / 2.)); + + if (maxeta < mineta) + std::swap(maxeta, mineta); + return std::make_pair(mineta, maxeta); + } + + std::pair, std::pair> getCompatiblePhiRange(unsigned int detId, + double ptmin, + double ptmax) const { + double minr = getMinR(detId); + double maxr = getMaxR(detId); + double minphi = getMinPhi(detId); + double maxphi = getMaxPhi(detId); + double A = k2Rinv1GeVf * kB / 2.; + double pos_q_phi_lo_bound = phi_mpi_pi(A * minr / ptmax + minphi); + double pos_q_phi_hi_bound = phi_mpi_pi(A * maxr / ptmin + maxphi); + double neg_q_phi_lo_bound = phi_mpi_pi(-A * maxr / ptmin + minphi); + double neg_q_phi_hi_bound = phi_mpi_pi(-A * minr / ptmax + maxphi); + return std::make_pair(std::make_pair(pos_q_phi_lo_bound, pos_q_phi_hi_bound), + std::make_pair(neg_q_phi_lo_bound, neg_q_phi_hi_bound)); + } + }; +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/Helix.h b/RecoTracker/LSTCore/interface/LSTGeometry/Helix.h new file mode 100644 index 0000000000000..ca15660f3dfff --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/Helix.h @@ -0,0 +1,18 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_Helix_h +#define RecoTracker_LSTCore_interface_LSTGeometry_Helix_h + +namespace lstgeometry { + + struct Helix { + double center_x; + double center_y; + double center_z; + double radius; + double phi; + double lam; + int charge; + }; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/IO.h b/RecoTracker/LSTCore/interface/LSTGeometry/IO.h new file mode 100644 index 0000000000000..ea20bd3d70907 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/IO.h @@ -0,0 +1,281 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_IO_h +#define RecoTracker_LSTCore_interface_LSTGeometry_IO_h + +#include "Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/PixelMapMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/OrientationMethods.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace lstgeometry { + + std::string trim(std::string const& str) { + size_t first = str.find_first_not_of(" \t\r\n"); + if (first == std::string::npos) + return ""; + size_t last = str.find_last_not_of(" \t\r\n"); + return str.substr(first, (last - first + 1)); + } + + std::vector parseCSVLine(std::string const& line) { + std::vector tokens; + std::stringstream ss(line); + std::string token; + + while (std::getline(ss, token, ',')) { + tokens.push_back(trim(token)); + } + + return tokens; + } + + std::vector readModuleInfo(std::string const& filename) { + std::vector modules; + std::string line; + std::ifstream file(filename); + + if (!file.is_open()) { + throw std::runtime_error("Could not open file " + filename); + } + + // Skip header line + std::getline(file, line); + + while (std::getline(file, line)) { + if (line.empty()) + continue; + + std::vector tokens = parseCSVLine(line); + if (tokens.size() != 23) + continue; + + ModuleInfo m{static_cast(std::stoul(tokens[0])), + std::stod(tokens[5]) / 10.0, + std::stod(tokens[6]) / 10.0, + degToRad(std::stod(tokens[7])), + degToRad(std::stod(tokens[8])), + degToRad(std::stod(tokens[9])), + degToRad(std::stod(tokens[10])), + std::stod(tokens[19]) / 10.0, + std::stod(tokens[20]) / 10.0, + std::stod(tokens[21]) / 10.0, + MatrixD8x3::Zero()}; + + modules.push_back(m); + } + + return modules; + } + + std::unordered_map readSensorInfo(std::string const& filename) { + std::unordered_map sensors; + std::string line; + std::ifstream file(filename); + + if (!file.is_open()) { + throw std::runtime_error("Could not open file " + filename); + } + + // Skip header line + std::getline(file, line); + + while (std::getline(file, line)) { + if (line.empty()) + continue; + + std::vector tokens = parseCSVLine(line); + if (tokens.size() != 8) + continue; + + SensorInfo s{ + static_cast(std::stoul(tokens[0])), + std::stod(tokens[5]) / 10.0, + std::stod(tokens[6]) / 10.0, + degToRad(std::stod(tokens[7])), + }; + + sensors[s.detId] = s; + } + + return sensors; + } + + std::vector readAverages(std::string const& filename) { + std::vector averages; + std::string line; + std::ifstream file(filename); + + if (!file.is_open()) { + throw std::runtime_error("Could not open file " + filename); + } + + while (std::getline(file, line)) { + if (line.empty()) + continue; + + std::vector tokens = parseCSVLine(line); + if (tokens.size() != 1) + continue; + + averages.push_back(std::stod(tokens[0])); + } + + return averages; + } + + void writeCentroids(std::unordered_map const& centroids, + std::string const& base_filename, + bool binary = true) { + std::filesystem::path filepath(base_filename); + std::filesystem::create_directories(filepath.parent_path()); + + std::string filename = base_filename + (binary ? ".bin" : ".txt"); + std::ofstream file(filename, binary ? std::ios::binary : std::ios::out); + + if (binary) { + for (auto& [detid, centroid] : centroids) { + float x = centroid.x; + float y = centroid.y; + float z = centroid.z; + unsigned int moduleType = centroid.moduleType; + file.write(reinterpret_cast(&detid), sizeof(detid)); + file.write(reinterpret_cast(&x), sizeof(x)); + file.write(reinterpret_cast(&y), sizeof(y)); + file.write(reinterpret_cast(&z), sizeof(z)); + file.write(reinterpret_cast(&moduleType), sizeof(moduleType)); + } + } else { + for (auto& [detid, centroid] : centroids) { + file << detid << "," << centroid.x << "," << centroid.y << "," << centroid.z << "," << centroid.moduleType + << std::endl; + } + } + } + + void writeSlopes(std::unordered_map const& slopes, + std::unordered_map const& sensors, + std::string const& base_filename, + bool binary = true) { + std::filesystem::path filepath(base_filename); + std::filesystem::create_directories(filepath.parent_path()); + + std::string filename = base_filename + (binary ? ".bin" : ".txt"); + std::ofstream file(filename, binary ? std::ios::binary : std::ios::out); + + if (binary) { + for (auto& [detid, slope] : slopes) { + float drdz_slope = slope.drdz_slope; + float dxdy_slope = slope.dxdy_slope; + float phi = sensors.at(detid).phi_rad; + file.write(reinterpret_cast(&detid), sizeof(detid)); + if (drdz_slope != kDefaultSlope) { + file.write(reinterpret_cast(&drdz_slope), sizeof(drdz_slope)); + file.write(reinterpret_cast(&dxdy_slope), sizeof(dxdy_slope)); + } else { + file.write(reinterpret_cast(&dxdy_slope), sizeof(dxdy_slope)); + file.write(reinterpret_cast(&phi), sizeof(phi)); + } + } + } else { + for (auto& [detid, slope] : slopes) { + float drdz_slope = slope.drdz_slope; + float dxdy_slope = slope.dxdy_slope; + float phi = sensors.at(detid).phi_rad; + file << detid << ","; + if (drdz_slope != kDefaultSlope) { + file << drdz_slope << "," << dxdy_slope << std::endl; + } else { + file << dxdy_slope << "," << phi << std::endl; + } + } + } + } + + void writeModuleConnections(std::unordered_map> const& connections, + std::string const& base_filename, + bool binary = true) { + std::filesystem::path filepath(base_filename); + std::filesystem::create_directories(filepath.parent_path()); + + std::string filename = base_filename + (binary ? ".bin" : ".txt"); + std::ofstream file(filename, binary ? std::ios::binary : std::ios::out); + + if (binary) { + for (auto& [detid, set] : connections) { + file.write(reinterpret_cast(&detid), sizeof(detid)); + unsigned int length = set.size(); + file.write(reinterpret_cast(&length), sizeof(length)); + for (unsigned int i : set) { + file.write(reinterpret_cast(&i), sizeof(i)); + } + } + } else { + for (auto& [detid, set] : connections) { + file << detid << "," << set.size(); + for (unsigned int i : set) { + file << "," << i; + } + file << std::endl; + } + } + } + + void writePixelMaps(PixelMap const& maps, std::string const& base_filename, bool binary = true) { + std::filesystem::path filepath(base_filename); + std::filesystem::create_directories(filepath.parent_path()); + + if (binary) { + for (auto& [layersubdetcharge, map] : maps) { + auto& [layer, subdet, charge] = layersubdetcharge; + + std::string charge_str = charge > 0 ? "_pos" : (charge < 0 ? "_neg" : ""); + std::string filename = std::format("{}{}_layer{}_subdet{}.bin", base_filename, charge_str, layer, subdet); + + std::ofstream file(filename, std::ios::binary); + + for (unsigned int isuperbin = 0; isuperbin < map.size(); isuperbin++) { + auto const& set = map.at(isuperbin); + + file.write(reinterpret_cast(&isuperbin), sizeof(isuperbin)); + unsigned int length = set.size(); + file.write(reinterpret_cast(&length), sizeof(length)); + for (unsigned int i : set) { + file.write(reinterpret_cast(&i), sizeof(i)); + } + } + } + } else { + for (auto& [layersubdetcharge, map] : maps) { + auto& [layer, subdet, charge] = layersubdetcharge; + + std::string charge_str = charge > 0 ? "_pos" : (charge < 0 ? "_neg" : ""); + std::string filename = std::format("{}{}_layer{}_subdet{}.txt", base_filename, charge_str, layer, subdet); + + std::ofstream file(filename); + + for (unsigned int isuperbin = 0; isuperbin < map.size(); isuperbin++) { + auto const& set = map.at(isuperbin); + + unsigned int length = set.size(); + file << isuperbin << "," << length; + for (unsigned int i : set) { + file << "," << i; + } + file << std::endl; + } + } + } + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h b/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h new file mode 100644 index 0000000000000..87e75ba3e2533 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h @@ -0,0 +1,22 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_LSTGeometry_h +#define RecoTracker_LSTCore_interface_LSTGeometry_LSTGeometry_h + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SlopeData.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/PixelMap.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h" + +namespace lstgeometry { + + struct LSTGeometry { + std::unordered_map centroids; + std::unordered_map barrel_slopes; + std::unordered_map endcap_slopes; + PixelMap pixel_map; + std::unordered_map> merged_line_connections; + std::unordered_map sensor_info; + }; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometryMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometryMethods.h new file mode 100644 index 0000000000000..338ff0e0c7e07 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometryMethods.h @@ -0,0 +1,62 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_LSTGeometryMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_LSTGeometryMethods_h + +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/CornerMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/CentroidMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/OrientationMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/PixelMapMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/ModuleMapMethods.h" + +namespace lstgeometry { + + std::unique_ptr makeLSTGeometry(std::vector &modules_info, + std::unordered_map &sensors_info, + std::vector const &average_r, + std::vector const &average_z, + double ptCut) { + for (auto &mod : modules_info) + transformSensorCorners(mod); + + auto assigned_corners = assignCornersToSensors(modules_info, sensors_info); + + auto centroids = computeCentroids(sensors_info); + + auto [barrel_slopes, endcap_slopes] = processCorners(assigned_corners); + + auto det_geom = DetectorGeometry(assigned_corners, average_r, average_z); + det_geom.buildByLayer(); + + auto pixel_map = computePixelMap(centroids, det_geom, ptCut); + + auto detids_etaphi_layer_ref = det_geom.getDetIds([](const auto &x) { + auto mod = Module(x.first); + return ((mod.subdet() == 5 && mod.isLower() == 1 && mod.layer() != 6) || + (mod.subdet() == 4 && mod.isLower() == 1 && mod.layer() != 5 && !(mod.ring() == 15 && mod.layer() == 1) && + !(mod.ring() == 15 && mod.layer() == 2) && !(mod.ring() == 12 && mod.layer() == 3) && + !(mod.ring() == 12 && mod.layer() == 4))); + }); + + std::unordered_map> straight_line_connections; + std::unordered_map> curved_line_connections; + + for (auto ref_detid : detids_etaphi_layer_ref) { + straight_line_connections[ref_detid] = getStraightLineConnections(ref_detid, centroids, det_geom); + curved_line_connections[ref_detid] = getCurvedLineConnections(ref_detid, centroids, det_geom, ptCut); + } + auto merged_line_connections = mergeLineConnections({&straight_line_connections, &curved_line_connections}); + + auto lstGeometry = std::make_unique(std::move(centroids), + std::move(barrel_slopes), + std::move(endcap_slopes), + std::move(pixel_map), + std::move(merged_line_connections), + std::move(sensors_info)); + + return lstGeometry; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/LSTMath.h b/RecoTracker/LSTCore/interface/LSTGeometry/LSTMath.h new file mode 100644 index 0000000000000..7a7137a874cd3 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/LSTMath.h @@ -0,0 +1,152 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_LSTMath_h +#define RecoTracker_LSTCore_interface_LSTGeometry_LSTMath_h + +#include + +#include +#include +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Helix.h" + +namespace lstgeometry { + + using Point = boost::geometry::model::d2::point_xy; + using Polygon = boost::geometry::model::polygon; + + // Clarification : phi was derived assuming a negatively charged particle would start + // at the first quadrant. However the way signs are set up in the get_track_point function + // implies the particle actually starts out in the fourth quadrant, and phi is measured from + // the y axis as opposed to x axis in the expression provided in this function. Hence I tucked + // in an extra pi/2 to account for these effects + Helix constructHelixFromPoints( + double pt, double vx, double vy, double vz, double mx, double my, double mz, int charge) { + double radius = pt / (k2Rinv1GeVf * kB); + + double t = 2. * std::asin(std::sqrt((vx - mx) * (vx - mx) + (vy - my) * (vy - my)) / (2. * radius)); + double phi = std::numbers::pi_v / 2. + std::atan((vy - my) / (vx - mx)) + + ((vy - my) / (vx - mx) < 0) * (std::numbers::pi_v)+charge * t / 2. + + (my - vy < 0) * (std::numbers::pi_v / 2.) - (my - vy > 0) * (std::numbers::pi_v / 2.); + + double cx = vx + charge * radius * std::sin(phi); + double cy = vy - charge * radius * std::cos(phi); + double cz = vz; + double lam = std::atan((mz - vz) / (radius * t)); + + return Helix(cx, cy, cz, radius, phi, lam, charge); + } + + std::tuple getHelixPointFromRadius(Helix const& helix, double target_r) { + auto objective_function = [&helix, target_r](double t) { + double x = helix.center_x - helix.charge * helix.radius * std::sin(helix.phi - helix.charge * t); + double y = helix.center_y + helix.charge * helix.radius * std::cos(helix.phi - helix.charge * t); + return std::fabs(std::sqrt(x * x + y * y) - target_r); + }; + int bits = std::numeric_limits::digits; + auto result = boost::math::tools::brent_find_minima(objective_function, 0.0, std::numbers::pi_v, bits); + double t = result.first; + + double x = helix.center_x - helix.charge * helix.radius * std::sin(helix.phi - helix.charge * t); + double y = helix.center_y + helix.charge * helix.radius * std::cos(helix.phi - helix.charge * t); + double z = helix.center_z + helix.radius * std::tan(helix.lam) * t; + double r = std::sqrt(x * x + y * y); + + return std::make_tuple(x, y, z, r); + } + + std::tuple getHelixPointFromZ(Helix const& helix, double target_z) { + auto objective_function = [&helix, target_z](double t) { + double z = helix.center_z + helix.radius * std::tan(helix.lam) * t; + return std::fabs(z - target_z); + }; + int bits = std::numeric_limits::digits; + auto result = boost::math::tools::brent_find_minima(objective_function, 0.0, std::numbers::pi_v, bits); + double t = result.first; + + double x = helix.center_x - helix.charge * helix.radius * std::sin(helix.phi - helix.charge * t); + double y = helix.center_y + helix.charge * helix.radius * std::cos(helix.phi - helix.charge * t); + double z = helix.center_z + helix.radius * std::tan(helix.lam) * t; + double r = std::sqrt(x * x + y * y); + + return std::make_tuple(x, y, z, r); + } + + std::pair getEtaPhi(double x, double y, double z, double refphi = 0) { + double phi = phi_mpi_pi(std::atan2(y, x) - refphi); + double eta = std::copysign(-std::log(std::tan(std::atan(std::sqrt(x * x + y * y) / std::abs(z)) / 2.)), z); + return std::make_pair(eta, phi); + } + + Polygon getEtaPhiPolygon(MatrixDNx3 const& mod_boundaries, double refphi, double zshift = 0) { + int npoints = mod_boundaries.rows(); + MatrixDNx2 mod_boundaries_etaphi(npoints, 2); + for (int i = 0; i < npoints; ++i) { + auto ref_etaphi = getEtaPhi(mod_boundaries(i, 1), mod_boundaries(i, 2), mod_boundaries(i, 0) + zshift, refphi); + mod_boundaries_etaphi(i, 0) = ref_etaphi.first; + mod_boundaries_etaphi(i, 1) = ref_etaphi.second; + } + + Polygon poly; + // <= because we need to close the polygon with the first point + for (int i = 0; i <= npoints; ++i) { + boost::geometry::append(poly, + Point(mod_boundaries_etaphi(i % npoints, 0), mod_boundaries_etaphi(i % npoints, 1))); + } + boost::geometry::correct(poly); + return poly; + } + + bool moduleOverlapsInEtaPhi(MatrixD4x3 const& ref_mod_boundaries, + MatrixD4x3 const& tar_mod_boundaries, + double refphi = 0, + double zshift = 0) { + RowVectorD3 ref_center = ref_mod_boundaries.colwise().sum(); + ref_center /= 4.; + RowVectorD3 tar_center = tar_mod_boundaries.colwise().sum(); + tar_center /= 4.; + + double ref_center_phi = std::atan2(ref_center(2), ref_center(1)); + double tar_center_phi = std::atan2(tar_center(2), tar_center(1)); + + if (std::fabs(phi_mpi_pi(ref_center_phi - tar_center_phi)) > std::numbers::pi_v / 2.) + return false; + + MatrixD4x2 ref_mod_boundaries_etaphi; + MatrixD4x2 tar_mod_boundaries_etaphi; + + for (int i = 0; i < 4; ++i) { + auto ref_etaphi = + getEtaPhi(ref_mod_boundaries(i, 1), ref_mod_boundaries(i, 2), ref_mod_boundaries(i, 0) + zshift, refphi); + auto tar_etaphi = + getEtaPhi(tar_mod_boundaries(i, 1), tar_mod_boundaries(i, 2), tar_mod_boundaries(i, 0) + zshift, refphi); + ref_mod_boundaries_etaphi(i, 0) = ref_etaphi.first; + ref_mod_boundaries_etaphi(i, 1) = ref_etaphi.second; + tar_mod_boundaries_etaphi(i, 0) = tar_etaphi.first; + tar_mod_boundaries_etaphi(i, 1) = tar_etaphi.second; + } + + // Quick cut + RowVectorD2 diff = ref_mod_boundaries_etaphi.row(0) - tar_mod_boundaries_etaphi.row(0); + if (std::fabs(diff(0)) > 0.5) + return false; + if (std::fabs(phi_mpi_pi(diff(1))) > 1.) + return false; + + Polygon ref_poly, tar_poly; + + // <= 4 because we need to close the polygon with the first point + for (int i = 0; i <= 4; ++i) { + boost::geometry::append(ref_poly, + Point(ref_mod_boundaries_etaphi(i % 4, 0), ref_mod_boundaries_etaphi(i % 4, 1))); + boost::geometry::append(tar_poly, + Point(tar_mod_boundaries_etaphi(i % 4, 0), tar_mod_boundaries_etaphi(i % 4, 1))); + } + boost::geometry::correct(ref_poly); + boost::geometry::correct(tar_poly); + + return boost::geometry::intersects(ref_poly, tar_poly); + } + +} // namespace lstgeometry +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/Module.h b/RecoTracker/LSTCore/interface/LSTGeometry/Module.h new file mode 100644 index 0000000000000..51aa7d4e5ae57 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/Module.h @@ -0,0 +1,475 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_Module_h +#define RecoTracker_LSTCore_interface_LSTGeometry_Module_h + +#include +#include + +namespace lstgeometry { + + class Module { + private: + // Decoding DetId + // + // detId comes in 29 bits. There are two formats depending on which sub detector it is. + // + // 29 bits total + // + // left to right index (useful python, i.e. string[idx:jdx]) + // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 + // + // right to left index (useful when C++ style, i.e. bit shifting) + // 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 + // + // x x x x x x x x x x x x x x x x x x x x x x x x x x x x x + // + // -subdet- -layer-- -side --------rod--------- -------module------- # if subdet == 5 + // -subdet- -side --layer- ----ring--- -------module------- # if subdet == 4 + // + // + + //---------- + // * detId * + //---------- + // The unique detector ID for this module layer + unsigned int detId_; + + // The unique detector ID to its partner + unsigned int partnerDetId_; + + //----------- + // * subdet * + //----------- + // bits 27 to 25 + // subdet = (detId & (7 << 25)) >> 25; + // subdet can take either 4 or 5 + // 4: endcap + // 5: barrel + public: + enum SubDet { Barrel = 5, Endcap = 4 }; + + private: + unsigned short subdet_; + + //--------- + // * Side * + //--------- + // bits 24 to 23 + // if (subdet_ == 4) + // { + // side_ = (detId_ & (3 << 23)) >> 23; + // } + // else if (subdet_ == 5) + // { + // side_ = (detId_ & (3 << 18)) >> 18; + // } + // 1 = -z side of the endcap modules AND -z side of tilted modules + // 2 = +z side of the endcap modules AND +z side of tilted modules + // 3 = barrel modules (determined via checking subdet) + public: + enum Side { NegZ = 1, PosZ = 2, Center = 3 }; + + private: + unsigned short side_; + + //---------- + // * Layer * + //---------- + // either bits 22 to 20 or 20 to 18 + // if (subdet_ == 4) + // { + // layer_ = (detId_ & (7 << 18)) >> 18; + // } + // else if (subdet_ == 5) + // { + // layer_ = (detId_ & (7 << 20)) >> 20; + // } + // depending on whether it is subdet = 4 or 5, the position of layer information is different + // layer = detId_bits[06:08] if subdet = 5 + // layer = detId_bits[08:10] if subdet = 4 + unsigned short layer_; + + //-------- + // * Rod * + //-------- + // bits 16 to 10 only when subdet = 5 + // if (subdet_ == 5) + // { + // rod_ = (detId_ & (127 << 10)) >> 10; + // } + // else if (subdet_ == 4) + // { + // rod_ = 0; + // } + // Index of which rod in the barrel + // Closest to the positive x-axis line is rod = 1, and it goes counter-clockwise in x-y plane projection + // total number of rods for each layer: 18, 26, 36, 48, 60, and 78 + unsigned short rod_; + + //--------- + // * Ring * + //--------- + // bits 15 to 12 only when subdet = 4 + // if (subdet_ == 5) + // { + // ring_ = 0; + // } + // else if (subdet_ == 4) + // { + // ring_ = (detId_ & (15 << 12)) >> 12; + // } + // Index of which ring in the endcap + // For the layer 1 and 2, there are 15 rings, first 10 are PS, the latter 5 are 2S + // For the layer 3, 4, and 5, there are 12 rings, first 7 are PS, the latter 5 are 2S + unsigned short ring_; + + //----------- + // * Module * + //----------- + // bits 8 to 2 + // module_ = (detId_ & (127 << 2)) >> 2; + // For subdet==4 the # of module depends on how far away from beam spot, + // module 1 is closest to the positive x-axis line and it goes counter-clockwise in x-y plane projection + // layer 1 or 2, ring 1: 20 modules + // layer 1 or 2, ring 2: 24 modules + // layer 1 or 2, ring 3: 24 modules + // layer 1 or 2, ring 4: 28 modules + // layer 1 or 2, ring 5: 32 modules + // layer 1 or 2, ring 6: 32 modules + // layer 1 or 2, ring 7: 36 modules + // layer 1 or 2, ring 8: 40 modules + // layer 1 or 2, ring 9: 40 modules + // layer 1 or 2, ring 10: 44 modules + // layer 1 or 2, ring 11: 52 modules + // layer 1 or 2, ring 12: 60 modules + // layer 1 or 2, ring 13: 64 modules + // layer 1 or 2, ring 14: 72 modules + // layer 1 or 2, ring 15: 76 modules + // layer 3, 4, or 5, ring 1: 28 modules + // layer 3, 4, or 5, ring 2: 28 modules + // layer 3, 4, or 5, ring 3: 32 modules + // layer 3, 4, or 5, ring 4: 36 modules + // layer 3, 4, or 5, ring 5: 36 modules + // layer 3, 4, or 5, ring 6: 40 modules + // layer 3, 4, or 5, ring 7: 44 modules + // layer 3, 4, or 5, ring 8: 52 modules + // layer 3, 4, or 5, ring 9: 56 modules + // layer 3, 4, or 5, ring 10: 64 modules + // layer 3, 4, or 5, ring 11: 72 modules + // layer 3, 4, or 5, ring 12: 76 modules + // + // For subdet==5, the # of module depends on how far away from beam spot, + // for side==3: module 1 has lowest z (starting from the negative value) + // layer 1, side 3: 7 modules + // layer 2, side 3: 11 modules + // layer 3, side 3: 15 modules + // layer 4, 5, or 6, side 3: 24 modules + // for side==1,2 (i.e. tilted): module 1 is along x-axis + // layer 1, side 1, or 2: 18 modules + // layer 2, side 1, or 2: 26 modules + // layer 3, side 1, or 2: 36 modules + unsigned short module_; + + //------------ + // * isLower * + //------------ + // bit 28 + // isLower_ = (detId_ & 1); + // isLower is always the pixel if it's a PS module, if it's a 2S module it's whichever is the protruding side when 2S are staggered + unsigned short isLower_; + + // The modules are put in alternating order where the modules are inverted every other one + bool isInverted_; + + // To hold information whether it is a 2S or PS + public: + enum ModuleType { PS, PSP = 23, PSS = 24, TwoS = 25 }; + + private: + ModuleType moduleType_; + + // To hold information whether it is a Pixel or Strip + // Pixel + // Strip + public: + enum ModuleLayerType { Pixel, Strip }; + + private: + ModuleLayerType moduleLayerType_; + + void setDerivedQuantities(); + void setDerivedQuantities(unsigned int moduleTypeInfo); + void setDerivedQuantities(ModuleType moduleType, ModuleLayerType moduleLayerType); + + public: + // constructor/destructor + Module(); + Module(unsigned int detId); + Module(unsigned int detId, unsigned int moduleTypeInfo); + Module(unsigned int detId, ModuleType moduleType, ModuleLayerType moduleLayerType); + Module(const Module&); + ~Module(); + + // accessor functions + const unsigned int& detId() const; + const unsigned int& partnerDetId() const; + const unsigned short& subdet() const; + const unsigned short& side() const; + const unsigned short& layer() const; + const unsigned short& rod() const; + const unsigned short& ring() const; + const unsigned short& module() const; + const unsigned short& isLower() const; + const bool& isInverted() const; + const ModuleType& moduleType() const; + const ModuleLayerType& moduleLayerType() const; + + // modifying the class content + void setDetId(unsigned int); + void setDetId(unsigned int, unsigned int); + void setDetId(unsigned int, ModuleType, ModuleLayerType); + + // static functions to parse detId + static unsigned short parseSubdet(unsigned int); + static unsigned short parseSide(unsigned int); + static unsigned short parseLayer(unsigned int); + static unsigned short parseRod(unsigned int); + static unsigned short parseRing(unsigned int); + static unsigned short parseModule(unsigned int); + static unsigned short parseIsLower(unsigned int); + static bool parseIsInverted(unsigned int); + static unsigned int parsePartnerDetId(unsigned int); + static ModuleType parseModuleType(unsigned int); + static ModuleLayerType parseModuleLayerType(unsigned int); + }; + +} // namespace lstgeometry + +lstgeometry::Module::Module() { setDetId(0); } + +lstgeometry::Module::Module(unsigned int detId) { setDetId(detId); } + +lstgeometry::Module::Module(unsigned int detId, unsigned int moduleTypeInfo) { setDetId(detId, moduleTypeInfo); } + +lstgeometry::Module::Module(const Module& module) { + setDetId(module.detId(), module.moduleType(), module.moduleLayerType()); +} + +lstgeometry::Module::~Module() {} + +const unsigned short& lstgeometry::Module::subdet() const { return subdet_; } + +const unsigned short& lstgeometry::Module::side() const { return side_; } + +const unsigned short& lstgeometry::Module::layer() const { return layer_; } + +const unsigned short& lstgeometry::Module::rod() const { return rod_; } + +const unsigned short& lstgeometry::Module::ring() const { return ring_; } + +const unsigned short& lstgeometry::Module::module() const { return module_; } + +const unsigned short& lstgeometry::Module::isLower() const { return isLower_; } + +const unsigned int& lstgeometry::Module::detId() const { return detId_; } + +const unsigned int& lstgeometry::Module::partnerDetId() const { return partnerDetId_; } + +const bool& lstgeometry::Module::isInverted() const { return isInverted_; } + +const lstgeometry::Module::ModuleType& lstgeometry::Module::moduleType() const { return moduleType_; } + +const lstgeometry::Module::ModuleLayerType& lstgeometry::Module::moduleLayerType() const { return moduleLayerType_; } + +void lstgeometry::Module::setDetId(unsigned int detId) { + detId_ = detId; + setDerivedQuantities(); +} + +void lstgeometry::Module::setDetId(unsigned int detId, unsigned int moduleTypeInfo) { + detId_ = detId; + setDerivedQuantities(moduleTypeInfo); +} + +void lstgeometry::Module::setDetId(unsigned int detId, ModuleType moduleType, ModuleLayerType moduleLayerType) { + detId_ = detId; + setDerivedQuantities(moduleType, moduleLayerType); +} + +void lstgeometry::Module::setDerivedQuantities() { + subdet_ = parseSubdet(detId_); + side_ = parseSide(detId_); + layer_ = parseLayer(detId_); + rod_ = parseRod(detId_); + ring_ = parseRing(detId_); + module_ = parseModule(detId_); + isLower_ = parseIsLower(detId_); + isInverted_ = parseIsInverted(detId_); + partnerDetId_ = parsePartnerDetId(detId_); + moduleType_ = parseModuleType(detId_); + moduleLayerType_ = parseModuleLayerType(detId_); +} + +void lstgeometry::Module::setDerivedQuantities(unsigned int moduleTypeInfo) { + subdet_ = parseSubdet(detId_); + side_ = parseSide(detId_); + layer_ = parseLayer(detId_); + rod_ = parseRod(detId_); + ring_ = parseRing(detId_); + module_ = parseModule(detId_); + isLower_ = parseIsLower(detId_); + isInverted_ = parseIsInverted(detId_); + partnerDetId_ = parsePartnerDetId(detId_); + moduleType_ = (moduleTypeInfo == 25 ? lstgeometry::Module::TwoS + : lstgeometry::Module::PS); // 23 : Ph2PSP, 24 : Ph2PSS, 25 : Ph2SS + moduleLayerType_ = (moduleTypeInfo == 23 ? lstgeometry::Module::Pixel + : lstgeometry::Module::Strip); // 23 : Ph2PSP, 24 : Ph2PSS, 25 : Ph2SS +} + +void lstgeometry::Module::setDerivedQuantities(ModuleType moduleType, ModuleLayerType moduleLayerType) { + subdet_ = parseSubdet(detId_); + side_ = parseSide(detId_); + layer_ = parseLayer(detId_); + rod_ = parseRod(detId_); + ring_ = parseRing(detId_); + module_ = parseModule(detId_); + isLower_ = parseIsLower(detId_); + isInverted_ = parseIsInverted(detId_); + partnerDetId_ = parsePartnerDetId(detId_); + moduleType_ = moduleType; + moduleLayerType_ = moduleLayerType; +} + +unsigned short lstgeometry::Module::parseSubdet(unsigned int detId) { return (detId & (7 << 25)) >> 25; } + +unsigned short lstgeometry::Module::parseSide(unsigned int detId) { + if (parseSubdet(detId) == lstgeometry::Module::Endcap) { + return (detId & (3 << 23)) >> 23; + } else if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + return (detId & (3 << 18)) >> 18; + } else { + return 0; + } +} + +unsigned short lstgeometry::Module::parseLayer(unsigned int detId) { + if (parseSubdet(detId) == lstgeometry::Module::Endcap) { + return (detId & (7 << 18)) >> 18; + } else if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + return (detId & (7 << 20)) >> 20; + } else { + return 0; + } +} + +unsigned short lstgeometry::Module::parseRod(unsigned int detId) { + if (parseSubdet(detId) == lstgeometry::Module::Endcap) { + return 0; + } else if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + return (detId & (127 << 10)) >> 10; + } else { + return 0; + } +} + +unsigned short lstgeometry::Module::parseRing(unsigned int detId) { + if (parseSubdet(detId) == lstgeometry::Module::Endcap) { + return (detId & (15 << 12)) >> 12; + } else if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + return 0; + } else { + return 0; + } +} + +unsigned short lstgeometry::Module::parseModule(unsigned int detId) { return (detId & (127 << 2)) >> 2; } + +unsigned short lstgeometry::Module::parseIsLower(unsigned int detId) { + return ((parseIsInverted(detId)) ? !(detId & 1) : (detId & 1)); +} + +bool lstgeometry::Module::parseIsInverted(unsigned int detId) { + if (detId == 1) // "1" detId means "pixel module" where we store all pixel hits/mini/segments into one bucket + return 0; + if (parseSubdet(detId) == lstgeometry::Module::Endcap) { + if (parseSide(detId) == lstgeometry::Module::NegZ) { + return parseModule(detId) % 2 == 1; + } else if (parseSide(detId) == lstgeometry::Module::PosZ) { + return parseModule(detId) % 2 == 0; + } else { + std::cout << "Warning: parseIsInverted() categorization failed" << std::endl; + return 0; + } + } else if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + if (parseSide(detId) == lstgeometry::Module::Center) { + if (parseLayer(detId) <= 3) { + return parseModule(detId) % 2 == 1; + } else if (parseLayer(detId) >= 4) { + return parseModule(detId) % 2 == 0; + } else { + std::cout << "Warning: parseIsInverted() categorization failed" << std::endl; + return 0; + } + } else if (parseSide(detId) == lstgeometry::Module::NegZ or parseSide(detId) == lstgeometry::Module::PosZ) { + if (parseLayer(detId) <= 2) { + return parseModule(detId) % 2 == 1; + } else if (parseLayer(detId) == 3) { + return parseModule(detId) % 2 == 0; + } else { + std::cout << "Warning: parseIsInverted() categorization failed" << std::endl; + return 0; + } + } else { + std::cout << "Warning: parseIsInverted() categorization failed" << std::endl; + return 0; + } + } else { + std::cout << "Warning: parseIsInverted() categorization failed" << std::endl; + return 0; + } +} + +unsigned int lstgeometry::Module::parsePartnerDetId(unsigned int detId) { + if (parseIsLower(detId)) + return ((parseIsInverted(detId)) ? detId - 1 : detId + 1); + else + return ((parseIsInverted(detId)) ? detId + 1 : detId - 1); +} + +lstgeometry::Module::ModuleType lstgeometry::Module::parseModuleType(unsigned int detId) { + if (parseSubdet(detId) == lstgeometry::Module::Barrel) { + if (parseLayer(detId) <= 3) + return lstgeometry::Module::PS; + else + return lstgeometry::Module::TwoS; + } else { + if (parseLayer(detId) <= 2) { + if (parseRing(detId) <= 10) + return lstgeometry::Module::PS; + else + return lstgeometry::Module::TwoS; + } else { + if (parseRing(detId) <= 7) + return lstgeometry::Module::PS; + else + return lstgeometry::Module::TwoS; + } + } +} + +lstgeometry::Module::ModuleLayerType lstgeometry::Module::parseModuleLayerType(unsigned int detId) { + if (parseModuleType(detId) == lstgeometry::Module::TwoS) + return lstgeometry::Module::Strip; + if (parseIsInverted(detId)) { + if (parseIsLower(detId)) + return lstgeometry::Module::Strip; + else + return lstgeometry::Module::Pixel; + } else { + if (parseIsLower(detId)) + return lstgeometry::Module::Pixel; + else + return lstgeometry::Module::Strip; + } +} + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h b/RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h new file mode 100644 index 0000000000000..d3fea87091ed4 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h @@ -0,0 +1,24 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_ModuleInfo_h +#define RecoTracker_LSTCore_interface_LSTGeometry_ModuleInfo_h + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" + +namespace lstgeometry { + + struct ModuleInfo { + unsigned int detId; + double sensorCenterRho_cm; + double sensorCenterZ_cm; + double tiltAngle_rad; + double skewAngle_rad; + double yawAngle_rad; + double phi_rad; + double meanWidth_cm; + double length_cm; + double sensorSpacing_cm; + MatrixD8x3 transformedCorners; + }; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/ModuleMapMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/ModuleMapMethods.h new file mode 100644 index 0000000000000..856a27bc67a6c --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/ModuleMapMethods.h @@ -0,0 +1,298 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_ModuleMapMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_ModuleMapMethods_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTMath.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Module.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h" + +namespace lstgeometry { + + std::vector getStraightLineConnections(unsigned int ref_detid, + std::unordered_map const& centroids, + DetectorGeometry const& det_geom) { + auto centroid = centroids.at(ref_detid); + + double refphi = std::atan2(centroid.y, centroid.x); + + Module refmodule(ref_detid); + + unsigned short ref_layer = refmodule.layer(); + unsigned short ref_subdet = refmodule.subdet(); + + auto etaphi = getEtaPhi(centroid.x, centroid.y, centroid.z); + auto etaphibins = getEtaPhiBins(etaphi.first, etaphi.second); + + auto const& tar_detids_to_be_considered = + ref_subdet == 5 ? det_geom.getBarrelLayerDetIds(ref_layer + 1, etaphibins.first, etaphibins.second) + : det_geom.getEndcapLayerDetIds(ref_layer + 1, etaphibins.first, etaphibins.second); + + std::vector list_of_detids_etaphi_layer_tar; + for (unsigned int tar_detid : tar_detids_to_be_considered) { + if (moduleOverlapsInEtaPhi(det_geom.getCorners(ref_detid), det_geom.getCorners(tar_detid), refphi, 0) || + moduleOverlapsInEtaPhi(det_geom.getCorners(ref_detid), det_geom.getCorners(tar_detid), refphi, 10) || + moduleOverlapsInEtaPhi(det_geom.getCorners(ref_detid), det_geom.getCorners(tar_detid), refphi, -10)) + list_of_detids_etaphi_layer_tar.push_back(tar_detid); + } + + // Consider barrel to endcap connections if the intersection area is > 0 + // We construct the reference polygon as a vector of polygons because the boost::geometry::difference + // function can return multiple polygons if the difference results in disjoint pieces + if (ref_subdet == 5) { + std::unordered_set barrel_endcap_connected_tar_detids; + + for (float zshift : {0, 10, -10}) { + std::vector ref_polygon; + ref_polygon.push_back(getEtaPhiPolygon(det_geom.getCorners(ref_detid), refphi, zshift)); + + // Check whether there is still significant non-zero area + for (unsigned int tar_detid : list_of_detids_etaphi_layer_tar) { + if (!ref_polygon.size()) + break; + Polygon tar_polygon = getEtaPhiPolygon(det_geom.getCorners(tar_detid), refphi, zshift); + + std::vector difference; + for (auto& ref_polygon_piece : ref_polygon) { + std::vector tmp_difference; + boost::geometry::difference(ref_polygon_piece, tar_polygon, tmp_difference); + difference.insert(difference.end(), tmp_difference.begin(), tmp_difference.end()); + } + + ref_polygon = std::move(difference); + } + + double area = 0.; + for (auto& ref_polygon_piece : ref_polygon) + area += boost::geometry::area(ref_polygon_piece); + + if (area <= 1e-6) + continue; + + auto const& new_tar_detids_to_be_considered = + det_geom.getEndcapLayerDetIds(1, etaphibins.first, etaphibins.second); + + for (unsigned int tar_detid : new_tar_detids_to_be_considered) { + auto centroid_target = centroids.at(tar_detid); + double tarphi = std::atan2(centroid_target.y, centroid_target.x); + + if (std::fabs(phi_mpi_pi(tarphi - refphi)) > std::numbers::pi_v / 2.) + continue; + + Polygon tar_polygon = getEtaPhiPolygon(det_geom.getCorners(tar_detid), refphi, zshift); + + bool intersects = false; + for (auto& ref_polygon_piece : ref_polygon) { + if (boost::geometry::intersects(ref_polygon_piece, tar_polygon)) { + intersects = true; + break; + } + } + + if (intersects) + barrel_endcap_connected_tar_detids.insert(tar_detid); + } + } + list_of_detids_etaphi_layer_tar.insert(list_of_detids_etaphi_layer_tar.end(), + barrel_endcap_connected_tar_detids.begin(), + barrel_endcap_connected_tar_detids.end()); + } + + return list_of_detids_etaphi_layer_tar; + } + + MatrixD4x3 boundsAfterCurved(unsigned int ref_detid, + std::unordered_map const& centroids, + DetectorGeometry const& det_geom, + double ptCut, + bool doR = true) { + auto bounds = det_geom.getCorners(ref_detid); + auto centroid = centroids.at(ref_detid); + int charge = 1; + double theta = std::atan2(std::sqrt(centroid.x * centroid.x + centroid.y * centroid.y), centroid.z); + double refphi = std::atan2(centroid.y, centroid.x); + Module refmodule(ref_detid); + unsigned short ref_layer = refmodule.layer(); + unsigned short ref_subdet = refmodule.subdet(); + MatrixD4x3 next_layer_bound_points; + + for (int i = 0; i < bounds.rows(); i++) { + Helix helix_p10 = constructHelixFromPoints(ptCut, 0, 0, 10, bounds(i, 1), bounds(i, 2), bounds(i, 0), -charge); + Helix helix_m10 = constructHelixFromPoints(ptCut, 0, 0, -10, bounds(i, 1), bounds(i, 2), bounds(i, 0), -charge); + Helix helix_p10_pos = constructHelixFromPoints(ptCut, 0, 0, 10, bounds(i, 1), bounds(i, 2), bounds(i, 0), charge); + Helix helix_m10_pos = + constructHelixFromPoints(ptCut, 0, 0, -10, bounds(i, 1), bounds(i, 2), bounds(i, 0), charge); + double bound_theta = + std::atan2(std::sqrt(bounds(i, 1) * bounds(i, 1) + bounds(i, 2) * bounds(i, 2)), bounds(i, 0)); + double bound_phi = std::atan2(bounds(i, 2), bounds(i, 1)); + double phi_diff = phi_mpi_pi(bound_phi - refphi); + + std::tuple next_point; + if (ref_subdet == 5) { + if (doR) { + double tar_layer_radius = det_geom.getBarrelLayerAverageRadius(ref_layer + 1); + if (bound_theta > theta) { + next_point = getHelixPointFromRadius(phi_diff > 0 ? helix_p10 : helix_p10_pos, tar_layer_radius); + } else { + next_point = getHelixPointFromRadius(phi_diff > 0 ? helix_m10 : helix_m10_pos, tar_layer_radius); + } + } else { + double tar_layer_z = det_geom.getEndcapLayerAverageAbsZ(1); + if (bound_theta > theta) { + if (phi_diff > 0) { + next_point = getHelixPointFromZ(helix_p10, std::copysign(tar_layer_z, helix_p10.lam)); + } else { + next_point = getHelixPointFromZ(helix_p10_pos, std::copysign(tar_layer_z, helix_p10_pos.lam)); + } + } else { + if (phi_diff > 0) { + next_point = getHelixPointFromZ(helix_m10, std::copysign(tar_layer_z, helix_p10.lam)); + } else { + next_point = getHelixPointFromZ(helix_m10_pos, std::copysign(tar_layer_z, helix_p10_pos.lam)); + } + } + } + } else { + double tar_layer_z = det_geom.getEndcapLayerAverageAbsZ(ref_layer + 1); + if (bound_theta > theta) { + if (phi_diff > 0) { + next_point = getHelixPointFromZ(helix_p10, std::copysign(tar_layer_z, helix_p10.lam)); + } else { + next_point = getHelixPointFromZ(helix_p10_pos, std::copysign(tar_layer_z, helix_p10_pos.lam)); + } + } else { + if (phi_diff > 0) { + next_point = getHelixPointFromZ(helix_m10, std::copysign(tar_layer_z, helix_m10.lam)); + } else { + next_point = getHelixPointFromZ(helix_m10_pos, std::copysign(tar_layer_z, helix_m10_pos.lam)); + } + } + } + next_layer_bound_points(i, 0) = std::get<2>(next_point); + next_layer_bound_points(i, 1) = std::get<0>(next_point); + next_layer_bound_points(i, 2) = std::get<1>(next_point); + } + + return next_layer_bound_points; + } + + std::vector getCurvedLineConnections(unsigned int ref_detid, + std::unordered_map const& centroids, + DetectorGeometry const& det_geom, + double ptCut) { + auto centroid = centroids.at(ref_detid); + + double refphi = std::atan2(centroid.y, centroid.x); + + Module refmodule(ref_detid); + + unsigned short ref_layer = refmodule.layer(); + unsigned short ref_subdet = refmodule.subdet(); + + auto etaphi = getEtaPhi(centroid.x, centroid.y, centroid.z); + auto etaphibins = getEtaPhiBins(etaphi.first, etaphi.second); + + auto const& tar_detids_to_be_considered = + ref_subdet == 5 ? det_geom.getBarrelLayerDetIds(ref_layer + 1, etaphibins.first, etaphibins.second) + : det_geom.getEndcapLayerDetIds(ref_layer + 1, etaphibins.first, etaphibins.second); + + auto next_layer_bound_points = boundsAfterCurved(ref_detid, centroids, det_geom, ptCut); + + std::vector list_of_detids_etaphi_layer_tar; + for (unsigned int tar_detid : tar_detids_to_be_considered) { + if (moduleOverlapsInEtaPhi(next_layer_bound_points, det_geom.getCorners(tar_detid), refphi, 0)) + list_of_detids_etaphi_layer_tar.push_back(tar_detid); + } + + // Consider barrel to endcap connections if the intersection area is > 0 + // We construct the reference polygon as a vector of polygons because the boost::geometry::difference + // function can return multiple polygons if the difference results in disjoint pieces + if (ref_subdet == 5) { + std::unordered_set barrel_endcap_connected_tar_detids; + + int zshift = 0; + + std::vector ref_polygon; + ref_polygon.push_back(getEtaPhiPolygon(next_layer_bound_points, refphi, zshift)); + + // Check whether there is still significant non-zero area + for (unsigned int tar_detid : list_of_detids_etaphi_layer_tar) { + if (!ref_polygon.size()) + break; + Polygon tar_polygon = getEtaPhiPolygon(det_geom.getCorners(tar_detid), refphi, zshift); + + std::vector difference; + for (auto& ref_polygon_piece : ref_polygon) { + std::vector tmp_difference; + boost::geometry::difference(ref_polygon_piece, tar_polygon, tmp_difference); + difference.insert(difference.end(), tmp_difference.begin(), tmp_difference.end()); + } + + ref_polygon = std::move(difference); + } + + double area = 0.; + for (auto& ref_polygon_piece : ref_polygon) + area += boost::geometry::area(ref_polygon_piece); + + if (area > 1e-6) { + auto const& new_tar_detids_to_be_considered = + det_geom.getEndcapLayerDetIds(1, etaphibins.first, etaphibins.second); + + for (unsigned int tar_detid : new_tar_detids_to_be_considered) { + auto centroid_target = centroids.at(tar_detid); + double tarphi = std::atan2(centroid_target.y, centroid_target.x); + + if (std::fabs(phi_mpi_pi(tarphi - refphi)) > std::numbers::pi_v / 2.) + continue; + + Polygon tar_polygon = getEtaPhiPolygon(det_geom.getCorners(tar_detid), refphi, zshift); + + bool intersects = false; + for (auto& ref_polygon_piece : ref_polygon) { + if (boost::geometry::intersects(ref_polygon_piece, tar_polygon)) { + intersects = true; + break; + } + } + + if (intersects) + barrel_endcap_connected_tar_detids.insert(tar_detid); + } + } + + list_of_detids_etaphi_layer_tar.insert(list_of_detids_etaphi_layer_tar.end(), + barrel_endcap_connected_tar_detids.begin(), + barrel_endcap_connected_tar_detids.end()); + } + + return list_of_detids_etaphi_layer_tar; + } + + std::unordered_map> mergeLineConnections( + std::initializer_list>*> connections_list) { + std::unordered_map> merged; + + for (auto* connections : connections_list) { + for (const auto& [detid, list] : *connections) { + auto& target = merged[detid]; + target.insert(list.begin(), list.end()); + } + } + + return merged; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/OrientationMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/OrientationMethods.h new file mode 100644 index 0000000000000..5e2b128a41887 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/OrientationMethods.h @@ -0,0 +1,55 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_OrientationMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_OrientationMethods_h + +#include +#include +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/CentroidMethods.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/SlopeData.h" + +namespace lstgeometry { + + // Use each sensor's corners to calculate and categorize drdz and dxdy slopes. + SlopeData calculateSlope(double dx, double dy, double dz) { + double dr = sqrt(dx * dx + dy * dy); + double drdz_slope = dz != 0 ? dr / dz : kDefaultSlope; + double dxdy_slope = dy != 0 ? -dx / dy : kDefaultSlope; + return SlopeData{drdz_slope, dxdy_slope}; + } + + // Use each sensor's corners to calculate and categorize drdz and dxdy slopes. + std::tuple, std::unordered_map> processCorners( + std::unordered_map& corners) { + std::unordered_map barrel_slopes; + std::unordered_map endcap_slopes; + + for (const auto& [detId, corners] : corners) { + double dx = roundCoordinate(corners(1, 1) - corners(0, 1)); + double dy = roundCoordinate(corners(1, 2) - corners(0, 2)); + double dz = roundCoordinate(corners(1, 0) - corners(0, 0)); + + SlopeData slope = calculateSlope(dx, dy, dz); + + unsigned int module_type = static_cast(parseModuleType(detId)); + Module module(detId, module_type); + + unsigned short subdet = module.subdet(); + bool is_tilted = module.side() != 3; + bool is_strip = module.moduleLayerType() == 1; + + if (!is_strip) + continue; + + if (subdet == Module::SubDet::Barrel and is_tilted) + barrel_slopes[detId] = slope; + else if (subdet == Module::SubDet::Endcap) + endcap_slopes[detId] = slope; + } + + return std::make_tuple(barrel_slopes, endcap_slopes); + } +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/PixelMap.h b/RecoTracker/LSTCore/interface/LSTGeometry/PixelMap.h new file mode 100644 index 0000000000000..8a9fba984c0e2 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/PixelMap.h @@ -0,0 +1,19 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_PixelMap_h +#define RecoTracker_LSTCore_interface_LSTGeometry_PixelMap_h + +#include +#include +#include +#include + +namespace lstgeometry { + + using LayerSubdetChargeKey = std::tuple; + using LayerSubdetChargeMap = std::unordered_map>, + boost::hash>; + using PixelMap = LayerSubdetChargeMap; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/PixelMapMethods.h b/RecoTracker/LSTCore/interface/LSTGeometry/PixelMapMethods.h new file mode 100644 index 0000000000000..9a05c6ca7fc4f --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/PixelMapMethods.h @@ -0,0 +1,139 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_PixelMapMethods_h +#define RecoTracker_LSTCore_interface_LSTGeometry_PixelMapMethods_h + +#include + +#include "RecoTracker/LSTCore/interface/LSTGeometry/Common.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Centroid.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/DetectorGeometry.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Module.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/PixelMap.h" + +namespace lstgeometry { + + PixelMap computePixelMap(std::unordered_map const& centroids, + DetectorGeometry const& det_geom, + double ptCut) { + // Charge 0 is the union of charge 1 and charge -1 + PixelMap maps; + + std::size_t nSuperbin = kPtBounds.size() * kNPhi * kNEta * kNZ; + + // Initialize empty lists for the pixel map + for (unsigned int layer : {1, 2}) { + for (unsigned int subdet : {4, 5}) { + for (int charge : {-1, 0, 1}) { + maps.try_emplace({layer, subdet, charge}, nSuperbin); + } + } + } + + // Loop over the detids and for each detid compute which superbins it is connected to + for (auto detId : det_geom.getDetIds()) { + auto centroid = centroids.at(detId); + + // Parse the layer and subdet + auto module = Module(detId, centroid.moduleType); + auto layer = module.layer(); + if (layer > 2) + continue; + auto subdet = module.subdet(); + + // Skip if the module is not PS module and is not lower module + if (module.isLower() != 1 || module.moduleType() != 0) + continue; + + // For this module, now compute which super bins they belong to + // To compute which super bins it belongs to, one needs to provide at least pt and z window to compute compatible eta and phi range + // So we have a loop in pt and Z + for (unsigned int ipt = 0; ipt < kPtBounds.size(); ipt++) { + for (unsigned int iz = 0; iz < kNZ; iz++) { + // The zmin, zmax of consideration + double zmin = -30 + iz * (60. / kNZ); + double zmax = -30 + (iz + 1) * (60. / kNZ); + + zmin -= 0.05; + zmax += 0.05; + + // The ptmin, ptmax of consideration + double pt_lo = ipt == 0 ? ptCut : kPtBounds[ipt - 1]; + double pt_hi = kPtBounds[ipt]; + + auto [etamin, etamax] = det_geom.getCompatibleEtaRange(detId, zmin, zmax); + + etamin -= 0.05; + etamax += 0.05; + + if (layer == 2 && subdet == 4) { + if (etamax < 2.3) + continue; + if (etamin < 2.3) + etamin = 2.3; + } + + // Compute the indices of the compatible eta range + unsigned int ietamin = static_cast(std::max((etamin + 2.6) / (5.2 / kNEta), 0.0)); + unsigned int ietamax = + static_cast(std::min((etamax + 2.6) / (5.2 / kNEta), static_cast(kNEta - 1))); + + auto phi_ranges = det_geom.getCompatiblePhiRange(detId, pt_lo, pt_hi); + + unsigned int iphimin_pos = static_cast((phi_ranges.first.first + std::numbers::pi_v) / + (2. * std::numbers::pi_v / kNPhi)); + unsigned int iphimax_pos = static_cast((phi_ranges.first.second + std::numbers::pi_v) / + (2. * std::numbers::pi_v / kNPhi)); + unsigned int iphimin_neg = static_cast((phi_ranges.second.first + std::numbers::pi_v) / + (2. * std::numbers::pi_v / kNPhi)); + unsigned int iphimax_neg = static_cast((phi_ranges.second.second + std::numbers::pi_v) / + (2. * std::numbers::pi_v / kNPhi)); + + // <= to cover some inefficiencies + for (unsigned int ieta = ietamin; ieta <= ietamax; ieta++) { + // if the range is crossing the -pi v. pi boundary special care is needed + if (iphimin_pos <= iphimax_pos) { + for (unsigned int iphi = iphimin_pos; iphi < iphimax_pos; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, 1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + } else { + for (unsigned int iphi = 0; iphi < iphimax_pos; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, 1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + for (unsigned int iphi = iphimin_pos; iphi < kNPhi; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, 1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + } + if (iphimin_neg <= iphimax_neg) { + for (unsigned int iphi = iphimin_neg; iphi < iphimax_neg; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, -1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + } else { + for (unsigned int iphi = 0; iphi < iphimax_neg; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, -1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + for (unsigned int iphi = iphimin_neg; iphi < kNPhi; iphi++) { + unsigned int isuperbin = (ipt * kNPhi * kNEta * kNZ) + (ieta * kNPhi * kNZ) + (iphi * kNZ) + iz; + maps[{layer, subdet, -1}][isuperbin].insert(detId); + maps[{layer, subdet, 0}][isuperbin].insert(detId); + } + } + } + } + } + } + + return maps; + } + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h b/RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h new file mode 100644 index 0000000000000..ffd6f336e3d4d --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h @@ -0,0 +1,16 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_SensorInfo_h +#define RecoTracker_LSTCore_interface_LSTGeometry_SensorInfo_h + +#include + +namespace lstgeometry { + + struct SensorInfo { + unsigned int detId; + double sensorCenterRho_cm; + double sensorCenterZ_cm; + double phi_rad; + }; +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/LSTGeometry/SlopeData.h b/RecoTracker/LSTCore/interface/LSTGeometry/SlopeData.h new file mode 100644 index 0000000000000..84d4aa4503ea1 --- /dev/null +++ b/RecoTracker/LSTCore/interface/LSTGeometry/SlopeData.h @@ -0,0 +1,13 @@ +#ifndef RecoTracker_LSTCore_interface_LSTGeometry_SlopeData_h +#define RecoTracker_LSTCore_interface_LSTGeometry_SlopeData_h + +namespace lstgeometry { + + struct SlopeData { + double drdz_slope; + double dxdy_slope; + }; + +} // namespace lstgeometry + +#endif diff --git a/RecoTracker/LSTCore/interface/ModuleConnectionMap.h b/RecoTracker/LSTCore/interface/ModuleConnectionMap.h index 63c3496523c0d..7df14a0d0cf34 100644 --- a/RecoTracker/LSTCore/interface/ModuleConnectionMap.h +++ b/RecoTracker/LSTCore/interface/ModuleConnectionMap.h @@ -14,8 +14,10 @@ namespace lst { public: ModuleConnectionMap(); ModuleConnectionMap(std::string const& filename); + ModuleConnectionMap(std::map> const&); void load(std::string const&); + void load(std::map> const&); void add(std::string const&); void print(); diff --git a/RecoTracker/LSTCore/interface/TiltedGeometry.h b/RecoTracker/LSTCore/interface/TiltedGeometry.h index 7a17106195522..2545ff4c0d11e 100644 --- a/RecoTracker/LSTCore/interface/TiltedGeometry.h +++ b/RecoTracker/LSTCore/interface/TiltedGeometry.h @@ -1,6 +1,8 @@ #ifndef RecoTracker_LSTCore_interface_TiltedGeometry_h #define RecoTracker_LSTCore_interface_TiltedGeometry_h +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" + #include #include #include @@ -16,6 +18,7 @@ namespace lst { TiltedGeometry(std::string const& filename); void load(std::string const&); + void load(std::unordered_map const&); float getDrDz(unsigned int detid) const; float getDxDy(unsigned int detid) const; diff --git a/RecoTracker/LSTCore/interface/alpaka/Common.h b/RecoTracker/LSTCore/interface/alpaka/Common.h index 5ed0546351490..84c0083b53403 100644 --- a/RecoTracker/LSTCore/interface/alpaka/Common.h +++ b/RecoTracker/LSTCore/interface/alpaka/Common.h @@ -43,8 +43,6 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE::lst { HOST_DEVICE_CONSTANT float kWidthPS = 0.01; HOST_DEVICE_CONSTANT float kPt_betaMax = 7.0; HOST_DEVICE_CONSTANT int kNTripletThreshold = 1000; - // To be updated with std::numeric_limits::infinity() in the code and data files - HOST_DEVICE_CONSTANT float kVerticalModuleSlope = 123456789.0; HOST_DEVICE_CONSTANT int kLogicalOTLayers = 11; // logical OT layers are 1..11 HOST_DEVICE_CONSTANT float kMiniDeltaTilted[3] = {0.26f, 0.26f, 0.26f}; diff --git a/RecoTracker/LSTCore/plugins/BuildFile.xml b/RecoTracker/LSTCore/plugins/BuildFile.xml new file mode 100644 index 0000000000000..0b73a4fffed62 --- /dev/null +++ b/RecoTracker/LSTCore/plugins/BuildFile.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RecoTracker/LSTCore/plugins/LSTGeometryESProducer.cc b/RecoTracker/LSTCore/plugins/LSTGeometryESProducer.cc new file mode 100644 index 0000000000000..f579da887a9b8 --- /dev/null +++ b/RecoTracker/LSTCore/plugins/LSTGeometryESProducer.cc @@ -0,0 +1,141 @@ +#include "FWCore/Framework/interface/ModuleFactory.h" +#include "FWCore/Framework/interface/ESProducer.h" + +#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h" +#include "RecoTracker/Record/interface/TrackerRecoGeometryRecord.h" +#include "DataFormats/GeometrySurface/interface/RectangularPlaneBounds.h" +#include "Geometry/CommonTopologies/interface/GeomDetEnumerators.h" + +// LST includes +#include "RecoTracker/LSTCore/interface/LSTGeometry/SensorInfo.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/ModuleInfo.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/Module.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometryMethods.h" + +#include +#include +#include + +class LSTGeometryESProducer : public edm::ESProducer { +public: + LSTGeometryESProducer(const edm::ParameterSet &iConfig); + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions); + + std::unique_ptr produce(const TrackerRecoGeometryRecord &iRecord); + +private: + double ptCut_; + + edm::ESGetToken geomToken_; + + const TrackerGeometry *trackerGeom_ = nullptr; +}; + +LSTGeometryESProducer::LSTGeometryESProducer(const edm::ParameterSet &iConfig) + : ptCut_(iConfig.getParameter("ptCut")) { + auto cc = setWhatProduced(this, "LSTGeometry"); + geomToken_ = cc.consumes(); +} + +void LSTGeometryESProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + edm::ParameterSetDescription desc; + desc.add("ptCut", 0.8); + descriptions.addWithDefaultLabel(desc); +} + +std::unique_ptr LSTGeometryESProducer::produce(const TrackerRecoGeometryRecord &iRecord) { + trackerGeom_ = &iRecord.get(geomToken_); + + std::vector modules; + std::unordered_map sensors; + + std::vector avg_r_cm(6, 0.0); + std::vector avg_z_cm(5, 0.0); + std::vector avg_r_counter(6, 0); + std::vector avg_z_counter(5, 0); + + for (auto &det : trackerGeom_->dets()) { + const DetId detId = det->geographicalId(); + + const auto &surface = det->surface(); + const Bounds *b = &(surface).bounds(); + const auto &position = surface.position(); + + const double rho_cm = position.perp(); + const double z_cm = lstgeometry::roundCoordinate(position.z()); + const double phi_rad = lstgeometry::roundAngle(position.phi()); + + if (det->isLeaf()) { + // Leafs are the sensors + lstgeometry::SensorInfo sensor{detId(), rho_cm, z_cm, phi_rad}; + sensors[detId()] = std::move(sensor); + continue; + } + + const RectangularPlaneBounds *b2 = dynamic_cast(b); + if (!b2) { + throw cms::Exception("UnimplementedFeature") << "unsupported Bounds class"; + } + + double tiltAngle_rad = lstgeometry::roundAngle(std::asin(det->rotation().zz())); + + double meanWidth_cm = b2->width(); + double length_cm = b2->length(); + + double sensorSpacing_cm = det->components()[0]->toLocal(det->components()[1]->position()).mag(); + + unsigned int detid = detId(); + + unsigned short layer = lstgeometry::Module::parseLayer(detid); + + // This part is a little weird, but this is how to match the csv files. + // I think it might be better to not do this since other parts of the code + // assume the center of the module is at (rho_cm, z_cm). + // + // z_cm += sensorSpacing_cm / 2.0 * std::sin(tiltAngle_rad); + // bool isFlipped = surface.normalVector().basicVector().dot(position.basicVector()) < 0; + // rho_cm += (isFlipped ? -1 : 1) * signsensorSpacing_cm / 2.0 * std::cos(tiltAngle_rad); + + // Fix angles of some modules + if (std::fabs(std::fabs(tiltAngle_rad) - std::numbers::pi_v / 2) < 1e-3) { + tiltAngle_rad = std::numbers::pi_v / 2; + } else if (std::fabs(tiltAngle_rad) > 1e-3) { + tiltAngle_rad = std::copysign(tiltAngle_rad, z_cm); + } + + if (lstgeometry::Module::parseSubdet(detid) == lstgeometry::Module::SubDet::Barrel) { + avg_r_cm[layer - 1] += rho_cm; + avg_r_counter[layer - 1] += 1; + } else { + avg_z_cm[layer - 1] += std::fabs(z_cm); + avg_z_counter[layer - 1] += 1; + } + + lstgeometry::ModuleInfo module{detid, + rho_cm, + z_cm, + tiltAngle_rad, + 0.0, + 0.0, + phi_rad, + meanWidth_cm, + length_cm, + sensorSpacing_cm, + lstgeometry::MatrixD8x3::Zero()}; + modules.push_back(module); + } + + for (size_t i = 0; i < avg_r_cm.size(); ++i) { + avg_r_cm[i] /= avg_r_counter[i]; + } + for (size_t i = 0; i < avg_z_cm.size(); ++i) { + avg_z_cm[i] /= avg_z_counter[i]; + } + + auto lstGeometry = makeLSTGeometry(modules, sensors, avg_r_cm, avg_z_cm, ptCut_); + + return lstGeometry; +} + +DEFINE_FWK_EVENTSETUP_MODULE(LSTGeometryESProducer); diff --git a/RecoTracker/LSTCore/src/ES_LSTGeometry.cc b/RecoTracker/LSTCore/src/ES_LSTGeometry.cc new file mode 100644 index 0000000000000..5254589aa904e --- /dev/null +++ b/RecoTracker/LSTCore/src/ES_LSTGeometry.cc @@ -0,0 +1,7 @@ +#ifndef LST_STANDALONE + +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" +#include "FWCore/Utilities/interface/typelookup.h" +TYPELOOKUP_DATA_REG(lstgeometry::LSTGeometry); + +#endif diff --git a/RecoTracker/LSTCore/src/EndcapGeometry.cc b/RecoTracker/LSTCore/src/EndcapGeometry.cc index 17e72379bb2ec..549c8f501e859 100644 --- a/RecoTracker/LSTCore/src/EndcapGeometry.cc +++ b/RecoTracker/LSTCore/src/EndcapGeometry.cc @@ -39,6 +39,19 @@ void lst::EndcapGeometry::load(std::string const& filename) { fillGeoMapArraysExplicit(); } +void lst::EndcapGeometry::load(std::unordered_map const& slopes, + std::unordered_map const& sensors) { + dxdy_slope_.clear(); + centroid_phis_.clear(); + + for (const auto& [detId, slopeData] : slopes) { + dxdy_slope_[detId] = slopeData.dxdy_slope; + centroid_phis_[detId] = sensors.at(detId).phi_rad; + } + + fillGeoMapArraysExplicit(); +} + void lst::EndcapGeometry::fillGeoMapArraysExplicit() { nEndCapMap = centroid_phis_.size(); diff --git a/RecoTracker/LSTCore/src/LSTESData.cc b/RecoTracker/LSTCore/src/LSTESData.cc index 4f74ac486e1b1..8b4f56e693df0 100644 --- a/RecoTracker/LSTCore/src/LSTESData.cc +++ b/RecoTracker/LSTCore/src/LSTESData.cc @@ -7,6 +7,8 @@ #include "ModuleMethods.h" #include +#include +#include namespace { std::string geometryDataDir() { @@ -119,3 +121,83 @@ std::unique_ptr> lst::loadAndFillESHost(s std::move(endcapGeometryDev), pixelMappingPtr); } + +std::unique_ptr> lst::loadAndFillESHost(lstgeometry::LSTGeometry const& lstg) { + uint16_t nModules; + uint16_t nLowerModules; + unsigned int nPixels; + MapPLStoLayer pLStoLayer; + EndcapGeometry endcapGeometry; + TiltedGeometry tiltedGeometry; + PixelMap pixelMapping; + ModuleConnectionMap moduleConnectionMap; + + endcapGeometry.load(lstg.endcap_slopes, lstg.sensor_info); + auto endcapGeometryDev = + std::make_shared(endcapGeometry.nEndCapMap, cms::alpakatools::host()); + std::memcpy(endcapGeometryDev->view().geoMapDetId().data(), + endcapGeometry.geoMapDetId_buf.data(), + endcapGeometry.nEndCapMap * sizeof(unsigned int)); + std::memcpy(endcapGeometryDev->view().geoMapPhi().data(), + endcapGeometry.geoMapPhi_buf.data(), + endcapGeometry.nEndCapMap * sizeof(float)); + + tiltedGeometry.load(lstg.barrel_slopes); + + std::map> final_modulemap; + for (auto const& [detId, connections] : lstg.merged_line_connections) { + final_modulemap[detId] = std::vector(connections.begin(), connections.end()); + } + moduleConnectionMap.load(final_modulemap); + + for (auto& [layersubdetcharge, map] : lstg.pixel_map) { + auto& [layer, subdet, charge] = layersubdetcharge; + + std::map> final_pixelmap; + for (unsigned int isuperbin = 0; isuperbin < map.size(); isuperbin++) { + auto const& set = map.at(isuperbin); + final_pixelmap[isuperbin] = std::vector(set.begin(), set.end()); + } + + if (charge == 0) { + pLStoLayer[0][layer - 1 + (subdet == 4 ? 2 : 0)] = lst::ModuleConnectionMap(final_pixelmap); + } else if (charge > 0) { + pLStoLayer[1][layer - 1 + (subdet == 4 ? 2 : 0)] = lst::ModuleConnectionMap(final_pixelmap); + } else { + pLStoLayer[2][layer - 1 + (subdet == 4 ? 2 : 0)] = lst::ModuleConnectionMap(final_pixelmap); + } + } + + ModuleMetaData mmd; + unsigned int counter = 0; + for (auto const& [detId, centroid] : lstg.centroids) { + mmd.detIdToIndex[detId] = counter; + mmd.module_x[detId] = centroid.x; + mmd.module_y[detId] = centroid.y; + mmd.module_z[detId] = centroid.z; + mmd.module_type[detId] = centroid.moduleType; + counter++; + } + mmd.detIdToIndex[1] = counter; //pixel module is the last module in the module list + counter++; + nModules = counter; + + auto modulesBuffers = constructModuleCollection(pLStoLayer, + mmd, + nModules, + nLowerModules, + nPixels, + pixelMapping, + endcapGeometry, + tiltedGeometry, + moduleConnectionMap); + + auto pixelMappingPtr = std::make_shared(std::move(pixelMapping)); + return std::make_unique>(nModules, + nLowerModules, + nPixels, + endcapGeometry.nEndCapMap, + std::move(modulesBuffers), + std::move(endcapGeometryDev), + pixelMappingPtr); +} diff --git a/RecoTracker/LSTCore/src/ModuleConnectionMap.cc b/RecoTracker/LSTCore/src/ModuleConnectionMap.cc index 0da0f4cc4ac6f..ca1c39a895ea4 100644 --- a/RecoTracker/LSTCore/src/ModuleConnectionMap.cc +++ b/RecoTracker/LSTCore/src/ModuleConnectionMap.cc @@ -9,6 +9,10 @@ lst::ModuleConnectionMap::ModuleConnectionMap() {} lst::ModuleConnectionMap::ModuleConnectionMap(std::string const& filename) { load(filename); } +lst::ModuleConnectionMap::ModuleConnectionMap(std::map> const& map) { + load(map); +} + void lst::ModuleConnectionMap::load(std::string const& filename) { moduleConnections_.clear(); @@ -53,6 +57,10 @@ void lst::ModuleConnectionMap::load(std::string const& filename) { } } +void lst::ModuleConnectionMap::load(std::map> const& map) { + moduleConnections_ = map; +} + void lst::ModuleConnectionMap::add(std::string const& filename) { std::ifstream ifile; ifile.open(filename.c_str()); diff --git a/RecoTracker/LSTCore/src/ModuleMethods.h b/RecoTracker/LSTCore/src/ModuleMethods.h index 05b1ff68eb53c..18c64e6ba4393 100644 --- a/RecoTracker/LSTCore/src/ModuleMethods.h +++ b/RecoTracker/LSTCore/src/ModuleMethods.h @@ -218,19 +218,16 @@ namespace lst { nModules = counter; } - inline std::shared_ptr loadModulesFromFile(MapPLStoLayer const& pLStoLayer, - const char* moduleMetaDataFilePath, - uint16_t& nModules, - uint16_t& nLowerModules, - unsigned int& nPixels, - PixelMap& pixelMapping, - const EndcapGeometry& endcapGeometry, - const TiltedGeometry& tiltedGeometry, - const ModuleConnectionMap& moduleConnectionMap) { - ModuleMetaData mmd; - - loadCentroidsFromFile(moduleMetaDataFilePath, mmd, nModules); - + inline std::shared_ptr constructModuleCollection( + MapPLStoLayer const& pLStoLayer, + ModuleMetaData& mmd, + uint16_t& nModules, + uint16_t& nLowerModules, + unsigned int& nPixels, + PixelMap& pixelMapping, + const EndcapGeometry& endcapGeometry, + const TiltedGeometry& tiltedGeometry, + const ModuleConnectionMap& moduleConnectionMap) { // TODO: this whole section could use some refactoring auto [totalSizes, connectedModuleDetIds, @@ -404,5 +401,29 @@ namespace lst { return modulesHC; } + + inline std::shared_ptr loadModulesFromFile(MapPLStoLayer const& pLStoLayer, + const char* moduleMetaDataFilePath, + uint16_t& nModules, + uint16_t& nLowerModules, + unsigned int& nPixels, + PixelMap& pixelMapping, + const EndcapGeometry& endcapGeometry, + const TiltedGeometry& tiltedGeometry, + const ModuleConnectionMap& moduleConnectionMap) { + ModuleMetaData mmd; + + loadCentroidsFromFile(moduleMetaDataFilePath, mmd, nModules); + return constructModuleCollection(pLStoLayer, + mmd, + nModules, + nLowerModules, + nPixels, + pixelMapping, + endcapGeometry, + tiltedGeometry, + moduleConnectionMap); + } + } // namespace lst #endif diff --git a/RecoTracker/LSTCore/src/TiltedGeometry.cc b/RecoTracker/LSTCore/src/TiltedGeometry.cc index d65a9a4a5f7b9..2c579cfed2020 100644 --- a/RecoTracker/LSTCore/src/TiltedGeometry.cc +++ b/RecoTracker/LSTCore/src/TiltedGeometry.cc @@ -37,6 +37,16 @@ void lst::TiltedGeometry::load(std::string const& filename) { } } +void lst::TiltedGeometry::load(std::unordered_map const& slopes) { + drdzs_.clear(); + dxdys_.clear(); + + for (const auto& [detId, slopeData] : slopes) { + drdzs_[detId] = slopeData.drdz_slope; + dxdys_[detId] = slopeData.dxdy_slope; + } +} + float lst::TiltedGeometry::getDrDz(unsigned int detid) const { auto res = drdzs_.find(detid); return res == drdzs_.end() ? 0.f : res->second; diff --git a/RecoTracker/LSTCore/src/alpaka/MiniDoublet.h b/RecoTracker/LSTCore/src/alpaka/MiniDoublet.h index b1404b600a75c..3c294e042edd7 100644 --- a/RecoTracker/LSTCore/src/alpaka/MiniDoublet.h +++ b/RecoTracker/LSTCore/src/alpaka/MiniDoublet.h @@ -300,8 +300,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE::lst { drprime = (moduleSeparation / alpaka::math::sin(acc, angleA + angleB)) * alpaka::math::sin(acc, angleA); // Compute arctan of the slope and take care of the slope = infinity case - absArctanSlope = - ((slope != kVerticalModuleSlope && edm::isFinite(slope)) ? fabs(alpaka::math::atan(acc, slope)) : kPi / 2.f); + absArctanSlope = (edm::isFinite(slope) ? fabs(alpaka::math::atan(acc, slope)) : kPi / 2.f); // Depending on which quadrant the pixel hit lies, we define the angleM by shifting them slightly differently if (xp > 0 and yp > 0) { @@ -324,8 +323,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE::lst { ya = yp + drprime_y; // Compute the new strip hit position (if the slope value is in special condition take care of the exceptions) - if (slope == kVerticalModuleSlope || - edm::isNotFinite(slope)) // Designated for tilted module when the slope is infinity (module lying along y-axis) + if (edm::isNotFinite(slope)) // Designated for tilted module when the slope is infinity (module lying along y-axis) { xn = xa; // New x point is simply where the anchor is yn = yo; // No shift in y diff --git a/RecoTracker/LSTCore/src/alpaka/Quintuplet.h b/RecoTracker/LSTCore/src/alpaka/Quintuplet.h index a943facc28be4..fa562618ae3f8 100644 --- a/RecoTracker/LSTCore/src/alpaka/Quintuplet.h +++ b/RecoTracker/LSTCore/src/alpaka/Quintuplet.h @@ -665,9 +665,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE::lst { // Computing sigmas is a very tricky affair // if the module is tilted or endcap, we need to use the slopes properly! - absArctanSlope = ((slopes[i] != kVerticalModuleSlope && edm::isFinite(slopes[i])) - ? alpaka::math::abs(acc, alpaka::math::atan(acc, slopes[i])) - : kPi / 2.f); + absArctanSlope = + (edm::isFinite(slopes[i]) ? alpaka::math::abs(acc, alpaka::math::atan(acc, slopes[i])) : kPi / 2.f); if (xs[i] > 0 and ys[i] > 0) { angleM = kPi / 2.f - absArctanSlope; @@ -749,9 +748,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE::lst { float chiSquared = 0.f; float absArctanSlope, angleM, xPrime, yPrime, sigma2; for (size_t i = 0; i < nPoints; i++) { - absArctanSlope = ((slopes[i] != kVerticalModuleSlope && edm::isFinite(slopes[i])) - ? alpaka::math::abs(acc, alpaka::math::atan(acc, slopes[i])) - : kPi / 2.f); + absArctanSlope = + (edm::isFinite(slopes[i]) ? alpaka::math::abs(acc, alpaka::math::atan(acc, slopes[i])) : kPi / 2.f); if (xs[i] > 0 and ys[i] > 0) { angleM = kPi / 2.f - absArctanSlope; } else if (xs[i] < 0 and ys[i] > 0) { diff --git a/RecoTracker/LSTCore/standalone/.gitignore b/RecoTracker/LSTCore/standalone/.gitignore index 3d27afd0c4469..5925b5aefc296 100644 --- a/RecoTracker/LSTCore/standalone/.gitignore +++ b/RecoTracker/LSTCore/standalone/.gitignore @@ -15,6 +15,7 @@ bin/lst bin/lst_cuda bin/lst_cpu bin/lst_rocm +bin/lst_make_geometry code/rooutil/librooutil.so code/rooutil/rooutil.so .gitversion.txt diff --git a/RecoTracker/LSTCore/standalone/Makefile b/RecoTracker/LSTCore/standalone/Makefile index f06bf0bfffba4..3aa498c6f1d6c 100644 --- a/RecoTracker/LSTCore/standalone/Makefile +++ b/RecoTracker/LSTCore/standalone/Makefile @@ -1,6 +1,7 @@ # Simple makefile EXES := bin/lst_cpu bin/lst_cuda +GEOMETRY_EXES := bin/lst_make_geometry SOURCES=$(wildcard code/core/*.cc) OBJECTS_CPU=$(SOURCES:.cc=_cpu.o) @@ -10,7 +11,7 @@ OBJECTS=$(OBJECTS_CPU) $(OBJECTS_CUDA) $(OBJECTS_ROCM) CXX = g++ CXXFLAGS = -g -O2 -Wall -fPIC -Woverloaded-virtual -Wno-unused-function -fno-var-tracking -std=c++20 -INCLUDEFLAGS= -ILST -I$(shell pwd) -Icode -Icode/core -I${ALPAKA_ROOT}/include -I/${BOOST_ROOT}/include $(shell rooutil-config --include) -I$(shell root-config --incdir) -I${TRACKLOOPERDIR}/../../../ -I${CMSSW_BASE}/src -I${FMT_ROOT}/include -I../interface/ -I../interface/alpaka/ -I../src/ -I../src/alpaka/ +INCLUDEFLAGS= -ILST -I$(shell pwd) -Icode -Icode/core -I${ALPAKA_ROOT}/include -I/${BOOST_ROOT}/include -I/${EIGEN_ROOT}/include/eigen3 $(shell rooutil-config --include) -I$(shell root-config --incdir) -I${TRACKLOOPERDIR}/../../../ -I${CMSSW_BASE}/src -I${FMT_ROOT}/include -I../interface/ -I../interface/alpaka/ -I../src/ -I../src/alpaka/ ifdef CMSSW_RELEASE_BASE INCLUDEFLAGS:= ${INCLUDEFLAGS} -I${CMSSW_RELEASE_BASE}/src endif @@ -31,17 +32,17 @@ CUTVALUEFLAG_FLAGS = -DCUT_VALUE_DEBUG PRIMITIVEFLAG = PRIMITIVEFLAG_FLAGS = -DPRIMITIVE_STUDY -all: rooutil efficiency $(EXES) +all: rooutil efficiency $(GEOMETRY_EXES) $(EXES) cutvalue: CUTVALUEFLAG = ${CUTVALUEFLAG_FLAGS} -cutvalue: rooutil efficiency $(EXES) +cutvalue: rooutil efficiency $(GEOMETRY_EXES) $(EXES) primitive: PRIMITIVEFLAG = ${PRIMITIVEFLAG_FLAGS} -primitive: rooutil efficiency $(EXES) +primitive: rooutil efficiency $(GEOMETRY_EXES) $(EXES) cutvalue_primitive: CUTVALUEFLAG = ${CUTVALUEFLAG_FLAGS} cutvalue_primitive: PRIMITIVEFLAG = ${PRIMITIVEFLAG_FLAGS} -cutvalue_primitive: rooutil efficiency $(EXES) +cutvalue_primitive: rooutil efficiency $(GEOMETRY_EXES) $(EXES) bin/lst_cpu: LSTLIB=-llst_cpu @@ -61,6 +62,11 @@ bin/lst_rocm: bin/lst_rocm.o $(OBJECTS_ROCM) %_rocm.o: %.cc rooutil $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(INCLUDEFLAGS) $(ALPAKAFLAGS) $(CUTVALUEFLAG) $(PRIMITIVEFLAG) $(DOQUINTUPLET) $(ALPAKA_ROCM) $(ROCMINCLUDE) $< -c -o $@ +bin/lst_make_geometry: bin/lst_make_geometry.o + $(CXX) $(LDFLAGS) $(EXTRAFLAGS) $(INCLUDEFLAGS) $(ALPAKAFLAGS) $^ -o $@ +%_geometry.o: %_geometry.cc + $(CXX) $(CXXFLAGS) $(INCLUDEFLAGS) $< -c -o $@ + rooutil: $(MAKE) -C code/rooutil/ @@ -68,7 +74,7 @@ efficiency: rooutil $(MAKE) -C efficiency/ clean: - rm -f $(OBJECTS) bin/*.o $(EXES) bin/lst + rm -f $(OBJECTS) bin/*.o $(EXES) bin/lst $(GEOMETRY_EXES) rm -f code/rooutil/*.so code/rooutil/*.o rm -f bin/lst.o rm -f LST/*.o diff --git a/RecoTracker/LSTCore/standalone/bin/lst_make_geometry.cc b/RecoTracker/LSTCore/standalone/bin/lst_make_geometry.cc new file mode 100644 index 0000000000000..586f5256fe58e --- /dev/null +++ b/RecoTracker/LSTCore/standalone/bin/lst_make_geometry.cc @@ -0,0 +1,61 @@ +#include + +#include "cxxopts.h" + +#include "RecoTracker/LSTCore/interface/LSTGeometry/IO.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometryMethods.h" + +using namespace lstgeometry; + +int main(int argc, char** argv) { + cxxopts::Options options("\nLST Geometry\n\n"); + options.add_options()("module_info_file", + "The path to the csv file containing module information.", + cxxopts::value()->default_value("../data/module_info_OT800_IT711.csv"))( + "sensor_info_file", + "The path to the csv file containing sensor information.", + cxxopts::value()->default_value("../data/DetId_sensors_list_OT800_IT711.csv"))( + "average_r_file", + "The path to the text file containing the average r positions of the Barrel layers.", + cxxopts::value()->default_value("../data/average_r_OT800_IT711.txt"))( + "average_z_file", + "The path to the text file containing the average z positions of the Endcap layers.", + cxxopts::value()->default_value("../data/average_z_OT800_IT711.txt"))( + "output_dir", "The path to the output directory.", cxxopts::value()->default_value("../data/"))( + "output_as_binary", + "Boolean flag specifying whether to write outputs as binary or text files.", + cxxopts::value()->default_value("true"))( + "pt_cut", "pT cutoff value.", cxxopts::value()->default_value("0.8"))("h,help", "Print help"); + + auto result = options.parse(argc, argv); + + if (result.count("help")) { + std::cout << options.help() << std::endl; + exit(1); + } + + std::string module_info_file = result["module_info_file"].as(); + std::string sensor_info_file = result["sensor_info_file"].as(); + std::string average_r_file = result["average_r_file"].as(); + std::string average_z_file = result["average_z_file"].as(); + std::string output_dir = result["output_dir"].as(); + bool output_as_bin = result["output_as_binary"].as(); + double ptCut = result["pt_cut"].as(); + + auto modules_info = readModuleInfo(module_info_file); + auto sensors_info = readSensorInfo(sensor_info_file); + auto average_r = readAverages(average_r_file); + auto average_z = readAverages(average_z_file); + + auto lstGeometry = makeLSTGeometry(modules_info, sensors_info, average_r, average_z, ptCut); + + writeCentroids(lstGeometry->centroids, output_dir + "sensor_centroids", output_as_bin); + writeSlopes( + lstGeometry->barrel_slopes, lstGeometry->sensor_info, output_dir + "tilted_barrel_orientation", output_as_bin); + writeSlopes(lstGeometry->endcap_slopes, lstGeometry->sensor_info, output_dir + "endcap_orientation", output_as_bin); + writePixelMaps(lstGeometry->pixel_map, output_dir + "pixelmap/pLS_map", output_as_bin); + writeModuleConnections( + lstGeometry->merged_line_connections, output_dir + "module_connection_tracing_merged", output_as_bin); + + return 0; +} diff --git a/RecoTracker/LSTCore/standalone/setup.sh b/RecoTracker/LSTCore/standalone/setup.sh index f08180201192d..8b89aeba001f8 100644 --- a/RecoTracker/LSTCore/standalone/setup.sh +++ b/RecoTracker/LSTCore/standalone/setup.sh @@ -25,6 +25,7 @@ fi # Export paths to libraries we need export ALPAKA_ROOT=$(scram tool info alpaka | grep ALPAKA_BASE | cut -d'=' -f2) export BOOST_ROOT=$(scram tool info boost | grep BOOST_BASE | cut -d'=' -f2) +export EIGEN_ROOT=$(scram tool info eigen | grep EIGEN_BASE | cut -d'=' -f2) export CUDA_HOME=$(scram tool info cuda | grep CUDA_BASE | cut -d'=' -f2) export FMT_ROOT=$(scram tool info fmt | grep FMT_BASE | cut -d'=' -f2) export ROCM_ROOT=$(scram tool info rocm | grep ROCM_BASE | cut -d'=' -f2) diff --git a/RecoTracker/LSTCore/test/BuildFile.xml b/RecoTracker/LSTCore/test/BuildFile.xml new file mode 100644 index 0000000000000..c5aa2f03a7b62 --- /dev/null +++ b/RecoTracker/LSTCore/test/BuildFile.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/RecoTracker/LSTCore/test/DumpLSTGeometry.cc b/RecoTracker/LSTCore/test/DumpLSTGeometry.cc new file mode 100644 index 0000000000000..451fc20382688 --- /dev/null +++ b/RecoTracker/LSTCore/test/DumpLSTGeometry.cc @@ -0,0 +1,47 @@ +#include "FWCore/Framework/interface/one/EDAnalyzer.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESTransientHandle.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/EventSetup.h" + +#include "RecoTracker/Record/interface/TrackerRecoGeometryRecord.h" + +#include "RecoTracker/LSTCore/interface/LSTGeometry/LSTGeometry.h" +#include "RecoTracker/LSTCore/interface/LSTGeometry/IO.h" + +class DumpLSTGeometry : public edm::one::EDAnalyzer<> { +public: + explicit DumpLSTGeometry(const edm::ParameterSet& config); + +private: + void analyze(const edm::Event& event, const edm::EventSetup& eventSetup) override; + + std::string ptCut_; + std::string outputDirectory_; + bool binaryOutput_; + + edm::ESGetToken lstGeoToken_; +}; + +DumpLSTGeometry::DumpLSTGeometry(const edm::ParameterSet& config) + : ptCut_(config.getParameter("ptCut")), + outputDirectory_(config.getUntrackedParameter("outputDirectory", "data/")), + binaryOutput_(config.getUntrackedParameter("outputAsBinary", true)), + lstGeoToken_{esConsumes(edm::ESInputTag("", ptCut_))} {} + +void DumpLSTGeometry::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) { + const auto& lstg = iSetup.getData(lstGeoToken_); + + lstgeometry::writeCentroids(lstg.centroids, outputDirectory_ + "sensor_centroids", binaryOutput_); + lstgeometry::writeSlopes( + lstg.barrel_slopes, lstg.sensor_info, outputDirectory_ + "tilted_barrel_orientation", binaryOutput_); + lstgeometry::writeSlopes( + lstg.endcap_slopes, lstg.sensor_info, outputDirectory_ + "endcap_orientation", binaryOutput_); + lstgeometry::writePixelMaps(lstg.pixel_map, outputDirectory_ + "pixelmap/pLS_map", binaryOutput_); + lstgeometry::writeModuleConnections( + lstg.merged_line_connections, outputDirectory_ + "module_connection_tracing_merged", binaryOutput_); + + edm::LogInfo("DumpLSTGeometry") << "Centroids size: " << lstg.centroids.size() << std::endl; +} + +DEFINE_FWK_MODULE(DumpLSTGeometry); diff --git a/RecoTracker/LSTCore/test/dumpLSTGeometry.py b/RecoTracker/LSTCore/test/dumpLSTGeometry.py new file mode 100644 index 0000000000000..1988ce88d15df --- /dev/null +++ b/RecoTracker/LSTCore/test/dumpLSTGeometry.py @@ -0,0 +1,68 @@ +import FWCore.ParameterSet.Config as cms +from Configuration.AlCa.GlobalTag import GlobalTag +import Configuration.Geometry.defaultPhase2ConditionsEra_cff as _settings +import FWCore.ParameterSet.VarParsing as VarParsing + +trackingLSTCommon = cms.Modifier() +trackingLST = cms.ModifierChain(trackingLSTCommon) + +################################################################### +# Set default phase-2 settings +################################################################### +_PH2_GLOBAL_TAG, _PH2_ERA = _settings.get_era_and_conditions(_settings.DEFAULT_VERSION) + +# No era in Fireworks/Geom reco dumper +process = cms.Process("DUMP", _PH2_ERA, trackingLST) + +# import of standard configurations +process.load("Configuration.StandardSequences.Services_cff") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.Geometry.GeometryExtendedRun4DefaultReco_cff") +process.load("Configuration.StandardSequences.MagneticField_cff") +process.load("Configuration.StandardSequences.Reconstruction_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") + +process.GlobalTag = GlobalTag(process.GlobalTag, _PH2_GLOBAL_TAG, "") + +process.MessageLogger.cerr.threshold = "INFO" +process.MessageLogger.cerr.LSTGeometryESProducer = dict(limit=-1) + +process.source = cms.Source("EmptySource") +process.maxEvents.input = 1 + +process.add_(cms.ESProducer("LSTGeometryESProducer")) + +options = VarParsing.VarParsing() +options.register( + "outputDirectory", + "data/", + VarParsing.VarParsing.multiplicity.singleton, + VarParsing.VarParsing.varType.string, + "Output directory for LST geometry files", +) +options.register( + "ptCut", + 0.8, + VarParsing.VarParsing.multiplicity.singleton, + VarParsing.VarParsing.varType.float, + "pT cut for LST module maps", +) +options.register( + "binaryOutput", + True, + VarParsing.VarParsing.multiplicity.singleton, + VarParsing.VarParsing.varType.bool, + "Dump LST geometry as binary files", +) +options.parseArguments() + + +process.dump = cms.EDAnalyzer( + "DumpLSTGeometry", + outputDirectory = cms.untracked.string(options.outputDirectory), + ptCut = cms.string(str(options.ptCut)), + outputAsBinary = cms.untracked.bool(options.binaryOutput), +) + +print(f"Requesting LST geometry dump into directory: {options.outputDirectory}\n") +process.p = cms.Path(process.dump) diff --git a/RecoTracker/LSTCore/test/testDumpLSTGeometry.sh b/RecoTracker/LSTCore/test/testDumpLSTGeometry.sh new file mode 100755 index 0000000000000..f3a7524015b53 --- /dev/null +++ b/RecoTracker/LSTCore/test/testDumpLSTGeometry.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function die { echo $1: status $2; exit $2; } + +if [ "${SCRAM_TEST_NAME}" != "" ] ; then + mkdir ${SCRAM_TEST_NAME} + cd ${SCRAM_TEST_NAME} +fi + +(cmsRun ${SCRAM_TEST_PATH}/dumpLSTGeometry.py outputDirectory="data/" ptCut=0.8 binaryOutput=true) || die "failed to run dumpLSTGeometry.py" $?