Commit b30ee796 authored by Radek Privara's avatar Radek Privara
Browse files

Abstract DetectorModel and new PixelDetectorModel class

parent 8dc00673
Loading
Loading
Loading
Loading
+0 −84
Original line number Diff line number Diff line
@@ -41,18 +41,6 @@ DetectorModel::DetectorModel(std::string type, ConfigReader reader) : type_(std:
    using namespace ROOT::Math;
    auto config = reader_.getHeaderConfiguration();

    // Number of pixels
    setNPixels(config.get<DisplacementVector2D<Cartesian2D<unsigned int>>>("number_of_pixels"));
    // Size of the pixels
    auto pixel_size = config.get<XYVector>("pixel_size");
    setPixelSize(pixel_size);
    // Size of the collection diode implant on each pixels, defaults to the full pixel size when not specified
    auto implant_size = config.get<XYVector>("implant_size", pixel_size);
    if(implant_size.x() > pixel_size.x() || implant_size.y() > pixel_size.y()) {
        throw InvalidValueError(config, "implant_size", "implant size cannot be larger than pixel pitch");
    }
    setImplantSize(implant_size);

    // Sensor thickness
    setSensorThickness(config.get<double>("sensor_thickness"));
    // Excess around the sensor from the pixel grid
@@ -195,75 +183,3 @@ std::vector<DetectorModel::SupportLayer> DetectorModel::getSupportLayers() const

    return ret_layers;
}

/**
 * The definition of inside the sensor is determined by the detector model
 */
bool DetectorModel::isWithinSensor(const ROOT::Math::XYZPoint& local_pos) const {
    auto sensor_center = getSensorCenter();
    auto sensor_size = getSensorSize();
    return (2 * std::fabs(local_pos.z() - sensor_center.z()) <= sensor_size.z()) &&
           (2 * std::fabs(local_pos.y() - sensor_center.y()) <= sensor_size.y()) &&
           (2 * std::fabs(local_pos.x() - sensor_center.x()) <= sensor_size.x());
}

/**
 * The definition of inside the implant region is determined by the detector model
 *
 * @note The pixel implant currently is always positioned symmetrically, in the center of the pixel cell.
 */
bool DetectorModel::isWithinImplant(const ROOT::Math::XYZPoint& local_pos) const {

    auto [xpixel, ypixel] = getPixelIndex(local_pos);
    auto inPixelPos = local_pos - getPixelCenter(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel));

    return (std::fabs(inPixelPos.x()) <= std::fabs(getImplantSize().x() / 2) &&
            std::fabs(inPixelPos.y()) <= std::fabs(getImplantSize().y() / 2));
}

/**
 * The definition of the pixel grid size is determined by the detector model
 */
bool DetectorModel::isWithinMatrix(const Pixel::Index& pixel_index) const {
    return !(pixel_index.x() >= number_of_pixels_.x() || pixel_index.y() >= number_of_pixels_.y());
}

/**
 * The definition of the pixel grid size is determined by the detector model
 */
bool DetectorModel::isWithinMatrix(const int x, const int y) const {
    return !(x < 0 || x >= static_cast<int>(number_of_pixels_.x()) || y < 0 || y >= static_cast<int>(number_of_pixels_.y()));
}

ROOT::Math::XYZPoint DetectorModel::getPixelCenter(unsigned int x, unsigned int y) const {
    auto size = getPixelSize();
    auto local_x = size.x() * x;
    auto local_y = size.y() * y;
    return {local_x, local_y, 0};
}

std::pair<int, int> DetectorModel::getPixelIndex(const ROOT::Math::XYZPoint& position) const {
    auto pixel_x = static_cast<int>(std::round(position.x() / pixel_size_.x()));
    auto pixel_y = static_cast<int>(std::round(position.y() / pixel_size_.y()));
    return {pixel_x, pixel_y};
}

