22#include <boost/filesystem.hpp>
23#include <boost/format.hpp>
49void CanonicalizeOrbitalPhases(Eigen::MatrixXd& coeffs) {
50 constexpr double tol = 1
e-14;
52 for (
Index col = 0; col < coeffs.cols(); ++col) {
53 Eigen::Index pivot = 0;
54 const double maxabs = coeffs.col(col).cwiseAbs().maxCoeff(&pivot);
60 if (coeffs(pivot, col) < 0.0) {
61 coeffs.col(col) *= -1.0;
66void CanonicalizeOrbitalPhases(tools::EigenSystem& mos) {
67 CanonicalizeOrbitalPhases(mos.eigenvectors());
87 const std::string key_xtpdft =
"xtpdft";
90 if (options.
exists(
".auxbasisset")) {
97 options.
get(key_xtpdft +
".fock_matrix_reset").
as<
Index>();
99 if (options.
exists(
".ecp")) {
103 if (options.
exists(key_xtpdft +
".force_uks_path")) {
109 grid_name_ = options.
get(key_xtpdft +
".integration_grid").
as<std::string>();
112 if (options.
exists(key_xtpdft +
".externaldensity")) {
115 options.
get(key_xtpdft +
".externaldensity.orbfile").
as<std::string>();
116 gridquality_ = options.
get(key_xtpdft +
".externaldensity.gridquality")
119 options.
get(key_xtpdft +
".externaldensity.state").
as<std::string>();
122 if (options.
exists(
".externalfield")) {
128 options.
get(key_xtpdft +
".convergence.energy").
as<
double>();
130 options.
get(key_xtpdft +
".convergence.error").
as<
double>();
132 options.
get(key_xtpdft +
".convergence.max_iterations").
as<
Index>();
135 options.
get(key_xtpdft +
".convergence.method").
as<std::string>();
136 if (method ==
"DIIS") {
138 }
else if (method ==
"mixing") {
146 options.
get(key_xtpdft +
".convergence.mixing").
as<
double>();
148 options.
get(key_xtpdft +
".convergence.levelshift").
as<
double>();
150 options.
get(key_xtpdft +
".convergence.levelshift_end").
as<
double>();
152 options.
get(key_xtpdft +
".convergence.DIIS_maxout").
as<
bool>();
154 options.
get(key_xtpdft +
".convergence.DIIS_length").
as<
Index>();
156 options.
get(key_xtpdft +
".convergence.DIIS_start").
as<
double>();
158 options.
get(key_xtpdft +
".convergence.ADIIS_start").
as<
double>();
160 if (options.
exists(key_xtpdft +
".dft_in_dft.activeatoms")) {
162 options.
get(key_xtpdft +
".dft_in_dft.activeatoms").
as<std::string>();
164 options.
get(key_xtpdft +
".dft_in_dft.threshold").
as<
double>();
166 options.
get(key_xtpdft +
".dft_in_dft.levelshift").
as<
double>();
168 options.
get(key_xtpdft +
".dft_in_dft.truncate_basis").
as<
bool>();
171 options.
get(key_xtpdft +
".dft_in_dft.truncation_threshold")
178 XTP_LOG(level, *
pLog_) <<
" Orbital energies: " << std::flush;
179 XTP_LOG(level, *
pLog_) <<
" index occupation energy(Hartree) " << std::flush;
181 for (
Index i = 0; i < MOEnergies.size(); ++i) {
189 XTP_LOG(level, *
pLog_) << (boost::format(
" %1$5d %2$1d %3$+1.10f") %
190 i % occupancy % MOEnergies(i))
198 const Eigen::VectorXd& beta_energies,
200 XTP_LOG(level, *
pLog_) <<
" UKS orbital energies:" << std::flush;
201 XTP_LOG(level, *
pLog_) <<
" index occ eps_a(Ha) eps_b(Ha)"
205 std::max<Index>(alpha_energies.size(), beta_energies.size());
207 for (
Index i = 0; i < nrows; ++i) {
211 std::string occ =
"0";
212 if (occ_a && occ_b) {
220 std::string eps_a =
" -";
221 std::string eps_b =
" -";
223 if (i < alpha_energies.size()) {
224 eps_a = (boost::format(
"%+1.10f") % alpha_energies(i)).str();
226 if (i < beta_energies.size()) {
227 eps_b = (boost::format(
"%+1.10f") % beta_energies(i)).str();
231 " %1$5d %2$1s %3$15s %4$15s") %
232 i % occ % eps_a % eps_b)
240 " alpha HOMO-LUMO gap: %+1.10f Ha") %
249 " beta HOMO-LUMO gap: %+1.10f Ha") %
261 <<
TimeStamp() <<
" Electric Dipole is[e*bohr]:\n\t\t dx=" << result[0]
262 <<
"\n\t\t dy=" << result[1] <<
"\n\t\t dz=" << result[2] << std::flush;
275 const Eigen::MatrixXd& MOCoeff,
const Eigen::MatrixXd& Dmat,
276 double error)
const {
279 return ERIs_.CalculateERIs_EXX_3c(Eigen::MatrixXd::Zero(0, 0), Dmat);
282 return ERIs_.CalculateERIs_EXX_3c(occblock, Dmat);
285 return ERIs_.CalculateERIs_EXX_4c(Dmat, error);
292 double error)
const {
294 return ERIs_.CalculateERIs_3c(Dmat);
296 return ERIs_.CalculateERIs_4c(Dmat, error);
317 <<
TimeStamp() <<
" Filled DFT Vxc matrix " << std::flush;
322 std::array<Eigen::MatrixXd, 2> both =
342 <<
" Forcing closed-shell singlet through UKS development path."
366 <<
TimeStamp() <<
" Reading guess from orbitals object/file"
383 throw std::runtime_error(
"Initial guess method not known/implemented");
389 Eigen::MatrixXd Dmat = spin_dmat.
total();
392 <<
TimeStamp() <<
" Guess Matrix gives N=" << std::setprecision(9)
393 << Dmat.cwiseProduct(
dftAOoverlap_.Matrix()).sum() <<
" electrons."
397 <<
TimeStamp() <<
" STARTING SCF cycle" << std::flush;
399 <<
" ----------------------------------------------"
400 "----------------------------"
403 Eigen::MatrixXd J = Eigen::MatrixXd::Zero(Dmat.rows(), Dmat.cols());
406 K = Eigen::MatrixXd::Zero(Dmat.rows(), Dmat.cols());
409 double start_incremental_F_threshold = 1
e-4;
411 start_incremental_F_threshold = 0.0;
424 <<
TimeStamp() <<
" Filled DFT Vxc matrix " << std::flush;
427 double Eone = Dmat.cwiseProduct(H0.
matrix()).sum();
428 double Etwo = e_vxc.
energy();
436 double integral_error =
444 Etwo += 0.5 * Dmat.cwiseProduct(J).sum();
447 exx = 0.25 *
ScaHFX_ * Dmat.cwiseProduct(K).sum();
449 <<
TimeStamp() <<
" Filled F+K matrix " << std::flush;
453 <<
TimeStamp() <<
" Filled F matrix " << std::flush;
455 Etwo += 0.5 * Dmat.cwiseProduct(J).sum();
459 double totenergy = Eone + H0.
energy() + Etwo;
462 << std::setprecision(12) << Eone << std::flush;
464 << std::setprecision(12) << Etwo << std::flush;
466 <<
TimeStamp() << std::setprecision(12) <<
" Local Exc contribution "
467 << e_vxc.
energy() << std::flush;
471 <<
" Non local Ex contribution " << exx << std::flush;
474 <<
TimeStamp() <<
" Total Energy " << std::setprecision(12) << totenergy
494 <<
TimeStamp() <<
" Total Energy has converged to "
496 <<
"[Ha] after " << this_iter + 1
497 <<
" iterations. DIIS error is converged up to "
500 <<
TimeStamp() <<
" Final Single Point Energy "
501 << std::setprecision(12) << totenergy <<
" Ha" << std::flush;
503 <<
" Final Local Exc contribution "
504 << e_vxc.
energy() <<
" Ha" << std::flush;
507 <<
" Final Non Local Ex contribution "
508 << exx <<
" Ha" << std::flush;
513 Index nuclear_charge = 0;
515 nuclear_charge += atom.getNuccharge();
531 <<
TimeStamp() <<
" DFT calculation has not converged after "
533 <<
" iterations. Use more iterations or another convergence "
534 "acceleration scheme."
577 <<
TimeStamp() <<
" Reading UKS guess from orbitals object/file"
580 MOs_alpha = orb.
MOs();
589 <<
" Orbital file has no beta MOs, using alpha guess for beta."
591 MOs_beta = MOs_alpha;
608 throw std::runtime_error(
"Initial guess method not known/implemented");
621 <<
TimeStamp() <<
" UKS guess gives Nalpha="
628 <<
TimeStamp() <<
" STARTING UKS SCF cycle" << std::flush;
630 <<
" ------------------------------------------------------------"
638 Eigen::MatrixXd H_alpha = H0.
matrix();
639 Eigen::MatrixXd H_beta = H0.
matrix();
643 const Eigen::MatrixXd D_total = Dspin.
total();
645 double E_one = Dspin.
alpha.cwiseProduct(H0.
matrix()).sum() +
652 double integral_error = std::min(conv_uks.
getDIIsError() * 1
e-5, 1
e-5);
655 std::array<Eigen::MatrixXd, 2> both_alpha =
CalcERIs_EXX(
656 Eigen::MatrixXd::Zero(0, 0), Dspin.
alpha, integral_error);
657 std::array<Eigen::MatrixXd, 2> both_beta =
660 Eigen::MatrixXd J = both_alpha[0] + both_beta[0];
661 Eigen::MatrixXd K_alpha = both_alpha[1];
662 Eigen::MatrixXd K_beta = both_beta[1];
664 H_alpha += J +
ScaHFX_ * K_alpha;
665 H_beta += J +
ScaHFX_ * K_beta;
667 E_coul = 0.5 * D_total.cwiseProduct(J).sum();
669 (Dspin.
alpha.cwiseProduct(K_alpha).sum() +
670 Dspin.
beta.cwiseProduct(K_beta).sum());
672 Eigen::MatrixXd J =
CalcERIs(D_total, integral_error);
675 E_coul = 0.5 * D_total.cwiseProduct(J).sum();
680 H_beta += vxc.vxc_beta;
683 double totenergy = H0.
energy() + E_one + E_coul + E_xc + E_exx;
686 << std::setprecision(12) << E_one << std::flush;
688 << std::setprecision(12) << E_coul << std::flush;
690 << std::setprecision(12) << E_xc << std::flush;
693 <<
TimeStamp() <<
" EXX contribution " << std::setprecision(12)
694 << E_exx << std::flush;
697 <<
TimeStamp() <<
" Total Energy " << std::setprecision(12) << totenergy
701 Dspin = conv_uks.
Iterate(Dspin, Hspin, MOs_alpha, MOs_beta, totenergy);
703 MOs_beta = MOs_alpha;
721 Index nuclear_charge = 0;
723 nuclear_charge += atom.getNuccharge();
726 CanonicalizeOrbitalPhases(MOs_alpha);
727 CanonicalizeOrbitalPhases(MOs_beta);
730 orb.
MOs() = MOs_alpha;
741 <<
TimeStamp() <<
" UKS converged after " << this_iter + 1
742 <<
" iterations. Delta E=" << conv_uks.
getDeltaE()
743 <<
" DIIS error=" << conv_uks.
getDIIsError() << std::flush;
746 <<
TimeStamp() <<
" Final Single Point Energy "
747 << std::setprecision(12) << totenergy <<
" Ha" << std::flush;
749 <<
TimeStamp() << std::setprecision(12) <<
" Final XC contribution "
750 << E_xc <<
" Ha" << std::flush;
754 <<
" Final EXX contribution " << E_exx <<
" Ha" << std::flush;
770 <<
TimeStamp() <<
" UKS calculation has not converged after "
771 <<
max_iter_ <<
" iterations." << std::flush;
793 <<
TimeStamp() <<
" Filled DFT Kinetic energy matrix ." << std::flush;
798 <<
TimeStamp() <<
" Filled DFT nuclear potential matrix." << std::flush;
800 Eigen::MatrixXd H0 = dftAOkinetic.
Matrix() + dftAOESP.
Matrix();
802 <<
TimeStamp() <<
" Constructed independent particle hamiltonian "
806 << std::setprecision(9) << E0 << std::flush;
813 <<
TimeStamp() <<
" Filled DFT ECP matrix" << std::flush;
818 <<
" External sites" << std::flush;
819 bool has_quadrupoles = std::any_of(
821 [](
const std::unique_ptr<StaticSite>& s) { return s->getRank() == 2; });
823 " Name Coordinates[a0] charge[e] dipole[e*a0] ";
824 if (has_quadrupoles) {
825 header +=
" quadrupole[e*a0^2]";
831 if (counter == limit) {
835 (boost::format(
" %1$s"
836 " %2$+1.4f %3$+1.4f %4$+1.4f"
838 site->getElement() % site->getPos()[0] % site->getPos()[1] %
839 site->getPos()[2] % site->getCharge())
841 const Eigen::Vector3d& dipole = site->getDipole();
842 output += (boost::format(
" %1$+1.4f %2$+1.4f %3$+1.4f") % dipole[0] %
843 dipole[1] % dipole[2])
845 if (site->getRank() > 1) {
846 Eigen::VectorXd quadrupole = site->Q().tail<5>();
848 (boost::format(
" %1$+1.4f %2$+1.4f %3$+1.4f %4$+1.4f %5$+1.4f") %
849 quadrupole[0] % quadrupole[1] % quadrupole[2] % quadrupole[3] %
856 if (counter == limit) {
859 <<
" sites not displayed)\n"
866 <<
TimeStamp() <<
" Nuclei-external site interaction energy "
867 << std::setprecision(9) << ext_multipoles.
energy() << std::flush;
868 E0 += ext_multipoles.
energy();
869 H0 += ext_multipoles.
matrix();
876 E0 += extdensity_result.
energy();
878 <<
TimeStamp() <<
" Nuclei-external density interaction energy "
879 << std::setprecision(9) << extdensity_result.
energy() << std::flush;
880 H0 += extdensity_result.
matrix();
886 <<
TimeStamp() <<
" Integrating external electric field with F[Hrt]="
900 <<
TimeStamp() <<
" Filled DFT Overlap matrix." << std::flush;
917 <<
TimeStamp() <<
" Inverted AUX Coulomb matrix, removed "
918 <<
ERIs_.Removedfunctions() <<
" functions from aux basis"
922 <<
" Setup invariant parts of Electron Repulsion integrals "
926 <<
TimeStamp() <<
" Calculating 4c diagonals. " << std::flush;
929 <<
TimeStamp() <<
" Calculated 4c diagonals. " << std::flush;
936 const QMAtom& uniqueAtom)
const {
948 dftbasis.
Fill(basisset, atom);
958 ecp.
Fill(ecps, atom);
965 if ((numofelectrons % 2) != 0) {
966 alpha_e = numofelectrons / 2 + numofelectrons % 2;
967 beta_e = numofelectrons / 2;
969 alpha_e = numofelectrons / 2;
979 dftAOoverlap.
Fill(dftbasis);
980 dftAOkinetic.
Fill(dftbasis);
1008 Eigen::MatrixXd H0 = dftAOkinetic.
Matrix() + dftAOESP.
Matrix();
1015 Eigen::MatrixXd dftAOdmat_alpha = Convergence_alpha.
DensityMatrix(MOs_alpha);
1018 return dftAOdmat_alpha;
1022 Eigen::MatrixXd dftAOdmat_beta = Convergence_beta.
DensityMatrix(MOs_beta);
1025 for (
Index this_iter = 0; this_iter < maxiter; this_iter++) {
1026 Eigen::MatrixXd H_alpha = H0;
1027 Eigen::MatrixXd H_beta = H0;
1029 double E_coul = 0.0;
1033 double integral_error = std::min(1
e-5 * 0.5 *
1039 std::array<Eigen::MatrixXd, 2> both_alpha =
1041 std::array<Eigen::MatrixXd, 2> both_beta =
1044 Eigen::MatrixXd Hartree = both_alpha[0] + both_beta[0];
1045 H_alpha += Hartree +
ScaHFX_ * both_alpha[1];
1046 H_beta += Hartree +
ScaHFX_ * both_beta[1];
1049 0.5 * (dftAOdmat_alpha + dftAOdmat_beta).cwiseProduct(Hartree).sum();
1051 (both_alpha[1].cwiseProduct(dftAOdmat_alpha).sum() +
1052 both_beta[1].cwiseProduct(dftAOdmat_beta).sum());
1055 dftAOdmat_alpha + dftAOdmat_beta, integral_error);
1059 0.5 * (dftAOdmat_alpha + dftAOdmat_beta).cwiseProduct(Hartree).sum();
1065 H_beta += vxc.vxc_beta;
1068 double E_one_alpha = dftAOdmat_alpha.cwiseProduct(H0).sum();
1069 double E_one_beta = dftAOdmat_beta.cwiseProduct(H0).sum();
1070 double totenergy = E_one_alpha + E_one_beta + E_coul + E_exx + E_xc;
1072 dftAOdmat_alpha = Convergence_alpha.
Iterate(dftAOdmat_alpha, H_alpha,
1073 MOs_alpha, totenergy);
1075 Convergence_beta.
Iterate(dftAOdmat_beta, H_beta, MOs_beta, totenergy);
1078 <<
TimeStamp() <<
" Iter " << this_iter <<
" of " << maxiter <<
" Etot "
1079 << totenergy <<
" diise_a " << Convergence_alpha.
getDIIsError()
1080 <<
" diise_b " << Convergence_beta.
getDIIsError() <<
"\n\t\t a_gap "
1086 << dftAOoverlap.
Matrix().cwiseProduct(dftAOdmat_alpha).sum()
1087 <<
" Nbeta=" << dftAOoverlap.
Matrix().cwiseProduct(dftAOdmat_beta).sum()
1092 if (converged || this_iter == maxiter - 1) {
1095 <<
TimeStamp() <<
" Converged after " << this_iter + 1
1096 <<
" iterations" << std::flush;
1099 <<
TimeStamp() <<
" Not converged after " << this_iter + 1
1100 <<
" iterations. Unconverged density.\n\t\t\t"
1101 <<
" DIIsError_alpha=" << Convergence_alpha.
getDIIsError()
1102 <<
" DIIsError_beta=" << Convergence_beta.
getDIIsError()
1109 Eigen::MatrixXd avgmatrix =
1113 <<
" gives N=" << std::setprecision(9)
1114 << avgmatrix.cwiseProduct(dftAOoverlap.
Matrix()).sum() <<
" electrons."
1123 <<
TimeStamp() <<
" Scanning molecule of size " << mol.
size()
1124 <<
" for unique elements" << std::flush;
1126 for (
auto element : elements) {
1127 uniqueelements.
push_back(
QMAtom(0, element, Eigen::Vector3d::Zero()));
1131 <<
" unique elements found" << std::flush;
1132 std::vector<Eigen::MatrixXd> uniqueatom_guesses;
1133 for (
QMAtom& unique_atom : uniqueelements) {
1135 <<
TimeStamp() <<
" Calculating atom density for "
1136 << unique_atom.getElement() << std::flush;
1138 uniqueatom_guesses.push_back(dmat_unrestricted);
1141 Eigen::MatrixXd guess =
1144 for (
const QMAtom& atom : mol) {
1146 for (; index < uniqueelements.
size(); index++) {
1147 if (atom.getElement() == uniqueelements[index].getElement()) {
1151 Eigen::MatrixXd& dmat_unrestricted = uniqueatom_guesses[index];
1152 guess.block(start, start, dmat_unrestricted.rows(),
1153 dmat_unrestricted.cols()) = dmat_unrestricted;
1154 start += dmat_unrestricted.rows();
1165 throw std::runtime_error(
1166 (boost::format(
"Basisset Name in guess orb file "
1167 "and in dftengine option file differ %1% vs %2%") %
1175 "Orbital file has no basisset information,"
1176 "using it as a guess might work or not for calculation with "
1201 throw std::runtime_error(
1202 (boost::format(
"ECPs in orb file: %1% and options %2% differ") %
1209 throw std::runtime_error(
1210 (boost::format(
"Number of electrons in guess orb file "
1211 "and in dftengine differ: "
1212 "alpha %1% vs %2%, beta %3% vs %4%.") %
1218 throw std::runtime_error(
1219 (boost::format(
"Number of levels in guess orb file: "
1220 "%1% and in dftengine: %2% differ.") %
1240 <<
TimeStamp() <<
" Using MKL overload for Eigen " << std::flush;
1244 <<
" Using native Eigen implementation, no BLAS overload "
1249 for (
const QMAtom& atom : mol) {
1251 std::string output = (boost::format(
" %1$s"
1252 " %2$+1.4f %3$+1.4f %4$+1.4f") %
1253 atom.getElement() % pos[0] % pos[1] % pos[2])
1264 <<
dftbasis_.AOBasisSize() <<
" functions" << std::flush;
1272 <<
auxbasis_.AOBasisSize() <<
" functions" << std::flush;
1280 std::vector<std::string> results =
ecp_.Fill(ecpbasisset, mol);
1282 <<
TimeStamp() <<
" Filled ECP Basis" << std::flush;
1283 if (results.size() > 0) {
1284 std::string message =
"";
1285 for (
const std::string& element : results) {
1286 message +=
" " + element;
1289 <<
TimeStamp() <<
" Found no ECPs for elements" << message
1300 Index nuclear_charge = 0;
1301 for (
const QMAtom& atom : mol) {
1302 nuclear_charge += atom.getNuccharge();
1308 if (multiplicity < 1) {
1309 throw std::runtime_error(
"Spin multiplicity must be >= 1.");
1312 if (numofelectrons >= 0) {
1318 Index spin_excess = multiplicity - 1;
1321 throw std::runtime_error(
"Computed a negative number of electrons.");
1325 throw std::runtime_error(
1326 "Spin multiplicity incompatible with total number of electrons.");
1330 throw std::runtime_error(
1331 "Charge and spin multiplicity imply non-integer alpha/beta "
1343 <<
" (charge=" << target_charge <<
", multiplicity=" << multiplicity
1369 <<
" divided into " << grid.
getBoxesSize() <<
" boxes" << std::flush;
1374 double E_nucnuc = 0.0;
1376 for (
Index i = 0; i < mol.
size(); i++) {
1377 const Eigen::Vector3d& r1 = mol[i].
getPos();
1378 double charge1 = double(mol[i].getNuccharge());
1379 for (
Index j = 0; j < i; j++) {
1380 const Eigen::Vector3d& r2 = mol[j].
getPos();
1381 double charge2 = double(mol[j].getNuccharge());
1382 E_nucnuc += charge1 * charge2 / (r1 - r2).norm();
1390 const Eigen::MatrixXd& dmat,
const AOBasis& dftbasis)
const {
1391 Eigen::MatrixXd avdmat = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
1392 for (
const AOShell& shellrow : dftbasis) {
1393 Index size_row = shellrow.getNumFunc();
1394 Index start_row = shellrow.getStartIndex();
1395 for (
const AOShell& shellcol : dftbasis) {
1396 Index size_col = shellcol.getNumFunc();
1397 Index start_col = shellcol.getStartIndex();
1398 Eigen::MatrixXd shelldmat =
1399 dmat.block(start_row, start_col, size_row, size_col);
1400 if (shellrow.getL() == shellcol.getL()) {
1401 double diagavg = shelldmat.diagonal().sum() / double(shelldmat.rows());
1402 Index offdiagelements =
1403 shelldmat.rows() * shelldmat.cols() - shelldmat.cols();
1404 double offdiagavg = (shelldmat.sum() - shelldmat.diagonal().sum()) /
1405 double(offdiagelements);
1406 avdmat.block(start_row, start_col, size_row, size_col).array() =
1408 avdmat.block(start_row, start_col, size_row, size_col)
1412 double avg = shelldmat.sum() / double(shelldmat.size());
1413 avdmat.block(start_row, start_col, size_row, size_col).array() = avg;
1422 const std::vector<std::unique_ptr<StaticSite> >& multipoles)
const {
1424 if (multipoles.size() == 0) {
1430 for (
const QMAtom& atom : mol) {
1432 for (
const std::unique_ptr<StaticSite>& site : *
externalsites_) {
1433 if ((site->getPos() - nucleus.
getPos()).norm() < 1
e-7) {
1435 <<
" External site sits on nucleus, "
1436 "interaction between them is ignored."
1451 Eigen::MatrixXd result =
1453 for (
Index i = 0; i < 3; i++) {
1461 const std::vector<std::unique_ptr<StaticSite> >& multipoles)
const {
1468 <<
TimeStamp() <<
" Filled DFT external multipole potential matrix"
1489 <<
TimeStamp() <<
" Calculated external density" << std::flush;
1492 <<
TimeStamp() <<
" Calculated potential from electron density"
1497 double nuc_energy = 0.0;
1498 for (
const QMAtom& atom : mol) {
1502 const double dist = (atom.getPos() - extatom.getPos()).norm();
1504 double(atom.getNuccharge()) * double(extatom.getNuccharge()) / dist;
1508 <<
TimeStamp() <<
" Calculated potential from nuclei" << std::flush;
1510 <<
TimeStamp() <<
" Electrostatic: " << nuc_energy << std::flush;
1515 const Eigen::MatrixXd& GuessMOs)
const {
1516 Eigen::MatrixXd nonortho =
1518 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(nonortho);
1519 Eigen::MatrixXd result = GuessMOs * es.operatorInverseSqrt();
1532 Eigen::VectorXd eps = Eigen::VectorXd::Zero(nao);
1536 int l =
static_cast<int>(shell.getL());
1537 Index start = shell.getStartIndex();
1538 Index nfunc = shell.getNumFunc();
1540 const QMAtom& atom = mol[shell.getAtomIndex()];
1541 const std::string& element = atom.
getElement();
1546 for (
Index i = 0; i < nfunc; ++i) {
1557 const Index nao =
S.rows();
1559 Eigen::MatrixXd
H = Eigen::MatrixXd::Zero(nao, nao);
1560 constexpr double K = 1.75;
1562 for (
Index mu = 0; mu < nao; ++mu) {
1563 H(mu, mu) = eps(mu);
1564 for (
Index nu = 0; nu < mu; ++nu) {
1565 double hij = K *
S(mu, nu) * 0.5 * (eps(mu) + eps(nu));
1577 <<
TimeStamp() <<
" Building Extended Huckel guess" << std::flush;
1582 <<
TimeStamp() <<
" Solving EHT generalized eigenproblem" << std::flush;
1600 std::array<Eigen::MatrixXd, 2> both =
Container to hold Basisfunctions for all atoms.
void Fill(const BasisSet &bs, const QMMolecule &atoms)
void setCenter(const Eigen::Vector3d &r)
const std::array< Eigen::MatrixXd, 3 > & Matrix() const
void Fill(const AOBasis &aobasis) final
void FillPotential(const AOBasis &aobasis, const ECPAOBasis &ecp)
void Fill(const AOBasis &aobasis) final
const Eigen::MatrixXd & Matrix() const
void FillPotential(const AOBasis &aobasis, const QMMolecule &atoms)
void Fill(const AOBasis &aobasis) final
const Eigen::MatrixXd & Matrix() const
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > & Matrix() const
void push_back(const T &atom)
std::vector< std::string > FindUniqueElements() const
const Eigen::Vector3d & getPos() const
void Load(const std::string &name)
Eigen::MatrixXd DensityMatrix(const tools::EigenSystem &MOs) const
void Configure(const ConvergenceAcc::options &opt)
void setLogger(Logger *log)
Attach the logger used for convergence diagnostics.
Eigen::MatrixXd Iterate(const Eigen::MatrixXd &dmat, Eigen::MatrixXd &H, tools::EigenSystem &MOs, double totE)
double getDIIsError() const
Return the DIIS commutator norm from the latest iteration.
tools::EigenSystem SolveFockmatrix(const Eigen::MatrixXd &H) const
Solve the generalized eigenvalue problem for the current Fock matrix.
void setOverlap(AOOverlap &S, double etol)
Precompute overlap-dependent quantities used when solving the Fock matrix.
Eigen::MatrixXd CalcERIs(const Eigen::MatrixXd &Dmat, double error) const
Build the Coulomb matrix contribution from the current density matrix.
std::string auxbasis_name_
Index num_alpha_electrons_
tools::EigenSystem ModelPotentialGuess(const Mat_p_Energy &H0, const QMMolecule &mol, const Vxc_Potential< Vxc_Grid > &vxcpotential) const
Mat_p_Energy IntegrateExternalMultipoles(const QMMolecule &mol, const std::vector< std::unique_ptr< StaticSite > > &multipoles) const
tools::EigenSystem IndependentElectronGuess(const Mat_p_Energy &H0) const
Generate an initial guess by diagonalizing the core Hamiltonian only.
Index num_beta_electrons_
bool EvaluateClosedShell(Orbitals &orb, const Mat_p_Energy &H0, const Vxc_Potential< Vxc_Grid > &vxcpotential)
Run the restricted closed-shell SCF loop and store the converged result.
void PrintMOsUKS(const Eigen::VectorXd &alpha_energies, const Eigen::VectorXd &beta_energies, Log::Level level) const
Print separate alpha and beta orbital energies for a UKS calculation.
std::string dftbasis_name_
bool EvaluateUKS(Orbitals &orb, const Mat_p_Energy &H0, const Vxc_Potential< Vxc_Grid > &vxcpotential)
double truncation_threshold_
Mat_p_Energy IntegrateExternalDensity(const QMMolecule &mol, const Orbitals &extdensity) const
Eigen::MatrixXd RunAtomicDFT_unrestricted(const QMAtom &uniqueAtom) const
void Prepare(Orbitals &orb, Index numofelectrons=-1)
std::string initial_guess_
Eigen::MatrixXd AtomicGuess(const QMMolecule &mol) const
Build an atomic-density based initial guess in the AO basis.
Eigen::MatrixXd BuildEHTHamiltonian(const QMMolecule &mol) const
Build the extended-Hückel Hamiltonian for the current molecule.
Eigen::MatrixXd IntegrateExternalField(const QMMolecule &mol) const
Integrate a homogeneous external electric field into the AO basis.
Eigen::Vector3d extfield_
std::array< Eigen::MatrixXd, 2 > CalcERIs_EXX(const Eigen::MatrixXd &MOCoeff, const Eigen::MatrixXd &Dmat, double error) const
void Initialize(tools::Property &options)
Read DFT, grid, and SCF settings from the user options tree.
std::string xc_functional_name_
void CalcElDipole(const Orbitals &orb) const
Evaluate and print the electronic dipole moment from the final density.
double ExternalRepulsion(const QMMolecule &mol, const std::vector< std::unique_ptr< StaticSite > > &multipoles) const
ConvergenceAcc::options conv_opt_
void SetupInvariantMatrices()
Precompute AO matrices that remain unchanged throughout the SCF procedure.
tools::EigenSystem ExtendedHuckelDFTGuess(const Mat_p_Energy &H0, const QMMolecule &mol, const Vxc_Potential< Vxc_Grid > &vxcpotential) const
std::string active_atoms_as_string_
void ConfigOrbfile(Orbitals &orb)
Propagate basis-set, XC, and metadata settings into the orbital container.
Eigen::VectorXd BuildEHTOrbitalEnergies(const QMMolecule &mol) const
Build orbital energies used in the extended-Hückel starting guess.
bool integrate_ext_density_
void PrintMOs(const Eigen::VectorXd &MOEnergies, Log::Level level)
Print a one-spin list of orbital energies and occupations to the logger.
Mat_p_Energy SetupH0(const QMMolecule &mol) const
Assemble the one-electron core Hamiltonian for the current molecule.
tools::EigenSystem ExtendedHuckelGuess(const QMMolecule &mol) const
Eigen::MatrixXd OrthogonalizeGuess(const Eigen::MatrixXd &GuessMOs) const
Orthonormalize an initial MO guess with respect to the AO overlap matrix.
Eigen::MatrixXd SphericalAverageShells(const Eigen::MatrixXd &dmat, const AOBasis &dftbasis) const
bool Evaluate(Orbitals &orb)
std::vector< std::unique_ptr< StaticSite > > * externalsites_
Vxc_Potential< Vxc_Grid > SetupVxc(const QMMolecule &mol)
bool integrate_ext_field_
double NuclearRepulsion(const QMMolecule &mol) const
Compute the classical nucleus-nucleus repulsion energy.
ConvergenceAcc conv_accelerator_
double IntegratePotential(const Eigen::Vector3d &rvector) const
double IntegrateDensity(const Eigen::MatrixXd &density_matrix)
Container to hold ECPs for all atoms.
std::vector< std::string > Fill(const ECPBasisSet &bs, QMMolecule &atoms)
void Load(const std::string &name)
Takes a density matrix and and an auxiliary basis set and calculates the electron repulsion integrals...
std::array< Eigen::MatrixXd, 2 > CalculateERIs_EXX_4c(const Eigen::MatrixXd &DMAT, double error) const
void Initialize_4c(const AOBasis &dftbasis)
Eigen::MatrixXd CalculateERIs_4c(const Eigen::MatrixXd &DMAT, double error) const
double GetWithFallback(const std::string &element, int l, int *used_l=nullptr) const
void UpdateDmats(const Eigen::MatrixXd &dmat, double DiisError, Index Iteration)
void Configure(const Eigen::MatrixXd &dmat)
void resetMatrices(Eigen::MatrixXd &J, Eigen::MatrixXd &K, const Eigen::MatrixXd &dmat)
void Start(Index iteration, double DiisError)
void UpdateCriteria(double DiisError, Index Iteration)
const Eigen::MatrixXd & getDmat_diff() const
Logger is used for thread-safe output of messages.
Eigen::MatrixXd & matrix()
Container for molecular orbitals and derived one-particle data.
void setScaHFX(double ScaHFX)
Store the fraction of exact exchange associated with the functional.
Index getCharge() const
Return the stored total charge.
Index getSpin() const
Return the stored spin multiplicity.
const tools::EigenSystem & MOs_beta() const
Return read-only access to beta-spin molecular orbitals.
Index getNumberOfAlphaElectrons() const
Return the stored number of alpha electrons.
void setNumberOfAlphaElectrons(Index electrons)
Store the total number of alpha electrons.
Eigen::MatrixXd DensityMatrixFull(const QMState &state) const
void SetupAuxBasis(std::string aux_basis_name)
void setNumberOfBetaElectrons(Index electrons)
Store the total number of beta electrons.
void setECPName(const std::string &ECP)
Store the effective core potential label.
void setXCGrid(std::string grid)
Store the numerical XC grid quality label.
void setNumberOfOccupiedLevels(Index occupied_levels)
Index getBasisSetSize() const
Return the number of AO basis functions in the DFT basis.
void setQMEnergy(double qmenergy)
Store the total DFT energy.
bool hasECPName() const
Report whether an effective core potential label has been stored.
const tools::EigenSystem & MOs() const
Return read-only access to alpha/restricted molecular orbitals.
const QMMolecule & QMAtoms() const
Return read-only access to the molecular geometry.
void ReadFromCpt(const std::string &filename)
Read the orbital container from a checkpoint file on disk.
void setNumberOfOccupiedLevelsBeta(Index occupied_levels_beta)
Store the number of occupied beta-spin orbitals.
void setChargeAndSpin(Index charge, Index spin)
bool hasDFTbasisName() const
Report whether a DFT basis-set name has been stored.
const std::string & getECPName() const
Return the effective core potential label.
const std::string & getDFTbasisName() const
Return the DFT basis-set name.
bool hasBetaMOs() const
Report whether beta-spin molecular orbitals are available.
void SetupDftBasis(std::string basis_name)
Build and attach the DFT AO basis from the stored molecular geometry.
Eigen::Vector3d CalcElDipole(const QMState &state) const
Compute the electronic dipole moment associated with a state density.
Index getNumberOfBetaElectrons() const
Return the stored number of beta electrons.
const AOBasis & getDftBasis() const
Return the DFT AO basis, throwing if it has not been initialized.
void setXCFunctionalName(std::string functionalname)
const std::string & getElement() const
Index getNuccharge() const
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
Class to represent Atom/Site in electrostatic.
const Eigen::Vector3d & getPos() const
Timestamp returns the current time as a string Example: cout << TimeStamp()
SpinDensity DensityMatrix(const tools::EigenSystem &MOs_alpha, const tools::EigenSystem &MOs_beta) const
void setOverlap(AOOverlap &S, double etol)
void setLogger(Logger *log)
void Configure(const options &opt_alpha, const options &opt_beta)
SpinDensity Iterate(const SpinDensity &dmat, SpinFock &H, tools::EigenSystem &MOs_alpha, tools::EigenSystem &MOs_beta, double totE)
double getDIIsError() const
Index getGridSize() const
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Index getBoxesSize() const
Mat_p_Energy IntegrateVXC(const Eigen::MatrixXd &density_matrix) const
void setXCfunctional(const std::string &functional)
static double getExactExchange(const std::string &functional)
SpinResult IntegrateVXCSpin(const Eigen::MatrixXd &dmat_alpha, const Eigen::MatrixXd &dmat_beta) const
Mediates interaction between polar and static sites.
double CalcStaticEnergy_site(const StaticSite &site1, const StaticSite &site2) const
#define XTP_LOG(level, log)
Charge transport classes.
bool XTP_HAS_MKL_OVERLOAD()
Provides a means for comparing floating point numbers.
Spin-resolved density matrices returned for open-shell SCF updates.
Eigen::MatrixXd total() const
Return the total density P = P^alpha + P^beta.
Eigen::MatrixXd total() const
Eigen::MatrixXd vxc_alpha