1 /*
2 * Copyright 2009-2020 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 // Standard includes
21 #include <cstdio>
22 #include <fstream>
23 #include <iomanip>
24 #include <numeric>
25
26 // Local VOTCA includes
27 #include "votca/xtp/aomatrix.h"
28 #include "votca/xtp/orbitals.h"
29 #include "votca/xtp/orbreorder.h"
30 #include "votca/xtp/qmstate.h"
31 #include "votca/xtp/vc2index.h"
32 #include "votca/xtp/version.h"
33
34 namespace votca {
35 namespace xtp {
36
Orbitals()37 Orbitals::Orbitals() : atoms_("", 0) { ; }
38
39 /**
40 *
41 * @param energy_difference_ [ev] Two levels are degenerate if their energy is
42 * smaller than this value
43 * @return vector with indices off all orbitals degenerate to this including
44 * itself
45 */
CheckDegeneracy(Index level,double energy_difference) const46 std::vector<Index> Orbitals::CheckDegeneracy(Index level,
47 double energy_difference) const {
48
49 std::vector<Index> result;
50 if (level > mos_.eigenvalues().size()) {
51 throw std::runtime_error(
52 "Level for degeneracy is higher than maximum level");
53 }
54 double MOEnergyLevel = mos_.eigenvalues()(level);
55
56 for (Index i = 0; i < mos_.eigenvalues().size(); ++i) {
57 if (std::abs(mos_.eigenvalues()(i) - MOEnergyLevel) < energy_difference) {
58 result.push_back(i);
59 }
60 }
61
62 if (result.empty()) {
63 result.push_back(level);
64 }
65 return result;
66 }
67
SortEnergies()68 std::vector<Index> Orbitals::SortEnergies() {
69 std::vector<Index> index = std::vector<Index>(mos_.eigenvalues().size());
70 std::iota(index.begin(), index.end(), 0);
71 std::stable_sort(index.begin(), index.end(), [this](Index i1, Index i2) {
72 return this->MOs().eigenvalues()[i1] < this->MOs().eigenvalues()[i2];
73 });
74 return index;
75 }
76
77 /*
78 * Returns the density matrix relative to the ground state, for the full density
79 * use DensityMatrixFull
80 */
DensityMatrixWithoutGS(const QMState & state) const81 Eigen::MatrixXd Orbitals::DensityMatrixWithoutGS(const QMState& state) const {
82 if (state.Type().isExciton()) {
83 std::array<Eigen::MatrixXd, 2> DMAT = DensityMatrixExcitedState(state);
84 return DMAT[1] - DMAT[0];
85 } else if (state.Type().isKSState() || state.Type().isPQPState()) {
86 return DensityMatrixKSstate(state);
87 } else if (state.Type() == QMStateType::DQPstate) {
88 Eigen::MatrixXd DMATQP = DensityMatrixQuasiParticle(state);
89 if (state.StateIdx() > getHomo()) {
90 return DMATQP;
91 } else {
92 return -DMATQP;
93 }
94 } else {
95 throw std::runtime_error(
96 "DensityMatrixWithoutGS does not yet implement QMStateType:" +
97 state.Type().ToLongString());
98 }
99 }
100
101 /*
102 * Returns the density matrix with the ground state density, for the partial
103 * density relative to the ground state use DensityMatrixWithoutGS
104 */
DensityMatrixFull(const QMState & state) const105 Eigen::MatrixXd Orbitals::DensityMatrixFull(const QMState& state) const {
106 if (state.isTransition()) {
107 return this->TransitionDensityMatrix(state);
108 }
109 Eigen::MatrixXd result = this->DensityMatrixGroundState();
110 if (state.Type().isExciton()) {
111 std::array<Eigen::MatrixXd, 2> DMAT = DensityMatrixExcitedState(state);
112 result = result - DMAT[0] + DMAT[1]; // Ground state + hole_contribution +
113 // electron contribution
114 } else if (state.Type() == QMStateType::DQPstate) {
115 Eigen::MatrixXd DMATQP = DensityMatrixQuasiParticle(state);
116 if (state.StateIdx() > getHomo()) {
117 result += DMATQP;
118 } else {
119 result -= DMATQP;
120 }
121 } else if (state.Type() != QMStateType::Gstate) {
122 throw std::runtime_error(
123 "DensityMatrixFull does not yet implement QMStateType:" +
124 state.Type().ToLongString());
125 }
126 return result;
127 }
128
129 // Determine ground state density matrix
DensityMatrixGroundState() const130 Eigen::MatrixXd Orbitals::DensityMatrixGroundState() const {
131 if (!hasMOs()) {
132 throw std::runtime_error("Orbitals file does not contain MO coefficients");
133 }
134 Eigen::MatrixXd occstates = mos_.eigenvectors().leftCols(occupied_levels_);
135 Eigen::MatrixXd dmatGS = 2.0 * occstates * occstates.transpose();
136 return dmatGS;
137 }
138
139 // Density matrix for a single KS orbital
DensityMatrixKSstate(const QMState & state) const140 Eigen::MatrixXd Orbitals::DensityMatrixKSstate(const QMState& state) const {
141 if (!hasMOs()) {
142 throw std::runtime_error("Orbitals file does not contain MO coefficients");
143 }
144 if (state.Type() != QMStateType::KSstate &&
145 state.Type() != QMStateType::PQPstate) {
146 throw std::runtime_error("State:" + state.ToString() +
147 " is not a Kohn Sham state");
148 }
149 Eigen::VectorXd KSstate = mos_.eigenvectors().col(state.StateIdx());
150 Eigen::MatrixXd dmatKS = KSstate * KSstate.transpose();
151 return dmatKS;
152 }
153
CalculateQParticleAORepresentation() const154 Eigen::MatrixXd Orbitals::CalculateQParticleAORepresentation() const {
155 if (!hasQPdiag()) {
156 throw std::runtime_error("Orbitals file does not contain QP coefficients");
157 }
158 return mos_.eigenvectors().middleCols(qpmin_, qpmax_ - qpmin_ + 1) *
159 QPdiag_.eigenvectors();
160 }
161
162 // Determine QuasiParticle Density Matrix
DensityMatrixQuasiParticle(const QMState & state) const163 Eigen::MatrixXd Orbitals::DensityMatrixQuasiParticle(
164 const QMState& state) const {
165 if (state.Type() != QMStateType::DQPstate) {
166 throw std::runtime_error("State:" + state.ToString() +
167 " is not a quasiparticle state");
168 }
169 Eigen::MatrixXd lambda = CalculateQParticleAORepresentation();
170 Eigen::MatrixXd dmatQP = lambda.col(state.StateIdx() - qpmin_) *
171 lambda.col(state.StateIdx() - qpmin_).transpose();
172 return dmatQP;
173 }
174
CalcElDipole(const QMState & state) const175 Eigen::Vector3d Orbitals::CalcElDipole(const QMState& state) const {
176 Eigen::Vector3d nuclei_dip = Eigen::Vector3d::Zero();
177 if (!state.isTransition()) {
178 for (const QMAtom& atom : atoms_) {
179 nuclei_dip += (atom.getPos() - atoms_.getPos()) * atom.getNuccharge();
180 }
181 }
182 AOBasis basis = SetupDftBasis();
183 AODipole dipole;
184 dipole.setCenter(atoms_.getPos());
185 dipole.Fill(basis);
186
187 Eigen::MatrixXd dmat = this->DensityMatrixFull(state);
188 Eigen::Vector3d electronic_dip;
189 for (Index i = 0; i < 3; ++i) {
190 electronic_dip(i) = dmat.cwiseProduct(dipole.Matrix()[i]).sum();
191 }
192 return nuclei_dip - electronic_dip;
193 }
194
TransitionDensityMatrix(const QMState & state) const195 Eigen::MatrixXd Orbitals::TransitionDensityMatrix(const QMState& state) const {
196 if (state.Type() != QMStateType::Singlet) {
197 throw std::runtime_error(
198 "Spin type not known for transition density matrix. Available only for "
199 "singlet");
200 }
201 const Eigen::MatrixXd& BSECoefs = BSE_singlet_.eigenvectors();
202 if (BSECoefs.cols() < state.StateIdx() + 1 || BSECoefs.rows() < 2) {
203 throw std::runtime_error("Orbitals object has no information about state:" +
204 state.ToString());
205 }
206
207 // The Transition dipole is sqrt2 bigger because of the spin, the excited
208 // state is a linear combination of 2 slater determinants, where either alpha
209 // or beta spin electron is excited
210
211 /*Trying to implement D_{alpha,beta}=
212 * sqrt2*sum_{i}^{occ}sum_{j}^{virt}{BSEcoef(i,j)*MOcoef(alpha,i)*MOcoef(beta,j)}
213 */
214 // c stands for conduction band and thus virtual orbitals
215 // v stand for valence band and thus occupied orbitals
216
217 Eigen::VectorXd coeffs = BSECoefs.col(state.StateIdx());
218
219 if (!useTDA_) {
220 coeffs += BSE_singlet_.eigenvectors2().col(state.StateIdx());
221 }
222 coeffs *= std::sqrt(2.0);
223 auto occlevels = mos_.eigenvectors().middleCols(bse_vmin_, bse_vtotal_);
224 auto virtlevels = mos_.eigenvectors().middleCols(bse_cmin_, bse_ctotal_);
225 Eigen::Map<const Eigen::MatrixXd> mat(coeffs.data(), bse_ctotal_,
226 bse_vtotal_);
227
228 return occlevels * mat.transpose() * virtlevels.transpose();
229 }
230
DensityMatrixExcitedState(const QMState & state) const231 std::array<Eigen::MatrixXd, 2> Orbitals::DensityMatrixExcitedState(
232 const QMState& state) const {
233 std::array<Eigen::MatrixXd, 2> dmat = DensityMatrixExcitedState_R(state);
234 if (!useTDA_) {
235 std::array<Eigen::MatrixXd, 2> dmat_AR =
236 DensityMatrixExcitedState_AR(state);
237 dmat[0] -= dmat_AR[0];
238 dmat[1] -= dmat_AR[1];
239 }
240 return dmat;
241 }
242
243 // Excited state density matrix
244
DensityMatrixExcitedState_R(const QMState & state) const245 std::array<Eigen::MatrixXd, 2> Orbitals::DensityMatrixExcitedState_R(
246 const QMState& state) const {
247 if (!state.Type().isExciton()) {
248 throw std::runtime_error(
249 "Spin type not known for density matrix. Available are singlet and "
250 "triplet");
251 }
252
253 const Eigen::MatrixXd& BSECoefs = (state.Type() == QMStateType::Singlet)
254 ? BSE_singlet_.eigenvectors()
255 : BSE_triplet_.eigenvectors();
256 if (BSECoefs.cols() < state.StateIdx() + 1 || BSECoefs.rows() < 2) {
257 throw std::runtime_error("Orbitals object has no information about state:" +
258 state.ToString());
259 }
260 /******
261 *
262 * Density matrix for GW-BSE based excitations
263 *
264 * - electron contribution
265 * D_ab = \sum{vc} \sum{c'} A_{vc}A_{vc'} mo_a(c)mo_b(c')
266 *
267 * - hole contribution
268 * D_ab = \sum{vc} \sum{v'} A_{vc}A_{v'c} mo_a(v)mo_b(v')
269 *
270 */
271
272 Eigen::VectorXd coeffs = BSECoefs.col(state.StateIdx());
273
274 std::array<Eigen::MatrixXd, 2> dmatEX;
275 // hole part as matrix products
276 Eigen::MatrixXd occlevels =
277 mos_.eigenvectors().middleCols(bse_vmin_, bse_vtotal_);
278 dmatEX[0] = occlevels * CalcAuxMat_vv(coeffs) * occlevels.transpose();
279
280 // electron part as matrix products
281 Eigen::MatrixXd virtlevels =
282 mos_.eigenvectors().middleCols(bse_cmin_, bse_ctotal_);
283 dmatEX[1] = virtlevels * CalcAuxMat_cc(coeffs) * virtlevels.transpose();
284
285 return dmatEX;
286 }
287
CalcAuxMat_vv(const Eigen::VectorXd & coeffs) const288 Eigen::MatrixXd Orbitals::CalcAuxMat_vv(const Eigen::VectorXd& coeffs) const {
289 const Eigen::Map<const Eigen::MatrixXd> mat(coeffs.data(), bse_ctotal_,
290 bse_vtotal_);
291 return mat.transpose() * mat;
292 }
293
CalcAuxMat_cc(const Eigen::VectorXd & coeffs) const294 Eigen::MatrixXd Orbitals::CalcAuxMat_cc(const Eigen::VectorXd& coeffs) const {
295 const Eigen::Map<const Eigen::MatrixXd> mat(coeffs.data(), bse_ctotal_,
296 bse_vtotal_);
297 return mat * mat.transpose();
298 }
299
DensityMatrixExcitedState_AR(const QMState & state) const300 std::array<Eigen::MatrixXd, 2> Orbitals::DensityMatrixExcitedState_AR(
301 const QMState& state) const {
302
303 if (!state.Type().isExciton()) {
304 throw std::runtime_error(
305 "Spin type not known for density matrix. Available are singlet and "
306 "triplet");
307 }
308
309 const Eigen::MatrixXd& BSECoefs_AR = (state.Type() == QMStateType::Singlet)
310 ? BSE_singlet_.eigenvectors2()
311 : BSE_triplet_.eigenvectors2();
312 if (BSECoefs_AR.cols() < state.StateIdx() + 1 || BSECoefs_AR.rows() < 2) {
313 throw std::runtime_error("Orbitals object has no information about state:" +
314 state.ToString());
315 }
316 /******
317 *
318 * Density matrix for GW-BSE based excitations
319 *
320 * - electron contribution
321 * D_ab = \sum{vc} \sum{v'} B_{vc}B_{v'c} mo_a(v)mo_b(v')
322 *
323 * - hole contribution
324 * D_ab = \sum{vc} \sum{c'} B_{vc}B_{vc'} mo_a(c)mo_b(c')
325 *
326 *
327 * more efficient:
328 *
329 * - electron contribution
330 * D_ab = \sum{v} \sum{v'} mo_a(v)mo_b(v') [ \sum{c} B_{vc}B_{v'c} ]
331 * = \sum{v} \sum{v'} mo_a(v)mo_b(v') B_{vv'}
332 *
333 * - hole contribution
334 * D_ab = \sum{c} \sum{c'} mo_a(c)mo_b(c') [ \sum{v} B_{vc}B_{vc'} ]
335 * = \sum{c} \sum{c'} mo_a(c)mo_b(c') B_{cc'}
336 *
337 */
338
339 Eigen::VectorXd coeffs = BSECoefs_AR.col(state.StateIdx());
340
341 std::array<Eigen::MatrixXd, 2> dmatAR;
342 Eigen::MatrixXd virtlevels =
343 mos_.eigenvectors().middleCols(bse_cmin_, bse_ctotal_);
344 dmatAR[0] = virtlevels * CalcAuxMat_cc(coeffs) * virtlevels.transpose();
345 // electron part as matrix products
346 Eigen::MatrixXd occlevels =
347 mos_.eigenvectors().middleCols(bse_vmin_, bse_vtotal_);
348 dmatAR[1] = occlevels * CalcAuxMat_vv(coeffs) * occlevels.transpose();
349
350 return dmatAR;
351 }
352
Oscillatorstrengths() const353 Eigen::VectorXd Orbitals::Oscillatorstrengths() const {
354
355 Index size = Index(transition_dipoles_.size());
356 if (size > BSE_singlet_.eigenvalues().size()) {
357 size = BSE_singlet_.eigenvalues().size();
358 }
359 Eigen::VectorXd oscs = Eigen::VectorXd::Zero(size);
360 for (Index i = 0; i < size; ++i) {
361 oscs(i) = transition_dipoles_[i].squaredNorm() * 2.0 / 3.0 *
362 (BSE_singlet_.eigenvalues()(i));
363 }
364 return oscs;
365 }
366
getTotalStateEnergy(const QMState & state) const367 double Orbitals::getTotalStateEnergy(const QMState& state) const {
368 double total_energy = getDFTTotalEnergy();
369 if (state.Type() == QMStateType::Gstate) {
370 return total_energy;
371 }
372 total_energy += getExcitedStateEnergy(state);
373 return total_energy;
374 }
375
getExcitedStateEnergy(const QMState & state) const376 double Orbitals::getExcitedStateEnergy(const QMState& state) const {
377
378 double omega = 0.0;
379 if (state.isTransition()) {
380 throw std::runtime_error(
381 "Total Energy does not exist for transition state");
382 }
383
384 if (state.Type() == QMStateType::Singlet) {
385 if (BSE_singlet_.eigenvalues().size() < state.StateIdx() + 1) {
386 throw std::runtime_error("Orbitals::getTotalEnergy You want " +
387 state.ToString() +
388 " which has not been calculated");
389 }
390 omega = BSE_singlet_.eigenvalues()[state.StateIdx()];
391 } else if (state.Type() == QMStateType::Triplet) {
392 if (BSE_triplet_.eigenvalues().size() < state.StateIdx() + 1) {
393 throw std::runtime_error("Orbitals::getTotalEnergy You want " +
394 state.ToString() +
395 " which has not been calculated");
396 }
397 omega = BSE_triplet_.eigenvalues()[state.StateIdx()];
398 } else if (state.Type() == QMStateType::DQPstate) {
399 if (QPdiag_.eigenvalues().size() < state.StateIdx() + 1 - getGWAmin()) {
400 throw std::runtime_error("Orbitals::getTotalEnergy You want " +
401 state.ToString() +
402 " which has not been calculated");
403 }
404 return QPdiag_.eigenvalues()[state.StateIdx() - getGWAmin()];
405 } else if (state.Type() == QMStateType::KSstate) {
406 if (mos_.eigenvalues().size() < state.StateIdx() + 1) {
407 throw std::runtime_error("Orbitals::getTotalEnergy You want " +
408 state.ToString() +
409 " which has not been calculated");
410 }
411 return mos_.eigenvalues()[state.StateIdx()];
412 } else if (state.Type() == QMStateType::PQPstate) {
413 if (this->QPpert_energies_.rows() < state.StateIdx() + 1 - getGWAmin()) {
414 throw std::runtime_error("Orbitals::getTotalEnergy You want " +
415 state.ToString() +
416 " which has not been calculated");
417 }
418 return QPpert_energies_(state.StateIdx() - getGWAmin(), 3);
419 } else {
420 throw std::runtime_error(
421 "GetTotalEnergy only knows states:singlet,triplet,KS,DQP,PQP");
422 }
423 return omega; // e.g. hartree
424 }
425
CalcFreeTransition_Dipoles() const426 std::array<Eigen::MatrixXd, 3> Orbitals::CalcFreeTransition_Dipoles() const {
427 const Eigen::MatrixXd& dft_orbitals = mos_.eigenvectors();
428 AOBasis basis = SetupDftBasis();
429 // Testing electric dipole AOMatrix
430 AODipole dft_dipole;
431 dft_dipole.Fill(basis);
432
433 // now transition dipole elements for free interlevel transitions
434 std::array<Eigen::MatrixXd, 3> interlevel_dipoles;
435
436 Eigen::MatrixXd empty = dft_orbitals.middleCols(bse_cmin_, bse_ctotal_);
437 Eigen::MatrixXd occ = dft_orbitals.middleCols(bse_vmin_, bse_vtotal_);
438 for (Index i = 0; i < 3; i++) {
439 interlevel_dipoles[i] = empty.transpose() * dft_dipole.Matrix()[i] * occ;
440 }
441 return interlevel_dipoles;
442 }
443
CalcCoupledTransition_Dipoles()444 void Orbitals::CalcCoupledTransition_Dipoles() {
445 std::array<Eigen::MatrixXd, 3> interlevel_dipoles =
446 CalcFreeTransition_Dipoles();
447 Index numofstates = BSE_singlet_.eigenvalues().size();
448 transition_dipoles_.resize(0);
449 transition_dipoles_.reserve(numofstates);
450 const double sqrt2 = std::sqrt(2.0);
451 for (Index i_exc = 0; i_exc < numofstates; i_exc++) {
452
453 Eigen::VectorXd coeffs = BSE_singlet_.eigenvectors().col(i_exc);
454 if (!useTDA_) {
455 coeffs += BSE_singlet_.eigenvectors2().col(i_exc);
456 }
457 Eigen::Map<Eigen::MatrixXd> mat(coeffs.data(), bse_ctotal_, bse_vtotal_);
458 Eigen::Vector3d tdipole = Eigen::Vector3d::Zero();
459 for (Index i = 0; i < 3; i++) {
460 tdipole[i] = mat.cwiseProduct(interlevel_dipoles[i]).sum();
461 }
462 // The Transition dipole is sqrt2 bigger because of the spin, the
463 // excited state is a linear combination of 2 slater determinants,
464 // where either alpha or beta spin electron is excited
465 transition_dipoles_.push_back(-sqrt2 * tdipole); //- because electrons are
466 // negatively charged
467 }
468 }
469
OrderMOsbyEnergy()470 void Orbitals::OrderMOsbyEnergy() {
471 std::vector<Index> sort_index = SortEnergies();
472 tools::EigenSystem MO_copy = mos_;
473 Index size = mos_.eigenvalues().size();
474 for (Index i = 0; i < size; ++i) {
475 mos_.eigenvalues()(i) = MO_copy.eigenvalues()(sort_index[i]);
476 }
477 for (Index i = 0; i < size; ++i) {
478 mos_.eigenvectors().col(i) = MO_copy.eigenvectors().col(sort_index[i]);
479 }
480 }
481
482 /**
483 * \brief Guess for a dimer based on monomer orbitals
484 *
485 * Given two monomer orbitals (A and B) constructs a guess for dimer
486 * orbitals: | A 0 | and energies: [EA, EB]
487 * | 0 B |
488 */
PrepareDimerGuess(const Orbitals & orbitalsA,const Orbitals & orbitalsB)489 void Orbitals::PrepareDimerGuess(const Orbitals& orbitalsA,
490 const Orbitals& orbitalsB) {
491
492 // constructing the direct product orbA x orbB
493 Index basisA = orbitalsA.getBasisSetSize();
494 Index basisB = orbitalsB.getBasisSetSize();
495
496 Index electronsA = orbitalsA.getNumberOfAlphaElectrons();
497 Index electronsB = orbitalsB.getNumberOfAlphaElectrons();
498
499 mos_.eigenvectors() = Eigen::MatrixXd::Zero(basisA + basisB, basisA + basisB);
500
501 // AxB = | A 0 | // A = [EA, EB] //
502 // | 0 B | // //
503 if (orbitalsA.getDFTbasisName() != orbitalsB.getDFTbasisName()) {
504 throw std::runtime_error("Basissets of Orbitals A and B differ " +
505 orbitalsA.getDFTbasisName() + ":" +
506 orbitalsB.getDFTbasisName());
507 }
508 this->setDFTbasisName(orbitalsA.getDFTbasisName());
509 if (orbitalsA.getECPName() != orbitalsB.getECPName()) {
510 throw std::runtime_error("ECPs of Orbitals A and B differ " +
511 orbitalsA.getECPName() + ":" +
512 orbitalsB.getECPName());
513 }
514 this->setECPName(orbitalsA.getECPName());
515 this->setBasisSetSize(basisA + basisB);
516 this->setNumberOfOccupiedLevels(electronsA + electronsB);
517 this->setNumberOfAlphaElectrons(electronsA + electronsB);
518
519 mos_.eigenvectors().topLeftCorner(basisA, basisA) =
520 orbitalsA.MOs().eigenvectors();
521 mos_.eigenvectors().bottomRightCorner(basisB, basisB) =
522 orbitalsB.MOs().eigenvectors();
523
524 mos_.eigenvalues().resize(basisA + basisB);
525
526 mos_.eigenvalues().head(basisA) = orbitalsA.MOs().eigenvalues();
527 mos_.eigenvalues().tail(basisB) = orbitalsB.MOs().eigenvalues();
528
529 OrderMOsbyEnergy();
530
531 return;
532 }
533
WriteToCpt(const std::string & filename) const534 void Orbitals::WriteToCpt(const std::string& filename) const {
535 CheckpointFile cpf(filename, CheckpointAccessLevel::CREATE);
536 WriteToCpt(cpf);
537 }
538
WriteToCpt(CheckpointFile f) const539 void Orbitals::WriteToCpt(CheckpointFile f) const {
540 WriteToCpt(f.getWriter("/QMdata"));
541 }
542
WriteToCpt(CheckpointWriter w) const543 void Orbitals::WriteToCpt(CheckpointWriter w) const {
544 w(XtpVersionStr(), "XTPVersion");
545 w(orbitals_version(), "version");
546 w(basis_set_size_, "basis_set_size");
547 w(occupied_levels_, "occupied_levels");
548 w(number_alpha_electrons_, "number_alpha_electrons");
549
550 w(mos_, "mos");
551
552 CheckpointWriter molgroup = w.openChild("qmmolecule");
553 atoms_.WriteToCpt(molgroup);
554
555 w(qm_energy_, "qm_energy");
556 w(qm_package_, "qm_package");
557
558 w(dftbasis_, "dftbasis");
559 w(auxbasis_, "auxbasis");
560
561 w(rpamin_, "rpamin");
562 w(rpamax_, "rpamax");
563 w(qpmin_, "qpmin");
564 w(qpmax_, "qpmax");
565 w(bse_vmin_, "bse_vmin");
566 w(bse_cmax_, "bse_cmax");
567 w(functionalname_, "XCFunctional");
568 w(grid_quality_, "XC_grid_quality");
569 w(ScaHFX_, "ScaHFX");
570
571 w(useTDA_, "useTDA");
572 w(ECP_, "ECP");
573
574 w(rpa_inputenergies_, "RPA_inputenergies");
575 w(QPpert_energies_, "QPpert_energies");
576
577 w(QPdiag_, "QPdiag");
578
579 w(BSE_singlet_, "BSE_singlet");
580
581 w(transition_dipoles_, "transition_dipoles");
582
583 w(BSE_triplet_, "BSE_triplet");
584
585 w(use_Hqp_offdiag_, "use_Hqp_offdiag");
586
587 w(BSE_singlet_energies_dynamic_, "BSE_singlet_dynamic");
588
589 w(BSE_triplet_energies_dynamic_, "BSE_triplet_dynamic");
590 }
591
ReadFromCpt(const std::string & filename)592 void Orbitals::ReadFromCpt(const std::string& filename) {
593 CheckpointFile cpf(filename, CheckpointAccessLevel::READ);
594 ReadFromCpt(cpf);
595 }
596
ReadFromCpt(CheckpointFile f)597 void Orbitals::ReadFromCpt(CheckpointFile f) {
598 ReadFromCpt(f.getReader("/QMdata"));
599 }
600
ReadFromCpt(CheckpointReader r)601 void Orbitals::ReadFromCpt(CheckpointReader r) {
602 r(basis_set_size_, "basis_set_size");
603 r(occupied_levels_, "occupied_levels");
604 r(number_alpha_electrons_, "number_alpha_electrons");
605 int version;
606 r(version, "version");
607 // Read qmatoms
608 CheckpointReader molgroup = r.openChild("qmmolecule");
609 atoms_.ReadFromCpt(molgroup);
610
611 r(qm_energy_, "qm_energy");
612 r(qm_package_, "qm_package");
613
614 r(dftbasis_, "dftbasis");
615 r(auxbasis_, "auxbasis");
616
617 r(version, "version");
618 r(mos_, "mos");
619 if (version < 3) {
620 // clang-format off
621 std::array<Index, 49> votcaOrder_old = {
622 0, // s
623 0, -1, 1, // p
624 0, -1, 1, -2, 2, // d
625 0, -1, 1, -2, 2, -3, 3, // f
626 0, -1, 1, -2, 2, -3, 3, -4, 4, // g
627 0, -1, 1, -2, 2, -3, 3, -4, 4,-5,5, // h
628 0, -1, 1, -2, 2, -3, 3, -4, 4,-5,5,-6,6 // i
629 };
630 // clang-format on
631
632 std::array<Index, 49> multiplier;
633 multiplier.fill(1);
634 OrbReorder ord(votcaOrder_old, multiplier);
635 ord.reorderOrbitals(mos_.eigenvectors(), this->SetupDftBasis());
636 }
637
638 r(rpamin_, "rpamin");
639 r(rpamax_, "rpamax");
640 r(qpmin_, "qpmin");
641 r(qpmax_, "qpmax");
642 r(bse_vmin_, "bse_vmin");
643 r(bse_cmax_, "bse_cmax");
644 setBSEindices(bse_vmin_, bse_cmax_);
645 try {
646 r(functionalname_, "XCFunctional");
647 r(grid_quality_, "XC_grid_quality");
648 } catch (std::runtime_error& e) {
649 grid_quality_ = "medium";
650 }
651 r(ScaHFX_, "ScaHFX");
652 r(useTDA_, "useTDA");
653 r(ECP_, "ECP");
654
655 r(rpa_inputenergies_, "RPA_inputenergies");
656 r(QPpert_energies_, "QPpert_energies");
657 r(QPdiag_, "QPdiag");
658
659 r(BSE_singlet_, "BSE_singlet");
660
661 r(transition_dipoles_, "transition_dipoles");
662
663 r(BSE_triplet_, "BSE_triplet");
664
665 r(use_Hqp_offdiag_, "use_Hqp_offdiag");
666
667 if (version > 1) {
668 r(BSE_singlet_energies_dynamic_, "BSE_singlet_dynamic");
669
670 r(BSE_triplet_energies_dynamic_, "BSE_triplet_dynamic");
671 }
672 }
673 } // namespace xtp
674 } // namespace votca
675