63 double simtime,
unsigned long step) {
64 double absolute_field =
field_.norm();
66 if (absolute_field == 0) {
68 Eigen::Matrix3d result =
73 <<
" Diffusion tensor averaged over all carriers (nm^2/s):\n"
76 double average_mobility = 0;
77 double bohr2Hrts_to_nm2Vs =
81 Eigen::Vector3d velocity =
carriers_[i].get_dRtravelled() / simtime;
83 velocity.dot(
field_) / (absolute_field * absolute_field);
85 << std::scientific <<
" carrier " << i + 1
86 <<
": mu=" << mobility * bohr2Hrts_to_nm2Vs << std::flush;
88 velocity.dot(
field_) / (absolute_field * absolute_field);
93 <<
" Overall average mobility in field direction <mu>="
94 << average_mobility * bohr2Hrts_to_nm2Vs <<
" nm^2/Vs " << std::flush;
117 unsigned long step)
const {
118 double absolute_field =
field_.norm();
119 double currentenergy = 0;
120 double currentmobility = 0;
121 Eigen::Vector3d dr_travelled_current = Eigen::Vector3d::Zero();
122 double dr_travelled_field = 0.0;
123 Eigen::Vector3d avgvelocity_current = Eigen::Vector3d::Zero();
124 if (absolute_field != 0) {
126 dr_travelled_current += carrier.get_dRtravelled();
127 currentenergy += carrier.getCurrentEnergy();
131 avgvelocity_current = dr_travelled_current / simtime;
133 avgvelocity_current.dot(
field_) / (absolute_field * absolute_field);
134 dr_travelled_field = dr_travelled_current.dot(
field_) / absolute_field;
136 double bohr2Hrts_to_nm2Vs =
138 tfile << simtime <<
"\t" << step <<
"\t"
140 << currentmobility * bohr2Hrts_to_nm2Vs <<
"\t"
147 double simtime,
unsigned long step) {
149 Eigen::Matrix3d result =
153 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> es;
154 es.computeDirect(result);
157 for (
Index i = 0; i < 3; i++) {
159 <<
"Eigenvalue: " << es.eigenvalues()(i) * bohr2_nm2 << std::flush
160 <<
"Eigenvector: " << es.eigenvectors().col(i).x() <<
" "
161 << es.eigenvectors().col(i).y() <<
" " << es.eigenvectors().col(i).z()
165 double bohr2Hrts_to_nm2Vs =
170 <<
"The following value is calculated using the Einstein relation "
171 "and assuming an isotropic medium"
173 double avgD = 1. / 3. * es.eigenvalues().sum();
174 double average_mobility = std::abs(avgD /
temperature_);
176 << std::scientific <<
" Overall average mobility <mu>="
177 << average_mobility * bohr2Hrts_to_nm2Vs <<
" nm^2/Vs " << std::flush;
201 std::chrono::time_point<std::chrono::system_clock> realtime_start =
202 std::chrono::system_clock::now();
204 <<
"\nAlgorithm: VSSM for Multiple Charges" << std::flush;
208 <<
"number of nodes: " <<
nodes_.size() << std::flush;
211 double nexttrajoutput = 0;
212 unsigned long maxsteps = boost::numeric_cast<unsigned long>(
runtime_);
213 unsigned long outputstep = boost::numeric_cast<unsigned long>(
outputtime_);
214 bool stopontime =
false;
218 <<
"stop condition: " << maxsteps <<
" steps." << std::flush;
223 <<
"every " << outputstep <<
" steps." << std::flush;
228 <<
"stop condition: " <<
runtime_ <<
" seconds runtime." << std::flush;
237 <<
"(If you specify runtimes larger than 100 kmcmultiple assumes that "
238 "you are specifying the number of steps for both runtime and "
243 throw std::runtime_error(
244 "ERROR in kmcmultiple: runtime was specified in steps (>100) and "
245 "outputtime in seconds (not an integer). Please use the same units for "
246 "both input parameters.");
250 throw std::runtime_error(
251 "ERROR in kmcmultiple: specified number of carriers is greater than "
253 "number of nodes. This conflicts with single occupation.");
265 traj <<
"time[s]\tsteps\t";
267 traj <<
"carrier" << i + 1 <<
" x_\t";
268 traj <<
"carrier" << i + 1 <<
" y_\t";
269 traj <<
"carrier" << i + 1 <<
" z_";
277 <<
"Writing time dependence of energy and mobility to " <<
timefile_
278 <<
"." << std::flush;
279 tfile.open(
timefile_, std::fstream::out);
280 tfile <<
"time[s]\t "
281 "steps\tenergy_per_carrier[eV]\tmobility[nm**2/"
282 "Vs]\tdistance_fielddirection[nm]\tdistance_absolute[nm]"
288 Eigen::Vector3d::Zero());
290 startposition[i] =
carriers_[i].getCurrentPosition();
306 std::vector<GNode*> forbiddennodes;
307 std::vector<GNode*> forbiddendests;
309 Eigen::Matrix3d avgdiffusiontensor = Eigen::Matrix3d::Zero();
311 double simtime = 0.0;
312 unsigned long step = 0;
314 while (((stopontime && simtime <
runtime_) ||
315 (!stopontime && step < maxsteps))) {
317 std::chrono::duration<double> elapsed_time =
318 std::chrono::system_clock::now() - realtime_start;
319 if (elapsed_time.count() > (
maxrealtime_ * 60. * 60.)) {
321 <<
"\nReal time limit of " <<
maxrealtime_ <<
" hours ("
323 <<
" seconds) has been reached. Stopping here.\n"
328 double cumulated_rate = 0;
330 cumulated_rate += carrier.getCurrentEscapeRate();
332 if (cumulated_rate <= 0) {
334 throw std::runtime_error(
335 "ERROR in kmcmultiple: Incorrect rates. All "
336 "the escape rates for the current setting are 0.");
345 carrier.updateOccupationtime(dt);
349 bool level1step =
true;
353 GNode* newnode =
nullptr;
365 newnode =
event.getDestination();
367 if (newnode ==
nullptr) {
403 avgdiffusiontensor += (carrier.get_dRtravelled()) *
404 (carrier.get_dRtravelled()).transpose();
413 bool outputsteps = (!stopontime && step % outputstep == 0);
414 bool outputtime = (stopontime && simtime > nexttrajoutput);
415 if (outputsteps || outputtime) {
438 << simtime <<
" seconds.\n"
446 << std::scientific <<
" carrier " << i + 1 <<
": "