22#include <boost/filesystem.hpp>
23#include <boost/format.hpp>
62 const std::string key_xtpdft =
"xtpdft";
65 if (options.
exists(
".auxbasisset")) {
72 options.
get(key_xtpdft +
".fock_matrix_reset").
as<
Index>();
74 if (options.
exists(
".ecp")) {
80 grid_name_ = options.
get(key_xtpdft +
".integration_grid").
as<std::string>();
83 if (options.
exists(key_xtpdft +
".externaldensity")) {
86 options.
get(key_xtpdft +
".externaldensity.orbfile").
as<std::string>();
90 options.
get(key_xtpdft +
".externaldensity.state").
as<std::string>();
93 if (options.
exists(
".externalfield")) {
99 options.
get(key_xtpdft +
".convergence.energy").
as<
double>();
101 options.
get(key_xtpdft +
".convergence.error").
as<
double>();
103 options.
get(key_xtpdft +
".convergence.max_iterations").
as<
Index>();
106 options.
get(key_xtpdft +
".convergence.method").
as<std::string>();
107 if (method ==
"DIIS") {
109 }
else if (method ==
"mixing") {
117 options.
get(key_xtpdft +
".convergence.mixing").
as<
double>();
119 options.
get(key_xtpdft +
".convergence.levelshift").
as<
double>();
121 options.
get(key_xtpdft +
".convergence.levelshift_end").
as<
double>();
123 options.
get(key_xtpdft +
".convergence.DIIS_maxout").
as<
bool>();
125 options.
get(key_xtpdft +
".convergence.DIIS_length").
as<
Index>();
127 options.
get(key_xtpdft +
".convergence.DIIS_start").
as<
double>();
129 options.
get(key_xtpdft +
".convergence.ADIIS_start").
as<
double>();
131 if (options.
exists(key_xtpdft +
".dft_in_dft.activeatoms")) {
133 options.
get(key_xtpdft +
".dft_in_dft.activeatoms").
as<std::string>();
135 options.
get(key_xtpdft +
".dft_in_dft.threshold").
as<
double>();
137 options.
get(key_xtpdft +
".dft_in_dft.levelshift").
as<
double>();
139 options.
get(key_xtpdft +
".dft_in_dft.truncate_basis").
as<
bool>();
142 options.
get(key_xtpdft +
".dft_in_dft.truncation_threshold")
149 XTP_LOG(level, *
pLog_) <<
" Orbital energies: " << std::flush;
150 XTP_LOG(level, *
pLog_) <<
" index occupation energy(Hartree) " << std::flush;
152 for (
Index i = 0; i < MOEnergies.size(); ++i) {
160 XTP_LOG(level, *
pLog_) << (boost::format(
" %1$5d %2$1d %3$+1.10f") %
161 i % occupancy % MOEnergies(i))
169 const Eigen::VectorXd& beta_energies,
171 XTP_LOG(level, *
pLog_) <<
" UKS orbital energies:" << std::flush;
172 XTP_LOG(level, *
pLog_) <<
" index occ eps_a(Ha) eps_b(Ha)"
176 std::max<Index>(alpha_energies.size(), beta_energies.size());
178 for (
Index i = 0; i < nrows; ++i) {
182 std::string occ =
"0";
183 if (occ_a && occ_b) {
191 std::string eps_a =
" -";
192 std::string eps_b =
" -";
194 if (i < alpha_energies.size()) {
195 eps_a = (boost::format(
"%+1.10f") % alpha_energies(i)).str();
197 if (i < beta_energies.size()) {
198 eps_b = (boost::format(
"%+1.10f") % beta_energies(i)).str();
202 " %1$5d %2$1s %3$15s %4$15s") %
203 i % occ % eps_a % eps_b)
211 " alpha HOMO-LUMO gap: %+1.10f Ha") %
220 " beta HOMO-LUMO gap: %+1.10f Ha") %
232 <<
TimeStamp() <<
" Electric Dipole is[e*bohr]:\n\t\t dx=" << result[0]
233 <<
"\n\t\t dy=" << result[1] <<
"\n\t\t dz=" << result[2] << std::flush;
246 const Eigen::MatrixXd& MOCoeff,
const Eigen::MatrixXd& Dmat,
247 double error)
const {
250 return ERIs_.CalculateERIs_EXX_3c(Eigen::MatrixXd::Zero(0, 0), Dmat);
253 return ERIs_.CalculateERIs_EXX_3c(occblock, Dmat);
256 return ERIs_.CalculateERIs_EXX_4c(Dmat, error);
263 double error)
const {
265 return ERIs_.CalculateERIs_3c(Dmat);
267 return ERIs_.CalculateERIs_4c(Dmat, error);
288 <<
TimeStamp() <<
" Filled DFT Vxc matrix " << std::flush;
293 std::array<Eigen::MatrixXd, 2> both =
331 <<
TimeStamp() <<
" Reading guess from orbitals object/file"
348 throw std::runtime_error(
"Initial guess method not known/implemented");
354 Eigen::MatrixXd Dmat = spin_dmat.
total();
357 <<
TimeStamp() <<
" Guess Matrix gives N=" << std::setprecision(9)
358 << Dmat.cwiseProduct(
dftAOoverlap_.Matrix()).sum() <<
" electrons."
362 <<
TimeStamp() <<
" STARTING SCF cycle" << std::flush;
364 <<
" ----------------------------------------------"
365 "----------------------------"
368 Eigen::MatrixXd J = Eigen::MatrixXd::Zero(Dmat.rows(), Dmat.cols());
371 K = Eigen::MatrixXd::Zero(Dmat.rows(), Dmat.cols());
374 double start_incremental_F_threshold = 1
e-4;
376 start_incremental_F_threshold = 0.0;
389 <<
TimeStamp() <<
" Filled DFT Vxc matrix " << std::flush;
392 double Eone = Dmat.cwiseProduct(H0.
matrix()).sum();
393 double Etwo = e_vxc.
energy();
401 double integral_error =
409 Etwo += 0.5 * Dmat.cwiseProduct(J).sum();
412 exx = 0.25 *
ScaHFX_ * Dmat.cwiseProduct(K).sum();
414 <<
TimeStamp() <<
" Filled F+K matrix " << std::flush;
418 <<
TimeStamp() <<
" Filled F matrix " << std::flush;
420 Etwo += 0.5 * Dmat.cwiseProduct(J).sum();
424 double totenergy = Eone + H0.
energy() + Etwo;
427 << std::setprecision(12) << Eone << std::flush;
429 << std::setprecision(12) << Etwo << std::flush;
431 <<
TimeStamp() << std::setprecision(12) <<
" Local Exc contribution "
432 << e_vxc.
energy() << std::flush;
436 <<
" Non local Ex contribution " << exx << std::flush;
439 <<
TimeStamp() <<
" Total Energy " << std::setprecision(12) << totenergy
459 <<
TimeStamp() <<
" Total Energy has converged to "
461 <<
"[Ha] after " << this_iter + 1
462 <<
" iterations. DIIS error is converged up to "
465 <<
TimeStamp() <<
" Final Single Point Energy "
466 << std::setprecision(12) << totenergy <<
" Ha" << std::flush;
468 <<
" Final Local Exc contribution "
469 << e_vxc.
energy() <<
" Ha" << std::flush;
472 <<
" Final Non Local Ex contribution "
473 << exx <<
" Ha" << std::flush;
478 Index nuclear_charge = 0;
480 nuclear_charge += atom.getNuccharge();
496 <<
TimeStamp() <<
" DFT calculation has not converged after "
498 <<
" iterations. Use more iterations or another convergence "
499 "acceleration scheme."
542 <<
TimeStamp() <<
" Reading UKS guess from orbitals object/file"
545 MOs_alpha = orb.
MOs();
554 <<
" Orbital file has no beta MOs, using alpha guess for beta."
556 MOs_beta = MOs_alpha;
573 throw std::runtime_error(
"Initial guess method not known/implemented");
586 <<
TimeStamp() <<
" UKS guess gives Nalpha="
593 <<
TimeStamp() <<
" STARTING UKS SCF cycle" << std::flush;
595 <<
" ------------------------------------------------------------"
603 Eigen::MatrixXd H_alpha = H0.
matrix();
604 Eigen::MatrixXd H_beta = H0.
matrix();
608 const Eigen::MatrixXd D_total = Dspin.
total();
610 double E_one = Dspin.
alpha.cwiseProduct(H0.
matrix()).sum() +
617 double integral_error = std::min(conv_uks.
getDIIsError() * 1
e-5, 1
e-5);
620 std::array<Eigen::MatrixXd, 2> both_alpha =
CalcERIs_EXX(
621 Eigen::MatrixXd::Zero(0, 0), Dspin.
alpha, integral_error);
622 std::array<Eigen::MatrixXd, 2> both_beta =
625 Eigen::MatrixXd J = both_alpha[0] + both_beta[0];
626 Eigen::MatrixXd K_alpha = both_alpha[1];
627 Eigen::MatrixXd K_beta = both_beta[1];
629 H_alpha += J +
ScaHFX_ * K_alpha;
630 H_beta += J +
ScaHFX_ * K_beta;
632 E_coul = 0.5 * D_total.cwiseProduct(J).sum();
634 (Dspin.
alpha.cwiseProduct(K_alpha).sum() +
635 Dspin.
beta.cwiseProduct(K_beta).sum());
637 Eigen::MatrixXd J =
CalcERIs(D_total, integral_error);
640 E_coul = 0.5 * D_total.cwiseProduct(J).sum();
645 H_beta += vxc.vxc_beta;
648 double totenergy = H0.
energy() + E_one + E_coul + E_xc + E_exx;
651 << std::setprecision(12) << E_one << std::flush;
653 << std::setprecision(12) << E_coul << std::flush;
655 << std::setprecision(12) << E_xc << std::flush;
658 <<
TimeStamp() <<
" EXX contribution " << std::setprecision(12)
659 << E_exx << std::flush;
662 <<
TimeStamp() <<
" Total Energy " << std::setprecision(12) << totenergy
666 Dspin = conv_uks.
Iterate(Dspin, Hspin, MOs_alpha, MOs_beta, totenergy);
682 Index nuclear_charge = 0;
684 nuclear_charge += atom.getNuccharge();
688 orb.
MOs() = MOs_alpha;
699 <<
TimeStamp() <<
" UKS converged after " << this_iter + 1
700 <<
" iterations. Delta E=" << conv_uks.
getDeltaE()
701 <<
" DIIS error=" << conv_uks.
getDIIsError() << std::flush;
704 <<
TimeStamp() <<
" Final Single Point Energy "
705 << std::setprecision(12) << totenergy <<
" Ha" << std::flush;
707 <<
TimeStamp() << std::setprecision(12) <<
" Final XC contribution "
708 << E_xc <<
" Ha" << std::flush;
712 <<
" Final EXX contribution " << E_exx <<
" Ha" << std::flush;
728 <<
TimeStamp() <<
" UKS calculation has not converged after "
729 <<
max_iter_ <<
" iterations." << std::flush;
751 <<
TimeStamp() <<
" Filled DFT Kinetic energy matrix ." << std::flush;
756 <<
TimeStamp() <<
" Filled DFT nuclear potential matrix." << std::flush;
758 Eigen::MatrixXd H0 = dftAOkinetic.
Matrix() + dftAOESP.
Matrix();
760 <<
TimeStamp() <<
" Constructed independent particle hamiltonian "
764 << std::setprecision(9) << E0 << std::flush;
771 <<
TimeStamp() <<
" Filled DFT ECP matrix" << std::flush;
776 <<
" External sites" << std::flush;
777 bool has_quadrupoles = std::any_of(
779 [](
const std::unique_ptr<StaticSite>& s) { return s->getRank() == 2; });
781 " Name Coordinates[a0] charge[e] dipole[e*a0] ";
782 if (has_quadrupoles) {
783 header +=
" quadrupole[e*a0^2]";
789 if (counter == limit) {
793 (boost::format(
" %1$s"
794 " %2$+1.4f %3$+1.4f %4$+1.4f"
796 site->getElement() % site->getPos()[0] % site->getPos()[1] %
797 site->getPos()[2] % site->getCharge())
799 const Eigen::Vector3d& dipole = site->getDipole();
800 output += (boost::format(
" %1$+1.4f %2$+1.4f %3$+1.4f") % dipole[0] %
801 dipole[1] % dipole[2])
803 if (site->getRank() > 1) {
804 Eigen::VectorXd quadrupole = site->Q().tail<5>();
806 (boost::format(
" %1$+1.4f %2$+1.4f %3$+1.4f %4$+1.4f %5$+1.4f") %
807 quadrupole[0] % quadrupole[1] % quadrupole[2] % quadrupole[3] %
814 if (counter == limit) {
817 <<
" sites not displayed)\n"
824 <<
TimeStamp() <<
" Nuclei-external site interaction energy "
825 << std::setprecision(9) << ext_multipoles.
energy() << std::flush;
826 E0 += ext_multipoles.
energy();
827 H0 += ext_multipoles.
matrix();
834 E0 += extdensity_result.
energy();
836 <<
TimeStamp() <<
" Nuclei-external density interaction energy "
837 << std::setprecision(9) << extdensity_result.
energy() << std::flush;
838 H0 += extdensity_result.
matrix();
844 <<
TimeStamp() <<
" Integrating external electric field with F[Hrt]="
858 <<
TimeStamp() <<
" Filled DFT Overlap matrix." << std::flush;
875 <<
TimeStamp() <<
" Inverted AUX Coulomb matrix, removed "
876 <<
ERIs_.Removedfunctions() <<
" functions from aux basis"
880 <<
" Setup invariant parts of Electron Repulsion integrals "
884 <<
TimeStamp() <<
" Calculating 4c diagonals. " << std::flush;
887 <<
TimeStamp() <<
" Calculated 4c diagonals. " << std::flush;
894 const QMAtom& uniqueAtom)
const {
906 dftbasis.
Fill(basisset, atom);
916 ecp.
Fill(ecps, atom);
923 if ((numofelectrons % 2) != 0) {
924 alpha_e = numofelectrons / 2 + numofelectrons % 2;
925 beta_e = numofelectrons / 2;
927 alpha_e = numofelectrons / 2;
937 dftAOoverlap.
Fill(dftbasis);
938 dftAOkinetic.
Fill(dftbasis);
966 Eigen::MatrixXd H0 = dftAOkinetic.
Matrix() + dftAOESP.
Matrix();
973 Eigen::MatrixXd dftAOdmat_alpha = Convergence_alpha.
DensityMatrix(MOs_alpha);
976 return dftAOdmat_alpha;
980 Eigen::MatrixXd dftAOdmat_beta = Convergence_beta.
DensityMatrix(MOs_beta);
983 for (
Index this_iter = 0; this_iter < maxiter; this_iter++) {
984 Eigen::MatrixXd H_alpha = H0;
985 Eigen::MatrixXd H_beta = H0;
991 double integral_error = std::min(1
e-5 * 0.5 *
997 std::array<Eigen::MatrixXd, 2> both_alpha =
999 std::array<Eigen::MatrixXd, 2> both_beta =
1002 Eigen::MatrixXd Hartree = both_alpha[0] + both_beta[0];
1003 H_alpha += Hartree +
ScaHFX_ * both_alpha[1];
1004 H_beta += Hartree +
ScaHFX_ * both_beta[1];
1007 0.5 * (dftAOdmat_alpha + dftAOdmat_beta).cwiseProduct(Hartree).sum();
1009 (both_alpha[1].cwiseProduct(dftAOdmat_alpha).sum() +
1010 both_beta[1].cwiseProduct(dftAOdmat_beta).sum());
1013 dftAOdmat_alpha + dftAOdmat_beta, integral_error);
1017 0.5 * (dftAOdmat_alpha + dftAOdmat_beta).cwiseProduct(Hartree).sum();
1023 H_beta += vxc.vxc_beta;
1026 double E_one_alpha = dftAOdmat_alpha.cwiseProduct(H0).sum();
1027 double E_one_beta = dftAOdmat_beta.cwiseProduct(H0).sum();
1028 double totenergy = E_one_alpha + E_one_beta + E_coul + E_exx + E_xc;
1030 dftAOdmat_alpha = Convergence_alpha.
Iterate(dftAOdmat_alpha, H_alpha,
1031 MOs_alpha, totenergy);
1033 Convergence_beta.
Iterate(dftAOdmat_beta, H_beta, MOs_beta, totenergy);
1036 <<
TimeStamp() <<
" Iter " << this_iter <<
" of " << maxiter <<
" Etot "
1037 << totenergy <<
" diise_a " << Convergence_alpha.
getDIIsError()
1038 <<
" diise_b " << Convergence_beta.
getDIIsError() <<
"\n\t\t a_gap "
1044 << dftAOoverlap.
Matrix().cwiseProduct(dftAOdmat_alpha).sum()
1045 <<
" Nbeta=" << dftAOoverlap.
Matrix().cwiseProduct(dftAOdmat_beta).sum()
1050 if (converged || this_iter == maxiter - 1) {
1053 <<
TimeStamp() <<
" Converged after " << this_iter + 1
1054 <<
" iterations" << std::flush;
1057 <<
TimeStamp() <<
" Not converged after " << this_iter + 1
1058 <<
" iterations. Unconverged density.\n\t\t\t"
1059 <<
" DIIsError_alpha=" << Convergence_alpha.
getDIIsError()
1060 <<
" DIIsError_beta=" << Convergence_beta.
getDIIsError()
1067 Eigen::MatrixXd avgmatrix =
1071 <<
" gives N=" << std::setprecision(9)
1072 << avgmatrix.cwiseProduct(dftAOoverlap.
Matrix()).sum() <<
" electrons."
1081 <<
TimeStamp() <<
" Scanning molecule of size " << mol.
size()
1082 <<
" for unique elements" << std::flush;
1084 for (
auto element : elements) {
1085 uniqueelements.
push_back(
QMAtom(0, element, Eigen::Vector3d::Zero()));
1089 <<
" unique elements found" << std::flush;
1090 std::vector<Eigen::MatrixXd> uniqueatom_guesses;
1091 for (
QMAtom& unique_atom : uniqueelements) {
1093 <<
TimeStamp() <<
" Calculating atom density for "
1094 << unique_atom.getElement() << std::flush;
1096 uniqueatom_guesses.push_back(dmat_unrestricted);
1099 Eigen::MatrixXd guess =
1102 for (
const QMAtom& atom : mol) {
1104 for (; index < uniqueelements.
size(); index++) {
1105 if (atom.getElement() == uniqueelements[index].getElement()) {
1109 Eigen::MatrixXd& dmat_unrestricted = uniqueatom_guesses[index];
1110 guess.block(start, start, dmat_unrestricted.rows(),
1111 dmat_unrestricted.cols()) = dmat_unrestricted;
1112 start += dmat_unrestricted.rows();
1123 throw std::runtime_error(
1124 (boost::format(
"Basisset Name in guess orb file "
1125 "and in dftengine option file differ %1% vs %2%") %
1133 "Orbital file has no basisset information,"
1134 "using it as a guess might work or not for calculation with "
1159 throw std::runtime_error(
1160 (boost::format(
"ECPs in orb file: %1% and options %2% differ") %
1167 throw std::runtime_error(
1168 (boost::format(
"Number of electrons in guess orb file "
1169 "and in dftengine differ: "
1170 "alpha %1% vs %2%, beta %3% vs %4%.") %
1176 throw std::runtime_error(
1177 (boost::format(
"Number of levels in guess orb file: "
1178 "%1% and in dftengine: %2% differ.") %
1198 <<
TimeStamp() <<
" Using MKL overload for Eigen " << std::flush;
1202 <<
" Using native Eigen implementation, no BLAS overload "
1207 for (
const QMAtom& atom : mol) {
1209 std::string output = (boost::format(
" %1$s"
1210 " %2$+1.4f %3$+1.4f %4$+1.4f") %
1211 atom.getElement() % pos[0] % pos[1] % pos[2])
1222 <<
dftbasis_.AOBasisSize() <<
" functions" << std::flush;
1230 <<
auxbasis_.AOBasisSize() <<
" functions" << std::flush;
1238 std::vector<std::string> results =
ecp_.Fill(ecpbasisset, mol);
1240 <<
TimeStamp() <<
" Filled ECP Basis" << std::flush;
1241 if (results.size() > 0) {
1242 std::string message =
"";
1243 for (
const std::string& element : results) {
1244 message +=
" " + element;
1247 <<
TimeStamp() <<
" Found no ECPs for elements" << message
1258 Index nuclear_charge = 0;
1259 for (
const QMAtom& atom : mol) {
1260 nuclear_charge += atom.getNuccharge();
1266 if (multiplicity < 1) {
1267 throw std::runtime_error(
"Spin multiplicity must be >= 1.");
1270 if (numofelectrons >= 0) {
1276 Index spin_excess = multiplicity - 1;
1279 throw std::runtime_error(
"Computed a negative number of electrons.");
1283 throw std::runtime_error(
1284 "Spin multiplicity incompatible with total number of electrons.");
1288 throw std::runtime_error(
1289 "Charge and spin multiplicity imply non-integer alpha/beta "
1301 <<
" (charge=" << target_charge <<
", multiplicity=" << multiplicity
1327 <<
" divided into " << grid.
getBoxesSize() <<
" boxes" << std::flush;
1332 double E_nucnuc = 0.0;
1334 for (
Index i = 0; i < mol.
size(); i++) {
1335 const Eigen::Vector3d& r1 = mol[i].
getPos();
1336 double charge1 = double(mol[i].getNuccharge());
1337 for (
Index j = 0; j < i; j++) {
1338 const Eigen::Vector3d& r2 = mol[j].
getPos();
1339 double charge2 = double(mol[j].getNuccharge());
1340 E_nucnuc += charge1 * charge2 / (r1 - r2).norm();
1348 const Eigen::MatrixXd& dmat,
const AOBasis& dftbasis)
const {
1349 Eigen::MatrixXd avdmat = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
1350 for (
const AOShell& shellrow : dftbasis) {
1351 Index size_row = shellrow.getNumFunc();
1352 Index start_row = shellrow.getStartIndex();
1353 for (
const AOShell& shellcol : dftbasis) {
1354 Index size_col = shellcol.getNumFunc();
1355 Index start_col = shellcol.getStartIndex();
1356 Eigen::MatrixXd shelldmat =
1357 dmat.block(start_row, start_col, size_row, size_col);
1358 if (shellrow.getL() == shellcol.getL()) {
1359 double diagavg = shelldmat.diagonal().sum() / double(shelldmat.rows());
1360 Index offdiagelements =
1361 shelldmat.rows() * shelldmat.cols() - shelldmat.cols();
1362 double offdiagavg = (shelldmat.sum() - shelldmat.diagonal().sum()) /
1363 double(offdiagelements);
1364 avdmat.block(start_row, start_col, size_row, size_col).array() =
1366 avdmat.block(start_row, start_col, size_row, size_col)
1370 double avg = shelldmat.sum() / double(shelldmat.size());
1371 avdmat.block(start_row, start_col, size_row, size_col).array() = avg;
1380 const std::vector<std::unique_ptr<StaticSite> >& multipoles)
const {
1382 if (multipoles.size() == 0) {
1388 for (
const QMAtom& atom : mol) {
1390 for (
const std::unique_ptr<StaticSite>& site : *
externalsites_) {
1391 if ((site->getPos() - nucleus.
getPos()).norm() < 1
e-7) {
1393 <<
" External site sits on nucleus, "
1394 "interaction between them is ignored."
1409 Eigen::MatrixXd result =
1411 for (
Index i = 0; i < 3; i++) {
1419 const std::vector<std::unique_ptr<StaticSite> >& multipoles)
const {
1426 <<
TimeStamp() <<
" Filled DFT external multipole potential matrix"
1447 <<
TimeStamp() <<
" Calculated external density" << std::flush;
1450 <<
TimeStamp() <<
" Calculated potential from electron density"
1455 double nuc_energy = 0.0;
1456 for (
const QMAtom& atom : mol) {
1460 const double dist = (atom.getPos() - extatom.getPos()).norm();
1462 double(atom.getNuccharge()) * double(extatom.getNuccharge()) / dist;
1466 <<
TimeStamp() <<
" Calculated potential from nuclei" << std::flush;
1468 <<
TimeStamp() <<
" Electrostatic: " << nuc_energy << std::flush;
1473 const Eigen::MatrixXd& GuessMOs)
const {
1474 Eigen::MatrixXd nonortho =
1476 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(nonortho);
1477 Eigen::MatrixXd result = GuessMOs * es.operatorInverseSqrt();
1490 Eigen::VectorXd eps = Eigen::VectorXd::Zero(nao);
1494 int l =
static_cast<int>(shell.getL());
1495 Index start = shell.getStartIndex();
1496 Index nfunc = shell.getNumFunc();
1498 const QMAtom& atom = mol[shell.getAtomIndex()];
1499 const std::string& element = atom.
getElement();
1504 for (
Index i = 0; i < nfunc; ++i) {
1515 const Index nao =
S.rows();
1517 Eigen::MatrixXd
H = Eigen::MatrixXd::Zero(nao, nao);
1518 constexpr double K = 1.75;
1520 for (
Index mu = 0; mu < nao; ++mu) {
1521 H(mu, mu) = eps(mu);
1522 for (
Index nu = 0; nu < mu; ++nu) {
1523 double hij = K *
S(mu, nu) * 0.5 * (eps(mu) + eps(nu));
1535 <<
TimeStamp() <<
" Building Extended Huckel guess" << std::flush;
1540 <<
TimeStamp() <<
" Solving EHT generalized eigenproblem" << std::flush;
1558 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