std::set<Pixel::Index> DetectorModel::getNeighbors(const Pixel::Index& idx, const size_t distance) const {
    std::set<Pixel::Index> neighbors;

    for(int x = static_cast<int>(idx.x() - distance); x <= static_cast<int>(idx.x() + distance); x++) {
        for(int y = static_cast<int>(idx.y() - distance); y <= static_cast<int>(idx.y() + distance); y++) {
            if(!isWithinMatrix(x, y)) {
                continue;
            }
            neighbors.insert({static_cast<unsigned int>(x), static_cast<unsigned int>(y)});
        }
    }

    return neighbors;
}

bool DetectorModel::areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const {
    auto pixel_distance = [](unsigned int lhs, unsigned int rhs) { return (lhs > rhs ? lhs - rhs : rhs - lhs); };
    return (pixel_distance(seed.x(), entrant.x()) <= distance && pixel_distance(seed.y(), entrant.y()) <= distance);
}
+13 −13
Original line number Diff line number Diff line
@@ -207,10 +207,10 @@ namespace allpix {

        /* PIXEL GRID */
        /**
         * @brief Get number of pixel (replicated blocks in generic sensors)
         * @brief Get number of pixels (replicated blocks in generic sensors)
         * @return Number of two dimensional pixels
         */
        virtual ROOT::Math::DisplacementVector2D<ROOT::Math::Cartesian2D<unsigned int>> getNPixels() const {
        ROOT::Math::DisplacementVector2D<ROOT::Math::Cartesian2D<unsigned int>> getNPixels() const {
            return number_of_pixels_;
        }
        /**
@@ -224,7 +224,7 @@ namespace allpix {
         * @brief Get size of a single pixel
         * @return Size of a pixel
         */
        virtual ROOT::Math::XYVector getPixelSize() const { return pixel_size_; }
        ROOT::Math::XYVector getPixelSize() const { return pixel_size_; }
        /**
         * @brief Set the size of a pixel
         * @param val Size of a pixel
@@ -234,7 +234,7 @@ namespace allpix {
         * @brief Get size of the collection diode
         * @return Size of the collection diode implant
         */
        virtual ROOT::Math::XYVector getImplantSize() const { return implant_size_; }
        ROOT::Math::XYVector getImplantSize() const { return implant_size_; }
        /**
         * @brief Set the size of the implant (collection diode) within a pixel
         * @param val Size of the collection diode implant
@@ -378,21 +378,21 @@ namespace allpix {
         * @param local_pos Position in local coordinates of the detector model
         * @return True if a local position is within the sensor, false otherwise
         */
        virtual bool isWithinSensor(const ROOT::Math::XYZPoint& local_pos) const;
        virtual bool isWithinSensor(const ROOT::Math::XYZPoint& local_pos) const = 0;

        /**
         * @brief Returns if a local position is within the pixel implant region of the sensitive device
         * @param local_pos Position in local coordinates of the detector model
         * @return True if a local position is within the pixel implant, false otherwise
         */
        virtual bool isWithinImplant(const ROOT::Math::XYZPoint& local_pos) const;
        virtual bool isWithinImplant(const ROOT::Math::XYZPoint& local_pos) const = 0;

        /**
         * @brief Returns if a pixel index is within the grid of pixels defined for the device
         * @param pixel_index Pixel index to be checked
         * @return True if pixel_index is within the pixel grid, false otherwise
         */
        virtual bool isWithinMatrix(const Pixel::Index& pixel_index) const;
        virtual bool isWithinMatrix(const Pixel::Index& pixel_index) const = 0;

        /**
         * @brief Returns if a set of pixel coordinates is within the grid of pixels defined for the device
@@ -400,7 +400,7 @@ namespace allpix {
         * @param y Y- (or row-) coordinate to be checked
         * @return True if pixel coordinates are within the pixel grid, false otherwise
         */
        virtual bool isWithinMatrix(const int x, const int y) const;
        virtual bool isWithinMatrix(const int x, const int y) const = 0;

        /**
         * @brief Returns a pixel center in local coordinates
@@ -408,16 +408,16 @@ namespace allpix {
         * @param y Y- (or row-) coordinate of the pixel
         * @return Coordinates of the pixel center
         */
        virtual ROOT::Math::XYZPoint getPixelCenter(unsigned int x, unsigned int y) const;
        virtual ROOT::Math::XYZPoint getPixelCenter(unsigned int x, unsigned int y) const = 0;

        /**
         * @brief Return X,Y indices of a pixel corresponding to a local position in a sensor.
         * @param position Position in local coordinates of the detector model
         * @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.
         */
        virtual std::pair<int, int> getPixelIndex(const ROOT::Math::XYZPoint& position) const;
        virtual std::pair<int, int> getPixelIndex(const ROOT::Math::XYZPoint& local_pos) const = 0;

        /**
         * @brief Return a set containing all pixels neighboring the given one with a configurable maximum distance
@@ -427,7 +427,7 @@ namespace allpix {
         *
         * @note The returned set should always also include the initial pixel indices the neighbors are calculated for
         */
        virtual std::set<Pixel::Index> getNeighbors(const Pixel::Index& idx, const size_t distance) const;
        virtual std::set<Pixel::Index> getNeighbors(const Pixel::Index& idx, const size_t distance) const = 0;

        /**
         * @brief Check if two pixel indices are neighbors to each other
@@ -436,7 +436,7 @@ namespace allpix {
         * @param distance  Distance for pixels to be considered neighbors
         * @return         Boolean whether pixels are neighbors or not
         */
        virtual bool areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const;
        virtual bool areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const = 0;

    protected:
        std::string type_;
+105 −0
Original line number Diff line number Diff line
/**
 * @file
 * @brief Implementation of a pixel detector model
 *
 * @copyright Copyright (c) 2017-2020 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.
 */

#include "PixelDetectorModel.hpp"
#include "core/module/exceptions.h"

using namespace allpix;

PixelDetectorModel::PixelDetectorModel(std::string type, ConfigReader reader) : DetectorModel(std::move(type), reader) {
    using namespace ROOT::Math;
    auto config = reader.getHeaderConfiguration();

    // Number of pixels
    setNPixels(config.get<DisplacementVector2D<Cartesian2D<unsigned int>>>("number_of_pixels"));
    // Size of the pixels
    auto pixel_size = config.get<XYVector>("pixel_size");
    setPixelSize(pixel_size);
    // Size of the collection diode implant on each pixel, defaults to the full pixel size when not specified
    auto implant_size = config.get<XYVector>("implant_size", pixel_size);
    if(implant_size.x() > pixel_size.x() || implant_size.y() > pixel_size.y()) {
        throw InvalidValueError(config, "implant_size", "implant size cannot be larger than pixel pitch");
    }
    setImplantSize(implant_size);
}

/**
 * The definition of inside the sensor is determined by the detector model
 */
bool PixelDetectorModel::isWithinSensor(const ROOT::Math::XYZPoint& local_pos) const {
    auto sensor_center = getSensorCenter();
    auto sensor_size = getSensorSize();
    return (2 * std::fabs(local_pos.z() - sensor_center.z()) <= sensor_size.z()) &&
           (2 * std::fabs(local_pos.y() - sensor_center.y()) <= sensor_size.y()) &&
           (2 * std::fabs(local_pos.x() - sensor_center.x()) <= sensor_size.x());
}

/**
 * The definition of inside the implant region is determined by the detector model
 *
 * @note The pixel implant currently is always positioned symmetrically, in the center of the pixel cell.
 */
bool PixelDetectorModel::isWithinImplant(const ROOT::Math::XYZPoint& local_pos) const {

    auto [xpixel, ypixel] = getPixelIndex(local_pos);
    auto inPixelPos = local_pos - getPixelCenter(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel));

    return (std::fabs(inPixelPos.x()) <= std::fabs(getImplantSize().x() / 2) &&
            std::fabs(inPixelPos.y()) <= std::fabs(getImplantSize().y() / 2));
}

/**
 * The definition of the pixel grid size is determined by the detector model
 */
bool PixelDetectorModel::isWithinMatrix(const Pixel::Index& pixel_index) const {
    return !(pixel_index.x() >= number_of_pixels_.x() || pixel_index.y() >= number_of_pixels_.y());
}

/**
 * The definition of the pixel grid size is determined by the detector model
 */
bool PixelDetectorModel::isWithinMatrix(const int x, const int y) const {
    return !(x < 0 || x >= static_cast<int>(number_of_pixels_.x()) || y < 0 || y >= static_cast<int>(number_of_pixels_.y()));
}

ROOT::Math::XYZPoint PixelDetectorModel::getPixelCenter(unsigned int x, unsigned int y) const {
    auto size = getPixelSize();
    auto local_x = size.x() * x;
    auto local_y = size.y() * y;
    auto local_z = getSensorCenter().z() - getSensorSize().z() / 2.0;

    return {local_x, local_y, local_z};
}

std::pair<int, int> PixelDetectorModel::getPixelIndex(const ROOT::Math::XYZPoint& position) const {
    auto pixel_x = static_cast<int>(std::round(position.x() / pixel_size_.x()));
    auto pixel_y = static_cast<int>(std::round(position.y() / pixel_size_.y()));
    return {pixel_x, pixel_y};
}

std::set<Pixel::Index> PixelDetectorModel::getNeighbors(const Pixel::Index& idx, const size_t distance) const {
    std::set<Pixel::Index> neighbors;

    for(int x = static_cast<int>(idx.x() - distance); x <= static_cast<int>(idx.x() + distance); x++) {
        for(int y = static_cast<int>(idx.y() - distance); y <= static_cast<int>(idx.y() + distance); y++) {
            if(!isWithinMatrix(x, y)) {
                continue;
            }
            neighbors.insert({static_cast<unsigned int>(x), static_cast<unsigned int>(y)});
        }
    }

    return neighbors;
}

bool PixelDetectorModel::areNeighbors(const Pixel::Index& seed, const Pixel::Index& entrant, const size_t distance) const {
    auto pixel_distance = [](unsigned int lhs, unsigned int rhs) { return (lhs > rhs ? lhs - rhs : rhs - lhs); };
    return (pixel_distance(seed.x(), entrant.x()) <= distance && pixel_distance(seed.y(), entrant.y()) <= distance);
}
+189 −0
Original line number Diff line number Diff line
/**
 * @file
 * @brief Pixel detector model
 *
 * @copyright Copyright (c) 2017-2020 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.
 */

#ifndef ALLPIX_PIXEL_DETECTOR_MODEL_H
#define ALLPIX_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 "core/config/ConfigReader.hpp"
#include "core/config/exceptions.h"
#include "core/geometry/DetectorModel.hpp"
#include "core/utils/log.h"
#include "objects/Pixel.hpp"
#include "tools/ROOT.h"

namespace allpix {
    /**
     * @ingroup DetectorModels
     * @brief Model of a generic pixel detector. This model is further extended by specialized pixel detector models.
     */
    class PixelDetectorModel : public DetectorModel {
    public:
        /**
         * @brief Constructs the pixel detector model
         * @param type Name of the model type
         * @param reader Configuration reader with description of the model
         */
        explicit PixelDetectorModel(std::string type, ConfigReader reader);

        /* SENSOR */
        /**
         * @brief Get size of the sensor
         * @return Size of the sensor
         *
         * Calculated from \ref DetectorModel::getMatrixSize "pixel grid size", sensor excess and sensor thickness
         */
        ROOT::Math::XYZVector getSensorSize() const override {
            ROOT::Math::XYZVector excess_thickness((sensor_excess_.at(1) + sensor_excess_.at(3)),
                                                   (sensor_excess_.at(0) + sensor_excess_.at(2)),
                                                   sensor_thickness_);
            return getMatrixSize() + excess_thickness;
        }

        /**
         * @brief Get center of the sensor in local coordinates
         * @return Center of the sensor
         *
         * Center of the sensor with excess taken into account
         */
        ROOT::Math::XYZPoint getSensorCenter() const override {
            ROOT::Math::XYZVector offset(
                (sensor_excess_.at(1) - sensor_excess_.at(3)) / 2.0, (sensor_excess_.at(0) - sensor_excess_.at(2)) / 2.0, 0);
            return getMatrixCenter() + offset;
        }
        /**
         * @brief Set the thickness of the sensor
         * @param val Thickness of the sensor
         */
        void setSensorThickness(double val) { sensor_thickness_ = val; }
        /**
         * @brief Set the excess at the top of the sensor (positive y-coordinate)
         * @param val Sensor top excess
         */
        void setSensorExcessTop(double val) { sensor_excess_.at(0) = val; }
        /**
         * @brief Set the excess at the right of the sensor (positive x-coordinate)
         * @param val Sensor right excess
         */
        void setSensorExcessRight(double val) { sensor_excess_.at(1) = val; }
        /**
         * @brief Set the excess at the bottom of the sensor (negative y-coordinate)
         * @param val Sensor bottom excess
         */
        void setSensorExcessBottom(double val) { sensor_excess_.at(2) = val; }
        /**
         * @brief Set the excess at the left of the sensor (negative x-coordinate)
         * @param val Sensor right excess
         */
        void setSensorExcessLeft(double val) { sensor_excess_.at(3) = val; }

        /* CHIP */
        /**
         * @brief Get size of the chip
         * @return Size of the chip
         *
         * Calculated from \ref DetectorModel::getMatrixSize "pixel grid size", sensor excess and chip thickness
         */
        ROOT::Math::XYZVector getChipSize() const override {
            ROOT::Math::XYZVector excess_thickness((sensor_excess_.at(1) + sensor_excess_.at(3)),
                                                   (sensor_excess_.at(0) + sensor_excess_.at(2)),
                                                   chip_thickness_);
            return getMatrixSize() + excess_thickness;
        }

        /**
         * @brief Get center of the chip in local coordinates
         * @return Center of the chip
         *
         * Center of the chip calculcated from chip excess and sensor offset
         */
        ROOT::Math::XYZPoint getChipCenter() const override {
            ROOT::Math::XYZVector offset((sensor_excess_.at(1) - sensor_excess_.at(3)) / 2.0,
                                         (sensor_excess_.at(0) - sensor_excess_.at(2)) / 2.0,
                                         getSensorSize().z() / 2.0 + getChipSize().z() / 2.0);
            return getMatrixCenter() + offset;
        }

        /**
         * @brief Returns if a local position is within the sensitive device
         * @param local_pos Position in local coordinates of the detector model
         * @return True if a local position is within the sensor, false otherwise
         */
        bool isWithinSensor(const ROOT::Math::XYZPoint& local_pos) const override;

        /**
         * @brief Returns if a local position is within the pixel implant region of the sensitive device
         * @param local_pos Position in local coordinates of the detector model
         * @return True if a local position is within the pixel implant, false otherwise
         */
        bool isWithinImplant(const ROOT::Math::XYZPoint& local_pos) const override;

        /**
         * @brief Returns if a pixel index is within the grid of pixels defined for the device
         * @param pixel_index Pixel index to be checked
         * @return True if pixel_index is within the pixel grid, false otherwise
         */
        bool isWithinMatrix(const Pixel::Index& pixel_index) const override;

        /**
         * @brief Returns if a set of pixel coordinates is within the grid of pixels defined for the device
         * @param x X- (or column-) coordinate to be checked
         * @param y Y- (or row-) coordinate to be checked
         * @return True if pixel coordinates are within the pixel grid, false otherwise
         */
        bool isWithinMatrix(const int x, const int y) 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(unsigned int x, unsigned 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;
    };
} // namespace allpix

#endif // ALLPIX_DETECTOR_MODEL_H