Commit 33091298 authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Add BrickwallPixelDetectorModel

parent c9614be3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+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);
}
+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
+3 −0
Original line number Diff line number Diff line
@@ -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"
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -143,4 +143,4 @@ namespace allpix {
    };
} // namespace allpix

#endif // ALLPIX_DETECTOR_MODEL_H
#endif // ALLPIX_PIXEL_DETECTOR_MODEL_H
Loading