37 RunObserver(
const Eigen::Vector3d& normal,
Index carriers,
38 std::function<
void(
double,
double)> displacement,
39 std::function<
void(
double)> arrival)
41 inject_time_(carriers, 0.0),
42 displacement_(std::move(displacement)),
43 arrival_(std::move(arrival)) {}
44 void Inject(
Index carrier,
Index,
double t)
override {
45 inject_time_[carrier] = t;
47 void Hop(
Index,
Index,
Index,
const Eigen::Vector3d& dR,
double t)
override {
48 displacement_(t, dR.dot(normal_));
50 void Absorb(
Index carrier,
Index,
double t)
override {
55 transit_sum_ += t - inject_time_[carrier];
58 double First()
const {
return first_; }
59 double MeanTransit()
const {
60 return absorbed_ > 0 ? transit_sum_ / double(absorbed_) : 0.0;
64 Eigen::Vector3d normal_;
65 std::vector<double> inject_time_;
66 std::function<void(
double,
double)> displacement_;
67 std::function<void(
double)> arrival_;
70 double transit_sum_ = 0.0;
90 throw std::runtime_error(
91 "ToFSimulation: the rates belong to a different graph");
101 throw std::runtime_error(
102 "ToFSimulation: needs a ToF graph with sinks, not a bulk graph without "
107 throw std::runtime_error(
"ToFSimulation: runs must be positive");
111 throw std::runtime_error(
112 "ToFSimulation: need 0 < tmin < tmax and bins_per_decade >= 1");
116 bins = std::max<Index>(bins, 1);
118 for (
Index b = 0; b <= bins; ++b) {
120 std::pow(10.0,
double(b) /
double(
settings_.bins_per_decade));
137 std::vector<double>& current,
138 std::vector<double>& arrivals,
140 double& after)
const {
144 std::vector<double> times =
147 RunObserver observer(
149 [&](
double t,
double dx) {
153 }
else if (b >= nbins) {
162 arrivals[std::max<Index>(b, 0)] += 1.0;
166 data.status = engine_->Run(times, random, observer, settings_.limits);
167 data.first_arrival = observer.First();
168 data.mean_transit = observer.MeanTransit();
174 s.samples =
Index(samples.size());
175 if (samples.empty()) {
178 double n = double(samples.size());
179 s.mean = std::accumulate(samples.begin(), samples.end(), 0.0) / n;
180 double var = std::accumulate(
181 samples.begin(), samples.end(), 0.0,
182 [&s](
double acc,
double x) { return acc + (x - s.mean) * (x - s.mean); });
183 var = (samples.size() > 1) ? var / (n - 1.0) : 0.0;
184 s.standard_deviation = std::sqrt(var);
185 s.standard_error = s.standard_deviation / std::sqrt(n);
186 std::sort(samples.begin(), samples.end(), std::greater<double>());
187 Index top = std::max<Index>(1,
Index(std::ceil(0.01 * n)));
188 double top_sum = std::accumulate(samples.begin(), samples.begin() + top, 0.0);
189 s.top_percent_share = (s.mean > 0.0) ? top_sum / (s.mean * n) : 0.0;
197 result.
runs.resize(runs);
199 std::vector<double> current(nbins, 0.0);
200 std::vector<double> arrivals(nbins, 0.0);
205 const Index block = 256;
206 std::vector<std::vector<double>> run_current(block);
207 std::vector<std::vector<double>> run_arrivals(block);
208 std::vector<double> run_before(block);
209 std::vector<double> run_after(block);
210 for (
Index start = 0; start < runs; start += block) {
211 Index count = std::min(block, runs - start);
212#pragma omp parallel for schedule(dynamic)
213 for (
Index k = 0; k < count; ++k) {
214 run_current[k].assign(nbins, 0.0);
215 run_arrivals[k].assign(nbins, 0.0);
218 result.
runs[start + k] =
219 SingleRun(start + k, run_current[k], run_arrivals[k], run_before[k],
222 for (
Index k = 0; k < count; ++k) {
223 for (
Index b = 0; b < nbins; ++b) {
224 current[b] += run_current[k][b];
225 arrivals[b] += run_arrivals[k][b];
227 before += run_before[k];
228 after += run_after[k];
232 std::vector<double> first;
233 std::vector<double> transit;
251 double norm =
graph_.Length() * double(std::max<Index>(result.
injected, 1));
254 double cumulative = 0.0;
255 for (
Index b = 0; b < nbins; ++b) {
257 cumulative += arrivals[b];
259 cumulative / double(std::max<Index>(result.
injected, 1));
Time-homogeneous KMC: waiting time Exp(escape rate), destination with probability w_e / escape rate....
static std::vector< double > InjectionTimes(const std::vector< Pulse > &pulses, Random &random)
the rates stored in the ToFGraph, constant in time
Hop rates of the edges of a ToFGraph as functions of time.
const ToFGraph & Graph() const
Hopping graph for time-of-flight (ToF) transport.
Index Bin(double t) const
std::unique_ptr< WaitingTimeStrategy > own_strategy_
std::vector< double > edges_
std::unique_ptr< StaticRates > own_rates_
std::unique_ptr< KMCEngine > engine_
std::string strategy_name_
ToFSimulation(const ToFGraph &graph, const Settings &settings)
static rates of the graph, exponential waiting times
RunData SingleRun(Index run, std::vector< double > ¤t, std::vector< double > &arrivals, double &before, double &after) const
static Statistic Analyze(std::vector< double > samples)
How a carrier's next hop is drawn: the waiting time and the destination. The pluggable part of the KM...
virtual std::string Name() const =0
virtual void Prepare(const TimeDependentRates &rates)=0
Charge transport classes.
Provides a means for comparing floating point numbers.
Index blocked_injections
injections dropped because all source sites were occupied
double displacement_after
std::vector< double > collected
std::vector< RunData > runs
std::vector< double > bin_edges
double displacement_before
std::vector< double > current
KMCEngine::RunStatus status