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 // Local private VOTCA includes
19 #include "eanalyze.h"
20 #include "votca/xtp/qmstate.h"
21
22 namespace votca {
23 namespace xtp {
24
ParseOptions(const tools::Property & options)25 void EAnalyze::ParseOptions(const tools::Property &options) {
26
27 resolution_pairs_ = options.get(".resolution_pairs").as<double>();
28 resolution_sites_ = options.get(".resolution_sites").as<double>();
29 resolution_spatial_ = options.get(".resolution_spatial").as<double>();
30 seg_pattern_ = options.get(".match_pattern").as<std::string>();
31
32 states_ = options.get(".states").as<std::vector<QMStateType>>();
33
34 doenergy_landscape_ = options.get(".output_energy_landscape").as<bool>();
35
36 if (options.exists(".distancemode")) {
37 std::string distancemode = options.get("distancemode").as<std::string>();
38 if (distancemode == "centerofmass") {
39 atomdistances_ = false;
40 } else {
41 atomdistances_ = true;
42 }
43 }
44 }
45
Evaluate(Topology & top)46 bool EAnalyze::Evaluate(Topology &top) {
47
48 // Short-list segments according to pattern
49 for (Segment &seg : top.Segments()) {
50 std::string seg_name = seg.getType();
51 if (votca::tools::wildcmp(seg_pattern_, seg_name)) {
52 seg_shortlist_.push_back(&seg);
53 }
54 }
55 std::cout << std::endl
56 << "... ... Short-listed " << seg_shortlist_.size()
57 << " segments (pattern='" << seg_pattern_ << "')" << std::flush;
58 std::cout
59 << std::endl
60 << "... ... ... NOTE Statistics of site energies and spatial"
61 << " correlations thereof are based on the short-listed segments only. "
62 << std::flush;
63 std::cout << std::endl
64 << "... ... ... "
65 << "Statistics of site-energy differences operate on the full list."
66 << std::flush;
67
68 // Calculate
69 // ... Site-energy histogram, mean, width
70 // ... Pair-energy histogram, mean, width
71 // ... Site-energy correlation
72
73 const QMNBList &nblist = top.NBList();
74
75 for (QMStateType state : states_) {
76 std::cout << std::endl
77 << "... ... excited state " << state.ToString() << std::flush;
78
79 if (!seg_shortlist_.size()) {
80 std::cout << std::endl
81 << "... ... ... No segments short-listed. Skip ... "
82 << std::flush;
83 } else {
84 SiteHist(state);
85 SiteCorr(top, state);
86 }
87
88 if (!nblist.size()) {
89 std::cout << std::endl
90 << "... ... ... No pairs in topology. Skip ... " << std::flush;
91 } else {
92 PairHist(top, state);
93 }
94 }
95 std::cout << std::endl;
96 return true;
97 }
98
SiteHist(QMStateType state) const99 void EAnalyze::SiteHist(QMStateType state) const {
100
101 std::vector<double> Es;
102 Es.reserve(seg_shortlist_.size());
103 for (Segment *seg : seg_shortlist_) {
104 Es.push_back(seg->getSiteEnergy(state) * tools::conv::hrt2ev);
105 }
106
107 double MAX = *std::max_element(Es.begin(), Es.end());
108 double MIN = *std::min_element(Es.begin(), Es.end());
109 double sum = std::accumulate(Es.begin(), Es.end(), 0.0);
110 double AVG = sum / double(Es.size());
111 double sq_sum = std::inner_product(Es.begin(), Es.end(), Es.begin(), 0.0);
112 double STD = std::sqrt(sq_sum / double(Es.size()) - AVG * AVG);
113
114 // Prepare bins
115 Index BIN = Index((MAX - MIN) / resolution_sites_ + 0.5) + 1;
116
117 tools::HistogramNew hist;
118 hist.Initialize(MIN, MAX, BIN);
119 hist.ProcessRange<std::vector<double>::iterator>(Es.begin(), Es.end());
120 tools::Table &tab = hist.data();
121 tab.flags() = std::vector<char>(tab.size(), ' ');
122 std::string comment =
123 (boost::format("EANALYZE: SITE-ENERGY HISTOGRAM[eV] \n # AVG %1$4.7f STD "
124 "%2$4.7f MIN %3$4.7f MAX %4$4.7f") %
125 AVG % STD % MIN % MAX)
126 .str();
127 std::string filename = "eanalyze.sitehist_" + state.ToString() + ".out";
128 tab.set_comment(comment);
129 tab.Save(filename);
130
131 // Write "seg x y z energy" with atomic {x,y,z}
132 if (doenergy_landscape_) {
133 std::string filename2 = "eanalyze.landscape_" + state.ToString() + ".out";
134 std::ofstream out;
135 out.open(filename2);
136 if (!out) {
137 throw std::runtime_error("error, cannot open file " + filename2);
138 }
139 for (Segment *seg : seg_shortlist_) {
140 if (seg->getId() < first_seg_) {
141 continue;
142 }
143 if (seg->getId() == last_seg_) {
144 break;
145 }
146 double E = seg->getSiteEnergy(state);
147 for (Atom &atm : *seg) {
148 out << boost::format("%1$3s %2$4.7f %3$4.7f %4$4.7f %5$4.7f\n") %
149 seg->getType() % atm.getPos().x() % atm.getPos().y() %
150 atm.getPos().z() % E;
151 }
152 }
153 out.close();
154 }
155 }
156
PairHist(const Topology & top,QMStateType state) const157 void EAnalyze::PairHist(const Topology &top, QMStateType state) const {
158
159 const QMNBList &nblist = top.NBList();
160
161 std::string filenamelist = "eanalyze.pairlist_" + state.ToString() + ".out";
162
163 // Collect site-energy differences from neighbourlist
164 std::vector<double> dE;
165 dE.reserve(2 * nblist.size());
166 std::ofstream out;
167 out.open(filenamelist);
168 if (!out) {
169 throw std::runtime_error("error, cannot open file " + filenamelist);
170 }
171 for (QMPair *pair : nblist) {
172 double deltaE = pair->getdE12(state) * tools::conv::hrt2ev;
173 dE.push_back(deltaE);
174 dE.push_back(-deltaE);
175 out << boost::format("%1$5d %2$5d %3$4.7f \n") % pair->Seg1()->getId() %
176 pair->Seg2()->getId() % deltaE;
177 }
178 out.close();
179
180 double MAX = *std::max_element(dE.begin(), dE.end());
181 double MIN = *std::min_element(dE.begin(), dE.end());
182 double sum = std::accumulate(dE.begin(), dE.end(), 0.0);
183 double AVG = sum / double(dE.size());
184 double sq_sum = std::inner_product(dE.begin(), dE.end(), dE.begin(), 0.0);
185 double STD = std::sqrt(sq_sum / double(dE.size()) - AVG * AVG);
186 Index BIN = Index((MAX - MIN) / resolution_pairs_ + 0.5) + 1;
187
188 std::string filename2 = "eanalyze.pairhist_" + state.ToString() + ".out";
189 tools::HistogramNew hist;
190 hist.Initialize(MIN, MAX, BIN);
191 hist.ProcessRange<std::vector<double>::iterator>(dE.begin(), dE.end());
192 tools::Table &tab = hist.data();
193 std::string comment =
194 (boost::format("EANALYZE: PAIR-ENERGY HISTOGRAM[eV] \n # AVG %1$4.7f STD "
195 "%2$4.7f MIN %3$4.7f MAX %4$4.7f") %
196 AVG % STD % MIN % MAX)
197 .str();
198 tab.set_comment(comment);
199 tab.flags() = std::vector<char>(tab.size(), ' ');
200 tab.Save(filename2);
201 }
202
SiteCorr(const Topology & top,QMStateType state) const203 void EAnalyze::SiteCorr(const Topology &top, QMStateType state) const {
204
205 std::vector<double> Es;
206 Es.reserve(seg_shortlist_.size());
207 for (Segment *seg : seg_shortlist_) {
208 Es.push_back(seg->getSiteEnergy(state) * tools::conv::hrt2ev);
209 }
210
211 double sum = std::accumulate(Es.begin(), Es.end(), 0.0);
212 double AVG = sum / double(Es.size());
213 double sq_sum = std::inner_product(Es.begin(), Es.end(), Es.begin(), 0.0);
214 double VAR = sq_sum / double(Es.size()) - AVG * AVG;
215 double STD = std::sqrt(VAR);
216
217 // Collect inter-site distances, correlation product
218 tools::Table tabcorr;
219 Index length =
220 Index(seg_shortlist_.size()) * Index(seg_shortlist_.size() - 1) / 2;
221 tabcorr.resize(length);
222 Index index = 0;
223 for (Index i = 0; i < Index(seg_shortlist_.size()); i++) {
224 const Segment &segi = *seg_shortlist_[i];
225 for (Index j = i + 1; j < Index(seg_shortlist_.size()); j++) {
226 const Segment &segj = *seg_shortlist_[j];
227 double R = 0;
228 if (atomdistances_) {
229 R = top.GetShortestDist(segi, segj);
230 } else {
231 R = (top.PbShortestConnect(segi.getPos(), segj.getPos())).norm();
232 }
233
234 double C =
235 (segi.getSiteEnergy(state) - AVG) * (segj.getSiteEnergy(state) - AVG);
236 tabcorr.set(index, R * tools::conv::bohr2nm, C);
237 index++;
238 }
239 }
240
241 double MIN = tabcorr.x().minCoeff();
242 double MAX = tabcorr.x().maxCoeff();
243
244 // Prepare bins
245 Index BIN = Index((MAX - MIN) / resolution_spatial_ + 0.5) + 1;
246 std::vector<std::vector<double>> histCs;
247 histCs.resize(BIN);
248
249 for (Index i = 0; i < tabcorr.size(); ++i) {
250 Index bin = Index((tabcorr.x()[i] - MIN) / resolution_spatial_ + 0.5);
251 histCs[bin].push_back(tabcorr.y()[i]);
252 }
253
254 tools::Table histC;
255 histC.SetHasYErr(true);
256 // Calculate spatial correlation
257 histC.resize(BIN);
258 for (Index bin = 0; bin < BIN; ++bin) {
259 double corr = 0.0;
260 double dcorr2 = 0.0;
261 for (double entry : histCs[bin]) {
262 corr += entry / VAR;
263 }
264 corr = corr / double(histCs[bin].size());
265 for (Index i = 0; i < Index(histCs[bin].size()); ++i) {
266 dcorr2 += (histCs[bin][i] / VAR / double(histCs[bin].size()) - corr) *
267 (histCs[bin][i] / VAR / double(histCs[bin].size()) - corr);
268 }
269 // error on mean value
270 dcorr2 =
271 dcorr2 / double(histCs[bin].size()) / double(histCs[bin].size() - 1);
272 double R = MIN + double(bin) * resolution_spatial_;
273 histC.set(bin, R, corr, ' ', std::sqrt(dcorr2));
274 }
275
276 std::string filename = "eanalyze.sitecorr_" + state.ToString() + ".out";
277 std::string comment =
278 (boost::format("EANALYZE: DISTANCE[nm] SPATIAL SITE-ENERGY "
279 "CORRELATION[eV] \n # AVG "
280 "%1$4.7f STD %2$4.7f MIN %3$4.7f MAX %4$4.7f") %
281 AVG % STD % MIN % MAX)
282 .str();
283 histC.set_comment(comment);
284 histC.Save(filename);
285 }
286
287 } // namespace xtp
288 } // namespace votca
289