47 throw std::runtime_error(
"kmclifetime cannot be run for state: " +
54 if (options.
get(
".injectionmethod").
as<std::string>() !=
"random") {
55 throw std::runtime_error(
"kmclifetime: injectionmethod must be random");
63 settings_.max_wall_time = options.
get(
".maxrealtime").
as<
double>();
75 energyfile_ = energy.get(
"outputfile").as<std::string>();
76 alpha_ = energy.get(
"alpha").as<
double>();
81 log_.setMultithreading(
true);
82 log_.setCommonPreface(
"\n ...");
88 std::vector<tools::Property*> sites = xml.
Select(
"lifetimes.site");
90 std::vector<double> rates(n, -1.0);
93 if (id < 0 || id >= n) {
94 throw std::runtime_error(
"kmclifetime: site " + std::to_string(
id) +
96 " is not in the state file");
98 if (rates[
id] >= 0.0) {
99 throw std::runtime_error(
"kmclifetime: site " + std::to_string(
id) +
102 double lifetime = prop->as<
double>();
103 if (!(lifetime > 0.0) || !std::isfinite(lifetime)) {
104 throw std::runtime_error(
"kmclifetime: the lifetime of site " +
105 std::to_string(
id) +
" must be positive");
107 rates[id] = 1.0 / lifetime;
109 for (
Index i = 0; i < n; ++i) {
110 if (rates[i] < 0.0) {
112 throw std::runtime_error(
"kmclifetime: no lifetime for site " +
123 "\n KMC WITH FINITE LIFETIMES"
124 "\n-----------------------------------"
135 std::unique_ptr<LifetimeSimulation::ExactResult> exact;
137 exact = std::make_unique<LifetimeSimulation::ExactResult>(
140 <<
" (" << exact->solver <<
", backward error "
141 << exact->backward_error <<
"):" << std::flush;
143 << std::scientific <<
" lifetime " << exact->lifetime
144 <<
" s, diffusion length sqrt(<R^2>) "
145 << std::sqrt(exact->squared_displacement) * nm
146 <<
" nm, per direction sqrt(<R_a^2>) "
147 << (exact->squared_components.cwiseSqrt() * nm).transpose() <<
" nm"
149 if (!exact->converged) {
151 <<
"Warning: the iterative solver did not converge" << std::flush;
156 <<
" carriers the KMC includes site exclusion, the exact values "
162 std::unique_ptr<LifetimeSimulation::Result> result;
165 std::unique_ptr<WaitingTimeStrategy> strategy =
172 <<
"times: " << strategy->Name() << std::flush;
173 auto start = std::chrono::steady_clock::now();
175 std::make_unique<LifetimeSimulation::Result>(simulation.
Simulate());
177 std::chrono::duration<double>(std::chrono::steady_clock::now() - start)
182 <<
" hops, " << r.
null_events <<
" attempts into occupied sites, "
188 <<
" run(s) stopped by maxrealtime" << std::flush;
192 << std::scientific <<
"Average lifetime: " << r.
lifetime <<
" +- "
195 <<
"\n mean distance <|R|>: " << r.
mean_distance * nm <<
" +- "
197 <<
"\n diffusion length sqrt(<R^2>): " << LD * nm <<
" +- "
199 <<
"\n per direction sqrt(<R_a^2>): "
201 <<
"\n D = <R^2>/(6 <lifetime>): "
206 <<
" KMC - exact: lifetime "
208 <<
" standard errors, <R^2> "
211 <<
" standard errors" << std::flush;
216 out <<
"#Simtime [s]\t Insertion\t Carrier ID\t Lifetime[s]\tSteps\t "
217 "Decay segment\t x_travelled[nm]\t y_travelled[nm]\t "
218 "z_travelled[nm]\t run\n";
219 out << std::setprecision(10);
223 <<
"\t" << d.
hops <<
"\t" << d.
site <<
"\t"
232 out <<
"#Simtime [s]\tHops\tEnergy[eV]\tEnergy_a=" <<
alpha_
233 <<
"[eV] (run 0, mean over the carriers present)\n";
234 double avg = r.
energy.empty() ? 0.0 : r.
energy.front().energy;
237 out <<
e.time <<
"\t" <<
e.hops <<
"\t"
244 out <<
"#SiteID, Occupation prob at "
256 ResultFile out(
"kmclifetime: kinetic Monte Carlo with finite lifetimes");
257 const double to_m = nm * 1
e-9;
258 const char* axes =
"xyz";
267 out.
Add(
"hops_per_carrier", r.
hops,
"-");
272 for (
Index a = 0; a < 3; ++a) {
273 out.
Add(std::string(
"msd_") + axes[a],
278 out.
Add(
"diffusion_coefficient",
282 out.
Add(
"exact_available",
Index(exact !=
nullptr));
284 out.
Add(
"exact_lifetime", exact->lifetime,
"s");
285 out.
Add(
"exact_msd", exact->squared_displacement * to_m * to_m,
"m^2");
286 for (
Index a = 0; a < 3; ++a) {
287 out.
Add(std::string(
"exact_msd_") + axes[a],
288 exact->squared_components[a] * to_m * to_m,
"m^2");
290 out.
Add(
"exact_diffusion_length",
291 std::sqrt(exact->squared_displacement) * to_m,
"m");
292 out.
Add(
"exact_backward_error", exact->backward_error,
"-");
302 out <<
"#PairID,SiteID1,SiteID2, ,rate12[1/s],rate21[1/s] at "
308 out << pair->getId() <<
" " << pair->Seg1()->getId() <<
" "
309 << pair->Seg2()->getId() <<
" " << rates.
rate12 <<
" " << rates.
rate21
316 const ToFGraph& graph,
const std::vector<double>& decay,
320 Eigen::VectorXd in = Eigen::VectorXd::Zero(n);
321 for (
Index i = 0; i < n; ++i) {
327 out <<
"#SiteID, k/(k+outgoing rates), k/(k+incoming rates), fraction of "
328 "the KMC decays, exact decay probability (one carrier)\n";
329 for (
Index i = 0; i < n; ++i) {
331 double pout = (k > 0.0) ? k / (k + graph.
EscapeRate(i)) : 0.0;
332 double pin = (k > 0.0) ? k / (k + in[i]) : 0.0;
333 out << i <<
" " << pout <<
" " << pin <<
" "
338 <<
"Decay probabilities written to " <<
probfile_ << std::flush;
std::string trajectoryfile_
void WriteDecayProbabilities(const ToFGraph &graph, const std::vector< double > &decay, const LifetimeSimulation::Result *kmc, const LifetimeSimulation::ExactResult *exact)
std::vector< double > ReadDecayRates(const ToFGraph &graph) const
std::string lifetimefile_
void WriteRates(const Topology &top)
std::string injection_pattern_
std::string ignore_types_
bool Evaluate(Topology &top) override
LifetimeSimulation::Settings settings_
void ParseOptions(const tools::Property &options) override
Kinetic Monte Carlo of carriers (excitons) that hop and decay with a site-dependent rate,...
static ExactResult Exact(const ToFGraph &graph, const std::vector< double > &decay_rates, Index direct_limit=20000, double tolerance=1e-12)
PairRates Rate(const QMPair &pair, QMStateType carriertype) const
Small machine-readable result file of a calculator: one "key value unit" line per quantity (unit "-" ...
void Write(const std::string &filename) const
void Add(const std::string &key, double value, const std::string &unit)
the rates stored in the ToFGraph, constant in time
Hopping graph for time-of-flight (ToF) transport.
const Site & getSite(Index i) const
Index NumberOfSites() const
static Options BulkOptions(const std::string &injection_pattern, const std::string &ignore_types)
EdgeRange OutEdges(Index i) const
double EscapeRate(Index i) const
sum of the rates of all out-edges
std::string Summary() const
human readable summary
Container for segments and box and atoms.
#define XTP_LOG(level, log)
Charge transport classes.
std::unique_ptr< WaitingTimeStrategy > MakeWaitingTimeStrategy(const std::string &name)
strategy by name: exponential, thinning, inversion
Provides a means for comparing floating point numbers.
static Level current_level
Eigen::VectorXd decay_probability
Eigen::Vector3d displacement
Eigen::VectorXd occupation
occupation probability per site (sum: number of carriers)
std::vector< Record > records
double squared_displacement
Eigen::VectorXd decay_fraction
fraction of the decays per site
std::vector< EnergySample > energy
double mean_distance_error
Eigen::Vector3d squared_components
double squared_displacement_error
bool ignored
segment type in Options::ignore_types, no edges