29#include <boost/math/special_functions/erf.hpp>
30#include <boost/math/special_functions/gamma.hpp>
48 std::uint32_t(seed & 0xffffffffu), std::uint32_t(seed >> 32),
49 std::uint32_t(stream & 0xffffffffu), std::uint32_t(stream >> 32)};
58 double r = std::sqrt(-2.0 * std::log(
Uniform()));
60 spare_ = r * std::sin(phi);
62 return r * std::cos(phi);
66 if (!(mean >= 0.0) || !std::isfinite(mean)) {
67 throw std::runtime_error(
"ModelRandom::Poisson: mean must be >= 0");
72 double m = std::min(mean, 500.0);
74 const double limit = std::exp(-m);
86 throw std::runtime_error(
"ModelRandom::Integer: n must be positive");
88 const std::uint64_t un = std::uint64_t(n);
89 const std::uint64_t limit = std::numeric_limits<std::uint64_t>::max() -
90 std::numeric_limits<std::uint64_t>::max() % un;
101 const std::vector<Eigen::Vector3d>& points)
103 if (!(box.minCoeff() > 0.0)) {
104 throw std::runtime_error(
"PeriodicCells: box lengths must be positive");
106 if (!(radius > 0.0) || !(2.0 * radius < box.minCoeff())) {
107 throw std::runtime_error(
108 "PeriodicCells: the search radius must be positive and smaller than "
111 for (
Index d = 0; d < 3; ++d) {
112 n_[d] = std::max(
Index(1),
Index(std::floor(box[d] / radius)));
115 while (
double(
n_[0]) *
double(
n_[1]) *
double(
n_[2]) >
116 2.0 *
double(points.size()) + 27.0) {
117 Index d = Index(std::max_element(n_.begin(), n_.end()) - n_.begin());
118 n_[d] = std::max(Index(1), n_[d] / 2);
120 for (
Index d = 0; d < 3; ++d) {
121 cell_[d] = box[d] / double(
n_[d]);
124 std::vector<Index> cell_of(points.size());
125 start_.assign(ncells + 1, 0);
126 std::array<Index, 3> c;
127 for (
Index i = 0; i <
Index(points.size()); ++i) {
131 for (
Index k = 0; k < ncells; ++k) {
135 std::vector<Index> fill(
start_.begin(),
start_.end() - 1);
136 for (
Index i = 0; i <
Index(points.size()); ++i) {
142 std::array<Index, 3>& c)
const {
143 for (
Index d = 0; d < 3; ++d) {
144 double x = p[d] -
box_[d] * std::floor(p[d] /
box_[d]);
146 c[d] = std::min(std::max(k,
Index(0)),
n_[d] - 1);
148 return (c[0] *
n_[1] + c[1]) *
n_[2] + c[2];
154 std::array<Index, 3> lo, hi;
155 for (
Index d = 0; d < 3; ++d) {
156 lo[d] = std::min(s, (
n_[d] - 1) / 2);
157 hi[d] = std::min(s,
n_[d] - 1 - (
n_[d] - 1) / 2);
159 for (
Index o0 = -lo[0]; o0 <= hi[0]; ++o0) {
160 for (
Index o1 = -lo[1]; o1 <= hi[1]; ++o1) {
161 for (
Index o2 = -lo[2]; o2 <= hi[2]; ++o2) {
162 if (std::max({std::abs(o0), std::abs(o1), std::abs(o2)}) != s) {
168 f((k0 *
n_[1] + k1) *
n_[2] + k2);
175 const Eigen::Vector3d& r2)
const {
176 Eigen::Vector3d d = r2 - r1;
177 for (
Index k = 0; k < 3; ++k) {
179 if (d[k] > 0.5 *
box_[k]) {
181 }
else if (d[k] < -0.5 *
box_[k]) {
184 if (std::abs(d[k]) > 0.5 *
box_[k]) {
185 d[k] -=
box_[k] * std::round(d[k] /
box_[k]);
192 const Eigen::Vector3d& p,
double radius,
193 const std::function<
void(
Index,
const Eigen::Vector3d&,
double)>& f)
const {
194 if (radius >
cell_.minCoeff() * (1.0 + 1
e-12)) {
195 throw std::runtime_error(
196 "PeriodicCells::Within: radius larger than the cell list radius");
198 std::array<Index, 3> c;
200 for (
Index s = 0; s <= 1; ++s) {
205 double dist = conn.norm();
222 throw std::runtime_error(
"PeriodicCells::Nearest: more neighbours (" +
223 std::to_string(l) +
") than points (" +
224 std::to_string(n) +
")");
229 std::array<Index, 3> c;
231 std::vector<std::pair<double, Index>> cand;
232 const double inf = std::numeric_limits<double>::infinity();
233 for (
Index s = 0;; ++s) {
241 double guaranteed = inf;
243 for (
Index d = 0; d < 3; ++d) {
244 Index full = std::max((
n_[d] - 1) / 2,
n_[d] - 1 - (
n_[d] - 1) / 2);
247 guaranteed = std::min(guaranteed,
double(s) *
cell_[d]);
253 if (
Index(cand.size()) >= l &&
254 std::count_if(cand.begin(), cand.end(),
255 [guaranteed](
const std::pair<double, Index>& x) {
256 return x.first <= guaranteed;
261 std::partial_sort(cand.begin(), cand.begin() + l, cand.end());
262 std::vector<Index> result(l);
263 for (
Index k = 0; k < l; ++k) {
264 result[k] = cand[k].second;
275 if (!
opt_.traps.empty() &&
opt_.trap_factor > 0.0) {
290 auto fail = [](
const std::string& m) {
291 throw std::runtime_error(
"StochasticNetwork: " + m);
293 if (!(
opt_.box.minCoeff() > 0.0)) {
294 fail(
"box lengths must be positive");
296 if (
opt_.sites <= 0) {
297 fail(
"need at least one site");
304 "point process: hard core, radius mean and variance must be >= 0, "
305 "candidates and iterations > 0");
308 fail(
"point process: a radius variance needs a positive radius mean");
310 if (
opt_.connection_r.empty() ||
311 opt_.connection_r.size() !=
opt_.connection_p.size()) {
312 fail(
"connection table: r and p need the same, nonzero length");
314 for (std::size_t k = 0; k <
opt_.connection_r.size(); ++k) {
315 if (!(
opt_.connection_p[k] >= 0.0 &&
opt_.connection_p[k] <= 1.0)) {
316 fail(
"connection probabilities must be in [0, 1]");
318 if (!(
opt_.connection_r[k] >= 0.0) ||
319 (k > 0 && !(
opt_.connection_r[k] >
opt_.connection_r[k - 1]))) {
320 fail(
"connection distances must be >= 0 and ascending");
323 if (!(2.0 *
opt_.connection_r.back() <
opt_.box.minCoeff())) {
324 fail(
"the largest connection distance must be smaller than half the box");
326 if (
opt_.carriers.empty()) {
327 fail(
"need at least one carrier");
329 for (std::size_t c = 0; c <
opt_.carriers.size(); ++c) {
332 fail(car.
state.
ToString() +
" is not a hopping state (e, h, s, t)");
334 for (std::size_t d = 0; d < c; ++d) {
335 if (
opt_.carriers[d].state == car.
state) {
340 double w_c = 1.0 -
e.w_a -
e.w_b;
341 if (!(
e.sigma >= 0.0) || !(
e.w_a >= 0.0) || !(
e.w_b >= 0.0) ||
343 fail(
"energy model: sigma, w_a, w_b >= 0 and w_a + w_b <= 1");
345 if (
e.l_b <= 0 ||
e.l_c <= 0 || (
e.w_b > 0.0 &&
e.l_b >
opt_.sites) ||
346 (w_c > 1
e-12 &&
e.l_c >
opt_.sites)) {
347 fail(
"energy model: l_b and l_c must be in [1, number of sites]");
352 fail(
"coupling model: residual quantiles must be ascending");
356 if (!(
opt_.trap_factor >= 0.0)) {
357 fail(
"the trap factor must be >= 0");
362 fail(
"traps need a carrier, a density >= 0 and at least one site");
364 for (
const auto& o : t.
offsets) {
365 if (o.size() !=
opt_.carriers.size()) {
366 fail(
"trap offsets need one value per carrier");
370 if (!(std::abs(
opt_.energy_correlation) <= 1.0) ||
371 !(std::abs(
opt_.coupling_correlation) <= 1.0)) {
372 fail(
"correlations must be in [-1, 1]");
377 const Eigen::Vector3d& box,
Index n,
379 std::vector<Eigen::Vector3d>& positions,
380 std::vector<double>& radii) {
388 constexpr Index M = 512;
389 std::vector<double> table;
392 for (
Index k = 1; k < M; ++k) {
393 table[k] = boost::math::gamma_p_inv(shape,
double(k) /
double(M));
396 auto radius = [&]() {
401 double t = u * double(M);
404 if (k < 1 || k >= M - 1) {
405 x = boost::math::gamma_p_inv(shape, std::min(u, 1.0 - 1
e-16));
407 x = table[k] + (t - double(k)) * (table[k + 1] - table[k]);
411 const double half_box = 0.5 * box.minCoeff();
414 positions.reserve(n);
416 double max_accepted = 0.0;
417 std::vector<Eigen::Vector3d> cand;
418 std::vector<double> cand_r;
419 std::vector<char> keep;
420 std::vector<Index> survivors;
425 double max_cand = 0.0;
426 for (
Index k = 0; k < m; ++k) {
427 for (
Index d = 0; d < 3; ++d) {
428 cand[k][d] = (1.0 - random.
Uniform()) * box[d];
430 cand_r[k] = radius();
431 max_cand = std::max(max_cand, cand_r[k]);
433 double search = std::max(max_cand, max_accepted);
434 if (!(search < half_box)) {
435 throw std::runtime_error(
"StochasticNetwork: point radii (" +
437 " nm) must be smaller than half the box");
440 search = std::max(search, 1
e-9 * half_box);
443 if (!positions.empty()) {
445 for (
Index k = 0; k < m; ++k) {
446 acc.
Within(cand[k], std::max(cand_r[k], max_accepted),
447 [&](
Index j,
const Eigen::Vector3d&,
double dist) {
448 if (dist < std::max(cand_r[k], radii[j])) {
457 PeriodicCells cells(box, std::max(max_cand, 1
e-9 * half_box), cand);
458 for (
Index k = 0; k < m; ++k) {
462 cells.
Within(cand[k], std::max(max_cand, 1
e-9 * half_box),
463 [&](
Index j,
const Eigen::Vector3d&,
double dist) {
467 bool larger = cand_r[j] > cand_r[k] ||
468 (j < k && cand_r[j] == cand_r[k]);
469 if (larger && dist < cand_r[j]) {
476 for (
Index k = 0; k < m; ++k) {
478 survivors.push_back(k);
482 if (
Index(survivors.size()) > need) {
484 for (
Index k = 0; k < need; ++k) {
486 std::swap(survivors[k], survivors[r]);
488 survivors.resize(need);
490 for (
Index k : survivors) {
491 positions.push_back(cand[k]);
492 radii.push_back(cand_r[k]);
493 max_accepted = std::max(max_accepted, cand_r[k]);
495 if (
Index(positions.size()) == n) {
499 throw std::runtime_error(
500 "StochasticNetwork: the point process placed only " +
501 std::to_string(positions.size()) +
" of " + std::to_string(n) +
503 " iterations; the box is too small for the radii (increase the box or "
509 const std::vector<double>& A,
const std::vector<double>& Bf,
510 const std::vector<double>& C) {
511 if (
Index(A.size()) != sites ||
Index(Bf.size()) != sites ||
512 Index(C.size()) != sites) {
513 throw std::runtime_error(
514 "StochasticNetwork::MovingAverage: need one field value per site");
516 const double w_c = std::max(0.0, 1.0 - m.
w_a - m.
w_b);
517 const double fa = std::sqrt(m.
w_a);
518 const double fb = std::sqrt(m.
w_b /
double(m.
l_b));
519 const double fc = std::sqrt(w_c /
double(m.
l_c));
521 const Index lc = w_c > 0.0 ? m.
l_c : 0;
522 const Index lmax = std::max(lb, lc);
523 std::vector<double> z(sites);
524#pragma omp parallel for schedule(dynamic, 256)
525 for (
Index i = 0; i < sites; ++i) {
526 std::vector<Index> nb = cells.
Nearest(i, lmax);
528 for (
Index k = 0; k < lb; ++k) {
532 for (
Index k = 0; k < lc; ++k) {
535 z[i] = fa * A[i] + fb * b + fc * c;
543 double volume =
opt_.box.prod();
545 std::min(0.49 *
opt_.box.minCoeff(), 2.0 * std::cbrt(volume /
double(n)));
548 std::vector<double> first;
549 std::vector<double> A(n), B(n), C(n);
550 for (std::size_t c = 0; c <
opt_.carriers.size(); ++c) {
554 for (std::vector<double>* f : {&A, &B, &C}) {
555 for (
double& x : *f) {
562 }
else if (c == 1 &&
opt_.energy_correlation != 0.0) {
563 double rho =
opt_.energy_correlation;
564 double s = std::sqrt(std::max(0.0, 1.0 - rho * rho));
565 for (
Index i = 0; i < n; ++i) {
566 z[i] = rho * first[i] + s * z[i];
569 for (
double& x : z) {
577 const std::vector<double>& rs =
opt_.connection_r;
578 const std::vector<double>& ps =
opt_.connection_p;
579 if (r <= rs.front()) {
582 if (r >= rs.back()) {
585 std::size_t k = std::size_t(std::upper_bound(rs.begin(), rs.end(), r) -
587 double t = (r - rs[k - 1]) / (rs[k] - rs[k - 1]);
588 return ps[k - 1] + t * (ps[k] - ps[k - 1]);
592double NormalCdf(
double g) {
return 0.5 * std::erfc(-g / std::sqrt(2.0)); }
593double NormalQuantile(
double u) {
594 return -std::sqrt(2.0) * boost::math::erfc_inv(2.0 * u);
609 auto node = [K](
Index k) {
610 return NormalQuantile((
double(k) + 0.5) /
double(K));
612 double t = NormalCdf(g) * double(K) - 0.5;
614 return q[0] + (g - node(0));
616 if (t >=
double(K - 1)) {
617 return q[K - 1] + (g - node(K - 1));
619 Index k = std::min(
Index(std::floor(t)), K - 2);
621 double g1 = node(k + 1);
622 double f = std::min(1.0, std::max(0.0, (g - g0) / (g1 - g0)));
623 return q[k] + f * (q[k + 1] - q[k]);
630 return mean + std::sqrt(var) *
Residual(m, g);
635 if (
opt_.traps.empty() ||
opt_.trap_factor == 0.0) {
639 double volume =
opt_.box.prod();
641 std::min(0.49 *
opt_.box.minCoeff(), 2.0 * std::cbrt(volume /
double(n)));
643 std::vector<char> used(n, 0);
644 for (std::size_t t = 0; t <
opt_.traps.size(); ++t) {
646 double expected = trap.
density *
opt_.trap_factor * double(n);
648 if (random.
Uniform() <= expected -
double(count)) {
652 for (
Index k = 0; k < count; ++k) {
654 std::vector<Index> sites;
655 for (
Index attempt = 0; attempt < 1000 && sites.empty(); ++attempt) {
657 std::vector<Index> nb = cells.
Nearest(centre, size);
658 if (std::none_of(nb.begin(), nb.end(),
659 [&used](
Index i) { return used[i] != 0; })) {
664 throw std::runtime_error(
665 "StochasticNetwork: no free place for a trap; the trap density "
668 for (
Index q = 0; q < size; ++q) {
670 for (std::size_t c = 0; c <
opt_.carriers.size(); ++c) {
682 const double rmax =
opt_.connection_r.back();
689 const std::size_t ncar =
opt_.carriers.size();
690 const double rho =
opt_.coupling_correlation;
691 const double s = std::sqrt(std::max(0.0, 1.0 - rho * rho));
697 std::vector<Partner> partners;
698 std::vector<double> g(ncar);
699 for (
Index i = 0; i < n; ++i) {
702 [&](
Index j,
const Eigen::Vector3d& conn,
double dist) {
704 partners.push_back({j, conn, dist});
707 std::sort(partners.begin(), partners.end(),
708 [](
const Partner& a,
const Partner& b) { return a.j < b.j; });
709 for (
const Partner& p : partners) {
711 if (f <= 0.0 || (f < 1.0 && random.
Uniform() > f)) {
714 for (std::size_t c = 0; c < ncar; ++c) {
718 g[1] = rho * g[0] + s * g[1];
720 Pair pair{i, p.j, p.R, std::vector<double>(ncar)};
721 for (std::size_t c = 0; c < ncar; ++c) {
723 std::pow(10.0,
Log10J2(
opt_.carriers[c].coupling, p.dist, g[c])) *
726 pairs_.push_back(std::move(pair));
733 throw std::runtime_error(
"StochasticNetwork: topology must be empty");
735 Eigen::Matrix3d box = Eigen::Matrix3d::Zero();
736 box.diagonal() =
opt_.box;
743 for (std::size_t c = 0; c <
opt_.carriers.size(); ++c) {
751 const std::vector<Segment>& segs = top.
Segments();
754 QMPair& pair = nblist.
Add(segs[p.i], segs[p.j], p.R);
755 for (std::size_t c = 0; c <
opt_.carriers.size(); ++c) {
756 pair.setJeff2(p.J2[c],
opt_.carriers[c].state);
770 std::vector<double> box = p.
get(
"box").
as<std::vector<double>>();
771 if (box.size() != 3) {
772 throw std::runtime_error(
"stochasticnetwork: box needs three lengths");
774 opt.
box = Eigen::Vector3d(box[0], box[1], box[2]) * nm;
784 pp.ifExistsReturnElseReturnDefault<
double>(
"candidates", 3.0);
786 pp.ifExistsReturnElseReturnDefault<
Index>(
"maxiterations", 200);
811 if (j.exists(
"quantiles")) {
813 j.get(
"quantiles").as<std::vector<double>>();
816 c->ifExistsReturnElseReturnDefault<
double>(
"U_xX_nN", 0.0) * ev;
818 c->ifExistsReturnElseReturnDefault<
double>(
"U_nX_nN", 0.0) * ev;
820 c->ifExistsReturnElseReturnDefault<
double>(
"U_xN_xX", 0.0) * ev;
825 QMStateType state(t->get(
"carrier").as<std::string>());
827 for (std::size_t c = 0; c < opt.
carriers.size(); ++c) {
828 if (opt.
carriers[c].state == state) {
833 throw std::runtime_error(
"stochasticnetwork: trap for carrier " +
834 state.
ToString() +
" without a carrier block");
836 trap.
density = t->get(
"density").as<
double>();
838 t->ifExistsReturnElseReturnDefault<
double>(
"releaserate", 0.0);
840 std::vector<double> o = site->as<std::vector<double>>();
841 for (
double& x : o) {
846 opt.
traps.push_back(trap);
854 std::ostringstream out;
855 out << std::setprecision(10);
856 auto list = [&out](
const std::vector<double>& v,
double f) {
857 for (std::size_t k = 0; k < v.size(); ++k) {
858 out << (k ?
" " :
"") << v[k] * f;
861 out <<
"<?xml version=\"1.0\"?>\n";
862 out <<
"<!-- stochastic network model; lengths nm, energies eV, couplings "
863 "log10(J^2/eV^2) with r in nm -->\n";
864 out <<
"<stochasticnetwork>\n";
865 out <<
" <sites>" << opt.
sites <<
"</sites>\n";
866 out <<
" <box>" << opt.
box[0] * nm <<
" " << opt.
box[1] * nm <<
" "
867 << opt.
box[2] * nm <<
"</box>\n";
868 out <<
" <seed>" << opt.
seed <<
"</seed>\n";
869 out <<
" <segmentname>" << opt.
segment_name <<
"</segmentname>\n";
870 out <<
" <points>\n";
874 <<
"</radiusvariance>\n";
877 <<
"</maxiterations>\n";
878 out <<
" </points>\n";
879 out <<
" <connection>\n <r>";
883 out <<
"</p>\n </connection>\n";
885 <<
"</energycorrelation>\n";
887 <<
"</couplingcorrelation>\n";
889 out <<
" <carrier>\n";
891 out <<
" <energy>\n";
892 out <<
" <mean>" << c.
energy.
mean * ev <<
"</mean>\n";
893 out <<
" <sigma>" << c.
energy.
sigma * ev <<
"</sigma>\n";
894 out <<
" <w_a>" << c.
energy.
w_a <<
"</w_a>\n";
895 out <<
" <w_b>" << c.
energy.
w_b <<
"</w_b>\n";
896 out <<
" <l_b>" << c.
energy.
l_b <<
"</l_b>\n";
897 out <<
" <l_c>" << c.
energy.
l_c <<
"</l_c>\n";
898 out <<
" </energy>\n";
899 out <<
" <coupling>\n";
905 out <<
" <quantiles>";
907 out <<
"</quantiles>\n";
909 out <<
" </coupling>\n";
910 out <<
" <U_xX_nN>" << c.
U_xX_nN * ev <<
"</U_xX_nN>\n";
911 out <<
" <U_nX_nN>" << c.
U_nX_nN * ev <<
"</U_nX_nN>\n";
912 out <<
" <U_xN_xX>" << c.
U_xN_xX * ev <<
"</U_xN_xX>\n";
913 out <<
" </carrier>\n";
916 out <<
" <!-- trap: site energies relative to the bulk mean (eV) for the "
917 "carriers in the order of the carrier blocks, deepest site first "
922 out <<
" <density>" << t.
density <<
"</density>\n";
923 out <<
" <releaserate>" << t.
release_rate <<
"</releaserate>\n";
924 for (
const auto& o : t.
offsets) {
931 out <<
"</stochasticnetwork>\n";
void push_back(const T &atom)
Platform independent random numbers for the stochastic models: mt19937_64 with self-written transform...
Index Poisson(double mean)
Poisson distributed count.
Index Integer(Index n)
integer in [0, n)
ModelRandom(std::uint64_t seed, std::uint64_t stream)
independent streams for the same seed (points, energies, pairs)
Periodic orthorhombic cell list for neighbour searches.
std::array< Index, 3 > n_
PeriodicCells(const Eigen::Vector3d &box, double radius, const std::vector< Eigen::Vector3d > &points)
box lengths and the largest search radius used with Within()
std::vector< Index > NearestTo(const Eigen::Vector3d &p, Index l) const
indices of the l points nearest to any position p
Index CellIndex(const Eigen::Vector3d &p, std::array< Index, 3 > &c) const
std::vector< Index > start_
std::vector< Index > members_
void Shell(const std::array< Index, 3 > &c, Index s, F &&f) const
Eigen::Vector3d Connection(const Eigen::Vector3d &r1, const Eigen::Vector3d &r2) const
shortest periodic connection r2 - r1
void Within(const Eigen::Vector3d &p, double radius, const std::function< void(Index, const Eigen::Vector3d &, double)> &f) const
std::vector< Index > Nearest(Index i, Index l) const
const std::vector< Eigen::Vector3d > & points_
QMPair & Add(const Segment &seg1, const Segment &seg2, const Eigen::Vector3d &r)
std::string ToString() const
void setU_xX_nN(double dU, QMStateType state)
UxX - UnN.
void setU_nX_nN(double dU, QMStateType state)
UnX - UnN.
void setEMpoles(QMStateType state, double energy)
void setU_xN_xX(double dU, QMStateType state)
UxN - UxX.
StochasticNetwork(const Options &opt)
static Index SamplePoints(const PointProcess &pp, const Eigen::Vector3d &box, Index sites, ModelRandom &random, std::vector< Eigen::Vector3d > &positions, std::vector< double > &radii)
void BuildTopology(Topology &top) const
fill an empty topology (segments with one pseudo atom, box, pairs)
std::vector< InsertedTrap > inserted_
std::vector< std::vector< double > > energies_
std::vector< Eigen::Vector3d > positions_
void GenerateEnergies(ModelRandom &random)
static std::vector< double > MovingAverage(const PeriodicCells &cells, const EnergyModel &m, Index sites, const std::vector< double > &A, const std::vector< double > &Bf, const std::vector< double > &C)
double Connection(double r) const
connection probability at distance r (bohr)
static double Log10J2(const CouplingModel &m, double r, double g)
log10(J^2/eV^2) for distance r (bohr) and standard normal g
std::vector< Pair > pairs_
static std::string ToXML(const Options &opt)
the parameter file (root element "stochasticnetwork")
void InsertTraps(ModelRandom &random)
std::vector< double > radii_
static double Residual(const CouplingModel &m, double g)
standardized residual for a standard normal g
void GeneratePairs(ModelRandom &random)
Index NumberOfSites() const
static Options FromProperty(const tools::Property &p)
Container for segments and box and atoms.
Segment & AddSegment(std::string segment_name)
void setTime(double time)
void setBox(const Eigen::Matrix3d &box, csg::BoundaryCondition::eBoxtype boxtype=csg::BoundaryCondition::typeAuto)
std::vector< Segment > & Segments()
void Cite(const std::string &key)
marks a reference as used (thread safe; unknown keys are printed as such)
Charge transport classes.
Provides a means for comparing floating point numbers.
std::vector< double > residual_quantiles
double energy_correlation
double coupling_correlation
std::vector< Trap > traps
trap templates, inserted after the Gaussian energies
std::vector< double > connection_r
connection probability table: f at distances r (ascending, bohr)
std::vector< Carrier > carriers
std::vector< double > connection_p
double candidates
candidates per iteration in units of the number of sites
std::vector< std::vector< double > > offsets
offsets[k][c]: site k (deepest first), carrier c, Hartree