Loading doc/usermanual/06_models/03_lifetime_recombination.md +48 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,54 @@ lifetime_hole = 4.5ns This model can be selected in the configuration file via the parameter `recombination_model = "constant"`. ## Custom Recombination Models Allpix Squared provides the possibility to use fully custom recombination models. In order to use a custom model, the parameter `recombination_model = "custom"` needs to be set in the configuration file. Additionally, the following configuration keys have to be provided: - `lifetime_function_electrons`: The formula describing the electron lifetime. - `lifetime_function_holes`: The formula describing the hole lifetime. The functions defined via these parameters can depend on the local doping concentration. In order to use the doping concentration in the formula, an `x` has to be placed at the respective position. Parameters of the functions can either be placed directly in the formulas in framework-internal units, or provided separately as arrays via the `lifetime_parameters_electrons` and `lifetime_parameters_electrons`. Placeholders for parameters in the formula are denoted with squared brackets and a parameter number, for example `[0]` for the first parameter provided. Parameters specified separately from the formula can contain units which will be interpreted automatically. {{% alert title="Warning" color="warning" %}} Parameters directly placed in the recombination formula have to be supplied in framework-internal units since the function will be evaluated with the doping concentration in internal units. It is recommended to use the possibility of separately configuring the parameters and to make use of units to avoid conversion mistakes. {{% /alert %}} The following set of parameters re-implements the [Shockley-Read-Hall recombination](#shockley-read-hall-recombination) model using a custom recombination model. The lifetimes are calculated at a fixed temperature of 293 Kelvin. ```ini # Replicating the Shockley-Read-Hall model at T = 293K recombination_model = "custom" lifetime_function_electrons = "[0]/(1 + x / [1])" lifetime_parameters_electrons = 1.036e-5s, 1e16/cm/cm/cm lifetime_function_holes = "[0]/(1 + x / [1])" lifetime_parameters_holes = 4.144e-4s, 7.1e15/cm/cm/cm ``` {{% alert title="Warning" color="warning" %}} It should be noted that the temperature passed via the module configuration is not evaluated for the custom recombination model, but the model parameters need to be manually adjusted to the required temperature. {{% /alert %}} The interpretation of the custom recombination functions is based on the `ROOT::TFormula` class \[[@rootformula]\] and supports all corresponding features, mathematical expressions and constants. [@shockley-read]: https://doi.org/10.1103/PhysRev.87.835 [@hall]: https://doi.org/10.1103/PhysRev.87.387 Loading src/modules/GenericPropagation/tests/16-lifetime-custom.conf 0 → 100644 +39 −0 Original line number Diff line number Diff line # SPDX-FileCopyrightText: 2017-2023 CERN and the Allpix Squared authors # SPDX-License-Identifier: MIT #DESC tests if custom recombination models work properly [Allpix] detectors_file = "detector.conf" number_of_events = 1 random_seed = 0 [DepositionPointCharge] model = "fixed" source_type = "point" position = 445um 220um 0um number_of_charges = 2000 [ElectricFieldReader] model = "linear" bias_voltage = 100V depletion_voltage = 150V [DopingProfileReader] model = "constant" doping_concentration = -2134560000000 [GenericPropagation] log_level = INFO temperature = 293K charge_per_step = 1 propagate_electrons = false propagate_holes = true recombination_model = "custom" lifetime_function_electrons = "[0]/(1 + x / [1])" lifetime_parameters_electrons = 1.036e-5s, 1e16/cm/cm/cm lifetime_function_holes = "[0]/(1 + x / [1])" lifetime_parameters_holes = 4.144e-4s, 7.1e15/cm/cm/cm #PASS (INFO) [I:GenericPropagation:mydetector] Selected recombination model "custom" src/physics/Recombination.hpp +58 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #ifndef ALLPIX_RECOMBINATION_MODELS_H #define ALLPIX_RECOMBINATION_MODELS_H #include <TFormula.h> #include "exceptions.h" #include "core/config/Configuration.hpp" Loading Loading @@ -171,6 +173,60 @@ namespace allpix { double hole_lifetime_; }; /** * @ingroup Models * @brief Custom recombination model for charge carriers */ class CustomRecombination : virtual public RecombinationModel { public: CustomRecombination(const Configuration& config, bool doping) { electron_lifetime_ = configure_lifetime(config, CarrierType::ELECTRON, doping); hole_lifetime_ = configure_lifetime(config, CarrierType::HOLE, doping); }; bool operator()(const CarrierType& type, double doping, double survival_prob, double timestep) const override { return survival_prob < (1 - std::exp(-1. * timestep / (type == CarrierType::ELECTRON ? electron_lifetime_->Eval(doping) : hole_lifetime_->Eval(doping)))); }; private: std::unique_ptr<TFormula> electron_lifetime_; std::unique_ptr<TFormula> hole_lifetime_; std::unique_ptr<TFormula> configure_lifetime(const Configuration& config, const CarrierType type, bool doping) { std::string name = (type == CarrierType::ELECTRON ? "electrons" : "holes"); auto function = config.get<std::string>("lifetime_function_" + name); auto parameters = config.getArray<double>("lifetime_parameters_" + name, {}); auto lifetime = std::make_unique<TFormula>(("lifetime_" + name).c_str(), function.c_str()); if(!lifetime->IsValid()) { throw InvalidValueError( config, "lifetime_function_" + name, "The provided model is not a valid ROOT::TFormula expression"); } // Check if a doping concentration dependency can be detected by checking for the number of dimensions: if(!doping && lifetime->GetNdim() == 1) { throw ModelUnsuitable("No doping profile available but doping dependence found"); } // Check if number of parameters match up if(static_cast<size_t>(lifetime->GetNpar()) != parameters.size()) { throw InvalidValueError(config, "lifetime_parameters_" + name, "The number of provided parameters and parameters in the function do not match"); } // Set the parameters for(size_t n = 0; n < parameters.size(); ++n) { lifetime->SetParameter(static_cast<int>(n), parameters[n]); } return lifetime; }; }; /** * @brief Wrapper class and factory for recombination models. * Loading Loading @@ -206,6 +262,8 @@ namespace allpix { } else if(model == "none") { LOG(INFO) << "No charge carrier recombination model chosen, finite lifetime not simulated"; model_ = std::make_unique<None>(); } else if(model == "custom") { model_ = std::make_unique<CustomRecombination>(config, doping); } else { throw InvalidModelError(model); } Loading Loading
doc/usermanual/06_models/03_lifetime_recombination.md +48 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,54 @@ lifetime_hole = 4.5ns This model can be selected in the configuration file via the parameter `recombination_model = "constant"`. ## Custom Recombination Models Allpix Squared provides the possibility to use fully custom recombination models. In order to use a custom model, the parameter `recombination_model = "custom"` needs to be set in the configuration file. Additionally, the following configuration keys have to be provided: - `lifetime_function_electrons`: The formula describing the electron lifetime. - `lifetime_function_holes`: The formula describing the hole lifetime. The functions defined via these parameters can depend on the local doping concentration. In order to use the doping concentration in the formula, an `x` has to be placed at the respective position. Parameters of the functions can either be placed directly in the formulas in framework-internal units, or provided separately as arrays via the `lifetime_parameters_electrons` and `lifetime_parameters_electrons`. Placeholders for parameters in the formula are denoted with squared brackets and a parameter number, for example `[0]` for the first parameter provided. Parameters specified separately from the formula can contain units which will be interpreted automatically. {{% alert title="Warning" color="warning" %}} Parameters directly placed in the recombination formula have to be supplied in framework-internal units since the function will be evaluated with the doping concentration in internal units. It is recommended to use the possibility of separately configuring the parameters and to make use of units to avoid conversion mistakes. {{% /alert %}} The following set of parameters re-implements the [Shockley-Read-Hall recombination](#shockley-read-hall-recombination) model using a custom recombination model. The lifetimes are calculated at a fixed temperature of 293 Kelvin. ```ini # Replicating the Shockley-Read-Hall model at T = 293K recombination_model = "custom" lifetime_function_electrons = "[0]/(1 + x / [1])" lifetime_parameters_electrons = 1.036e-5s, 1e16/cm/cm/cm lifetime_function_holes = "[0]/(1 + x / [1])" lifetime_parameters_holes = 4.144e-4s, 7.1e15/cm/cm/cm ``` {{% alert title="Warning" color="warning" %}} It should be noted that the temperature passed via the module configuration is not evaluated for the custom recombination model, but the model parameters need to be manually adjusted to the required temperature. {{% /alert %}} The interpretation of the custom recombination functions is based on the `ROOT::TFormula` class \[[@rootformula]\] and supports all corresponding features, mathematical expressions and constants. [@shockley-read]: https://doi.org/10.1103/PhysRev.87.835 [@hall]: https://doi.org/10.1103/PhysRev.87.387 Loading
src/modules/GenericPropagation/tests/16-lifetime-custom.conf 0 → 100644 +39 −0 Original line number Diff line number Diff line # SPDX-FileCopyrightText: 2017-2023 CERN and the Allpix Squared authors # SPDX-License-Identifier: MIT #DESC tests if custom recombination models work properly [Allpix] detectors_file = "detector.conf" number_of_events = 1 random_seed = 0 [DepositionPointCharge] model = "fixed" source_type = "point" position = 445um 220um 0um number_of_charges = 2000 [ElectricFieldReader] model = "linear" bias_voltage = 100V depletion_voltage = 150V [DopingProfileReader] model = "constant" doping_concentration = -2134560000000 [GenericPropagation] log_level = INFO temperature = 293K charge_per_step = 1 propagate_electrons = false propagate_holes = true recombination_model = "custom" lifetime_function_electrons = "[0]/(1 + x / [1])" lifetime_parameters_electrons = 1.036e-5s, 1e16/cm/cm/cm lifetime_function_holes = "[0]/(1 + x / [1])" lifetime_parameters_holes = 4.144e-4s, 7.1e15/cm/cm/cm #PASS (INFO) [I:GenericPropagation:mydetector] Selected recombination model "custom"
src/physics/Recombination.hpp +58 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #ifndef ALLPIX_RECOMBINATION_MODELS_H #define ALLPIX_RECOMBINATION_MODELS_H #include <TFormula.h> #include "exceptions.h" #include "core/config/Configuration.hpp" Loading Loading @@ -171,6 +173,60 @@ namespace allpix { double hole_lifetime_; }; /** * @ingroup Models * @brief Custom recombination model for charge carriers */ class CustomRecombination : virtual public RecombinationModel { public: CustomRecombination(const Configuration& config, bool doping) { electron_lifetime_ = configure_lifetime(config, CarrierType::ELECTRON, doping); hole_lifetime_ = configure_lifetime(config, CarrierType::HOLE, doping); }; bool operator()(const CarrierType& type, double doping, double survival_prob, double timestep) const override { return survival_prob < (1 - std::exp(-1. * timestep / (type == CarrierType::ELECTRON ? electron_lifetime_->Eval(doping) : hole_lifetime_->Eval(doping)))); }; private: std::unique_ptr<TFormula> electron_lifetime_; std::unique_ptr<TFormula> hole_lifetime_; std::unique_ptr<TFormula> configure_lifetime(const Configuration& config, const CarrierType type, bool doping) { std::string name = (type == CarrierType::ELECTRON ? "electrons" : "holes"); auto function = config.get<std::string>("lifetime_function_" + name); auto parameters = config.getArray<double>("lifetime_parameters_" + name, {}); auto lifetime = std::make_unique<TFormula>(("lifetime_" + name).c_str(), function.c_str()); if(!lifetime->IsValid()) { throw InvalidValueError( config, "lifetime_function_" + name, "The provided model is not a valid ROOT::TFormula expression"); } // Check if a doping concentration dependency can be detected by checking for the number of dimensions: if(!doping && lifetime->GetNdim() == 1) { throw ModelUnsuitable("No doping profile available but doping dependence found"); } // Check if number of parameters match up if(static_cast<size_t>(lifetime->GetNpar()) != parameters.size()) { throw InvalidValueError(config, "lifetime_parameters_" + name, "The number of provided parameters and parameters in the function do not match"); } // Set the parameters for(size_t n = 0; n < parameters.size(); ++n) { lifetime->SetParameter(static_cast<int>(n), parameters[n]); } return lifetime; }; }; /** * @brief Wrapper class and factory for recombination models. * Loading Loading @@ -206,6 +262,8 @@ namespace allpix { } else if(model == "none") { LOG(INFO) << "No charge carrier recombination model chosen, finite lifetime not simulated"; model_ = std::make_unique<None>(); } else if(model == "custom") { model_ = std::make_unique<CustomRecombination>(config, doping); } else { throw InvalidModelError(model); } Loading