Commit d6ce5aab authored by Paul Schütze's avatar Paul Schütze
Browse files

Merge branch 'b-laser-materials' into 'v2.4-stable'

[v2.4-stable]  Deposition laser: check for detector materials

See merge request allpix-squared/allpix-squared!960
parents f5ade211 4d2a9d89
Loading
Loading
Loading
Loading
+52 −37
Original line number Diff line number Diff line
@@ -96,21 +96,16 @@ DepositionLaserModule::DepositionLaserModule(Configuration& config, Messenger* m
}

void DepositionLaserModule::initialize() {

    // Check for incompatible passive objects, warn user if there are any
    auto passive_configs = geo_manager_->getPassiveElements();
    for(const auto& item : passive_configs) {
        auto shape = item.get<std::string>("type");
        if(shape != "box") {
            LOG(WARNING) << item.getName() << " passive object has unsupported type (" << shape << ") and will be ignored";
        }
    }

    // Check if there are user-specified optical properties for materials
    is_user_optics_ = (config_.count({"absorption_length", "refractive_index"}) == 2);
    if(is_user_optics_) {
        absorption_length_ = config_.get<double>("absorption_length");
        refractive_index_ = config_.get<double>("refractive_index");
        LOG(DEBUG) << "Setting user-defined optical properties for sensor material";
    } else {
        // Load data
        std::string laser_data_path = ALLPIX_LASER_DATA_DIRECTORY;

        std::ifstream f(std::filesystem::path(laser_data_path) / "silicon_photoabsorption.data");

        // wavelength: {absorption_length, refractive_index}
        std::map<double, std::pair<double, double>> optics_lut;
        double wl = 0;
@@ -121,7 +116,7 @@ void DepositionLaserModule::initialize() {
            optics_lut[Units::get(wl, "nm")] = {abs_length, refr_ind};
        }

    LOG(DEBUG) << "Loading absorption data: " << laser_data_path;
        LOG(DEBUG) << "Loading optical properties for sensor material from LUT: " << laser_data_path;

        // Find or interpolate absorption depth for given wavelength

@@ -137,11 +132,29 @@ void DepositionLaserModule::initialize() {
            refractive_index_ =
                (optics_lut[wl1].second * (wl2 - wavelength_) + optics_lut[wl2].second * (wavelength_ - wl1)) / (wl2 - wl1);
        }

    }
    LOG(DEBUG) << "Wavelength = " << Units::display(wavelength_, "nm")
               << ", absorption length: " << Units::display(absorption_length_, {"um", "mm"})
               << ", refractive index: " << refractive_index_;

    // Check for unsupported detector materials, warn user if present

    std::vector<std::shared_ptr<Detector>> detectors = geo_manager_->getDetectors();
    for(auto& detector : detectors) {
        auto material = detector->getModel()->getSensorMaterial();
        if(material != SensorMaterial::SILICON && !is_user_optics_) {
            LOG(WARNING) << "Detector " << detector->getName() << " has unsupported material and will be ignored";
        }
    }
    // Check for incompatible passive objects, warn user if there are any
    auto passive_configs = geo_manager_->getPassiveElements();
    for(const auto& item : passive_configs) {
        auto shape = item.get<std::string>("type");
        if(shape != "box") {
            LOG(WARNING) << item.getName() << " passive object has unsupported type (" << shape << ") and will be ignored";
        }
    }

    // Create Histograms
    if(output_plots_) {
        LOG(DEBUG) << "Initializing histograms";
@@ -179,7 +192,6 @@ void DepositionLaserModule::initialize() {
        h_pulse_shape_ =
            CreateHistogram<TH1D>("pulse_shape", "Phi_distribution w.r.t. beam direction", nbins, 0, 8 * pulse_duration_);

        std::vector<std::shared_ptr<Detector>> detectors = geo_manager_->getDetectors();
        for(const auto& detector : detectors) {
            std::string name = "dep_charge_" + detector->getName();
            auto sensor = detector->getModel()->getSensorSize();
@@ -473,6 +485,9 @@ std::optional<DepositionLaserModule::PhotonHit> DepositionLaserModule::track(con
    std::vector<std::pair<std::shared_ptr<Detector>, std::pair<double, double>>> intersection_segments;

    for(auto& detector : detectors) {
        if(detector->getModel()->getSensorMaterial() != SensorMaterial::SILICON && !is_user_optics_) {
            continue;
        }
        auto intersection = intersect_with_sensor(detector, position, direction);
        if(intersection) {
            intersection_segments.emplace_back(std::make_pair(detector, intersection.value()));
+1 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ namespace allpix {
        double absorption_length_{0.};
        double refractive_index_{0.};
        double pulse_duration_;
        bool is_user_optics_;

        // Histograms
        bool output_plots_;
+5 −3
Original line number Diff line number Diff line
@@ -11,12 +11,13 @@ module_output: "DepositedCharge, MCParticle"
## Description

This deposition generator is mostly intended for simulations of laser-TCT experiments.
It would generate charge, deposited by absorption of a laser pulse in silicon bulk.
It generates charge, deposited by absorption of a laser pulse in detector bulk.
This module is not dependent on Geant4. Instead, it implements tracking algorithms and simulations of corresponding physical phenomena by its own, using internal Allpix geometry.

Current implementation assumes that the laser pulse is a bunch of point-like photons, each traveling in a straight line. A lookup table \[[@optical_properties]\] is used to determine absorption and refraction coefficients for a given wavelength.
Current implementation assumes that the laser pulse is a bunch of point-like photons, each traveling in a straight line. A lookup table \[[@optical_properties]\] is used to determine absorption and refraction coefficients in silicon for a given wavelength.
The only supported sensor material is silicon, unless optical properties are explicitly set (see *Parameters*).

Multiple photons are produced in a *one* event, thus a *single* event models a *single* laser pulse.  
Multiple photons are produced in *one* event, thus a *single* event models a *single* laser pulse.


Tracking features:
@@ -60,6 +61,7 @@ As a result, this module yields `DepositedCharge` instances for each detector, w
* `focal_distance`: needs to be specified for `converging` beam. This distance is *as it would be in air*. In silicon, beam shape will effectively stretch along its direction due to refraction and the actual focus will be further away from the source.
* `beam_convergence_angle`: max angle between tracks and `beam_direction`. Needs to be specified for a `converging` beam.
* `output_plots`: if set `true`, this module will produce histograms to monitor beam shape and also 3D distributions of charges, deposited in each detector. Histograms would look sensible even for one-event runs. Defaults to `false`.
* `absorption_length` and `refractive_index`: if both are specified, they override corresponding values from the lookup table. This also allows use of sensor materials other than silicon.

## Usage
A simulation pipeline to build an analog detector response would include `DepositionLaser`, `TransientPropagation` and `PulseTransfer`.
+23 −0
Original line number Diff line number Diff line
# SPDX-FileCopyrightText: 2023 CERN and the Allpix Squared authors
# SPDX-License-Identifier: MIT

#DESC tests reading of physical constants from the datafile

[Allpix]
detectors_file = "geometry_basic_diamond.conf"
number_of_events = 1
multithreading = false

[DepositionLaser]
log_level = "DEBUG"
beam_geometry = "cylindrical"
number_of_photons = 1
source_position = 0 0 0
beam_direction = 0 0 1
wavelength = 1064nm
absorption_length = 1mm
refractive_index = 2.5


#PASS Wavelength = 1064nm, absorption length: 1mm, refractive index: 2.5
#FAIL Detector d1 has unsupported material and will be ignored
+10 −0
Original line number Diff line number Diff line
# SPDX-FileCopyrightText: 2023 CERN and the Allpix Squared authors
# SPDX-License-Identifier: MIT

type = "monolithic"
geometry = "pixel"
sensor_material = "diamond"

number_of_pixels = 1 1
pixel_size = 1mm 1mm
sensor_thickness = 500um
Loading