votca 2026-dev
Loading...
Searching...
No Matches
kmctof.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Standard includes
21#include <chrono>
22#include <fstream>
23#include <iomanip>
24
25// VOTCA includes
28
29// Local VOTCA includes
30#include "votca/xtp/eigen.h"
31#include "votca/xtp/kmcrates.h"
35#include "votca/xtp/topology.h"
36
37// Local private VOTCA includes
38#include "kmctof.h"
39
40namespace votca {
41namespace xtp {
42
44 carriertype_ = QMStateType(options.get(".carriertype").as<std::string>());
45 if (!carriertype_.isKMCState()) {
46 throw std::runtime_error("kmctof cannot be run for state: " +
47 carriertype_.ToLongString());
48 }
49 temperature_ = options.get(".temperature").as<double>() * tools::conv::kB *
51 field_Vm_ = options.get(".field").as<Eigen::Vector3d>();
53 tof_ = ToFGraph::OptionsFromProperty(options.get(".tof"));
54 seed_ = options.get(".seed").as<std::uint64_t>();
55 runs_ = options.get(".runs").as<Index>();
56
57 const tools::Property& inj = options.get(".injection");
58 KMCEngine::Pulse pulse;
59 pulse.carriers = inj.get("carriers").as<Index>();
60 pulse.shape = KMCEngine::ShapeFromString(inj.get("shape").as<std::string>());
61 pulse.width = inj.get("width").as<double>();
62 Index npulses = inj.get("pulses").as<Index>();
63 double period = inj.get("period").as<double>();
64 if (npulses < 1 || pulse.carriers < 1) {
65 throw std::runtime_error("kmctof: pulses and carriers must be positive");
66 }
67 if (npulses > 1 && !(period > 0.0)) {
68 throw std::runtime_error("kmctof: a pulse train needs period > 0");
69 }
70 pulses_.clear();
71 for (Index p = 0; p < npulses; ++p) {
72 pulse.start = double(p) * period;
73 pulses_.push_back(pulse);
74 }
75
76 waitingtime_ = options.get(".waitingtime").as<std::string>();
77 limits_.max_time = options.get(".maxtime").as<double>();
78 limits_.max_events = options.get(".maxevents").as<Index>();
79 runfile_ = options.get(".runfile").as<std::string>();
80 currentfile_ = options.get(".current.file").as<std::string>();
81 resultfile_ = options.get(".resultfile").as<std::string>();
82 tmin_ = options.get(".current.tmin").as<double>();
83 tmax_ = options.get(".current.tmax").as<double>();
84 bins_per_decade_ = options.get(".current.binsperdecade").as<Index>();
85 log_.setReportLevel(Log::current_level);
86 log_.setMultithreading(true);
87 log_.setCommonPreface("\n ...");
88}
89
91 XTP_LOG(Log::error, log_) << "\n-----------------------------------"
92 "\n KINETIC MONTE CARLO TIME OF FLIGHT"
93 "\n-----------------------------------"
94 << std::flush;
96 XTP_LOG(Log::error, log_) << graph.Summary() << std::flush;
97
99 settings.seed = seed_;
100 settings.runs = runs_;
101 settings.pulses = pulses_;
102 settings.limits = limits_;
103 settings.tmin = tmin_;
104 settings.tmax = tmax_;
106 // rates and waiting times: the static Marcus rates of the graph; a
107 // time-dependent TimeDependentRates (e.g. oscillating field) plugs in here
108 StaticRates rates(graph);
109 std::unique_ptr<WaitingTimeStrategy> strategy =
111 ToFSimulation simulation(graph, settings, rates, *strategy);
113 << "Waiting times: " << simulation.StrategyName() << std::flush;
115 << runs_ << " runs, " << pulses_.size() << " pulse(s) of "
116 << pulses_[0].carriers << " carrier(s), " << OPENMP::getMaxThreads()
117 << " thread(s)" << std::flush;
118 auto start = std::chrono::steady_clock::now();
119 ToFSimulation::Result result = simulation.Simulate();
120 double seconds =
121 std::chrono::duration<double>(std::chrono::steady_clock::now() - start)
122 .count();
123
125 << std::setprecision(6) << result.hops << " hops, " << result.null_events
126 << " null events (occupied site or rejected), " << seconds << " s"
127 << std::flush;
128 if (result.censored > 0) {
130 << "Warning: " << result.censored
131 << " runs stopped by maxtime/maxevents before all carriers arrived; "
132 "they are left out, which biases the times low"
133 << std::flush;
134 }
135 if (result.blocked_injections > 0) {
137 << "Warning: " << result.blocked_injections
138 << " injections dropped (all source sites occupied)" << std::flush;
139 }
140 auto report = [this](const std::string& name,
141 const ToFSimulation::Statistic& s) {
143 << name << ": " << s.mean << " +- " << s.standard_error
144 << " s (standard error, " << s.samples << " runs), standard deviation "
145 << s.standard_deviation
146 << " s, largest 1 % of the runs: " << 100.0 * s.top_percent_share
147 << " % of the sum" << std::flush;
148 };
149 report("First arrival", result.first);
150 report("Mean transit time per carrier", result.transit);
151 if (result.transit.top_percent_share > 0.2) {
153 << "Warning: heavy tail, the mean is dominated by rare long runs; "
154 "compare with grw"
155 << std::flush;
156 }
157
158 double Fn = field_Vm_.dot(graph.Normal());
159 if (Fn != 0.0 && result.transit.samples > 0) {
160 double L = graph.Length() * tools::conv::bohr2nm * 1e-9; // m
162 << "Mobility L/(tau F) from the mean transit time: "
163 << L / result.transit.mean * 1e4 / std::abs(Fn) << " cm^2/Vs"
164 << std::flush;
165 }
166
167 if (!resultfile_.empty()) {
168 ResultFile out("kmctof: time-of-flight kinetic Monte Carlo");
169 out.Add("runs", runs_);
170 out.Add("injected", result.injected);
171 out.Add("censored", result.censored);
172 out.Add("blocked_injections", result.blocked_injections);
173 out.Add("hops", result.hops);
174 out.Add("null_events", result.null_events);
175 out.Add("first_mean", result.first.mean, "s");
176 out.Add("first_error", result.first.standard_error, "s");
177 out.Add("first_std", result.first.standard_deviation, "s");
178 out.Add("transit_mean", result.transit.mean, "s");
179 out.Add("transit_error", result.transit.standard_error, "s");
180 out.Add("transit_std", result.transit.standard_deviation, "s");
181 out.Add("transit_top_percent_share", result.transit.top_percent_share, "-");
182 double L = graph.Length() * tools::conv::bohr2nm * 1e-9; // m
183 out.Add("length", L, "m");
184 out.Add("field_normal", Fn, "V/m");
185 if (Fn != 0.0 && result.transit.samples > 0) {
186 out.Add("mobility_transit", L / result.transit.mean * 1e4 / std::abs(Fn),
187 "cm^2/Vs");
188 }
189 out.Write(resultfile_);
190 }
191 if (!runfile_.empty()) {
192 std::ofstream out(runfile_);
193 out << "# run, injected, absorbed, censored, first arrival [s], mean "
194 "transit [s], hops, null events, end time [s]\n";
195 out << std::setprecision(10);
196 for (Index r = 0; r < Index(result.runs.size()); ++r) {
197 const ToFSimulation::RunData& d = result.runs[r];
198 out << r << " " << d.status.injected << " " << d.status.absorbed << " "
199 << d.status.censored << " " << d.first_arrival << " "
200 << d.mean_transit << " " << d.status.hops << " "
201 << d.status.null_events << " " << d.status.end_time << "\n";
202 }
203 }
204 if (!currentfile_.empty()) {
205 std::ofstream out(currentfile_);
206 out << "# transient current per injected carrier (Ramo-Shockley): "
207 "I = (sum of the hop displacements along the transport normal "
208 "in the bin) / (L x injected carriers x bin width), in 1/s; the "
209 "circuit current is q x injected carriers x I, and the integral "
210 "of I is the mean displacement per injected carrier in units of "
211 "L\n";
212 out << "# collected fraction: carriers absorbed up to t_high / injected "
213 "carriers\n";
214 out << "# t_low [s], t_high [s], t_mid (geometric) [s], current [1/s], "
215 "collected fraction at t_high\n";
216 out << "# displacement before t_low of the first bin: "
217 << result.displacement_before
218 << ", after the last bin: " << result.displacement_after << "\n";
219 out << std::setprecision(10);
220 for (Index b = 0; b < Index(result.current.size()); ++b) {
221 double lo = result.bin_edges[b];
222 double hi = result.bin_edges[b + 1];
223 out << lo << " " << hi << " " << std::sqrt(lo * hi) << " "
224 << result.current[b] << " " << result.collected[b] << "\n";
225 }
226 }
227 std::cout << log_;
228 return true;
229}
230
231} // namespace xtp
232} // namespace votca
class to manage program options with xml serialization functionality
Definition property.h:55
Property & get(const std::string &key)
get existing property
Definition property.cc:79
T as() const
return value as type
Definition property.h:283
static Pulse::Shape ShapeFromString(const std::string &name)
Definition kmcengine.cc:67
std::string currentfile_
Definition kmctof.h:70
ToFGraph::Options tof_
Definition kmctof.h:63
QMStateType carriertype_
Definition kmctof.h:59
std::uint64_t seed_
Definition kmctof.h:64
bool Evaluate(Topology &top) override
Definition kmctof.cc:90
Eigen::Vector3d field_Vm_
Definition kmctof.h:62
std::string runfile_
Definition kmctof.h:69
double temperature_
Definition kmctof.h:60
void ParseOptions(const tools::Property &options) override
Definition kmctof.cc:43
KMCEngine::Limits limits_
Definition kmctof.h:67
std::string waitingtime_
Definition kmctof.h:68
std::string resultfile_
Definition kmctof.h:71
Index bins_per_decade_
Definition kmctof.h:74
std::vector< KMCEngine::Pulse > pulses_
Definition kmctof.h:66
Eigen::Vector3d field_
Definition kmctof.h:61
Small machine-readable result file of a calculator: one "key value unit" line per quantity (unit "-" ...
Definition resultfile.h:42
void Write(const std::string &filename) const
Definition resultfile.h:59
void Add(const std::string &key, double value, const std::string &unit)
Definition resultfile.h:49
the rates stored in the ToFGraph, constant in time
Definition kmcrates.h:80
Hopping graph for time-of-flight (ToF) transport.
Definition tofgraph.h:77
double Length() const
Definition tofgraph.h:184
const Eigen::Vector3d & Normal() const
unit normal of the cut face, pointing from source to sink side
Definition tofgraph.h:179
static Options OptionsFromProperty(const tools::Property &tof)
Options from the "tof" subpackage (subpackages/tof.xml), lengths in nm.
Definition tofgraph.cc:73
std::string Summary() const
human readable summary
Definition tofgraph.cc:360
Many independent time-of-flight KMC runs on a ToFGraph and their statistics.
const std::string & StrategyName() const
Container for segments and box and atoms.
Definition topology.h:41
#define XTP_LOG(level, log)
Definition logger.h:40
const double ev2hrt
Definition constants.h:54
const double kB
Definition constants.h:40
const double bohr2nm
Definition constants.h:46
const double nm2bohr
Definition constants.h:47
Index getMaxThreads()
Definition eigen.h:145
Charge transport classes.
Definition ERIs.h:28
std::unique_ptr< WaitingTimeStrategy > MakeWaitingTimeStrategy(const std::string &name)
strategy by name: exponential, thinning, inversion
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
static Level current_level
Definition globals.h:30
std::vector< double > collected
std::vector< RunData > runs
std::vector< double > bin_edges
std::vector< double > current
std::vector< KMCEngine::Pulse > pulses
double top_percent_share
share of the sum contributed by the largest 1 % of the samples