votca 2024.2-dev
Loading...
Searching...
No Matches
kmclifetime.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18// Standard includes
19#include <exception>
20#include <fstream>
21
22// Third party includes
23#include <boost/format.hpp>
24#include <boost/timer/progress_display.hpp>
25
26// VOTCA includes
29
30// Local VOTCA includes
31#include "votca/xtp/eigen.h"
32#include "votca/xtp/gnode.h"
33#include "votca/xtp/qmstate.h"
34#include "votca/xtp/topology.h"
35
36// Local private VOTCA includes
37#include "kmclifetime.h"
38
39namespace votca {
40namespace xtp {
41
43
44 insertions_ = options.get(".numberofinsertions").as<unsigned long>();
45 lifetimefile_ = options.get(".lifetimefile").as<std::string>();
46
47 probfile_ = options.ifExistsReturnElseReturnDefault<std::string>(
48 ".decayprobfile", "");
49
50 const tools::Property& carrier_options = options.get(".carrierenergy");
51 do_carrierenergy_ = carrier_options.get(".run").as<bool>();
52 energy_outputfile_ = carrier_options.get(".outputfile").as<std::string>();
53 alpha_ = carrier_options.get(".alpha").as<double>();
54 outputsteps_ = carrier_options.get(".outputsteps").as<unsigned long>();
55
57 log_.setCommonPreface("\n ...");
58
61 << "carrier type:" << carriertype_.ToLongString() << std::flush;
62 field_ = Eigen::Vector3d::Zero();
63}
64
65void KMCLifetime::WriteDecayProbability(std::string filename) {
66
67 Eigen::VectorXd outrates = Eigen::VectorXd::Zero(nodes_.size());
68 Eigen::VectorXd inrates = Eigen::VectorXd::Zero(nodes_.size());
69 Eigen::VectorXd decayrates = Eigen::VectorXd::Ones(nodes_.size());
70
71 for (unsigned i = 0; i < nodes_.size(); i++) {
72 GNode& node = nodes_[i];
73 if (node.canDecay()) {
74 for (const GLink& event : node.Events()) {
75 if (event.isDecayEvent()) {
76 decayrates[i] = event.getRate();
77 } else {
78 inrates[event.getDestination()->getId()] += event.getRate();
79 outrates[i] += event.getRate();
80 }
81 }
82 }
83 }
84 outrates = decayrates.cwiseQuotient(outrates + decayrates);
85 inrates = decayrates.cwiseQuotient(inrates + decayrates);
86
87 std::fstream probs;
88 probs.open(filename, std::fstream::out);
89 if (!probs.is_open()) {
90 std::string error_msg = "Unable to write to file " + filename;
91 throw std::runtime_error(error_msg);
92 }
93 probs << "#SiteID, Relative Prob outgoing, Relative Prob ingoing\n";
94 for (unsigned i = 0; i < nodes_.size(); i++) {
95 probs << nodes_[i].getId() << " " << outrates[i] << " " << inrates[i]
96 << std::endl;
97 }
98 probs.close();
99 return;
100}
101
102void KMCLifetime::ReadLifetimeFile(std::string filename) {
103 tools::Property xml;
104 xml.LoadFromXML(filename);
105 std::vector<tools::Property*> jobProps = xml.Select("lifetimes.site");
106 if (jobProps.size() != nodes_.size()) {
107 throw std::runtime_error(
108 (boost::format("The number of sites in the topology: %i does not match "
109 "the number in the lifetimefile: %i") %
110 nodes_.size() % jobProps.size())
111 .str());
112 }
113
114 for (tools::Property* prop : jobProps) {
115 Index site_id = prop->getAttribute<Index>("id");
116 double lifetime = boost::lexical_cast<double>(prop->value());
117 bool check = false;
118 for (auto& node : nodes_) {
119 if (node.getId() == site_id && !(node.canDecay())) {
120 node.AddDecayEvent(1.0 / lifetime);
121 check = true;
122 break;
123 } else if (node.getId() == site_id && node.canDecay()) {
124 throw std::runtime_error(
125 (boost::format("Node %i appears twice in your list") % site_id)
126 .str());
127 }
128 }
129 if (!check) {
130 throw std::runtime_error(
131 (boost::format("Site from file with id: %i not found in state file") %
132 site_id)
133 .str());
134 }
135 }
136 for (auto& node : nodes_) {
137 node.InitEscapeRate();
138 node.MakeHuffTree();
139 }
140 return;
141}
142
143void KMCLifetime::WriteToTraj(std::fstream& traj, unsigned long insertioncount,
144 double simtime,
145 const Chargecarrier& affectedcarrier) const {
146 const Eigen::Vector3d& dr_travelled = affectedcarrier.get_dRtravelled();
147 traj << simtime << "\t" << insertioncount << "\t" << affectedcarrier.getId()
148 << "\t" << affectedcarrier.getLifetime() << "\t"
149 << affectedcarrier.getSteps() << "\t"
150 << affectedcarrier.getCurrentNodeId() + 1 << "\t"
151 << dr_travelled.x() * tools::conv::bohr2nm << "\t"
152 << dr_travelled.y() * tools::conv::bohr2nm << "\t"
153 << dr_travelled.z() * tools::conv::bohr2nm << std::endl;
154}
155
157
158 std::chrono::time_point<std::chrono::system_clock> realtime_start =
159 std::chrono::system_clock::now();
161 << "\nAlgorithm: VSSM for Multiple Charges with finite Lifetime\n"
162 "number of charges: "
163 << numberofcarriers_ << "\nnumber of nodes: " << nodes_.size()
164 << std::flush;
165
166 if (numberofcarriers_ > Index(nodes_.size())) {
167 throw std::runtime_error(
168 "ERROR in kmclifetime: specified number of charges is greater than the "
169 "number of nodes. This conflicts with single occupation.");
170 }
171
172 std::fstream traj;
173 std::fstream energyfile;
174
176 << "Writing trajectory to " << trajectoryfile_ << "." << std::flush;
177
178 traj.open(trajectoryfile_, std::fstream::out);
179 if (!traj.is_open()) {
180 std::string error_msg = "Unable to write to file " + trajectoryfile_;
181 throw std::runtime_error(error_msg);
182 }
183
184 traj << "#Simtime [s]\t Insertion\t Carrier ID\t Lifetime[s]\tSteps\t Last "
185 "Segment\t x_travelled[nm]\t y_travelled[nm]\t z_travelled[nm]\n";
186
187 if (do_carrierenergy_) {
188
190 << "Tracking the energy of one charge carrier and exponential average "
191 "with alpha="
192 << alpha_ << " to " << energy_outputfile_ << std::flush;
193 energyfile.open(energy_outputfile_, std::fstream::out);
194 if (!energyfile.is_open()) {
195 std::string error_msg = "Unable to write to file " + energy_outputfile_;
196 throw std::runtime_error(error_msg);
197 }
198
199 energyfile << "Simtime [s]\tSteps\tCarrier ID\tEnergy_a=" << alpha_
200 << "[eV]\n";
201 }
202
203 // Injection
205 << "\ninjection method: " << injectionmethod_ << std::flush;
206
208
209 unsigned long insertioncount = 0;
210 unsigned long step = 0;
211 double simtime = 0.0;
212
213 std::vector<GNode*> forbiddennodes;
214 std::vector<GNode*> forbiddendests;
215
216 time_t now = time(nullptr);
217 tm* localtm = localtime(&now);
219 << "Run started at " << asctime(localtm) << std::flush;
220
221 double avlifetime = 0.0;
222 double meanfreepath = 0.0;
223 Eigen::Vector3d difflength_squared = Eigen::Vector3d::Zero();
224
225 double avgenergy = carriers_[0].getCurrentEnergy();
226 Index carrieridold = carriers_[0].getId();
227
228 while (insertioncount < insertions_) {
229 std::chrono::duration<double> elapsed_time =
230 std::chrono::system_clock::now() - realtime_start;
231 if (elapsed_time.count() > (maxrealtime_ * 60. * 60.)) {
233 << "\nReal time limit of " << maxrealtime_ << " hours ("
234 << Index(maxrealtime_ * 60 * 60 + 0.5)
235 << " seconds) has been reached. Stopping here.\n"
236 << std::flush;
237 break;
238 }
239
240 double cumulated_rate = 0;
241
242 for (const auto& carrier : carriers_) {
243 cumulated_rate += carrier.getCurrentEscapeRate();
244 }
245 if (cumulated_rate == 0) { // this should not happen: no possible jumps
246 // defined for a node
247 throw std::runtime_error(
248 "ERROR in kmclifetime: Incorrect rates in the database file. All the "
249 "escape rates for the current setting are 0.");
250 }
251 // go forward in time
252 double dt = Promotetime(cumulated_rate);
253
254 if (do_carrierenergy_) {
255 bool print = false;
256 if (carriers_[0].getId() > carrieridold) {
257 avgenergy = carriers_[0].getCurrentEnergy();
258 print = true;
259 carrieridold = carriers_[0].getId();
260 } else if (step % outputsteps_ == 0) {
261 avgenergy =
262 alpha_ * carriers_[0].getCurrentEnergy() + (1 - alpha_) * avgenergy;
263 print = true;
264 }
265 if (print) {
266 energyfile << simtime << "\t" << step << "\t" << carriers_[0].getId()
267 << "\t" << avgenergy * tools::conv::hrt2ev << std::endl;
268 }
269 }
270
271 simtime += dt;
272 step++;
273 for (auto& carrier : carriers_) {
274 carrier.updateLifetime(dt);
275 carrier.updateSteps(1);
276 carrier.updateOccupationtime(dt);
277 }
278
279 ResetForbiddenlist(forbiddennodes);
280 bool secondlevel = true;
281 while (secondlevel) {
282
283 // determine which carrier will escape
284 GNode* newnode = nullptr;
285 Chargecarrier* affectedcarrier = ChooseAffectedCarrier(cumulated_rate);
286
287 if (CheckForbidden(affectedcarrier->getCurrentNode(), forbiddennodes)) {
288 continue;
289 }
290
291 // determine where it will jump to
292 ResetForbiddenlist(forbiddendests);
293 boost::timer::progress_display progress(insertions_);
294
295 while (true) {
296 // LEVEL 2
297
298 newnode = nullptr;
299 const GLink& event =
300 ChooseHoppingDest(affectedcarrier->getCurrentNode());
301
302 if (event.isDecayEvent()) {
303 const Eigen::Vector3d& dr_travelled =
304 affectedcarrier->get_dRtravelled();
305 avlifetime += affectedcarrier->getLifetime();
306 meanfreepath += dr_travelled.norm();
307 difflength_squared += dr_travelled.cwiseAbs2();
308 WriteToTraj(traj, insertioncount, simtime, *affectedcarrier);
309 ++progress;
310 RandomlyAssignCarriertoSite(*affectedcarrier);
311 affectedcarrier->resetCarrier();
312 insertioncount++;
313 affectedcarrier->setId(numberofcarriers_ - 1 + insertioncount);
314 secondlevel = false;
315 break;
316 } else {
317 newnode = event.getDestination();
318 }
319
320 // check after the event if this was allowed
321 if (CheckForbidden(*newnode, forbiddendests)) {
322 continue;
323 }
324
325 // if the new segment is unoccupied: jump; if not: add to forbidden list
326 // and choose new hopping destination
327 if (newnode->isOccupied()) {
328 if (CheckSurrounded(affectedcarrier->getCurrentNode(),
329 forbiddendests)) {
330 AddtoForbiddenlist(affectedcarrier->getCurrentNode(),
331 forbiddennodes);
332 break; // select new escape node (ends level 2 but without setting
333 // level1step to 1)
334 }
335 AddtoForbiddenlist(*newnode, forbiddendests);
336 continue; // select new destination
337 } else {
338 affectedcarrier->jumpAccordingEvent(event);
339 secondlevel = false;
340
341 break; // this ends LEVEL 2 , so that the time is updated and the
342 // next MC step started
343 }
344
345 // END LEVEL 2
346 }
347 // END LEVEL 1
348 }
349 }
350
352 << "\nTotal runtime:\t\t\t\t\t" << simtime
353 << " s\n"
354 "Total KMC steps:\t\t\t\t"
355 << step << "\nAverage lifetime:\t\t\t\t"
356 << avlifetime / double(insertioncount) << " s\n"
357 << "Mean freepath\t l=<|r_x-r_o|> :\t\t"
358 << (meanfreepath * tools::conv::bohr2nm / double(insertioncount))
359 << " nm\n"
360 << "Average diffusionlength\t d=sqrt(<(r_x-r_o)^2>)\t"
361 << std::sqrt(difflength_squared.norm() / double(insertioncount)) *
363 << " nm\n"
364 << std::flush;
365
367 traj.close();
368 if (do_carrierenergy_) {
369 energyfile.close();
370 }
371 return;
372}
373
375 XTP_LOG(Log::error, log_) << "\n-----------------------------------"
376 "\n KMCLIFETIME started"
377 "\n-----------------------------------\n"
378 << std::flush;
379
380 XTP_LOG(Log::info, log_) << "\nInitialising random number generator"
381 << std::flush;
382
384 LoadGraph(top);
386
387 if (!probfile_.empty()) {
389 }
390 RunVSSM();
391
392 time_t now = time(nullptr);
393 tm* localtm = localtime(&now);
394
395 XTP_LOG(Log::info, log_) << " KMCLIFETIME finished at:" << asctime(localtm)
396 << std::flush;
397 std::cout << log_;
398 return true;
399}
400
401} // namespace xtp
402} // 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
T ifExistsReturnElseReturnDefault(const std::string &key, T defaultvalue) const
Definition property.h:321
std::vector< Property * > Select(const std::string &filter)
select property based on a filter
Definition property.cc:185
void LoadFromXML(std::string filename)
Definition property.cc:238
void init(Index seed)
Definition random.h:32
Index getCurrentNodeId() const
GNode & getCurrentNode() const
void jumpAccordingEvent(const GLink &event)
const Eigen::Vector3d & get_dRtravelled() const
const std::vector< GLink > & Events() const
Definition gnode.h:47
bool canDecay() const
Definition gnode.h:42
bool isOccupied() const
Definition gnode.h:39
void ResetForbiddenlist(std::vector< GNode * > &forbiddenid) const
void LoadGraph(Topology &top)
std::vector< Chargecarrier > carriers_
double Promotetime(double cumulated_rate)
Chargecarrier * ChooseAffectedCarrier(double cumulated_rate)
const GLink & ChooseHoppingDest(const GNode &node)
void AddtoForbiddenlist(GNode &node, std::vector< GNode * > &forbiddenid) const
void RandomlyAssignCarriertoSite(Chargecarrier &Charge)
bool CheckSurrounded(const GNode &node, const std::vector< GNode * > &forbiddendests) const
tools::Random RandomVariable_
std::vector< GNode > nodes_
void WriteOccupationtoFile(double simtime, std::string filename)
bool CheckForbidden(const GNode &node, const std::vector< GNode * > &forbiddenlist) const
void WriteToTraj(std::fstream &traj, unsigned long insertioncount, double simtime, const Chargecarrier &affectedcarrier) const
void WriteDecayProbability(std::string filename)
void ReadLifetimeFile(std::string filename)
std::string lifetimefile_
Definition kmclifetime.h:53
unsigned long outputsteps_
Definition kmclifetime.h:51
void ParseSpecificOptions(const tools::Property &user_options)
std::string energy_outputfile_
Definition kmclifetime.h:49
unsigned long insertions_
Definition kmclifetime.h:52
bool Evaluate(Topology &top)
void setReportLevel(Log::Level ReportLevel)
Definition logger.h:185
void setCommonPreface(const std::string &preface)
Definition logger.h:198
std::string ToLongString() const
Definition qmstate.cc:69
Container for segments and box and atoms.
Definition topology.h:41
#define XTP_LOG(level, log)
Definition logger.h:40
const double bohr2nm
Definition constants.h:46
const double hrt2ev
Definition constants.h:53
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
static Level current_level
Definition globals.h:30