Loading src/core/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ ADD_LIBRARY( geometry/DetectorModel.cpp geometry/PixelDetectorModel.cpp geometry/GeometryManager.cpp geometry/BrickwallPixelDetectorModel.cpp geometry/HexagonalPixelDetectorModel.cpp geometry/RadialStripDetectorModel.cpp Allpix.cpp) Loading src/core/geometry/BrickwallPixelDetectorModel.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /** * @file * @brief Implementation of a brick wall pixel detector model * * @copyright Copyright (c) 2025 CERN and the Allpix Squared authors. * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md". * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an * Intergovernmental Organization or submit itself to any jurisdiction. * SPDX-License-Identifier: MIT */ #include "BrickwallPixelDetectorModel.hpp" #include "core/module/exceptions.h" using namespace allpix; BrickwallPixelDetectorModel::BrickwallPixelDetectorModel(std::string type, const std::shared_ptr<DetectorAssembly>& assembly, const ConfigReader& reader, const Configuration& config) : PixelDetectorModel(std::move(type), assembly, reader, config) { // Read tile offset - for now only possible along x, applied to odd rows offset_ = config.get<double>("pixel_offset"); if(std::fabs(offset_) > 1.0) { throw InvalidValueError(config, "pixel_offset", "pixel offset should be provided in fractions of the pitch and cannot be larger than +-1.0"); } } /** * Faster implementation of matrix lookup for local coordinate positions than going through the pixel index * This is quite easy for rectangular pixels and matrices. */ bool BrickwallPixelDetectorModel::isWithinMatrix(const ROOT::Math::XYZPoint& position) const { // Check if we have an odd or even row bool odd_row = (static_cast<int>(std::lround(position.y() / pixel_size_.y())) % 2) != 0; // For odd rows, shift everything by the offset (positive or negative) if(position.x() < (-0.5 + (odd_row ? offset_ : 0.)) * pixel_size_.x() || position.x() > (number_of_pixels_.x() - 0.5 + (odd_row ? offset_ : 0.)) * pixel_size_.x()) { return false; } if(position.y() < -0.5 * pixel_size_.y() || position.y() > (number_of_pixels_.y() - 0.5) * pixel_size_.y()) { return false; } return true; } ROOT::Math::XYZPoint BrickwallPixelDetectorModel::getPixelCenter(const int x, const int y) const { auto size = getPixelSize(); auto local_x = size.x() * (x + ((y % 2) != 0 ? offset_ : 0.)); auto local_y = size.y() * y; return {local_x, local_y, 0}; } std::pair<int, int> BrickwallPixelDetectorModel::getPixelIndex(const ROOT::Math::XYZPoint& position) const { // Check if we have an odd or even row bool odd_row = (static_cast<int>(std::lround(position.y() / pixel_size_.y())) % 2) != 0; auto pixel_x = static_cast<int>(std::lround(position.x() / pixel_size_.x() - (odd_row ? offset_ : 0.))); auto pixel_y = static_cast<int>(std::lround(position.y() / pixel_size_.y())); return {pixel_x, pixel_y}; } std::set<Pixel::Index> BrickwallPixelDetectorModel::getNeighbors(const Pixel::Index& idx, const size_t distance) const { std::set<Pixel::Index> neighbors; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-overflow" // Neighbor rows are the same as in a regular aligned pixel model for(int y = idx.y() - static_cast<int>(distance); y <= idx.y() + static_cast<int>(distance); y++) { // In neighbor columns, we have three neighbors in odd rows and only two in even rows // For positive offsets, the leftmost fall away int distance_left = static_cast<int>(distance) - (y % 2 == 0 && offset_ > 0 ? 1 : 0); // For negative offsets, the rightmost fall away int distance_right = static_cast<int>(distance) - (y % 2 == 0 && offset_ < 0 ? 1 : 0); for(int x = idx.x() - distance_left; x <= idx.x() + distance_right; x++) { if(!PixelDetectorModel::isWithinMatrix(x, y)) { continue; } neighbors.insert({x, y}); } } #pragma GCC diagnostic pop return neighbors; } bool BrickwallPixelDetectorModel::areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const { // Along y, it's just adjacent rows bool neighbor_in_y = static_cast<size_t>(std::abs(seed.y() - entrant.y())) <= distance; // Along x, we need to take the offset into account // For positive offsets, the leftmost fall away in even rows int distance_left = static_cast<int>(distance) - (entrant.y() % 2 == 0 && offset_ > 0 ? 1 : 0); // For negative offsets, the rightmost fall away in even rows int distance_right = static_cast<int>(distance) - (entrant.y() % 2 == 0 && offset_ < 0 ? 1 : 0); bool neighbor_in_x = (seed.x() > entrant.x() && (seed.x() - entrant.x()) <= distance_right) || (seed.x() < entrant.x() && (entrant.x() - seed.x()) <= distance_left); return (neighbor_in_x && neighbor_in_y); } src/core/geometry/BrickwallPixelDetectorModel.hpp 0 → 100644 +93 −0 Original line number Diff line number Diff line /** * @file * @brief Pixel detector model * * @copyright Copyright (c) 2025 CERN and the Allpix Squared authors. * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md". * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an * Intergovernmental Organization or submit itself to any jurisdiction. * SPDX-License-Identifier: MIT */ #ifndef ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H #define ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H #include <array> #include <string> #include <utility> #include <Math/Point2D.h> #include <Math/Point3D.h> #include <Math/Vector2D.h> #include <Math/Vector3D.h> #include "PixelDetectorModel.hpp" namespace allpix { /** * @ingroup DetectorModels * @brief Model of a pixel detector with a brick wall layout. */ class BrickwallPixelDetectorModel : public PixelDetectorModel { public: /** * @brief Constructs the pixel detector model * @param type Name of the model type * @param assembly Detector assembly object with information about ASIC and packaging * @param reader Configuration reader with description of the model * @param config Configuration reference holding the unnamed section of detector configuration */ explicit BrickwallPixelDetectorModel(std::string type, const std::shared_ptr<DetectorAssembly>& assembly, const ConfigReader& reader, const Configuration& config); /** * @brief Returns if a position is within the grid of pixels defined for the device * @param position Position in local coordinates of the detector model * @return True if position within the pixel grid, false otherwise */ bool isWithinMatrix(const ROOT::Math::XYZPoint& position) const override; /** * @brief Returns a pixel center in local coordinates * @param x X- (or column-) coordinate of the pixel * @param y Y- (or row-) coordinate of the pixel * @return Coordinates of the pixel center */ ROOT::Math::XYZPoint getPixelCenter(const int x, const int y) const override; /** * @brief Return X,Y indices of a pixel corresponding to a local position in a sensor. * @param local_pos Position in local coordinates of the detector model * @return X,Y pixel indices * * @note No checks are performed on whether these indices represent an existing pixel or are within the pixel matrix. */ std::pair<int, int> getPixelIndex(const ROOT::Math::XYZPoint& local_pos) const override; /** * @brief Return a set containing all pixels neighboring the given one with a configurable maximum distance * @param idx Index of the pixel in question * @param distance Distance for pixels to be considered neighbors * @return Set of neighboring pixel indices, including the initial pixel * * @note The returned set should always also include the initial pixel indices the neighbors are calculated for */ std::set<Pixel::Index> getNeighbors(const Pixel::Index& idx, const size_t distance) const override; /** * @brief Check if two pixel indices are neighbors to each other * @param seed Initial pixel index * @param entrant Entrant pixel index to be tested * @param distance Distance for pixels to be considered neighbors * @return Boolean whether pixels are neighbors or not */ bool areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const override; private: double offset_; }; } // namespace allpix #endif // ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H src/core/geometry/DetectorModel.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include "DetectorModel.hpp" #include "core/module/exceptions.h" #include "core/geometry/BrickwallPixelDetectorModel.hpp" #include "core/geometry/HexagonalPixelDetectorModel.hpp" #include "core/geometry/PixelDetectorModel.hpp" #include "core/geometry/RadialStripDetectorModel.hpp" Loading Loading @@ -55,6 +56,8 @@ std::shared_ptr<DetectorModel> DetectorModel::factory(const std::string& name, c model = std::make_shared<RadialStripDetectorModel>(name, assembly, reader, config); } else if(geometry == "hexagonal") { model = std::make_shared<HexagonalPixelDetectorModel>(name, assembly, reader, config); } else if(geometry == "brickwall") { model = std::make_shared<BrickwallPixelDetectorModel>(name, assembly, reader, config); } else { LOG(FATAL) << "Model file " << config.getFilePath() << " geometry parameter is not valid"; // FIXME: The model can probably be silently ignored if we have more model readers later Loading src/core/geometry/PixelDetectorModel.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -143,4 +143,4 @@ namespace allpix { }; } // namespace allpix #endif // ALLPIX_DETECTOR_MODEL_H #endif // ALLPIX_PIXEL_DETECTOR_MODEL_H Loading
src/core/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ ADD_LIBRARY( geometry/DetectorModel.cpp geometry/PixelDetectorModel.cpp geometry/GeometryManager.cpp geometry/BrickwallPixelDetectorModel.cpp geometry/HexagonalPixelDetectorModel.cpp geometry/RadialStripDetectorModel.cpp Allpix.cpp) Loading
src/core/geometry/BrickwallPixelDetectorModel.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /** * @file * @brief Implementation of a brick wall pixel detector model * * @copyright Copyright (c) 2025 CERN and the Allpix Squared authors. * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md". * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an * Intergovernmental Organization or submit itself to any jurisdiction. * SPDX-License-Identifier: MIT */ #include "BrickwallPixelDetectorModel.hpp" #include "core/module/exceptions.h" using namespace allpix; BrickwallPixelDetectorModel::BrickwallPixelDetectorModel(std::string type, const std::shared_ptr<DetectorAssembly>& assembly, const ConfigReader& reader, const Configuration& config) : PixelDetectorModel(std::move(type), assembly, reader, config) { // Read tile offset - for now only possible along x, applied to odd rows offset_ = config.get<double>("pixel_offset"); if(std::fabs(offset_) > 1.0) { throw InvalidValueError(config, "pixel_offset", "pixel offset should be provided in fractions of the pitch and cannot be larger than +-1.0"); } } /** * Faster implementation of matrix lookup for local coordinate positions than going through the pixel index * This is quite easy for rectangular pixels and matrices. */ bool BrickwallPixelDetectorModel::isWithinMatrix(const ROOT::Math::XYZPoint& position) const { // Check if we have an odd or even row bool odd_row = (static_cast<int>(std::lround(position.y() / pixel_size_.y())) % 2) != 0; // For odd rows, shift everything by the offset (positive or negative) if(position.x() < (-0.5 + (odd_row ? offset_ : 0.)) * pixel_size_.x() || position.x() > (number_of_pixels_.x() - 0.5 + (odd_row ? offset_ : 0.)) * pixel_size_.x()) { return false; } if(position.y() < -0.5 * pixel_size_.y() || position.y() > (number_of_pixels_.y() - 0.5) * pixel_size_.y()) { return false; } return true; } ROOT::Math::XYZPoint BrickwallPixelDetectorModel::getPixelCenter(const int x, const int y) const { auto size = getPixelSize(); auto local_x = size.x() * (x + ((y % 2) != 0 ? offset_ : 0.)); auto local_y = size.y() * y; return {local_x, local_y, 0}; } std::pair<int, int> BrickwallPixelDetectorModel::getPixelIndex(const ROOT::Math::XYZPoint& position) const { // Check if we have an odd or even row bool odd_row = (static_cast<int>(std::lround(position.y() / pixel_size_.y())) % 2) != 0; auto pixel_x = static_cast<int>(std::lround(position.x() / pixel_size_.x() - (odd_row ? offset_ : 0.))); auto pixel_y = static_cast<int>(std::lround(position.y() / pixel_size_.y())); return {pixel_x, pixel_y}; } std::set<Pixel::Index> BrickwallPixelDetectorModel::getNeighbors(const Pixel::Index& idx, const size_t distance) const { std::set<Pixel::Index> neighbors; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-overflow" // Neighbor rows are the same as in a regular aligned pixel model for(int y = idx.y() - static_cast<int>(distance); y <= idx.y() + static_cast<int>(distance); y++) { // In neighbor columns, we have three neighbors in odd rows and only two in even rows // For positive offsets, the leftmost fall away int distance_left = static_cast<int>(distance) - (y % 2 == 0 && offset_ > 0 ? 1 : 0); // For negative offsets, the rightmost fall away int distance_right = static_cast<int>(distance) - (y % 2 == 0 && offset_ < 0 ? 1 : 0); for(int x = idx.x() - distance_left; x <= idx.x() + distance_right; x++) { if(!PixelDetectorModel::isWithinMatrix(x, y)) { continue; } neighbors.insert({x, y}); } } #pragma GCC diagnostic pop return neighbors; } bool BrickwallPixelDetectorModel::areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const { // Along y, it's just adjacent rows bool neighbor_in_y = static_cast<size_t>(std::abs(seed.y() - entrant.y())) <= distance; // Along x, we need to take the offset into account // For positive offsets, the leftmost fall away in even rows int distance_left = static_cast<int>(distance) - (entrant.y() % 2 == 0 && offset_ > 0 ? 1 : 0); // For negative offsets, the rightmost fall away in even rows int distance_right = static_cast<int>(distance) - (entrant.y() % 2 == 0 && offset_ < 0 ? 1 : 0); bool neighbor_in_x = (seed.x() > entrant.x() && (seed.x() - entrant.x()) <= distance_right) || (seed.x() < entrant.x() && (entrant.x() - seed.x()) <= distance_left); return (neighbor_in_x && neighbor_in_y); }
src/core/geometry/BrickwallPixelDetectorModel.hpp 0 → 100644 +93 −0 Original line number Diff line number Diff line /** * @file * @brief Pixel detector model * * @copyright Copyright (c) 2025 CERN and the Allpix Squared authors. * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md". * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an * Intergovernmental Organization or submit itself to any jurisdiction. * SPDX-License-Identifier: MIT */ #ifndef ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H #define ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H #include <array> #include <string> #include <utility> #include <Math/Point2D.h> #include <Math/Point3D.h> #include <Math/Vector2D.h> #include <Math/Vector3D.h> #include "PixelDetectorModel.hpp" namespace allpix { /** * @ingroup DetectorModels * @brief Model of a pixel detector with a brick wall layout. */ class BrickwallPixelDetectorModel : public PixelDetectorModel { public: /** * @brief Constructs the pixel detector model * @param type Name of the model type * @param assembly Detector assembly object with information about ASIC and packaging * @param reader Configuration reader with description of the model * @param config Configuration reference holding the unnamed section of detector configuration */ explicit BrickwallPixelDetectorModel(std::string type, const std::shared_ptr<DetectorAssembly>& assembly, const ConfigReader& reader, const Configuration& config); /** * @brief Returns if a position is within the grid of pixels defined for the device * @param position Position in local coordinates of the detector model * @return True if position within the pixel grid, false otherwise */ bool isWithinMatrix(const ROOT::Math::XYZPoint& position) const override; /** * @brief Returns a pixel center in local coordinates * @param x X- (or column-) coordinate of the pixel * @param y Y- (or row-) coordinate of the pixel * @return Coordinates of the pixel center */ ROOT::Math::XYZPoint getPixelCenter(const int x, const int y) const override; /** * @brief Return X,Y indices of a pixel corresponding to a local position in a sensor. * @param local_pos Position in local coordinates of the detector model * @return X,Y pixel indices * * @note No checks are performed on whether these indices represent an existing pixel or are within the pixel matrix. */ std::pair<int, int> getPixelIndex(const ROOT::Math::XYZPoint& local_pos) const override; /** * @brief Return a set containing all pixels neighboring the given one with a configurable maximum distance * @param idx Index of the pixel in question * @param distance Distance for pixels to be considered neighbors * @return Set of neighboring pixel indices, including the initial pixel * * @note The returned set should always also include the initial pixel indices the neighbors are calculated for */ std::set<Pixel::Index> getNeighbors(const Pixel::Index& idx, const size_t distance) const override; /** * @brief Check if two pixel indices are neighbors to each other * @param seed Initial pixel index * @param entrant Entrant pixel index to be tested * @param distance Distance for pixels to be considered neighbors * @return Boolean whether pixels are neighbors or not */ bool areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const override; private: double offset_; }; } // namespace allpix #endif // ALLPIX_BRICKWALL_PIXEL_DETECTOR_MODEL_H
src/core/geometry/DetectorModel.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include "DetectorModel.hpp" #include "core/module/exceptions.h" #include "core/geometry/BrickwallPixelDetectorModel.hpp" #include "core/geometry/HexagonalPixelDetectorModel.hpp" #include "core/geometry/PixelDetectorModel.hpp" #include "core/geometry/RadialStripDetectorModel.hpp" Loading Loading @@ -55,6 +56,8 @@ std::shared_ptr<DetectorModel> DetectorModel::factory(const std::string& name, c model = std::make_shared<RadialStripDetectorModel>(name, assembly, reader, config); } else if(geometry == "hexagonal") { model = std::make_shared<HexagonalPixelDetectorModel>(name, assembly, reader, config); } else if(geometry == "brickwall") { model = std::make_shared<BrickwallPixelDetectorModel>(name, assembly, reader, config); } else { LOG(FATAL) << "Model file " << config.getFilePath() << " geometry parameter is not valid"; // FIXME: The model can probably be silently ignored if we have more model readers later Loading
src/core/geometry/PixelDetectorModel.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -143,4 +143,4 @@ namespace allpix { }; } // namespace allpix #endif // ALLPIX_DETECTOR_MODEL_H #endif // ALLPIX_PIXEL_DETECTOR_MODEL_H